Move the create_empty_fork method to the test framework's blocktools.py module to enable reuse across multiple tests.
What changed, and why it matters
This commit simply moves a helper function used only in Bitcoin Core's internal test suite from one test file into a shared test-framework library. It does not change any production code, network behavior, or wallet logic. There is no security issue here.
No action required; this is a benign test-only refactor.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change refactors create_empty_fork, a method that generates empty blocks for regtest-style reorg tests, out of mempool_updatefromblock.py and into test_framework/blocktools.py. The implementation is identical except for adding a default FORK_LENGTH = 10 constant and changing the method signature to accept a node object. No consensus, mempool, P2P, or wallet code is modified.
Changed components
test/functional/mempool_updatefromblock.pytest/functional/test_framework/blocktools.pyInspect captured patch +27 / −27
diff --git a/test/functional/mempool_updatefromblock.py b/test/functional/mempool_updatefromblock.py
index 060c72e2..0340bb74 100755
--- a/test/functional/mempool_updatefromblock.py
+++ b/test/functional/mempool_updatefromblock.py
@@ -11,10 +11,7 @@ from decimal import Decimal
from math import ceil
import time
-from test_framework.blocktools import (
- create_block,
- create_coinbase,
-)
+from test_framework.blocktools import create_empty_fork
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
from test_framework.wallet import MiniWallet
@@ -30,26 +27,6 @@ class MempoolUpdateFromBlockTest(BitcoinTestFramework):
self.num_nodes = 1
self.extra_args = [['-limitclustersize=1000']]
- def create_empty_fork(self, fork_length):
- '''
- Creates a fork using first node's chaintip as the starting point.
- Returns a list of blocks to submit in order.
- '''
- tip = int(self.nodes[0].getbestblockhash(), 16)
- height = self.nodes[0].getblockcount()
- block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1
-
- blocks = []
- for _ in range(fork_length):
- block = create_block(tip, create_coinbase(height + 1), block_time)
- block.solve()
- blocks.append(block)
- tip = block.hash_int
- block_time += 1
- height += 1
-
- return blocks
-
def transaction_graph_test(self, size, *, n_tx_to_mine, fee=100_000):
"""Create an acyclic tournament (a type of directed graph) of transactions and use it for testing.
@@ -69,7 +46,7 @@ class MempoolUpdateFromBlockTest(BitcoinTestFramework):
# Prep for fork with empty blocks to not use invalidateblock directly
# for reorg case. The rpc has different codepath
- fork_blocks = self.create_empty_fork(fork_length=7)
+ fork_blocks = create_empty_fork(self.nodes[0], fork_length=7)
tx_id = []
tx_size = []
@@ -146,7 +123,7 @@ class MempoolUpdateFromBlockTest(BitcoinTestFramework):
assert_equal(self.nodes[0].getrawmempool(), [])
# Set up empty fork blocks ahead of time, needs to be longer than full fork made later
- fork_blocks = self.create_empty_fork(fork_length=60)
+ fork_blocks = create_empty_fork(self.nodes[0], fork_length=60)
large_std_txs = []
# Add children to ensure they're recursively removed if disconnectpool trimming of parent occurs
@@ -195,7 +172,7 @@ class MempoolUpdateFromBlockTest(BitcoinTestFramework):
assert_equal(self.nodes[0].getrawmempool(), [])
# Prep fork
- fork_blocks = self.create_empty_fork(fork_length=10)
+ fork_blocks = create_empty_fork(self.nodes[0])
# Two higher than descendant count
chain = wallet.create_self_transfer_chain(chain_length=DEFAULT_CLUSTER_LIMIT + 2)
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index eb1d3b05..605e9102 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -84,6 +84,9 @@ assert_equal(uint256_from_compact(DIFF_4_N_BITS), DIFF_4_TARGET)
# From BIP325
SIGNET_HEADER = b"\xec\xc7\xda\xa2"
+# Number of blocks to create in temporary blockchain branch for reorg testing
+FORK_LENGTH = 10
+
def nbits_str(nbits):
return f"{nbits:08x}"
@@ -113,6 +116,26 @@ def create_block(hashprev=None, coinbase=None, ntime=None, *, version=None, tmpl
block.hashMerkleRoot = block.calc_merkle_root()
return block
+def create_empty_fork(node, fork_length=FORK_LENGTH):
+ '''
+ Creates a fork using node's chaintip as the starting point.
+ Returns a list of blocks to submit in order.
+ '''
+ tip = int(node.getbestblockhash(), 16)
+ height = node.getblockcount()
+ block_time = node.getblock(node.getbestblockhash())['time'] + 1
+
+ blocks = []
+ for _ in range(fork_length):
+ block = create_block(tip, create_coinbase(height + 1), block_time)
+ block.solve()
+ blocks.append(block)
+ tip = block.hash_int
+ block_time += 1
+ height += 1
+
+ return blocks
+
def get_witness_script(witness_root, witness_nonce):
witness_commitment = hash256(ser_uint256(witness_root) + ser_uint256(witness_nonce))
output_data = WITNESS_COMMITMENT_HEADER + witness_commitment
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.