mirror of
https://github.com/varun-r-mallya/py-libp2p.git
synced 2026-02-11 15:40:54 +00:00
fix: added identify push to setup.py
This commit is contained in:
@ -35,10 +35,10 @@ from libp2p.peer.peerinfo import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
logging.basicConfig(
|
# logging.basicConfig(
|
||||||
level=logging.DEBUG,
|
# level=logging.DEBUG,
|
||||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
# format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||||
)
|
# )
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -119,3 +119,9 @@ async def main() -> None:
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
trio.run(main)
|
trio.run(main)
|
||||||
|
|
||||||
|
|
||||||
|
# Non-async entry point for console script
|
||||||
|
def run_main():
|
||||||
|
"""Non-async entry point for the console script."""
|
||||||
|
trio.run(main)
|
||||||
|
|||||||
@ -23,11 +23,17 @@ import logging
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
import multiaddr
|
import multiaddr
|
||||||
|
from multiaddr import (
|
||||||
|
Multiaddr,
|
||||||
|
)
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
from libp2p import (
|
from libp2p import (
|
||||||
new_host,
|
new_host,
|
||||||
)
|
)
|
||||||
|
from libp2p.abc import (
|
||||||
|
INetStream,
|
||||||
|
)
|
||||||
from libp2p.crypto.secp256k1 import (
|
from libp2p.crypto.secp256k1 import (
|
||||||
create_new_key_pair,
|
create_new_key_pair,
|
||||||
)
|
)
|
||||||
@ -35,6 +41,9 @@ from libp2p.identity.identify import (
|
|||||||
identify_handler_for,
|
identify_handler_for,
|
||||||
)
|
)
|
||||||
from libp2p.identity.identify import ID as ID_IDENTIFY
|
from libp2p.identity.identify import ID as ID_IDENTIFY
|
||||||
|
from libp2p.identity.identify.pb.identify_pb2 import (
|
||||||
|
Identify,
|
||||||
|
)
|
||||||
from libp2p.identity.identify_push import (
|
from libp2p.identity.identify_push import (
|
||||||
identify_push_handler_for,
|
identify_push_handler_for,
|
||||||
push_identify_to_peer,
|
push_identify_to_peer,
|
||||||
@ -45,16 +54,88 @@ from libp2p.peer.peerinfo import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
logging.basicConfig(
|
# logging.basicConfig(
|
||||||
level=logging.DEBUG,
|
# level=logging.DEBUG,
|
||||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
# format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||||
)
|
# )
|
||||||
logger = logging.getLogger("libp2p.identity.identify-push-example")
|
logger = logging.getLogger("libp2p.identity.identify-push-example")
|
||||||
|
|
||||||
# Default port configuration
|
# Default port configuration
|
||||||
DEFAULT_PORT = 8888
|
DEFAULT_PORT = 8888
|
||||||
|
|
||||||
|
|
||||||
|
def custom_identify_push_handler_for(host):
|
||||||
|
"""
|
||||||
|
Create a custom handler for the identify/push protocol that logs and prints
|
||||||
|
the identity information received from the dialer.
|
||||||
|
"""
|
||||||
|
|
||||||
|
async def handle_identify_push(stream: INetStream) -> None:
|
||||||
|
peer_id = stream.muxed_conn.peer_id
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Read the identify message from the stream
|
||||||
|
data = await stream.read()
|
||||||
|
identify_msg = Identify()
|
||||||
|
identify_msg.ParseFromString(data)
|
||||||
|
|
||||||
|
# Log and print the identify information
|
||||||
|
logger.info("Received identify/push from peer %s", peer_id)
|
||||||
|
print(f"\n==== Received identify/push from peer {peer_id} ====")
|
||||||
|
|
||||||
|
if identify_msg.HasField("protocol_version"):
|
||||||
|
logger.info(" Protocol Version: %s", identify_msg.protocol_version)
|
||||||
|
print(f" Protocol Version: {identify_msg.protocol_version}")
|
||||||
|
|
||||||
|
if identify_msg.HasField("agent_version"):
|
||||||
|
logger.info(" Agent Version: %s", identify_msg.agent_version)
|
||||||
|
print(f" Agent Version: {identify_msg.agent_version}")
|
||||||
|
|
||||||
|
if identify_msg.HasField("public_key"):
|
||||||
|
logger.info(
|
||||||
|
" Public Key: %s", identify_msg.public_key.hex()[:16] + "..."
|
||||||
|
)
|
||||||
|
print(f" Public Key: {identify_msg.public_key.hex()[:16]}...")
|
||||||
|
|
||||||
|
if identify_msg.listen_addrs:
|
||||||
|
addrs = [Multiaddr(addr) for addr in identify_msg.listen_addrs]
|
||||||
|
logger.info(" Listen Addresses: %s", addrs)
|
||||||
|
print(" Listen Addresses:")
|
||||||
|
for addr in addrs:
|
||||||
|
print(f" - {addr}")
|
||||||
|
|
||||||
|
if identify_msg.HasField("observed_addr") and identify_msg.observed_addr:
|
||||||
|
observed_addr = Multiaddr(identify_msg.observed_addr)
|
||||||
|
logger.info(" Observed Address: %s", observed_addr)
|
||||||
|
print(f" Observed Address: {observed_addr}")
|
||||||
|
|
||||||
|
if identify_msg.protocols:
|
||||||
|
logger.info(" Protocols: %s", identify_msg.protocols)
|
||||||
|
print(" Protocols:")
|
||||||
|
for protocol in identify_msg.protocols:
|
||||||
|
print(f" - {protocol}")
|
||||||
|
|
||||||
|
# Update the peerstore with the new information as usual
|
||||||
|
peerstore = host.get_peerstore()
|
||||||
|
from libp2p.identity.identify_push.identify_push import (
|
||||||
|
_update_peerstore_from_identify,
|
||||||
|
)
|
||||||
|
|
||||||
|
await _update_peerstore_from_identify(peerstore, peer_id, identify_msg)
|
||||||
|
|
||||||
|
logger.info("Successfully processed identify/push from peer %s", peer_id)
|
||||||
|
print(f"\nSuccessfully processed identify/push from peer {peer_id}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error("Error processing identify/push from %s: %s", peer_id, e)
|
||||||
|
print(f"\nError processing identify/push from {peer_id}: {e}")
|
||||||
|
finally:
|
||||||
|
# Close the stream after processing
|
||||||
|
await stream.close()
|
||||||
|
|
||||||
|
return handle_identify_push
|
||||||
|
|
||||||
|
|
||||||
async def run_listener(port: int) -> None:
|
async def run_listener(port: int) -> None:
|
||||||
"""Run a host in listener mode."""
|
"""Run a host in listener mode."""
|
||||||
print(f"\n==== Starting Identify-Push Listener on port {port} ====\n")
|
print(f"\n==== Starting Identify-Push Listener on port {port} ====\n")
|
||||||
@ -67,7 +148,7 @@ async def run_listener(port: int) -> None:
|
|||||||
|
|
||||||
# Set up the identify and identify/push handlers
|
# Set up the identify and identify/push handlers
|
||||||
host.set_stream_handler(ID_IDENTIFY, identify_handler_for(host))
|
host.set_stream_handler(ID_IDENTIFY, identify_handler_for(host))
|
||||||
host.set_stream_handler(ID_IDENTIFY_PUSH, identify_push_handler_for(host))
|
host.set_stream_handler(ID_IDENTIFY_PUSH, custom_identify_push_handler_for(host))
|
||||||
|
|
||||||
# Start listening
|
# Start listening
|
||||||
listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}")
|
listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}")
|
||||||
@ -84,7 +165,7 @@ async def run_listener(port: int) -> None:
|
|||||||
print(f"Peer ID: {host.get_id().pretty()}")
|
print(f"Peer ID: {host.get_id().pretty()}")
|
||||||
|
|
||||||
print("\nRun dialer with command:")
|
print("\nRun dialer with command:")
|
||||||
print(f"python identify_push_listener_dialer.py -d {addr}")
|
print(f"identify-push-listener-dialer-demo -d {addr}")
|
||||||
print("\nWaiting for incoming connections... (Ctrl+C to exit)")
|
print("\nWaiting for incoming connections... (Ctrl+C to exit)")
|
||||||
|
|
||||||
# Keep running until interrupted
|
# Keep running until interrupted
|
||||||
|
|||||||
2
setup.py
2
setup.py
@ -108,6 +108,8 @@ setup(
|
|||||||
"echo-demo=examples.echo.echo:main",
|
"echo-demo=examples.echo.echo:main",
|
||||||
"ping-demo=examples.ping.ping:main",
|
"ping-demo=examples.ping.ping:main",
|
||||||
"identify-demo=examples.identify.identify:main",
|
"identify-demo=examples.identify.identify:main",
|
||||||
|
"identify-push-demo=examples.identify_push.identify_push_demo:run_main",
|
||||||
|
"identify-push-listener-dialer-demo=examples.identify_push.identify_push_listener_dialer:main",
|
||||||
"pubsub-demo=examples.pubsub.pubsub:main",
|
"pubsub-demo=examples.pubsub.pubsub:main",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -14,6 +14,7 @@ from libp2p.identity.identify_push.identify_push import (
|
|||||||
_update_peerstore_from_identify,
|
_update_peerstore_from_identify,
|
||||||
identify_push_handler_for,
|
identify_push_handler_for,
|
||||||
push_identify_to_peer,
|
push_identify_to_peer,
|
||||||
|
push_identify_to_peers,
|
||||||
)
|
)
|
||||||
from tests.utils.factories import (
|
from tests.utils.factories import (
|
||||||
host_pair_factory,
|
host_pair_factory,
|
||||||
@ -24,6 +25,16 @@ logger = logging.getLogger("libp2p.identity.identify-push-test")
|
|||||||
|
|
||||||
@pytest.mark.trio
|
@pytest.mark.trio
|
||||||
async def test_identify_push_protocol(security_protocol):
|
async def test_identify_push_protocol(security_protocol):
|
||||||
|
"""
|
||||||
|
Test the basic functionality of the identify/push protocol.
|
||||||
|
|
||||||
|
This test verifies that when host_a pushes identify information to host_b:
|
||||||
|
1. The information is correctly received and processed
|
||||||
|
2. The peerstore of host_b is updated with host_a's peer ID
|
||||||
|
3. The peerstore contains all of host_a's addresses
|
||||||
|
4. The peerstore contains all of host_a's supported protocols
|
||||||
|
5. The public key in the peerstore matches host_a's public key
|
||||||
|
"""
|
||||||
async with host_pair_factory(security_protocol=security_protocol) as (
|
async with host_pair_factory(security_protocol=security_protocol) as (
|
||||||
host_a,
|
host_a,
|
||||||
host_b,
|
host_b,
|
||||||
@ -72,6 +83,17 @@ async def test_identify_push_protocol(security_protocol):
|
|||||||
|
|
||||||
@pytest.mark.trio
|
@pytest.mark.trio
|
||||||
async def test_identify_push_handler(security_protocol):
|
async def test_identify_push_handler(security_protocol):
|
||||||
|
"""
|
||||||
|
Test the identify_push_handler_for function specifically.
|
||||||
|
|
||||||
|
This test focuses on verifying that the handler function correctly:
|
||||||
|
1. Receives the identify message
|
||||||
|
2. Updates the peerstore with the peer information
|
||||||
|
3. Processes all fields of the identify message (addresses, protocols, public key)
|
||||||
|
|
||||||
|
Note: This test is similar to test_identify_push_protocol but specifically
|
||||||
|
focuses on the handler function's behavior.
|
||||||
|
"""
|
||||||
async with host_pair_factory(security_protocol=security_protocol) as (
|
async with host_pair_factory(security_protocol=security_protocol) as (
|
||||||
host_a,
|
host_a,
|
||||||
host_b,
|
host_b,
|
||||||
@ -120,6 +142,16 @@ async def test_identify_push_handler(security_protocol):
|
|||||||
|
|
||||||
@pytest.mark.trio
|
@pytest.mark.trio
|
||||||
async def test_identify_push_to_peers(security_protocol):
|
async def test_identify_push_to_peers(security_protocol):
|
||||||
|
"""
|
||||||
|
Test the push_identify_to_peers function to broadcast identity to multiple peers.
|
||||||
|
|
||||||
|
This test verifies that:
|
||||||
|
1. Host_a can push identify information to multiple peers simultaneously
|
||||||
|
2. The identify information is correctly received by all connected peers
|
||||||
|
3. Both host_b and host_c have their peerstores updated with host_a's information
|
||||||
|
|
||||||
|
This tests the broadcasting capability of the identify/push protocol.
|
||||||
|
"""
|
||||||
# Create three hosts
|
# Create three hosts
|
||||||
async with host_pair_factory(security_protocol=security_protocol) as (
|
async with host_pair_factory(security_protocol=security_protocol) as (
|
||||||
host_a,
|
host_a,
|
||||||
@ -178,8 +210,116 @@ async def test_identify_push_to_peers(security_protocol):
|
|||||||
assert peer_id_a in peerstore_c.peer_ids()
|
assert peer_id_a in peerstore_c.peer_ids()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.trio
|
||||||
|
async def test_push_identify_to_peers_with_explicit_params(security_protocol):
|
||||||
|
"""
|
||||||
|
Test the push_identify_to_peers function with explicit parameters.
|
||||||
|
|
||||||
|
This test verifies that:
|
||||||
|
1. The function correctly handles an explicitly provided set of peer IDs
|
||||||
|
2. The function correctly uses the provided observed_multiaddr
|
||||||
|
3. The identify information is only pushed to the specified peers
|
||||||
|
4. The observed address is correctly included in the identify message
|
||||||
|
|
||||||
|
This test ensures all parameters of push_identify_to_peers are properly tested.
|
||||||
|
"""
|
||||||
|
import multiaddr
|
||||||
|
|
||||||
|
from libp2p import (
|
||||||
|
new_host,
|
||||||
|
)
|
||||||
|
from libp2p.crypto.secp256k1 import (
|
||||||
|
create_new_key_pair,
|
||||||
|
)
|
||||||
|
from libp2p.peer.peerinfo import (
|
||||||
|
info_from_p2p_addr,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create four hosts to thoroughly test selective pushing
|
||||||
|
async with host_pair_factory(security_protocol=security_protocol) as (
|
||||||
|
host_a,
|
||||||
|
host_b,
|
||||||
|
):
|
||||||
|
# Create two additional hosts
|
||||||
|
key_pair_c = create_new_key_pair()
|
||||||
|
host_c = new_host(key_pair=key_pair_c)
|
||||||
|
|
||||||
|
key_pair_d = create_new_key_pair()
|
||||||
|
host_d = new_host(key_pair=key_pair_d)
|
||||||
|
|
||||||
|
# Set up the identify/push handlers for all hosts
|
||||||
|
host_b.set_stream_handler(ID_PUSH, identify_push_handler_for(host_b))
|
||||||
|
host_c.set_stream_handler(ID_PUSH, identify_push_handler_for(host_c))
|
||||||
|
host_d.set_stream_handler(ID_PUSH, identify_push_handler_for(host_d))
|
||||||
|
|
||||||
|
# Start listening on random ports
|
||||||
|
listen_addr_c = multiaddr.Multiaddr("/ip4/127.0.0.1/tcp/0")
|
||||||
|
listen_addr_d = multiaddr.Multiaddr("/ip4/127.0.0.1/tcp/0")
|
||||||
|
|
||||||
|
async with host_c.run([listen_addr_c]), host_d.run([listen_addr_d]):
|
||||||
|
# Connect all hosts to host_a
|
||||||
|
await host_c.connect(info_from_p2p_addr(host_a.get_addrs()[0]))
|
||||||
|
await host_d.connect(info_from_p2p_addr(host_a.get_addrs()[0]))
|
||||||
|
|
||||||
|
# Create a specific observed multiaddr for the test
|
||||||
|
observed_addr = multiaddr.Multiaddr("/ip4/192.0.2.1/tcp/1234")
|
||||||
|
|
||||||
|
# Only push to hosts B and C (not D)
|
||||||
|
selected_peers = {host_b.get_id(), host_c.get_id()}
|
||||||
|
|
||||||
|
# Push identify information from host_a to selected peers with observed addr
|
||||||
|
await push_identify_to_peers(
|
||||||
|
host=host_a, peer_ids=selected_peers, observed_multiaddr=observed_addr
|
||||||
|
)
|
||||||
|
|
||||||
|
# Wait a bit for the push to complete
|
||||||
|
await trio.sleep(0.1)
|
||||||
|
|
||||||
|
# Check that host_b's and host_c's peerstores have been updated
|
||||||
|
peerstore_b = host_b.get_peerstore()
|
||||||
|
peerstore_c = host_c.get_peerstore()
|
||||||
|
peerstore_d = host_d.get_peerstore()
|
||||||
|
peer_id_a = host_a.get_id()
|
||||||
|
|
||||||
|
# Hosts B and C should have peer_id_a in their peerstores
|
||||||
|
assert peer_id_a in peerstore_b.peer_ids()
|
||||||
|
assert peer_id_a in peerstore_c.peer_ids()
|
||||||
|
|
||||||
|
# Host D should NOT have peer_id_a in its peerstore from the push
|
||||||
|
# (it may still have it from the connection)
|
||||||
|
# So we check for the observed address instead, which would only be
|
||||||
|
# present from a push
|
||||||
|
|
||||||
|
# Hosts B and C should have the observed address in their peerstores
|
||||||
|
addrs_b = [str(addr) for addr in peerstore_b.addrs(peer_id_a)]
|
||||||
|
addrs_c = [str(addr) for addr in peerstore_c.addrs(peer_id_a)]
|
||||||
|
|
||||||
|
assert str(observed_addr) in addrs_b
|
||||||
|
assert str(observed_addr) in addrs_c
|
||||||
|
|
||||||
|
# If host D has addresses for peer_id_a, the observed address
|
||||||
|
# should not be there
|
||||||
|
if peer_id_a in peerstore_d.peer_ids():
|
||||||
|
addrs_d = [str(addr) for addr in peerstore_d.addrs(peer_id_a)]
|
||||||
|
assert str(observed_addr) not in addrs_d
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.trio
|
@pytest.mark.trio
|
||||||
async def test_update_peerstore_from_identify(security_protocol):
|
async def test_update_peerstore_from_identify(security_protocol):
|
||||||
|
"""
|
||||||
|
Test the _update_peerstore_from_identify function directly.
|
||||||
|
|
||||||
|
This test verifies that the internal function responsible for updating
|
||||||
|
the peerstore from an identify message works correctly:
|
||||||
|
1. It properly updates the peerstore with all fields from the identify message
|
||||||
|
2. The peer ID is added to the peerstore
|
||||||
|
3. All addresses are correctly stored
|
||||||
|
4. All protocols are correctly stored
|
||||||
|
5. The public key is correctly stored
|
||||||
|
|
||||||
|
This tests the low-level peerstore update mechanism used by
|
||||||
|
the identify/push protocol.
|
||||||
|
"""
|
||||||
async with host_pair_factory(security_protocol=security_protocol) as (
|
async with host_pair_factory(security_protocol=security_protocol) as (
|
||||||
host_a,
|
host_a,
|
||||||
host_b,
|
host_b,
|
||||||
@ -225,6 +365,19 @@ async def test_update_peerstore_from_identify(security_protocol):
|
|||||||
|
|
||||||
@pytest.mark.trio
|
@pytest.mark.trio
|
||||||
async def test_partial_update_peerstore_from_identify(security_protocol):
|
async def test_partial_update_peerstore_from_identify(security_protocol):
|
||||||
|
"""
|
||||||
|
Test partial updates of the peerstore using the identify/push protocol.
|
||||||
|
|
||||||
|
This test verifies that:
|
||||||
|
1. A partial identify message (containing only some fields) correctly updates
|
||||||
|
the peerstore without affecting other existing information
|
||||||
|
2. New protocols are added to the existing set in the peerstore
|
||||||
|
3. The original protocols, addresses, and public key remain intact
|
||||||
|
4. The update is additive rather than replacing all existing data
|
||||||
|
|
||||||
|
This tests the ability of the identify/push protocol to handle incremental
|
||||||
|
or partial updates to peer information.
|
||||||
|
"""
|
||||||
async with host_pair_factory(security_protocol=security_protocol) as (
|
async with host_pair_factory(security_protocol=security_protocol) as (
|
||||||
host_a,
|
host_a,
|
||||||
host_b,
|
host_b,
|
||||||
|
|||||||
Reference in New Issue
Block a user