public void FundRawTransactionWithValidTxsThenReturnsCorrectResponse()
        {
            var k  = new Key();
            var tx = new Transaction();

            tx.Outputs.Add(new TxOut(Money.Coins(1), k));
            RPCClient rpc = this.rpcTestFixture.RpcClient;
            FundRawTransactionResponse result = rpc.FundRawTransaction(tx);

            TestFundRawTransactionResult(tx, result);

            result = rpc.FundRawTransaction(tx, new FundRawTransactionOptions());
            TestFundRawTransactionResult(tx, result);
            FundRawTransactionResponse result1 = result;

            BitcoinAddress change  = rpc.GetNewAddress();
            BitcoinAddress change2 = rpc.GetRawChangeAddress();

            result = rpc.FundRawTransaction(tx, new FundRawTransactionOptions()
            {
                FeeRate         = new FeeRate(Money.Satoshis(50), 1),
                IncludeWatching = true,
                ChangeAddress   = change,
            });
            TestFundRawTransactionResult(tx, result);
            Assert.True(result1.Fee < result.Fee);
            Assert.Contains(result.Transaction.Outputs, o => o.ScriptPubKey == change.ScriptPubKey);
        }
示例#2
0
        public void CanFundRawTransactionWithChangeAddressSpecified()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode node = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StraxRegTest150Miner).Start();

                var tx   = this.network.CreateTransaction();
                var dest = new Key().ScriptPubKey;
                tx.Outputs.Add(new TxOut(Money.Coins(1.0m), dest));

                // We specifically don't want to use the first available account as that is where the node has been mining to, and that is where the
                // fundrawtransaction RPC will by default get a change address from.
                // TODO: Investigate why WithReadyBlockchainData is not setting the node.WalletName and node.WalletPassword fields
                var account = node.FullNode.WalletManager().GetUnusedAccount("mywallet", "password");

                var walletAccountReference = new WalletAccountReference("mywallet", account.Name);
                var changeAddress          = node.FullNode.WalletManager().GetUnusedChangeAddress(walletAccountReference);

                var options = new FundRawTransactionOptions()
                {
                    ChangeAddress = BitcoinAddress.Create(changeAddress.Address, this.network).ToString()
                };

                FundRawTransactionResponse funded = node.CreateRPCClient().FundRawTransaction(tx, options);

                Money fee = CheckFunding(node, funded.Transaction);

                Assert.Equal(new Money(this.network.MinRelayTxFee), fee);
                Assert.True(funded.ChangePos > -1);
            }
        }
示例#3
0
        public Transaction FundTransaction(TxOut txOut, FeeRate feeRate)
        {
            Transaction tx = new Transaction();

            tx.Outputs.Add(txOut);

            var changeAddress = _RPCClient.GetRawChangeAddress();

            FundRawTransactionResponse response = null;

            try
            {
                response = _RPCClient.FundRawTransaction(tx, new FundRawTransactionOptions()
                {
                    ChangeAddress = changeAddress,
                    FeeRate       = feeRate,
                    LockUnspents  = true
                });
            }
            catch (RPCException)
            {
                var balance = _RPCClient.GetBalance(0, false);
                var needed  = tx.Outputs.Select(o => o.Value).Sum()
                              + feeRate.GetFee(2000);
                var missing = needed - balance;
                if (missing > Money.Zero)
                {
                    throw new NotEnoughFundsException("Not enough funds", "", missing);
                }
                throw;
            }
            var result = _RPCClient.SendCommand("signrawtransaction", response.Transaction.ToHex());

            return(new Transaction(((JObject)result.Result)["hex"].Value <string>()));
        }
示例#4
0
        public void CannotSignRawTransactionWithUnownedUtxo()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode node  = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StraxRegTest150Miner).Start();
                CoreNode node2 = builder.CreateStratisPosNode(this.network).WithWallet().Start();

                TestHelper.ConnectAndSync(node, node2);
                TestBase.WaitLoop(() => node2.CreateRPCClient().GetBlockCount() >= 150);

                (HdAddress addressUsed, _) = TestHelper.MineBlocks(node2, 1);
                TransactionData otherFunds = addressUsed.Transactions.First();

                var tx = this.network.CreateTransaction();
                tx.Outputs.Add(new TxOut(Money.Coins(1.0m), new Key()));
                FundRawTransactionResponse funded = node.CreateRPCClient().FundRawTransaction(tx);

                // Add an additional (and unnecessary, but that doesn't matter) input belonging to the second node's wallet that the first node will not be able to sign for.
                funded.Transaction.Inputs.Add(new TxIn(new OutPoint(otherFunds.Id, otherFunds.Index)));

                node.CreateRPCClient().WalletPassphrase("password", 600);

                Assert.Throws <RPCException>(() => node.CreateRPCClient().SignRawTransaction(funded.Transaction));
            }
        }
