test: cover IPC blockmaxweight policy
What changed, and why it matters
This commit only adds a new automated test to Bitcoin Core. It checks that a configuration option called -blockmaxweight correctly limits the size of blocks produced through the IPC mining interface, both when a block template is first created and when it is refreshed. There is no change to production code, no bug fix, and no security patch.
No action required; this is a test-only addition. Reviewers may optionally confirm the test passes in CI.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff adds run_block_max_weight_test() to test/functional/interface_ipc_mining.py. The test restarts a node with a low -blockmaxweight, fills the mempool, and verifies via the Cap’n Proto IPC mining interface that createNewBlock/waitNext templates respect the weight cap. It imports DEFAULT_BLOCK_RESERVED_WEIGHT and uses existing test helpers. No C++/Python production logic is modified.
Changed components
test/functional/interface_ipc_mining.pyInspect captured patch +61 / −0
diff --git a/test/functional/interface_ipc_mining.py b/test/functional/interface_ipc_mining.py
index d09bc538..710a9a2d 100755
--- a/test/functional/interface_ipc_mining.py
+++ b/test/functional/interface_ipc_mining.py
@@ -16,6 +16,7 @@ from test_framework.messages import (
CTxIn,
CTxInWitness,
CTxOut,
+ DEFAULT_BLOCK_RESERVED_WEIGHT,
MAX_BLOCK_WEIGHT,
from_hex,
msg_headers,
@@ -376,6 +377,65 @@ class IPCMiningTest(BitcoinTestFramework):
asyncio.run(capnp.run(async_routine()))
+ def run_block_max_weight_test(self):
+ """Verify IPC createNewBlock() and waitNext() preserve the -blockmaxweight policy."""
+ self.log.info("Running block_max_weight test")
+
+ # Cap that leaves room for only a handful of mempool transactions
+ # above DEFAULT_BLOCK_RESERVED_WEIGHT (8000). Well below MAX_BLOCK_WEIGHT
+ # (4_000_000), so any truncation observed here is attributable to the
+ # cap, not to consensus limits or wallet chain limits.
+ small_cap = DEFAULT_BLOCK_RESERVED_WEIGHT + 4000
+ NUM_TXS = 20
+
+ self.restart_node(0, extra_args=[
+ f"-blockmaxweight={small_cap}",
+ "-minrelaytxfee=0",
+ "-persistmempool=0",
+ ])
+ # Refresh miniwallet's UTXO view from the chain after restart.
+ self.miniwallet.rescan_utxos()
+
+ # Fill the mempool enough that the configured block weight cap forces
+ # template truncation.
+ for _ in range(NUM_TXS):
+ self.miniwallet.send_self_transfer(from_node=self.nodes[0], confirmed_only=True)
+ assert_equal(self.nodes[0].getmempoolinfo()["size"], NUM_TXS)
+
+ async def async_routine():
+ ctx, mining = await make_mining_ctx(self)
+ async with AsyncExitStack() as stack:
+ 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_greater_than_or_equal(small_cap, block.get_weight())
+ # Exclude the coinbase; the cap must have forced truncation.
+ initial_included = len(block.vtx) - 1
+ assert initial_included < NUM_TXS, (
+ f"Expected -blockmaxweight={small_cap} to truncate; "
+ f"included {initial_included}/{NUM_TXS} mempool txs"
+ )
+
+ self.log.debug("waitNext should preserve -blockmaxweight")
+ high_fee_tx = self.miniwallet.send_self_transfer(
+ from_node=self.nodes[0],
+ confirmed_only=True,
+ fee_rate=10,
+ )
+ 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)
+ assert_greater_than_or_equal(small_cap, block_next.get_weight())
+ assert high_fee_tx["txid"] in {tx.txid_hex for tx in block_next.vtx[1:]}
+ next_included = len(block_next.vtx) - 1
+ assert next_included < NUM_TXS + 1, (
+ f"Expected -blockmaxweight={small_cap} to remain capped after waitNext; "
+ f"included {next_included}/{NUM_TXS + 1} mempool txs"
+ )
+
+ 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")
@@ -507,6 +567,7 @@ class IPCMiningTest(BitcoinTestFramework):
self.run_block_template_test()
self.run_coinbase_and_submission_test()
self.run_waitnext_mining_policy_test()
+ self.run_block_max_weight_test()
self.run_ipc_option_override_test()
# Needs to run last because it resets the chain.
Why this scored 14/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.