public WitnessInfo(byte[] sHash, byte[] byWitness, int nHeight) { Witness = SnarkDllApi.CmWitness_Create(); SnarkDllApi.SetCMWitnessFromBinary(Witness, byWitness, byWitness.Length); ScriptHash = sHash; WitnessHeight = nHeight; }
public UInt256 pk_enc() { IntPtr ptr_pk_enc = SnarkDllApi.Key_ReceivingKey_Pk_enc(this.ToArray()); byte[] by_pk_enc = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptr_pk_enc, by_pk_enc, 0, 32); return(new UInt256(by_pk_enc)); //return NoteEncryption.generate_pubkey(this); }
public ReceivingKey receiving_key() { IntPtr ptr_rk = SnarkDllApi.Key_SpendingKey_ReceivingKey(this.ToArray()); byte[] by_rk = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptr_rk, by_rk, 0, 32); return(new ReceivingKey(new UInt256(by_rk))); //return new ReceivingKey(NoteEncryption.generate_privkey(this)); }
public PaymentAddress address() { IntPtr ptr_pa = SnarkDllApi.Key_SpendingKey_Address(this.ToArray()); byte[] by_a_pk = new byte[32]; byte[] by_pk_enc = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptr_pa, by_a_pk, 0, 32); System.Runtime.InteropServices.Marshal.Copy(ptr_pa + 32, by_pk_enc, 0, 32); return(new PaymentAddress(new UInt256(by_a_pk), new UInt256(by_pk_enc))); //return viewing_key().address(); }
public ViewingKey viewing_key() { IntPtr ptr_vk = SnarkDllApi.Key_SpendingKey_ReceivingKey(this.ToArray()); byte[] by_a_pk = new byte[32]; byte[] by_sk_enc = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptr_vk, by_a_pk, 0, 32); System.Runtime.InteropServices.Marshal.Copy(ptr_vk + 32, by_sk_enc, 0, 32); return(new ViewingKey(new UInt256(by_a_pk), new ReceivingKey(new UInt256(by_sk_enc)))); //return new ViewingKey(PRFClass.PRF_addr_a_pk(this), receiving_key()); }
public override bool Verify(IEnumerable <Transaction> mempool) { // Check Token Type for (int i = 0; i < byJoinSplit.Count; i++) { UInt256 AssetID = Asset_ID(i); AssetState asset = Blockchain.Default.GetAssetState(AssetID); if (asset.AssetType == AssetType.TransparentToken) { return(false); } } // Check double spend about tranparent input for (int i = 1; i < Inputs.Length; i++) { for (int j = 0; j < i; j++) { if (Inputs[i].PrevHash == Inputs[j].PrevHash && Inputs[i].PrevIndex == Inputs[j].PrevIndex) { return(false); } } } if (mempool.Where(p => p != this).SelectMany(p => p.Inputs).Intersect(Inputs).Count() > 0) { return(false); } if (Blockchain.Default.IsDoubleSpend(this)) { return(false); } if (Blockchain.Default.IsDoubleNullifier(this)) { return(false); } Fixed8 assetFee = Fixed8.Zero; Fixed8 qrsAssetFee = Fixed8.Zero; // Check output format foreach (var group in Outputs.GroupBy(p => p.AssetId)) { AssetState asset = Blockchain.Default.GetAssetState(group.Key); if (asset == null) { return(false); } if (asset.Expiration <= Blockchain.Default.Height + 1 && asset.AssetType != AssetType.GoverningToken && asset.AssetType != AssetType.UtilityToken) { return(false); } foreach (TransactionOutput output in group) { if (output.Value.GetData() % (long)Math.Pow(10, 8 - asset.Precision) != 0) { return(false); } } } TransactionResult[] results_transparent = GetTransactionResults()?.ToArray(); List <TransactionResult> results_anonymous = new List <TransactionResult>(); for (int i = 0; i < this.byJoinSplit.Count; i++) { bool isAdded = false; for (int j = 0; j < results_anonymous.Count; j++) { if (results_anonymous[j].AssetId == this.Asset_ID(i)) { results_anonymous[j].Amount -= this.vPub_Old(i); results_anonymous[j].Amount += this.vPub_New(i); isAdded = true; break; } } if (isAdded == false) { TransactionResult anonyItem = new TransactionResult(); anonyItem.AssetId = this.Asset_ID(i); anonyItem.Amount = this.vPub_New(i) - this.vPub_Old(i); results_anonymous.Add(anonyItem); } AssetState asset = Blockchain.Default.GetAssetState(this.Asset_ID(i)); } TransactionResult[] results = results_anonymous.Select(p => new { AssetId = p.AssetId, Value = p.Amount }).Concat(results_transparent.Select(p => new { AssetId = p.AssetId, Value = p.Amount })).GroupBy(p => p.AssetId, (k, g) => new TransactionResult { AssetId = k, Amount = g.Sum(p => p.Value) }).Where(p => p.Amount != Fixed8.Zero)?.ToArray(); if (results == null) { return(false); } TransactionResult[] results_destroy_temp = results.Where(p => p.Amount > Fixed8.Zero).ToArray(); TransactionResult[] results_destroy = results_destroy_temp.Where(p => p.Amount > Fixed8.Zero).ToArray(); Fixed8 result_qrs_fee = Fixed8.Zero; Fixed8 result_qrg_fee = Fixed8.Zero; Fixed8 result_other_fee = Fixed8.Zero; for (int i = 0; i < results_destroy.Length; i++) { if (results_destroy[i].AssetId == Blockchain.GoverningToken.Hash) { result_qrs_fee = results_destroy[i].Amount; } else if (results_destroy[i].AssetId == Blockchain.UtilityToken.Hash) { result_qrg_fee = results_destroy[i].Amount; } else { result_other_fee = results_destroy[i].Amount; } } if (result_other_fee > Fixed8.Zero || (SystemFee > result_qrg_fee && assetFee > Fixed8.Zero)) { return(false); } TransactionResult[] results_issue = results.Where(p => p.Amount < Fixed8.Zero).ToArray(); switch (Type) { case TransactionType.MinerTransaction: case TransactionType.ClaimTransaction: if (results_issue.Any(p => p.AssetId != Blockchain.UtilityToken.Hash)) { return(false); } break; case TransactionType.IssueTransaction: if (results_issue.Any(p => p.AssetId == Blockchain.UtilityToken.Hash)) { return(false); } break; default: if (results_issue.Length > 0) { return(false); } break; } if (Attributes.Count(p => p.Usage == TransactionAttributeUsage.ECDH02 || p.Usage == TransactionAttributeUsage.ECDH03) > 1) { return(false); } if (!Sodium.PublicKeyAuth.VerifyDetached(joinSplitSig, JsHash.ToArray(), joinSplitPubKey.ToArray())) { return(false); } for (int i = 0; i < byJoinSplit.Count; i++) { if (!SnarkDllApi.Snark_JSVerify(byJoinSplit[i], joinSplitPubKey.ToArray())) { return(false); } } if (Inputs.Length > 0) { return(this.VerifyScripts()); } else { return(true); } }
public void DoWork() { Global.AssetDescriptor asset = Asset as Global.AssetDescriptor; string fromAddress = FromAddr; string toAddress = ToAddr; string strAmount = Amount; byte toAddrVersion; byte fromAddrVersion; if (asset == null) { return; } if (!Fixed8.TryParse(strAmount, out Fixed8 amount)) { return; } if (amount == Fixed8.Zero) { return; } if (amount.GetData() % (long)Math.Pow(10, 8 - (Asset as Global.AssetDescriptor).Precision) != 0) { return; } try { fromAddrVersion = Wallet.GetAddressVersion(fromAddress); toAddrVersion = Wallet.GetAddressVersion(toAddress); } catch { return; } Transaction tx; if (toAddrVersion == Wallet.AddressVersion && fromAddrVersion == Wallet.AddressVersion) { List <TransactionAttribute> attributes = new List <TransactionAttribute>(); tx = new ContractTransaction(); //if (!string.IsNullOrEmpty(remark)) // attributes.Add(new TransactionAttribute // { // Usage = TransactionAttributeUsage.Remark, // Data = Encoding.UTF8.GetBytes(remark) // }); tx.Attributes = attributes.ToArray(); TransactionOutput outPut = new TransactionOutput(); outPut.ScriptHash = Wallet.ToScriptHash(toAddress); outPut.Value = amount; outPut.AssetId = (UInt256)asset.AssetId; tx.Outputs = new TransactionOutput[1]; tx.Outputs[0] = outPut; if (tx is ContractTransaction ctx) { tx = Constant.CurrentWallet.MakeTransactionFrom(ctx, fromAddress); } /* * if (tx is InvocationTransaction itx) * { * using (InvokeContractDialog dialog = new InvokeContractDialog(itx)) * { * if (dialog.ShowDialog() != DialogResult.OK) return; * tx = dialog.GetTransaction(); * } * } */ FormUI.Helper.SignAndShowInformation(tx); } else if (fromAddrVersion == Wallet.AddressVersion && toAddrVersion == Wallet.AnonymouseAddressVersion) { UInt256 joinSplitPubKey_; byte[] joinSplitPrivKey_; List <TransactionAttribute> attributes = new List <TransactionAttribute>(); tx = new AnonymousContractTransaction(); tx.Attributes = attributes.ToArray(); Sodium.KeyPair keyPair; keyPair = Sodium.PublicKeyAuth.GenerateKeyPair(); joinSplitPubKey_ = new UInt256(keyPair.PublicKey); joinSplitPrivKey_ = keyPair.PrivateKey; ((AnonymousContractTransaction)tx).joinSplitPubKey = joinSplitPubKey_; AsyncJoinSplitInfo info = new AsyncJoinSplitInfo(); info.vpub_old = new Fixed8(0); info.vpub_new = new Fixed8(0); JSOutput jsOut = new JSOutput(Wallet.ToPaymentAddress(toAddress), amount, (UInt256)asset.AssetId); info.vjsout.Add(jsOut); info.vpub_old += amount; if (tx is AnonymousContractTransaction ctx) { tx = Constant.CurrentWallet.MakeTandATransaction(ctx, fromAddress, info); if (tx is AnonymousContractTransaction ctx_) { IntPtr w = SnarkDllApi.Witnesses_Create(); IntPtr ptrRoot = SnarkDllApi.GetCMRoot(Blockchain.Default.GetCmMerkleTree()); byte[] byRoot = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptrRoot, byRoot, 0, 32); UInt256 anchor = new UInt256(byRoot); tx = Constant.CurrentWallet.Perform_JoinSplit(ctx_, info, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)asset.AssetId, w, anchor); /* * int dstOffset = 0; * byte[] byJsBody = new byte[ctx_.byJoinSplit.GetListLength()]; * for (int index = 0; index < ctx_.byJoinSplit.Count; index++) * { * Buffer.BlockCopy(ctx_.byJoinSplit[index], 0, byJsBody, dstOffset, ctx_.byJoinSplit[index].Length); * dstOffset += ctx_.byJoinSplit[index].Length; * } * * UInt256 jsHash = new UInt256(Crypto.Default.Hash256(byJsBody)); */ ctx_.joinSplitSig = Sodium.PublicKeyAuth.SignDetached(ctx.JsHash.ToArray(), joinSplitPrivKey_); if (!Sodium.PublicKeyAuth.VerifyDetached(ctx_.joinSplitSig, ctx.JsHash.ToArray(), joinSplitPubKey_.ToArray())) { return; } } } FormUI.Helper.SignAndShowInformation(tx); } else if (fromAddrVersion == Wallet.AnonymouseAddressVersion && toAddrVersion == Wallet.AddressVersion) { UInt256 joinSplitPubKey_; byte[] joinSplitPrivKey_; List <TransactionAttribute> attributes = new List <TransactionAttribute>(); tx = new AnonymousContractTransaction(); Fixed8 vpubNewTarget = Fixed8.Zero; Fixed8 totalAmount = amount; tx.Attributes = attributes.ToArray(); Sodium.KeyPair keyPair; keyPair = Sodium.PublicKeyAuth.GenerateKeyPair(); joinSplitPubKey_ = new UInt256(keyPair.PublicKey); joinSplitPrivKey_ = keyPair.PrivateKey; ((AnonymousContractTransaction)tx).joinSplitPubKey = joinSplitPubKey_; // Do process the transparent outputs. TransactionOutput outPut = new TransactionOutput(); outPut.ScriptHash = Wallet.ToScriptHash(toAddress); outPut.Value = amount; outPut.AssetId = (UInt256)asset.AssetId; tx.Outputs = new TransactionOutput[1]; tx.Outputs[0] = outPut; tx.Scripts = new Witness[0]; vpubNewTarget = amount; AsyncJoinSplitInfo info = new AsyncJoinSplitInfo(); info.vpub_old = Fixed8.Zero; info.vpub_new = Fixed8.Zero; Fixed8 jsInputValue = Fixed8.Zero; IntPtr ptrRoot = SnarkDllApi.GetCMRoot(Blockchain.Default.GetCmMerkleTree()); byte[] byRoot = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptrRoot, byRoot, 0, 32); UInt256 jsAnchor = new UInt256(byRoot); if (tx is AnonymousContractTransaction ctx) { tx = Constant.CurrentWallet.MakeAandTTransaction(ctx, fromAddress, info); IntPtr vectorWitness = SnarkDllApi.Witnesses_Create(); int jsIndex = 0; Fixed8 current_inputed_amount = Fixed8.Zero; Fixed8 rest_amount = totalAmount; for (int i = 0; i < info.vjsin.Count; i++) { IntPtr witness = SnarkDllApi.CmWitness_Create(); SnarkDllApi.SetCMWitnessFromBinary(witness, info.vjsin[i].witness, info.vjsin[i].witness.Length); SnarkDllApi.Witnesses_Add(vectorWitness, witness); IntPtr ptrWitness = SnarkDllApi.GetCMRootFromWitness(witness); byte[] byWRoot = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptrRoot, byWRoot, 0, 32); UInt256 wAnchor = new UInt256(byWRoot); if (jsAnchor != wAnchor) { throw new InvalidOperationException("Anchor is not correct"); } current_inputed_amount += info.vjsin[i].note.value; jsIndex++; if (jsIndex == 2 && i != info.vjsin.Count - 1) { AsyncJoinSplitInfo jsInfo = new AsyncJoinSplitInfo(); jsInfo.vjsin.Add(info.vjsin[i - 1]); jsInfo.vjsin.Add(info.vjsin[i]); jsInfo.notes.Add(info.notes[i - 1]); jsInfo.notes.Add(info.notes[i]); rest_amount -= jsInfo.notes[0].value; rest_amount -= jsInfo.notes[1].value; if (rest_amount > Fixed8.Zero) { jsInfo.vpub_new = info.vjsin[i - 1].note.value + info.vjsin[i].note.value; jsInfo.vpub_old = Fixed8.Zero; } else { //JSOutput jso = new JSOutput(Wallet.ToPaymentAddress(toAddress), jsInputedAmount, (UInt256)asset.AssetId); //JSOutput jso_remain = new JSOutput(Wallet.ToPaymentAddress(fromAddress), -rest_amount, (UInt256)asset.AssetId); //jsInfo.vjsout.Add(jso); //jsInfo.vjsout.Add(jso_remain); } tx = Constant.CurrentWallet.Perform_JoinSplit(ctx, jsInfo, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)asset.AssetId, vectorWitness, jsAnchor); jsIndex = 0; SnarkDllApi.Witnesses_Clear(vectorWitness); } if (i == info.vjsin.Count - 1) { AsyncJoinSplitInfo jsInfo = new AsyncJoinSplitInfo(); Fixed8 jsInputedAmount = Fixed8.Zero; for (int ji = jsIndex - 1; ji > -1; ji--) { jsInfo.vjsin.Add(info.vjsin[i - ji]); jsInfo.notes.Add(info.notes[i - ji]); jsInputedAmount += info.notes[i - ji].value; rest_amount -= info.notes[i - ji].value; } if (rest_amount < Fixed8.Zero) { JSOutput jso_remain = new JSOutput(Wallet.ToPaymentAddress(fromAddress), -rest_amount, (UInt256)asset.AssetId); jsInfo.vpub_new = jsInputedAmount + rest_amount; jsInfo.vpub_old = Fixed8.Zero; jsInfo.vjsout.Add(jso_remain); } tx = Constant.CurrentWallet.Perform_JoinSplit(ctx, jsInfo, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)asset.AssetId, vectorWitness, jsAnchor); if (tx.Inputs == null) { tx.Inputs = new CoinReference[0]; } jsIndex = 0; SnarkDllApi.Witnesses_Clear(vectorWitness); } } /* * int dstOffset = 0; * byte[] byJsBody = new byte[ctx.byJoinSplit.GetListLength()]; * for (int index = 0; index < ctx.byJoinSplit.Count; index++) * { * Buffer.BlockCopy(ctx.byJoinSplit[index], 0, byJsBody, dstOffset, ctx.byJoinSplit[index].Length); * dstOffset += ctx.byJoinSplit[index].Length; * } * * UInt256 jsHash = new UInt256(Crypto.Default.Hash256(byJsBody)); */ //UInt256 tmp_jsHash = ctx.JsHash; ctx.joinSplitSig = Sodium.PublicKeyAuth.SignDetached(ctx.JsHash.ToArray(), joinSplitPrivKey_); if (!Sodium.PublicKeyAuth.VerifyDetached(ctx.joinSplitSig, ctx.JsHash.ToArray(), joinSplitPubKey_.ToArray())) { return; } } FormUI.Helper.SignAndShowInformation(tx); } else if (fromAddrVersion == Wallet.AnonymouseAddressVersion && toAddrVersion == Wallet.AnonymouseAddressVersion) { UInt256 joinSplitPubKey_; byte[] joinSplitPrivKey_; List <TransactionAttribute> attributes = new List <TransactionAttribute>(); tx = new AnonymousContractTransaction(); Fixed8 totalAmount = amount; tx.Scripts = new Witness[0]; tx.Attributes = attributes.ToArray(); Sodium.KeyPair keyPair; keyPair = Sodium.PublicKeyAuth.GenerateKeyPair(); joinSplitPubKey_ = new UInt256(keyPair.PublicKey); joinSplitPrivKey_ = keyPair.PrivateKey; ((AnonymousContractTransaction)tx).joinSplitPubKey = joinSplitPubKey_; AsyncJoinSplitInfo info = new AsyncJoinSplitInfo(); info.vpub_old = Fixed8.Zero; info.vpub_new = Fixed8.Zero; JSOutput jsOut = new JSOutput(Wallet.ToPaymentAddress(toAddress), amount, (UInt256)asset.AssetId); info.vjsout.Add(jsOut); Fixed8 jsInputValue = Fixed8.Zero; IntPtr ptrRoot = SnarkDllApi.GetCMRoot(Blockchain.Default.GetCmMerkleTree()); byte[] byRoot = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptrRoot, byRoot, 0, 32); UInt256 jsAnchor = new UInt256(byRoot); if (tx is AnonymousContractTransaction ctx) { tx = Constant.CurrentWallet.MakeAandATransaction(ctx, fromAddress, info); IntPtr vectorWitness = SnarkDllApi.Witnesses_Create(); int jsIndex = 0; Fixed8 current_inputed_amount = Fixed8.Zero; Fixed8 rest_amount = totalAmount; for (int i = 0; i < info.vjsin.Count; i++) { IntPtr witness = SnarkDllApi.CmWitness_Create(); SnarkDllApi.SetCMWitnessFromBinary(witness, info.vjsin[i].witness, info.vjsin[i].witness.Length); SnarkDllApi.Witnesses_Add(vectorWitness, witness); IntPtr ptrWitness = SnarkDllApi.GetCMRootFromWitness(witness); byte[] byWRoot = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptrRoot, byWRoot, 0, 32); UInt256 wAnchor = new UInt256(byWRoot); if (jsAnchor != wAnchor) { throw new InvalidOperationException("Anchor is not correct"); } current_inputed_amount += info.vjsin[i].note.value; jsIndex++; if (jsIndex == 2 && i != info.vjsin.Count - 1) { AsyncJoinSplitInfo jsInfo = new AsyncJoinSplitInfo(); jsInfo.vjsin.Add(info.vjsin[i - 1]); jsInfo.vjsin.Add(info.vjsin[i]); jsInfo.notes.Add(info.notes[i - 1]); jsInfo.notes.Add(info.notes[i]); tx = Constant.CurrentWallet.Perform_JoinSplit(ctx, jsInfo, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)asset.AssetId, vectorWitness, jsAnchor); jsIndex = 0; SnarkDllApi.Witnesses_Clear(vectorWitness); } if (i == info.vjsin.Count - 1) { AsyncJoinSplitInfo jsInfo = new AsyncJoinSplitInfo(); Fixed8 jsInputedAmount = Fixed8.Zero; for (int ji = jsIndex - 1; ji > -1; ji--) { jsInfo.vjsin.Add(info.vjsin[i - ji]); jsInfo.notes.Add(info.notes[i - ji]); jsInputedAmount += info.notes[i - ji].value; rest_amount -= info.notes[i - ji].value; } for (int jo = 0; jo < info.vjsout.Count; jo++) { jsInfo.vjsout.Add(info.vjsout[jo]); } try { tx = Constant.CurrentWallet.Perform_JoinSplit(ctx, jsInfo, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)asset.AssetId, vectorWitness, jsAnchor); } catch (Exception ex) { string strException = ex.Message; } if (tx.Inputs == null) { tx.Inputs = new CoinReference[0]; } jsIndex = 0; SnarkDllApi.Witnesses_Clear(vectorWitness); } } /* * int dstOffset = 0; * byte[] byJsBody = new byte[ctx.byJoinSplit.GetListLength()]; * for (int index = 0; index < ctx.byJoinSplit.Count; index++) * { * Buffer.BlockCopy(ctx.byJoinSplit[index], 0, byJsBody, dstOffset, ctx.byJoinSplit[index].Length); * dstOffset += ctx.byJoinSplit[index].Length; * } * * UInt256 jsHash = new UInt256(Crypto.Default.Hash256(byJsBody)); */ ctx.joinSplitSig = Sodium.PublicKeyAuth.SignDetached(ctx.JsHash.ToArray(), joinSplitPrivKey_); if (!Sodium.PublicKeyAuth.VerifyDetached(ctx.joinSplitSig, ctx.JsHash.ToArray(), joinSplitPubKey_.ToArray())) { return; } } FormUI.Helper.SignAndShowInformation(tx); } }
private void Window_Loaded(object sender, RoutedEventArgs e) { AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; try { Mutex.OpenExisting("QURAS WALLET MUTEX"); MessageBox.Show(StringTable.GetInstance().GetString("STR_WALLET_DUPPLICATION_ERROR", iLang), "QURAS"); this.Close(); return; } catch { _m = new Mutex(true, "QURAS WALLET MUTEX"); } SplashTimer.Tick += new EventHandler(NextWindow); SplashTimer.Interval = new TimeSpan(0, 0, 3); SplashTimer.Start(); Version localVersion = Assembly.GetExecutingAssembly().GetName().Version; Version serverVersion = GetNewestWalletVersionFromServer(); if (localVersion < serverVersion) { // Show the Update Window; } else { // Check the Key file Exception. } Task.Run(() => { try { string vkKeyPath = SettingsConfig.Default.VkKeyPath; string pkKeyPath = SettingsConfig.Default.PkKeyPath; vkKeyPath = System.IO.Path.GetFullPath(vkKeyPath); pkKeyPath = System.IO.Path.GetFullPath(pkKeyPath); if (Constant.isLoadedVK == false) { int ret = SnarkDllApi.Snark_DllInit(1, vkKeyPath.ToArray(), pkKeyPath.ToArray()); if (ret <= 0) { MessageBox.Show("Verify key cannot load.", "Error", MessageBoxButton.OK); this.Close(); return; } Constant.isLoadedVK = true; } } catch (Exception ex) { MessageBox.Show("Verify key cannot load." + ex.ToString(), "Error", MessageBoxButton.OK); this.Dispatcher.BeginInvoke(new Action(() => { this.Close(); })); } try { Blockchain.RegisterBlockchain(new LevelDBBlockchain("chain")); this.Dispatcher.BeginInvoke(new Action(() => { isLoadedBlockchain = true; })); } catch (Exception ex) { this.Dispatcher.BeginInvoke(new Action(() => { MessageBox.Show("Cannot load blockchain db." + System.Environment.NewLine + ex.ToString(), "Error", MessageBoxButton.OK); this.Close(); })); } }); }
private void btnZKModuleLoad_Click(object sender, RoutedEventArgs e) { btnZKModuleLoad.IsEnabled = false; string vkKeyPath = SettingsConfig.Default.VkKeyPath; string pkKeyPath = SettingsConfig.Default.PkKeyPath; vkKeyPath = System.IO.Path.GetFullPath(vkKeyPath); pkKeyPath = System.IO.Path.GetFullPath(pkKeyPath); if (StaticUtils.CheckZKSnarksKeyStatus() == 0) { Task.Run(() => { int ret; if (vkKeyState == KeyState.Loaded) { ret = 1; this.Dispatcher.BeginInvoke(new Action(() => { zkModuleState = KeyState.Loading; ShowZkModuleState(zkModuleState); })); } else { try { this.Dispatcher.BeginInvoke(new Action(() => { StaticUtils.ShowMessageBox(StaticUtils.BlueBrush, StringTable.GetInstance().GetString("STR_SUCCESS_LOADING_VERIFYKEY", iLang)); vkKeyState = KeyState.Loading; ShowVkKeyState(vkKeyState); zkModuleState = KeyState.Loading; ShowZkModuleState(zkModuleState); })); ret = SnarkDllApi.Snark_DllInit(1, vkKeyPath.ToArray(), pkKeyPath.ToArray()); } catch (Exception ex) { ret = -1; } } if (ret > 0) { this.Dispatcher.BeginInvoke(new Action(() => { StaticUtils.ShowMessageBox(StaticUtils.GreenBrush, StringTable.GetInstance().GetString("STR_SUCCESS_LOADED_VERIFYKEY", iLang)); vkKeyState = KeyState.Loaded; Constant.isLoadedVK = true; ShowVkKeyState(vkKeyState); })); vkKeyPath = SettingsConfig.Default.VkKeyPath; pkKeyPath = SettingsConfig.Default.PkKeyPath; vkKeyPath = System.IO.Path.GetFullPath(vkKeyPath); pkKeyPath = System.IO.Path.GetFullPath(pkKeyPath); try { this.Dispatcher.BeginInvoke(new Action(() => { StaticUtils.ShowMessageBox(StaticUtils.BlueBrush, StringTable.GetInstance().GetString("STR_BEGIN_LOADING_PUBLICKEY", iLang)); pkKeyState = KeyState.Loading; ShowPkKeyState(pkKeyState); LoadKeyTaskMessage taskMessage = new LoadKeyTaskMessage(StringTable.GetInstance().GetString("STR_TASK_MESSAGE_PK_KEY_LOAD_START", iLang), DateTime.Now); Constant.TaskMessages.Add(taskMessage); TaskChangedEvent?.Invoke(this, taskMessage); })); ret = SnarkDllApi.Snark_DllInit(2, vkKeyPath.ToArray(), pkKeyPath.ToArray()); } catch (Exception) { ret = -1; } if (ret > 0) { this.Dispatcher.BeginInvoke(new Action(() => { StaticUtils.ShowMessageBox(StaticUtils.GreenBrush, StringTable.GetInstance().GetString("STR_SUCCESS_LOADED_PUBLICKEY", iLang)); pkKeyState = KeyState.Loaded; ShowPkKeyState(pkKeyState); Constant.isLoadedPK = true; zkModuleState = KeyState.Loaded; ShowZkModuleState(zkModuleState); Constant.bSnarksParamLoaded = true; LoadKeyTaskMessage taskMessage = new LoadKeyTaskMessage(StringTable.GetInstance().GetString("STR_TASK_MESSAGE_PK_KEY_LOAD_FINISHED", iLang), DateTime.Now); Constant.TaskMessages.Add(taskMessage); TaskChangedEvent?.Invoke(this, taskMessage); btnZKModuleLoad.IsEnabled = false; })); } else { this.Dispatcher.BeginInvoke(new Action(() => { StaticUtils.ShowMessageBox(StaticUtils.ErrorBrush, StringTable.GetInstance().GetString("STR_ERR_LOADING_PUBLICKEY", iLang)); pkKeyState = KeyState.Downloaded; ShowPkKeyState(pkKeyState); zkModuleState = KeyState.Downloaded; ShowZkModuleState(zkModuleState); LoadKeyTaskMessage taskMessage = new LoadKeyTaskMessage(StringTable.GetInstance().GetString("STR_TASK_MESSAGE_PK_KEY_LOAD_FAILED", iLang), DateTime.Now, TaskColor.Red); Constant.TaskMessages.Add(taskMessage); TaskChangedEvent?.Invoke(this, taskMessage); btnZKModuleLoad.IsEnabled = true; })); } } else { this.Dispatcher.BeginInvoke(new Action(() => { StaticUtils.ShowMessageBox(StaticUtils.GreenBrush, StringTable.GetInstance().GetString("STR_ERR_LOADING_VERIFYKEY", iLang)); vkKeyState = KeyState.Downloaded; ShowVkKeyState(vkKeyState); zkModuleState = KeyState.Downloaded; ShowZkModuleState(zkModuleState); btnZKModuleLoad.IsEnabled = true; })); } }); } }
protected internal override void OnStart(string[] args) { Blockchain.RegisterBlockchain(new LevelDBBlockchain(Settings.Default.DataDirectoryPath)); if (File.Exists(PeerStatePath)) { using (FileStream fs = new FileStream(PeerStatePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { LocalNode.LoadState(fs); } } // Load Verify Key string vk_path = ".//crypto//vk.key"; string pk_path = ".//crypto//pk.key"; int ret = SnarkDllApi.Snark_DllInit(1, vk_path.ToArray(), pk_path.ToArray()); if (ret > 0) { Console.WriteLine($"Verify key loading success"); } else { Console.WriteLine($"Verify key loading unseccess"); } LocalNode = new LocalNode(); Task.Run(() => { const string acc_path = "chain.acc"; const string acc_zip_path = acc_path + ".zip"; if (File.Exists(acc_path)) { using (FileStream fs = new FileStream(acc_path, FileMode.Open, FileAccess.Read, FileShare.None)) { ImportBlocks(fs); } File.Delete(acc_path); } else if (File.Exists(acc_zip_path)) { using (FileStream fs = new FileStream(acc_zip_path, FileMode.Open, FileAccess.Read, FileShare.None)) using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) using (Stream zs = zip.GetEntry(acc_path).Open()) { ImportBlocks(zs); } File.Delete(acc_zip_path); } LocalNode.Start(Settings.Default.NodePort, Settings.Default.WsPort); bool recordNotifications = false; for (int i = 0; i < args.Length; i++) { switch (args[i]) { case "/rpc": case "--rpc": case "-r": if (rpc == null) { rpc = new RpcServerWithWallet(LocalNode); rpc.Start(Settings.Default.UriPrefix.OfType <string>().ToArray(), Settings.Default.SslCert, Settings.Default.SslCertPassword); } break; case "--record-notifications": recordNotifications = true; break; } } if (recordNotifications) { Blockchain.Notify += Blockchain_Notify; } }); }
private void MainWalletForm_Load(object sender, EventArgs e) { string vkKeyPath = Settings.Default.VkKeyPath; string pkKeyPath = Settings.Default.PkKeyPath; vkKeyPath = Path.GetFullPath(vkKeyPath); pkKeyPath = Path.GetFullPath(pkKeyPath); if (Utils.CheckZKSnarksKeyStatus() == 0) { int ret; try { ret = SnarkDllApi.Snark_DllInit(1, vkKeyPath.ToArray(), pkKeyPath.ToArray()); } catch (Exception) { ret = -1; } if (ret > 0) { Invoke(new Action(() => { lbl_status.Text = StringTable.DATA[iLang, 37]; })); Task.Run(() => { Invoke(new Action(() => { lbl_status.Text = StringTable.DATA[iLang, 38]; })); vkKeyPath = Settings.Default.VkKeyPath; pkKeyPath = Settings.Default.PkKeyPath; vkKeyPath = Path.GetFullPath(vkKeyPath); pkKeyPath = Path.GetFullPath(pkKeyPath); ret = SnarkDllApi.Snark_DllInit(2, vkKeyPath.ToArray(), pkKeyPath.ToArray()); if (ret > 0) { Invoke(new Action(() => { lbl_status.Text = StringTable.DATA[iLang, 39]; Constant.bSnarksParamLoaded = true; })); } else { Invoke(new Action(() => { lbl_status.Text = StringTable.DATA[iLang, 40] + ret.ToString(); })); } }); } else { Invoke(new Action(() => { lbl_status.Text = StringTable.DATA[iLang, 41] + ret.ToString(); })); } } else { Invoke(new Action(() => { lbl_status.Text = StringTable.DATA[iLang, 41]; })); } Task.Run(() => { const string acc_path = "chain.acc"; const string acc_zip_path = acc_path + ".zip"; if (File.Exists(acc_path)) { using (FileStream fs = new FileStream(acc_path, FileMode.Open, FileAccess.Read, FileShare.None)) { ImportBlocks(fs); } File.Delete(acc_path); } else if (File.Exists(acc_zip_path)) { using (FileStream fs = new FileStream(acc_zip_path, FileMode.Open, FileAccess.Read, FileShare.None)) using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) using (Stream zs = zip.GetEntry(acc_path).Open()) { ImportBlocks(zs); } File.Delete(acc_zip_path); } Blockchain.PersistCompleted += Blockchain_PersistCompleted; Constant.LocalNode.Start(Settings.Default.NodePort, Settings.Default.WsPort); }); }
public void DoWork() { #region Checking Fields Global.AssetDescriptor asset = Asset as Global.AssetDescriptor; string fromAddress = FromAddr; string toAddress = ToAddr; string strAmount = Amount; string strFee = Fee; byte toAddrVersion; byte fromAddrVersion; if (asset == null) { throw new InvalidOperationException("Anchor is not correct"); } if (!Fixed8.TryParse(strAmount, out Fixed8 amount)) { throw new InvalidOperationException("Anchor is not correct"); } if (amount == Fixed8.Zero) { throw new InvalidOperationException("Anchor is not correct"); } if (amount.GetData() % (long)Math.Pow(10, 8 - (Asset as Global.AssetDescriptor).Precision) != 0) { throw new InvalidOperationException("Anchor is not correct"); } if (!Fixed8.TryParse(strFee, out Fixed8 fee)) { throw new InvalidOperationException("Anchor is not correct"); } if (fee < Fixed8.Zero) { throw new InvalidOperationException("Anchor is not correct"); } try { fromAddrVersion = Wallet.GetAddressVersion(fromAddress); toAddrVersion = Wallet.GetAddressVersion(toAddress); } catch { throw new InvalidOperationException("Anchor is not correct"); } Transaction tx; #endregion #region T -> T if (toAddrVersion == Wallet.AddressVersion && fromAddrVersion == Wallet.AddressVersion) // T -> T { List <TransactionAttribute> attributes = new List <TransactionAttribute>(); tx = new ContractTransaction(); //if (!string.IsNullOrEmpty(remark)) // attributes.Add(new TransactionAttribute // { // Usage = TransactionAttributeUsage.Remark, // Data = Encoding.UTF8.GetBytes(remark) // }); tx.Attributes = attributes.ToArray(); TransactionOutput outPut = new TransactionOutput(); outPut.ScriptHash = Wallet.ToScriptHash(toAddress); outPut.Value = amount; outPut.AssetId = (UInt256)asset.AssetId; outPut.Fee = fee; tx.Outputs = new TransactionOutput[1]; tx.Outputs[0] = outPut; if (tx is ContractTransaction ctx) { tx = Constant.CurrentWallet.MakeTransactionFrom(ctx, fromAddress); if (tx == null) { throw new InvalidOperationException("Anchor is not correct"); } } Helper.SignAndShowInformation(tx); } #endregion #region T -> A else if (fromAddrVersion == Wallet.AddressVersion && toAddrVersion == Wallet.AnonymouseAddressVersion) // T -> A { UInt256 joinSplitPubKey_; byte[] joinSplitPrivKey_; List <TransactionAttribute> attributes = new List <TransactionAttribute>(); tx = new AnonymousContractTransaction(); tx.Attributes = attributes.ToArray(); Sodium.KeyPair keyPair; keyPair = Sodium.PublicKeyAuth.GenerateKeyPair(); joinSplitPubKey_ = new UInt256(keyPair.PublicKey); joinSplitPrivKey_ = keyPair.PrivateKey; ((AnonymousContractTransaction)tx).joinSplitPubKey = joinSplitPubKey_; AsyncJoinSplitInfo info = new AsyncJoinSplitInfo(); info.vpub_old = new Fixed8(0); info.vpub_new = new Fixed8(0); JSOutput jsOut = new JSOutput(Wallet.ToPaymentAddress(toAddress), amount, fee, (UInt256)asset.AssetId); info.vjsout.Add(jsOut); info.vpub_old += amount; if (tx is AnonymousContractTransaction ctx) { tx = Constant.CurrentWallet.MakeTandATransaction(ctx, fromAddress, info); if (tx is AnonymousContractTransaction ctx_) { IntPtr w = SnarkDllApi.Witnesses_Create(); IntPtr ptrRoot = SnarkDllApi.GetCMRoot(Blockchain.Default.GetCmMerkleTree()); byte[] byRoot = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptrRoot, byRoot, 0, 32); UInt256 anchor = new UInt256(byRoot); tx = Constant.CurrentWallet.Perform_JoinSplit(ctx_, info, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)asset.AssetId, w, anchor); ctx_.joinSplitSig = Sodium.PublicKeyAuth.SignDetached(ctx.JsHash.ToArray(), joinSplitPrivKey_); if (!Sodium.PublicKeyAuth.VerifyDetached(ctx_.joinSplitSig, ctx.JsHash.ToArray(), joinSplitPubKey_.ToArray())) { throw new InvalidOperationException("Anchor is not correct"); } } else { throw new InvalidOperationException("Anchor is not correct"); } } else { throw new InvalidOperationException("Anchor is not correct"); } Helper.SignAndShowInformation(tx); } #endregion #region A -> T else if (fromAddrVersion == Wallet.AnonymouseAddressVersion && toAddrVersion == Wallet.AddressVersion) // A -> T { UInt256 joinSplitPubKey_; byte[] joinSplitPrivKey_; List <TransactionAttribute> attributes = new List <TransactionAttribute>(); tx = new AnonymousContractTransaction(); Fixed8 vpubNewTarget = Fixed8.Zero; Fixed8 totalAmount = amount; tx.Attributes = attributes.ToArray(); Sodium.KeyPair keyPair; keyPair = Sodium.PublicKeyAuth.GenerateKeyPair(); joinSplitPubKey_ = new UInt256(keyPair.PublicKey); joinSplitPrivKey_ = keyPair.PrivateKey; ((AnonymousContractTransaction)tx).joinSplitPubKey = joinSplitPubKey_; // Do process the transparent outputs. TransactionOutput outPut = new TransactionOutput(); outPut.ScriptHash = Wallet.ToScriptHash(toAddress); outPut.Value = amount; outPut.AssetId = (UInt256)asset.AssetId; tx.Outputs = new TransactionOutput[1]; tx.Outputs[0] = outPut; tx.Scripts = new Witness[0]; vpubNewTarget = amount; AsyncJoinSplitInfo info = new AsyncJoinSplitInfo(); info.vpub_old = Fixed8.Zero; info.vpub_new = Fixed8.Zero; Fixed8 jsInputValue = Fixed8.Zero; IntPtr ptrRoot = SnarkDllApi.GetCMRoot(Blockchain.Default.GetCmMerkleTree()); byte[] byRoot = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptrRoot, byRoot, 0, 32); UInt256 jsAnchor = new UInt256(byRoot); if (tx is AnonymousContractTransaction ctx) { tx = Constant.CurrentWallet.MakeAandTTransaction(ctx, fromAddress, info); #region Split token types /* ****************************** Split the info into main token and fee token ********************************** */ AsyncJoinSplitInfo mainTokenInfo = new AsyncJoinSplitInfo(); AsyncJoinSplitInfo subTokenInfo = new AsyncJoinSplitInfo(); Fixed8 main_total_output_amount = Fixed8.Zero; Fixed8 sub_total_output_amount = Fixed8.Zero; for (int i = 0; i < info.vjsin.Count; i++) { if (info.vjsin[i].AssetID == Blockchain.UtilityToken.Hash) { subTokenInfo.vjsin.Add(info.vjsin[i]); subTokenInfo.notes.Add(info.vjsin[i].note); } else { mainTokenInfo.vjsin.Add(info.vjsin[i]); mainTokenInfo.notes.Add(info.vjsin[i].note); } } for (int i = 0; i < info.vjsout.Count; i++) { if (info.vjsout[i].AssetID == Blockchain.UtilityToken.Hash) { subTokenInfo.vjsout.Add(info.vjsout[i]); sub_total_output_amount += info.vjsout[i].value; } else { mainTokenInfo.vjsout.Add(info.vjsout[i]); main_total_output_amount += info.vjsout[i].value; } } /* ****************************** End ********************************** */ #endregion IntPtr vectorWitness = SnarkDllApi.Witnesses_Create(); int jsIndex = 0; Fixed8 current_inputed_amount = Fixed8.Zero; Fixed8 rest_amount = totalAmount; #region Do Process the Main token part for (int i = 0; i < mainTokenInfo.vjsin.Count; i++) { IntPtr witness = SnarkDllApi.CmWitness_Create(); SnarkDllApi.SetCMWitnessFromBinary(witness, mainTokenInfo.vjsin[i].witness, mainTokenInfo.vjsin[i].witness.Length); SnarkDllApi.Witnesses_Add(vectorWitness, witness); IntPtr ptrWitness = SnarkDllApi.GetCMRootFromWitness(witness); byte[] byWRoot = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptrWitness, byWRoot, 0, 32); UInt256 wAnchor = new UInt256(byWRoot); if (jsAnchor != wAnchor) { throw new InvalidOperationException("Anchor is not correct"); } current_inputed_amount += mainTokenInfo.vjsin[i].note.value; jsIndex++; if (jsIndex == 2 && i != mainTokenInfo.vjsin.Count - 1) { AsyncJoinSplitInfo jsInfo = new AsyncJoinSplitInfo(); jsInfo.vjsin.Add(mainTokenInfo.vjsin[i - 1]); jsInfo.vjsin.Add(mainTokenInfo.vjsin[i]); jsInfo.notes.Add(mainTokenInfo.notes[i - 1]); jsInfo.notes.Add(mainTokenInfo.notes[i]); var vInputsSum = jsInfo.vjsin[0].note.value + jsInfo.vjsin[1].note.value; for (int oti = 0; oti < mainTokenInfo.vjsout.Count; oti++) { if (mainTokenInfo.vjsout[oti].value >= vInputsSum) { JSOutput jsOut1 = new JSOutput(mainTokenInfo.vjsout[oti].addr, vInputsSum, mainTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); mainTokenInfo.vjsout[oti].value -= vInputsSum; vInputsSum = Fixed8.Zero; break; } if (mainTokenInfo.vjsout[oti].value < vInputsSum) { JSOutput jsOut1 = new JSOutput(mainTokenInfo.vjsout[oti].addr, mainTokenInfo.vjsout[oti].value, mainTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); vInputsSum = vInputsSum - mainTokenInfo.vjsout[oti].value; mainTokenInfo.vjsout[oti].value = Fixed8.Zero; } } if (vInputsSum >= Fixed8.Zero) { jsInfo.vpub_new = vInputsSum; } tx = Constant.CurrentWallet.Perform_JoinSplit(ctx, jsInfo, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)jsInfo.vjsin[0].AssetID, vectorWitness, jsAnchor); jsIndex = 0; SnarkDllApi.Witnesses_Clear(vectorWitness); } if (i == mainTokenInfo.vjsin.Count - 1) { AsyncJoinSplitInfo jsInfo = new AsyncJoinSplitInfo(); Fixed8 jsInputedAmount = Fixed8.Zero; for (int ji = jsIndex - 1; ji > -1; ji--) { jsInfo.vjsin.Add(mainTokenInfo.vjsin[i - ji]); jsInfo.notes.Add(mainTokenInfo.notes[i - ji]); jsInputedAmount += mainTokenInfo.notes[i - ji].value; rest_amount -= mainTokenInfo.notes[i - ji].value; } for (int oti = 0; oti < mainTokenInfo.vjsout.Count; oti++) { if (mainTokenInfo.vjsout[oti].value >= jsInputedAmount) { JSOutput jsOut1 = new JSOutput(mainTokenInfo.vjsout[oti].addr, jsInputedAmount, mainTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); mainTokenInfo.vjsout[oti].value -= jsInputedAmount; jsInputedAmount = Fixed8.Zero; break; } if (mainTokenInfo.vjsout[oti].value < jsInputedAmount) { JSOutput jsOut1 = new JSOutput(mainTokenInfo.vjsout[oti].addr, mainTokenInfo.vjsout[oti].value, mainTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); jsInputedAmount = jsInputedAmount - mainTokenInfo.vjsout[oti].value; mainTokenInfo.vjsout[oti].value = Fixed8.Zero; } } if (jsInputedAmount != Fixed8.Zero) { jsInfo.vpub_new = jsInputedAmount; } try { tx = Constant.CurrentWallet.Perform_JoinSplit(ctx, jsInfo, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)jsInfo.vjsin[0].AssetID, vectorWitness, jsAnchor); } catch (Exception ex) { string strException = ex.Message; throw new InvalidOperationException("JoinSplit Errors"); } if (tx.Inputs == null) { tx.Inputs = new CoinReference[0]; } jsIndex = 0; SnarkDllApi.Witnesses_Clear(vectorWitness); } } #endregion #region Do Process the Fee token part, And when sending the QRG token, then there is no Main token part. for (int i = 0; i < subTokenInfo.vjsin.Count; i++) { IntPtr witness = SnarkDllApi.CmWitness_Create(); SnarkDllApi.SetCMWitnessFromBinary(witness, subTokenInfo.vjsin[i].witness, subTokenInfo.vjsin[i].witness.Length); SnarkDllApi.Witnesses_Add(vectorWitness, witness); IntPtr ptrWitness = SnarkDllApi.GetCMRootFromWitness(witness); byte[] byWRoot = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptrWitness, byWRoot, 0, 32); UInt256 wAnchor = new UInt256(byWRoot); if (jsAnchor != wAnchor) { throw new InvalidOperationException("Anchor is not correct"); } current_inputed_amount += subTokenInfo.vjsin[i].note.value; jsIndex++; if (jsIndex == 2 && i != subTokenInfo.vjsin.Count - 1) { AsyncJoinSplitInfo jsInfo = new AsyncJoinSplitInfo(); jsInfo.vjsin.Add(subTokenInfo.vjsin[i - 1]); jsInfo.vjsin.Add(subTokenInfo.vjsin[i]); jsInfo.notes.Add(subTokenInfo.notes[i - 1]); jsInfo.notes.Add(subTokenInfo.notes[i]); var vInputsSum = jsInfo.vjsin[0].note.value + jsInfo.vjsin[1].note.value; for (int oti = 0; oti < subTokenInfo.vjsout.Count; oti++) { if (subTokenInfo.vjsout[oti].value >= vInputsSum) { JSOutput jsOut1 = new JSOutput(subTokenInfo.vjsout[oti].addr, vInputsSum, subTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); subTokenInfo.vjsout[oti].value -= vInputsSum; vInputsSum = Fixed8.Zero; break; } if (subTokenInfo.vjsout[oti].value < vInputsSum) { JSOutput jsOut1 = new JSOutput(subTokenInfo.vjsout[oti].addr, subTokenInfo.vjsout[oti].value, subTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); vInputsSum = vInputsSum - subTokenInfo.vjsout[oti].value; subTokenInfo.vjsout[oti].value = Fixed8.Zero; } } if (vInputsSum >= Fixed8.Zero) { jsInfo.vpub_new = vInputsSum; } tx = Constant.CurrentWallet.Perform_JoinSplit(ctx, jsInfo, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)jsInfo.vjsin[0].AssetID, vectorWitness, jsAnchor); jsIndex = 0; SnarkDllApi.Witnesses_Clear(vectorWitness); } if (i == subTokenInfo.vjsin.Count - 1) { AsyncJoinSplitInfo jsInfo = new AsyncJoinSplitInfo(); Fixed8 jsInputedAmount = Fixed8.Zero; for (int ji = jsIndex - 1; ji > -1; ji--) { jsInfo.vjsin.Add(subTokenInfo.vjsin[i - ji]); jsInfo.notes.Add(subTokenInfo.notes[i - ji]); jsInputedAmount += subTokenInfo.notes[i - ji].value; rest_amount -= subTokenInfo.notes[i - ji].value; } for (int oti = 0; oti < subTokenInfo.vjsout.Count; oti++) { if (subTokenInfo.vjsout[oti].value >= jsInputedAmount) { JSOutput jsOut1 = new JSOutput(subTokenInfo.vjsout[oti].addr, jsInputedAmount, subTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); subTokenInfo.vjsout[oti].value -= jsInputedAmount; jsInputedAmount = Fixed8.Zero; break; } if (subTokenInfo.vjsout[oti].value < jsInputedAmount) { JSOutput jsOut1 = new JSOutput(subTokenInfo.vjsout[oti].addr, subTokenInfo.vjsout[oti].value, subTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); jsInputedAmount = jsInputedAmount - subTokenInfo.vjsout[oti].value; subTokenInfo.vjsout[oti].value = Fixed8.Zero; } } if (jsInputedAmount != Fixed8.Zero) { jsInfo.vpub_new = jsInputedAmount; } try { tx = Constant.CurrentWallet.Perform_JoinSplit(ctx, jsInfo, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)jsInfo.vjsin[0].AssetID, vectorWitness, jsAnchor); } catch (Exception ex) { string strException = ex.Message; throw new InvalidOperationException("JoinSplit Errors"); } if (tx.Inputs == null) { tx.Inputs = new CoinReference[0]; } jsIndex = 0; SnarkDllApi.Witnesses_Clear(vectorWitness); } } #endregion ctx.joinSplitSig = Sodium.PublicKeyAuth.SignDetached(ctx.JsHash.ToArray(), joinSplitPrivKey_); if (!Sodium.PublicKeyAuth.VerifyDetached(ctx.joinSplitSig, ctx.JsHash.ToArray(), joinSplitPubKey_.ToArray())) { throw new InvalidOperationException("Anchor is not correct"); } } else { throw new InvalidOperationException("Anchor is not correct"); } Helper.SignAndShowInformation(tx); } #endregion #region A -> A else if (fromAddrVersion == Wallet.AnonymouseAddressVersion && toAddrVersion == Wallet.AnonymouseAddressVersion) // A -> A { UInt256 joinSplitPubKey_; byte[] joinSplitPrivKey_; List <TransactionAttribute> attributes = new List <TransactionAttribute>(); tx = new AnonymousContractTransaction(); Fixed8 totalAmount = amount; tx.Scripts = new Witness[0]; tx.Attributes = attributes.ToArray(); Sodium.KeyPair keyPair; keyPair = Sodium.PublicKeyAuth.GenerateKeyPair(); joinSplitPubKey_ = new UInt256(keyPair.PublicKey); joinSplitPrivKey_ = keyPair.PrivateKey; ((AnonymousContractTransaction)tx).joinSplitPubKey = joinSplitPubKey_; AsyncJoinSplitInfo info = new AsyncJoinSplitInfo(); info.vpub_old = Fixed8.Zero; info.vpub_new = Fixed8.Zero; JSOutput jsOut = new JSOutput(Wallet.ToPaymentAddress(toAddress), amount, (UInt256)asset.AssetId); info.vjsout.Add(jsOut); Fixed8 jsInputValue = Fixed8.Zero; IntPtr ptrRoot = SnarkDllApi.GetCMRoot(Blockchain.Default.GetCmMerkleTree()); byte[] byRoot = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptrRoot, byRoot, 0, 32); UInt256 jsAnchor = new UInt256(byRoot); if (tx is AnonymousContractTransaction ctx) { tx = Constant.CurrentWallet.MakeAandATransaction(ctx, fromAddress, info); #region Split token type /* ****************************** Split the info into main token and fee token ********************************** */ AsyncJoinSplitInfo mainTokenInfo = new AsyncJoinSplitInfo(); AsyncJoinSplitInfo subTokenInfo = new AsyncJoinSplitInfo(); Fixed8 main_total_output_amount = Fixed8.Zero; Fixed8 sub_total_output_amount = Fixed8.Zero; for (int i = 0; i < info.vjsin.Count; i++) { if (info.vjsin[i].AssetID == Blockchain.UtilityToken.Hash) { subTokenInfo.vjsin.Add(info.vjsin[i]); subTokenInfo.notes.Add(info.vjsin[i].note); } else { mainTokenInfo.vjsin.Add(info.vjsin[i]); mainTokenInfo.notes.Add(info.vjsin[i].note); } } for (int i = 0; i < info.vjsout.Count; i++) { if (info.vjsout[i].AssetID == Blockchain.UtilityToken.Hash) { subTokenInfo.vjsout.Add(info.vjsout[i]); sub_total_output_amount += info.vjsout[i].value; } else { mainTokenInfo.vjsout.Add(info.vjsout[i]); main_total_output_amount += info.vjsout[i].value; } } /* ****************************** End ********************************** */ #endregion IntPtr vectorWitness = SnarkDllApi.Witnesses_Create(); int jsIndex = 0; Fixed8 current_inputed_amount = Fixed8.Zero; Fixed8 rest_amount = totalAmount; #region Do Process the Main token part for (int i = 0; i < mainTokenInfo.vjsin.Count; i++) { IntPtr witness = SnarkDllApi.CmWitness_Create(); SnarkDllApi.SetCMWitnessFromBinary(witness, mainTokenInfo.vjsin[i].witness, mainTokenInfo.vjsin[i].witness.Length); SnarkDllApi.Witnesses_Add(vectorWitness, witness); IntPtr ptrWitness = SnarkDllApi.GetCMRootFromWitness(witness); byte[] byWRoot = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptrWitness, byWRoot, 0, 32); UInt256 wAnchor = new UInt256(byWRoot); if (jsAnchor != wAnchor) { throw new InvalidOperationException("Anchor is not correct"); } current_inputed_amount += mainTokenInfo.vjsin[i].note.value; jsIndex++; if (jsIndex == 2 && i != mainTokenInfo.vjsin.Count - 1) { AsyncJoinSplitInfo jsInfo = new AsyncJoinSplitInfo(); jsInfo.vjsin.Add(mainTokenInfo.vjsin[i - 1]); jsInfo.vjsin.Add(mainTokenInfo.vjsin[i]); jsInfo.notes.Add(mainTokenInfo.notes[i - 1]); jsInfo.notes.Add(mainTokenInfo.notes[i]); var vInputsSum = jsInfo.vjsin[0].note.value + jsInfo.vjsin[1].note.value; for (int oti = 0; oti < mainTokenInfo.vjsout.Count; oti++) { if (mainTokenInfo.vjsout[oti].value >= vInputsSum) { JSOutput jsOut1 = new JSOutput(mainTokenInfo.vjsout[oti].addr, vInputsSum, mainTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); mainTokenInfo.vjsout[oti].value -= vInputsSum; vInputsSum = Fixed8.Zero; break; } if (mainTokenInfo.vjsout[oti].value < vInputsSum) { JSOutput jsOut1 = new JSOutput(mainTokenInfo.vjsout[oti].addr, mainTokenInfo.vjsout[oti].value, mainTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); vInputsSum = vInputsSum - mainTokenInfo.vjsout[oti].value; mainTokenInfo.vjsout[oti].value = Fixed8.Zero; } } tx = Constant.CurrentWallet.Perform_JoinSplit(ctx, jsInfo, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)jsInfo.vjsin[0].AssetID, vectorWitness, jsAnchor); jsIndex = 0; SnarkDllApi.Witnesses_Clear(vectorWitness); } if (i == mainTokenInfo.vjsin.Count - 1) { AsyncJoinSplitInfo jsInfo = new AsyncJoinSplitInfo(); Fixed8 jsInputedAmount = Fixed8.Zero; for (int ji = jsIndex - 1; ji > -1; ji--) { jsInfo.vjsin.Add(mainTokenInfo.vjsin[i - ji]); jsInfo.notes.Add(mainTokenInfo.notes[i - ji]); jsInputedAmount += mainTokenInfo.notes[i - ji].value; rest_amount -= mainTokenInfo.notes[i - ji].value; } for (int oti = 0; oti < mainTokenInfo.vjsout.Count; oti++) { if (mainTokenInfo.vjsout[oti].value >= jsInputedAmount) { JSOutput jsOut1 = new JSOutput(mainTokenInfo.vjsout[oti].addr, jsInputedAmount, mainTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); mainTokenInfo.vjsout[oti].value -= jsInputedAmount; jsInputedAmount = Fixed8.Zero; break; } if (mainTokenInfo.vjsout[oti].value < jsInputedAmount) { JSOutput jsOut1 = new JSOutput(mainTokenInfo.vjsout[oti].addr, mainTokenInfo.vjsout[oti].value, mainTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); jsInputedAmount = jsInputedAmount - mainTokenInfo.vjsout[oti].value; mainTokenInfo.vjsout[oti].value = Fixed8.Zero; } } if (jsInputedAmount != Fixed8.Zero) { jsInfo.vpub_new = jsInputedAmount; } try { tx = Constant.CurrentWallet.Perform_JoinSplit(ctx, jsInfo, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)jsInfo.vjsin[0].AssetID, vectorWitness, jsAnchor); } catch (Exception ex) { string strException = ex.Message; throw new InvalidOperationException("JoinSplit Errors"); } if (tx.Inputs == null) { tx.Inputs = new CoinReference[0]; } jsIndex = 0; SnarkDllApi.Witnesses_Clear(vectorWitness); } } #endregion #region Do Process the Fee token part, And when sending the QRG token, then there is no Main token part. for (int i = 0; i < subTokenInfo.vjsin.Count; i++) { IntPtr witness = SnarkDllApi.CmWitness_Create(); SnarkDllApi.SetCMWitnessFromBinary(witness, subTokenInfo.vjsin[i].witness, subTokenInfo.vjsin[i].witness.Length); SnarkDllApi.Witnesses_Add(vectorWitness, witness); IntPtr ptrWitness = SnarkDllApi.GetCMRootFromWitness(witness); byte[] byWRoot = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptrWitness, byWRoot, 0, 32); UInt256 wAnchor = new UInt256(byWRoot); if (jsAnchor != wAnchor) { throw new InvalidOperationException("Anchor is not correct"); } current_inputed_amount += subTokenInfo.vjsin[i].note.value; jsIndex++; if (jsIndex == 2 && i != subTokenInfo.vjsin.Count - 1) { AsyncJoinSplitInfo jsInfo = new AsyncJoinSplitInfo(); jsInfo.vjsin.Add(subTokenInfo.vjsin[i - 1]); jsInfo.vjsin.Add(subTokenInfo.vjsin[i]); jsInfo.notes.Add(subTokenInfo.notes[i - 1]); jsInfo.notes.Add(subTokenInfo.notes[i]); var vInputsSum = jsInfo.vjsin[0].note.value + jsInfo.vjsin[1].note.value; for (int oti = 0; oti < subTokenInfo.vjsout.Count; oti++) { if (subTokenInfo.vjsout[oti].value >= vInputsSum) { JSOutput jsOut1 = new JSOutput(subTokenInfo.vjsout[oti].addr, vInputsSum, subTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); subTokenInfo.vjsout[oti].value -= vInputsSum; vInputsSum = Fixed8.Zero; break; } if (subTokenInfo.vjsout[oti].value < vInputsSum) { JSOutput jsOut1 = new JSOutput(subTokenInfo.vjsout[oti].addr, subTokenInfo.vjsout[oti].value, subTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); vInputsSum = vInputsSum - subTokenInfo.vjsout[oti].value; subTokenInfo.vjsout[oti].value = Fixed8.Zero; } } tx = Constant.CurrentWallet.Perform_JoinSplit(ctx, jsInfo, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)jsInfo.vjsin[0].AssetID, vectorWitness, jsAnchor); jsIndex = 0; SnarkDllApi.Witnesses_Clear(vectorWitness); } if (i == subTokenInfo.vjsin.Count - 1) { AsyncJoinSplitInfo jsInfo = new AsyncJoinSplitInfo(); Fixed8 jsInputedAmount = Fixed8.Zero; for (int ji = jsIndex - 1; ji > -1; ji--) { jsInfo.vjsin.Add(subTokenInfo.vjsin[i - ji]); jsInfo.notes.Add(subTokenInfo.notes[i - ji]); jsInputedAmount += subTokenInfo.notes[i - ji].value; rest_amount -= subTokenInfo.notes[i - ji].value; } for (int oti = 0; oti < subTokenInfo.vjsout.Count; oti++) { if (subTokenInfo.vjsout[oti].value >= jsInputedAmount) { JSOutput jsOut1 = new JSOutput(subTokenInfo.vjsout[oti].addr, jsInputedAmount, subTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); subTokenInfo.vjsout[oti].value -= jsInputedAmount; jsInputedAmount = Fixed8.Zero; break; } if (subTokenInfo.vjsout[oti].value < jsInputedAmount) { JSOutput jsOut1 = new JSOutput(subTokenInfo.vjsout[oti].addr, subTokenInfo.vjsout[oti].value, subTokenInfo.vjsout[oti].AssetID); jsInfo.vjsout.Add(jsOut1); jsInputedAmount = jsInputedAmount - subTokenInfo.vjsout[oti].value; subTokenInfo.vjsout[oti].value = Fixed8.Zero; } } if (jsInputedAmount != Fixed8.Zero) { jsInfo.vpub_new = jsInputedAmount; } try { tx = Constant.CurrentWallet.Perform_JoinSplit(ctx, jsInfo, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)jsInfo.vjsin[0].AssetID, vectorWitness, jsAnchor); } catch (Exception ex) { string strException = ex.Message; throw new InvalidOperationException("JoinSplit Errors"); } if (tx.Inputs == null) { tx.Inputs = new CoinReference[0]; } jsIndex = 0; SnarkDllApi.Witnesses_Clear(vectorWitness); } } #endregion ctx.joinSplitSig = Sodium.PublicKeyAuth.SignDetached(ctx.JsHash.ToArray(), joinSplitPrivKey_); if (!Sodium.PublicKeyAuth.VerifyDetached(ctx.joinSplitSig, ctx.JsHash.ToArray(), joinSplitPubKey_.ToArray())) { throw new InvalidOperationException("Anchor is not correct"); } } else { throw new InvalidOperationException("Anchor is not correct"); } Helper.SignAndShowInformation(tx); } #endregion #region S -> S else if (fromAddrVersion == Wallet.StealthAddressVersion && toAddrVersion == Wallet.StealthAddressVersion) { List <TransactionAttribute> attributes = new List <TransactionAttribute>(); tx = new RingConfidentialTransaction(); tx.Attributes = attributes.ToArray(); if (tx is RingConfidentialTransaction ctx) { List <RCTransactionOutput> rctOutput = new List <RCTransactionOutput>(); Pure.Wallets.StealthKey.StealthKeyPair fromKeyPair = null; foreach (KeyPairBase key in Constant.CurrentWallet.GetKeys()) { if (key is Pure.Wallets.StealthKey.StealthKeyPair rctKey) { if (Wallet.ToStealthAddress(rctKey) == fromAddress) { fromKeyPair = rctKey; } } } if (fromKeyPair == null) { throw new InvalidOperationException("From key is not exist."); } byte[] r = SchnorrNonLinkable.GenerateRandomScalar(); Pure.Cryptography.ECC.ECPoint R = Pure.Cryptography.ECC.ECCurve.Secp256r1.G * r; Pure.Wallets.StealthKey.StealthPubKeys outPubKey = Wallet.ToStealthKeyPair(toAddress).ToStelathPubKeys(); RCTransactionOutput output = new RCTransactionOutput { AssetId = (UInt256)asset.AssetId, PubKey = Pure.Cryptography.ECC.ECPoint.DecodePoint(outPubKey.GenPaymentPubKeyHash(r), Pure.Cryptography.ECC.ECCurve.Secp256r1), Value = amount, ScriptHash = Pure.SmartContract.Contract.CreateRingSignatureRedeemScript(outPubKey.PayloadPubKey, outPubKey.ViewPubKey).ToScriptHash() }; rctOutput.Add(output); ctx.Scripts = new Witness[0]; tx = Constant.CurrentWallet.MakeRCTransaction(ctx, fromAddress, rctOutput, fromKeyPair, r); if (tx == null) { throw new InvalidOperationException("Anchor is not correct"); } } Helper.SignAndShowInformation(tx); } #endregion #region T -> S else if (fromAddrVersion == Wallet.AddressVersion && toAddrVersion == Wallet.StealthAddressVersion) { tx = new RingConfidentialTransaction(); List <TransactionAttribute> attributes = new List <TransactionAttribute>(); tx.Attributes = attributes.ToArray(); if (tx is RingConfidentialTransaction rtx) { List <RCTransactionOutput> rctOutput = new List <RCTransactionOutput>(); byte[] r = SchnorrNonLinkable.GenerateRandomScalar(); Pure.Cryptography.ECC.ECPoint R = Pure.Cryptography.ECC.ECCurve.Secp256r1.G * r; Pure.Wallets.StealthKey.StealthPubKeys outPubKey = Wallet.ToStealthKeyPair(toAddress).ToStelathPubKeys(); RCTransactionOutput output = new RCTransactionOutput { AssetId = (UInt256)asset.AssetId, PubKey = Pure.Cryptography.ECC.ECPoint.DecodePoint(outPubKey.GenPaymentPubKeyHash(r), Pure.Cryptography.ECC.ECCurve.Secp256r1), Value = amount, ScriptHash = Pure.SmartContract.Contract.CreateRingSignatureRedeemScript(outPubKey.PayloadPubKey, outPubKey.ViewPubKey).ToScriptHash() }; rctOutput.Add(output); tx = Constant.CurrentWallet.MakeRCTransaction(rtx, fromAddress, rctOutput, null, r); if (tx == null) { throw new InvalidOperationException("Anchor is not correct"); } } Helper.SignAndShowInformation(tx); } #endregion #region S -> T else if (fromAddrVersion == Wallet.StealthAddressVersion && toAddrVersion == Wallet.AddressVersion) { List <TransactionAttribute> attributes = new List <TransactionAttribute>(); tx = new RingConfidentialTransaction(); tx.Attributes = attributes.ToArray(); if (tx is RingConfidentialTransaction ctx) { List <RCTransactionOutput> rctOutput = new List <RCTransactionOutput>(); Pure.Wallets.StealthKey.StealthKeyPair fromKeyPair = null; foreach (KeyPairBase key in Constant.CurrentWallet.GetKeys()) { if (key is Pure.Wallets.StealthKey.StealthKeyPair rctKey) { if (Wallet.ToStealthAddress(rctKey) == fromAddress) { fromKeyPair = rctKey; } } } if (fromKeyPair == null) { throw new InvalidOperationException("From key is not exist."); } byte[] r = SchnorrNonLinkable.GenerateRandomScalar(); Pure.Cryptography.ECC.ECPoint R = Pure.Cryptography.ECC.ECCurve.Secp256r1.G * r; ctx.Scripts = new Witness[0]; TransactionOutput outPut = new TransactionOutput(); outPut.ScriptHash = Wallet.ToScriptHash(toAddress); outPut.Value = amount; outPut.AssetId = (UInt256)asset.AssetId; tx.Outputs = new TransactionOutput[1]; tx.Outputs[0] = outPut; tx = Constant.CurrentWallet.MakeRCTransaction(ctx, fromAddress, rctOutput, fromKeyPair, r); if (tx == null) { throw new InvalidOperationException("Anchor is not correct"); } } Helper.SignAndShowInformation(tx); } #endregion }
private void Persist(Block block) { bool change_cm_merkle_tree = false; WriteBatch batch = new WriteBatch(); DbCache <UInt160, AccountState> accounts = new DbCache <UInt160, AccountState>(db, DataEntryPrefix.ST_Account); DbCache <UInt256, UnspentCoinState> unspentcoins = new DbCache <UInt256, UnspentCoinState>(db, DataEntryPrefix.ST_Coin); DbCache <UInt256, SpentCoinState> spentcoins = new DbCache <UInt256, SpentCoinState>(db, DataEntryPrefix.ST_SpentCoin); DbCache <ECPoint, ValidatorState> validators = new DbCache <ECPoint, ValidatorState>(db, DataEntryPrefix.ST_Validator); DbCache <UInt256, AssetState> assets = new DbCache <UInt256, AssetState>(db, DataEntryPrefix.ST_Asset); DbCache <UInt160, ContractState> contracts = new DbCache <UInt160, ContractState>(db, DataEntryPrefix.ST_Contract); DbCache <StorageKey, StorageItem> storages = new DbCache <StorageKey, StorageItem>(db, DataEntryPrefix.ST_Storage); List <NotifyEventArgs> notifications = new List <NotifyEventArgs>(); long amount_sysfee = GetSysFeeAmount(block.PrevHash) + (long)block.Transactions.Sum(p => p.SystemFee); batch.Put(SliceBuilder.Begin(DataEntryPrefix.DATA_Block).Add(block.Hash), SliceBuilder.Begin().Add(amount_sysfee).Add(block.Trim())); foreach (Transaction tx in block.Transactions) { batch.Put(SliceBuilder.Begin(DataEntryPrefix.DATA_Transaction).Add(tx.Hash), SliceBuilder.Begin().Add(block.Index).Add(tx.ToArray())); unspentcoins.Add(tx.Hash, new UnspentCoinState { Items = Enumerable.Repeat(CoinState.Confirmed, tx.Outputs.Length).ToArray() }); foreach (TransactionOutput output in tx.Outputs) { AccountState account = accounts.GetAndChange(output.ScriptHash, () => new AccountState(output.ScriptHash)); if (account.Balances.ContainsKey(output.AssetId)) { account.Balances[output.AssetId] += output.Value; } else { account.Balances[output.AssetId] = output.Value; } } foreach (var group in tx.Inputs.GroupBy(p => p.PrevHash)) { int height; Transaction tx_prev = GetTransaction(ReadOptions.Default, group.Key, out height); foreach (CoinReference input in group) { unspentcoins.GetAndChange(input.PrevHash).Items[input.PrevIndex] |= CoinState.Spent; if (tx_prev.Outputs[input.PrevIndex].AssetId.Equals(GoverningToken.Hash)) { spentcoins.GetAndChange(input.PrevHash, () => new SpentCoinState { TransactionHash = input.PrevHash, TransactionHeight = (uint)height, Items = new Dictionary <ushort, uint>() }).Items.Add(input.PrevIndex, block.Index); } accounts.GetAndChange(tx_prev.Outputs[input.PrevIndex].ScriptHash).Balances[tx_prev.Outputs[input.PrevIndex].AssetId] -= tx_prev.Outputs[input.PrevIndex].Value; } } switch (tx.Type) { case TransactionType.RingConfidentialTransaction: { if (tx is RingConfidentialTransaction ctx) { for (int i = 0; i < ctx.RingCTSig.Count; i++) { // Add the I Commitment to blockchain. for (int j = 0; j < ctx.RingCTSig[i].MG.II.Count; j++) { batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_RingCTCommitment).Add(ctx.RingCTSig[i].MG.II[j]), SliceBuilder.Begin().Add(ctx.RingCTSig[i].AssetID)); } } } } break; case TransactionType.AnonymousContractTransaction: { if (tx is AnonymousContractTransaction ctx) { for (int jsIndex = 0; jsIndex < ctx.byJoinSplit.Count; jsIndex++) { batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_Nullifier).Add(ctx.Nullifiers(jsIndex)[0]), SliceBuilder.Begin().Add(ctx.Asset_ID(jsIndex))); batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_Nullifier).Add(ctx.Nullifiers(jsIndex)[1]), SliceBuilder.Begin().Add(ctx.Asset_ID(jsIndex))); SnarkDllApi.AppendCommitment(gCmMerkleTree, ctx.Commitments(jsIndex)[0].ToArray()); SnarkDllApi.AppendCommitment(gCmMerkleTree, ctx.Commitments(jsIndex)[1].ToArray()); } change_cm_merkle_tree = true; } } break; case TransactionType.RegisterTransaction: { #pragma warning disable CS0612 RegisterTransaction rtx = (RegisterTransaction)tx; assets.Add(tx.Hash, new AssetState { AssetId = rtx.Hash, AssetType = rtx.AssetType, Name = rtx.Name, Amount = rtx.Amount, Available = Fixed8.Zero, Precision = rtx.Precision, Fee = rtx.T_Fee, FeeMin = rtx.T_Fee_Min, FeeMax = rtx.T_Fee_Max, AFee = rtx.A_Fee, FeeAddress = new UInt160(), Owner = rtx.Owner, Admin = rtx.Admin, Issuer = rtx.Admin, Expiration = block.Index + 2 * 2000000, IsFrozen = false }); #pragma warning restore CS0612 } break; case TransactionType.IssueTransaction: foreach (TransactionResult result in tx.GetTransactionResults().Where(p => p.Amount < Fixed8.Zero)) { assets.GetAndChange(result.AssetId).Available -= result.Amount; } break; case TransactionType.ClaimTransaction: foreach (CoinReference input in ((ClaimTransaction)tx).Claims) { if (spentcoins.TryGet(input.PrevHash)?.Items.Remove(input.PrevIndex) == true) { spentcoins.GetAndChange(input.PrevHash); } } break; case TransactionType.EnrollmentTransaction: { #pragma warning disable CS0612 EnrollmentTransaction enroll_tx = (EnrollmentTransaction)tx; validators.GetOrAdd(enroll_tx.PublicKey, () => new ValidatorState { PublicKey = enroll_tx.PublicKey }); #pragma warning restore CS0612 } break; case TransactionType.PublishTransaction: { #pragma warning disable CS0612 PublishTransaction publish_tx = (PublishTransaction)tx; contracts.GetOrAdd(publish_tx.ScriptHash, () => new ContractState { Script = publish_tx.Script, ParameterList = publish_tx.ParameterList, ReturnType = publish_tx.ReturnType, HasStorage = publish_tx.NeedStorage, Name = publish_tx.Name, CodeVersion = publish_tx.CodeVersion, Author = publish_tx.Author, Email = publish_tx.Email, Description = publish_tx.Description }); #pragma warning restore CS0612 } break; case TransactionType.InvocationTransaction: { InvocationTransaction itx = (InvocationTransaction)tx; CachedScriptTable script_table = new CachedScriptTable(contracts); StateMachine service = new StateMachine(accounts, validators, assets, contracts, storages); ApplicationEngine engine = new ApplicationEngine(TriggerType.Application, itx, script_table, service, itx.Gas); engine.LoadScript(itx.Script, false); if (engine.Execute()) { service.Commit(); notifications.AddRange(service.Notifications); } } break; } } if (change_cm_merkle_tree == true) { int[] outLen = new int[1]; outLen[0] = 0; IntPtr ptrTree = SnarkDllApi.GetCMTreeInBinary(gCmMerkleTree, outLen); byte[] byTree = new byte[outLen[0]]; System.Runtime.InteropServices.Marshal.Copy(ptrTree, byTree, 0, outLen[0]); IntPtr ptrRt1 = SnarkDllApi.GetCMRoot(gCmMerkleTree); byte[] by_rt = new byte[32]; System.Runtime.InteropServices.Marshal.Copy(ptrRt1, by_rt, 0, 32); UInt256 current_rt = new UInt256(by_rt); db.Put(WriteOptions.Default, SliceBuilder.Begin(DataEntryPrefix.AM_CmMerkleTree), byTree); mCmMerkleRoots.Add(current_rt); while ((int)mCmMerkleRoots.Count - 5 >= stored_cm_root_count) { using (MemoryStream ms = new MemoryStream()) using (BinaryWriter w = new BinaryWriter(ms)) { w.Write(mCmMerkleRoots.Skip((int)stored_cm_root_count).Take(5).ToArray()); w.Flush(); batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_MerkleRoot).Add(stored_cm_root_count), ms.ToArray()); } stored_cm_root_count += 5; } if (mCmMerkleRoots.Count > stored_cm_root_count) { using (MemoryStream ms = new MemoryStream()) using (BinaryWriter w = new BinaryWriter(ms)) { w.Write(mCmMerkleRoots.Skip((int)stored_cm_root_count).ToArray()); w.Flush(); batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_MerkleRoot).Add(stored_cm_root_count), ms.ToArray()); } } } if (notifications.Count > 0) { OnNotify(block, notifications.ToArray()); } accounts.DeleteWhere((k, v) => !v.IsFrozen && v.Votes.Length == 0 && v.Balances.All(p => p.Value <= Fixed8.Zero)); accounts.Commit(batch); unspentcoins.DeleteWhere((k, v) => v.Items.All(p => p.HasFlag(CoinState.Spent))); unspentcoins.Commit(batch); spentcoins.DeleteWhere((k, v) => v.Items.Count == 0); spentcoins.Commit(batch); validators.Commit(batch); assets.Commit(batch); contracts.Commit(batch); storages.Commit(batch); batch.Put(SliceBuilder.Begin(DataEntryPrefix.SYS_CurrentBlock), SliceBuilder.Begin().Add(block.Hash).Add(block.Index)); db.Write(WriteOptions.Default, batch); current_block_height = block.Index; }
public LevelDBBlockchain(string path) { header_index.Add(GenesisBlock.Hash); Version version; Slice value; db = DB.Open(path, new Options { CreateIfMissing = true }); gCmMerkleTree = SnarkDllApi.CmMerkleTree_Create(); Slice cmValue; if (db.TryGet(ReadOptions.Default, SliceBuilder.Begin(DataEntryPrefix.AM_CmMerkleTree), out cmValue)) { byCMMerkleTree = cmValue.ToArray(); SnarkDllApi.SetCMTreeFromBinary(gCmMerkleTree, byCMMerkleTree, byCMMerkleTree.Length); } if (db.TryGet(ReadOptions.Default, SliceBuilder.Begin(DataEntryPrefix.SYS_Version), out value) && Version.TryParse(value.ToString(), out version) && version >= Version.Parse("1.1")) { ReadOptions options = new ReadOptions { FillCache = false }; value = db.Get(options, SliceBuilder.Begin(DataEntryPrefix.SYS_CurrentBlock)); UInt256 current_header_hash = new UInt256(value.ToArray().Take(32).ToArray()); this.current_block_height = value.ToArray().ToUInt32(32); uint current_header_height = current_block_height; if (db.TryGet(options, SliceBuilder.Begin(DataEntryPrefix.SYS_CurrentHeader), out value)) { current_header_hash = new UInt256(value.ToArray().Take(32).ToArray()); current_header_height = value.ToArray().ToUInt32(32); } foreach (UInt256 hash in db.Find(options, SliceBuilder.Begin(DataEntryPrefix.IX_HeaderHashList), (k, v) => { using (MemoryStream ms = new MemoryStream(v.ToArray(), false)) using (BinaryReader r = new BinaryReader(ms)) { return(new { Index = k.ToArray().ToUInt32(1), Hashes = r.ReadSerializableArray <UInt256>() }); } }).OrderBy(p => p.Index).SelectMany(p => p.Hashes).ToArray()) { if (!hash.Equals(GenesisBlock.Hash)) { header_index.Add(hash); } stored_header_count++; } if (stored_header_count == 0) { Header[] headers = db.Find( options, SliceBuilder.Begin(DataEntryPrefix.DATA_Block), (k, v) => Header.FromTrimmedData(v.ToArray(), sizeof(long)) ).OrderBy(p => p.Index).ToArray(); for (int i = 1; i < headers.Length; i++) { header_index.Add(headers[i].Hash); } } else if (current_header_height >= stored_header_count) { for (UInt256 hash = current_header_hash; hash != header_index[(int)stored_header_count - 1];) { Header header = Header.FromTrimmedData(db.Get(options, SliceBuilder.Begin(DataEntryPrefix.DATA_Block).Add(hash)).ToArray(), sizeof(long)); header_index.Insert((int)stored_header_count, hash); hash = header.PrevHash; } } foreach (UInt256 hash in db.Find(options, SliceBuilder.Begin(DataEntryPrefix.ST_MerkleRoot), (k, v) => { using (MemoryStream ms = new MemoryStream(v.ToArray(), false)) using (BinaryReader r = new BinaryReader(ms)) { return(new { Index = k.ToArray().ToUInt32(1), Hashes = r.ReadSerializableArray <UInt256>() }); } }).OrderBy(p => p.Index).SelectMany(p => p.Hashes).ToArray()) { mCmMerkleRoots.Add(hash); stored_cm_root_count = (uint)(mCmMerkleRoots.Count / 5) * 5; } } else { WriteBatch batch = new WriteBatch(); ReadOptions options = new ReadOptions { FillCache = false }; using (Iterator it = db.NewIterator(options)) { for (it.SeekToFirst(); it.Valid(); it.Next()) { batch.Delete(it.Key()); } } db.Write(WriteOptions.Default, batch); Persist(GenesisBlock); db.Put(WriteOptions.Default, SliceBuilder.Begin(DataEntryPrefix.SYS_Version), GetType().GetTypeInfo().Assembly.GetName().Version.ToString()); } thread_persistence = new Thread(PersistBlocks); thread_persistence.Name = "LevelDBBlockchain.PersistBlocks"; thread_persistence.Start(); }
private void Event_SendCoinSuccess(object sender, EventArgs e) { Global.AssetDescriptor asset = sendcoinsPan1.GetAsset() as Global.AssetDescriptor; string fromAddress = sendcoinsPan1.GetFromAddress(); string toAddress = sendcoinsPan1.GetRecieveAddress(); string strAmount = sendcoinsPan1.GetAmount(); byte toAddrVersion; byte fromAddrVersion; if (asset == null) { return; } if (!Fixed8.TryParse(strAmount, out Fixed8 amount)) { return; } if (amount == Fixed8.Zero) { return; } if (amount.GetData() % (long)Math.Pow(10, 8 - (sendcoinsPan1.GetAsset() as Global.AssetDescriptor).Precision) != 0) { return; } try { fromAddrVersion = Wallet.GetAddressVersion(fromAddress); toAddrVersion = Wallet.GetAddressVersion(toAddress); } catch { return; } Transaction tx; if (toAddrVersion == Wallet.AddressVersion && fromAddrVersion == Wallet.AddressVersion) { List <TransactionAttribute> attributes = new List <TransactionAttribute>(); tx = new ContractTransaction(); //if (!string.IsNullOrEmpty(remark)) // attributes.Add(new TransactionAttribute // { // Usage = TransactionAttributeUsage.Remark, // Data = Encoding.UTF8.GetBytes(remark) // }); tx.Attributes = attributes.ToArray(); TransactionOutput outPut = new TransactionOutput(); outPut.ScriptHash = Wallet.ToScriptHash(toAddress); outPut.Value = amount; outPut.AssetId = (UInt256)asset.AssetId; tx.Outputs = new TransactionOutput[1]; tx.Outputs[0] = outPut; if (tx is ContractTransaction ctx) { tx = Constant.CurrentWallet.MakeTransactionFrom(ctx, fromAddress); } /* * if (tx is InvocationTransaction itx) * { * using (InvokeContractDialog dialog = new InvokeContractDialog(itx)) * { * if (dialog.ShowDialog() != DialogResult.OK) return; * tx = dialog.GetTransaction(); * } * } */ Helper.SignAndShowInformation(tx); } else if (toAddrVersion == Wallet.AnonymouseAddressVersion) { UInt256 joinSplitPubKey_; byte[] joinSplitPrivKey_; List <TransactionAttribute> attributes = new List <TransactionAttribute>(); tx = new AnonymousContractTransaction(); tx.Attributes = attributes.ToArray(); Sodium.KeyPair keyPair; keyPair = Sodium.PublicKeyAuth.GenerateKeyPair(); joinSplitPubKey_ = new UInt256(keyPair.PublicKey); joinSplitPrivKey_ = keyPair.PrivateKey; ((AnonymousContractTransaction)tx).joinSplitPubKey = joinSplitPubKey_; AsyncJoinSplitInfo info = new AsyncJoinSplitInfo(); info.vpub_old = new Fixed8(0); info.vpub_new = new Fixed8(0); JSOutput jsOut = new JSOutput(Wallet.ToPaymentAddress(toAddress), amount, (UInt256)asset.AssetId); info.vjsout.Add(jsOut); info.vpub_old += amount; if (tx is AnonymousContractTransaction ctx) { tx = Constant.CurrentWallet.MakeTandATransaction(ctx, fromAddress, info); if (tx is AnonymousContractTransaction ctx_) { IntPtr w = SnarkDllApi.Witnesses_Create(); UInt256 anchor = new UInt256(); tx = Constant.CurrentWallet.Perform_JoinSplit(ctx_, info, joinSplitPubKey_, joinSplitPrivKey_, (UInt256)asset.AssetId, w, anchor); } } Helper.SignAndShowInformation(tx); } }
private void MainForm_Load(object sender, EventArgs e) { string vkKeyPath = Settings.Default.VkKeyPath; string pkKeyPath = Settings.Default.PkKeyPath; vkKeyPath = Path.GetFullPath(vkKeyPath); pkKeyPath = Path.GetFullPath(pkKeyPath); int ret = SnarkDllApi.Snark_DllInit(1, vkKeyPath.ToArray(), pkKeyPath.ToArray()); if (ret > 0) { Invoke(new Action(() => { lbl_status.Text = "Verify key was loaded."; })); Task.Run(() => { Invoke(new Action(() => { lbl_status.Text = "Loading PK..."; })); vkKeyPath = Settings.Default.VkKeyPath; pkKeyPath = Settings.Default.PkKeyPath; vkKeyPath = Path.GetFullPath(vkKeyPath); pkKeyPath = Path.GetFullPath(pkKeyPath); ret = SnarkDllApi.Snark_DllInit(2, vkKeyPath.ToArray(), pkKeyPath.ToArray()); if (ret > 0) { Invoke(new Action(() => { lbl_status.Text = "Loading PK Successed!"; })); } else { Invoke(new Action(() => { lbl_status.Text = "Loading PK Failed!" + ret.ToString(); })); } }); } else { Invoke(new Action(() => { lbl_status.Text = "Loading verify key was failed" + ret.ToString(); })); } Task.Run(() => { const string acc_path = "chain.acc"; const string acc_zip_path = acc_path + ".zip"; if (File.Exists(acc_path)) { using (FileStream fs = new FileStream(acc_path, FileMode.Open, FileAccess.Read, FileShare.None)) { ImportBlocks(fs); } File.Delete(acc_path); } else if (File.Exists(acc_zip_path)) { using (FileStream fs = new FileStream(acc_zip_path, FileMode.Open, FileAccess.Read, FileShare.None)) using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) using (Stream zs = zip.GetEntry(acc_path).Open()) { ImportBlocks(zs); } File.Delete(acc_zip_path); } Blockchain.PersistCompleted += Blockchain_PersistCompleted; Constant.LocalNode.Start(Settings.Default.NodePort, Settings.Default.WsPort); }); LoadAddrbook(); LoadAssets(); }