示例#5
0
        public void CanSignRawTransaction()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode node = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StraxRegTest150Miner).Start();

                var tx = this.network.CreateTransaction();
                tx.Outputs.Add(new TxOut(Money.Coins(1.0m), new Key()));
                FundRawTransactionResponse funded = node.CreateRPCClient().FundRawTransaction(tx);

                node.CreateRPCClient().WalletPassphrase("password", 600);

                Transaction signed = node.CreateRPCClient().SignRawTransaction(funded.Transaction);

                Assert.NotNull(signed);
                Assert.NotEmpty(signed.Inputs);

                foreach (var input in signed.Inputs)
                {
                    Assert.NotNull(input.ScriptSig);

                    // Basic sanity check that the transaction has actually been signed.
                    // A segwit transaction would fail this check but we aren't checking that here.
                    // In any case, the mempool count test shows definitively if the transaction passes validation.
                    Assert.NotEqual(input.ScriptSig, Script.Empty);
                }

                node.CreateRPCClient().SendRawTransaction(signed);

                TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length == 1);
                TestHelper.MineBlocks(node, 1);
                TestBase.WaitLoop(() => node.CreateRPCClient().GetRawMempool().Length == 0);
            }
        }
示例#6
0
        protected override async Task <Transaction> SendTransactionAsync(TxOut[] data)
        {
            var tx = new Transaction();

            tx.Outputs.AddRange(data);
            var changeAddress = _RPCClient.GetRawChangeAddress();

            FundRawTransactionResponse response = null;

            try
            {
                response = await _RPCClient.FundRawTransactionAsync(tx, new FundRawTransactionOptions()
                {
                    ChangeAddress = changeAddress,
                    FeeRate       = FeeRate,
                    LockUnspents  = true
                }).ConfigureAwait(false);
            }
            catch (RPCException ex)
            {
                var balance = await _RPCClient.GetBalanceAsync(0, false).ConfigureAwait(false);

                var needed = tx.Outputs.Select(o => o.Value).Sum()
                             + FeeRate.GetFee(2000);
                var missing = needed - balance;
                if (missing > Money.Zero || ex.Message.Equals("Insufficient funds", StringComparison.OrdinalIgnoreCase))
                {
                    throw new NotEnoughFundsException("Not enough funds", "", missing);
                }
                throw;
            }
            var result = await _RPCClient.SendCommandAsync("signrawtransaction", response.Transaction.ToHex()).ConfigureAwait(false);

            return(new Transaction(((JObject)result.Result)["hex"].Value <string>()));
        }
示例#7
0
        public Transaction FundTransaction(TxOut txOut, FeeRate feeRate)
        {
            Transaction tx = new Transaction();

            tx.Outputs.Add(txOut);

            var changeAddress = BitcoinAddress.Create(_RPCClient.SendCommand("getrawchangeaddress").ResultString, _RPCClient.Network);

            FundRawTransactionResponse response = null;

            try
            {
                response = _RPCClient.FundRawTransaction(tx, new FundRawTransactionOptions()
                {
                    ChangeAddress = changeAddress,
                    FeeRate       = feeRate,
                    LockUnspents  = true
                });
            }
            catch (RPCException ex)
            {
                if (ex.Message.Equals("Insufficient funds", StringComparison.OrdinalIgnoreCase))
                {
                    return(null);
                }
                throw;
            }
            var result = _RPCClient.SendCommand("signrawtransaction", response.Transaction.ToHex());

            return(new Transaction(((JObject)result.Result)["hex"].Value <string>()));
        }
 private static void TestFundRawTransactionResult(Transaction tx, FundRawTransactionResponse result)
 {
     Assert.Equal(tx.Version, result.Transaction.Version);
     Assert.True(result.Transaction.Inputs.Count > 0);
     Assert.True(result.Transaction.Outputs.Count > 1);
     Assert.True(result.ChangePos != -1);
     Assert.Equal(Money.Coins(50m) - result.Transaction.Outputs.Select(txout => txout.Value).Sum(), result.Fee);
 }
示例#9
0
 private static void TestFundRawTransactionResult(Transaction tx, FundRawTransactionResponse result)
 {
     Assert.Equal(tx.Version, result.Transaction.Version);
     Assert.True(result.Transaction.Inputs.Count > 0);
     Assert.True(result.Transaction.Outputs.Count > 1);
     //Assert.True(result.ChangePos != -1);
     Assert.Equal(Money.Coins(210000m) - result.Transaction.TotalOut, result.Fee);
 }
