Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
251'secret-torpassword',252'Command-line arg: rpcbind=****',253'Command-line arg: rpcallowip=****',254]):255self.start_node(0, extra_args=[256'-addnode=some.node',257'-rpcauth=alice:f7efda5c189b999524f151318c0c86$d5b51b3beffbc0',258'-rpcbind=127.1.1.1',259'-rpcbind=127.0.0.1',260"-rpcallowip=127.0.0.1",261'-rpcpassword=',262'-rpcuser=secret-rpcuser',263'-torpassword=secret-torpassword',264UNREACHABLE_PROXY_ARG,265])266self.stop_node(0)268def test_empty_addnode(self):269self.log.info("Test empty addnode configuration values are ignored")270node = self.nodes[0]271util.append_config(node.datadir_path, ["addnode="])273with node.assert_debug_log(expected_msgs=["Ignoring empty -addnode value"]):274# Values consisting of whitespace only are trimmed away by the275# config file parser, so they can only be passed on the command276# line. Non-empty values are unaffected.277self.start_node(0, extra_args=["-addnode= ", "-addnode=some.node"])278util.assert_equal([added["addednode"] for added in node.getaddednodeinfo()], ["some.node"])279self.stop_node(0)281node.replace_in_config([("addnode=\n", "")])283def test_networkactive(self):284self.log.info('Test -networkactive option')285with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: true\n']):286self.start_node(0)288self.stop_node(0)289with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: true\n']):290self.start_node(0, extra_args=['-networkactive'])292self.stop_node(0)293with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: true\n']):294self.start_node(0, extra_args=['-networkactive=1'])296self.stop_node(0)297with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: false\n']):298self.start_node(0, extra_args=['-networkactive=0'])300self.stop_node(0)301with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: false\n']):302self.start_node(0, extra_args=['-nonetworkactive'])304self.stop_node(0)305with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: false\n']):306self.start_node(0, extra_args=['-nonetworkactive=1'])307self.stop_node(0)309def test_seed_peers(self):310self.log.info('Test seed peers')311default_data_dir = self.nodes[0].datadir_path312peer_dat = default_data_dir / 'peers.dat'314# No peers.dat exists and -dnsseed=1315# We expect the node will use DNS Seeds, but Regtest mode does not have316# any valid DNS seeds. So after 60 seconds, the node should fallback to317# fixed seeds318assert not peer_dat.exists()319start = int(time.time())320with self.nodes[0].assert_debug_log(321expected_msgs=[322"Loaded 0 addresses from peers.dat",323"0 addresses found from DNS seeds",324"opencon thread start", # Ensure ThreadOpenConnections::start time is properly set325],326timeout=10,327):328self.start_node(0, extra_args=['-dnsseed=1', '-fixedseeds=1', f'-mocktime={start}', UNREACHABLE_PROXY_ARG])330# Only regtest has no fixed seeds. To avoid connections to random331# nodes, regtest is the only network where it is safe to enable332# -fixedseeds in tests333util.assert_equal(self.nodes[0].getblockchaininfo()['chain'],'regtest')335with self.nodes[0].assert_debug_log(expected_msgs=[336"Adding fixed seeds as 60 seconds have passed and addrman is empty",337], timeout=2):338self.nodes[0].setmocktime(start + 65)339self.stop_node(0)341# No peers.dat exists and -dnsseed=0342# We expect the node will fallback immediately to fixed seeds343# An empty -addnode value is ignored, so it must not delay the fallback344# either.345assert not peer_dat.exists()346with self.nodes[0].assert_debug_log(expected_msgs=[347"Loaded 0 addresses from peers.dat",348"DNS seeding disabled",349"Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet) and neither -addnode nor -seednode are provided\n",350], timeout=2):351self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=1', '-addnode='])352self.stop_node(0)353self.nodes[0].assert_start_raises_init_error(['-dnsseed=1', '-onlynet=i2p', '-i2psam=127.0.0.1:7656'], "Error: Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6")355# No peers.dat exists and dns seeds are disabled.356# We expect the node will not add fixed seeds when explicitly disabled.357assert not peer_dat.exists()358with self.nodes[0].assert_debug_log(expected_msgs=[359"Loaded 0 addresses from peers.dat",360"DNS seeding disabled",361"Fixed seeds are disabled",362], timeout=2):363self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=0'])364self.stop_node(0)366# No peers.dat exists and -dnsseed=0, but a -addnode is provided367# We expect the node will allow 60 seconds prior to using fixed seeds368assert not peer_dat.exists()369start = int(time.time())370with self.nodes[0].assert_debug_log(371expected_msgs=[372"Loaded 0 addresses from peers.dat",373"DNS seeding disabled",374"opencon thread start", # Ensure ThreadOpenConnections::start time is properly set375],376timeout=10,377):378self.start_node(0, extra_args=['-dnsseed=0', '-fixedseeds=1', '-addnode=fakenodeaddr', f'-mocktime={start}', UNREACHABLE_PROXY_ARG])379with self.nodes[0].assert_debug_log(expected_msgs=[380"Adding fixed seeds as 60 seconds have passed and addrman is empty",381], timeout=2):382self.nodes[0].setmocktime(start + 65)383self.stop_node(0)385def test_connect_with_seednode(self):386self.log.info('Test -connect with -seednode')387seednode_ignored = ['-seednode is ignored when -connect is used\n']388dnsseed_ignored = ['-dnsseed is ignored when -connect is used and -proxy is specified\n']389addcon_thread_started = ['addcon thread start\n']390dnsseed_disabled = "parameter interaction: -connect or -maxconnections=0 set -> setting -dnsseed=0"391listen_disabled = "parameter interaction: -connect or -maxconnections=0 set -> setting -listen=0"393# When -connect is supplied, expanding addrman via getaddr calls to ADDR_FETCH(-seednode)394# nodes is irrelevant and -seednode is ignored.395with self.nodes[0].assert_debug_log(expected_msgs=seednode_ignored):396self.start_node(0, extra_args=['-connect=fakeaddress1', '-seednode=fakeaddress2', UNREACHABLE_PROXY_ARG])398# With -proxy, an ADDR_FETCH connection is made to a peer that the dns seed resolves to.399# ADDR_FETCH connections are not used when -connect is used.400with self.nodes[0].assert_debug_log(expected_msgs=dnsseed_ignored):401self.restart_node(0, extra_args=['-connect=fakeaddress1', '-dnsseed=1', UNREACHABLE_PROXY_ARG])403# If the user did not disable -dnsseed, but it was soft-disabled because they provided -connect,404# they shouldn't see a warning about -dnsseed being ignored.405with self.nodes[0].assert_debug_log(expected_msgs=addcon_thread_started,406unexpected_msgs=dnsseed_ignored, timeout=2):407self.restart_node(0, extra_args=['-connect=fakeaddress1', UNREACHABLE_PROXY_ARG])409# We have to supply expected_msgs as it's a required argument410# The expected_msg must be something we are confident will be logged after the unexpected_msg411# These cases test for -connect being supplied but only to disable it412for connect_arg in ['-connect=0', '-noconnect']:413with self.nodes[0].assert_debug_log(expected_msgs=addcon_thread_started,414unexpected_msgs=seednode_ignored, timeout=2):415self.restart_node(0, extra_args=[connect_arg, '-seednode=fakeaddress2'])417# Make sure -noconnect soft-disables -listen and -dnsseed.418# Need to temporarily remove these settings from the config file in419# order for the two log messages to appear420self.nodes[0].replace_in_config([("bind=", "#bind="), ("dnsseed=", "#dnsseed=")])421with self.nodes[0].assert_debug_log(expected_msgs=[dnsseed_disabled, listen_disabled]):422self.restart_node(0, extra_args=[connect_arg])423self.nodes[0].replace_in_config([("#bind=", "bind="), ("#dnsseed=", "dnsseed=")])425# Make sure -proxy and -noconnect warn about -dnsseed setting being426# ignored, just like -proxy and -connect do.427with self.nodes[0].assert_debug_log(expected_msgs=dnsseed_ignored):428self.restart_node(0, extra_args=[connect_arg, '-dnsseed', '-proxy=localhost:1080'])429self.stop_node(0)431def test_privatebroadcast(self):432self.log.info("Test that an invalid usage of -privatebroadcast throws an init error")433self.stop_node(0)434# -privatebroadcast init error: Tor/I2P not reachable at startup435self.nodes[0].assert_start_raises_init_error(436extra_args=["-privatebroadcast"],437expected_msg=(438"Error: Private broadcast of own transactions requested (-privatebroadcast), "439"but none of Tor or I2P networks is reachable"))440# -privatebroadcast init error: incompatible with -connect441self.nodes[0].assert_start_raises_init_error(442extra_args=["-privatebroadcast", "-connect=127.0.0.1:8333", "-onion=127.0.0.1:9050"],443expected_msg=(444"Error: Private broadcast of own transactions requested (-privatebroadcast), but -connect is also configured. "445"They are incompatible because the private broadcast needs to open new connections to randomly "446"chosen Tor or I2P peers. Consider using -maxconnections=0 -addnode=... instead"))447# Warning case: private broadcast allowed, but -proxyrandomize=0 triggers a privacy warning448self.start_node(0, extra_args=["-privatebroadcast", "-onion=127.0.0.1:9050", "-proxyrandomize=0"])449self.stop_node(0, expected_stderr=(450"Warning: Private broadcast of own transactions requested (-privatebroadcast) and "451"-proxyrandomize is disabled. Tor circuits for private broadcast connections may "452"be correlated to other connections over Tor. To reduce this risk, set -proxyrandomize=1."))454def test_ignored_conf(self):455self.log.info('Test error is triggered when the datadir in use contains a bitcoin.conf file that would be ignored '456'because a conflicting -conf file argument is passed.')457node = self.nodes[0]458with tempfile.NamedTemporaryFile(dir=self.options.tmpdir, mode="wt", delete=False) as temp_conf:459temp_conf.write(f"datadir={node.datadir_path}\n")460node.assert_start_raises_init_error([f"-conf={temp_conf.name}"], re.escape(461f'Error: Data directory "{node.datadir_path}" contains a "bitcoin.conf" file which is ignored, because a '462f'different configuration file "{temp_conf.name}" from command line argument "-conf={temp_conf.name}" '463f'is being used instead.') + r"[\s\S]*", match=ErrorMatch.FULL_REGEX)465# Test that passing a redundant -conf command line argument pointing to466# the same bitcoin.conf that would be loaded anyway does not trigger an467# error.468self.start_node(0, [f'-conf={node.datadir_path}/bitcoin.conf'])469self.stop_node(0)471def test_ignored_default_conf(self):472# Disable this test for windows currently because trying to override473# the default datadir through the environment does not seem to work.474if platform.system() == "Windows":475return477self.log.info('Test error is triggered when bitcoin.conf in the default data directory sets another datadir '478'and it contains a different bitcoin.conf file that would be ignored')480# Create a temporary directory that will be treated as the default data481# directory by bitcoind.482env, default_datadir = util.get_temp_default_datadir(Path(self.options.tmpdir, "home"))483default_datadir.mkdir(parents=True)485# Write a bitcoin.conf file in the default data directory containing a486# datadir= line pointing at the node datadir. This will trigger a487# startup error because the node datadir contains a different488# bitcoin.conf that would be ignored.489node = self.nodes[0]490(default_datadir / "bitcoin.conf").write_text(f"datadir={node.datadir_path}\n")492# Drop the node -datadir= argument during this test, because if it is493# specified it would take precedence over the datadir setting in the494# config file.495node_args = node.args496node.args = [arg for arg in node.args if not arg.startswith("-datadir=")]497node.assert_start_raises_init_error([], re.escape(498f'Error: Data directory "{node.datadir_path}" contains a "bitcoin.conf" file which is ignored, because a '499f'different configuration file "{default_datadir}/bitcoin.conf" from data directory "{default_datadir}" '500f'is being used instead.') + r"[\s\S]*", env=env, match=ErrorMatch.FULL_REGEX)
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.