wallet_spend_unconfirmed.py
1 #!/usr/bin/env python3 2 # Copyright (c) 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 6 from decimal import Decimal, getcontext 7 8 from test_framework.test_framework import BitcoinTestFramework 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(BitcoinTestFramework): 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().main()