mirror of https://github.com/bitcoin/bitcoin.git
93 lines
3.6 KiB
Python
Executable File
93 lines
3.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Copyright (c) 2019-2022 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)
|
|
|
|
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'],
|
|
'6885775faa46290bedfa071f22d0598c93f1d7e01f24607c4dedd69b9baa4a8f')
|
|
|
|
# UTXO snapshot hash should be deterministic based on mocked time.
|
|
assert_equal(
|
|
sha256sum_file(str(expected_path)).hex(),
|
|
'd9506d541437f5e2892d6b6ea173f55233de11601650c157a27d8f2b9d08cb6f')
|
|
|
|
assert_equal(
|
|
out['txoutset_hash'], 'd4453995f4f20db7bb3a604afd10d7128e8ee11159cde56d5b2fd7f55be7c74c')
|
|
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()
|