Skip to content

Commit 2c1e504

Browse files
committed
Merge branch 'feature/bootstrap' of https://github.com/sumanjeet0012/py-libp2p into feature/bootstrap
2 parents 9e76940 + d03bdd7 commit 2c1e504

29 files changed

+309
-55
lines changed

docs/release_notes.rst

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,65 @@ Release Notes
33

44
.. towncrier release notes start
55
6+
py-libp2p v0.2.9 (2025-07-09)
7+
-----------------------------
8+
9+
Breaking Changes
10+
~~~~~~~~~~~~~~~~
11+
12+
- Reordered the arguments to ``upgrade_security`` to place ``is_initiator`` before ``peer_id``, and made ``peer_id`` optional.
13+
This allows the method to reflect the fact that peer identity is not required for inbound connections. (`#681 <https://github.com/libp2p/py-libp2p/issues/681>`__)
14+
15+
16+
Bugfixes
17+
~~~~~~~~
18+
19+
- Add timeout wrappers in:
20+
1. ``multiselect.py``: ``negotiate`` function
21+
2. ``multiselect_client.py``: ``select_one_of`` , ``query_multistream_command`` functions
22+
to prevent indefinite hangs when a remote peer does not respond. (`#696 <https://github.com/libp2p/py-libp2p/issues/696>`__)
23+
- Align stream creation logic with yamux specification (`#701 <https://github.com/libp2p/py-libp2p/issues/701>`__)
24+
- Fixed an issue in ``Pubsub`` where async validators were not handled reliably under concurrency. Now uses a safe aggregator list for consistent behavior. (`#702 <https://github.com/libp2p/py-libp2p/issues/702>`__)
25+
26+
27+
Features
28+
~~~~~~~~
29+
30+
- Added support for ``Kademlia DHT`` in py-libp2p. (`#579 <https://github.com/libp2p/py-libp2p/issues/579>`__)
31+
- Limit concurrency in ``push_identify_to_peers`` to prevent resource congestion under high peer counts. (`#621 <https://github.com/libp2p/py-libp2p/issues/621>`__)
32+
- Store public key and peer ID in peerstore during handshake
33+
34+
Modified the InsecureTransport class to accept an optional peerstore parameter and updated the handshake process to store the received public key and peer ID in the peerstore when available.
35+
36+
Added test cases to verify:
37+
1. The peerstore remains unchanged when handshake fails due to peer ID mismatch
38+
2. The handshake correctly adds a public key to a peer ID that already exists in the peerstore but doesn't have a public key yet (`#631 <https://github.com/libp2p/py-libp2p/issues/631>`__)
39+
- Fixed several flow-control and concurrency issues in the ``YamuxStream`` class. Previously, stress-testing revealed that transferring data over ``DEFAULT_WINDOW_SIZE`` would break the stream due to inconsistent window update handling and lock management. The fixes include:
40+
41+
- Removed sending of window updates during writes to maintain correct flow-control.
42+
- Added proper timeout handling when releasing and acquiring locks to prevent concurrency errors.
43+
- Corrected the ``read`` function to properly handle window updates for both ``read_until_EOF`` and ``read_n_bytes``.
44+
- Added event logging at ``send_window_updates`` and ``waiting_for_window_updates`` for better observability. (`#639 <https://github.com/libp2p/py-libp2p/issues/639>`__)
45+
- Added support for ``Multicast DNS`` in py-libp2p (`#649 <https://github.com/libp2p/py-libp2p/issues/649>`__)
46+
- Optimized pubsub publishing to send multiple topics in a single message instead of separate messages per topic. (`#685 <https://github.com/libp2p/py-libp2p/issues/685>`__)
47+
- Optimized pubsub message writing by implementing a write_msg() method that uses pre-allocated buffers and single write operations, improving performance by eliminating separate varint prefix encoding and write operations in FloodSub and GossipSub. (`#687 <https://github.com/libp2p/py-libp2p/issues/687>`__)
48+
- Added peer exchange and backoff logic as part of Gossipsub v1.1 upgrade (`#690 <https://github.com/libp2p/py-libp2p/issues/690>`__)
49+
50+
51+
Internal Changes - for py-libp2p Contributors
52+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
53+
54+
- Added sparse connect utility function to pubsub test utilities for creating test networks with configurable connectivity. (`#679 <https://github.com/libp2p/py-libp2p/issues/679>`__)
55+
- Added comprehensive tests for pubsub connection utility functions to verify degree limits are enforced, excess peers are handled correctly, and edge cases (degree=0, negative values, empty lists) are managed gracefully. (`#707 <https://github.com/libp2p/py-libp2p/issues/707>`__)
56+
- Added extra tests for identify push concurrency cap under high peer load (`#708 <https://github.com/libp2p/py-libp2p/issues/708>`__)
57+
58+
59+
Miscellaneous Changes
60+
~~~~~~~~~~~~~~~~~~~~~
61+
62+
- `#678 <https://github.com/libp2p/py-libp2p/issues/678>`__, `#684 <https://github.com/libp2p/py-libp2p/issues/684>`__
63+
64+
665
py-libp2p v0.2.8 (2025-06-10)
766
-----------------------------
867

