Ejemplo n.º 1
0
 /// <summary>
 /// 验证交易
 /// </summary>
 /// <returns>返回验证后的结果</returns>
 public override bool Verify(IEnumerable<Transaction> mempool)
 {
     if (!base.Verify(mempool)) return false;
     TransactionResult[] results = GetTransactionResults()?.Where(p => p.Amount < Fixed8.Zero).ToArray();
     if (results == null) return false;
     foreach (TransactionResult r in results)
     {
         AssetState asset = Blockchain.Default.GetAssetState(r.AssetId);
         if (asset == null) return false;
         if (asset.Amount < Fixed8.Zero) continue;
         Fixed8 quantity_issued = asset.Available + mempool.OfType<IssueTransaction>().Where(p => p != this).SelectMany(p => p.Outputs).Where(p => p.AssetId == r.AssetId).Sum(p => p.Value);
         if (asset.Amount - quantity_issued < -r.Amount) return false;
     }
     return true;
 }
Ejemplo n.º 2
0
        public override UInt160[] GetScriptHashesForVerifying()
        {
            HashSet <UInt160> hashes = new HashSet <UInt160>(base.GetScriptHashesForVerifying());

            foreach (TransactionResult result in GetTransactionResults().Where(p => p.Amount < Fixed8.Zero))
            {
                AssetState asset = Blockchain.Default.GetAssetState(result.AssetId);
                if (asset == null)
                {
                    throw new InvalidOperationException();
                }
                hashes.Add(asset.Issuer);
            }
            return(hashes.OrderBy(p => p).ToArray());
        }
Ejemplo n.º 3
0
        /// <summary>
        /// 获取需要校验的脚本散列值
        /// </summary>
        /// <returns>返回需要校验的脚本散列值</returns>
        public virtual UInt160[] GetScriptHashesForVerifying()
        {
            if (References == null)
            {
                throw new InvalidOperationException();
            }
            HashSet <UInt160> hashes = new HashSet <UInt160>(Inputs.Select(p => References[p].ScriptHash));

            hashes.UnionWith(Attributes.Where(p => p.Usage == TransactionAttributeUsage.Script).Select(p => new UInt160(p.Data)));
            foreach (var group in Outputs.GroupBy(p => p.AssetId))
            {
                AssetState asset = Blockchain.Default.GetAssetState(group.Key);
                if (asset == null)
                {
                    throw new InvalidOperationException();
                }
                if (asset.AssetType.HasFlag(AssetType.DutyFlag))
                {
                    hashes.UnionWith(group.Select(p => p.ScriptHash));
                }
            }
            return(hashes.OrderBy(p => p).ToArray());
        }
