예제 #1
0
        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());
        }
예제 #2
0
        //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);
        }
예제 #3
0
 internal void DeserializeInTransaction(BinaryReader reader, AgencyTransaction tx)
 {
     DeserializeUnsignedInternal(reader, tx.AssetId, tx.ValueAssetId, tx.Agent);
     Scripts = reader.ReadSerializableArray <Script>();
 }
예제 #4
0
파일: Order.cs 프로젝트: 4T-Shirt/AntShares
 internal void DeserializeInTransaction(BinaryReader reader, AgencyTransaction tx)
 {
     DeserializeUnsignedInternal(reader, tx.AssetId, tx.ValueAssetId, tx.Agent);
     this.Scripts = reader.ReadBytesArray();
 }
예제 #5
0
파일: Order.cs 프로젝트: zhengger/AntShares
 internal void DeserializeInTransaction(BinaryReader reader, AgencyTransaction tx)
 {
     DeserializeUnsignedInternal(reader, tx.AssetId, tx.ValueAssetId, tx.Agent);
     Scripts = reader.ReadSerializableArray<Script>();
 }
예제 #6
0
파일: Order.cs 프로젝트: imcoddy/AntShares
 internal void DeserializeInTransaction(BinaryReader reader, AgencyTransaction tx)
 {
     DeserializeInternal(reader, tx.AssetId, tx.ValueAssetId, tx.Agent);
 }