Beispiel #1
0
        public IDbSelect GetLastSelect()
        {
            IDbSelect dbSelect = null;

            var results = new Stack <IDbObject>();

            while (ResultStack.Count > 0)
            {
                var dbObject = ResultStack.Pop();
                results.Push(dbObject);

                dbSelect = dbObject as IDbSelect;
                if (dbSelect != null)
                {
                    break;
                }
            }

            while (results.Count > 0)
            {
                ResultStack.Push(results.Pop());
            }

            return(dbSelect);
        }
Beispiel #2
0
        public Transaction MakeTransaction(List <TransactionAttribute> attributes, IEnumerable <TransferOutput> outputs, UInt160 from = null, UInt160 change_address = null, Fixed8 fee = default(Fixed8))
        {
            var cOutputs = outputs.Where(p => !p.IsGlobalAsset).GroupBy(p => new
            {
                AssetId = (UInt160)p.AssetId,
                Account = p.ScriptHash
            }, (k, g) => new
            {
                k.AssetId,
                Value = g.Aggregate(BigInteger.Zero, (x, y) => x + y.Value.Value),
                k.Account
            }).ToArray();
            Transaction tx;

            if (attributes == null)
            {
                attributes = new List <TransactionAttribute>();
            }
            UInt160[]         accounts    = from == null?GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).ToArray() : new[] { from };
            HashSet <UInt160> sAttributes = new HashSet <UInt160>();

            using (ScriptBuilder sb = new ScriptBuilder())
            {
                foreach (var output in cOutputs)
                {
                    var balances = new List <(UInt160 Account, BigInteger Value)>();
                    foreach (UInt160 account in accounts)
                    {
                        byte[] script;
                        using (ScriptBuilder sb2 = new ScriptBuilder())
                        {
                            sb2.EmitAppCall(output.AssetId, "balanceOf", account);
                            script = sb2.ToArray();
                        }
                        ApplicationEngine engine = ApplicationEngine.Run(script);
                        if (engine.State.HasFlag(VMState.FAULT))
                        {
                            return(null);
                        }
                        balances.Add((account, engine.ResultStack.Pop().GetBigInteger()));
                    }
                    BigInteger sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value);
                    if (sum < output.Value)
                    {
                        return(null);
                    }
                    if (sum != output.Value)
                    {
                        balances = balances.OrderByDescending(p => p.Value).ToList();
                        BigInteger amount = output.Value;
                        int        i      = 0;
                        while (balances[i].Value <= amount)
                        {
                            amount -= balances[i++].Value;
                        }
                        if (amount == BigInteger.Zero)
                        {
                            balances = balances.Take(i).ToList();
                        }
                        else
                        {
                            balances = balances.Take(i).Concat(new[] { balances.Last(p => p.Value >= amount) }).ToList();
                        }
                        sum = balances.Aggregate(BigInteger.Zero, (x, y) => x + y.Value);
                    }
                    sAttributes.UnionWith(balances.Select(p => p.Account));
                    for (int i = 0; i < balances.Count; i++)
                    {
                        BigInteger value = balances[i].Value;
                        if (i == 0)
                        {
                            BigInteger change = sum - output.Value;
                            if (change > 0)
                            {
                                value -= change;
                            }
                        }
                        sb.EmitAppCall(output.AssetId, "transfer", balances[i].Account, output.Account, value);
                        sb.Emit(OpCode.THROWIFNOT);
                    }
                }
                byte[] nonce = new byte[8];
                rand.NextBytes(nonce);
                sb.Emit(OpCode.RET, nonce);
                tx = new InvocationTransaction
                {
                    Version = 1,
                    Script  = sb.ToArray()
                };
            }
            attributes.AddRange(sAttributes.Select(p => new TransactionAttribute
            {
                Usage = TransactionAttributeUsage.Script,
                Data  = p.ToArray()
            }));
            tx.Attributes = attributes.ToArray();
            tx.Inputs     = new CoinReference[0];
            tx.Outputs    = outputs.Where(p => p.IsGlobalAsset).Select(p => p.ToTxOutput()).ToArray();
            tx.Witnesses  = new Witness[0];
            if (tx is InvocationTransaction itx)
            {
                ApplicationEngine engine = ApplicationEngine.Run(itx.Script, itx);
                if (engine.State.HasFlag(VMState.FAULT))
                {
                    return(null);
                }
                tx = new InvocationTransaction
                {
                    Version    = itx.Version,
                    Script     = itx.Script,
                    Gas        = InvocationTransaction.GetGas(engine.GasConsumed),
                    Attributes = itx.Attributes,
                    Inputs     = itx.Inputs,
                    Outputs    = itx.Outputs
                };
            }
            tx = MakeTransaction(tx, from, change_address, fee);
            return(tx);
        }