Ejemplo n.º 4
0
        public static Dictionary <UInt256, Fixed8> CalculateNetFee(IEnumerable <Transaction> transactions)
        {
            Dictionary <UInt256, Fixed8> ret = new Dictionary <UInt256, Fixed8>();

            #region Calculate QRG fee
            {
                Transaction[] ts            = transactions.Where(p => p.Type != TransactionType.MinerTransaction && p.Type != TransactionType.ClaimTransaction && p.Type != TransactionType.AnonymousContractTransaction).ToArray();
                Fixed8        amount_in     = ts.SelectMany(p => p.References.Values.Where(o => o.AssetId == Blockchain.UtilityToken.Hash)).Sum(p => p.Value);
                Fixed8        amount_out    = ts.SelectMany(p => p.Outputs.Where(o => o.AssetId == Blockchain.UtilityToken.Hash)).Sum(p => p.Value);
                Fixed8        amount_sysfee = ts.Sum(p => p.SystemFee);
                Fixed8        normalFee     = amount_in - amount_out;

                Transaction[] ats         = transactions.Where(p => p.Type == TransactionType.AnonymousContractTransaction && p.Inputs.Length == 0).ToArray();
                Fixed8        v_pubNewSum = Fixed8.Zero;
                Fixed8        outAmount   = ats.SelectMany(p => p.Outputs.Where(o => o.AssetId == Blockchain.UtilityToken.Hash)).Sum(p => p.Value);

                foreach (var atx in ats)
                {
                    if (atx is AnonymousContractTransaction)
                    {
                        var formatedTx = atx as AnonymousContractTransaction;
                        for (int i = 0; i < formatedTx.byJoinSplit.Count; i++)
                        {
                            if (formatedTx.Asset_ID(i) == Blockchain.UtilityToken.Hash)
                            {
                                v_pubNewSum += formatedTx.vPub_New(i);
                            }
                        }
                    }
                }

                Fixed8        anonymousFee = v_pubNewSum - outAmount;
                Fixed8        totalQrgFee  = normalFee + anonymousFee;
                Transaction[] feeTxs       = transactions.Where(p => p.Type != TransactionType.MinerTransaction && p.Type != TransactionType.ClaimTransaction).ToArray();

                foreach (var tx in feeTxs)
                {
                    Dictionary <UInt256, Fixed8> fee = new Dictionary <UInt256, Fixed8>();
                    if (tx.Type != TransactionType.AnonymousContractTransaction)
                    {
                        foreach (var txOut in tx.Outputs)
                        {
                            if (txOut.AssetId != Blockchain.GoverningToken.Hash)
                            {
                                if (!fee.ContainsKey(txOut.AssetId))
                                {
                                    AssetState asset = Blockchain.Default.GetAssetState(txOut.AssetId);
                                    fee[txOut.AssetId] = asset.Fee;
                                }
                            }
                        }
                    }
                    else if (tx.Type == TransactionType.AnonymousContractTransaction && tx.Inputs.Length > 0)
                    {
                        var atx = tx as AnonymousContractTransaction;

                        for (int i = 0; i < atx.byJoinSplit.Count; i++)
                        {
                            if (atx.Asset_ID(i) != Blockchain.GoverningToken.Hash)
                            {
                                if (!fee.ContainsKey(atx.Asset_ID(i)))
                                {
                                    AssetState asset = Blockchain.Default.GetAssetState(atx.Asset_ID(i));
                                    fee[asset.AssetId] = asset.Fee;
                                }
                            }
                        }
                    }
                    else
                    {
                        var atx = tx as AnonymousContractTransaction;

                        for (int i = 0; i < atx.byJoinSplit.Count; i++)
                        {
                            if (atx.Asset_ID(i) != Blockchain.GoverningToken.Hash)
                            {
                                if (!fee.ContainsKey(atx.Asset_ID(i)))
                                {
                                    AssetState asset = Blockchain.Default.GetAssetState(atx.Asset_ID(i));
                                    fee[asset.AssetId] = asset.AFee;
                                }
                            }
                        }
                    }

                    foreach (var key in fee.Keys)
                    {
                        if (ret.ContainsKey(key))
                        {
                            ret[key] += fee[key];
                        }
                        else
                        {
                            ret[key] = fee[key];
                        }
                    }
                }

                Fixed8 qrgAssetFee = ret.Sum(p => p.Value);

                if (ret.ContainsKey(Blockchain.UtilityToken.Hash))
                {
                    ret[Blockchain.UtilityToken.Hash] = ret[Blockchain.UtilityToken.Hash] + totalQrgFee - qrgAssetFee;
                }
                else
                {
                    ret[Blockchain.UtilityToken.Hash] = totalQrgFee - qrgAssetFee;
                }
            }

            #endregion

            #region Calculate QRS Fee
            {
                Transaction[] ts            = transactions.Where(p => p.Type != TransactionType.MinerTransaction && p.Type != TransactionType.ClaimTransaction && p.Type != TransactionType.AnonymousContractTransaction).ToArray();
                Fixed8        amount_in     = ts.SelectMany(p => p.References.Values.Where(o => o.AssetId == Blockchain.GoverningToken.Hash)).Sum(p => p.Value);
                Fixed8        amount_out    = ts.SelectMany(p => p.Outputs.Where(o => o.AssetId == Blockchain.GoverningToken.Hash)).Sum(p => p.Value);
                Fixed8        amount_sysfee = ts.Sum(p => p.SystemFee);
                Fixed8        normalFee     = amount_in - amount_out;

                Transaction[] ats         = transactions.Where(p => p.Type == TransactionType.AnonymousContractTransaction && p.Inputs.Length == 0).ToArray();
                Fixed8        v_pubNewSum = Fixed8.Zero;
                Fixed8        outAmount   = ats.SelectMany(p => p.Outputs.Where(o => o.AssetId == Blockchain.GoverningToken.Hash)).Sum(p => p.Value);

                foreach (var atx in ats)
                {
                    if (atx is AnonymousContractTransaction)
                    {
                        var formatedTx = atx as AnonymousContractTransaction;
                        for (int i = 0; i < formatedTx.byJoinSplit.Count; i++)
                        {
                            if (formatedTx.Asset_ID(i) == Blockchain.GoverningToken.Hash)
                            {
                                v_pubNewSum += formatedTx.vPub_New(i);
                            }
                        }
                    }
                }

                Fixed8        anonymousFee = v_pubNewSum - outAmount;
                Fixed8        totalQrsFee  = normalFee + anonymousFee;
                Transaction[] feeTxs       = transactions.Where(p => p.Type != TransactionType.MinerTransaction && p.Type != TransactionType.ClaimTransaction).ToArray();

                foreach (var tx in feeTxs)
                {
                    Dictionary <UInt256, Fixed8> fee = new Dictionary <UInt256, Fixed8>();
                    if (tx.Type != TransactionType.AnonymousContractTransaction)
                    {
                        foreach (var txOut in tx.Outputs)
                        {
                            if (txOut.AssetId == Blockchain.GoverningToken.Hash)
                            {
                                if (!fee.ContainsKey(txOut.AssetId))
                                {
                                    AssetState asset = Blockchain.Default.GetAssetState(txOut.AssetId);
                                    fee[txOut.AssetId] = asset.Fee;
                                }
                            }
                        }
                    }
                    else if (tx.Type == TransactionType.AnonymousContractTransaction && tx.Inputs.Length > 0)
                    {
                        var atx = tx as AnonymousContractTransaction;

                        for (int i = 0; i < atx.byJoinSplit.Count; i++)
                        {
                            if (atx.Asset_ID(i) == Blockchain.GoverningToken.Hash)
                            {
                                if (!fee.ContainsKey(atx.Asset_ID(i)))
                                {
                                    AssetState asset = Blockchain.Default.GetAssetState(atx.Asset_ID(i));
                                    fee[asset.AssetId] = asset.Fee;
                                }
                            }
                        }
                    }
                    else
                    {
                        var atx = tx as AnonymousContractTransaction;

                        for (int i = 0; i < atx.byJoinSplit.Count; i++)
                        {
                            if (atx.Asset_ID(i) == Blockchain.GoverningToken.Hash)
                            {
                                if (!fee.ContainsKey(atx.Asset_ID(i)))
                                {
                                    AssetState asset = Blockchain.Default.GetAssetState(atx.Asset_ID(i));
                                    fee[asset.AssetId] = asset.AFee;
                                }
                            }
                        }
                    }

                    foreach (var key in fee.Keys)
                    {
                        if (ret.ContainsKey(key))
                        {
                            ret[key] += fee[key];
                        }
                        else
                        {
                            ret[key] = fee[key];
                        }
                    }
                }

                Fixed8 qrsAssetFee = ret.Sum(p => p.Value);

                if (ret.ContainsKey(Blockchain.GoverningToken.Hash))
                {
                    ret[Blockchain.GoverningToken.Hash] = ret[Blockchain.UtilityToken.Hash] + totalQrsFee - qrsAssetFee;
                }
                else
                {
                    ret[Blockchain.GoverningToken.Hash] = totalQrsFee - qrsAssetFee;
                }
            }
            #endregion

            Dictionary <UInt256, Fixed8> retFees = new Dictionary <UInt256, Fixed8>();
            foreach (var key in ret.Keys)
            {
                if (ret[key] > Fixed8.Zero)
                {
                    retFees[key] = ret[key];
                }
            }

            return(retFees);
        }
