mirror of
https://github.com/varun-r-mallya/py-libp2p.git
synced 2025-12-31 20:36:24 +00:00
linter respacing
This commit is contained in:
@ -1,52 +1,53 @@
|
||||
import time
|
||||
import threading
|
||||
from typing import Optional
|
||||
import time
|
||||
|
||||
from multiaddr import Multiaddr
|
||||
|
||||
from libp2p.abc import IPeerRecord
|
||||
import libp2p.peer.pb.peer_record_pb2 as pb
|
||||
|
||||
from multiaddr import Multiaddr
|
||||
from libp2p.peer.peerinfo import PeerInfo
|
||||
from libp2p.peer.id import ID
|
||||
|
||||
import libp2p.peer.pb.peer_record_pb2 as pb
|
||||
from libp2p.peer.peerinfo import PeerInfo
|
||||
|
||||
PEER_RECORD_ENVELOPE_DOMAIN = "libp2p-peer-record"
|
||||
PEER_RECORD_ENVELOPE_PAYLOAD_TYPE = b'\x03\x01'
|
||||
PEER_RECORD_ENVELOPE_PAYLOAD_TYPE = b"\x03\x01"
|
||||
|
||||
_last_timestamp_lock = threading.Lock()
|
||||
_last_timestamp: int = 0
|
||||
_last_timestamp: int = 0
|
||||
|
||||
|
||||
class PeerRecord(IPeerRecord):
|
||||
"""
|
||||
A record that contains metatdata about a peer in the libp2p network.
|
||||
|
||||
|
||||
This includes:
|
||||
- `peer_id`: The peer's globally unique indentifier.
|
||||
- `addrs`: A list of the peer's publicly reachable multiaddrs.
|
||||
- `seq`: A strictly monotonically increasing timestamp used
|
||||
- `seq`: A strictly monotonically increasing timestamp used
|
||||
to order records over time.
|
||||
|
||||
|
||||
PeerRecords are designed to be signed and transmitted in libp2p routing Envelopes.
|
||||
"""
|
||||
|
||||
peer_id: ID
|
||||
addrs: list[Multiaddr]
|
||||
seq: int
|
||||
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
peer_id: Optional[ID] = None,
|
||||
addrs: Optional[list[Multiaddr]] = None,
|
||||
seq: Optional[int] = None,
|
||||
) -> None:
|
||||
peer_id: ID | None = None,
|
||||
addrs: list[Multiaddr] | None = None,
|
||||
seq: int | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Initialize a new PeerRecord.
|
||||
If `seq` is not provided, a timestamp-based strictly increasing sequence
|
||||
If `seq` is not provided, a timestamp-based strictly increasing sequence
|
||||
number will be generated.
|
||||
|
||||
|
||||
:param peer_id: ID of the peer this record refers to.
|
||||
:param addrs: Public multiaddrs of the peer.
|
||||
:param seq: Monotonic sequence number.
|
||||
|
||||
"""
|
||||
|
||||
"""
|
||||
if peer_id is not None:
|
||||
self.peer_id = peer_id
|
||||
self.addrs = addrs or []
|
||||
@ -54,27 +55,27 @@ class PeerRecord(IPeerRecord):
|
||||
self.seq = seq
|
||||
else:
|
||||
self.seq = timestamp_seq()
|
||||
|
||||
|
||||
def domain(self) -> str:
|
||||
"""
|
||||
Return the domain string associated with this PeerRecord.
|
||||
|
||||
|
||||
Used during record signing and envelope validation to identify the record type.
|
||||
"""
|
||||
return PEER_RECORD_ENVELOPE_DOMAIN
|
||||
|
||||
|
||||
def codec(self) -> bytes:
|
||||
"""
|
||||
Return the codec identifier for PeerRecords.
|
||||
|
||||
|
||||
This binary perfix helps distinguish PeerRecords in serialized envelopes.
|
||||
"""
|
||||
return PEER_RECORD_ENVELOPE_PAYLOAD_TYPE
|
||||
|
||||
|
||||
def to_protobuf(self) -> pb.PeerRecord:
|
||||
"""
|
||||
Convert the current PeerRecord into a ProtoBuf PeerRecord message.
|
||||
|
||||
|
||||
:raises ValueError: if peer_id serialization fails.
|
||||
:return: A ProtoBuf-encoded PeerRecord message object.
|
||||
"""
|
||||
@ -82,36 +83,36 @@ class PeerRecord(IPeerRecord):
|
||||
id_bytes = self.peer_id.to_bytes()
|
||||
except Exception as e:
|
||||
raise ValueError(f"failed to marshal peer_id: {e}")
|
||||
|
||||
|
||||
msg = pb.PeerRecord()
|
||||
msg.peer_id = id_bytes
|
||||
msg.seq = self.seq
|
||||
msg.addresses.extend(addrs_to_protobuf(self.addrs))
|
||||
return msg
|
||||
|
||||
|
||||
def marshal_record(self) -> bytes:
|
||||
"""
|
||||
Serialize a PeerRecord into raw bytes suitable for embedding in an Envelope.
|
||||
|
||||
|
||||
This is typically called during the process of signing or sealing the record.
|
||||
:raises ValueError: if serialization to protobuf fails.
|
||||
:return: Serialized PeerRecord bytes.
|
||||
:return: Serialized PeerRecord bytes.
|
||||
"""
|
||||
try:
|
||||
msg = self.to_protobuf()
|
||||
return msg.SerializeToString()
|
||||
except Exception as e:
|
||||
raise ValueError(f"failed to marshal PeerRecord: {e}")
|
||||
|
||||
|
||||
def equal(self, other) -> bool:
|
||||
"""
|
||||
Check if this PeerRecord is identical to another.
|
||||
|
||||
|
||||
Two PeerRecords are considered equal if:
|
||||
- Their peer IDs match.
|
||||
- Their sequence numbers are identical.
|
||||
- Their address lists are identical and in the same order.
|
||||
|
||||
|
||||
:param other: Another PeerRecord instance.
|
||||
:return: True if all fields mathch, False otherwise.
|
||||
"""
|
||||
@ -122,45 +123,47 @@ class PeerRecord(IPeerRecord):
|
||||
for a1, a2 in zip(self.addrs, other.addrs):
|
||||
if a1 == a2:
|
||||
continue
|
||||
else:
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def unmarshal_record(data: bytes) -> PeerRecord:
|
||||
"""
|
||||
Deserialize a PeerRecord from its serialized byte representation.
|
||||
|
||||
|
||||
Typically used when receiveing a PeerRecord inside a signed routing Envelope.
|
||||
|
||||
|
||||
:param data: Serialized protobuf-encoded bytes.
|
||||
:raises ValueError: if parsing or conversion fails.
|
||||
:reurn: A valid PeerRecord instance.
|
||||
"""
|
||||
if data is None:
|
||||
raise ValueError("cannot unmarshal PeerRecord from None")
|
||||
|
||||
|
||||
msg = pb.PeerRecord()
|
||||
try:
|
||||
msg.ParseFromString(data)
|
||||
except Exception as e:
|
||||
raise ValueError(f"Failed to parse PeerRecord protobuf: {e}")
|
||||
|
||||
|
||||
try:
|
||||
record = peer_record_from_protobuf(msg)
|
||||
except Exception as e:
|
||||
raise ValueError(f"Failed to convert protobuf to PeerRecord: {e}")
|
||||
|
||||
|
||||
return record
|
||||
|
||||
|
||||
def timestamp_seq() -> int:
|
||||
"""
|
||||
Generate a strictly increasing timestamp-based sequence number.
|
||||
|
||||
Ensures that even if multiple PeerRecords are generated in the same nanosecond,
|
||||
their `seq` values will still be strictly increasing by using a lock to track the
|
||||
Generate a strictly increasing timestamp-based sequence number.
|
||||
|
||||
Ensures that even if multiple PeerRecords are generated in the same nanosecond,
|
||||
their `seq` values will still be strictly increasing by using a lock to track the
|
||||
last value.
|
||||
|
||||
|
||||
:return: A strictly increasing integer timestamp.
|
||||
"""
|
||||
global _last_timestamp
|
||||
@ -171,11 +174,11 @@ def timestamp_seq() -> int:
|
||||
_last_timestamp = now
|
||||
return now
|
||||
|
||||
|
||||
|
||||
def peer_record_from_peer_info(info: PeerInfo) -> PeerRecord:
|
||||
"""
|
||||
Create a PeerRecord from a PeerInfo object.
|
||||
|
||||
|
||||
This automatically assigns a timestamp-based sequence number to the record.
|
||||
:param info: A PeerInfo instance (contains peer_id and addrs).
|
||||
:return: A PeerRecord instance.
|
||||
@ -185,6 +188,7 @@ def peer_record_from_peer_info(info: PeerInfo) -> PeerRecord:
|
||||
record.addrs = info.addrs
|
||||
return record
|
||||
|
||||
|
||||
def peer_record_from_protobuf(msg: pb.PeerRecord) -> PeerRecord:
|
||||
"""
|
||||
Convert a protobuf PeerRecord message into a PeerRecord object.
|
||||
@ -220,6 +224,7 @@ def addrs_from_protobuf(addrs: list[pb.PeerRecord.AddressInfo]) -> list[Multiadd
|
||||
continue
|
||||
return out
|
||||
|
||||
|
||||
def addrs_to_protobuf(addrs: list[Multiaddr]) -> list[pb.PeerRecord.AddressInfo]:
|
||||
"""
|
||||
Convert a list of Multiaddr objects into their protobuf representation.
|
||||
@ -230,6 +235,6 @@ def addrs_to_protobuf(addrs: list[Multiaddr]) -> list[pb.PeerRecord.AddressInfo]
|
||||
out = []
|
||||
for addr in addrs:
|
||||
addr_info = pb.PeerRecord.AddressInfo()
|
||||
addr_info.multiaddr = addr.to_bytes()
|
||||
addr_info.multiaddr = addr.to_bytes()
|
||||
out.append(addr_info)
|
||||
return out
|
||||
return out
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import time
|
||||
from libp2p.peer.id import ID
|
||||
import libp2p.peer.pb.peer_record_pb2 as pb
|
||||
|
||||
from multiaddr import Multiaddr
|
||||
|
||||
from libp2p.peer.id import ID
|
||||
import libp2p.peer.pb.peer_record_pb2 as pb
|
||||
from libp2p.peer.peer_record import (
|
||||
PeerRecord,
|
||||
addrs_from_protobuf,
|
||||
@ -12,93 +13,100 @@ from libp2p.peer.peer_record import (
|
||||
|
||||
# Testing methods from PeerRecord base class and PeerRecord protobuf:
|
||||
|
||||
|
||||
def test_basic_protobuf_serializatrion_deserialization():
|
||||
record = pb.PeerRecord()
|
||||
record.seq = 1
|
||||
|
||||
|
||||
serialized = record.SerializeToString()
|
||||
new_record = pb.PeerRecord()
|
||||
new_record.ParseFromString(serialized)
|
||||
|
||||
|
||||
assert new_record.seq == 1
|
||||
|
||||
|
||||
|
||||
def test_timestamp_seq_monotonicity():
|
||||
rec1 = PeerRecord()
|
||||
time.sleep(1)
|
||||
rec2 = PeerRecord()
|
||||
|
||||
|
||||
assert isinstance(rec1.seq, int)
|
||||
assert isinstance(rec2.seq, int)
|
||||
assert rec2.seq > rec1.seq, f"Expected seq2 ({rec2.seq}) > seq1 ({rec1.seq})"
|
||||
|
||||
|
||||
|
||||
def test_addrs_from_protobuf_multiple_addresses():
|
||||
ma1 = Multiaddr("/ip4/127.0.0.1/tcp/4001")
|
||||
ma2 = Multiaddr("/ip4/127.0.0.1/tcp/4002")
|
||||
|
||||
|
||||
addr_info1 = pb.PeerRecord.AddressInfo()
|
||||
addr_info1.multiaddr = ma1.to_bytes()
|
||||
|
||||
|
||||
addr_info2 = pb.PeerRecord.AddressInfo()
|
||||
addr_info2.multiaddr = ma2.to_bytes()
|
||||
|
||||
|
||||
result = addrs_from_protobuf([addr_info1, addr_info2])
|
||||
assert result == [ma1, ma2]
|
||||
|
||||
|
||||
|
||||
def test_peer_record_from_protobuf():
|
||||
peer_id = ID.from_base58("QmNM23MiU1Kd7yfiKVdUnaDo8RYca8By4zDmr7uSaVV8Px")
|
||||
record = pb.PeerRecord()
|
||||
record.peer_id = peer_id.to_bytes()
|
||||
record.seq = 42
|
||||
|
||||
|
||||
for addr_str in ["/ip4/127.0.0.1/tcp/4001", "/ip4/127.0.0.1/tcp/4002"]:
|
||||
ma = Multiaddr(addr_str)
|
||||
addr_info = pb.PeerRecord.AddressInfo()
|
||||
addr_info.multiaddr = ma.to_bytes()
|
||||
record.addresses.append(addr_info)
|
||||
|
||||
|
||||
result = peer_record_from_protobuf(record)
|
||||
|
||||
|
||||
assert result.peer_id == peer_id
|
||||
assert result.seq == 42
|
||||
assert len(result.addrs) == 2
|
||||
assert str(result.addrs[0]) == "/ip4/127.0.0.1/tcp/4001"
|
||||
assert str(result.addrs[1]) == "/ip4/127.0.0.1/tcp/4002"
|
||||
|
||||
|
||||
|
||||
def test_to_protobuf_generates_correct_message():
|
||||
peer_id = ID.from_base58("QmNM23MiU1Kd7yfiKVdUnaDo8RYca8By4zDmr7uSaVV8Px")
|
||||
addrs = [Multiaddr("/ip4/127.0.0.1/tcp/4001")]
|
||||
seq = 12345
|
||||
|
||||
|
||||
record = PeerRecord(peer_id, addrs, seq)
|
||||
proto = record.to_protobuf()
|
||||
|
||||
|
||||
assert isinstance(proto, pb.PeerRecord)
|
||||
assert proto.peer_id == peer_id.to_bytes()
|
||||
assert proto.seq == seq
|
||||
assert len(proto.addresses) == 1
|
||||
assert proto.addresses[0].multiaddr == addrs[0].to_bytes()
|
||||
|
||||
|
||||
def test_unmarshal_record_roundtrip():
|
||||
record = PeerRecord(
|
||||
peer_id = ID.from_base58("QmNM23MiU1Kd7yfiKVdUnaDo8RYca8By4zDmr7uSaVV8Px"),
|
||||
addrs = [Multiaddr("/ip4/127.0.0.1/tcp/4001")],
|
||||
seq = 999,
|
||||
)
|
||||
|
||||
peer_id=ID.from_base58("QmNM23MiU1Kd7yfiKVdUnaDo8RYca8By4zDmr7uSaVV8Px"),
|
||||
addrs=[Multiaddr("/ip4/127.0.0.1/tcp/4001")],
|
||||
seq=999,
|
||||
)
|
||||
|
||||
serialized = record.to_protobuf().SerializeToString()
|
||||
deserialized = unmarshal_record(serialized)
|
||||
|
||||
|
||||
assert deserialized.peer_id == record.peer_id
|
||||
assert deserialized.seq == record.seq
|
||||
assert len(deserialized.addrs) == 1
|
||||
assert deserialized.addrs[0] == record.addrs[0]
|
||||
|
||||
|
||||
|
||||
def test_marshal_record_and_equal():
|
||||
peer_id = ID.from_base58("QmNM23MiU1Kd7yfiKVdUnaDo8RYca8By4zDmr7uSaVV8Px")
|
||||
addrs = [Multiaddr("/ip4/127.0.0.1/tcp/4001")]
|
||||
original = PeerRecord(peer_id, addrs)
|
||||
|
||||
original = PeerRecord(peer_id, addrs)
|
||||
|
||||
serialized = original.marshal_record()
|
||||
deserailzed = unmarshal_record(serialized)
|
||||
|
||||
assert original.equal(deserailzed)
|
||||
|
||||
assert original.equal(deserailzed)
|
||||
|
||||
Reference in New Issue
Block a user