Skip to content

Commit 303bf30

Browse files
committed
implemented peer exchange
1 parent 788b4cf commit 303bf30

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

libp2p/peer/peerinfo.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,23 @@ def info_from_p2p_addr(addr: multiaddr.Multiaddr) -> PeerInfo:
6666
return PeerInfo(peer_id, [addr])
6767

6868

69+
def peer_info_to_bytes(peer_info: PeerInfo) -> bytes:
70+
lines = [str(peer_info.peer_id)] + [str(addr) for addr in peer_info.addrs]
71+
return "\n".join(lines).encode("utf-8")
72+
73+
74+
def peer_info_from_bytes(data: bytes) -> PeerInfo:
75+
try:
76+
lines = data.decode("utf-8").splitlines()
77+
if not lines:
78+
raise InvalidAddrError("no data to decode PeerInfo")
79+
80+
peer_id = ID.from_base58(lines[0])
81+
addrs = [multiaddr.Multiaddr(addr_str) for addr_str in lines[1:]]
82+
return PeerInfo(peer_id, addrs)
83+
except Exception as e:
84+
raise InvalidAddrError(f"failed to decode PeerInfo: {e}")
85+
86+
6987
class InvalidAddrError(ValueError):
7088
pass

libp2p/pubsub/gossipsub.py

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
)
3333
from libp2p.peer.peerinfo import (
3434
PeerInfo,
35+
peer_info_from_bytes,
36+
peer_info_to_bytes,
3537
)
3638
from libp2p.peer.peerstore import (
3739
PERMANENT_ADDR_TTL,
@@ -93,6 +95,7 @@ class GossipSub(IPubsubRouter, Service):
9395
direct_connect_interval: int
9496

9597
do_px: bool
98+
px_peers_count: int
9699
back_off: dict[str, dict[ID, int]]
97100
prune_back_off: int
98101
unsubscribe_back_off: int
@@ -112,6 +115,7 @@ def __init__(
112115
direct_connect_initial_delay: float = 0.1,
113116
direct_connect_interval: int = 300,
114117
do_px: bool = False,
118+
px_peers_count: int = 16,
115119
prune_back_off: int = 60,
116120
unsubscribe_back_off: int = 10,
117121
) -> None:
@@ -149,6 +153,7 @@ def __init__(
149153
self.time_since_last_publish = {}
150154

151155
self.do_px = do_px
156+
self.px_peers_count = px_peers_count
152157
self.back_off = dict()
153158
self.prune_back_off = prune_back_off
154159
self.unsubscribe_back_off = unsubscribe_back_off
@@ -737,6 +742,37 @@ def _check_back_off(self, peer: ID, topic: str) -> bool:
737742
del self.back_off[topic][peer]
738743
return False
739744

745+
async def _do_px(self, px_peers: list[rpc_pb2.PeerInfo]) -> None:
746+
if len(px_peers) > self.px_peers_count:
747+
px_peers = px_peers[: self.px_peers_count]
748+
749+
for peer in px_peers:
750+
peer_id: ID = ID(peer.peerID)
751+
752+
if self.pubsub and peer_id in self.pubsub.peers:
753+
continue
754+
755+
try:
756+
peer_info = peer_info_from_bytes(peer.signedPeerRecord)
757+
try:
758+
if self.pubsub is None:
759+
raise NoPubsubAttached
760+
await self.pubsub.host.connect(peer_info)
761+
except Exception as e:
762+
logger.warning(
763+
"failed to connect to px peer %s: %s",
764+
peer_id,
765+
e,
766+
)
767+
continue
768+
except Exception as e:
769+
logger.warning(
770+
"failed to parse peer info from px peer %s: %s",
771+
peer_id,
772+
e,
773+
)
774+
continue
775+
740776
# RPC handlers
741777

742778
async def handle_ihave(
@@ -853,6 +889,9 @@ async def handle_prune(
853889
) -> None:
854890
topic: str = prune_msg.topicID
855891
backoff_till: int = prune_msg.backoff
892+
px_peers: list[rpc_pb2.PeerInfo] = []
893+
for peer in prune_msg.peers:
894+
px_peers.append(peer)
856895

857896
# Remove peer from mesh for topic
858897
if topic in self.mesh:
@@ -863,6 +902,9 @@ async def handle_prune(
863902

864903
self.mesh[topic].discard(sender_peer_id)
865904

905+
if px_peers:
906+
await self._do_px(px_peers)
907+
866908
# RPC emitters
867909

868910
def pack_control_msgs(
@@ -924,8 +966,18 @@ async def emit_prune(
924966

925967
prune_msg.backoff = back_off_duration
926968

927-
# TODO: add peers once peerstore changes are complete
928-
# prune_msg.peers =
969+
if do_px:
970+
exchange_peers = self._get_in_topic_gossipsub_peers_from_minus(
971+
topic, self.px_peers_count, [to_peer]
972+
)
973+
for peer in exchange_peers:
974+
if self.pubsub is None:
975+
raise NoPubsubAttached
976+
peer_info = self.pubsub.host.get_peerstore().peer_info(peer)
977+
signed_peer_record: rpc_pb2.PeerInfo = rpc_pb2.PeerInfo()
978+
signed_peer_record.peerID = peer.to_bytes()
979+
signed_peer_record.signedPeerRecord = peer_info_to_bytes(peer_info)
980+
prune_msg.peers.append(signed_peer_record)
929981

930982
control_msg: rpc_pb2.ControlMessage = rpc_pb2.ControlMessage()
931983
control_msg.prune.extend([prune_msg])

0 commit comments

Comments
 (0)