From 63b23ea1e94f8f1f74e24abbadf2e5de3148f396 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 12 May 2026 15:56:56 +0200 Subject: [PATCH] test: regression test for waitNext mining policy Demonstrates that BlockTemplateImpl::waitNext() must respect the mining policy supplied via -blockmintxfee, not silently fall back to defaults. Co-authored-by: Enoch Azariah --- test/functional/interface_ipc_mining.py | 56 +++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/test/functional/interface_ipc_mining.py b/test/functional/interface_ipc_mining.py index e78a21f7c02..d09bc538819 100755 --- a/test/functional/interface_ipc_mining.py +++ b/test/functional/interface_ipc_mining.py @@ -6,6 +6,7 @@ import asyncio import time from contextlib import AsyncExitStack +from decimal import Decimal from io import BytesIO from test_framework.blocktools import NULL_OUTPOINT, script_BIP34_coinbase_height from test_framework.messages import ( @@ -324,6 +325,57 @@ class IPCMiningTest(BitcoinTestFramework): asyncio.run(capnp.run(async_routine())) + def run_waitnext_mining_policy_test(self): + """Verify that waitNext() preserves the mining policy from -blockmintxfee + instead of falling back to defaults.""" + self.log.info("Running waitNext mining policy test") + block_min_tx_fee = Decimal("0.00002000") + below_block_min_tx_fee = Decimal("0.00001000") + above_block_min_tx_fee = Decimal("0.00003000") + + self.restart_node(0, extra_args=[ + f"-blockmintxfee={block_min_tx_fee:.8f}", + "-minrelaytxfee=0", + "-persistmempool=0", + ]) + + async def async_routine(): + ctx, mining = await make_mining_ctx(self) + + self.log.debug("Create a below -blockmintxfee transaction") + low_fee_tx = self.miniwallet.send_self_transfer( + fee_rate=below_block_min_tx_fee, + from_node=self.nodes[0], + confirmed_only=True, + ) + assert low_fee_tx["txid"] in self.nodes[0].getrawmempool() + + async with AsyncExitStack() as stack: + self.log.debug("createNewBlock should respect -blockmintxfee") + template = await mining_create_block_template(mining, stack, ctx, self.default_block_create_options) + assert template is not None + block = await mining_get_block(template, ctx) + assert low_fee_tx["txid"] not in {tx.txid_hex for tx in block.vtx[1:]} + + self.log.debug("waitNext should preserve the same mining policy") + high_fee_tx = self.miniwallet.send_self_transfer( + fee_rate=above_block_min_tx_fee, + from_node=self.nodes[0], + confirmed_only=True, + ) + mempool_txids = self.nodes[0].getrawmempool() + assert high_fee_tx["txid"] in mempool_txids + assert low_fee_tx["txid"] in mempool_txids + template_next = await mining_wait_next_template(template, stack, ctx, self.default_block_wait_options) + assert template_next is not None + + block_next = await mining_get_block(template_next, ctx) + block_next_txids = {tx.txid_hex for tx in block_next.vtx[1:]} + assert high_fee_tx["txid"] in block_next_txids + assert low_fee_tx["txid"] not in block_next_txids + + asyncio.run(capnp.run(async_routine())) + def run_coinbase_and_submission_test(self): """Test coinbase construction (getCoinbaseTx) and block submission (submitSolution).""" self.log.info("Running coinbase construction and submission test") @@ -447,10 +499,14 @@ class IPCMiningTest(BitcoinTestFramework): def run_test(self): self.miniwallet = MiniWallet(self.nodes[0]) self.default_block_create_options = self.capnp_modules['mining'].BlockCreateOptions() + self.default_block_wait_options = self.capnp_modules['mining'].BlockWaitOptions() + self.default_block_wait_options.timeout = 1000.0 * self.options.timeout_factor + self.default_block_wait_options.feeThreshold = 1 self.run_mining_interface_test() self.run_early_startup_test() self.run_block_template_test() self.run_coinbase_and_submission_test() + self.run_waitnext_mining_policy_test() self.run_ipc_option_override_test() # Needs to run last because it resets the chain.