/// <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) { RegisterTransaction tx = Blockchain.Default.GetTransaction(r.AssetId) as RegisterTransaction; if (tx == null) { return(false); } if (tx.Amount < Fixed8.Zero) { continue; } if (!Blockchain.Default.Ability.HasFlag(BlockchainAbility.Statistics)) { return(false); } Fixed8 quantity_issued = Blockchain.Default.GetQuantityIssued(r.AssetId); quantity_issued += mempool.OfType <IssueTransaction>().SelectMany(p => p.Outputs).Where(p => p.AssetId == r.AssetId).Sum(p => p.Value); if (tx.Amount - quantity_issued < -r.Amount) { return(false); } } return(true); }
/// <summary> /// 验证交易 /// </summary> /// <returns>返回验证后的结果</returns> public override bool Verify() { if (!base.Verify()) { return(false); } TransactionResult[] results = GetTransactionResults()?.Where(p => p.Amount < Fixed8.Zero).ToArray(); if (results == null) { return(false); } foreach (TransactionResult r in results) { RegisterTransaction tx = Blockchain.Default.GetTransaction(r.AssetId) as RegisterTransaction; if (tx == null) { return(false); } if (tx.Amount < Fixed8.Zero) { continue; } if (!Blockchain.Default.Ability.HasFlag(BlockchainAbility.Statistics)) { return(false); } Fixed8 quantity_issued = Blockchain.Default.GetQuantityIssued(r.AssetId); //TODO: 已发行量是否应考虑内存池内未被写入区块链的交易,以防止“双重发行” if (tx.Amount - quantity_issued < -r.Amount) { return(false); } } return(true); }
private void button1_Click(object sender, EventArgs e) { RegisterTransaction antshare = new RegisterTransaction { AssetType = AssetType.AntShare, Name = "[{'lang':'zh-CN','name':'小蚁股'},{'lang':'en','name':'AntShare'}]", Amount = Fixed8.FromDecimal(numericUpDown1.Value), Issuer = textBox1.Text.ToScriptHash(), Admin = textBox2.Text.ToScriptHash(), Inputs = new TransactionInput[0], Outputs = new TransactionOutput[0] }; SignatureContext context = new SignatureContext(antshare); InformationBox.Show(context.ToString(), "小蚁股签名上下文"); }
/// <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)) { RegisterTransaction tx = Blockchain.Default.GetTransaction(result.AssetId) as RegisterTransaction; if (tx == null) { throw new InvalidOperationException(); } hashes.Add(tx.Admin); } return(hashes.OrderBy(p => p).ToArray()); }
public override UInt160[] GetScriptHashesForVerifying() { HashSet <UInt160> hashes = new HashSet <UInt160>(base.GetScriptHashesForVerifying()); foreach (var group in Outputs.GroupBy(p => p.AssetId)) { RegisterTransaction tx = Blockchain.Default.GetTransaction(group.Key) as RegisterTransaction; if (tx == null) { throw new InvalidOperationException(); } if (tx.AssetType == AssetType.Share) { hashes.UnionWith(group.Select(p => p.ScriptHash)); } } return(hashes.OrderBy(p => p).ToArray()); }
private void button1_Click(object sender, EventArgs e) { RegisterTransaction antshare = new RegisterTransaction { AssetType = AssetType.AntShare, #if TESTNET Name = "[{'lang':'zh-CN','name':'小蚁股(测试)'},{'lang':'en','name':'AntShare(TestNet)'}]", #else Name = "[{'lang':'zh-CN','name':'小蚁股'},{'lang':'en','name':'AntShare'}]", #endif Amount = Fixed8.FromDecimal(numericUpDown1.Value), Issuer = ECPoint.Parse(textBox1.Text, ECCurve.Secp256r1), Admin = Wallet.ToScriptHash(textBox2.Text), Attributes = new TransactionAttribute[0], Inputs = new TransactionInput[0], Outputs = new TransactionOutput[0] }; SignatureContext context = new SignatureContext(antshare); InformationBox.Show(context.ToString(), "小蚁股签名上下文:"); }
public virtual UInt160[] GetScriptHashesForVerifying() { if (References == null) { throw new InvalidOperationException(); } TransactionOutput[] inputs = Inputs.Select(p => References[p]).ToArray(); HashSet <UInt160> hashes = new HashSet <UInt160>(inputs.Where(p => p.Value > Fixed8.Zero).Select(p => p.ScriptHash)); foreach (UInt256 asset_id in inputs.Where(p => p.Value < Fixed8.Zero).Select(p => p.AssetId).Distinct()) { RegisterTransaction tx = Blockchain.Default.GetTransaction(asset_id) as RegisterTransaction; if (tx == null) { throw new InvalidOperationException(); } hashes.Add(tx.Admin); } 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)); foreach (var group in Outputs.GroupBy(p => p.AssetId)) { RegisterTransaction tx = Blockchain.Default.GetTransaction(group.Key) as RegisterTransaction; if (tx == null) { throw new InvalidOperationException(); } if (tx.AssetType.HasFlag(AssetType.DutyFlag)) { hashes.UnionWith(group.Select(p => p.ScriptHash)); } } return(hashes.OrderBy(p => p).ToArray()); }
UInt160[] ISignable.GetScriptHashesForVerifying() { HashSet <UInt160> hashes = new HashSet <UInt160>(); RegisterTransaction asset = Blockchain.Default.GetTransaction(AssetId) as RegisterTransaction; if (asset == null) { throw new InvalidOperationException(); } if (asset.AssetType == AssetType.Share) { hashes.Add(Client); } foreach (var group in Inputs.GroupBy(p => p.PrevHash)) { Transaction tx = Blockchain.Default.GetTransaction(group.Key); if (tx == null) { throw new InvalidOperationException(); } hashes.UnionWith(group.Select(p => tx.Outputs[p.PrevIndex].ScriptHash)); } return(hashes.OrderBy(p => p).ToArray()); }
//TODO: 此处需要较多的测试来证明它的正确性 //因为委托交易的验证算法有点太复杂了, //考虑未来是否可以优化这个算法 public override bool Verify() { if (!base.Verify()) { return(false); } foreach (Order order in Orders) { if (!order.VerifySignature()) { return(false); } } RegisterTransaction asset_value = Blockchain.Default.GetTransaction(ValueAssetId) as RegisterTransaction; if (asset_value?.AssetType != AssetType.Currency) { return(false); } List <Order> orders = new List <Order>(Orders); foreach (var group in Inputs.GroupBy(p => p.PrevHash)) { Transaction tx = Blockchain.Default.GetTransaction(group.Key); if (tx == null) { return(false); } AgencyTransaction tx_agency = tx as AgencyTransaction; if (tx_agency?.SplitOrder == null || tx_agency.AssetId != AssetId || tx_agency.ValueAssetId != ValueAssetId || tx_agency.Agent != Agent) { continue; } var outputs = group.Select(p => new { Input = p, Output = tx_agency.Outputs[p.PrevIndex] }).Where(p => p.Output.ScriptHash == tx_agency.SplitOrder.Client).ToDictionary(p => p.Input, p => p.Output); if (outputs.Count == 0) { continue; } if (outputs.Count != tx_agency.Outputs.Count(p => p.ScriptHash == tx_agency.SplitOrder.Client)) { return(false); } orders.Add(new Order { AssetId = this.AssetId, ValueAssetId = this.ValueAssetId, Agent = this.Agent, Amount = tx_agency.SplitOrder.Amount, Price = tx_agency.SplitOrder.Price, Client = tx_agency.SplitOrder.Client, Inputs = outputs.Keys.ToArray() }); } if (orders.Count < 2) { return(false); } if (orders.Count(p => p.Amount > Fixed8.Zero) == 0 || orders.Count(p => p.Amount < Fixed8.Zero) == 0) { return(false); } Fixed8 amount_unmatched = orders.Sum(p => p.Amount); if (amount_unmatched == Fixed8.Zero) { if (SplitOrder != null) { return(false); } } else { if (SplitOrder?.Amount != amount_unmatched) { return(false); } } foreach (Order order in orders) { TransactionOutput[] inputs = order.Inputs.Select(p => References[p]).ToArray(); if (order.Amount > Fixed8.Zero) { if (inputs.Any(p => p.AssetId != order.ValueAssetId)) { return(false); } if (inputs.Sum(p => p.Value) < order.Amount * order.Price) { return(false); } } else { if (inputs.Any(p => p.AssetId != order.AssetId)) { return(false); } if (inputs.Sum(p => p.Value) < order.Amount) { return(false); } } } if (SplitOrder != null) { Fixed8 price_worst = amount_unmatched > Fixed8.Zero ? orders.Min(p => p.Price) : orders.Max(p => p.Price); if (SplitOrder.Price != price_worst) { return(false); } Order[] orders_worst = orders.Where(p => p.Price == price_worst && p.Client == SplitOrder.Client).ToArray(); if (orders_worst.Length == 0) { return(false); } Fixed8 amount_worst = orders_worst.Sum(p => p.Amount); if (amount_worst.Abs() < amount_unmatched.Abs()) { return(false); } Order order_combine = new Order { AssetId = this.AssetId, ValueAssetId = this.ValueAssetId, Agent = this.Agent, Amount = amount_worst - amount_unmatched, Price = price_worst, Client = SplitOrder.Client, Inputs = orders_worst.SelectMany(p => p.Inputs).ToArray() }; foreach (Order order_worst in orders_worst) { orders.Remove(order_worst); } orders.Add(order_combine); } foreach (var group in orders.GroupBy(p => p.Client)) { TransactionOutput[] inputs = group.SelectMany(p => p.Inputs).Select(p => References[p]).ToArray(); TransactionOutput[] outputs = Outputs.Where(p => p.ScriptHash == group.Key).ToArray(); Fixed8 money_spent = inputs.Where(p => p.AssetId == ValueAssetId).Sum(p => p.Value) - outputs.Where(p => p.AssetId == ValueAssetId).Sum(p => p.Value); Fixed8 amount_changed = outputs.Where(p => p.AssetId == AssetId).Sum(p => p.Value) - inputs.Where(p => p.AssetId == AssetId).Sum(p => p.Value); if (amount_changed != group.Sum(p => p.Amount)) { return(false); } if (money_spent > group.Sum(p => p.Amount * p.Price)) { return(false); } } return(true); }
/// <summary> /// 验证交易 /// </summary> /// <returns>返回验证的结果</returns> public virtual bool Verify(IEnumerable <Transaction> mempool) { if (Blockchain.Default.ContainsTransaction(Hash)) { return(true); } if (!Blockchain.Default.Ability.HasFlag(BlockchainAbility.UnspentIndexes) || !Blockchain.Default.Ability.HasFlag(BlockchainAbility.TransactionIndexes)) { return(false); } 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.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)) { RegisterTransaction asset = Blockchain.Default.GetTransaction(group.Key) as RegisterTransaction; if (asset == null) { 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.AntCoin.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.AntCoin.Hash)) { return(false); } break; case TransactionType.IssueTransaction: if (results_issue.Any(p => p.AssetId == Blockchain.AntCoin.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 (Attributes.Count(p => p.Usage == TransactionAttributeUsage.Vote) > 1024) { return(false); } if (Attributes.Where(p => p.Usage == TransactionAttributeUsage.Vote).Select(p => new UInt256(p.Data)).Distinct().Count() != Attributes.Count(p => p.Usage == TransactionAttributeUsage.Vote)) { return(false); } if (Attributes.Any(p => p.Usage == TransactionAttributeUsage.Vote)) { if (!Blockchain.Default.Ability.HasFlag(BlockchainAbility.UnspentIndexes)) { return(false); } if (Outputs.All(p => !p.AssetId.Equals(Blockchain.AntShare.Hash))) { return(false); } HashSet <ECPoint> pubkeys = new HashSet <ECPoint>(); foreach (UInt256 vote in Attributes.Where(p => p.Usage == TransactionAttributeUsage.Vote).Select(p => new UInt256(p.Data))) { EnrollmentTransaction tx = Blockchain.Default.GetTransaction(vote) as EnrollmentTransaction; if (tx == null) { return(false); } if (!Blockchain.Default.ContainsUnspent(vote, 0)) { return(false); } if (!pubkeys.Add(tx.PublicKey)) { return(false); } } } return(this.VerifySignature()); }
/// <summary> /// 验证交易 /// </summary> /// <returns>返回验证的结果</returns> public override bool Verify() { if (Blockchain.Default.ContainsTransaction(Hash)) { return(true); } if (!Blockchain.Default.Ability.HasFlag(BlockchainAbility.UnspentIndexes) || !Blockchain.Default.Ability.HasFlag(BlockchainAbility.TransactionIndexes)) { return(false); } if (Blockchain.Default.IsDoubleSpend(this)) { return(false); } foreach (var group in Outputs.GroupBy(p => p.AssetId)) { RegisterTransaction asset = Blockchain.Default.GetTransaction(group.Key) as RegisterTransaction; if (asset == null) { 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.AntCoin.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.AntCoin.Hash)) { return(false); } break; case TransactionType.IssueTransaction: if (results_issue.Any(p => p.AssetId == Blockchain.AntCoin.Hash)) { return(false); } break; default: if (results_issue.Length > 0) { return(false); } break; } TransactionAttribute script = Attributes.FirstOrDefault(p => p.Usage == TransactionAttributeUsage.Script); if (script != null) { ScriptEngine engine = new ScriptEngine(new Script { StackScript = new byte[0], RedeemScript = script.Data }, this, InterfaceEngine.Default); if (!engine.Execute()) { return(false); } } return(this.VerifySignature()); }
/// <summary> /// 验证交易 /// </summary> /// <returns>返回验证的结果</returns> public virtual bool Verify() { if (Blockchain.Default.ContainsTransaction(Hash)) { return(true); } if (!Blockchain.Default.Ability.HasFlag(BlockchainAbility.UnspentIndexes) || !Blockchain.Default.Ability.HasFlag(BlockchainAbility.TransactionIndexes)) { return(false); } if (Blockchain.Default.IsDoubleSpend(this)) { return(false); } foreach (var group in Outputs.GroupBy(p => p.AssetId)) { RegisterTransaction asset = Blockchain.Default.GetTransaction(group.Key) as RegisterTransaction; if (asset == null) { 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.AntCoin.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.AntCoin.Hash)) { return(false); } break; case TransactionType.IssueTransaction: if (results_issue.Any(p => p.AssetId == Blockchain.AntCoin.Hash)) { return(false); } break; default: if (results_issue.Length > 0) { return(false); } break; } foreach (TransactionAttribute script in Attributes.Where(p => p.Usage == TransactionAttributeUsage.Script)) { ScriptEngine engine = new ScriptEngine(this, ECDsaCrypto.Default, Blockchain.Default, InterfaceEngine.Default); if (!engine.ExecuteScript(script.Data, false)) { return(false); } if (engine.Stack.Count != 1 || !engine.Stack.Pop()) { return(false); } } if (Attributes.Any(p => p.Usage == TransactionAttributeUsage.Vote)) { if (!Blockchain.Default.Ability.HasFlag(BlockchainAbility.UnspentIndexes)) { return(false); } HashSet <ECPoint> pubkeys = new HashSet <ECPoint>(); foreach (UInt256 vote in Attributes.Where(p => p.Usage == TransactionAttributeUsage.Vote).Select(p => new UInt256(p.Data))) { EnrollmentTransaction tx = Blockchain.Default.GetTransaction(vote) as EnrollmentTransaction; if (tx == null) { return(false); } if (!Blockchain.Default.ContainsUnspent(vote, 0)) { return(false); } if (!pubkeys.Add(tx.PublicKey)) { return(false); } } } return(this.VerifySignature()); }
public override bool Verify() { if (Blockchain.Default.ContainsTransaction(Hash)) { return(true); } if (!Blockchain.Default.Ability.HasFlag(BlockchainAbility.UnspentIndexes) || !Blockchain.Default.Ability.HasFlag(BlockchainAbility.TransactionIndexes)) { return(false); } if (Blockchain.Default.IsDoubleSpend(this)) { return(false); } foreach (UInt256 hash in Outputs.Select(p => p.AssetId).Distinct()) { if (!Blockchain.Default.ContainsAsset(hash)) { return(false); } } if (References == null) { return(false); } foreach (var group in Outputs.Where(p => p.Value < Fixed8.Zero).GroupBy(p => p.AssetId)) { if (group.Key == Blockchain.AntCoin.Hash || group.Key == Blockchain.AntShare.Hash) { return(false); } RegisterTransaction tx = Blockchain.Default.GetTransaction(group.Key) as RegisterTransaction; if (tx == null) { return(false); } if (tx.Amount != Fixed8.Zero) { return(false); } if (group.Any(p => p.ScriptHash != tx.Issuer)) { return(false); } if (Type != TransactionType.IssueTransaction && References.Values.Where(p => p.AssetId == group.Key && p.Value < Fixed8.Zero).Sum(p => p.Value) > group.Sum(p => p.Value)) { return(false); } } TransactionResult[] results = GetTransactionResults().ToArray(); 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.AntCoin.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(); if (Type == TransactionType.GenerationTransaction) { if (results_issue.Any(p => p.AssetId != Blockchain.AntCoin.Hash)) { return(false); } } else if (Type != TransactionType.IssueTransaction) { if (results_issue.Length > 0) { return(false); } } return(this.VerifySignature()); }