wallet_spend_unconfirmed.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2022 The Limenka developers
   3  # Distributed under the MIT software license, see the accompanying
   4  # file COPYING or http://www.opensource.org/licenses/mit-license.php.
   5  
   6  from decimal import Decimal, getcontext
   7  
   8  from test_framework.test_framework import LimenkaTestFramework
   9  from test_framework.util import (
  10      assert_greater_than_or_equal,
  11      assert_equal,
  12      find_vout_for_address,
  13  )
  14  
  15  class UnconfirmedInputTest(LimenkaTestFramework):
  16      def add_options(self, parser):
  17          self.add_wallet_options(parser)
  18  
  19      def set_test_params(self):
  20          getcontext().prec=9
  21          self.setup_clean_chain = True
  22          self.num_nodes = 1
  23  
  24      def setup_and_fund_wallet(self, walletname):
  25          self.nodes[0].createwallet(walletname)
  26          wallet = self.nodes[0].get_wallet_rpc(walletname)
  27  
  28          self.def_wallet.sendtoaddress(address=wallet.getnewaddress(), amount=2)
  29          self.generate(self.nodes[0], 1) # confirm funding tx
  30          return wallet
  31  
  32      def skip_test_if_missing_module(self):
  33          self.skip_if_no_wallet()
  34  
  35      def calc_fee_rate(self, tx):
  36          fee = Decimal(-1e8) * tx["fee"]
  37          vsize = tx["decoded"]["vsize"]
  38          return fee / vsize
  39  
  40      def calc_set_fee_rate(self, txs):
  41          fees = Decimal(-1e8) * sum([tx["fee"] for tx in txs]) # fee is negative!
  42          vsizes = sum([tx["decoded"]["vsize"] for tx in txs])
  43          return fees / vsizes
  44  
  45      def assert_spends_only_parents(self, tx, parent_txids):
  46          parent_checklist = parent_txids.copy()
  47          number_inputs = len(tx["decoded"]["vin"])
  48          assert_equal(number_inputs, len(parent_txids))
  49          for i in range(number_inputs):
  50              txid_of_input = tx["decoded"]["vin"][i]["txid"]
  51              assert txid_of_input in parent_checklist
  52              parent_checklist.remove(txid_of_input)
  53  
  54      def assert_undershoots_target(self, tx):
  55          resulting_fee_rate = self.calc_fee_rate(tx)
  56          assert_greater_than_or_equal(self.target_fee_rate, resulting_fee_rate)
  57  
  58      def assert_beats_target(self, tx):
  59          resulting_fee_rate = self.calc_fee_rate(tx)
  60          assert_greater_than_or_equal(resulting_fee_rate, self.target_fee_rate)
  61  
  62      # Meta-Test: try feerate testing function on confirmed UTXO
  63      def test_target_feerate_confirmed(self):
  64          self.log.info("Start test feerate with confirmed input")
  65          wallet = self.setup_and_fund_wallet("confirmed_wallet")
  66  
  67          ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.5, fee_rate=self.target_fee_rate)
  68          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
  69          self.assert_beats_target(ancestor_aware_tx)
  70  
  71          wallet.unloadwallet()
  72  
  73      # Spend unconfirmed UTXO from high-feerate parent
  74      def test_target_feerate_unconfirmed_high(self):
  75          self.log.info("Start test feerate with high feerate unconfirmed input")
  76          wallet = self.setup_and_fund_wallet("unconfirmed_high_wallet")
  77  
  78          # Send unconfirmed transaction with high feerate to testing wallet
  79          parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=3*self.target_fee_rate)
  80          parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)
  81          self.assert_beats_target(parent_tx)
  82  
  83          ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.5, fee_rate=self.target_fee_rate)
  84          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
  85  
  86          self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])
  87  
  88          self.assert_beats_target(ancestor_aware_tx)
  89  
  90          wallet.unloadwallet()
  91  
  92      # Spend unconfirmed UTXO from low-feerate parent. Expect that parent gets
  93      # bumped to target feerate.
  94      def test_target_feerate_unconfirmed_low(self):
  95          self.log.info("Start test feerate with low feerate unconfirmed input")
  96          wallet = self.setup_and_fund_wallet("unconfirmed_low_wallet")
  97  
  98          parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=1)
  99          parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)
 100  
 101          self.assert_undershoots_target(parent_tx)
 102  
 103          ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.5, fee_rate=self.target_fee_rate)
 104          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
 105  
 106          self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])
 107  
 108          self.assert_beats_target(ancestor_aware_tx)
 109          resulting_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, ancestor_aware_tx])
 110          assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)
 111          assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)
 112  
 113          wallet.unloadwallet()
 114  
 115      # Spend UTXO with unconfirmed low feerate parent and grandparent
 116      # txs. Expect that both ancestors get bumped to target feerate.
 117      def test_chain_of_unconfirmed_low(self):
 118          self.log.info("Start test with parent and grandparent tx")
 119          wallet = self.setup_and_fund_wallet("unconfirmed_low_chain_wallet")
 120  
 121          grandparent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1.8, fee_rate=1)
 122          gp_tx = wallet.gettransaction(txid=grandparent_txid, verbose=True)
 123  
 124          self.assert_undershoots_target(gp_tx)
 125  
 126          parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1.5, fee_rate=2)
 127          p_tx = wallet.gettransaction(txid=parent_txid, verbose=True)
 128  
 129          self.assert_undershoots_target(p_tx)
 130  
 131          ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=1.3, fee_rate=self.target_fee_rate)
 132          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
 133          self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])
 134  
 135          self.assert_beats_target(ancestor_aware_tx)
 136          resulting_ancestry_fee_rate = self.calc_set_fee_rate([gp_tx, p_tx, ancestor_aware_tx])
 137          assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)
 138          assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)
 139  
 140          wallet.unloadwallet()
 141  
 142      # Spend unconfirmed UTXOs from two low feerate parent txs.
 143      def test_two_low_feerate_unconfirmed_parents(self):
 144          self.log.info("Start test with two unconfirmed parent txs")
 145          wallet = self.setup_and_fund_wallet("two_parents_wallet")
 146  
 147          # Add second UTXO to tested wallet
 148          self.def_wallet.sendtoaddress(address=wallet.getnewaddress(), amount=2)
 149          self.generate(self.nodes[0], 1) # confirm funding tx
 150  
 151          parent_one_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1.5, fee_rate=2)
 152          p_one_tx = wallet.gettransaction(txid=parent_one_txid, verbose=True)
 153          self.assert_undershoots_target(p_one_tx)
 154  
 155          parent_two_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1.5, fee_rate=1)
 156          p_two_tx = wallet.gettransaction(txid=parent_two_txid, verbose=True)
 157          self.assert_undershoots_target(p_two_tx)
 158  
 159          ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=2.8, fee_rate=self.target_fee_rate)
 160          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
 161          self.assert_spends_only_parents(ancestor_aware_tx, [parent_one_txid, parent_two_txid])
 162  
 163          self.assert_beats_target(ancestor_aware_tx)
 164          resulting_ancestry_fee_rate = self.calc_set_fee_rate([p_one_tx, p_two_tx, ancestor_aware_tx])
 165          assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)
 166          assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)
 167  
 168          wallet.unloadwallet()
 169  
 170      # Spend two unconfirmed inputs, one each from low and high feerate parents
 171      def test_mixed_feerate_unconfirmed_parents(self):
 172          self.log.info("Start test with two unconfirmed parent txs one of which has a higher feerate")
 173          wallet = self.setup_and_fund_wallet("two_mixed_parents_wallet")
 174  
 175          # Add second UTXO to tested wallet
 176          self.def_wallet.sendtoaddress(address=wallet.getnewaddress(), amount=2)
 177          self.generate(self.nodes[0], 1) # confirm funding tx
 178  
 179          high_parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1.5, fee_rate=self.target_fee_rate*2)
 180          p_high_tx = wallet.gettransaction(txid=high_parent_txid, verbose=True)
 181          # This time the parent is greater than the child
 182          self.assert_beats_target(p_high_tx)
 183  
 184          parent_low_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1.5, fee_rate=1)
 185          p_low_tx = wallet.gettransaction(txid=parent_low_txid, verbose=True)
 186          # Other parent needs bump
 187          self.assert_undershoots_target(p_low_tx)
 188  
 189          ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=2.8, fee_rate=self.target_fee_rate)
 190          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
 191          self.assert_spends_only_parents(ancestor_aware_tx, [parent_low_txid, high_parent_txid])
 192  
 193          self.assert_beats_target(ancestor_aware_tx)
 194          resulting_ancestry_fee_rate = self.calc_set_fee_rate([p_high_tx, p_low_tx, ancestor_aware_tx])
 195          assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)
 196  
 197          resulting_bumped_ancestry_fee_rate = self.calc_set_fee_rate([p_low_tx, ancestor_aware_tx])
 198          assert_greater_than_or_equal(resulting_bumped_ancestry_fee_rate, self.target_fee_rate)
 199          assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_bumped_ancestry_fee_rate)
 200  
 201          wallet.unloadwallet()
 202  
 203      # Spend from chain with high feerate grandparent and low feerate parent
 204      def test_chain_of_high_low(self):
 205          self.log.info("Start test with low parent and high grandparent tx")
 206          wallet = self.setup_and_fund_wallet("high_low_chain_wallet")
 207  
 208          grandparent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1.8, fee_rate=self.target_fee_rate * 10)
 209          gp_tx = wallet.gettransaction(txid=grandparent_txid, verbose=True)
 210          # grandparent has higher feerate
 211          self.assert_beats_target(gp_tx)
 212  
 213          parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1.5, fee_rate=1)
 214          # parent is low feerate
 215          p_tx = wallet.gettransaction(txid=parent_txid, verbose=True)
 216          self.assert_undershoots_target(p_tx)
 217  
 218          ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=1.3, fee_rate=self.target_fee_rate)
 219          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
 220          self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])
 221  
 222          self.assert_beats_target(ancestor_aware_tx)
 223          resulting_ancestry_fee_rate = self.calc_set_fee_rate([p_tx, ancestor_aware_tx])
 224          assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)
 225          assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)
 226          resulting_ancestry_fee_rate_with_high_feerate_gp = self.calc_set_fee_rate([gp_tx, p_tx, ancestor_aware_tx])
 227          # Check that we bumped the parent without relying on the grandparent
 228          assert_greater_than_or_equal(resulting_ancestry_fee_rate_with_high_feerate_gp, self.target_fee_rate*1.1)
 229  
 230          wallet.unloadwallet()
 231  
 232      # Spend UTXO from chain of unconfirmed transactions with low feerate
 233      # grandparent and even lower feerate parent
 234      def test_chain_of_high_low_below_target_feerate(self):
 235          self.log.info("Start test with low parent and higher low grandparent tx")
 236          wallet = self.setup_and_fund_wallet("low_and_lower_chain_wallet")
 237  
 238          grandparent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1.8, fee_rate=5)
 239          gp_tx = wallet.gettransaction(txid=grandparent_txid, verbose=True)
 240  
 241          # grandparent has higher feerate, but below target
 242          self.assert_undershoots_target(gp_tx)
 243  
 244          parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1.5, fee_rate=1)
 245          p_tx = wallet.gettransaction(txid=parent_txid, verbose=True)
 246          # parent even lower
 247          self.assert_undershoots_target(p_tx)
 248  
 249          ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=1.3, fee_rate=self.target_fee_rate)
 250          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
 251          self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])
 252  
 253          self.assert_beats_target(ancestor_aware_tx)
 254          resulting_ancestry_fee_rate = self.calc_set_fee_rate([gp_tx, p_tx, ancestor_aware_tx])
 255          assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)
 256          assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)
 257  
 258          wallet.unloadwallet()
 259  
 260      # Test fee calculation when bumping while using subtract fee from output (SFFO)
 261      def test_target_feerate_unconfirmed_low_sffo(self):
 262          self.log.info("Start test feerate with low feerate unconfirmed input, while subtracting from output")
 263          wallet = self.setup_and_fund_wallet("unconfirmed_low_wallet_sffo")
 264  
 265          parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=1)
 266          parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)
 267  
 268          self.assert_undershoots_target(parent_tx)
 269  
 270          ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.5, fee_rate=self.target_fee_rate, subtractfeefromamount=True)
 271          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
 272  
 273          self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])
 274  
 275          self.assert_beats_target(ancestor_aware_tx)
 276          resulting_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, ancestor_aware_tx])
 277          assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)
 278          assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)
 279  
 280          wallet.unloadwallet()
 281  
 282      # Test that parents of preset unconfirmed inputs get cpfp'ed
 283      def test_preset_input_cpfp(self):
 284          self.log.info("Start test with preset input from low feerate unconfirmed transaction")
 285          wallet = self.setup_and_fund_wallet("preset_input")
 286  
 287          parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=1)
 288          parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)
 289  
 290          self.assert_undershoots_target(parent_tx)
 291  
 292          number_outputs = len(parent_tx["decoded"]["vout"])
 293          assert_equal(number_outputs, 2)
 294  
 295          # we don't care which of the two outputs we spent, they're both ours
 296          ancestor_aware_txid = wallet.send(outputs=[{self.def_wallet.getnewaddress(): 0.5}], fee_rate=self.target_fee_rate, options={"add_inputs": True, "inputs": [{"txid": parent_txid, "vout": 0}]})["txid"]
 297          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
 298  
 299          self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])
 300  
 301          self.assert_beats_target(ancestor_aware_tx)
 302          resulting_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, ancestor_aware_tx])
 303          assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)
 304          assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)
 305  
 306          wallet.unloadwallet()
 307  
 308      # Test that RBFing a transaction with unconfirmed input gets the right feerate
 309      def test_rbf_bumping(self):
 310          self.log.info("Start test to rbf a transaction unconfirmed input to bump it")
 311          wallet = self.setup_and_fund_wallet("bump")
 312  
 313          parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=1)
 314          parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)
 315  
 316          self.assert_undershoots_target(parent_tx)
 317  
 318          to_be_rbfed_ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.5, fee_rate=self.target_fee_rate)
 319          ancestor_aware_tx = wallet.gettransaction(txid=to_be_rbfed_ancestor_aware_txid, verbose=True)
 320  
 321          self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])
 322  
 323          self.assert_beats_target(ancestor_aware_tx)
 324          resulting_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, ancestor_aware_tx])
 325          assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)
 326          assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)
 327  
 328          bumped_ancestor_aware_txid = wallet.bumpfee(txid=to_be_rbfed_ancestor_aware_txid, options={"fee_rate": self.target_fee_rate * 2} )["txid"]
 329          bumped_ancestor_aware_tx = wallet.gettransaction(txid=bumped_ancestor_aware_txid, verbose=True)
 330          self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])
 331  
 332          resulting_bumped_fee_rate = self.calc_fee_rate(bumped_ancestor_aware_tx)
 333          assert_greater_than_or_equal(resulting_bumped_fee_rate, 2*self.target_fee_rate)
 334          resulting_bumped_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, bumped_ancestor_aware_tx])
 335          assert_greater_than_or_equal(resulting_bumped_ancestry_fee_rate, 2*self.target_fee_rate)
 336          assert_greater_than_or_equal(2*self.target_fee_rate*1.01, resulting_bumped_ancestry_fee_rate)
 337  
 338          wallet.unloadwallet()
 339  
 340      # Test that transaction spending two UTXOs with overlapping ancestry does not bump shared ancestors twice
 341      def test_target_feerate_unconfirmed_low_overlapping_ancestry(self):
 342          self.log.info("Start test where two UTXOs have overlapping ancestry")
 343          wallet = self.setup_and_fund_wallet("overlapping_ancestry_wallet")
 344  
 345          parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=1)
 346          two_output_parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)
 347  
 348          self.assert_undershoots_target(two_output_parent_tx)
 349  
 350          # spend both outputs from parent transaction
 351          ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=1.5, fee_rate=self.target_fee_rate)
 352          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
 353          self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid, parent_txid])
 354  
 355          self.assert_beats_target(ancestor_aware_tx)
 356          resulting_ancestry_fee_rate = self.calc_set_fee_rate([two_output_parent_tx, ancestor_aware_tx])
 357          assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)
 358          assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)
 359  
 360          wallet.unloadwallet()
 361  
 362      # Test that new transaction ignores sibling transaction with low feerate
 363      def test_sibling_tx_gets_ignored(self):
 364          self.log.info("Start test where a low-fee sibling tx gets created and check that bumping ignores it")
 365          wallet = self.setup_and_fund_wallet("ignore-sibling")
 366  
 367          parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=2)
 368          parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)
 369  
 370          self.assert_undershoots_target(parent_tx)
 371  
 372          # create sibling tx
 373          sibling_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.9, fee_rate=1)
 374          sibling_tx = wallet.gettransaction(txid=sibling_txid, verbose=True)
 375          self.assert_undershoots_target(sibling_tx)
 376  
 377          # spend both outputs from parent transaction
 378          ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.5, fee_rate=self.target_fee_rate)
 379          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
 380  
 381          self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])
 382  
 383          self.assert_beats_target(ancestor_aware_tx)
 384          resulting_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, ancestor_aware_tx])
 385          assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)
 386          assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)
 387  
 388          wallet.unloadwallet()
 389  
 390      # Test that new transaction only pays for itself when high feerate sibling pays for parent
 391      def test_sibling_tx_bumps_parent(self):
 392          self.log.info("Start test where a high-fee sibling tx bumps the parent")
 393          wallet = self.setup_and_fund_wallet("generous-sibling")
 394  
 395          parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=1)
 396          parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)
 397          self.assert_undershoots_target(parent_tx)
 398  
 399          # create sibling tx
 400          sibling_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.9, fee_rate=3*self.target_fee_rate)
 401          sibling_tx = wallet.gettransaction(txid=sibling_txid, verbose=True)
 402          self.assert_beats_target(sibling_tx)
 403  
 404          # spend both outputs from parent transaction
 405          ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.5, fee_rate=self.target_fee_rate)
 406          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
 407  
 408          self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])
 409  
 410          self.assert_beats_target(ancestor_aware_tx)
 411          # Child is only paying for itself…
 412          resulting_fee_rate = self.calc_fee_rate(ancestor_aware_tx)
 413          assert_greater_than_or_equal(1.05 * self.target_fee_rate, resulting_fee_rate)
 414          # …because sibling bumped to parent to ~50 s/vB, while our target is 30 s/vB
 415          resulting_ancestry_fee_rate_sibling = self.calc_set_fee_rate([parent_tx, sibling_tx])
 416          assert_greater_than_or_equal(resulting_ancestry_fee_rate_sibling, self.target_fee_rate)
 417          # and our resulting "ancestry feerate" is therefore BELOW target feerate
 418          resulting_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, ancestor_aware_tx])
 419          assert_greater_than_or_equal(self.target_fee_rate, resulting_ancestry_fee_rate)
 420  
 421          wallet.unloadwallet()
 422  
 423      # Spend a confirmed and an unconfirmed input at the same time
 424      def test_confirmed_and_unconfirmed_parent(self):
 425          self.log.info("Start test with one unconfirmed and one confirmed input")
 426          wallet = self.setup_and_fund_wallet("confirmed_and_unconfirmed_wallet")
 427          confirmed_parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=self.target_fee_rate)
 428          self.generate(self.nodes[0], 1) # Wallet has two confirmed UTXOs of ~1BTC each
 429          unconfirmed_parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=0.5, fee_rate=0.5*self.target_fee_rate)
 430  
 431          # wallet has one confirmed UTXO of 1BTC and two unconfirmed UTXOs of ~0.5BTC each
 432          ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=1.4, fee_rate=self.target_fee_rate)
 433          ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
 434          self.assert_spends_only_parents(ancestor_aware_tx, [confirmed_parent_txid, unconfirmed_parent_txid])
 435          resulting_fee_rate = self.calc_fee_rate(ancestor_aware_tx)
 436          assert_greater_than_or_equal(resulting_fee_rate, self.target_fee_rate)
 437  
 438          wallet.unloadwallet()
 439  
 440      def test_external_input_unconfirmed_low(self):
 441          self.log.info("Send funds to an external wallet then build tx that bumps parent by spending external input")
 442          wallet = self.setup_and_fund_wallet("test_external_wallet")
 443  
 444          external_address = self.def_wallet.getnewaddress()
 445          address_info = self.def_wallet.getaddressinfo(external_address)
 446          external_descriptor = address_info["desc"]
 447          parent_txid = wallet.sendtoaddress(address=external_address, amount=1, fee_rate=1)
 448          parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)
 449  
 450          self.assert_undershoots_target(parent_tx)
 451  
 452          spend_res = wallet.send(outputs=[{self.def_wallet.getnewaddress(): 0.5}], fee_rate=self.target_fee_rate, options={"inputs":[{"txid":parent_txid, "vout":find_vout_for_address(self.nodes[0], parent_txid, external_address)}], "solving_data":{"descriptors":[external_descriptor]}})
 453          signed_psbt = self.def_wallet.walletprocesspsbt(spend_res["psbt"])
 454          external_tx = self.def_wallet.finalizepsbt(signed_psbt["psbt"])
 455          ancestor_aware_txid = self.def_wallet.sendrawtransaction(external_tx["hex"])
 456  
 457          ancestor_aware_tx = self.def_wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)
 458  
 459          self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])
 460  
 461          self.assert_beats_target(ancestor_aware_tx)
 462          resulting_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, ancestor_aware_tx])
 463          assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)
 464          assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)
 465  
 466          wallet.unloadwallet()
 467  
 468  
 469      def run_test(self):
 470          self.log.info("Starting UnconfirmedInputTest!")
 471          self.target_fee_rate = 30
 472          self.def_wallet  = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
 473          self.generate(self.nodes[0], 110)
 474  
 475          self.test_target_feerate_confirmed()
 476  
 477          self.test_target_feerate_unconfirmed_high()
 478  
 479          self.test_target_feerate_unconfirmed_low()
 480  
 481          self.test_chain_of_unconfirmed_low()
 482  
 483          self.test_two_low_feerate_unconfirmed_parents()
 484  
 485          self.test_mixed_feerate_unconfirmed_parents()
 486  
 487          self.test_chain_of_high_low()
 488  
 489          self.test_chain_of_high_low_below_target_feerate()
 490  
 491          self.test_target_feerate_unconfirmed_low_sffo()
 492  
 493          self.test_preset_input_cpfp()
 494  
 495          self.test_rbf_bumping()
 496  
 497          self.test_target_feerate_unconfirmed_low_overlapping_ancestry()
 498  
 499          self.test_sibling_tx_gets_ignored()
 500  
 501          self.test_sibling_tx_bumps_parent()
 502  
 503          self.test_confirmed_and_unconfirmed_parent()
 504  
 505          self.test_external_input_unconfirmed_low()
 506  
 507  if __name__ == '__main__':
 508      UnconfirmedInputTest(__file__).main()
 509