From 9e419076921300a4f6cf3fe009720f25f6684370 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Fri, 24 May 2019 07:00:54 -0400 Subject: [PATCH] Merge #16042: test: Bump MAX_NODES to 12 fa47330397 test: Speed up cache creation (MarcoFalke) fa6ad7a5ec test: Bump MAX_NODES to 12 (MarcoFalke) Pull request description: When testing a combination of settings that affect the datadir (e.g. prune, blockfilter, ...) we may need a lot of datadirs. Bump the maximum number of nodes proactively from 8 to 12, so that caches get populated with 12 node dirs, as opposed to 8. Also, add an assert that the list of deterministic keys is exactly the number of max nodes (and not more than that. Also, create the cache faster. ACKs for commit fa4733: laanwj: utACK fa473303972b7dad600d949dc9b303d8136cb7e7 Tree-SHA512: 9803c765ed52d344102f5a3bce57b05d88a7429dcb05ed66ed6c881fda8d87c2834d02d21b95fe9f39c0efe3b8527e13cf94f006588cde22e8c2cd50b2d517a6 --- .../test_framework/test_framework.py | 77 ++++++++----------- test/functional/test_framework/test_node.py | 26 +++++-- 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 8348efb9ab..6372a38334 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -559,37 +559,29 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): rpc_handler.setLevel(logging.DEBUG) rpc_logger.addHandler(rpc_handler) - def _initialize_chain(self, extra_args=None): + def _initialize_chain(self): """Initialize a pre-mined blockchain for use by the test. - Create a cache of a 199-block-long chain (with wallet) for MAX_NODES + Create a cache of a 199-block-long chain Afterward, create num_nodes copies from the cache.""" + CACHE_NODE_ID = 0 # Use node 0 to create the cache for all other nodes + cache_node_dir = get_datadir_path(self.options.cachedir, CACHE_NODE_ID) assert self.num_nodes <= MAX_NODES - create_cache = False - for i in range(MAX_NODES): - if not os.path.isdir(get_datadir_path(self.options.cachedir, i)): - create_cache = True - break - if create_cache: - self.log.debug("Creating data directories from cached datadir") + if not os.path.isdir(cache_node_dir): + self.log.debug("Creating cache directory {}".format(cache_node_dir)) - # find and delete old cache directories if any exist - for i in range(MAX_NODES): - if os.path.isdir(get_datadir_path(self.options.cachedir, i)): - shutil.rmtree(get_datadir_path(self.options.cachedir, i)) - - # Create cache directories, run dashds: - self.set_genesis_mocktime() - for i in range(MAX_NODES): - datadir = initialize_datadir(self.options.cachedir, i, self.chain) - args = [self.options.bitcoind, "-datadir=" + datadir, "-mocktime="+str(TIME_GENESIS_BLOCK), '-disablewallet'] - if i > 0: - args.append("-connect=127.0.0.1:" + str(p2p_port(0))) - if extra_args is not None: - args.extend(extra_args) - self.nodes.append(TestNode(i, get_datadir_path(self.options.cachedir, i), chain=self.chain, extra_conf=["bind=127.0.0.1"], extra_args=[], extra_args_from_options=self.extra_args_from_options, rpchost=None, + initialize_datadir(self.options.cachedir, CACHE_NODE_ID, self.chain) + self.nodes.append( + TestNode( + CACHE_NODE_ID, + cache_node_dir, + chain=self.chain, + extra_conf=["bind=127.0.0.1"], + extra_args=['-disablewallet', "-mocktime=%d" % TIME_GENESIS_BLOCK], + extra_args_from_options=self.extra_args_from_options, + rpchost=None, timewait=self.rpc_timeout, bitcoind=self.options.bitcoind, bitcoin_cli=self.options.bitcoincli, @@ -597,12 +589,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): coverage_dir=None, cwd=self.options.tmpdir, )) - self.nodes[i].args = args - self.start_node(i) + self.start_node(CACHE_NODE_ID) # Wait for RPC connections to be ready - for node in self.nodes: - node.wait_for_rpc_connection() + self.nodes[CACHE_NODE_ID].wait_for_rpc_connection() # Create a 199-block-long chain; each of the 4 first nodes # gets 25 mature blocks and 25 immature. @@ -613,30 +603,31 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): self.set_genesis_mocktime() for i in range(8): self.bump_mocktime((25 if i != 7 else 24) * 156) - self.nodes[0].generatetoaddress(25 if i != 7 else 24, self.nodes[i % 4].get_deterministic_priv_key().address) - sync_blocks(self.nodes) - for n in self.nodes: - assert_equal(n.getblockchaininfo()["blocks"], 199) + self.nodes[CACHE_NODE_ID].generatetoaddress( + nblocks=25 if i != 7 else 24, + address=TestNode.PRIV_KEYS[i % 4].address, + ) - # Shut them down, and clean up cache directories: + assert_equal(self.nodes[CACHE_NODE_ID].getblockchaininfo()["blocks"], 199) + + # Shut it down, and clean up cache directories: self.stop_nodes() self.nodes = [] self.disable_mocktime() - def cache_path(n, *paths): - chain = get_chain_folder(get_datadir_path(self.options.cachedir, n), self.chain) - return os.path.join(get_datadir_path(self.options.cachedir, n), chain, *paths) + def cache_path(*paths): + chain = get_chain_folder(cache_node_dir, self.chain) + return os.path.join(cache_node_dir, chain, *paths) - for i in range(MAX_NODES): - os.rmdir(cache_path(i, 'wallets')) # Remove empty wallets dir - for entry in os.listdir(cache_path(i)): - if entry not in ['chainstate', 'blocks', 'indexes', 'evodb', 'llmq', 'backups']: - os.remove(cache_path(i, entry)) + os.rmdir(cache_path('wallets')) # Remove empty wallets dir + for entry in os.listdir(cache_path()): + if entry not in ['chainstate', 'blocks', 'indexes', 'evodb', 'llmq']: # Keep some folders + os.remove(cache_path(entry)) for i in range(self.num_nodes): - from_dir = get_datadir_path(self.options.cachedir, i) + self.log.debug("Copy cache directory {} to node {}".format(cache_node_dir, i)) to_dir = get_datadir_path(self.options.tmpdir, i) - shutil.copytree(from_dir, to_dir) + shutil.copytree(cache_node_dir, to_dir) initialize_datadir(self.options.tmpdir, i, self.chain) # Overwrite port/rpcport in dash.conf def _initialize_chain_clean(self): diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index b909563e30..7ba21de607 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -23,6 +23,7 @@ import collections from .authproxy import JSONRPCException from .util import ( + MAX_NODES, append_config, delete_cookie_file, get_rpc_proxy, @@ -131,10 +132,8 @@ class TestNode(): self.p2ps = [] - def get_deterministic_priv_key(self): - """Return a deterministic priv key in base58, that only depends on the node's index""" - AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key']) - PRIV_KEYS = [ + AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key']) + PRIV_KEYS = [ # address , privkey AddressKeyPair('yYdShjQSptFKitYLksFEUSwHe4hnbar5rf', 'cMfbiEsnG5b8Gwm6vEgfWvZLuXZNC4zsN2y7Es3An9xHRWRjmwgR'), AddressKeyPair('yfTFJgvq65UZsb9RBbpdYAAzsJoCGXqH2w', 'cStuFACUD1N6JjKQxNLUQ443qJUtSzLitKKEkA8x6utxTPZTLUtA'), @@ -145,8 +144,23 @@ class TestNode(): AddressKeyPair('yfy21e12jn3A3uDicNehCq486o9fMwJKMc', 'cMuko9rLDbtxCFWuBSrFgBDRSMxsLWKpJKScRGNuWKbhuQsnsjKT'), AddressKeyPair('yURgENB3b2YRMWnbhKF7iGs3KoaVRVXsJr', 'cQhdjTMh57MaHCDk9FsWGPtftRMBUuhaYAtouWnetcewmBuSrLSM'), AddressKeyPair('yYC9AxBEUs3ZZxfcQvj2LUF5PVxxtqaEs7', 'cQFueiiP13mfytV3Svoe4o4Ux79fRJvwuSgHapXsnBwrHod57EeL'), - ] - return PRIV_KEYS[self.index] + AddressKeyPair('yVs9jXGyLWLLFbpESnoppk7F8DtXcuCCTf', 'cN55daf1HotwBAgAKWVgDcoppmUNDtQSfb7XLutTLeAgVc3u8hik'), + AddressKeyPair('yV3eqNNshZJ4Pv6NCyYsbdJb1ERFFygFqf', 'cT7qK7g1wkYEMvKowd2ZrX1E5f6JQ7TM246UfqbCiyF7kZhorpX3'), + AddressKeyPair('yfE8gZCiFW9Uqu21v3JGibr3WVSPQWmY8n', 'cPiRWE8KMjTRxH1MWkPerhfoHFn5iHPWVK5aPqjW8NxmdwenFinJ'), + AddressKeyPair('yLLVXzya7GzmVkjQzsCG4iDpqYJyJFDSEV', 'cVLCocFyWxzyCwEknkWvDeWneTBsh9Jf3u4yiJCYjcy3gt8Jw1cM'), + AddressKeyPair('yLNNR3HeJxgR669oRePksYmCqHuPUG79mF', 'cQawC3oUgoToGDJBw1Ub2PpDmf44kVtcaVaTcHyzXMRKGwdn9UYW'), + AddressKeyPair('yLPKVwRTXME7Q3JfKAPJ4FHEaGdWgJuhpj', 'cVcFaWTbkCUZPFTHfDs8iHurPWns5QXc5rqcfkPMHUdmv17o8UYB'), + AddressKeyPair('yLPUundzTpvjU8KYVyM4Zmnr4REf3FFvhZ', 'cRVeRmRaYuEYP9HbCZFsf1ifYYZ4KQD9rttRoTNb9wjPzhvRwqMb'), + AddressKeyPair('yLRhHqau58AS1ALtnaowv1Pyztxi1Q6fXG', 'cNYFW52pJswYbfPR9fpiRpWHEQygg5tyMih2ASPsgMgPy9SUSSEV'), + AddressKeyPair('yLRwHeMkXwYrkDzC4q12vej243AyTeWiPm', 'cRqfZ3dAp8BJUcGhSv7ueCXNGbki1bpcXEKk5dEJN344H52GuHQY'), + AddressKeyPair('yLTMCXJhG1mpaWhbHcsr7zUt9wDWuQSPSk', 'cVWGbeCT5QcVGVTL5NuiLs9JfL8HFDb9PN5Gq2xudw6ZsDFeDy1V'), + AddressKeyPair('yLU9vxiAWUdiKKxn6EazLDFq9WXrK2T7RP', 'cVCzrzfxMhUMxV34UhTmdmntAqHvosAuNo2KUZsiHZSKLm73g35o'), + ] + + def get_deterministic_priv_key(self): + """Return a deterministic priv key in base58, that only depends on the node's index""" + assert len(self.PRIV_KEYS) == MAX_NODES + return self.PRIV_KEYS[self.index] def _node_msg(self, msg: str) -> str: """Return a modified msg that identifies this node by its index as a debugging aid."""