|
41 | 41 | HIGH = 500
|
42 | 42 | TOO_HIGH = 100000
|
43 | 43 |
|
| 44 | +def get_change_address(tx, node): |
| 45 | + tx_details = node.getrawtransaction(tx, 1) |
| 46 | + txout_addresses = [txout['scriptPubKey']['address'] for txout in tx_details["vout"]] |
| 47 | + return [address for address in txout_addresses if node.getaddressinfo(address)["ischange"]] |
44 | 48 |
|
45 | 49 | class BumpFeeTest(BitcoinTestFramework):
|
46 | 50 | def add_options(self, parser):
|
@@ -105,6 +109,7 @@ def run_test(self):
|
105 | 109 | # These tests wipe out a number of utxos that are expected in other tests
|
106 | 110 | test_small_output_with_feerate_succeeds(self, rbf_node, dest_address)
|
107 | 111 | test_no_more_inputs_fails(self, rbf_node, dest_address)
|
| 112 | + self.test_bump_back_to_yourself() |
108 | 113 |
|
109 | 114 | def test_invalid_parameters(self, rbf_node, peer_node, dest_address):
|
110 | 115 | self.log.info('Test invalid parameters')
|
@@ -169,6 +174,54 @@ def test_invalid_parameters(self, rbf_node, peer_node, dest_address):
|
169 | 174 |
|
170 | 175 | self.clear_mempool()
|
171 | 176 |
|
| 177 | + def test_bump_back_to_yourself(self): |
| 178 | + self.log.info("Test that bumpfee can send coins back to yourself") |
| 179 | + node = self.nodes[1] |
| 180 | + |
| 181 | + node.createwallet("back_to_yourself") |
| 182 | + wallet = node.get_wallet_rpc("back_to_yourself") |
| 183 | + |
| 184 | + # Make 3 UTXOs |
| 185 | + addr = wallet.getnewaddress() |
| 186 | + for _ in range(3): |
| 187 | + self.nodes[0].sendtoaddress(addr, 5) |
| 188 | + self.generate(self.nodes[0], 1) |
| 189 | + |
| 190 | + # Create a tx with two outputs. recipient and change. |
| 191 | + tx = wallet.send(outputs={wallet.getnewaddress(): 9}, fee_rate=2) |
| 192 | + tx_info = wallet.gettransaction(txid=tx["txid"], verbose=True) |
| 193 | + assert_equal(len(tx_info["decoded"]["vout"]), 2) |
| 194 | + assert_equal(len(tx_info["decoded"]["vin"]), 2) |
| 195 | + |
| 196 | + # Bump tx, send coins back to change address. |
| 197 | + change_addr = get_change_address(tx["txid"], wallet)[0] |
| 198 | + out_amount = 10 |
| 199 | + bumped = wallet.bumpfee(txid=tx["txid"], options={"fee_rate": 20, "outputs": [{change_addr: out_amount}]}) |
| 200 | + bumped_tx = wallet.gettransaction(txid=bumped["txid"], verbose=True) |
| 201 | + assert_equal(len(bumped_tx["decoded"]["vout"]), 1) |
| 202 | + assert_equal(len(bumped_tx["decoded"]["vin"]), 2) |
| 203 | + assert_equal(bumped_tx["decoded"]["vout"][0]["value"] + bumped["fee"], out_amount) |
| 204 | + |
| 205 | + # Bump tx again, now test send fewer coins back to change address. |
| 206 | + out_amount = 6 |
| 207 | + bumped = wallet.bumpfee(txid=bumped["txid"], options={"fee_rate": 40, "outputs": [{change_addr: out_amount}]}) |
| 208 | + bumped_tx = wallet.gettransaction(txid=bumped["txid"], verbose=True) |
| 209 | + assert_equal(len(bumped_tx["decoded"]["vout"]), 2) |
| 210 | + assert_equal(len(bumped_tx["decoded"]["vin"]), 2) |
| 211 | + assert any(txout['value'] == out_amount - bumped["fee"] and txout['scriptPubKey']['address'] == change_addr for txout in bumped_tx['decoded']['vout']) |
| 212 | + # Check that total out amount is still equal to the previously bumped tx |
| 213 | + assert_equal(bumped_tx["decoded"]["vout"][0]["value"] + bumped_tx["decoded"]["vout"][1]["value"] + bumped["fee"], 10) |
| 214 | + |
| 215 | + # Bump tx again, send more coins back to change address. The process will add another input to cover the target. |
| 216 | + out_amount = 12 |
| 217 | + bumped = wallet.bumpfee(txid=bumped["txid"], options={"fee_rate": 80, "outputs": [{change_addr: out_amount}]}) |
| 218 | + bumped_tx = wallet.gettransaction(txid=bumped["txid"], verbose=True) |
| 219 | + assert_equal(len(bumped_tx["decoded"]["vout"]), 2) |
| 220 | + assert_equal(len(bumped_tx["decoded"]["vin"]), 3) |
| 221 | + assert any(txout['value'] == out_amount - bumped["fee"] and txout['scriptPubKey']['address'] == change_addr for txout in bumped_tx['decoded']['vout']) |
| 222 | + assert_equal(bumped_tx["decoded"]["vout"][0]["value"] + bumped_tx["decoded"]["vout"][1]["value"] + bumped["fee"], 15) |
| 223 | + |
| 224 | + node.unloadwallet("back_to_yourself") |
172 | 225 |
|
173 | 226 | def test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address):
|
174 | 227 | self.log.info('Test simple bumpfee: {}'.format(mode))
|
@@ -628,21 +681,16 @@ def test_locked_wallet_fails(self, rbf_node, dest_address):
|
628 | 681 | def test_change_script_match(self, rbf_node, dest_address):
|
629 | 682 | self.log.info('Test that the same change addresses is used for the replacement transaction when possible')
|
630 | 683 |
|
631 |
| - def get_change_address(tx): |
632 |
| - tx_details = rbf_node.getrawtransaction(tx, 1) |
633 |
| - txout_addresses = [txout['scriptPubKey']['address'] for txout in tx_details["vout"]] |
634 |
| - return [address for address in txout_addresses if rbf_node.getaddressinfo(address)["ischange"]] |
635 |
| - |
636 | 684 | # Check that there is only one change output
|
637 | 685 | rbfid = spend_one_input(rbf_node, dest_address)
|
638 |
| - change_addresses = get_change_address(rbfid) |
| 686 | + change_addresses = get_change_address(rbfid, rbf_node) |
639 | 687 | assert_equal(len(change_addresses), 1)
|
640 | 688 |
|
641 | 689 | # Now find that address in each subsequent tx, and no other change
|
642 | 690 | bumped_total_tx = rbf_node.bumpfee(rbfid, {"fee_rate": ECONOMICAL})
|
643 |
| - assert_equal(change_addresses, get_change_address(bumped_total_tx['txid'])) |
| 691 | + assert_equal(change_addresses, get_change_address(bumped_total_tx['txid'], rbf_node)) |
644 | 692 | bumped_rate_tx = rbf_node.bumpfee(bumped_total_tx["txid"])
|
645 |
| - assert_equal(change_addresses, get_change_address(bumped_rate_tx['txid'])) |
| 693 | + assert_equal(change_addresses, get_change_address(bumped_rate_tx['txid'], rbf_node)) |
646 | 694 | self.clear_mempool()
|
647 | 695 |
|
648 | 696 |
|
|
0 commit comments