Skip to content

Commit 1cd4b3f

Browse files
authored
Merge branch 'main' into feat/add-webrtc-transport
2 parents 13378e6 + b01596a commit 1cd4b3f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+4216
-111
lines changed

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ PB = libp2p/crypto/pb/crypto.proto \
6060
libp2p/identity/identify/pb/identify.proto \
6161
libp2p/host/autonat/pb/autonat.proto \
6262
libp2p/relay/circuit_v2/pb/circuit.proto \
63+
libp2p/relay/circuit_v2/pb/dcutr.proto \
6364
libp2p/kad_dht/pb/kademlia.proto
6465

6566
PY = $(PB:.proto=_pb2.py)
@@ -68,6 +69,8 @@ PYI = $(PB:.proto=_pb2.pyi)
6869
## Set default to `protobufs`, otherwise `format` is called when typing only `make`
6970
all: protobufs
7071

72+
.PHONY: protobufs clean-proto
73+
7174
protobufs: $(PY)
7275

7376
%_pb2.py: %.proto
@@ -76,6 +79,11 @@ protobufs: $(PY)
7679
clean-proto:
7780
rm -f $(PY) $(PYI)
7881

82+
# Force protobuf regeneration by making them always out of date
83+
$(PY): FORCE
84+
85+
FORCE:
86+
7987
# docs commands
8088

8189
docs: check-docs

