diff --git a/src/common/args.cpp b/src/common/args.cpp index 833a0b28bd2..b94bccba4eb 100644 --- a/src/common/args.cpp +++ b/src/common/args.cpp @@ -5,6 +5,7 @@ #include +#include #include #include #include @@ -279,6 +280,18 @@ fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value) return result.has_filename() ? result : result.parent_path(); } +fs::path ArgsManager::GetSignetDataDir() const +{ + const std::string base_data_dir = BaseParams().DataDir(); + const std::string signet_challenge_str = GetArg("-signetchallenge", ""); + if (!signet_challenge_str.empty()) { + std::vector signet_challenge = ParseHex(signet_challenge_str); + const auto data_dir_suffix = HexStr(Hash160(signet_challenge)).substr(0, 8); + return fs::PathFromString(base_data_dir + "_" + data_dir_suffix); + } + return fs::PathFromString(base_data_dir); +} + fs::path ArgsManager::GetBlocksDirPath() const { LOCK(cs_args); @@ -298,7 +311,12 @@ fs::path ArgsManager::GetBlocksDirPath() const path = GetDataDirBase(); } - path /= fs::PathFromString(BaseParams().DataDir()); + if (GetChainType() == ChainType::SIGNET) { + path /= GetSignetDataDir(); + } else { + path /= fs::PathFromString(BaseParams().DataDir()); + } + path /= "blocks"; fs::create_directories(path); return path; @@ -324,7 +342,11 @@ fs::path ArgsManager::GetDataDir(bool net_specific) const } if (net_specific && !BaseParams().DataDir().empty()) { - path /= fs::PathFromString(BaseParams().DataDir()); + if (GetChainType() == ChainType::SIGNET) { + path /= GetSignetDataDir(); + } else { + path /= fs::PathFromString(BaseParams().DataDir()); + } } return path; diff --git a/src/common/args.h b/src/common/args.h index 8d9daf5f65d..11d0dd545c2 100644 --- a/src/common/args.h +++ b/src/common/args.h @@ -212,6 +212,14 @@ protected: */ std::optional GetCommand() const; + /** + * Get signet data directory path. + * If a signet-challange argument is provided, it is used in constructing the directory path. + * + * @return The path to the signet data directory. + */ + fs::path GetSignetDataDir() const; + /** * Get blocks directory path * diff --git a/test/functional/feature_signet.py b/test/functional/feature_signet.py index 63091b3ee87..4503509c356 100755 --- a/test/functional/feature_signet.py +++ b/test/functional/feature_signet.py @@ -5,6 +5,7 @@ """Test basic signet functionality""" from decimal import Decimal +from os import path from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal @@ -99,6 +100,12 @@ class SignetBasicTest(BitcoinTestFramework): assert_equal(self.nodes[4].submitblock(signet_blocks[0]), 'bad-signet-blksig') + self.log.info("Test that the signet data directory with -signetchallenge=51 is 'signet_da1745e9'") + assert_equal(path.basename(self.nodes[0].chain_path), "signet_da1745e9") + + self.log.info("Test that the main signet data directory is 'signet'") + assert_equal(path.basename(self.nodes[3].chain_path), "signet") + self.log.info("test that signet logs the network magic on node start") with self.nodes[0].assert_debug_log(["Signet derived magic (message start)"]): self.restart_node(0) diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py index 2618c12e9f5..8f845b5519d 100755 --- a/test/functional/interface_bitcoin_cli.py +++ b/test/functional/interface_bitcoin_cli.py @@ -101,7 +101,7 @@ class TestBitcoinCli(BitcoinTestFramework): assert_equal(self.nodes[0].cli("-named", "echo", "arg0=0", "arg1=1", "arg2=2", "arg1=3").send_cli(), ['0', '3', '2']) assert_raises_rpc_error(-8, "Parameter args specified multiple times", self.nodes[0].cli("-named", "echo", "args=[0,1,2,3]", "4", "5", "6", ).send_cli) - user, password = get_auth_cookie(self.nodes[0].datadir_path, self.chain) + user, password = get_auth_cookie(self.nodes[0].datadir_path, self.nodes[0].get_chain()) self.log.info("Test -stdinrpcpass option") assert_equal(BLOCKS, self.nodes[0].cli(f'-rpcuser={user}', '-stdinrpcpass', input=password).getblockcount()) diff --git a/test/functional/rpc_bind.py b/test/functional/rpc_bind.py index 69afd45b9af..4673e0038da 100755 --- a/test/functional/rpc_bind.py +++ b/test/functional/rpc_bind.py @@ -71,7 +71,7 @@ class RPCBindTest(BitcoinTestFramework): self.nodes[0].rpchost = None self.start_nodes([node_args]) # connect to node through non-loopback interface - node = get_rpc_proxy(rpc_url(self.nodes[0].datadir_path, 0, self.chain, "%s:%d" % (rpchost, rpcport)), 0, coveragedir=self.options.coveragedir) + node = get_rpc_proxy(rpc_url(self.nodes[0].datadir_path, 0, self.nodes[0].get_chain(), "%s:%d" % (rpchost, rpcport)), 0, coveragedir=self.options.coveragedir) node.getnetworkinfo() self.stop_nodes() diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index d5b338f2ba2..26c45b9c350 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -35,6 +35,7 @@ from .util import ( p2p_port, wait_until_helper_internal, ) +from .script import hash160 class TestStatus(Enum): @@ -557,11 +558,21 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): descriptors=self.options.descriptors, v2transport=self.options.v2transport, ) + if self.chain == "signet": + test_node_i.signet_chain = self.get_signet_chain(args) self.nodes.append(test_node_i) if not test_node_i.version_is_at_least(170000): # adjust conf for pre 17 test_node_i.replace_in_config([('[regtest]', '')]) + def get_signet_chain(self, args): + for arg in args: + if arg.startswith('-signetchallenge'): + signetchallenge = arg.split('=')[1] + data_dir_suffix = hash160(bytes.fromhex(signetchallenge)).hex()[0:8] + return f"signet_{data_dir_suffix}" + return 'signet' + def start_node(self, i, *args, **kwargs): """Start a bitcoind""" diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index f7d6ba78d23..8928b30d6be 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -90,6 +90,7 @@ class TestNode(): self.stdout_dir = self.datadir_path / "stdout" self.stderr_dir = self.datadir_path / "stderr" self.chain = chain + self.signet_chain = "" self.rpchost = rpchost self.rpc_timeout = timewait self.binary = bitcoind @@ -184,6 +185,9 @@ class TestNode(): AddressKeyPair('mzRe8QZMfGi58KyWCse2exxEFry2sfF2Y7', 'cPiRWE8KMjTRxH1MWkPerhfoHFn5iHPWVK5aPqjW8NxmdwenFinJ'), ] + def get_chain(self): + return self.signet_chain if self.chain == 'signet' else self.chain + 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 @@ -276,7 +280,7 @@ class TestNode(): f'bitcoind exited with status {self.process.returncode} during initialization. {str_error}')) try: rpc = get_rpc_proxy( - rpc_url(self.datadir_path, self.index, self.chain, self.rpchost), + rpc_url(self.datadir_path, self.index, self.get_chain(), self.rpchost), self.index, timeout=self.rpc_timeout // 2, # Shorter timeout to allow for one retry in case of ETIMEDOUT coveragedir=self.coverage_dir, @@ -340,7 +344,7 @@ class TestNode(): poll_per_s = 4 for _ in range(poll_per_s * self.rpc_timeout): try: - get_auth_cookie(self.datadir_path, self.chain) + get_auth_cookie(self.datadir_path, self.get_chain()) self.log.debug("Cookie credentials successfully retrieved") return except ValueError: # cookie file not found and no rpcuser or rpcpassword; bitcoind is still starting @@ -460,7 +464,7 @@ class TestNode(): @property def chain_path(self) -> Path: - return self.datadir_path / self.chain + return self.datadir_path / self.get_chain() @property def debug_log_path(self) -> Path: diff --git a/test/functional/tool_signet_miner.py b/test/functional/tool_signet_miner.py index 00841585548..bf1cbcc710c 100755 --- a/test/functional/tool_signet_miner.py +++ b/test/functional/tool_signet_miner.py @@ -33,8 +33,8 @@ class SignetMinerTest(BitcoinTestFramework): privkey = ECKey() privkey.set(CHALLENGE_PRIVATE_KEY, True) pubkey = privkey.get_pubkey().get_bytes() - challenge = key_to_p2wpkh_script(pubkey) - self.extra_args = [[f'-signetchallenge={challenge.hex()}']] + self.challenge = key_to_p2wpkh_script(pubkey) + self.extra_args = [[f'-signetchallenge={self.challenge.hex()}']] def skip_test_if_missing_module(self): self.skip_if_no_cli() @@ -49,10 +49,11 @@ class SignetMinerTest(BitcoinTestFramework): # generate block with signet miner tool base_dir = self.config["environment"]["SRCDIR"] signet_miner_path = os.path.join(base_dir, "contrib", "signet", "miner") + # breakpoint() subprocess.run([ sys.executable, signet_miner_path, - f'--cli={node.cli.binary} -datadir={node.cli.datadir}', + f'--cli={node.cli.binary} -datadir={node.cli.datadir} -signetchallenge={self.challenge.hex()}', 'generate', f'--address={node.getnewaddress()}', f'--grind-cmd={self.options.bitcoinutil} grind',