test: regression test for waitNext mining policy
What changed, and why it matters
This commit adds a new automated test for Bitcoin Core's mining interface. It checks that a feature called waitNext(), used by external mining programs, correctly follows the node's configured minimum transaction fee policy (-blockmintxfee) and does not quietly ignore that setting. The commit itself only adds a test; it does not change the actual mining code. The test appears to be a regression test for a bug where waitNext() may have fallen back to default fee policy instead of using the configured one.
Treat this as a test-only commit. If the regression test is failing or was added because of a known bug, verify whether a separate production-code fix already exists or is needed for BlockTemplateImpl::waitNext(). Review the current behavior of waitNext() against -blockmintxfee on the relevant branch. No immediate deployment action is required solely from this test addition.
Security signals we found
Regression test for mining policy consistency in waitNext()
Potential prior inconsistency between createNewBlock and waitNext() fee filtering
Configuration bypass risk: configured -blockmintxfee may have been ignored by waitNext()
Evidence from the diff
The change is a pure test addition in test/functional/interface_ipc_mining.py. It introduces run_waitnext_mining_policy_test(), which restarts a node with -blockmintxfee=0.00002000 and -minrelaytxfee=0, sends one transaction below the block-min fee and one above it, and verifies that both createNewBlock and waitNext() exclude the low-fee transaction and include the high-fee transaction. It also wires up default_block_wait_options in run_test(). The commit message frames this as a regression test demonstrating that BlockTemplateImpl::waitNext() must respect -blockmintxfee rather than silently falling back to defaults. No production code is patched here, so the underlying behavior issue, if any, is not fixed by this commit alone.
Changed components
test/functional/interface_ipc_mining.pyBlockTemplateImpl::waitNext() (referenced in commit message, not modified in diff)External mining IPC interfaceInspect captured patch +56 / −0
diff --git a/test/functional/interface_ipc_mining.py b/test/functional/interface_ipc_mining.py
index e78a21f7..d09bc538 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.
Why this scored 27/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.