/ test / functional / wallet_bumpfee.py
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()