README.md

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,47 +34,47 @@ ______________________________________________________________________
3434
| -------------------------------------- | :--------: | :---------------------------------------------------------------------------------: |
3535
| **`libp2p-tcp`** || [source](https://github.com/libp2p/py-libp2p/blob/main/libp2p/transport/tcp/tcp.py) |
3636
| **`libp2p-quic`** | 🌱 | |
37-
| **`libp2p-websocket`** | | |
38-
| **`libp2p-webrtc-browser-to-server`** | | |
39-
| **`libp2p-webrtc-private-to-private`** | | |
37+
| **`libp2p-websocket`** | 🌱 | |
38+
| **`libp2p-webrtc-browser-to-server`** | 🌱 | |
39+
| **`libp2p-webrtc-private-to-private`** | 🌱 | |
4040

4141
______________________________________________________________________
4242

4343
### NAT Traversal
4444

45-
| **NAT Traversal** | **Status** |
46-
| ----------------------------- | :--------: |
47-
| **`libp2p-circuit-relay-v2`** | |
48-
| **`libp2p-autonat`** | |
49-
| **`libp2p-hole-punching`** | |
45+
| **NAT Traversal** | **Status** | **Source** |
46+
| ----------------------------- | :--------: | :-----------------------------------------------------------------------------: |
47+
| **`libp2p-circuit-relay-v2`** | | [source](https://github.com/libp2p/py-libp2p/tree/main/libp2p/relay/circuit_v2) |
48+
| **`libp2p-autonat`** | | [source](https://github.com/libp2p/py-libp2p/tree/main/libp2p/host/autonat) |
49+
| **`libp2p-hole-punching`** | | [source](https://github.com/libp2p/py-libp2p/tree/main/libp2p/relay/circuit_v2) |
5050

5151
______________________________________________________________________
5252

5353
### Secure Communication
5454

5555
| **Secure Communication** | **Status** | **Source** |
5656
| ------------------------ | :--------: | :---------------------------------------------------------------------------: |
57-
| **`libp2p-noise`** | 🌱 | [source](https://github.com/libp2p/py-libp2p/tree/main/libp2p/security/noise) |
58-
| **`libp2p-tls`** | | |
57+
| **`libp2p-noise`** | | [source](https://github.com/libp2p/py-libp2p/tree/main/libp2p/security/noise) |
58+
| **`libp2p-tls`** | 🌱 | |
5959

6060
______________________________________________________________________
6161

6262
### Discovery
6363

64-
| **Discovery** | **Status** |
65-
| -------------------- | :--------: |
66-
| **`bootstrap`** | |
67-
| **`random-walk`** | |
68-
| **`mdns-discovery`** | |
69-
| **`rendezvous`** | |
64+
| **Discovery** | **Status** | **Source** |
65+
| -------------------- | :--------: | :--------------------------------------------------------------------------------: |
66+
| **`bootstrap`** | | [source](https://github.com/libp2p/py-libp2p/tree/main/libp2p/discovery/bootstrap) |
67+
| **`random-walk`** | 🌱 | |
68+
| **`mdns-discovery`** | | [source](https://github.com/libp2p/py-libp2p/tree/main/libp2p/discovery/mdns) |
69+
| **`rendezvous`** | 🌱 | |
7070

7171
______________________________________________________________________
7272

7373
### Peer Routing
7474

75-
| **Peer Routing** | **Status** |
76-
| -------------------- | :--------: |
77-
| **`libp2p-kad-dht`** | |
75+
| **Peer Routing** | **Status** | **Source** |
76+
| -------------------- | :--------: | :--------------------------------------------------------------------: |
77+
| **`libp2p-kad-dht`** | | [source](https://github.com/libp2p/py-libp2p/tree/main/libp2p/kad_dht) |
7878

7979
______________________________________________________________________
8080

@@ -89,18 +89,18 @@ ______________________________________________________________________
8989

9090
### Stream Muxers
9191

92-
| **Stream Muxers** | **Status** | **Status** |
93-
| ------------------ | :--------: | :----------------------------------------------------------------------------------------: |
94-
| **`libp2p-yamux`** | 🌱 | |
95-
| **`libp2p-mplex`** | 🛠️ | [source](https://github.com/libp2p/py-libp2p/blob/main/libp2p/stream_muxer/mplex/mplex.py) |
92+
| **Stream Muxers** | **Status** | **Source** |
93+
| ------------------ | :--------: | :-------------------------------------------------------------------------------: |
94+
| **`libp2p-yamux`** | | [source](https://github.com/libp2p/py-libp2p/tree/main/libp2p/stream_muxer/yamux) |
95+
| **`libp2p-mplex`** | | [source](https://github.com/libp2p/py-libp2p/tree/main/libp2p/stream_muxer/mplex) |
9696

9797
______________________________________________________________________
9898

9999
### Storage
100100

101101
| **Storage** | **Status** |
102102
| ------------------- | :--------: |
103-
| **`libp2p-record`** | |
103+
| **`libp2p-record`** | 🌱 |
104104

105105
______________________________________________________________________
106106

docs/libp2p.discovery.bootstrap.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
libp2p.discovery.bootstrap package
2+
==================================
3+
4+
Submodules
5+
----------
6+
7+
Module contents
8+
---------------
9+
10+
.. automodule:: libp2p.discovery.bootstrap
11+
:members:
12+
:undoc-members:
13+
:show-inheritance:

docs/libp2p.discovery.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Subpackages
77
.. toctree::
88
:maxdepth: 4
99

10+
libp2p.discovery.bootstrap
1011
libp2p.discovery.events
1112
libp2p.discovery.mdns
1213

examples/bootstrap/bootstrap.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import argparse
2+
import logging
3+
import secrets
4+
5+
import multiaddr
6+
import trio
7+
8+
from libp2p import new_host
9+
from libp2p.abc import PeerInfo
10+
from libp2p.crypto.secp256k1 import create_new_key_pair
11+
from libp2p.discovery.events.peerDiscovery import peerDiscovery
12+
13+
# Configure logging
14+
logger = logging.getLogger("libp2p.discovery.bootstrap")
15+
logger.setLevel(logging.INFO)
16+
handler = logging.StreamHandler()
17+
handler.setFormatter(
18+
logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
19+
)
20+
logger.addHandler(handler)
21+
22+
# Configure root logger to only show warnings and above to reduce noise
23+
# This prevents verbose DEBUG messages from multiaddr, DNS, etc.
24+
logging.getLogger().setLevel(logging.WARNING)
25+
26+
# Specifically silence noisy libraries
27+
logging.getLogger("multiaddr").setLevel(logging.WARNING)
28+
logging.getLogger("root").setLevel(logging.WARNING)
29+
30+
31+
def on_peer_discovery(peer_info: PeerInfo) -> None:
32+
"""Handler for peer discovery events."""
33+
logger.info(f"🔍 Discovered peer: {peer_info.peer_id}")
34+
logger.debug(f" Addresses: {[str(addr) for addr in peer_info.addrs]}")
35+
36+
37+
# Example bootstrap peers
38+
BOOTSTRAP_PEERS = [
39+
"/dnsaddr/github.com/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
40+
"/dnsaddr/cloudflare.com/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
41+
"/dnsaddr/google.com/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
42+
"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
43+
"/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
44+
"/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
45+
"/ip6/2604:a880:1:20::203:d001/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM",
46+
"/ip4/128.199.219.111/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64",
47+
"/ip4/104.236.76.40/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64",
48+
"/ip4/178.62.158.247/tcp/4001/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd",
49+
"/ip6/2604:a880:1:20::203:d001/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM",
50+
"/ip6/2400:6180:0:d0::151:6001/tcp/4001/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu",
51+
"/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/p2p/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm",
52+
]
53+
54+
55+
async def run(port: int, bootstrap_addrs: list[str]) -> None:
56+
"""Run the bootstrap discovery example."""
57+
# Generate key pair
58+
secret = secrets.token_bytes(32)
59+
key_pair = create_new_key_pair(secret)
60+
61+
# Create listen address
62+
listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}")
63+
64+
# Register peer discovery handler
65+
peerDiscovery.register_peer_discovered_handler(on_peer_discovery)
66+
67+
logger.info("🚀 Starting Bootstrap Discovery Example")
68+
logger.info(f"📍 Listening on: {listen_addr}")
69+
logger.info(f"🌐 Bootstrap peers: {len(bootstrap_addrs)}")
70+
71+
print("\n" + "=" * 60)
72+
print("Bootstrap Discovery Example")
73+
print("=" * 60)
74+
print("This example demonstrates connecting to bootstrap peers.")
75+
print("Watch the logs for peer discovery events!")
76+
print("Press Ctrl+C to exit.")
77+
print("=" * 60)
78+
79+
# Create and run host with bootstrap discovery
80+
host = new_host(key_pair=key_pair, bootstrap=bootstrap_addrs)
81+
82+
try:
83+
async with host.run(listen_addrs=[listen_addr]):
84+
# Keep running and log peer discovery events
85+
await trio.sleep_forever()
86+
except KeyboardInterrupt:
87+
logger.info("👋 Shutting down...")
88+
89+
90+
def main() -> None:
91+
"""Main entry point."""
92+
description = """
93+
Bootstrap Discovery Example for py-libp2p
94+
95+
This example demonstrates how to use bootstrap peers for peer discovery.
96+
Bootstrap peers are predefined peers that help new nodes join the network.
97+
98+
Usage:
99+
python bootstrap.py -p 8000
100+
python bootstrap.py -p 8001 --custom-bootstrap \\
101+
"/ip4/127.0.0.1/tcp/8000/p2p/QmYourPeerID"
102+
"""
103+
104+
parser = argparse.ArgumentParser(
105+
description=description, formatter_class=argparse.RawDescriptionHelpFormatter
106+
)
107+
parser.add_argument(
108+
"-p", "--port", default=0, type=int, help="Port to listen on (default: random)"
109+
)
110+
parser.add_argument(
111+
"--custom-bootstrap",
112+
nargs="*",
113+
help="Custom bootstrap addresses (space-separated)",
114+
)
115+
parser.add_argument(
116+
"-v", "--verbose", action="store_true", help="Enable verbose output"
117+
)
118+
119+
args = parser.parse_args()
120+
121+
if args.verbose:
122+
logger.setLevel(logging.DEBUG)
123+
124+
# Use custom bootstrap addresses if provided, otherwise use defaults
125+
bootstrap_addrs = (
126+
args.custom_bootstrap if args.custom_bootstrap else BOOTSTRAP_PEERS
127+
)
128+
129+
try:
130+
trio.run(run, args.port, bootstrap_addrs)
131+
except KeyboardInterrupt:
132+
logger.info("Exiting...")
133+
134+
135+
if __name__ == "__main__":
136+
main()

examples/chat/chat.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ async def run(port: int, destination: str) -> None:
4343
listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}")
4444
host = new_host()
4545
async with host.run(listen_addrs=[listen_addr]), trio.open_nursery() as nursery:
46+
# Start the peer-store cleanup task
47+
nursery.start_soon(host.get_peerstore().start_cleanup_task, 60)
48+
4649
if not destination: # its the server
4750

4851
async def stream_handler(stream: INetStream) -> None:

examples/echo/echo.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ async def run(port: int, destination: str, seed: int | None = None) -> None:
4545
secret = secrets.token_bytes(32)
4646

4747
host = new_host(key_pair=create_new_key_pair(secret))
48-
async with host.run(listen_addrs=[listen_addr]):
48+
async with host.run(listen_addrs=[listen_addr]), trio.open_nursery() as nursery:
49+
# Start the peer-store cleanup task
50+
nursery.start_soon(host.get_peerstore().start_cleanup_task, 60)
51+
4952
print(f"I am {host.get_id().to_string()}")
5053

5154
if not destination: # its the server

examples/identify/identify.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
identify_handler_for,
1515
parse_identify_response,
1616
)
17+
from libp2p.identity.identify.pb.identify_pb2 import Identify
18+
from libp2p.peer.envelope import debug_dump_envelope, unmarshal_envelope
1719
from libp2p.peer.peerinfo import (
1820
info_from_p2p_addr,
1921
)
@@ -32,10 +34,11 @@ def decode_multiaddrs(raw_addrs):
3234
return decoded_addrs
3335

3436

35-
def print_identify_response(identify_response):
37+
def print_identify_response(identify_response: Identify):
3638
"""Pretty-print Identify response."""
3739
public_key_b64 = base64.b64encode(identify_response.public_key).decode("utf-8")
3840
listen_addrs = decode_multiaddrs(identify_response.listen_addrs)
41+
signed_peer_record = unmarshal_envelope(identify_response.signedPeerRecord)
3942
try:
4043
observed_addr_decoded = decode_multiaddrs([identify_response.observed_addr])
4144
except Exception:
@@ -51,6 +54,8 @@ def print_identify_response(identify_response):
5154
f" Agent Version: {identify_response.agent_version}"
5255
)
5356

57+
debug_dump_envelope(signed_peer_record)
58+
5459

5560
async def run(port: int, destination: str, use_varint_format: bool = True) -> None:
5661
localhost_ip = "0.0.0.0"
@@ -61,12 +66,19 @@ async def run(port: int, destination: str, use_varint_format: bool = True) -> No
6166
host_a = new_host()
6267

6368
# Set up identify handler with specified format
69+
# Set use_varint_format = False, if want to checkout the Signed-PeerRecord
6470
identify_handler = identify_handler_for(
6571
host_a, use_varint_format=use_varint_format
6672
)
6773
host_a.set_stream_handler(IDENTIFY_PROTOCOL_ID, identify_handler)
6874

69-
async with host_a.run(listen_addrs=[listen_addr]):
75+
async with (
76+
host_a.run(listen_addrs=[listen_addr]),
77+
trio.open_nursery() as nursery,
78+
):
79+
# Start the peer-store cleanup task
80+
nursery.start_soon(host_a.get_peerstore().start_cleanup_task, 60)
81+
7082
# Get the actual address and replace 0.0.0.0 with 127.0.0.1 for client
7183
# connections
7284
server_addr = str(host_a.get_addrs()[0])
@@ -125,7 +137,13 @@ async def custom_identify_handler(stream):
125137
listen_addr = multiaddr.Multiaddr(f"/ip4/{localhost_ip}/tcp/{port}")
126138
host_b = new_host()
127139

128-
async with host_b.run(listen_addrs=[listen_addr]):
140+
async with (
141+
host_b.run(listen_addrs=[listen_addr]),
142+
trio.open_nursery() as nursery,
143+
):
144+
# Start the peer-store cleanup task
145+
nursery.start_soon(host_b.get_peerstore().start_cleanup_task, 60)
146+
129147
# Connect to the first host
130148
print(f"dialer (host_b) listening on {host_b.get_addrs()[0]}")
131149
maddr = multiaddr.Multiaddr(destination)
@@ -238,9 +256,9 @@ def main() -> None:
238256

239257
args = parser.parse_args()
240258

241-
# Determine format: raw format if --raw-format is specified, otherwise
242-
# length-prefixed
243-
use_varint_format = not args.raw_format
259+
# Determine format: use varint (length-prefixed) if --raw-format is specified,
260+
# otherwise use raw protobuf format (old format)
261+
use_varint_format = args.raw_format
244262

245263
try:
246264
if args.destination:

examples/identify_push/identify_push_demo.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,15 @@ async def main() -> None:
211211
listen_addr_1 = multiaddr.Multiaddr("/ip4/127.0.0.1/tcp/0")
212212
listen_addr_2 = multiaddr.Multiaddr("/ip4/127.0.0.1/tcp/0")
213213

214-
async with host_1.run([listen_addr_1]), host_2.run([listen_addr_2]):
214+
async with (
215+
host_1.run([listen_addr_1]),
216+
host_2.run([listen_addr_2]),
217+
trio.open_nursery() as nursery,
218+
):
219+
# Start the peer-store cleanup task
220+
nursery.start_soon(host_1.get_peerstore().start_cleanup_task, 60)
221+
nursery.start_soon(host_2.get_peerstore().start_cleanup_task, 60)
222+
215223
# Get the addresses of both hosts
216224
addr_1 = host_1.get_addrs()[0]
217225
addr_2 = host_2.get_addrs()[0]

0 commit comments

Comments
 (0)