/// <summary> /// 获取需要校验的脚本散列值 /// </summary> /// <returns>返回需要校验的脚本散列值</returns> 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()); }
/// <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()); }
/// <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()); }