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());
        }
Exemple #6
0
        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);
            }
        }
Exemple #8
0
        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();
                    }));
                }
            });
        }
Exemple #9
0
        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;
                        }));
                    }
                });
            }
        }
Exemple #10
0
        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;
                }
            });
        }
Exemple #11
0
        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();
        }
Exemple #15
0
        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);
            }
        }
Exemple #16
0
        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();
        }