Skip to content

Commit 4115d03

Browse files
committed
feat: identify identify/push raw-format fix and tests
1 parent 4bd2462 commit 4115d03

File tree

3 files changed

+119
-5
lines changed

3 files changed

+119
-5
lines changed

libp2p/identity/identify_push/identify_push.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,24 @@ async def handle_identify_push(stream: INetStream) -> None:
9191
return
9292
else:
9393
# Read raw protobuf message from the stream
94+
# For raw format, we need to read all data before the stream is closed
9495
data = b""
95-
while True:
96-
chunk = await stream.read(4096)
97-
if not chunk:
98-
break
99-
data += chunk
96+
try:
97+
# Read all available data in a single operation
98+
data = await stream.read()
99+
except StreamClosed:
100+
# Try to read any remaining data
101+
try:
102+
data = await stream.read()
103+
except Exception:
104+
pass
105+
106+
# If we got no data, log a warning and return
107+
if not data:
108+
logger.warning(
109+
"No data received in raw format from peer %s", peer_id
110+
)
111+
return
100112

101113
identify_msg = Identify()
102114
identify_msg.ParseFromString(data)

newsfragments/761.internal.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix raw format reading in identify/push protocol and add comprehensive test coverage for both varint and raw formats

tests/core/identity/identify_push/test_identify_push.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,3 +597,104 @@ async def test_all_peers_receive_identify_push_with_semaphore_under_high_peer_lo
597597
assert peer_id_a in dummy_peerstore.peer_ids()
598598

599599
nursery.cancel_scope.cancel()
600+
601+
602+
@pytest.mark.trio
603+
async def test_identify_push_default_varint_format(security_protocol):
604+
"""
605+
Test that the identify/push protocol uses varint format by default.
606+
607+
This test verifies that:
608+
1. The default behavior uses length-prefixed messages (varint format)
609+
2. Messages are correctly encoded with varint length prefix
610+
3. Messages are correctly decoded with varint length prefix
611+
4. The peerstore is updated correctly with the received information
612+
"""
613+
async with host_pair_factory(security_protocol=security_protocol) as (
614+
host_a,
615+
host_b,
616+
):
617+
# Set up the identify/push handlers with default settings
618+
# (use_varint_format=True)
619+
host_b.set_stream_handler(ID_PUSH, identify_push_handler_for(host_b))
620+
621+
# Push identify information from host_a to host_b using default settings
622+
success = await push_identify_to_peer(host_a, host_b.get_id())
623+
assert success, "Identify push should succeed with default varint format"
624+
625+
# Wait a bit for the push to complete
626+
await trio.sleep(0.1)
627+
628+
# Get the peerstore from host_b
629+
peerstore = host_b.get_peerstore()
630+
peer_id = host_a.get_id()
631+
632+
# Verify that the peerstore was updated correctly
633+
assert peer_id in peerstore.peer_ids()
634+
635+
# Check that addresses have been updated
636+
host_a_addrs = set(host_a.get_addrs())
637+
peerstore_addrs = set(peerstore.addrs(peer_id))
638+
assert all(addr in peerstore_addrs for addr in host_a_addrs)
639+
640+
# Check that protocols have been updated
641+
host_a_protocols = set(host_a.get_mux().get_protocols())
642+
peerstore_protocols = set(peerstore.get_protocols(peer_id))
643+
assert all(protocol in peerstore_protocols for protocol in host_a_protocols)
644+
645+
# Check that the public key has been updated
646+
host_a_public_key = host_a.get_public_key().serialize()
647+
peerstore_public_key = peerstore.pubkey(peer_id).serialize()
648+
assert host_a_public_key == peerstore_public_key
649+
650+
651+
@pytest.mark.trio
652+
async def test_identify_push_legacy_raw_format(security_protocol):
653+
"""
654+
Test that the identify/push protocol can use legacy raw format when specified.
655+
656+
This test verifies that:
657+
1. When use_varint_format=False, messages are sent without length prefix
658+
2. Raw protobuf messages are correctly encoded and decoded
659+
3. The peerstore is updated correctly with the received information
660+
4. The legacy format is backward compatible
661+
"""
662+
async with host_pair_factory(security_protocol=security_protocol) as (
663+
host_a,
664+
host_b,
665+
):
666+
# Set up the identify/push handlers with legacy format (use_varint_format=False)
667+
host_b.set_stream_handler(
668+
ID_PUSH, identify_push_handler_for(host_b, use_varint_format=False)
669+
)
670+
671+
# Push identify information from host_a to host_b using legacy format
672+
success = await push_identify_to_peer(
673+
host_a, host_b.get_id(), use_varint_format=False
674+
)
675+
assert success, "Identify push should succeed with legacy raw format"
676+
677+
# Wait a bit for the push to complete
678+
await trio.sleep(0.1)
679+
680+
# Get the peerstore from host_b
681+
peerstore = host_b.get_peerstore()
682+
peer_id = host_a.get_id()
683+
684+
# Verify that the peerstore was updated correctly
685+
assert peer_id in peerstore.peer_ids()
686+
687+
# Check that addresses have been updated
688+
host_a_addrs = set(host_a.get_addrs())
689+
peerstore_addrs = set(peerstore.addrs(peer_id))
690+
assert all(addr in peerstore_addrs for addr in host_a_addrs)
691+
692+
# Check that protocols have been updated
693+
host_a_protocols = set(host_a.get_mux().get_protocols())
694+
peerstore_protocols = set(peerstore.get_protocols(peer_id))
695+
assert all(protocol in peerstore_protocols for protocol in host_a_protocols)
696+
697+
# Check that the public key has been updated
698+
host_a_public_key = host_a.get_public_key().serialize()
699+
peerstore_public_key = peerstore.pubkey(peer_id).serialize()
700+
assert host_a_public_key == peerstore_public_key

0 commit comments

Comments
 (0)