test: use dynamic ports and add coverage in feature_bind_port_discover
What changed, and why it matters
This commit only changes a test script in Bitcoin Core. It updates the functional test feature_bind_port_discover.py to use dynamic ports instead of a hardcoded port, adds more test cases, and improves setup instructions. There is no change to the actual Bitcoin node software that users run, so it has no direct security impact on the network or wallets.
No security action needed. This is a routine test-quality improvement. Reviewers may verify the new test cases pass in CI.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff modifies test/functional/feature_bind_port_discover.py. It replaces a hardcoded BIND_PORT with ports allocated via the test framework’s p2p_port()/tor_port() helpers, adds two extra nodes to cover -bind=0.0.0.0 and -whitebind=0.0.0.0 scenarios, and updates comments about interface setup on Linux/macOS/FreeBSD. No C++/Python production code is touched.
Changed components
test/functional/feature_bind_port_discover.pyInspect captured patch +48 / −26
diff --git a/test/functional/feature_bind_port_discover.py b/test/functional/feature_bind_port_discover.py
index f3fe3454..613b111b 100755
--- a/test/functional/feature_bind_port_discover.py
+++ b/test/functional/feature_bind_port_discover.py
@@ -10,31 +10,46 @@ from test_framework.test_framework import BitcoinTestFramework, SkipTest
from test_framework.util import (
assert_equal,
assert_not_equal,
+ p2p_port,
+ tor_port,
)
-# We need to bind to a routable address for this test to exercise the relevant code
-# and also must have another routable address on another interface which must not
-# be named "lo" or "lo0".
-# To set these routable addresses on the machine, use:
+# We need to bind to routable addresses for this test. Both addresses must be on an
+# interface that is UP and not a loopback interface (IFF_LOOPBACK). To set these
+# routable addresses on the machine, use:
# Linux:
-# ifconfig lo:0 1.1.1.1/32 up && ifconfig lo:1 2.2.2.2/32 up # to set up
-# ifconfig lo:0 down && ifconfig lo:1 down # to remove it, after the test
+# First find your interfaces: ip addr show
+# Then use your actual interface names (replace INTERFACE_NAME with yours):
+# ip addr add 1.1.1.1/32 dev INTERFACE_NAME && ip addr add 2.2.2.2/32 dev INTERFACE_NAME # to set up
+# ip addr del 1.1.1.1/32 dev INTERFACE_NAME && ip addr del 2.2.2.2/32 dev INTERFACE_NAME # to remove it
+#
+# macOS:
+# ifconfig en0 alias 1.1.1.1 && ifconfig en0 alias 2.2.2.2 # to set up
+# ifconfig en0 1.1.1.1 -alias && ifconfig en0 2.2.2.2 -alias # to remove it, after the test
+#
# FreeBSD:
# ifconfig em0 1.1.1.1/32 alias && ifconfig wlan0 2.2.2.2/32 alias # to set up
# ifconfig em0 1.1.1.1 -alias && ifconfig wlan0 2.2.2.2 -alias # to remove it, after the test
ADDR1 = '1.1.1.1'
ADDR2 = '2.2.2.2'
-BIND_PORT = 31001
-
class BindPortDiscoverTest(BitcoinTestFramework):
def set_test_params(self):
# Avoid any -bind= on the command line. Force the framework to avoid adding -bind=127.0.0.1.
- self.setup_clean_chain = True
self.bind_to_localhost_only = False
+ # Get dynamic ports for each node from the test framework
+ self.bind_ports = [
+ p2p_port(0),
+ p2p_port(2), # node0 will use their port + 1 for onion listen, which is the same as p2p_port(1), so avoid collision
+ p2p_port(3),
+ p2p_port(4),
+ ]
self.extra_args = [
- ['-discover', f'-port={BIND_PORT}'], # bind on any
- ['-discover', f'-bind={ADDR1}:{BIND_PORT}'],
+ ['-discover', f'-port={self.bind_ports[0]}', '-listen=1'], # Without any -bind
+ ['-discover', f'-bind=0.0.0.0:{self.bind_ports[1]}'], # Explicit -bind=0.0.0.0
+ # Explicit -whitebind=0.0.0.0, add onion bind to avoid port conflict
+ ['-discover', f'-whitebind=0.0.0.0:{self.bind_ports[2]}', f'-bind=127.0.0.1:{tor_port(3)}=onion'],
+ ['-discover', f'-bind={ADDR1}:{self.bind_ports[3]}'], # Explicit -bind=routable_addr
]
self.num_nodes = len(self.extra_args)
@@ -70,28 +85,35 @@ class BindPortDiscoverTest(BitcoinTestFramework):
def run_test(self):
self.log.info(
- "Test that if -bind= is not passed then all addresses are "
+ "Test that if -bind= is not passed or -bind=0.0.0.0 is used then all addresses are "
"added to localaddresses")
- found_addr1 = False
- found_addr2 = False
- for local in self.nodes[0].getnetworkinfo()['localaddresses']:
- if local['address'] == ADDR1:
- found_addr1 = True
- assert_equal(local['port'], BIND_PORT)
- if local['address'] == ADDR2:
- found_addr2 = True
- assert_equal(local['port'], BIND_PORT)
- assert found_addr1
- assert found_addr2
+ for i in [0, 1, 2]:
+ found_addr1 = False
+ found_addr2 = False
+ localaddresses = self.nodes[i].getnetworkinfo()['localaddresses']
+ for local in localaddresses:
+ if local['address'] == ADDR1:
+ found_addr1 = True
+ assert_equal(local['port'], self.bind_ports[i])
+ if local['address'] == ADDR2:
+ found_addr2 = True
+ assert_equal(local['port'], self.bind_ports[i])
+ if not found_addr1:
+ self.log.error(f"Address {ADDR1} not found in node{i}'s local addresses: {localaddresses}")
+ assert False
+ if not found_addr2:
+ self.log.error(f"Address {ADDR2} not found in node{i}'s local addresses: {localaddresses}")
+ assert False
self.log.info(
- "Test that if -bind= is passed then only that address is "
+ "Test that if -bind=routable_addr is passed then only that address is "
"added to localaddresses")
found_addr1 = False
- for local in self.nodes[1].getnetworkinfo()['localaddresses']:
+ i = 3
+ for local in self.nodes[i].getnetworkinfo()['localaddresses']:
if local['address'] == ADDR1:
found_addr1 = True
- assert_equal(local['port'], BIND_PORT)
+ assert_equal(local['port'], self.bind_ports[i])
assert_not_equal(local['address'], ADDR2)
assert found_addr1
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.