Merge #15419: qa: Always refresh cache to be out of ibd
fa2cdc9ac2
test: Simplify create_cache (MarcoFalke)fa25210d62
qa: Fix wallet_txn_doublespend issue (MarcoFalke)1111aecbb5
qa: Always refresh stale cache to be out of ibd (MarcoFalke)fab0d85802
qa: Remove mocktime unless required (MarcoFalke) Pull request description: When starting a test, we are always in IBD because the timestamps on cached blocks are in the past. Usually, we solve that by generating a block at the beginning of the test. That is clumsy and might even lead to other problems such as #15360 and https://github.com/bitcoin/bitcoin/issues/14446#issuecomment-461926598 So fix that by getting rid of mocktime and always refreshing the last block of the cache when starting the test framework. Should fix #14446 Tree-SHA512: 6af09800f9c86131349a103af617a54551f5f3f3260d38e14e3f30fdd3d91a0feb0100c56cbb12eae4aeac5571ae4b530b16345cbb831d2670237b53351a22c1
This commit is contained in:
commit
8f470ecc53
7 changed files with 59 additions and 34 deletions
|
@ -44,6 +44,7 @@ RANGE_BEGIN = PORT_MIN + 2 * PORT_RANGE # Start after p2p and rpc ports
|
||||||
class ProxyTest(BitcoinTestFramework):
|
class ProxyTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
self.num_nodes = 4
|
self.num_nodes = 4
|
||||||
|
self.setup_clean_chain = True
|
||||||
|
|
||||||
def setup_nodes(self):
|
def setup_nodes(self):
|
||||||
self.have_ipv6 = test_ipv6_local()
|
self.have_ipv6 = test_ipv6_local()
|
||||||
|
@ -198,4 +199,3 @@ class ProxyTest(BitcoinTestFramework):
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
ProxyTest().main()
|
ProxyTest().main()
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@ from test_framework.util import (
|
||||||
assert_raises_rpc_error,
|
assert_raises_rpc_error,
|
||||||
bytes_to_hex_str,
|
bytes_to_hex_str,
|
||||||
hex_str_to_bytes,
|
hex_str_to_bytes,
|
||||||
wait_until,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,7 +37,6 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||||
self.num_nodes = 1
|
self.num_nodes = 1
|
||||||
self.extra_args = [[
|
self.extra_args = [[
|
||||||
'-txindex',
|
'-txindex',
|
||||||
'-reindex', # Need reindex for txindex
|
|
||||||
'-acceptnonstdtxn=0', # Try to mimic main-net
|
'-acceptnonstdtxn=0', # Try to mimic main-net
|
||||||
]] * self.num_nodes
|
]] * self.num_nodes
|
||||||
|
|
||||||
|
@ -56,7 +54,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||||
|
|
||||||
self.log.info('Start with empty mempool, and 200 blocks')
|
self.log.info('Start with empty mempool, and 200 blocks')
|
||||||
self.mempool_size = 0
|
self.mempool_size = 0
|
||||||
wait_until(lambda: node.getblockcount() == 200)
|
assert_equal(node.getblockcount(), 200)
|
||||||
assert_equal(node.getmempoolinfo()['size'], self.mempool_size)
|
assert_equal(node.getmempoolinfo()['size'], self.mempool_size)
|
||||||
coins = node.listunspent()
|
coins = node.listunspent()
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ from test_framework.util import (
|
||||||
from test_framework.blocktools import (
|
from test_framework.blocktools import (
|
||||||
create_block,
|
create_block,
|
||||||
create_coinbase,
|
create_coinbase,
|
||||||
|
TIME_GENESIS_BLOCK,
|
||||||
)
|
)
|
||||||
from test_framework.messages import (
|
from test_framework.messages import (
|
||||||
msg_block,
|
msg_block,
|
||||||
|
@ -46,9 +47,11 @@ from test_framework.mininode import (
|
||||||
|
|
||||||
class BlockchainTest(BitcoinTestFramework):
|
class BlockchainTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
|
self.setup_clean_chain = True
|
||||||
self.num_nodes = 1
|
self.num_nodes = 1
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
|
self.mine_chain()
|
||||||
self.restart_node(0, extra_args=['-stopatheight=207', '-prune=1']) # Set extra args with pruning after rescan is complete
|
self.restart_node(0, extra_args=['-stopatheight=207', '-prune=1']) # Set extra args with pruning after rescan is complete
|
||||||
|
|
||||||
self._test_getblockchaininfo()
|
self._test_getblockchaininfo()
|
||||||
|
@ -61,6 +64,15 @@ class BlockchainTest(BitcoinTestFramework):
|
||||||
self._test_waitforblockheight()
|
self._test_waitforblockheight()
|
||||||
assert self.nodes[0].verifychain(4, 0)
|
assert self.nodes[0].verifychain(4, 0)
|
||||||
|
|
||||||
|
def mine_chain(self):
|
||||||
|
self.log.info('Create some old blocks')
|
||||||
|
address = self.nodes[0].get_deterministic_priv_key().address
|
||||||
|
for t in range(TIME_GENESIS_BLOCK, TIME_GENESIS_BLOCK + 200 * 600, 600):
|
||||||
|
# ten-minute steps from genesis block time
|
||||||
|
self.nodes[0].setmocktime(t)
|
||||||
|
self.nodes[0].generatetoaddress(1, address)
|
||||||
|
assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200)
|
||||||
|
|
||||||
def _test_getblockchaininfo(self):
|
def _test_getblockchaininfo(self):
|
||||||
self.log.info("Test getblockchaininfo")
|
self.log.info("Test getblockchaininfo")
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,11 @@ from .util import (
|
||||||
get_datadir_path,
|
get_datadir_path,
|
||||||
initialize_datadir,
|
initialize_datadir,
|
||||||
p2p_port,
|
p2p_port,
|
||||||
set_node_times,
|
|
||||||
sync_blocks,
|
sync_blocks,
|
||||||
sync_mempools,
|
sync_mempools,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestStatus(Enum):
|
class TestStatus(Enum):
|
||||||
PASSED = 1
|
PASSED = 1
|
||||||
FAILED = 2
|
FAILED = 2
|
||||||
|
@ -94,7 +94,6 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||||
self.setup_clean_chain = False
|
self.setup_clean_chain = False
|
||||||
self.nodes = []
|
self.nodes = []
|
||||||
self.network_thread = None
|
self.network_thread = None
|
||||||
self.mocktime = 0
|
|
||||||
self.rpc_timeout = 60 # Wait for up to 60 seconds for the RPC server to respond
|
self.rpc_timeout = 60 # Wait for up to 60 seconds for the RPC server to respond
|
||||||
self.supports_cli = False
|
self.supports_cli = False
|
||||||
self.bind_to_localhost_only = True
|
self.bind_to_localhost_only = True
|
||||||
|
@ -275,6 +274,19 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||||
self.add_nodes(self.num_nodes, extra_args)
|
self.add_nodes(self.num_nodes, extra_args)
|
||||||
self.start_nodes()
|
self.start_nodes()
|
||||||
self.import_deterministic_coinbase_privkeys()
|
self.import_deterministic_coinbase_privkeys()
|
||||||
|
if not self.setup_clean_chain:
|
||||||
|
for n in self.nodes:
|
||||||
|
assert_equal(n.getblockchaininfo()["blocks"], 199)
|
||||||
|
# To ensure that all nodes are out of IBD, the most recent block
|
||||||
|
# must have a timestamp not too old (see IsInitialBlockDownload()).
|
||||||
|
self.log.debug('Generate a block with current time')
|
||||||
|
block_hash = self.nodes[0].generate(1)[0]
|
||||||
|
block = self.nodes[0].getblock(blockhash=block_hash, verbosity=0)
|
||||||
|
for n in self.nodes:
|
||||||
|
n.submitblock(block)
|
||||||
|
chain_info = n.getblockchaininfo()
|
||||||
|
assert_equal(chain_info["blocks"], 200)
|
||||||
|
assert_equal(chain_info["initialblockdownload"], False)
|
||||||
|
|
||||||
def import_deterministic_coinbase_privkeys(self):
|
def import_deterministic_coinbase_privkeys(self):
|
||||||
for n in self.nodes:
|
for n in self.nodes:
|
||||||
|
@ -316,7 +328,6 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||||
timewait=self.rpc_timeout,
|
timewait=self.rpc_timeout,
|
||||||
bitcoind=binary[i],
|
bitcoind=binary[i],
|
||||||
bitcoin_cli=self.options.bitcoincli,
|
bitcoin_cli=self.options.bitcoincli,
|
||||||
mocktime=self.mocktime,
|
|
||||||
coverage_dir=self.options.coveragedir,
|
coverage_dir=self.options.coveragedir,
|
||||||
cwd=self.options.tmpdir,
|
cwd=self.options.tmpdir,
|
||||||
extra_conf=extra_confs[i],
|
extra_conf=extra_confs[i],
|
||||||
|
@ -435,7 +446,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||||
def _initialize_chain(self):
|
def _initialize_chain(self):
|
||||||
"""Initialize a pre-mined blockchain for use by the test.
|
"""Initialize a pre-mined blockchain for use by the test.
|
||||||
|
|
||||||
Create a cache of a 200-block-long chain (with wallet) for MAX_NODES
|
Create a cache of a 199-block-long chain (with wallet) for MAX_NODES
|
||||||
Afterward, create num_nodes copies from the cache."""
|
Afterward, create num_nodes copies from the cache."""
|
||||||
|
|
||||||
assert self.num_nodes <= MAX_NODES
|
assert self.num_nodes <= MAX_NODES
|
||||||
|
@ -468,7 +479,6 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||||
timewait=self.rpc_timeout,
|
timewait=self.rpc_timeout,
|
||||||
bitcoind=self.options.bitcoind,
|
bitcoind=self.options.bitcoind,
|
||||||
bitcoin_cli=self.options.bitcoincli,
|
bitcoin_cli=self.options.bitcoincli,
|
||||||
mocktime=self.mocktime,
|
|
||||||
coverage_dir=None,
|
coverage_dir=None,
|
||||||
cwd=self.options.tmpdir,
|
cwd=self.options.tmpdir,
|
||||||
))
|
))
|
||||||
|
@ -479,32 +489,22 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||||
for node in self.nodes:
|
for node in self.nodes:
|
||||||
node.wait_for_rpc_connection()
|
node.wait_for_rpc_connection()
|
||||||
|
|
||||||
# For backward compatibility of the python scripts with previous
|
# Create a 199-block-long chain; each of the 4 first nodes
|
||||||
# versions of the cache, set mocktime to Jan 1,
|
|
||||||
# 2014 + (201 * 10 * 60)"""
|
|
||||||
self.mocktime = 1388534400 + (201 * 10 * 60)
|
|
||||||
|
|
||||||
# Create a 200-block-long chain; each of the 4 first nodes
|
|
||||||
# gets 25 mature blocks and 25 immature.
|
# gets 25 mature blocks and 25 immature.
|
||||||
# Note: To preserve compatibility with older versions of
|
# The 4th node gets only 24 immature blocks so that the very last
|
||||||
# initialize_chain, only 4 nodes will generate coins.
|
# block in the cache does not age too much (have an old tip age).
|
||||||
#
|
# This is needed so that we are out of IBD when the test starts,
|
||||||
# blocks are created with timestamps 10 minutes apart
|
# see the tip age check in IsInitialBlockDownload().
|
||||||
# starting from 2010 minutes in the past
|
for i in range(8):
|
||||||
block_time = self.mocktime - (201 * 10 * 60)
|
self.nodes[0].generatetoaddress(25 if i != 7 else 24, self.nodes[i % 4].get_deterministic_priv_key().address)
|
||||||
for i in range(2):
|
sync_blocks(self.nodes)
|
||||||
for peer in range(4):
|
|
||||||
for j in range(25):
|
for n in self.nodes:
|
||||||
set_node_times(self.nodes, block_time)
|
assert_equal(n.getblockchaininfo()["blocks"], 199)
|
||||||
self.nodes[peer].generatetoaddress(1, self.nodes[peer].get_deterministic_priv_key().address)
|
|
||||||
block_time += 10 * 60
|
|
||||||
# Must sync before next peer starts generating blocks
|
|
||||||
sync_blocks(self.nodes)
|
|
||||||
|
|
||||||
# Shut them down, and clean up cache directories:
|
# Shut them down, and clean up cache directories:
|
||||||
self.stop_nodes()
|
self.stop_nodes()
|
||||||
self.nodes = []
|
self.nodes = []
|
||||||
self.mocktime = 0
|
|
||||||
|
|
||||||
def cache_path(n, *paths):
|
def cache_path(n, *paths):
|
||||||
return os.path.join(get_datadir_path(self.options.cachedir, n), "regtest", *paths)
|
return os.path.join(get_datadir_path(self.options.cachedir, n), "regtest", *paths)
|
||||||
|
|
|
@ -61,7 +61,7 @@ class TestNode():
|
||||||
To make things easier for the test writer, any unrecognised messages will
|
To make things easier for the test writer, any unrecognised messages will
|
||||||
be dispatched to the RPC connection."""
|
be dispatched to the RPC connection."""
|
||||||
|
|
||||||
def __init__(self, i, datadir, *, rpchost, timewait, bitcoind, bitcoin_cli, mocktime, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False):
|
def __init__(self, i, datadir, *, rpchost, timewait, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False):
|
||||||
"""
|
"""
|
||||||
Kwargs:
|
Kwargs:
|
||||||
start_perf (bool): If True, begin profiling the node with `perf` as soon as
|
start_perf (bool): If True, begin profiling the node with `perf` as soon as
|
||||||
|
@ -90,8 +90,7 @@ class TestNode():
|
||||||
"-debug",
|
"-debug",
|
||||||
"-debugexclude=libevent",
|
"-debugexclude=libevent",
|
||||||
"-debugexclude=leveldb",
|
"-debugexclude=leveldb",
|
||||||
"-mocktime=" + str(mocktime),
|
"-uacomment=testnode%d" % i,
|
||||||
"-uacomment=testnode%d" % i
|
|
||||||
]
|
]
|
||||||
|
|
||||||
self.cli = TestNodeCLI(bitcoin_cli, self.datadir)
|
self.cli = TestNodeCLI(bitcoin_cli, self.datadir)
|
||||||
|
|
|
@ -7,17 +7,25 @@ from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import (
|
from test_framework.util import (
|
||||||
assert_equal,
|
assert_equal,
|
||||||
)
|
)
|
||||||
|
from test_framework.blocktools import (
|
||||||
|
TIME_GENESIS_BLOCK,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CreateTxWalletTest(BitcoinTestFramework):
|
class CreateTxWalletTest(BitcoinTestFramework):
|
||||||
def set_test_params(self):
|
def set_test_params(self):
|
||||||
self.setup_clean_chain = False
|
self.setup_clean_chain = True
|
||||||
self.num_nodes = 1
|
self.num_nodes = 1
|
||||||
|
|
||||||
def skip_test_if_missing_module(self):
|
def skip_test_if_missing_module(self):
|
||||||
self.skip_if_no_wallet()
|
self.skip_if_no_wallet()
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
|
self.log.info('Create some old blocks')
|
||||||
|
self.nodes[0].setmocktime(TIME_GENESIS_BLOCK)
|
||||||
|
self.nodes[0].generate(200)
|
||||||
|
self.nodes[0].setmocktime(0)
|
||||||
|
|
||||||
self.log.info('Check that we have some (old) blocks and that anti-fee-sniping is disabled')
|
self.log.info('Check that we have some (old) blocks and that anti-fee-sniping is disabled')
|
||||||
assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200)
|
assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 200)
|
||||||
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
|
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
|
||||||
|
|
|
@ -34,6 +34,14 @@ class TxnMallTest(BitcoinTestFramework):
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
# All nodes should start with 1,250 BTC:
|
# All nodes should start with 1,250 BTC:
|
||||||
starting_balance = 1250
|
starting_balance = 1250
|
||||||
|
|
||||||
|
# All nodes should be out of IBD.
|
||||||
|
# If the nodes are not all out of IBD, that can interfere with
|
||||||
|
# blockchain sync later in the test when nodes are connected, due to
|
||||||
|
# timing issues.
|
||||||
|
for n in self.nodes:
|
||||||
|
assert n.getblockchaininfo()["initialblockdownload"] == False
|
||||||
|
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
assert_equal(self.nodes[i].getbalance(), starting_balance)
|
assert_equal(self.nodes[i].getbalance(), starting_balance)
|
||||||
self.nodes[i].getnewaddress("") # bug workaround, coins generated assigned to first getnewaddress!
|
self.nodes[i].getnewaddress("") # bug workaround, coins generated assigned to first getnewaddress!
|
||||||
|
|
Loading…
Reference in a new issue