Ejemplo n.º 5
0
        public bool Verify(bool completely)
        {
            if (!Verify())
            {
                return(false);
            }
            if (Transactions[0].Type != TransactionType.MinerTransaction || Transactions.Skip(1).Any(p => p.Type == TransactionType.MinerTransaction))
            {
                return(false);
            }
            if (completely)
            {
                if (NextConsensus != Blockchain.GetConsensusAddress(Blockchain.Default.GetValidators(Transactions).ToArray()))
                {
                    return(false);
                }
                foreach (Transaction tx in Transactions)
                {
                    if (!tx.Verify(Transactions.Where(p => !p.Hash.Equals(tx.Hash))))
                    {
                        return(false);
                    }
                }
                Transaction tx_gen = Transactions.FirstOrDefault(p => p.Type == TransactionType.MinerTransaction);

                Dictionary <UInt256, Fixed8> assetFee = CalculateNetFee(Transactions);

                foreach (var key in assetFee.Keys)
                {
                    AssetState asset = Blockchain.Default.GetAssetState(key);

                    if (asset.AssetId == Blockchain.GoverningToken.Hash)
                    {
                        if (tx_gen?.Outputs.Where(p => p.AssetId == Blockchain.GoverningToken.Hash).Sum(p => p.Value) != assetFee[key])
                        {
                            return(false);
                        }
                    }
                    else if (asset.AssetId == Blockchain.UtilityToken.Hash)
                    {
                        if (tx_gen?.Outputs.Where(p => p.AssetId == Blockchain.UtilityToken.Hash).Sum(p => p.Value) != assetFee.Where(p => p.Key != Blockchain.GoverningToken.Hash).Sum(p => p.Value))
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        Fixed8 consensusFee  = Fixed8.Zero;
                        Fixed8 assetOwnerFee = Fixed8.Zero;

                        if (assetFee[key] <= Fixed8.One)
                        {
                            consensusFee  = assetFee[key] * 3 / 10;
                            assetOwnerFee = assetFee[key] * 7 / 10;
                        }
                        else if (assetFee[key] > Fixed8.One * 1)
                        {
                            consensusFee  = assetFee[key] * 4 / 10;
                            assetOwnerFee = assetFee[key] * 6 / 10;
                        }

                        if (tx_gen?.Outputs.Where(p => p.ScriptHash == asset.FeeAddress).Sum(p => p.Value) != assetOwnerFee)
                        {
                            return(false);
                        }
                    }
                }
                // if (tx_gen?.Outputs.Sum(p => p.Value) != CalculateNetFee(Transactions)) return false;
            }
            return(true);
        }