libp2p/abc.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@
5050
Pubsub,
5151
)
5252

53+
from typing import TYPE_CHECKING
54+
55+
if TYPE_CHECKING:
56+
from libp2p.protocol_muxer.multiselect import Multiselect
57+
5358
from libp2p.pubsub.pb import (
5459
rpc_pb2,
5560
)
@@ -1545,9 +1550,8 @@ def get_network(self) -> INetworkService:
15451550
15461551
"""
15471552

1548-
# FIXME: Replace with correct return type
15491553
@abstractmethod
1550-
def get_mux(self) -> Any:
1554+
def get_mux(self) -> "Multiselect":
15511555
"""
15521556
Retrieve the muxer instance for the host.
15531557
@@ -2158,6 +2162,7 @@ def add_handler(self, protocol: TProtocol, handler: StreamHandlerFn) -> None:
21582162
21592163
"""
21602164

2165+
@abstractmethod
21612166
def get_protocols(self) -> tuple[TProtocol | None, ...]:
21622167
"""
21632168
Retrieve the protocols for which handlers have been registered.
@@ -2168,7 +2173,6 @@ def get_protocols(self) -> tuple[TProtocol | None, ...]:
21682173
A tuple of registered protocol names.
21692174
21702175
"""
2171-
return tuple(self.handlers.keys())
21722176

21732177
@abstractmethod
21742178
async def negotiate(

libp2p/identity/identify/identify.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def _mk_identify_protobuf(
5959
) -> Identify:
6060
public_key = host.get_public_key()
6161
laddrs = host.get_addrs()
62-
protocols = host.get_mux().get_protocols()
62+
protocols = tuple(str(p) for p in host.get_mux().get_protocols() if p is not None)
6363

6464
observed_addr = observed_multiaddr.to_bytes() if observed_multiaddr else b""
6565
return Identify(

libp2p/peer/peerstore.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,11 @@ def peer_ids(self) -> list[ID]:
6464
return list(self.peer_data_map.keys())
6565

6666
def clear_peerdata(self, peer_id: ID) -> None:
67-
"""Clears the peer data of the peer"""
67+
"""Clears all data associated with the given peer_id."""
68+
if peer_id in self.peer_data_map:
69+
del self.peer_data_map[peer_id]
70+
else:
71+
raise PeerStoreError("peer ID not found")
6872

6973
def valid_peer_ids(self) -> list[ID]:
7074
"""

libp2p/protocol_muxer/multiselect.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,18 @@ async def negotiate(
101101
except trio.TooSlowError:
102102
raise MultiselectError("handshake read timeout")
103103

104+
def get_protocols(self) -> tuple[TProtocol | None, ...]:
105+
"""
106+
Retrieve the protocols for which handlers have been registered.
107+
108+
Returns
109+
-------
110+
tuple[TProtocol, ...]
111+
A tuple of registered protocol names.
112+
113+
"""
114+
return tuple(self.handlers.keys())
115+
104116
async def handshake(self, communicator: IMultiselectCommunicator) -> None:
105117
"""
106118
Perform handshake to agree on multiselect protocol.

libp2p/relay/circuit_v2/discovery.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,8 @@ async def _check_via_peerstore(self, peer_id: ID) -> bool | None:
234234

235235
if not callable(proto_getter):
236236
return None
237-
237+
if peer_id not in peerstore.peer_ids():
238+
return None
238239
try:
239240
# Try to get protocols
240241
proto_result = proto_getter(peer_id)
@@ -283,8 +284,6 @@ async def _check_via_mux(self, peer_id: ID) -> bool | None:
283284
return None
284285

285286
mux = self.host.get_mux()
286-
if not hasattr(mux, "protocols"):
287-
return None
288287

289288
peer_protocols = set()
290289
# Get protocols from mux with proper type safety
@@ -293,7 +292,9 @@ async def _check_via_mux(self, peer_id: ID) -> bool | None:
293292
# Get protocols with proper typing
294293
mux_protocols = mux.get_protocols()
295294
if isinstance(mux_protocols, (list, tuple)):
296-
available_protocols = list(mux_protocols)
295+
available_protocols = [
296+
p for p in mux.get_protocols() if p is not None
297+
]
297298

298299
for protocol in available_protocols:
299300
try:
@@ -313,7 +314,7 @@ async def _check_via_mux(self, peer_id: ID) -> bool | None:
313314

314315
self._protocol_cache[peer_id] = peer_protocols
315316
protocol_str = str(PROTOCOL_ID)
316-
for protocol in peer_protocols:
317+
for protocol in map(TProtocol, peer_protocols):
317318
if protocol == protocol_str:
318319
return True
319320
return False

newsfragments/579.feature.rst

Lines changed: 0 additions & 1 deletion
This file was deleted.

newsfragments/621.feature.rst

Lines changed: 0 additions & 1 deletion
This file was deleted.

newsfragments/631.feature.rst

Lines changed: 0 additions & 7 deletions
This file was deleted.

newsfragments/639.feature.rst

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)