test: have mining template helpers return None
What changed, and why it matters
This is a test-only code cleanup. It changes two helper functions used only in Bitcoin Core's automated functional tests so they return None when a mining template request times out or fails, instead of returning a raw response object. The test code is updated to check for None. There is no change to the actual Bitcoin node software that runs on the network, so this cannot affect real users, funds, or network security.
No security action needed. This is a benign test refactor. Reviewers can verify it only touches test files and does not alter node behavior.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit refactors test/functional/test_framework/ipc_util.py helpers mining_create_block_template and mining_wait_next_template to inspect the Cap’n Proto response for a ‘result’ field and return None if absent, otherwise enter the async context with the result. Correspondingly, test/functional/interface_ipc_mining.py replaces direct template.waitNext(ctx, waitoptions) calls and _has(‘result’) checks with the helper and explicit assert … is (not) None checks. This is purely a readability/error-message improvement in the functional test suite.
Changed components
test/functional/test_framework/ipc_util.pytest/functional/interface_ipc_mining.pyInspect captured patch +19 / −8
diff --git a/test/functional/interface_ipc_mining.py b/test/functional/interface_ipc_mining.py
index 20f90490..876a9231 100755
--- a/test/functional/interface_ipc_mining.py
+++ b/test/functional/interface_ipc_mining.py
@@ -160,6 +160,7 @@ class IPCMiningTest(BitcoinTestFramework):
async with AsyncExitStack() as stack:
self.log.debug("Create a template")
template = await mining_create_block_template(mining, stack, ctx, self.default_block_create_options)
+ assert template is not None
self.log.debug("Test some inspectors of Template")
header = (await template.getBlockHeader(ctx)).result
@@ -179,23 +180,26 @@ class IPCMiningTest(BitcoinTestFramework):
template2 = await wait_and_do(
mining_wait_next_template(template, stack, ctx, waitoptions),
lambda: self.generate(self.nodes[0], 1))
+ assert template2 is not None
block2 = await mining_get_block(template2, ctx)
assert_equal(len(block2.vtx), 1)
self.log.debug("Wait for another, but time out")
- template3 = await template2.waitNext(ctx, waitoptions)
- assert_equal(template3._has("result"), False)
+ template3 = await mining_wait_next_template(template2, stack, ctx, waitoptions)
+ assert template3 is None
self.log.debug("Wait for another, get one after increase in fees in the mempool")
template4 = await wait_and_do(
mining_wait_next_template(template2, stack, ctx, waitoptions),
lambda: self.miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0]))
+ assert template4 is not None
block3 = await mining_get_block(template4, ctx)
assert_equal(len(block3.vtx), 2)
self.log.debug("Wait again, this should return the same template, since the fee threshold is zero")
waitoptions.feeThreshold = 0
template5 = await mining_wait_next_template(template4, stack, ctx, waitoptions)
+ assert template5 is not None
block4 = await mining_get_block(template5, ctx)
assert_equal(len(block4.vtx), 2)
waitoptions.feeThreshold = 1
@@ -204,20 +208,21 @@ class IPCMiningTest(BitcoinTestFramework):
template6 = await wait_and_do(
mining_wait_next_template(template5, stack, ctx, waitoptions),
lambda: self.miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0]))
+ assert template6 is not None
block4 = await mining_get_block(template6, ctx)
assert_equal(len(block4.vtx), 3)
self.log.debug("Wait for another, but time out, since the fee threshold is set now")
- template7 = await template6.waitNext(ctx, waitoptions)
- assert_equal(template7._has("result"), False)
+ template7 = await mining_wait_next_template(template6, stack, ctx, waitoptions)
+ assert template7 is None
self.log.debug("interruptWait should abort the current wait")
async def wait_for_block():
new_waitoptions = self.capnp_modules['mining'].BlockWaitOptions()
new_waitoptions.timeout = timeout * 60 # 1 minute wait
new_waitoptions.feeThreshold = 1
- template7 = await template6.waitNext(ctx, new_waitoptions)
- assert_equal(template7._has("result"), False)
+ template7 = await mining_wait_next_template(template6, stack, ctx, new_waitoptions)
+ assert template7 is None
await wait_and_do(wait_for_block(), template6.interruptWait())
asyncio.run(capnp.run(async_routine()))
diff --git a/test/functional/test_framework/ipc_util.py b/test/functional/test_framework/ipc_util.py
index fc451faa..1b1ad7a5 100644
--- a/test/functional/test_framework/ipc_util.py
+++ b/test/functional/test_framework/ipc_util.py
@@ -108,12 +108,18 @@ async def make_capnp_init_ctx(self):
async def mining_create_block_template(mining, stack, ctx, opts):
"""Call mining.createNewBlock() and return template, then call template.destroy() when stack exits."""
- return await stack.enter_async_context(destroying((await mining.createNewBlock(opts)).result, ctx))
+ response = await mining.createNewBlock(opts)
+ if not response._has("result"):
+ return None
+ return await stack.enter_async_context(destroying(response.result, ctx))
async def mining_wait_next_template(template, stack, ctx, opts):
"""Call template.waitNext() and return template, then call template.destroy() when stack exits."""
- return await stack.enter_async_context(destroying((await template.waitNext(ctx, opts)).result, ctx))
+ response = await template.waitNext(ctx, opts)
+ if not response._has("result"):
+ return None
+ return await stack.enter_async_context(destroying(response.result, ctx))
async def mining_get_block(block_template, ctx):
Why this scored 15/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.