示例#10
0
        public void CanSignRawTransaction()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode node = builder.CreateBitcoinCoreNode(version: BitcoinCoreVersion15).Start();

                RPCClient rpcClient = node.CreateRPCClient();
                rpcClient.Generate(101);

                var tx = new Transaction();
                tx.Outputs.Add(new TxOut(Money.Coins(1.0m), new Key()));
                FundRawTransactionResponse funded = node.CreateRPCClient().FundRawTransaction(tx);
                Transaction signed = node.CreateRPCClient().SignRawTransaction(funded.Transaction);
                node.CreateRPCClient().SendRawTransaction(signed);
            }
        }
        public void CanSignRawTransaction()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode node = builder.CreateBitcoinCoreNode(version: "0.18.0", useNewConfigStyle: true).Start();

                CoreNode sfn = builder.CreateStratisPowNode(this.regTest).WithWallet().Start();

                TestHelper.ConnectAndSync(node, sfn);

                RPCClient rpcClient = node.CreateRPCClient();
                RPCClient sfnRpc    = sfn.CreateRPCClient();

                // Need one block per node so they can each fund a transaction.
                rpcClient.Generate(1);

                TestHelper.ConnectAndSync(node, sfn);

                sfnRpc.Generate(1);

                TestHelper.ConnectAndSync(node, sfn);

                // And then enough blocks mined on top for the coinbases to mature.
                rpcClient.Generate(101);

                TestHelper.ConnectAndSync(node, sfn);

                var tx = new Transaction();
                tx.Outputs.Add(new TxOut(Money.Coins(1.0m), new Key()));
                FundRawTransactionResponse funded = rpcClient.FundRawTransaction(tx);

                // signrawtransaction was removed in 0.18. So just use its equivalent so that we can test SFN's ability to call signrawtransaction.
                RPCResponse response = rpcClient.SendCommand("signrawtransactionwithwallet", tx.ToHex());

                Assert.NotNull(response.Result["hex"]);

                sfnRpc.WalletPassphrase(sfn.WalletPassword, 60);

                tx = new Transaction();
                tx.Outputs.Add(new TxOut(Money.Coins(1.0m), new Key()));
                funded = sfnRpc.FundRawTransaction(tx);
                Transaction signed = sfnRpc.SignRawTransaction(funded.Transaction);
                rpcClient.SendRawTransaction(signed);
            }
        }
示例#12
0
        public void CanFundRawTransactionWithoutOptions()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode node = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StraxRegTest150Miner).Start();

                var tx   = this.network.CreateTransaction();
                var dest = new Key().ScriptPubKey;
                tx.Outputs.Add(new TxOut(Money.Coins(1.0m), dest));

                FundRawTransactionResponse funded = node.CreateRPCClient().FundRawTransaction(tx);

                Money fee = CheckFunding(node, funded.Transaction);

                Assert.Equal(new Money(this.network.MinRelayTxFee), fee);
                Assert.True(funded.ChangePos > -1);
            }
        }
示例#13
0
        public void CanFundRawTransactionWithChangePositionSpecified()
        {
            using (NodeBuilder builder = NodeBuilder.Create(this))
            {
                CoreNode node = builder.CreateStratisPosNode(this.network).WithReadyBlockchainData(ReadyBlockchain.StraxRegTest150Miner).Start();

                var tx = this.network.CreateTransaction();
                tx.Outputs.Add(new TxOut(Money.Coins(1.1m), new Key().ScriptPubKey));
                tx.Outputs.Add(new TxOut(Money.Coins(1.2m), new Key().ScriptPubKey));
                tx.Outputs.Add(new TxOut(Money.Coins(1.3m), new Key().ScriptPubKey));
                tx.Outputs.Add(new TxOut(Money.Coins(1.4m), new Key().ScriptPubKey));

                Money totalSent = tx.TotalOut;

                // We specifically don't want to use the first available account as that is where the node has been mining to, and that is where the
                // fundrawtransaction RPC will by default get a change address from.
                var account = node.FullNode.WalletManager().GetUnusedAccount("mywallet", "password");

                var walletAccountReference = new WalletAccountReference("mywallet", account.Name);
                var changeAddress          = node.FullNode.WalletManager().GetUnusedChangeAddress(walletAccountReference);

                var options = new FundRawTransactionOptions()
                {
                    ChangeAddress  = BitcoinAddress.Create(changeAddress.Address, this.network).ToString(),
                    ChangePosition = 2
                };

                FundRawTransactionResponse funded = node.CreateRPCClient().FundRawTransaction(tx, options);

                Money fee = this.CheckFunding(node, funded.Transaction);

                Money totalInputs = this.GetTotalInputValue(node, funded.Transaction);

                Assert.Equal(new Money(this.network.MinRelayTxFee), fee);

                Assert.Equal(2, funded.ChangePos);
                Assert.Equal(changeAddress.ScriptPubKey, funded.Transaction.Outputs[funded.ChangePos].ScriptPubKey);

                // Check that the value of the change in the specified position is the expected value.
                Assert.Equal(totalInputs - totalSent - fee, funded.Transaction.Outputs[funded.ChangePos].Value);
            }
        }