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