What changed, and why it matters
This commit only changes Bitcoin Core's internal test code. It adds one more mock mainnet block to a test fixture, renames a function argument for clarity, removes an unused parameter, and expands documentation for how the test data was generated. There is no change to the actual Bitcoin network code that users run.
No security action needed. This is a routine test-maintenance commit. Reviewers may verify the new mock block 2016 and the renamed argument do not break the functional test suite.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit extends the functional test mining_mainnet.py and its data file mainnet_alt.json from 2015 to 2016 blocks so the test can exercise the first difficulty retarget at block 2016. It renames create_coinbase’s retarget_period argument to halving_period because the value 210000 refers to the subsidy-halving interval, not the difficulty-retarget interval. It drops the unused fees argument from the local mine helper. The JSON data gains one timestamp and one nonce; the README documents the generation process more fully. All changes are confined to the test/functional tree.
Changed components
test/functional/mining_mainnet.pytest/functional/data/mainnet_alt.jsontest/functional/data/README.mdtest/functional/test_framework/blocktools.pyInspect captured patch +30 / −13
diff --git a/test/functional/data/README.md b/test/functional/data/README.md
index bb03422f..956394e3 100644
--- a/test/functional/data/README.md
+++ b/test/functional/data/README.md
@@ -11,9 +11,10 @@ The alternate mainnet chain was generated as follows:
- restart node with a faketime 2 minutes later
```sh
-for i in {1..2015}
+for i in {1..2016}
do
- faketime "`date -d @"$(( 1231006505 + $i * 120 ))" +'%Y-%m-%d %H:%M:%S'`" \
+ t=$(( 1231006505 + $i * 120 ))
+ faketime "`date -d @$t +'%Y-%m-%d %H:%M:%S'`" \
bitcoind -connect=0 -nocheckpoints -stopatheight=$i
done
```
@@ -21,7 +22,9 @@ done
The CPU miner is kept running as follows:
```sh
-./minerd --coinbase-addr 1NQpH6Nf8QtR2HphLRcvuVqfhXBXsiWn8r --no-stratum --algo sha256d --no-longpoll --scantime 3 --retry-pause 1
+./minerd -u ... -p ... -o http://127.0.0.1:8332 --no-stratum \
+ --coinbase-addr 1NQpH6Nf8QtR2HphLRcvuVqfhXBXsiWn8r \
+ --algo sha256d --no-longpoll --scantime 3 --retry-pause 1
```
The payout address is derived from first BIP32 test vector master key:
@@ -40,3 +43,8 @@ The timestamp was not kept constant because at difficulty 1 it's not sufficient
to only grind the nonce. Grinding the extra_nonce or version field instead
would have required additional (stratum) software. It would also make it more
complicated to reconstruct the blocks in this test.
+
+The `getblocktemplate` RPC code needs to be patched to ignore not being connected
+to any peers, and to ignore the IBD status check.
+
+On macOS use `faketime "@$t"` instead.
diff --git a/test/functional/data/mainnet_alt.json b/test/functional/data/mainnet_alt.json
index a4a072d2..96821a36 100644
--- a/test/functional/data/mainnet_alt.json
+++ b/test/functional/data/mainnet_alt.json
@@ -2014,7 +2014,8 @@
1231247971,
1231248071,
1231248198,
- 1231248322
+ 1231248322,
+ 1231248621
],
"nonces": [
2345621585,
@@ -4031,6 +4032,7 @@
3658502865,
2519048297,
1915965760,
- 1183846025
+ 1183846025,
+ 2713372123
]
}
diff --git a/test/functional/mining_mainnet.py b/test/functional/mining_mainnet.py
index dbe6248f..eafa991c 100755
--- a/test/functional/mining_mainnet.py
+++ b/test/functional/mining_mainnet.py
@@ -53,15 +53,15 @@ class MiningMainnetTest(BitcoinTestFramework):
help='Block data file (default: %(default)s)',
)
- def mine(self, height, prev_hash, blocks, node, fees=0):
+ def mine(self, height, prev_hash, blocks, node):
self.log.debug(f"height={height}")
block = CBlock()
block.nVersion = 0x20000000
block.hashPrevBlock = int(prev_hash, 16)
block.nTime = blocks['timestamps'][height - 1]
- block.nBits = DIFF_1_N_BITS
+ block.nBits = DIFF_1_N_BITS if height < 2016 else DIFF_4_N_BITS
block.nNonce = blocks['nonces'][height - 1]
- block.vtx = [create_coinbase(height=height, script_pubkey=bytes.fromhex(COINBASE_SCRIPT_PUBKEY), retarget_period=2016)]
+ block.vtx = [create_coinbase(height=height, script_pubkey=bytes.fromhex(COINBASE_SCRIPT_PUBKEY), halving_period=210000)]
# The alternate mainnet chain was mined with non-timelocked coinbase txs.
block.vtx[0].nLockTime = 0
block.vtx[0].vin[0].nSequence = SEQUENCE_FINAL
@@ -82,12 +82,15 @@ class MiningMainnetTest(BitcoinTestFramework):
self.log.info("Load alternative mainnet blocks")
path = os.path.join(os.path.dirname(os.path.realpath(__file__)), self.options.datafile)
prev_hash = node.getbestblockhash()
+ blocks = None
with open(path, encoding='utf-8') as f:
blocks = json.load(f)
n_blocks = len(blocks['timestamps'])
- assert_equal(n_blocks, 2015)
- for i in range(2015):
- prev_hash = self.mine(i + 1, prev_hash, blocks, node)
+ assert_equal(n_blocks, 2016)
+
+ # Mine up to the last block of the first retarget period
+ for i in range(2015):
+ prev_hash = self.mine(i + 1, prev_hash, blocks, node)
assert_equal(node.getblockcount(), 2015)
@@ -102,5 +105,9 @@ class MiningMainnetTest(BitcoinTestFramework):
assert_equal(mining_info['next']['bits'], nbits_str(DIFF_4_N_BITS))
assert_equal(mining_info['next']['target'], target_str(DIFF_4_TARGET))
+ # Mine first block of the second retarget period
+ height = 2016
+ prev_hash = self.mine(height, prev_hash, blocks, node)
+ assert_equal(node.getblockcount(), height)
if __name__ == '__main__':
MiningMainnetTest(__file__).main()
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index fa4182c6..eb1d3b05 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -144,7 +144,7 @@ def script_BIP34_coinbase_height(height):
return CScript([CScriptNum(height)])
-def create_coinbase(height, pubkey=None, *, script_pubkey=None, extra_output_script=None, fees=0, nValue=50, retarget_period=REGTEST_RETARGET_PERIOD):
+def create_coinbase(height, pubkey=None, *, script_pubkey=None, extra_output_script=None, fees=0, nValue=50, halving_period=REGTEST_RETARGET_PERIOD):
"""Create a coinbase transaction.
If pubkey is passed in, the coinbase output will be a P2PK output;
@@ -158,7 +158,7 @@ def create_coinbase(height, pubkey=None, *, script_pubkey=None, extra_output_scr
coinbaseoutput = CTxOut()
coinbaseoutput.nValue = nValue * COIN
if nValue == 50:
- halvings = int(height / retarget_period)
+ halvings = int(height / halving_period)
coinbaseoutput.nValue >>= halvings
coinbaseoutput.nValue += fees
if pubkey is not None:
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.