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."""