mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-11 21:20:39 +02:00
Drop the include_dummy_extranonce branch from the OP_0 padding
condition in CreateNewBlock(), so that the dummy extraNonce is
only appended when consensus actually requires it (heights <= 16,
where the BIP34 height push alone would yield a 1-byte scriptSig
and trigger bad-cb-length).
The include_dummy_extranonce option struct field is now unused by
the miner and is removed in the next commit. Callers still set it,
so that this commit compiles.
Regenerate the hardcoded coinbase / block hashes throughout the
unit and functional test suites and update the regtest assumeutxo
snapshot in chainparams.
Additional side-effects:
- Without the dummy extranonce, coinbase scriptSigs are 1 byte
shorter at heights > 16, making every block 1 byte smaller.
This shifts where block files wrap and therefore where pruning
boundaries land.
- feature_assumeutxo malleation cases:
- case 1: error message changes due to UTXO reordering, similar
to 8f2078af6a
- case 4: the corruption byte is swapped from \x82 to \x83
because \x82 happened to be the actual value at that
offset in the new snapshot.
99 lines
3.9 KiB
Python
Executable File
99 lines
3.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Copyright (c) 2019-present The Bitcoin Core developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
"""Test the generation of UTXO snapshots using `dumptxoutset`.
|
|
"""
|
|
|
|
from test_framework.blocktools import COINBASE_MATURITY
|
|
from test_framework.test_framework import BitcoinTestFramework
|
|
from test_framework.util import (
|
|
assert_equal,
|
|
assert_raises_rpc_error,
|
|
sha256sum_file,
|
|
)
|
|
|
|
|
|
class DumptxoutsetTest(BitcoinTestFramework):
|
|
def set_test_params(self):
|
|
self.setup_clean_chain = True
|
|
self.num_nodes = 1
|
|
|
|
def test_dumptxoutset_with_fork(self):
|
|
node = self.nodes[0]
|
|
tip = node.getbestblockhash()
|
|
target_height = node.getblockcount() - 10
|
|
target_hash = node.getblockhash(target_height)
|
|
|
|
# Create a fork of two blocks at the target height
|
|
invalid_block = node.getblockhash(target_height + 1)
|
|
node.invalidateblock(invalid_block)
|
|
# Reset mocktime to not regenerate the same blockhash
|
|
node.setmocktime(0)
|
|
self.generate(node, 2)
|
|
|
|
# Move back on to actual main chain
|
|
node.reconsiderblock(invalid_block)
|
|
self.wait_until(lambda: node.getbestblockhash() == tip)
|
|
|
|
# Use dumptxoutset at the forked height
|
|
out = node.dumptxoutset("txoutset_fork.dat", "rollback", {"rollback": target_height})
|
|
|
|
# Verify the snapshot was created at the target height and not the fork tip
|
|
assert_equal(out['base_height'], target_height)
|
|
assert_equal(out['base_hash'], target_hash)
|
|
|
|
# Cover the same case as above with an in-memory database
|
|
out_mem = node.dumptxoutset("txoutset_fork_mem.dat", "rollback", {"rollback": target_height, "in_memory": True})
|
|
assert_equal(out_mem['base_height'], target_height)
|
|
assert_equal(out_mem['base_hash'], target_hash)
|
|
|
|
|
|
def run_test(self):
|
|
"""Test a trivial usage of the dumptxoutset RPC command."""
|
|
node = self.nodes[0]
|
|
mocktime = node.getblockheader(node.getblockhash(0))['time'] + 1
|
|
node.setmocktime(mocktime)
|
|
self.generate(node, COINBASE_MATURITY)
|
|
|
|
FILENAME = 'txoutset.dat'
|
|
out = node.dumptxoutset(FILENAME, "latest")
|
|
expected_path = node.chain_path / FILENAME
|
|
|
|
assert expected_path.is_file()
|
|
|
|
assert_equal(out['coins_written'], 100)
|
|
assert_equal(out['base_height'], 100)
|
|
assert_equal(out['path'], str(expected_path))
|
|
# Blockhash should be deterministic based on mocked time.
|
|
assert_equal(
|
|
out['base_hash'],
|
|
'220aee93f0f5409631f35488898258f0930952bd620063cb4d7d87f7c28a8f50')
|
|
|
|
# UTXO snapshot hash should be deterministic based on mocked time.
|
|
assert_equal(
|
|
sha256sum_file(str(expected_path)).hex(),
|
|
'e8c59b1bc1f19061c67eb7a392f4ea17eea83af58646ea2909e270546699c36c')
|
|
|
|
assert_equal(
|
|
out['txoutset_hash'], '771d773b5c27b6f35f598ce764652a2cf28fbc268341eb1827844e416c629c7d')
|
|
assert_equal(out['nchaintx'], 101)
|
|
|
|
# Specifying a path to an existing or invalid file will fail.
|
|
assert_raises_rpc_error(
|
|
-8, '{} already exists'.format(FILENAME), node.dumptxoutset, FILENAME, "latest")
|
|
invalid_path = node.datadir_path / "invalid" / "path"
|
|
assert_raises_rpc_error(
|
|
-8, "Couldn't open file {}.incomplete for writing".format(invalid_path), node.dumptxoutset, invalid_path, "latest")
|
|
|
|
self.log.info("Test that dumptxoutset with unknown dump type fails")
|
|
assert_raises_rpc_error(
|
|
-8, 'Invalid snapshot type "bogus" specified. Please specify "rollback" or "latest"', node.dumptxoutset, 'utxos.dat', "bogus")
|
|
|
|
self.log.info("Testing dumptxoutset with chain fork at target height")
|
|
self.test_dumptxoutset_with_fork()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
DumptxoutsetTest(__file__).main()
|