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.
251self.nodes[0].addnode(node=ip_port, command='add')252self.log.info("Try to add an equivalent ip and check it fails")253self.log.debug("(note that OpenBSD doesn't support the IPv4 shorthand notation with omitted zero-bytes)")254if platform.system() != "OpenBSD":255ip_port2 = "127.1:{}".format(p2p_port(2))256assert_raises_rpc_error(-23, "Node already added", self.nodes[0].addnode, node=ip_port2, command='add')257self.log.info("Check that the node has indeed been added")258added_nodes = self.nodes[0].getaddednodeinfo()259assert_equal(len(added_nodes), 1)260assert_equal(added_nodes[0]['addednode'], ip_port)261self.log.info("Check that filtering by node works")262self.nodes[0].addnode(node="11.22.33.44", command='add')263first_added_node = self.nodes[0].getaddednodeinfo(node=ip_port)264assert_equal(added_nodes, first_added_node)265assert_equal(len(self.nodes[0].getaddednodeinfo()), 2)266self.log.info("Check that node cannot be added again")267assert_raises_rpc_error(-23, "Node already added", self.nodes[0].addnode, node=ip_port, command='add')268self.log.info("Check that node can be removed")269self.nodes[0].addnode(node=ip_port, command='remove')270added_nodes = self.nodes[0].getaddednodeinfo()271assert_equal(len(added_nodes), 1)272assert_equal(added_nodes[0]['addednode'], "11.22.33.44")273self.log.info("Check that an invalid command returns an error")274assert_raises_rpc_error(-1, 'addnode "node" "command"', self.nodes[0].addnode, node=ip_port, command='abc')275self.log.info("Check that an empty node address returns an error")276for command in ['add', 'remove', 'onetry']:277assert_raises_rpc_error(-8, "Node address cannot be empty", self.nodes[0].addnode, node="", command=command)278assert_raises_rpc_error(-8, "Node address cannot be empty", self.nodes[0].addnode, node=" ", command=command)279assert_equal(len(self.nodes[0].getaddednodeinfo()), 1)280self.log.info("Check that trying to remove the node again returns an error")281assert_raises_rpc_error(-24, "Node could not be removed", self.nodes[0].addnode, node=ip_port, command='remove')282self.log.info("Check that a non-existent node returns an error")283assert_raises_rpc_error(-24, "Node has not been added", self.nodes[0].getaddednodeinfo, '1.1.1.1')285def test_service_flags(self):286self.log.info("Test service flags")287self.nodes[0].add_p2p_connection(P2PInterface(), services=(1 << 4) | (1 << 63))288if self.options.v2transport:289assert_equal(['UNKNOWN[2^4]', 'P2P_V2', 'UNKNOWN[2^63]'], self.nodes[0].getpeerinfo()[-1]['servicesnames'])290else:291assert_equal(['UNKNOWN[2^4]', 'UNKNOWN[2^63]'], self.nodes[0].getpeerinfo()[-1]['servicesnames'])292self.nodes[0].disconnect_p2ps()294def test_getnodeaddresses(self):295self.log.info("Test getnodeaddresses")296self.nodes[0].add_p2p_connection(P2PInterface())298# Add an IPv6 address to the address manager.299ipv6_addr = "1233:3432:2434:2343:3234:2345:6546:4534"300self.nodes[0].addpeeraddress(address=ipv6_addr, port=8333)302# Add 10,000 IPv4 addresses to the address manager. Due to the way bucket303# and bucket positions are calculated, some of these addresses will collide.304imported_addrs = []305for i in range(10000):306first_octet = i >> 8307second_octet = i % 256308a = f"{first_octet}.{second_octet}.1.1"309imported_addrs.append(a)310self.nodes[0].addpeeraddress(a, 8333)312# Fetch the addresses via the RPC and test the results.313assert_equal(len(self.nodes[0].getnodeaddresses()), 1) # default count is 1314assert_equal(len(self.nodes[0].getnodeaddresses(count=2)), 2)315assert_equal(len(self.nodes[0].getnodeaddresses(network="ipv4", count=8)), 8)317# Maximum possible addresses in AddrMan is 10000. The actual number will318# usually be less due to bucket and bucket position collisions.319node_addresses = self.nodes[0].getnodeaddresses(0, "ipv4")320assert_greater_than(len(node_addresses), 5000)321assert_greater_than(10000, len(node_addresses))322for a in node_addresses:323assert_greater_than(a["time"], 1527811200) # 1st June 2018324assert_equal(a["services"], P2P_SERVICES)325assert a["address"] in imported_addrs326assert_equal(a["port"], 8333)327assert_equal(a["network"], "ipv4")329# Test the IPv6 address.330res = self.nodes[0].getnodeaddresses(0, "ipv6")331assert_equal(len(res), 1)332assert_equal(res[0]["address"], ipv6_addr)333assert_equal(res[0]["network"], "ipv6")334assert_equal(res[0]["port"], 8333)335assert_equal(res[0]["services"], P2P_SERVICES)337for network in ["onion", "OnIoN", "i2p", "cjdns"]:338assert_equal(self.nodes[0].getnodeaddresses(0, network), [])340# Test invalid arguments.341assert_raises_rpc_error(-8, "Address count out of range", self.nodes[0].getnodeaddresses, -1)342for network in ["Foo", "tor"]:343assert_raises_rpc_error(-8, f"Network not recognized: {network}", self.nodes[0].getnodeaddresses, 1, network)345def test_addpeeraddress(self):346self.log.info("Test addpeeraddress")347# The node has an existing, non-deterministic addrman from a previous test.348# Clear it to have a deterministic addrman.349self.restart_node(1, ["-checkaddrman=1", "-test=addrman"], clear_addrman=True)350node = self.nodes[1]352self.log.debug("Test that addpeeraddress is a hidden RPC")353# It is hidden from general help, but its detailed help may be called directly.354assert "addpeeraddress" not in node.help()355assert "unknown command: addpeeraddress" not in node.help("addpeeraddress")357self.log.debug("Test that adding an empty address fails")358assert_raises_rpc_error(-30, "Invalid IP address", node.addpeeraddress, address="", port=8333)359assert_equal(node.getnodeaddresses(count=0), [])361self.log.debug("Test that adding a non-IP/hostname fails (no DNS lookup allowed)")362assert_raises_rpc_error(-30, "Invalid IP address", node.addpeeraddress, address="not_an_ip", port=8333)364self.log.debug("Test that non-bool tried fails")365assert_raises_rpc_error(-3, "JSON value of type string is not of expected type bool", self.nodes[0].addpeeraddress, address="1.2.3.4", tried="True", port=1234)367self.log.debug("Test that adding an address with invalid port fails")368assert_raises_rpc_error(-1, "JSON integer out of range", self.nodes[0].addpeeraddress, address="1.2.3.4", port=-1)369assert_raises_rpc_error(-1, "JSON integer out of range", self.nodes[0].addpeeraddress, address="1.2.3.4", port=65536)371self.log.debug("Test that adding a valid address to the new table succeeds")372assert_equal(node.addpeeraddress(address="1.0.0.0", tried=False, port=8333), {"success": True})373addrman = node.getrawaddrman()374assert_equal(len(addrman["tried"]), 0)375new_table = list(addrman["new"].values())376assert_equal(len(new_table), 1)377assert_equal(new_table[0]["address"], "1.0.0.0")378assert_equal(new_table[0]["port"], 8333)380self.log.debug("Test that adding an already-present new address to the new and tried tables fails")381for value in [True, False]:382assert_equal(node.addpeeraddress(address="1.0.0.0", tried=value, port=8333), {"success": False, "error": "failed-adding-to-new"})383assert_equal(len(node.getnodeaddresses(count=0)), 1)385self.log.debug("Test that adding a valid address to the tried table succeeds")386assert_equal(node.addpeeraddress(address="1.2.3.4", tried=True, port=8333), {"success": True})387addrman = node.getrawaddrman()388assert_equal(len(addrman["new"]), 1)389tried_table = list(addrman["tried"].values())390assert_equal(len(tried_table), 1)391assert_equal(tried_table[0]["address"], "1.2.3.4")392assert_equal(tried_table[0]["port"], 8333)393node.getnodeaddresses(count=0) # getnodeaddresses re-runs the addrman checks395self.log.debug("Test that adding an already-present tried address to the new and tried tables fails")396for value in [True, False]:397assert_equal(node.addpeeraddress(address="1.2.3.4", tried=value, port=8333), {"success": False, "error": "failed-adding-to-new"})398assert_equal(len(node.getnodeaddresses(count=0)), 2)400self.log.debug("Test that adding an address, which collides with the address in tried table, fails")401colliding_address = "1.2.5.45" # grinded address that produces a tried-table collision402assert_equal(node.addpeeraddress(address=colliding_address, tried=True, port=8333), {"success": False, "error": "failed-adding-to-tried"})403# When adding an address to the tried table, it's first added to the new table.404# As we fail to move it to the tried table, it remains in the new table.405addrman_info = node.getaddrmaninfo()406assert_equal(addrman_info["all_networks"]["tried"], 1)407assert_equal(addrman_info["all_networks"]["new"], 2)409self.log.debug("Test that adding an another address to the new table succeeds")410assert_equal(node.addpeeraddress(address="2.0.0.0", port=8333), {"success": True})411addrman_info = node.getaddrmaninfo()412assert_equal(addrman_info["all_networks"]["tried"], 1)413assert_equal(addrman_info["all_networks"]["new"], 3)414node.getnodeaddresses(count=0) # getnodeaddresses re-runs the addrman checks416def test_sendmsgtopeer(self):417node = self.nodes[0]419self.restart_node(0)420# we want to use a p2p v1 connection here in order to ensure421# a peer id of zero (a downgrade from v2 to v1 would lead422# to an increase of the peer id)423self.connect_nodes(0, 1, peer_advertises_v2=False)425self.log.info("Test sendmsgtopeer")426self.log.debug("Send a valid message")427msg_bytes_before = node.getpeerinfo()[0]["bytesrecv_per_msg"]["pong"]429with self.nodes[1].assert_debug_log(expected_msgs=["received: addr"]):430node.sendmsgtopeer(peer_id=0, msg_type="addr", msg="FFFFFF")431node.ping()432self.wait_until(lambda: node.getpeerinfo()[0]["bytesrecv_per_msg"]["pong"] > msg_bytes_before)434self.log.debug("Test error for sending to non-existing peer")435assert_raises_rpc_error(-1, "Error: Could not send message to peer", node.sendmsgtopeer, peer_id=100, msg_type="addr", msg="FF")437self.log.debug("Test that zero-length msg_type is allowed")438node.sendmsgtopeer(peer_id=0, msg_type="addr", msg="")440self.log.debug("Test error for msg_type that is too long")441assert_raises_rpc_error(-8, "Error: msg_type too long, max length is 12", node.sendmsgtopeer, peer_id=0, msg_type="long_msg_type", msg="FF")443self.log.debug("Test that unknown msg_type is allowed")444node.sendmsgtopeer(peer_id=0, msg_type="unknown", msg="FF")446self.log.debug("Test that empty msg is allowed")447node.sendmsgtopeer(peer_id=0, msg_type="addr", msg="FF")449self.log.debug("Test that oversized messages are allowed, but get us disconnected")450zero_byte_string = b'\x00' * 4000001451node.sendmsgtopeer(peer_id=0, msg_type="addr", msg=zero_byte_string.hex())452self.wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0, timeout=10)454def test_getaddrmaninfo(self):455self.log.info("Test getaddrmaninfo")456self.restart_node(1, extra_args=["-cjdnsreachable", "-test=addrman"], clear_addrman=True)457node = self.nodes[1]458seed_addrman(node)460expected_network_count = {461'all_networks': {'new': 4, 'tried': 4, 'total': 8},462'ipv4': {'new': 1, 'tried': 1, 'total': 2},463'ipv6': {'new': 1, 'tried': 1, 'total': 2},464'onion': {'new': 0, 'tried': 2, 'total': 2},465'i2p': {'new': 1, 'tried': 0, 'total': 1},466'cjdns': {'new': 1, 'tried': 0, 'total': 1},467}469self.log.debug("Test that count of addresses in addrman match expected values")470res = node.getaddrmaninfo()471for network, count in expected_network_count.items():472assert_equal(res[network]['new'], count['new'])473assert_equal(res[network]['tried'], count['tried'])474assert_equal(res[network]['total'], count['total'])476def test_getrawaddrman(self):477self.log.info("Test getrawaddrman")478self.restart_node(1, extra_args=["-cjdnsreachable", "-test=addrman"], clear_addrman=True)479node = self.nodes[1]480self.addr_time = int(time.time())481node.setmocktime(self.addr_time)482seed_addrman(node)484self.log.debug("Test that getrawaddrman is a hidden RPC")485# It is hidden from general help, but its detailed help may be called directly.486assert "getrawaddrman" not in node.help()487assert "unknown command: getrawaddrman" not in node.help("getrawaddrman")489def check_addr_information(result, expected):490"""Utility to compare a getrawaddrman result entry with an expected entry"""491assert_equal(result["address"], expected["address"])492assert_equal(result["port"], expected["port"])493assert_equal(result["services"], expected["services"])494assert_equal(result["network"], expected["network"])495assert_equal(result["source"], expected["source"])496assert_equal(result["source_network"], expected["source_network"])497assert_equal(result["time"], self.addr_time)499def check_getrawaddrman_entries(expected):500"""Utility to compare a getrawaddrman result with expected addrman contents"""
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.