示例#1
0
        static CoinPicker()
        {
            Transaction baseTx = Transaction.Create(new List <Transaction.Output>(), new Dictionary <Address, Money>(), new Dictionary <Address, ECKey>(), allowDust: true);

            MinBytesForTx = (long)(baseTx.ToByteArray().LongCount() * (1 + PercentError));

            var input = new Transaction.Input("23e90c875e2ed7a1ec01f5a80643879625b8aeb48b67db64c0f9edb8259240b6", 0, 0)
            {
                ScriptSig = Script.FromString("3045022100f65c5e8c5d3b2386547a876db4ddb7bba1e57f9dbeaec9f3010516e453577fda02206f9df1a9262997263ac01be4342d0ade7057f5cceab4375fa1020ac7bfc5054b01 04ef96e3bccc8fff6b21d28e81f61c4a93cfe0f133214c9547c0d683a9fc12f529229c8d1ab20004c0f7f13961566b65492c6267fa452784c0724b4f542e4001f1")
            };

            using (var stream = new MemoryStream()) {
                using (var writer = new BinaryWriter(stream)) {
                    input.Write(writer);
                    ApproxBytesPerInput = (long)(stream.ToArray().LongCount() * (1 + PercentError));
                }
            }

            var output = new Transaction.Output(Script.FromString("OP_DUP OP_HASH160 4da1b9632e160406693b961ff321402b22ce5452 OP_EQUALVERIFY OP_CHECKSIG"), Money.Create(0.002m, "BTC"), baseTx, 0);

            using (var stream = new MemoryStream()) {
                using (var writer = new BinaryWriter(stream)) {
                    output.Write(writer);
                    ApproxBytesPerOutput = (long)(stream.ToArray().LongCount() * (1 + PercentError));
                }
            }
        }
示例#2
0
        public void Withdraw(byte[] asset, BigInteger amount, Transaction.Input input)
        {
            var balance = balances.ContainsKey(asset) ? balances[asset] : 0;

            balance        -= amount;
            balances[asset] = balance;
            unspent.RemoveAll(x => x.prevHash == input.prevHash && x.prevIndex == input.prevIndex);
        }
示例#3
0
        public void Deposit(byte[] asset, BigInteger amount, Transaction.Input input)
        {
            var balance = balances.ContainsKey(asset) ? balances[asset] : 0;

            balance        += amount;
            balances[asset] = balance;

            unspent.Add(input);
        }
示例#4
0
        private void ExecuteTransaction(Transaction tx)
        {
            foreach (var input in tx.inputs)
            {
                var input_tx = GetTransaction(input.prevHash);
                var output   = input_tx.outputs[input.prevIndex];

                var account = GetAccount(output.scriptHash);
                account.Withdraw(output.assetID, output.value.ToBigInteger(), input);

                var asset = GetAsset(output.assetID);
                if (asset != null)
                {
                    var address = output.scriptHash.ToAddress();
                    Logger($"Withdrawing {output.value} {asset.name} from {address}");
                }
            }

            uint index = 0;

            foreach (var output in tx.outputs)
            {
                var account = GetAccount(output.scriptHash);
                var unspent = new Transaction.Input()
                {
                    prevIndex = index, prevHash = tx.Hash
                };
                account.Deposit(output.assetID, output.value.ToBigInteger(), unspent);

                var asset   = GetAsset(output.assetID);
                var address = output.scriptHash.ToAddress();
                Logger($"Depositing {output.value} {asset.name} to {address}");

                index++;
            }

            switch (tx.type)
            {
            case TransactionType.PublishTransaction:
            {
                var contract_hash = tx.contractRegistration.script.ToScriptHash();
                var account       = GetAccount(contract_hash);
                account.contract = tx.contractRegistration;
                account.storage  = new Storage();
                break;
            }

            case TransactionType.InvocationTransaction:
            {
                ExecuteVM(tx, TriggerType.Application);
                break;
            }
            }
        }
 private static string SerializeTransactionInput(Transaction.Input input)
 {
     return(reverseHex(input.prevHash) + reverseHex(num2hexstring(input.prevIndex, 4)));
 }
