diff --git a/examples/bootstrap/bootstrap.py b/examples/bootstrap/bootstrap.py index 93a6913a..825f3a08 100644 --- a/examples/bootstrap/bootstrap.py +++ b/examples/bootstrap/bootstrap.py @@ -2,7 +2,6 @@ import argparse import logging import secrets -import multiaddr import trio from libp2p import new_host @@ -54,18 +53,22 @@ BOOTSTRAP_PEERS = [ async def run(port: int, bootstrap_addrs: list[str]) -> None: """Run the bootstrap discovery example.""" + from libp2p.utils.address_validation import find_free_port, get_available_interfaces + + if port <= 0: + port = find_free_port() + # Generate key pair secret = secrets.token_bytes(32) key_pair = create_new_key_pair(secret) - # Create listen address - listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") + # Create listen addresses for all available interfaces + listen_addrs = get_available_interfaces(port) # Register peer discovery handler peerDiscovery.register_peer_discovered_handler(on_peer_discovery) logger.info("🚀 Starting Bootstrap Discovery Example") - logger.info(f"📍 Listening on: {listen_addr}") logger.info(f"🌐 Bootstrap peers: {len(bootstrap_addrs)}") print("\n" + "=" * 60) @@ -80,7 +83,16 @@ async def run(port: int, bootstrap_addrs: list[str]) -> None: host = new_host(key_pair=key_pair, bootstrap=bootstrap_addrs) try: - async with host.run(listen_addrs=[listen_addr]): + async with host.run(listen_addrs=listen_addrs): + # Get all available addresses with peer ID + all_addrs = host.get_addrs() + + logger.info("Listener ready, listening on:") + print("Listener ready, listening on:") + for addr in all_addrs: + logger.info(f"{addr}") + print(f"{addr}") + # Keep running and log peer discovery events await trio.sleep_forever() except KeyboardInterrupt: diff --git a/examples/chat/chat.py b/examples/chat/chat.py index c06e20a7..35f98d25 100755 --- a/examples/chat/chat.py +++ b/examples/chat/chat.py @@ -1,4 +1,5 @@ import argparse +import logging import sys import multiaddr @@ -17,6 +18,11 @@ from libp2p.peer.peerinfo import ( info_from_p2p_addr, ) +# Configure minimal logging +logging.basicConfig(level=logging.WARNING) +logging.getLogger("multiaddr").setLevel(logging.WARNING) +logging.getLogger("libp2p").setLevel(logging.WARNING) + PROTOCOL_ID = TProtocol("/chat/1.0.0") MAX_READ_LEN = 2**32 - 1 @@ -40,9 +46,14 @@ async def write_data(stream: INetStream) -> None: async def run(port: int, destination: str) -> None: - listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") + from libp2p.utils.address_validation import find_free_port, get_available_interfaces + + if port <= 0: + port = find_free_port() + + listen_addrs = get_available_interfaces(port) host = new_host() - async with host.run(listen_addrs=[listen_addr]), trio.open_nursery() as nursery: + async with host.run(listen_addrs=listen_addrs), trio.open_nursery() as nursery: # Start the peer-store cleanup task nursery.start_soon(host.get_peerstore().start_cleanup_task, 60) @@ -54,10 +65,18 @@ async def run(port: int, destination: str) -> None: host.set_stream_handler(PROTOCOL_ID, stream_handler) + # Get all available addresses with peer ID + all_addrs = host.get_addrs() + + print("Listener ready, listening on:\n") + for addr in all_addrs: + print(f"{addr}") + + # Use the first address as the default for the client command + default_addr = all_addrs[0] print( - "Run this from the same folder in another console:\n\n" - f"chat-demo " - f"-d {host.get_addrs()[0]}\n" + f"\nRun this from the same folder in another console:\n\n" + f"chat-demo -d {default_addr}\n" ) print("Waiting for incoming connection...") diff --git a/examples/echo/echo.py b/examples/echo/echo.py index 19e98377..42e3ff0c 100644 --- a/examples/echo/echo.py +++ b/examples/echo/echo.py @@ -1,4 +1,5 @@ import argparse +import logging import random import secrets @@ -28,6 +29,11 @@ from libp2p.utils.address_validation import ( get_available_interfaces, ) +# Configure minimal logging +logging.basicConfig(level=logging.WARNING) +logging.getLogger("multiaddr").setLevel(logging.WARNING) +logging.getLogger("libp2p").setLevel(logging.WARNING) + PROTOCOL_ID = TProtocol("/echo/1.0.0") MAX_READ_LEN = 2**32 - 1 diff --git a/examples/echo/echo_quic.py b/examples/echo/echo_quic.py index 248aed9f..667a50dc 100644 --- a/examples/echo/echo_quic.py +++ b/examples/echo/echo_quic.py @@ -20,6 +20,11 @@ from libp2p.custom_types import TProtocol from libp2p.network.stream.net_stream import INetStream from libp2p.peer.peerinfo import info_from_p2p_addr +# Configure minimal logging +logging.basicConfig(level=logging.WARNING) +logging.getLogger("multiaddr").setLevel(logging.WARNING) +logging.getLogger("libp2p").setLevel(logging.WARNING) + PROTOCOL_ID = TProtocol("/echo/1.0.0") @@ -38,6 +43,12 @@ async def _echo_stream_handler(stream: INetStream) -> None: async def run_server(port: int, seed: int | None = None) -> None: """Run echo server with QUIC transport.""" + from libp2p.utils.address_validation import find_free_port + + if port <= 0: + port = find_free_port() + + # For QUIC, we need to use UDP addresses listen_addr = Multiaddr(f"/ip4/0.0.0.0/udp/{port}/quic") if seed: @@ -63,10 +74,18 @@ async def run_server(port: int, seed: int | None = None) -> None: print(f"I am {host.get_id().to_string()}") host.set_stream_handler(PROTOCOL_ID, _echo_stream_handler) + # Get all available addresses with peer ID + all_addrs = host.get_addrs() + + print("Listener ready, listening on:") + for addr in all_addrs: + print(f"{addr}") + + # Use the first address as the default for the client command + default_addr = all_addrs[0] print( - "Run this from the same folder in another console:\n\n" - f"python3 ./examples/echo/echo_quic.py " - f"-d {host.get_addrs()[0]}\n" + f"\nRun this from the same folder in another console:\n\n" + f"python3 ./examples/echo/echo_quic.py -d {default_addr}\n" ) print("Waiting for incoming QUIC connections...") await trio.sleep_forever() @@ -173,6 +192,4 @@ def main() -> None: if __name__ == "__main__": - logging.basicConfig(level=logging.DEBUG) - logging.getLogger("aioquic").setLevel(logging.DEBUG) main() diff --git a/examples/identify/identify.py b/examples/identify/identify.py index 445962c3..bd973a3e 100644 --- a/examples/identify/identify.py +++ b/examples/identify/identify.py @@ -20,6 +20,11 @@ from libp2p.peer.peerinfo import ( info_from_p2p_addr, ) +# Configure minimal logging +logging.basicConfig(level=logging.WARNING) +logging.getLogger("multiaddr").setLevel(logging.WARNING) +logging.getLogger("libp2p").setLevel(logging.WARNING) + logger = logging.getLogger("libp2p.identity.identify-example") @@ -58,11 +63,16 @@ def print_identify_response(identify_response: Identify): async def run(port: int, destination: str, use_varint_format: bool = True) -> None: - localhost_ip = "127.0.0.1" + from libp2p.utils.address_validation import get_available_interfaces if not destination: # Create first host (listener) - listen_addr = multiaddr.Multiaddr(f"/ip4/{localhost_ip}/tcp/{port}") + if port <= 0: + from libp2p.utils.address_validation import find_free_port + + port = find_free_port() + + listen_addrs = get_available_interfaces(port) host_a = new_host() # Set up identify handler with specified format @@ -73,22 +83,28 @@ async def run(port: int, destination: str, use_varint_format: bool = True) -> No host_a.set_stream_handler(IDENTIFY_PROTOCOL_ID, identify_handler) async with ( - host_a.run(listen_addrs=[listen_addr]), + host_a.run(listen_addrs=listen_addrs), trio.open_nursery() as nursery, ): # Start the peer-store cleanup task nursery.start_soon(host_a.get_peerstore().start_cleanup_task, 60) - # Get the actual address - server_addr = str(host_a.get_addrs()[0]) - client_addr = server_addr + # Get all available addresses with peer ID + all_addrs = host_a.get_addrs() format_name = "length-prefixed" if use_varint_format else "raw protobuf" format_flag = "--raw-format" if not use_varint_format else "" + + print(f"First host listening (using {format_name} format).") + print("Listener ready, listening on:\n") + for addr in all_addrs: + print(f"{addr}") + + # Use the first address as the default for the client command + default_addr = all_addrs[0] print( - f"First host listening (using {format_name} format). " - f"Run this from another console:\n\n" - f"identify-demo {format_flag} -d {client_addr}\n" + f"\nRun this from the same folder in another console:\n\n" + f"identify-demo {format_flag} -d {default_addr}\n" ) print("Waiting for incoming identify request...") @@ -133,11 +149,19 @@ async def run(port: int, destination: str, use_varint_format: bool = True) -> No else: # Create second host (dialer) - listen_addr = multiaddr.Multiaddr(f"/ip4/{localhost_ip}/tcp/{port}") + from libp2p.utils.address_validation import ( + find_free_port, + get_available_interfaces, + ) + + if port <= 0: + port = find_free_port() + + listen_addrs = get_available_interfaces(port) host_b = new_host() async with ( - host_b.run(listen_addrs=[listen_addr]), + host_b.run(listen_addrs=listen_addrs), trio.open_nursery() as nursery, ): # Start the peer-store cleanup task diff --git a/examples/identify_push/identify_push_listener_dialer.py b/examples/identify_push/identify_push_listener_dialer.py index a9974b82..3701aaf5 100644 --- a/examples/identify_push/identify_push_listener_dialer.py +++ b/examples/identify_push/identify_push_listener_dialer.py @@ -56,6 +56,11 @@ from libp2p.peer.peerinfo import ( info_from_p2p_addr, ) +# Configure minimal logging +logging.basicConfig(level=logging.WARNING) +logging.getLogger("multiaddr").setLevel(logging.WARNING) +logging.getLogger("libp2p").setLevel(logging.WARNING) + # Configure logging logger = logging.getLogger("libp2p.identity.identify-push-example") @@ -194,6 +199,11 @@ async def run_listener( port: int, use_varint_format: bool = True, raw_format_flag: bool = False ) -> None: """Run a host in listener mode.""" + from libp2p.utils.address_validation import find_free_port, get_available_interfaces + + if port <= 0: + port = find_free_port() + format_name = "length-prefixed" if use_varint_format else "raw protobuf" print( f"\n==== Starting Identify-Push Listener on port {port} " @@ -215,26 +225,33 @@ async def run_listener( custom_identify_push_handler_for(host, use_varint_format=use_varint_format), ) - # Start listening - listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") + # Start listening on all available interfaces + listen_addrs = get_available_interfaces(port) try: - async with host.run([listen_addr]): - addr = host.get_addrs()[0] + async with host.run(listen_addrs): + all_addrs = host.get_addrs() logger.info("Listener host ready!") print("Listener host ready!") - logger.info(f"Listening on: {addr}") - print(f"Listening on: {addr}") + logger.info("Listener ready, listening on:") + print("Listener ready, listening on:") + for addr in all_addrs: + logger.info(f"{addr}") + print(f"{addr}") logger.info(f"Peer ID: {host.get_id().pretty()}") print(f"Peer ID: {host.get_id().pretty()}") - print("\nRun dialer with command:") + # Use the first address as the default for the dialer command + default_addr = all_addrs[0] + print("\nRun this from the same folder in another console:") if raw_format_flag: - print(f"identify-push-listener-dialer-demo -d {addr} --raw-format") + print( + f"identify-push-listener-dialer-demo -d {default_addr} --raw-format" + ) else: - print(f"identify-push-listener-dialer-demo -d {addr}") + print(f"identify-push-listener-dialer-demo -d {default_addr}") print("\nWaiting for incoming identify/push requests... (Ctrl+C to exit)") # Keep running until interrupted diff --git a/examples/kademlia/kademlia.py b/examples/kademlia/kademlia.py index faaa66be..80bbc995 100644 --- a/examples/kademlia/kademlia.py +++ b/examples/kademlia/kademlia.py @@ -150,26 +150,39 @@ async def run_node( key_pair = create_new_key_pair(secrets.token_bytes(32)) host = new_host(key_pair=key_pair) - listen_addr = Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") - async with host.run(listen_addrs=[listen_addr]), trio.open_nursery() as nursery: + from libp2p.utils.address_validation import get_available_interfaces + + listen_addrs = get_available_interfaces(port) + + async with host.run(listen_addrs=listen_addrs), trio.open_nursery() as nursery: # Start the peer-store cleanup task nursery.start_soon(host.get_peerstore().start_cleanup_task, 60) peer_id = host.get_id().pretty() - addr_str = f"/ip4/127.0.0.1/tcp/{port}/p2p/{peer_id}" + + # Get all available addresses with peer ID + all_addrs = host.get_addrs() + + logger.info("Listener ready, listening on:") + for addr in all_addrs: + logger.info(f"{addr}") + + # Use the first address as the default for the bootstrap command + default_addr = all_addrs[0] + bootstrap_cmd = f"--bootstrap {default_addr}" + logger.info("To connect to this node, use: %s", bootstrap_cmd) + await connect_to_bootstrap_nodes(host, bootstrap_nodes) dht = KadDHT(host, dht_mode) # take all peer ids from the host and add them to the dht for peer_id in host.get_peerstore().peer_ids(): await dht.routing_table.add_peer(peer_id) logger.info(f"Connected to bootstrap nodes: {host.get_connected_peers()}") - bootstrap_cmd = f"--bootstrap {addr_str}" - logger.info("To connect to this node, use: %s", bootstrap_cmd) # Save server address in server mode if dht_mode == DHTMode.SERVER: - save_server_addr(addr_str) + save_server_addr(str(default_addr)) # Start the DHT service async with background_trio_service(dht): diff --git a/examples/mDNS/mDNS.py b/examples/mDNS/mDNS.py index 499ca224..9f0cf74b 100644 --- a/examples/mDNS/mDNS.py +++ b/examples/mDNS/mDNS.py @@ -2,7 +2,6 @@ import argparse import logging import secrets -import multiaddr import trio from libp2p import ( @@ -14,6 +13,11 @@ from libp2p.crypto.secp256k1 import ( ) from libp2p.discovery.events.peerDiscovery import peerDiscovery +# Configure minimal logging +logging.basicConfig(level=logging.WARNING) +logging.getLogger("multiaddr").setLevel(logging.WARNING) +logging.getLogger("libp2p").setLevel(logging.WARNING) + logger = logging.getLogger("libp2p.discovery.mdns") logger.setLevel(logging.INFO) handler = logging.StreamHandler() @@ -22,34 +26,43 @@ handler.setFormatter( ) logger.addHandler(handler) -# Set root logger to DEBUG to capture all logs from dependencies -logging.getLogger().setLevel(logging.DEBUG) - def onPeerDiscovery(peerinfo: PeerInfo): logger.info(f"Discovered: {peerinfo.peer_id}") async def run(port: int) -> None: + from libp2p.utils.address_validation import find_free_port, get_available_interfaces + + if port <= 0: + port = find_free_port() + secret = secrets.token_bytes(32) key_pair = create_new_key_pair(secret) - listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") + listen_addrs = get_available_interfaces(port) peerDiscovery.register_peer_discovered_handler(onPeerDiscovery) - print( - "Run this from the same folder in another console to " - "start another peer on a different port:\n\n" - "mdns-demo -p \n" - ) - print("Waiting for mDNS peer discovery events...\n") - logger.info("Starting peer Discovery") host = new_host(key_pair=key_pair, enable_mDNS=True) - async with host.run(listen_addrs=[listen_addr]), trio.open_nursery() as nursery: + async with host.run(listen_addrs=listen_addrs), trio.open_nursery() as nursery: # Start the peer-store cleanup task nursery.start_soon(host.get_peerstore().start_cleanup_task, 60) + # Get all available addresses with peer ID + all_addrs = host.get_addrs() + + print("Listener ready, listening on:") + for addr in all_addrs: + print(f"{addr}") + + print( + "\nRun this from the same folder in another console to " + "start another peer on a different port:\n\n" + "mdns-demo -p \n" + ) + print("Waiting for mDNS peer discovery events...\n") + await trio.sleep_forever() diff --git a/examples/ping/ping.py b/examples/ping/ping.py index bb47bd95..52bb759a 100644 --- a/examples/ping/ping.py +++ b/examples/ping/ping.py @@ -1,4 +1,5 @@ import argparse +import logging import multiaddr import trio @@ -16,6 +17,11 @@ from libp2p.peer.peerinfo import ( info_from_p2p_addr, ) +# Configure minimal logging +logging.basicConfig(level=logging.WARNING) +logging.getLogger("multiaddr").setLevel(logging.WARNING) +logging.getLogger("libp2p").setLevel(logging.WARNING) + PING_PROTOCOL_ID = TProtocol("/ipfs/ping/1.0.0") PING_LENGTH = 32 RESP_TIMEOUT = 60 @@ -55,20 +61,33 @@ async def send_ping(stream: INetStream) -> None: async def run(port: int, destination: str) -> None: - listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") - host = new_host(listen_addrs=[listen_addr]) + from libp2p.utils.address_validation import find_free_port, get_available_interfaces - async with host.run(listen_addrs=[listen_addr]), trio.open_nursery() as nursery: + if port <= 0: + port = find_free_port() + + listen_addrs = get_available_interfaces(port) + host = new_host(listen_addrs=listen_addrs) + + async with host.run(listen_addrs=listen_addrs), trio.open_nursery() as nursery: # Start the peer-store cleanup task nursery.start_soon(host.get_peerstore().start_cleanup_task, 60) if not destination: host.set_stream_handler(PING_PROTOCOL_ID, handle_ping) + # Get all available addresses with peer ID + all_addrs = host.get_addrs() + + print("Listener ready, listening on:\n") + for addr in all_addrs: + print(f"{addr}") + + # Use the first address as the default for the client command + default_addr = all_addrs[0] print( - "Run this from the same folder in another console:\n\n" - f"ping-demo " - f"-d {host.get_addrs()[0]}\n" + f"\nRun this from the same folder in another console:\n\n" + f"ping-demo -d {default_addr}\n" ) print("Waiting for incoming connection...") diff --git a/examples/pubsub/pubsub.py b/examples/pubsub/pubsub.py index 843a2829..6e8495c1 100644 --- a/examples/pubsub/pubsub.py +++ b/examples/pubsub/pubsub.py @@ -102,14 +102,13 @@ async def monitor_peer_topics(pubsub, nursery, termination_event): async def run(topic: str, destination: str | None, port: int | None) -> None: - # Initialize network settings - localhost_ip = "127.0.0.1" + from libp2p.utils.address_validation import get_available_interfaces if port is None or port == 0: port = find_free_port() logger.info(f"Using random available port: {port}") - listen_addr = multiaddr.Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") + listen_addrs = get_available_interfaces(port) # Create a new libp2p host host = new_host( @@ -138,12 +137,11 @@ async def run(topic: str, destination: str | None, port: int | None) -> None: pubsub = Pubsub(host, gossipsub) termination_event = trio.Event() # Event to signal termination - async with host.run(listen_addrs=[listen_addr]), trio.open_nursery() as nursery: + async with host.run(listen_addrs=listen_addrs), trio.open_nursery() as nursery: # Start the peer-store cleanup task nursery.start_soon(host.get_peerstore().start_cleanup_task, 60) logger.info(f"Node started with peer ID: {host.get_id()}") - logger.info(f"Listening on: {listen_addr}") logger.info("Initializing PubSub and GossipSub...") async with background_trio_service(pubsub): async with background_trio_service(gossipsub): @@ -157,10 +155,18 @@ async def run(topic: str, destination: str | None, port: int | None) -> None: if not destination: # Server mode + # Get all available addresses with peer ID + all_addrs = host.get_addrs() + + logger.info("Listener ready, listening on:") + for addr in all_addrs: + logger.info(f"{addr}") + + # Use the first address as the default for the client command + default_addr = all_addrs[0] logger.info( - "Run this script in another console with:\n" - f"pubsub-demo " - f"-d /ip4/{localhost_ip}/tcp/{port}/p2p/{host.get_id()}\n" + f"\nRun this from the same folder in another console:\n\n" + f"pubsub-demo -d {default_addr}\n" ) logger.info("Waiting for peers...") @@ -182,11 +188,6 @@ async def run(topic: str, destination: str | None, port: int | None) -> None: f"Connecting to peer: {info.peer_id} " f"using protocols: {protocols_in_maddr}" ) - logger.info( - "Run this script in another console with:\n" - f"pubsub-demo " - f"-d /ip4/{localhost_ip}/tcp/{port}/p2p/{host.get_id()}\n" - ) try: await host.connect(info) logger.info(f"Connected to peer: {info.peer_id}") diff --git a/examples/random_walk/random_walk.py b/examples/random_walk/random_walk.py index b90d6304..d2278b16 100644 --- a/examples/random_walk/random_walk.py +++ b/examples/random_walk/random_walk.py @@ -16,7 +16,6 @@ import random import secrets import sys -from multiaddr import Multiaddr import trio from libp2p import new_host @@ -130,16 +129,24 @@ async def run_node(port: int, mode: str, demo_interval: int = 30) -> None: # Create host and DHT key_pair = create_new_key_pair(secrets.token_bytes(32)) host = new_host(key_pair=key_pair, bootstrap=DEFAULT_BOOTSTRAP_NODES) - listen_addr = Multiaddr(f"/ip4/127.0.0.1/tcp/{port}") - async with host.run(listen_addrs=[listen_addr]), trio.open_nursery() as nursery: + from libp2p.utils.address_validation import get_available_interfaces + + listen_addrs = get_available_interfaces(port) + + async with host.run(listen_addrs=listen_addrs), trio.open_nursery() as nursery: # Start maintenance tasks nursery.start_soon(host.get_peerstore().start_cleanup_task, 60) nursery.start_soon(maintain_connections, host) peer_id = host.get_id().pretty() logger.info(f"Node peer ID: {peer_id}") - logger.info(f"Node address: /ip4/127.0.0.1/tcp/{port}/p2p/{peer_id}") + + # Get all available addresses with peer ID + all_addrs = host.get_addrs() + logger.info("Listener ready, listening on:") + for addr in all_addrs: + logger.info(f"{addr}") # Create and start DHT with Random Walk enabled dht = KadDHT(host, dht_mode, enable_random_walk=True) diff --git a/libp2p/utils/address_validation.py b/libp2p/utils/address_validation.py index 10677241..a470ad24 100644 --- a/libp2p/utils/address_validation.py +++ b/libp2p/utils/address_validation.py @@ -73,8 +73,9 @@ def get_available_interfaces(port: int, protocol: str = "tcp") -> list[Multiaddr seen_v4: set[str] = set() for ip in _safe_get_network_addrs(4): - seen_v4.add(ip) - addrs.append(Multiaddr(f"/ip4/{ip}/{protocol}/{port}")) + if ip not in seen_v4: # Avoid duplicates + seen_v4.add(ip) + addrs.append(Multiaddr(f"/ip4/{ip}/{protocol}/{port}")) # Ensure IPv4 loopback is always included when IPv4 interfaces are discovered if seen_v4 and "127.0.0.1" not in seen_v4: @@ -89,8 +90,9 @@ def get_available_interfaces(port: int, protocol: str = "tcp") -> list[Multiaddr # # seen_v6: set[str] = set() # for ip in _safe_get_network_addrs(6): - # seen_v6.add(ip) - # addrs.append(Multiaddr(f"/ip6/{ip}/{protocol}/{port}")) + # if ip not in seen_v6: # Avoid duplicates + # seen_v6.add(ip) + # addrs.append(Multiaddr(f"/ip6/{ip}/{protocol}/{port}")) # # # Always include IPv6 loopback for testing purposes when IPv6 is available # # This ensures IPv6 functionality can be tested even without global IPv6 addresses