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:
MarcoFalke 2019-02-25 11:44:18 -05:00
commit 8f470ecc53
No known key found for this signature in database
GPG key ID: D2EA4850E7528B25
7 changed files with 59 additions and 34 deletions

View file

@ -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()

View file

@ -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()

View file

@ -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")

View file

@ -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):
for peer in range(4):
for j in range(25):
set_node_times(self.nodes, block_time)
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) sync_blocks(self.nodes)
for n in self.nodes:
assert_equal(n.getblockchaininfo()["blocks"], 199)
# 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)

View file

@ -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)

View file

@ -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)

View file

@ -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!