public override UInt160[] GetScriptHashesForVerifying() { HashSet <UInt160> hashes = new HashSet <UInt160>(); foreach (var group in Inputs.GroupBy(p => p.PrevHash)) { Transaction tx = Blockchain.Default.GetTransaction(group.Key); if (tx == null) { throw new InvalidOperationException(); } AgencyTransaction tx_agency = tx as AgencyTransaction; if (tx_agency?.SplitOrder == null || tx_agency.AssetId != AssetId || tx_agency.ValueAssetId != ValueAssetId || tx_agency.Agent != Agent) { hashes.UnionWith(group.Select(p => tx.Outputs[p.PrevIndex].ScriptHash)); } else { hashes.UnionWith(group.Select(p => tx.Outputs[p.PrevIndex].ScriptHash).Where(p => p != tx_agency.SplitOrder.Client)); } } hashes.Add(Agent); 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); }
internal void DeserializeInTransaction(BinaryReader reader, AgencyTransaction tx) { DeserializeUnsignedInternal(reader, tx.AssetId, tx.ValueAssetId, tx.Agent); Scripts = reader.ReadSerializableArray <Script>(); }
internal void DeserializeInTransaction(BinaryReader reader, AgencyTransaction tx) { DeserializeUnsignedInternal(reader, tx.AssetId, tx.ValueAssetId, tx.Agent); this.Scripts = reader.ReadBytesArray(); }
internal void DeserializeInTransaction(BinaryReader reader, AgencyTransaction tx) { DeserializeUnsignedInternal(reader, tx.AssetId, tx.ValueAssetId, tx.Agent); Scripts = reader.ReadSerializableArray<Script>(); }
internal void DeserializeInTransaction(BinaryReader reader, AgencyTransaction tx) { DeserializeInternal(reader, tx.AssetId, tx.ValueAssetId, tx.Agent); }