Ejemplo n.º 6
0
        public static Dictionary <UInt256, Fixed8> CalculateNetFee(IEnumerable <Transaction> transactions)
        {
            Dictionary <UInt256, Fixed8> ret = new Dictionary <UInt256, Fixed8>();

            #region Calculate QRG fee
            {
                Transaction[] ats = transactions.Where(p => p.Type == TransactionType.AnonymousContractTransaction).ToArray();

                Transaction[] ars = transactions.Where(p => p.Type == TransactionType.RingConfidentialTransaction).ToArray();

                foreach (var arx in ars)
                {
                    if (arx is RingConfidentialTransaction)
                    {
                        var ringTR = arx as RingConfidentialTransaction;
                        if (ringTR.RingCTSig.Count > 0)
                        {
                            AssetState asset = Blockchain.Default.GetAssetState(ringTR.RingCTSig[0].AssetID);

                            if (ret.ContainsKey(asset.AssetId))
                            {
                                ret[asset.AssetId] += asset.AFee;
                            }
                            else
                            {
                                ret[asset.AssetId] = asset.AFee;
                            }
                        }
                    }
                }

                foreach (var atx in ats)
                {
                    if (atx is AnonymousContractTransaction)
                    {
                        var formatedTx = atx as AnonymousContractTransaction;
                        if (formatedTx.Outputs.Length > 0)
                        {
                            AssetState asset = Blockchain.Default.GetAssetState(formatedTx.Outputs[0].AssetId);

                            if (ret.ContainsKey(asset.AssetId))
                            {
                                ret[asset.AssetId] += asset.AFee;
                            }
                            else
                            {
                                ret[asset.AssetId] = asset.AFee;
                            }
                        }
                        else
                        {
                            AssetState asset = Blockchain.Default.GetAssetState(((AnonymousContractTransaction)formatedTx).Asset_ID(0));
                            if (ret.ContainsKey(asset.AssetId))
                            {
                                ret[asset.AssetId] += asset.AFee;
                            }
                            else
                            {
                                ret[asset.AssetId] = asset.AFee;
                            }
                        }
                    }
                }

                Transaction[] invocationTxs = transactions.Where(p => p.Type == TransactionType.InvocationTransaction).ToArray();

                foreach (var tx in invocationTxs)
                {
                    if (ret.ContainsKey(Blockchain.UtilityToken.Hash))
                    {
                        ret[Blockchain.UtilityToken.Hash] += ((InvocationTransaction)tx).Gas;
                    }
                    else
                    {
                        ret[Blockchain.UtilityToken.Hash] = ((InvocationTransaction)tx).Gas;
                    }
                }

                Transaction[] issueTxs = transactions.Where(p => p.Type == TransactionType.IssueTransaction).ToArray();

                foreach (var tx in issueTxs)
                {
                    IssueTransaction tempTx = (IssueTransaction)tx;
                    if (ret.ContainsKey(Blockchain.UtilityToken.Hash))
                    {
                        ret[Blockchain.UtilityToken.Hash] += tempTx.NetworkFee + tempTx.SystemFee;
                    }
                    else
                    {
                        ret[Blockchain.UtilityToken.Hash] = tempTx.NetworkFee + tempTx.SystemFee;
                    }
                }

                Transaction[] feeTxs = transactions.Where(p => p.Type != TransactionType.MinerTransaction &&
                                                          p.Type != TransactionType.ClaimTransaction &&
                                                          p.Type != TransactionType.AnonymousContractTransaction &&
                                                          p.Type != TransactionType.RingConfidentialTransaction &&
                                                          p.Type != TransactionType.InvocationTransaction &&
                                                          p.Type != TransactionType.IssueTransaction).ToArray();

                foreach (var tx in feeTxs)
                {
                    Dictionary <UInt256, Fixed8> fee = new Dictionary <UInt256, Fixed8>();

                    foreach (var txOut in tx.Outputs)
                    {
                        if (!ret.ContainsKey(txOut.AssetId))
                        {
                            ret[txOut.AssetId] = txOut.Fee;
                        }
                        else
                        {
                            ret[txOut.AssetId] += txOut.Fee;
                        }
                    }
                }
            }

            #endregion

            Dictionary <UInt256, Fixed8> retFees = new Dictionary <UInt256, Fixed8>();
            foreach (var key in ret.Keys)
            {
                if (ret[key] > Fixed8.Zero)
                {
                    retFees[key] = ret[key];
                }
            }

            return(retFees);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// 验证交易
        /// </summary>
        /// <returns>返回验证的结果</returns>
        public virtual bool Verify(IEnumerable <Transaction> mempool)
        {
            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);
            }
            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 = GetTransactionResults()?.ToArray();
            if (results == null)
            {
                return(false);
            }
            TransactionResult[] results_destroy = results.Where(p => p.Amount > Fixed8.Zero).ToArray();
            if (results_destroy.Length > 1)
            {
                return(false);
            }
            if (results_destroy.Length == 1 && results_destroy[0].AssetId != Blockchain.UtilityToken.Hash)
            {
                return(false);
            }
            if (SystemFee > Fixed8.Zero && (results_destroy.Length == 0 || results_destroy[0].Amount < SystemFee))
            {
                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);
            }
            return(this.VerifyScripts());
        }
        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 || (QrsSystemFee > result_qrs_fee) || (SystemFee > result_qrg_fee && assetFee > Fixed8.Zero))
            {
                return(false);
            }

            /*
             * if (qrsAssetFee == Fixed8.Zero)
             * {
             *  if (SystemFee + assetFee > Fixed8.Zero && (results_destroy.Length == 0 || results_destroy[0].Amount < SystemFee + assetFee))
             *  {
             *      if (Inputs.Length == 0 && byJoinSplit.Count > 0)
             *      {
             *          if (Outputs.Length == 0)
             *          {
             *              Fixed8 fee = Fixed8.Zero;
             *              for (int i = 0; i < byJoinSplit.Count; i++)
             *              {
             *                  fee += vPub_New(i);
             *              }
             *
             *              if (fee < SystemFee)
             *              {
             *                  return false;
             *              }
             *          }
             *          else
             *          {
             *              Fixed8 fee = Fixed8.Zero;
             *              for (int i = 0; i < byJoinSplit.Count; i++)
             *              {
             *                  fee += vPub_New(i);
             *              }
             *
             *              for (int i = 0; i < Outputs.Length; i++)
             *              {
             *                  fee -= Outputs[i].Value;
             *              }
             *
             *              if (fee < SystemFee)
             *              {
             *                  return false;
             *              }
             *          }
             *      }
             *      else
             *      {
             *          return false;
             *      }
             *  }
             * }
             * else
             * {
             *  Fixed8 result_qrs_fee = Fixed8.Zero;
             *  Fixed8 result_qrg_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;
             *      }
             *  }
             *
             *  if (SystemFee + qrsAssetFee > Fixed8.Zero && result_qrs_fee < SystemFee + qrsAssetFee)
             *  {
             *      if (Inputs.Length == 0 && byJoinSplit.Count > 0)
             *      {
             *          if (Outputs.Length == 0)
             *          {
             *              Fixed8 fee = Fixed8.Zero;
             *              for (int i = 0; i < byJoinSplit.Count; i++)
             *              {
             *                  fee += vPub_New(i);
             *              }
             *
             *              if (fee < SystemFee)
             *              {
             *                  return false;
             *              }
             *          }
             *          else
             *          {
             *              Fixed8 fee = Fixed8.Zero;
             *              for (int i = 0; i < byJoinSplit.Count; i++)
             *              {
             *                  fee += vPub_New(i);
             *              }
             *
             *              for (int i = 0; i < Outputs.Length; i++)
             *              {
             *                  fee -= Outputs[i].Value;
             *              }
             *
             *              if (fee < SystemFee)
             *              {
             *                  return false;
             *              }
             *          }
             *      }
             *      else
             *      {
             *          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);
            }

            /*
             * int dstOffset = 0;
             * byte[] byJsBody = new byte[byJoinSplit.GetListLength()];
             * for (int index = 0; index < byJoinSplit.Count; index++)
             * {
             *  Buffer.BlockCopy(byJoinSplit[index], 0, byJsBody, dstOffset, byJoinSplit[index].Length);
             *  dstOffset += byJoinSplit[index].Length;
             * }
             *
             * UInt256 jsHash = new UInt256(Crypto.Default.Hash256(byJsBody));
             */

            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);
            }
        }