示例#6
0
        public void GenerateInputsOutputs(UInt160 from_script_hash, string symbol, IEnumerable <Transaction.Output> targets, out List <Transaction.Input> inputs, out List <Transaction.Output> outputs, decimal system_fee = 0)
        {
            var unspent = GetUnspent(from_script_hash);

            // filter any asset lists with zero unspent inputs
            unspent = unspent.Where(pair => pair.Value.Count > 0).ToDictionary(pair => pair.Key, pair => pair.Value);

            inputs  = new List <Transaction.Input>();
            outputs = new List <Transaction.Output>();

            string assetID;

            var info = GetAssetsInfo();

            if (info.ContainsKey(symbol))
            {
                assetID = info[symbol];
            }
            else
            {
                throw new NeoException($"{symbol} is not a valid blockchain asset.");
            }

            var from_address = from_script_hash.ToAddress();

            if (!unspent.ContainsKey(symbol))
            {
                throw new NeoException($"Not enough {symbol} in address {from_address}");
            }

            decimal cost = 0;

            if (targets != null)
            {
                foreach (var target in targets)
                {
                    if (target.scriptHash.Equals(from_script_hash))
                    {
                        throw new NeoException("Target can't be same as input");
                    }

                    cost += target.value;
                }
            }

            var targetAssetID = LuxUtils.ReverseHex(assetID).HexToBytes();

            var     sources  = unspent[symbol];
            decimal selected = 0;

            if (lastTransactions.ContainsKey(from_address))
            {
                var lastTx = lastTransactions[from_address];

                uint index = 0;
                foreach (var output in lastTx.outputs)
                {
                    if (output.assetID.SequenceEqual(targetAssetID) && output.scriptHash.Equals(from_script_hash))
                    {
                        selected += output.value;

                        var input = new Transaction.Input()
                        {
                            prevHash  = lastTx.Hash,
                            prevIndex = index,
                        };

                        inputs.Add(input);

                        break;
                    }

                    index++;
                }
            }

            foreach (var src in sources)
            {
                if (selected >= cost && inputs.Count > 0)
                {
                    break;
                }

                selected += src.value;

                var input = new Transaction.Input()
                {
                    prevHash  = src.hash,
                    prevIndex = src.index,
                };

                inputs.Add(input);
            }

            if (selected < cost)
            {
                throw new NeoException($"Not enough {symbol}");
            }

            if (cost > 0 && targets != null)
            {
                foreach (var target in targets)
                {
                    var output = new Transaction.Output()
                    {
                        assetID    = targetAssetID,
                        scriptHash = target.scriptHash,
                        value      = target.value
                    };
                    outputs.Add(output);
                }
            }

            if (selected > cost || cost == 0)
            {
                var left = selected - cost;

                var change = new Transaction.Output()
                {
                    assetID    = targetAssetID,
                    scriptHash = from_script_hash,
                    value      = left
                };
                outputs.Add(change);
            }
        }
示例#7
0
        private async Task RecalculatePendingTransaction()
        {
            if (PendingOutputs.Count == 0 || PendingOutputs.Any(x => !x.IsValid))
            {
                UnsetPendingTransaction();
                return;
            }

            var walletClient = App.Current.Synchronizer?.WalletRpcClient;

            var outputs = PendingOutputs.Select(po =>
            {
                var amount = po.OutputAmount;
                var script = po.BuildOutputScript().Script;
                return(new Transaction.Output(amount, Transaction.Output.LatestPkScriptVersion, script));
            }).ToArray();

            TransactionAuthor.InputSource inputSource = async targetAmount =>
            {
                var inputs = new Transaction.Input[0];
                // TODO: don't hardcode confs
                var funding = await walletClient.FundTransactionAsync(SelectedAccount.Account, targetAmount, 1);

                if (funding.Item2 >= targetAmount)
                {
                    inputs = funding.Item1.Select(o =>
                                                  Transaction.Input.CreateFromPrefix(new Transaction.OutPoint(o.TransactionHash, o.OutputIndex, o.Tree),
                                                                                     TransactionRules.MaxInputSequence)).ToArray();
                }
                return(Tuple.Create(funding.Item2, inputs));
            };
            TransactionAuthor.ChangeSource changeSource = async() =>
            {
                // Use cached change script if one has already been generated for this account.
                var          selectedAccount = SelectedAccount.Account;
                OutputScript cachedScript;
                if (_unusedChangeScripts.TryGetValue(selectedAccount, out cachedScript))
                {
                    return(cachedScript);
                }

                var changeAddress = await walletClient.NextInternalAddressAsync(SelectedAccount.Account);

                var changeScript = Address.Decode(changeAddress).BuildScript();
                _unusedChangeScripts[selectedAccount] = changeScript;
                return(changeScript);
            };

            try
            {
                var r = await TransactionAuthor.BuildUnsignedTransaction(outputs, TransactionFees.DefaultFeePerKb, inputSource, changeSource);

                Amount totalAccountBalance;
                using (var walletGuard = await App.Current.Synchronizer.WalletMutex.LockAsync())
                {
                    totalAccountBalance = walletGuard.Instance.LookupAccountProperties(SelectedAccount.Account).TotalBalance;
                }
                SetPendingTransaction(totalAccountBalance, r.Item1, r.Item2, outputs.Sum(o => o.Amount));
            }
            catch (Exception ex)
            {
                UnsetPendingTransaction();

                // Insufficient funds will need a nicer error displayed somehow.  For now, hide it
                // while disabling the UI to create the transaction.  All other errors are unexpected.
                if (!(ex is InsufficientFundsException))
                {
                    throw;
                }
            }
        }