wallet_bumpfee.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2016-2022 The Bitcoin Core developers 3 # Distributed under the MIT software license, see the accompanying 4 # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 """Test the bumpfee RPC. 6 7 Verifies that the bumpfee RPC creates replacement transactions successfully when 8 its preconditions are met, and returns appropriate errors in other cases. 9 10 This module consists of around a dozen individual test cases implemented in the 11 top-level functions named as test_<test_case_description>. The test functions 12 can be disabled or reordered if needed for debugging. If new test cases are 13 added in the future, they should try to follow the same convention and not 14 make assumptions about execution order. 15 """ 16 from decimal import Decimal 17 18 from test_framework.blocktools import ( 19 COINBASE_MATURITY, 20 ) 21 from test_framework.messages import ( 22 MAX_BIP125_RBF_SEQUENCE, 23 ) 24 from test_framework.test_framework import BitcoinTestFramework 25 from test_framework.util import ( 26 assert_equal, 27 assert_fee_amount, 28 assert_greater_than, 29 assert_raises_rpc_error, 30 get_fee, 31 find_vout_for_address, 32 ) 33 from test_framework.wallet import MiniWallet 34 35 36 WALLET_PASSPHRASE = "test" 37 WALLET_PASSPHRASE_TIMEOUT = 3600 38 39 # Fee rates (sat/vB) 40 INSUFFICIENT = 1 41 ECONOMICAL = 50 42 NORMAL = 100 43 HIGH = 500 44 TOO_HIGH = 100000 45 46 def get_change_address(tx, node): 47 tx_details = node.getrawtransaction(tx, 1) 48 txout_addresses = [txout['scriptPubKey']['address'] for txout in tx_details["vout"]] 49 return [address for address in txout_addresses if node.getaddressinfo(address)["ischange"]] 50 51 class BumpFeeTest(BitcoinTestFramework): 52 def add_options(self, parser): 53 self.add_wallet_options(parser) 54 55 def set_test_params(self): 56 self.num_nodes = 2 57 self.setup_clean_chain = True 58 # whitelist peers to speed up tx relay / mempool sync 59 self.noban_tx_relay = True 60 self.extra_args = [[ 61 "-walletrbf={}".format(i), 62 "-mintxfee=0.00002", 63 "-addresstype=bech32", 64 ] for i in range(self.num_nodes)] 65 66 def skip_test_if_missing_module(self): 67 self.skip_if_no_wallet() 68 69 def clear_mempool(self): 70 # Clear mempool between subtests. The subtests may only depend on chainstate (utxos) 71 self.generate(self.nodes[1], 1) 72 73 def run_test(self): 74 # Encrypt wallet for test_locked_wallet_fails test 75 self.nodes[1].encryptwallet(WALLET_PASSPHRASE) 76 self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) 77 78 peer_node, rbf_node = self.nodes 79 rbf_node_address = rbf_node.getnewaddress() 80 81 # fund rbf node with 10 coins of 0.001 btc (100,000 satoshis) 82 self.log.info("Mining blocks...") 83 self.generate(peer_node, 110) 84 for _ in range(25): 85 peer_node.sendtoaddress(rbf_node_address, 0.001) 86 self.sync_all() 87 self.generate(peer_node, 1) 88 assert_equal(rbf_node.getbalance(), Decimal("0.025")) 89 90 self.log.info("Running tests") 91 dest_address = peer_node.getnewaddress() 92 for mode in ["default", "fee_rate", "new_outputs"]: 93 test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address) 94 self.test_invalid_parameters(rbf_node, peer_node, dest_address) 95 test_segwit_bumpfee_succeeds(self, rbf_node, dest_address) 96 test_nonrbf_bumpfee_fails(self, peer_node, dest_address) 97 test_notmine_bumpfee(self, rbf_node, peer_node, dest_address) 98 test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_address) 99 test_bumpfee_with_abandoned_descendant_succeeds(self, rbf_node, rbf_node_address, dest_address) 100 test_dust_to_fee(self, rbf_node, dest_address) 101 test_watchonly_psbt(self, peer_node, rbf_node, dest_address) 102 test_rebumping(self, rbf_node, dest_address) 103 test_rebumping_not_replaceable(self, rbf_node, dest_address) 104 test_bumpfee_already_spent(self, rbf_node, dest_address) 105 test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address) 106 test_bumpfee_metadata(self, rbf_node, dest_address) 107 test_locked_wallet_fails(self, rbf_node, dest_address) 108 test_change_script_match(self, rbf_node, dest_address) 109 test_settxfee(self, rbf_node, dest_address) 110 test_maxtxfee_fails(self, rbf_node, dest_address) 111 # These tests wipe out a number of utxos that are expected in other tests 112 test_small_output_with_feerate_succeeds(self, rbf_node, dest_address) 113 test_no_more_inputs_fails(self, rbf_node, dest_address) 114 self.test_bump_back_to_yourself() 115 self.test_provided_change_pos(rbf_node) 116 self.test_single_output() 117 118 # Context independent tests 119 test_feerate_checks_replaced_outputs(self, rbf_node, peer_node) 120 121 def test_invalid_parameters(self, rbf_node, peer_node, dest_address): 122 self.log.info('Test invalid parameters') 123 rbfid = spend_one_input(rbf_node, dest_address) 124 self.sync_mempools((rbf_node, peer_node)) 125 assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool() 126 127 for key in ["totalFee", "feeRate"]: 128 assert_raises_rpc_error(-3, "Unexpected key {}".format(key), rbf_node.bumpfee, rbfid, {key: NORMAL}) 129 130 # Bumping to just above minrelay should fail to increase the total fee enough. 131 assert_raises_rpc_error(-8, "Insufficient total fee 0.00000141", rbf_node.bumpfee, rbfid, fee_rate=INSUFFICIENT) 132 133 self.log.info("Test invalid fee rate settings") 134 assert_raises_rpc_error(-4, "Specified or calculated fee 0.141 is too high (cannot be higher than -maxtxfee 0.10", 135 rbf_node.bumpfee, rbfid, fee_rate=TOO_HIGH) 136 # Test fee_rate with zero values. 137 msg = "Insufficient total fee 0.00" 138 for zero_value in [0, 0.000, 0.00000000, "0", "0.000", "0.00000000"]: 139 assert_raises_rpc_error(-8, msg, rbf_node.bumpfee, rbfid, fee_rate=zero_value) 140 msg = "Invalid amount" 141 # Test fee_rate values that don't pass fixed-point parsing checks. 142 for invalid_value in ["", 0.000000001, 1e-09, 1.111111111, 1111111111111111, "31.999999999999999999999"]: 143 assert_raises_rpc_error(-3, msg, rbf_node.bumpfee, rbfid, fee_rate=invalid_value) 144 # Test fee_rate values that cannot be represented in sat/vB. 145 for invalid_value in [0.0001, 0.00000001, 0.00099999, 31.99999999]: 146 assert_raises_rpc_error(-3, msg, rbf_node.bumpfee, rbfid, fee_rate=invalid_value) 147 # Test fee_rate out of range (negative number). 148 assert_raises_rpc_error(-3, "Amount out of range", rbf_node.bumpfee, rbfid, fee_rate=-1) 149 # Test type error. 150 for value in [{"foo": "bar"}, True]: 151 assert_raises_rpc_error(-3, "Amount is not a number or string", rbf_node.bumpfee, rbfid, fee_rate=value) 152 153 self.log.info("Test explicit fee rate raises RPC error if both fee_rate and conf_target are passed") 154 assert_raises_rpc_error(-8, "Cannot specify both conf_target and fee_rate. Please provide either a confirmation " 155 "target in blocks for automatic fee estimation, or an explicit fee rate.", 156 rbf_node.bumpfee, rbfid, conf_target=NORMAL, fee_rate=NORMAL) 157 158 self.log.info("Test explicit fee rate raises RPC error if both fee_rate and estimate_mode are passed") 159 assert_raises_rpc_error(-8, "Cannot specify both estimate_mode and fee_rate", 160 rbf_node.bumpfee, rbfid, estimate_mode="economical", fee_rate=NORMAL) 161 162 self.log.info("Test invalid conf_target settings") 163 assert_raises_rpc_error(-8, "confTarget and conf_target options should not both be set", 164 rbf_node.bumpfee, rbfid, {"confTarget": 123, "conf_target": 456}) 165 166 self.log.info("Test invalid estimate_mode settings") 167 for k, v in {"number": 42, "object": {"foo": "bar"}}.items(): 168 assert_raises_rpc_error(-3, f"JSON value of type {k} for field estimate_mode is not of expected type string", 169 rbf_node.bumpfee, rbfid, estimate_mode=v) 170 for mode in ["foo", Decimal("3.1415"), "sat/B", "BTC/kB"]: 171 assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"', 172 rbf_node.bumpfee, rbfid, estimate_mode=mode) 173 174 self.log.info("Test invalid outputs values") 175 assert_raises_rpc_error(-8, "Invalid parameter, output argument cannot be an empty array", 176 rbf_node.bumpfee, rbfid, {"outputs": []}) 177 assert_raises_rpc_error(-8, "Invalid parameter, duplicated address: " + dest_address, 178 rbf_node.bumpfee, rbfid, {"outputs": [{dest_address: 0.1}, {dest_address: 0.2}]}) 179 assert_raises_rpc_error(-8, "Invalid parameter, duplicate key: data", 180 rbf_node.bumpfee, rbfid, {"outputs": [{"data": "deadbeef"}, {"data": "deadbeef"}]}) 181 182 self.log.info("Test original_change_index option") 183 assert_raises_rpc_error(-1, "JSON integer out of range", rbf_node.bumpfee, rbfid, {"original_change_index": -1}) 184 assert_raises_rpc_error(-8, "Change position is out of range", rbf_node.bumpfee, rbfid, {"original_change_index": 2}) 185 186 self.log.info("Test outputs and original_change_index cannot both be provided") 187 assert_raises_rpc_error(-8, "The options 'outputs' and 'original_change_index' are incompatible. You can only either specify a new set of outputs, or designate a change output to be recycled.", rbf_node.bumpfee, rbfid, {"original_change_index": 2, "outputs": [{dest_address: 0.1}]}) 188 189 self.clear_mempool() 190 191 def test_bump_back_to_yourself(self): 192 self.log.info("Test that bumpfee can send coins back to yourself") 193 node = self.nodes[1] 194 195 node.createwallet("back_to_yourself") 196 wallet = node.get_wallet_rpc("back_to_yourself") 197 198 # Make 3 UTXOs 199 addr = wallet.getnewaddress() 200 for _ in range(3): 201 self.nodes[0].sendtoaddress(addr, 5) 202 self.generate(self.nodes[0], 1) 203 204 # Create a tx with two outputs. recipient and change. 205 tx = wallet.send(outputs={wallet.getnewaddress(): 9}, fee_rate=2) 206 tx_info = wallet.gettransaction(txid=tx["txid"], verbose=True) 207 assert_equal(len(tx_info["decoded"]["vout"]), 2) 208 assert_equal(len(tx_info["decoded"]["vin"]), 2) 209 210 # Bump tx, send coins back to change address. 211 change_addr = get_change_address(tx["txid"], wallet)[0] 212 out_amount = 10 213 bumped = wallet.bumpfee(txid=tx["txid"], options={"fee_rate": 20, "outputs": [{change_addr: out_amount}]}) 214 bumped_tx = wallet.gettransaction(txid=bumped["txid"], verbose=True) 215 assert_equal(len(bumped_tx["decoded"]["vout"]), 1) 216 assert_equal(len(bumped_tx["decoded"]["vin"]), 2) 217 assert_equal(bumped_tx["decoded"]["vout"][0]["value"] + bumped["fee"], out_amount) 218 219 # Bump tx again, now test send fewer coins back to change address. 220 out_amount = 6 221 bumped = wallet.bumpfee(txid=bumped["txid"], options={"fee_rate": 40, "outputs": [{change_addr: out_amount}]}) 222 bumped_tx = wallet.gettransaction(txid=bumped["txid"], verbose=True) 223 assert_equal(len(bumped_tx["decoded"]["vout"]), 2) 224 assert_equal(len(bumped_tx["decoded"]["vin"]), 2) 225 assert any(txout['value'] == out_amount - bumped["fee"] and txout['scriptPubKey']['address'] == change_addr for txout in bumped_tx['decoded']['vout']) 226 # Check that total out amount is still equal to the previously bumped tx 227 assert_equal(bumped_tx["decoded"]["vout"][0]["value"] + bumped_tx["decoded"]["vout"][1]["value"] + bumped["fee"], 10) 228 229 # Bump tx again, send more coins back to change address. The process will add another input to cover the target. 230 out_amount = 12 231 bumped = wallet.bumpfee(txid=bumped["txid"], options={"fee_rate": 80, "outputs": [{change_addr: out_amount}]}) 232 bumped_tx = wallet.gettransaction(txid=bumped["txid"], verbose=True) 233 assert_equal(len(bumped_tx["decoded"]["vout"]), 2) 234 assert_equal(len(bumped_tx["decoded"]["vin"]), 3) 235 assert any(txout['value'] == out_amount - bumped["fee"] and txout['scriptPubKey']['address'] == change_addr for txout in bumped_tx['decoded']['vout']) 236 assert_equal(bumped_tx["decoded"]["vout"][0]["value"] + bumped_tx["decoded"]["vout"][1]["value"] + bumped["fee"], 15) 237 238 node.unloadwallet("back_to_yourself") 239 240 def test_provided_change_pos(self, rbf_node): 241 self.log.info("Test the original_change_index option") 242 243 change_addr = rbf_node.getnewaddress() 244 dest_addr = rbf_node.getnewaddress() 245 assert_equal(rbf_node.getaddressinfo(change_addr)["ischange"], False) 246 assert_equal(rbf_node.getaddressinfo(dest_addr)["ischange"], False) 247 248 send_res = rbf_node.send(outputs=[{dest_addr: 1}], options={"change_address": change_addr}) 249 assert send_res["complete"] 250 txid = send_res["txid"] 251 252 tx = rbf_node.gettransaction(txid=txid, verbose=True) 253 assert_equal(len(tx["decoded"]["vout"]), 2) 254 255 change_pos = find_vout_for_address(rbf_node, txid, change_addr) 256 change_value = tx["decoded"]["vout"][change_pos]["value"] 257 258 bumped = rbf_node.bumpfee(txid, {"original_change_index": change_pos}) 259 new_txid = bumped["txid"] 260 261 new_tx = rbf_node.gettransaction(txid=new_txid, verbose=True) 262 assert_equal(len(new_tx["decoded"]["vout"]), 2) 263 new_change_pos = find_vout_for_address(rbf_node, new_txid, change_addr) 264 new_change_value = new_tx["decoded"]["vout"][new_change_pos]["value"] 265 266 assert_greater_than(change_value, new_change_value) 267 268 269 def test_single_output(self): 270 self.log.info("Test that single output txs can be bumped") 271 node = self.nodes[1] 272 273 node.createwallet("single_out_rbf") 274 wallet = node.get_wallet_rpc("single_out_rbf") 275 276 addr = wallet.getnewaddress() 277 amount = Decimal("0.001") 278 # Make 2 UTXOs 279 self.nodes[0].sendtoaddress(addr, amount) 280 self.nodes[0].sendtoaddress(addr, amount) 281 self.generate(self.nodes[0], 1) 282 utxos = wallet.listunspent() 283 284 tx = wallet.sendall(recipients=[wallet.getnewaddress()], fee_rate=2, options={"inputs": [utxos[0]]}) 285 286 # Set the only output with a crazy high feerate as change, should fail as the output would be dust 287 assert_raises_rpc_error(-4, "The transaction amount is too small to pay the fee", wallet.bumpfee, txid=tx["txid"], options={"fee_rate": 1100, "original_change_index": 0}) 288 289 # Specify single output as change successfully 290 bumped = wallet.bumpfee(txid=tx["txid"], options={"fee_rate": 10, "original_change_index": 0}) 291 bumped_tx = wallet.gettransaction(txid=bumped["txid"], verbose=True) 292 assert_equal(len(bumped_tx["decoded"]["vout"]), 1) 293 assert_equal(len(bumped_tx["decoded"]["vin"]), 1) 294 assert_equal(bumped_tx["decoded"]["vout"][0]["value"] + bumped["fee"], amount) 295 assert_fee_amount(bumped["fee"], bumped_tx["decoded"]["vsize"], Decimal(10) / Decimal(1e8) * 1000) 296 297 # Bumping without specifying change adds a new input and output 298 bumped = wallet.bumpfee(txid=bumped["txid"], options={"fee_rate": 20}) 299 bumped_tx = wallet.gettransaction(txid=bumped["txid"], verbose=True) 300 assert_equal(len(bumped_tx["decoded"]["vout"]), 2) 301 assert_equal(len(bumped_tx["decoded"]["vin"]), 2) 302 assert_fee_amount(bumped["fee"], bumped_tx["decoded"]["vsize"], Decimal(20) / Decimal(1e8) * 1000) 303 304 wallet.unloadwallet() 305 306 def test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address): 307 self.log.info('Test simple bumpfee: {}'.format(mode)) 308 rbfid = spend_one_input(rbf_node, dest_address) 309 rbftx = rbf_node.gettransaction(rbfid) 310 self.sync_mempools((rbf_node, peer_node)) 311 assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool() 312 if mode == "fee_rate": 313 bumped_psbt = rbf_node.psbtbumpfee(rbfid, fee_rate=str(NORMAL)) 314 bumped_tx = rbf_node.bumpfee(rbfid, fee_rate=NORMAL) 315 elif mode == "new_outputs": 316 new_address = peer_node.getnewaddress() 317 bumped_psbt = rbf_node.psbtbumpfee(rbfid, outputs={new_address: 0.0003}) 318 bumped_tx = rbf_node.bumpfee(rbfid, outputs={new_address: 0.0003}) 319 else: 320 bumped_psbt = rbf_node.psbtbumpfee(rbfid) 321 bumped_tx = rbf_node.bumpfee(rbfid) 322 assert_equal(bumped_tx["errors"], []) 323 assert bumped_tx["fee"] > -rbftx["fee"] 324 assert_equal(bumped_tx["origfee"], -rbftx["fee"]) 325 assert "psbt" not in bumped_tx 326 assert_equal(bumped_psbt["errors"], []) 327 assert bumped_psbt["fee"] > -rbftx["fee"] 328 assert_equal(bumped_psbt["origfee"], -rbftx["fee"]) 329 assert "psbt" in bumped_psbt 330 # check that bumped_tx propagates, original tx was evicted and has a wallet conflict 331 self.sync_mempools((rbf_node, peer_node)) 332 assert bumped_tx["txid"] in rbf_node.getrawmempool() 333 assert bumped_tx["txid"] in peer_node.getrawmempool() 334 assert rbfid not in rbf_node.getrawmempool() 335 assert rbfid not in peer_node.getrawmempool() 336 oldwtx = rbf_node.gettransaction(rbfid) 337 assert len(oldwtx["walletconflicts"]) > 0 338 # check wallet transaction replaces and replaced_by values 339 bumpedwtx = rbf_node.gettransaction(bumped_tx["txid"]) 340 assert_equal(oldwtx["replaced_by_txid"], bumped_tx["txid"]) 341 assert_equal(bumpedwtx["replaces_txid"], rbfid) 342 # if this is a new_outputs test, check that outputs were indeed replaced 343 if mode == "new_outputs": 344 assert len(bumpedwtx["details"]) == 1 345 assert bumpedwtx["details"][0]["address"] == new_address 346 self.clear_mempool() 347 348 349 def test_segwit_bumpfee_succeeds(self, rbf_node, dest_address): 350 self.log.info('Test that segwit-sourcing bumpfee works') 351 # Create a transaction with segwit output, then create an RBF transaction 352 # which spends it, and make sure bumpfee can be called on it. 353 354 segwit_out = rbf_node.getnewaddress(address_type='bech32') 355 segwitid = rbf_node.send({segwit_out: "0.0009"}, options={"change_position": 1})["txid"] 356 357 rbfraw = rbf_node.createrawtransaction([{ 358 'txid': segwitid, 359 'vout': 0, 360 "sequence": MAX_BIP125_RBF_SEQUENCE 361 }], {dest_address: Decimal("0.0005"), 362 rbf_node.getrawchangeaddress(): Decimal("0.0003")}) 363 rbfsigned = rbf_node.signrawtransactionwithwallet(rbfraw) 364 rbfid = rbf_node.sendrawtransaction(rbfsigned["hex"]) 365 assert rbfid in rbf_node.getrawmempool() 366 367 bumped_tx = rbf_node.bumpfee(rbfid) 368 assert bumped_tx["txid"] in rbf_node.getrawmempool() 369 assert rbfid not in rbf_node.getrawmempool() 370 self.clear_mempool() 371 372 373 def test_nonrbf_bumpfee_fails(self, peer_node, dest_address): 374 self.log.info('Test that we cannot replace a non RBF transaction') 375 not_rbfid = peer_node.sendtoaddress(dest_address, Decimal("0.00090000")) 376 assert_raises_rpc_error(-4, "Transaction is not BIP 125 replaceable", peer_node.bumpfee, not_rbfid) 377 self.clear_mempool() 378 379 380 def test_notmine_bumpfee(self, rbf_node, peer_node, dest_address): 381 self.log.info('Test that it cannot bump fee if non-owned inputs are included') 382 # here, the rbftx has a peer_node coin and then adds a rbf_node input 383 # Note that this test depends upon the RPC code checking input ownership prior to change outputs 384 # (since it can't use fundrawtransaction, it lacks a proper change output) 385 fee = Decimal("0.001") 386 utxos = [node.listunspent(minimumAmount=fee)[-1] for node in (rbf_node, peer_node)] 387 inputs = [{ 388 "txid": utxo["txid"], 389 "vout": utxo["vout"], 390 "address": utxo["address"], 391 "sequence": MAX_BIP125_RBF_SEQUENCE 392 } for utxo in utxos] 393 output_val = sum(utxo["amount"] for utxo in utxos) - fee 394 rawtx = rbf_node.createrawtransaction(inputs, {dest_address: output_val}) 395 signedtx = rbf_node.signrawtransactionwithwallet(rawtx) 396 signedtx = peer_node.signrawtransactionwithwallet(signedtx["hex"]) 397 rbfid = rbf_node.sendrawtransaction(signedtx["hex"]) 398 entry = rbf_node.getmempoolentry(rbfid) 399 old_fee = entry["fees"]["base"] 400 old_feerate = int(old_fee / entry["vsize"] * Decimal(1e8)) 401 assert_raises_rpc_error(-4, "Transaction contains inputs that don't belong to this wallet", 402 rbf_node.bumpfee, rbfid) 403 404 def finish_psbtbumpfee(psbt): 405 psbt = rbf_node.walletprocesspsbt(psbt) 406 psbt = peer_node.walletprocesspsbt(psbt["psbt"]) 407 res = rbf_node.testmempoolaccept([psbt["hex"]]) 408 assert res[0]["allowed"] 409 assert_greater_than(res[0]["fees"]["base"], old_fee) 410 411 self.log.info("Test that psbtbumpfee works for non-owned inputs") 412 psbt = rbf_node.psbtbumpfee(txid=rbfid) 413 finish_psbtbumpfee(psbt["psbt"]) 414 415 psbt = rbf_node.psbtbumpfee(txid=rbfid, fee_rate=old_feerate + 10) 416 finish_psbtbumpfee(psbt["psbt"]) 417 418 self.clear_mempool() 419 420 421 def test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_address): 422 self.log.info('Test that fee cannot be bumped when it has descendant') 423 # parent is send-to-self, so we don't have to check which output is change when creating the child tx 424 parent_id = spend_one_input(rbf_node, rbf_node_address) 425 tx = rbf_node.createrawtransaction([{"txid": parent_id, "vout": 0}], {dest_address: 0.00020000}) 426 tx = rbf_node.signrawtransactionwithwallet(tx) 427 rbf_node.sendrawtransaction(tx["hex"]) 428 assert_raises_rpc_error(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id) 429 430 # create tx with descendant in the mempool by using MiniWallet 431 miniwallet = MiniWallet(rbf_node) 432 parent_id = spend_one_input(rbf_node, miniwallet.get_address()) 433 tx = rbf_node.gettransaction(txid=parent_id, verbose=True)['decoded'] 434 miniwallet.scan_tx(tx) 435 miniwallet.send_self_transfer(from_node=rbf_node) 436 assert_raises_rpc_error(-8, "Transaction has descendants in the mempool", rbf_node.bumpfee, parent_id) 437 self.clear_mempool() 438 439 440 def test_bumpfee_with_abandoned_descendant_succeeds(self, rbf_node, rbf_node_address, dest_address): 441 self.log.info('Test that fee can be bumped when it has abandoned descendant') 442 # parent is send-to-self, so we don't have to check which output is change when creating the child tx 443 parent_id = spend_one_input(rbf_node, rbf_node_address) 444 # Submit child transaction with low fee 445 child_id = rbf_node.send(outputs={dest_address: 0.00020000}, 446 options={"inputs": [{"txid": parent_id, "vout": 0}], "fee_rate": 2})["txid"] 447 assert child_id in rbf_node.getrawmempool() 448 449 # Restart the node with higher min relay fee so the descendant tx is no longer in mempool so that we can abandon it 450 self.restart_node(1, ['-minrelaytxfee=0.00005'] + self.extra_args[1]) 451 rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) 452 self.connect_nodes(1, 0) 453 assert parent_id in rbf_node.getrawmempool() 454 assert child_id not in rbf_node.getrawmempool() 455 # Should still raise an error even if not in mempool 456 assert_raises_rpc_error(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id) 457 # Now abandon the child transaction and bump the original 458 rbf_node.abandontransaction(child_id) 459 bumped_result = rbf_node.bumpfee(parent_id, {"fee_rate": HIGH}) 460 assert bumped_result['txid'] in rbf_node.getrawmempool() 461 assert parent_id not in rbf_node.getrawmempool() 462 # Cleanup 463 self.restart_node(1, self.extra_args[1]) 464 rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) 465 self.connect_nodes(1, 0) 466 self.clear_mempool() 467 468 469 def test_small_output_with_feerate_succeeds(self, rbf_node, dest_address): 470 self.log.info('Testing small output with feerate bump succeeds') 471 472 # Make sure additional inputs exist 473 self.generatetoaddress(rbf_node, COINBASE_MATURITY + 1, rbf_node.getnewaddress()) 474 rbfid = spend_one_input(rbf_node, dest_address) 475 input_list = rbf_node.getrawtransaction(rbfid, 1)["vin"] 476 assert_equal(len(input_list), 1) 477 original_txin = input_list[0] 478 self.log.info('Keep bumping until transaction fee out-spends non-destination value') 479 tx_fee = 0 480 while True: 481 input_list = rbf_node.getrawtransaction(rbfid, 1)["vin"] 482 new_item = list(input_list)[0] 483 assert_equal(len(input_list), 1) 484 assert_equal(original_txin["txid"], new_item["txid"]) 485 assert_equal(original_txin["vout"], new_item["vout"]) 486 rbfid_new_details = rbf_node.bumpfee(rbfid) 487 rbfid_new = rbfid_new_details["txid"] 488 raw_pool = rbf_node.getrawmempool() 489 assert rbfid not in raw_pool 490 assert rbfid_new in raw_pool 491 rbfid = rbfid_new 492 tx_fee = rbfid_new_details["fee"] 493 494 # Total value from input not going to destination 495 if tx_fee > Decimal('0.00050000'): 496 break 497 498 # input(s) have been added 499 final_input_list = rbf_node.getrawtransaction(rbfid, 1)["vin"] 500 assert_greater_than(len(final_input_list), 1) 501 # Original input is in final set 502 assert [txin for txin in final_input_list 503 if txin["txid"] == original_txin["txid"] 504 and txin["vout"] == original_txin["vout"]] 505 506 self.generatetoaddress(rbf_node, 1, rbf_node.getnewaddress()) 507 assert_equal(rbf_node.gettransaction(rbfid)["confirmations"], 1) 508 self.clear_mempool() 509 510 511 def test_dust_to_fee(self, rbf_node, dest_address): 512 self.log.info('Test that bumped output that is dust is dropped to fee') 513 rbfid = spend_one_input(rbf_node, dest_address) 514 fulltx = rbf_node.getrawtransaction(rbfid, 1) 515 # The DER formatting used by Bitcoin to serialize ECDSA signatures means that signatures can have a 516 # variable size of 70-72 bytes (or possibly even less), with most being 71 or 72 bytes. The signature 517 # in the witness is divided by 4 for the vsize, so this variance can take the weight across a 4-byte 518 # boundary. Thus expected transaction size (p2wpkh, 1 input, 2 outputs) is 140-141 vbytes, usually 141. 519 if not 140 <= fulltx["vsize"] <= 141: 520 raise AssertionError("Invalid tx vsize of {} (140-141 expected), full tx: {}".format(fulltx["vsize"], fulltx)) 521 # Bump with fee_rate of 350.25 sat/vB vbytes to create dust. 522 # Expected fee is 141 vbytes * fee_rate 0.00350250 BTC / 1000 vbytes = 0.00049385 BTC. 523 # or occasionally 140 vbytes * fee_rate 0.00350250 BTC / 1000 vbytes = 0.00049035 BTC. 524 # Dust should be dropped to the fee, so actual bump fee is 0.00050000 BTC. 525 bumped_tx = rbf_node.bumpfee(rbfid, fee_rate=350.25) 526 full_bumped_tx = rbf_node.getrawtransaction(bumped_tx["txid"], 1) 527 assert_equal(bumped_tx["fee"], Decimal("0.00050000")) 528 assert_equal(len(fulltx["vout"]), 2) 529 assert_equal(len(full_bumped_tx["vout"]), 1) # change output is eliminated 530 assert_equal(full_bumped_tx["vout"][0]['value'], Decimal("0.00050000")) 531 self.clear_mempool() 532 533 534 def test_settxfee(self, rbf_node, dest_address): 535 self.log.info('Test settxfee') 536 assert_raises_rpc_error(-8, "txfee cannot be less than min relay tx fee", rbf_node.settxfee, Decimal('0.000005')) 537 assert_raises_rpc_error(-8, "txfee cannot be less than wallet min fee", rbf_node.settxfee, Decimal('0.000015')) 538 # check that bumpfee reacts correctly to the use of settxfee (paytxfee) 539 rbfid = spend_one_input(rbf_node, dest_address) 540 requested_feerate = Decimal("0.00025000") 541 rbf_node.settxfee(requested_feerate) 542 bumped_tx = rbf_node.bumpfee(rbfid) 543 actual_feerate = bumped_tx["fee"] * 1000 / rbf_node.getrawtransaction(bumped_tx["txid"], True)["vsize"] 544 # Assert that the difference between the requested feerate and the actual 545 # feerate of the bumped transaction is small. 546 assert_greater_than(Decimal("0.00001000"), abs(requested_feerate - actual_feerate)) 547 rbf_node.settxfee(Decimal("0.00000000")) # unset paytxfee 548 549 # check that settxfee respects -maxtxfee 550 self.restart_node(1, ['-maxtxfee=0.000025'] + self.extra_args[1]) 551 assert_raises_rpc_error(-8, "txfee cannot be more than wallet max tx fee", rbf_node.settxfee, Decimal('0.00003')) 552 self.restart_node(1, self.extra_args[1]) 553 rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) 554 self.connect_nodes(1, 0) 555 self.clear_mempool() 556 557 558 def test_maxtxfee_fails(self, rbf_node, dest_address): 559 self.log.info('Test that bumpfee fails when it hits -maxtxfee') 560 # size of bumped transaction (p2wpkh, 1 input, 2 outputs): 141 vbytes 561 # expected bump fee of 141 vbytes * 0.00200000 BTC / 1000 vbytes = 0.00002820 BTC 562 # which exceeds maxtxfee and is expected to raise 563 self.restart_node(1, ['-maxtxfee=0.000025'] + self.extra_args[1]) 564 rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) 565 rbfid = spend_one_input(rbf_node, dest_address) 566 assert_raises_rpc_error(-4, "Unable to create transaction. Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)", rbf_node.bumpfee, rbfid) 567 self.restart_node(1, self.extra_args[1]) 568 rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) 569 self.connect_nodes(1, 0) 570 self.clear_mempool() 571 572 573 def test_watchonly_psbt(self, peer_node, rbf_node, dest_address): 574 self.log.info('Test that PSBT is returned for bumpfee in watchonly wallets') 575 priv_rec_desc = "wpkh([00000001/84'/1'/0']tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/0/*)#rweraev0" 576 pub_rec_desc = rbf_node.getdescriptorinfo(priv_rec_desc)["descriptor"] 577 priv_change_desc = "wpkh([00000001/84'/1'/0']tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/*)#j6uzqvuh" 578 pub_change_desc = rbf_node.getdescriptorinfo(priv_change_desc)["descriptor"] 579 # Create a wallet with private keys that can sign PSBTs 580 rbf_node.createwallet(wallet_name="signer", disable_private_keys=False, blank=True) 581 signer = rbf_node.get_wallet_rpc("signer") 582 assert signer.getwalletinfo()['private_keys_enabled'] 583 reqs = [{ 584 "desc": priv_rec_desc, 585 "timestamp": 0, 586 "range": [0,1], 587 "internal": False, 588 "keypool": False # Keys can only be imported to the keypool when private keys are disabled 589 }, 590 { 591 "desc": priv_change_desc, 592 "timestamp": 0, 593 "range": [0, 0], 594 "internal": True, 595 "keypool": False 596 }] 597 if self.options.descriptors: 598 result = signer.importdescriptors(reqs) 599 else: 600 result = signer.importmulti(reqs) 601 assert_equal(result, [{'success': True}, {'success': True}]) 602 603 # Create another wallet with just the public keys, which creates PSBTs 604 rbf_node.createwallet(wallet_name="watcher", disable_private_keys=True, blank=True) 605 watcher = rbf_node.get_wallet_rpc("watcher") 606 assert not watcher.getwalletinfo()['private_keys_enabled'] 607 608 reqs = [{ 609 "desc": pub_rec_desc, 610 "timestamp": 0, 611 "range": [0, 10], 612 "internal": False, 613 "keypool": True, 614 "watchonly": True, 615 "active": True, 616 }, { 617 "desc": pub_change_desc, 618 "timestamp": 0, 619 "range": [0, 10], 620 "internal": True, 621 "keypool": True, 622 "watchonly": True, 623 "active": True, 624 }] 625 if self.options.descriptors: 626 result = watcher.importdescriptors(reqs) 627 else: 628 result = watcher.importmulti(reqs) 629 assert_equal(result, [{'success': True}, {'success': True}]) 630 631 funding_address1 = watcher.getnewaddress(address_type='bech32') 632 funding_address2 = watcher.getnewaddress(address_type='bech32') 633 peer_node.sendmany("", {funding_address1: 0.001, funding_address2: 0.001}) 634 self.generate(peer_node, 1) 635 636 # Create single-input PSBT for transaction to be bumped 637 # Ensure the payment amount + change can be fully funded using one of the 0.001BTC inputs. 638 psbt = watcher.walletcreatefundedpsbt([watcher.listunspent()[0]], {dest_address: 0.0005}, 0, 639 {"fee_rate": 1, "add_inputs": False}, True)['psbt'] 640 psbt_signed = signer.walletprocesspsbt(psbt=psbt, sign=True, sighashtype="ALL", bip32derivs=True) 641 original_txid = watcher.sendrawtransaction(psbt_signed["hex"]) 642 assert_equal(len(watcher.decodepsbt(psbt)["tx"]["vin"]), 1) 643 644 # bumpfee can't be used on watchonly wallets 645 assert_raises_rpc_error(-4, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.", watcher.bumpfee, original_txid) 646 647 # Bump fee, obnoxiously high to add additional watchonly input 648 bumped_psbt = watcher.psbtbumpfee(original_txid, fee_rate=HIGH) 649 assert_greater_than(len(watcher.decodepsbt(bumped_psbt['psbt'])["tx"]["vin"]), 1) 650 assert "txid" not in bumped_psbt 651 assert_equal(bumped_psbt["origfee"], -watcher.gettransaction(original_txid)["fee"]) 652 assert not watcher.finalizepsbt(bumped_psbt["psbt"])["complete"] 653 654 # Sign bumped transaction 655 bumped_psbt_signed = signer.walletprocesspsbt(psbt=bumped_psbt["psbt"], sign=True, sighashtype="ALL", bip32derivs=True) 656 assert bumped_psbt_signed["complete"] 657 658 # Broadcast bumped transaction 659 bumped_txid = watcher.sendrawtransaction(bumped_psbt_signed["hex"]) 660 assert bumped_txid in rbf_node.getrawmempool() 661 assert original_txid not in rbf_node.getrawmempool() 662 663 rbf_node.unloadwallet("watcher") 664 rbf_node.unloadwallet("signer") 665 self.clear_mempool() 666 667 668 def test_rebumping(self, rbf_node, dest_address): 669 self.log.info('Test that re-bumping the original tx fails, but bumping successor works') 670 rbfid = spend_one_input(rbf_node, dest_address) 671 bumped = rbf_node.bumpfee(rbfid, fee_rate=ECONOMICAL) 672 assert_raises_rpc_error(-4, f"Cannot bump transaction {rbfid} which was already bumped by transaction {bumped['txid']}", 673 rbf_node.bumpfee, rbfid, fee_rate=NORMAL) 674 rbf_node.bumpfee(bumped["txid"], fee_rate=NORMAL) 675 self.clear_mempool() 676 677 678 def test_rebumping_not_replaceable(self, rbf_node, dest_address): 679 self.log.info('Test that re-bumping non-replaceable fails') 680 rbfid = spend_one_input(rbf_node, dest_address) 681 bumped = rbf_node.bumpfee(rbfid, fee_rate=ECONOMICAL, replaceable=False) 682 assert_raises_rpc_error(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"], 683 {"fee_rate": NORMAL}) 684 self.clear_mempool() 685 686 687 def test_bumpfee_already_spent(self, rbf_node, dest_address): 688 self.log.info('Test that bumping tx with already spent coin fails') 689 txid = spend_one_input(rbf_node, dest_address) 690 self.generate(rbf_node, 1) # spend coin simply by mining block with tx 691 spent_input = rbf_node.gettransaction(txid=txid, verbose=True)['decoded']['vin'][0] 692 assert_raises_rpc_error(-1, f"{spent_input['txid']}:{spent_input['vout']} is already spent", 693 rbf_node.bumpfee, txid, fee_rate=NORMAL) 694 695 696 def test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address): 697 self.log.info('Test that unconfirmed outputs from bumped txns are not spendable') 698 rbfid = spend_one_input(rbf_node, rbf_node_address) 699 rbftx = rbf_node.gettransaction(rbfid)["hex"] 700 assert rbfid in rbf_node.getrawmempool() 701 bumpid = rbf_node.bumpfee(rbfid)["txid"] 702 assert bumpid in rbf_node.getrawmempool() 703 assert rbfid not in rbf_node.getrawmempool() 704 705 # check that outputs from the bump transaction are not spendable 706 # due to the replaces_txid check in CWallet::AvailableCoins 707 assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == bumpid], []) 708 709 # submit a block with the rbf tx to clear the bump tx out of the mempool, 710 # then invalidate the block so the rbf tx will be put back in the mempool. 711 # This makes it possible to check whether the rbf tx outputs are 712 # spendable before the rbf tx is confirmed. 713 block = self.generateblock(rbf_node, output="raw(51)", transactions=[rbftx]) 714 # Can not abandon conflicted tx 715 assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: rbf_node.abandontransaction(txid=bumpid)) 716 rbf_node.invalidateblock(block["hash"]) 717 # Call abandon to make sure the wallet doesn't attempt to resubmit 718 # the bump tx and hope the wallet does not rebroadcast before we call. 719 rbf_node.abandontransaction(bumpid) 720 721 tx_bump_abandoned = rbf_node.gettransaction(bumpid) 722 for tx in tx_bump_abandoned['details']: 723 assert_equal(tx['abandoned'], True) 724 725 assert bumpid not in rbf_node.getrawmempool() 726 assert rbfid in rbf_node.getrawmempool() 727 728 # check that outputs from the rbf tx are not spendable before the 729 # transaction is confirmed, due to the replaced_by_txid check in 730 # CWallet::AvailableCoins 731 assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == rbfid], []) 732 733 # check that the main output from the rbf tx is spendable after confirmed 734 self.generate(rbf_node, 1, sync_fun=self.no_op) 735 assert_equal( 736 sum(1 for t in rbf_node.listunspent(minconf=0, include_unsafe=False) 737 if t["txid"] == rbfid and t["address"] == rbf_node_address and t["spendable"]), 1) 738 self.clear_mempool() 739 740 741 def test_bumpfee_metadata(self, rbf_node, dest_address): 742 self.log.info('Test that bumped txn metadata persists to new txn record') 743 assert rbf_node.getbalance() < 49 744 self.generatetoaddress(rbf_node, 101, rbf_node.getnewaddress()) 745 rbfid = rbf_node.sendtoaddress(dest_address, 49, "comment value", "to value") 746 bumped_tx = rbf_node.bumpfee(rbfid) 747 bumped_wtx = rbf_node.gettransaction(bumped_tx["txid"]) 748 assert_equal(bumped_wtx["comment"], "comment value") 749 assert_equal(bumped_wtx["to"], "to value") 750 self.clear_mempool() 751 752 753 def test_locked_wallet_fails(self, rbf_node, dest_address): 754 self.log.info('Test that locked wallet cannot bump txn') 755 rbfid = spend_one_input(rbf_node, dest_address) 756 rbf_node.walletlock() 757 assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first.", 758 rbf_node.bumpfee, rbfid) 759 rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) 760 self.clear_mempool() 761 762 763 def test_change_script_match(self, rbf_node, dest_address): 764 self.log.info('Test that the same change addresses is used for the replacement transaction when possible') 765 766 # Check that there is only one change output 767 rbfid = spend_one_input(rbf_node, dest_address) 768 change_addresses = get_change_address(rbfid, rbf_node) 769 assert_equal(len(change_addresses), 1) 770 771 # Now find that address in each subsequent tx, and no other change 772 bumped_total_tx = rbf_node.bumpfee(rbfid, fee_rate=ECONOMICAL) 773 assert_equal(change_addresses, get_change_address(bumped_total_tx['txid'], rbf_node)) 774 bumped_rate_tx = rbf_node.bumpfee(bumped_total_tx["txid"]) 775 assert_equal(change_addresses, get_change_address(bumped_rate_tx['txid'], rbf_node)) 776 self.clear_mempool() 777 778 779 def spend_one_input(node, dest_address, change_size=Decimal("0.00049000"), data=None): 780 tx_input = dict( 781 sequence=MAX_BIP125_RBF_SEQUENCE, **next(u for u in node.listunspent() if u["amount"] == Decimal("0.00100000"))) 782 destinations = {dest_address: Decimal("0.00050000")} 783 if change_size > 0: 784 destinations[node.getrawchangeaddress()] = change_size 785 if data: 786 destinations['data'] = data 787 rawtx = node.createrawtransaction([tx_input], destinations) 788 signedtx = node.signrawtransactionwithwallet(rawtx) 789 txid = node.sendrawtransaction(signedtx["hex"]) 790 return txid 791 792 793 def test_no_more_inputs_fails(self, rbf_node, dest_address): 794 self.log.info('Test that bumpfee fails when there are no available confirmed outputs') 795 # feerate rbf requires confirmed outputs when change output doesn't exist or is insufficient 796 self.generatetoaddress(rbf_node, 1, dest_address) 797 # spend all funds, no change output 798 rbfid = rbf_node.sendall(recipients=[rbf_node.getnewaddress()])['txid'] 799 assert_raises_rpc_error(-4, "Unable to create transaction. Insufficient funds", rbf_node.bumpfee, rbfid) 800 self.clear_mempool() 801 802 803 def test_feerate_checks_replaced_outputs(self, rbf_node, peer_node): 804 # Make sure there is enough balance 805 peer_node.sendtoaddress(rbf_node.getnewaddress(), 60) 806 self.generate(peer_node, 1) 807 808 self.log.info("Test that feerate checks use replaced outputs") 809 outputs = [] 810 for i in range(50): 811 outputs.append({rbf_node.getnewaddress(address_type="bech32"): 1}) 812 tx_res = rbf_node.send(outputs=outputs, fee_rate=5) 813 tx_details = rbf_node.gettransaction(txid=tx_res["txid"], verbose=True) 814 815 # Calculate the minimum feerate required for the bump to work. 816 # Since the bumped tx will replace all of the outputs with a single output, we can estimate that its size will 31 * (len(outputs) - 1) bytes smaller 817 tx_size = tx_details["decoded"]["vsize"] 818 est_bumped_size = tx_size - (len(tx_details["decoded"]["vout"]) - 1) * 31 819 inc_fee_rate = max(rbf_node.getmempoolinfo()["incrementalrelayfee"], Decimal(0.00005000)) # Wallet has a fixed incremental relay fee of 5 sat/vb 820 # RPC gives us fee as negative 821 min_fee = (-tx_details["fee"] + get_fee(est_bumped_size, inc_fee_rate)) * Decimal(1e8) 822 min_fee_rate = (min_fee / est_bumped_size).quantize(Decimal("1.000")) 823 824 # Attempt to bumpfee and replace all outputs with a single one using a feerate slightly less than the minimum 825 new_outputs = [{rbf_node.getnewaddress(address_type="bech32"): 49}] 826 assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, tx_res["txid"], {"fee_rate": min_fee_rate - 1, "outputs": new_outputs}) 827 828 # Bumpfee and replace all outputs with a single one using the minimum feerate 829 rbf_node.bumpfee(tx_res["txid"], {"fee_rate": min_fee_rate, "outputs": new_outputs}) 830 self.clear_mempool() 831 832 833 if __name__ == "__main__": 834 BumpFeeTest().main()