1818 assert_equal ,
1919 assert_fee_amount ,
2020 assert_raises_rpc_error ,
21+ fill_mempool ,
2122)
2223from test_framework .wallet import (
2324 DEFAULT_FEE ,
@@ -82,7 +83,8 @@ def run_test(self):
8283 self .test_conflicting ()
8384 self .test_rbf ()
8485 self .test_submitpackage ()
85- self .test_maxfeerate_maxburn_submitpackage ()
86+ self .test_maxfeerate_submitpackage ()
87+ self .test_maxburn_submitpackage ()
8688
8789 def test_independent (self , coin ):
8890 self .log .info ("Test multiple independent transactions in a package" )
@@ -358,7 +360,7 @@ def test_submitpackage(self):
358360 assert_equal (res ["tx-results" ][sec_wtxid ]["error" ], "version" )
359361 peer .wait_for_broadcast ([first_wtxid ])
360362
361- def test_maxfeerate_maxburn_submitpackage (self ):
363+ def test_maxfeerate_submitpackage (self ):
362364 node = self .nodes [0 ]
363365 # clear mempool
364366 deterministic_address = node .get_deterministic_priv_key ().address
@@ -369,23 +371,72 @@ def test_maxfeerate_maxburn_submitpackage(self):
369371 minrate_btc_kvb = min ([chained_txn ["fee" ] / chained_txn ["tx" ].get_vsize () * 1000 for chained_txn in chained_txns ])
370372 chain_hex = [t ["hex" ] for t in chained_txns ]
371373 pkg_result = node .submitpackage (chain_hex , maxfeerate = minrate_btc_kvb - Decimal ("0.00000001" ))
374+
375+ # First tx failed in single transaction evaluation, so package message is generic
376+ assert_equal (pkg_result ["package_msg" ], "transaction failed" )
372377 assert_equal (pkg_result ["tx-results" ][chained_txns [0 ]["wtxid" ]]["error" ], "max feerate exceeded" )
373378 assert_equal (pkg_result ["tx-results" ][chained_txns [1 ]["wtxid" ]]["error" ], "bad-txns-inputs-missingorspent" )
374379 assert_equal (node .getrawmempool (), [])
375380
381+ # Make chain of two transactions where parent doesn't make minfee threshold
382+ # but child is too high fee
383+ # Lower mempool limit to make it easier to fill_mempool
384+ self .restart_node (0 , extra_args = [
385+ "-datacarriersize=100000" ,
386+ "-maxmempool=5" ,
387+ "-persistmempool=0" ,
388+ ])
389+
390+ fill_mempool (self , node , self .wallet )
391+
392+ minrelay = node .getmempoolinfo ()["minrelaytxfee" ]
393+ parent = self .wallet .create_self_transfer (
394+ fee_rate = minrelay ,
395+ )
396+
397+ child = self .wallet .create_self_transfer (
398+ fee_rate = DEFAULT_FEE ,
399+ utxo_to_spend = parent ["new_utxo" ],
400+ )
401+
402+ pkg_result = node .submitpackage ([parent ["hex" ], child ["hex" ]], maxfeerate = DEFAULT_FEE - Decimal ("0.00000001" ))
403+
404+ # Child is connected even though parent is invalid and still reports fee exceeded
405+ # this implies sub-package evaluation of both entries together.
406+ assert_equal (pkg_result ["package_msg" ], "transaction failed" )
407+ assert "mempool min fee not met" in pkg_result ["tx-results" ][parent ["wtxid" ]]["error" ]
408+ assert_equal (pkg_result ["tx-results" ][child ["wtxid" ]]["error" ], "max feerate exceeded" )
409+ assert parent ["txid" ] not in node .getrawmempool ()
410+ assert child ["txid" ] not in node .getrawmempool ()
411+
412+ # Reset maxmempool, datacarriersize, reset dynamic mempool minimum feerate, and empty mempool.
413+ self .restart_node (0 )
414+
415+ assert_equal (node .getrawmempool (), [])
416+
417+ def test_maxburn_submitpackage (self ):
418+ node = self .nodes [0 ]
419+
420+ assert_equal (node .getrawmempool (), [])
421+
376422 self .log .info ("Submitpackage maxburnamount arg testing" )
377- tx = tx_from_hex (chain_hex [1 ])
423+ chained_txns_burn = self .wallet .create_self_transfer_chain (chain_length = 2 )
424+ chained_burn_hex = [t ["hex" ] for t in chained_txns_burn ]
425+
426+ tx = tx_from_hex (chained_burn_hex [1 ])
378427 tx .vout [- 1 ].scriptPubKey = b'a' * 10001 # scriptPubKey bigger than 10k IsUnspendable
379- chain_hex = [chain_hex [0 ], tx .serialize ().hex ()]
428+ chained_burn_hex = [chained_burn_hex [0 ], tx .serialize ().hex ()]
380429 # burn test is run before any package evaluation; nothing makes it in and we get broader exception
381- assert_raises_rpc_error (- 25 , "Unspendable output exceeds maximum configured by user" , node .submitpackage , chain_hex , 0 , chained_txns [1 ]["new_utxo" ]["value" ] - Decimal ("0.00000001" ))
430+ assert_raises_rpc_error (- 25 , "Unspendable output exceeds maximum configured by user" , node .submitpackage , chained_burn_hex , 0 , chained_txns_burn [1 ]["new_utxo" ]["value" ] - Decimal ("0.00000001" ))
382431 assert_equal (node .getrawmempool (), [])
383432
433+ minrate_btc_kvb_burn = min ([chained_txn_burn ["fee" ] / chained_txn_burn ["tx" ].get_vsize () * 1000 for chained_txn_burn in chained_txns_burn ])
434+
384435 # Relax the restrictions for both and send it; parent gets through as own subpackage
385- pkg_result = node .submitpackage (chain_hex , maxfeerate = minrate_btc_kvb , maxburnamount = chained_txns [1 ]["new_utxo" ]["value" ])
386- assert "error" not in pkg_result ["tx-results" ][chained_txns [0 ]["wtxid" ]]
436+ pkg_result = node .submitpackage (chained_burn_hex , maxfeerate = minrate_btc_kvb_burn , maxburnamount = chained_txns_burn [1 ]["new_utxo" ]["value" ])
437+ assert "error" not in pkg_result ["tx-results" ][chained_txns_burn [0 ]["wtxid" ]]
387438 assert_equal (pkg_result ["tx-results" ][tx .getwtxid ()]["error" ], "scriptpubkey" )
388- assert_equal (node .getrawmempool (), [chained_txns [0 ]["txid" ]])
439+ assert_equal (node .getrawmempool (), [chained_txns_burn [0 ]["txid" ]])
389440
390441if __name__ == "__main__" :
391442 RPCPackagesTest ().main ()
0 commit comments