From 824bf3323976ad953e8187c20983d89e0a3931b1 Mon Sep 17 00:00:00 2001 From: mystical-prog Date: Fri, 25 Oct 2024 16:21:27 +0530 Subject: [PATCH 1/4] added PingService --- libp2p/host/ping.py | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/libp2p/host/ping.py b/libp2p/host/ping.py index 905942cf..af2b5855 100644 --- a/libp2p/host/ping.py +++ b/libp2p/host/ping.py @@ -1,6 +1,7 @@ import logging - +import time import trio +import secrets from libp2p.network.stream.exceptions import ( StreamClosed, @@ -15,6 +16,11 @@ TProtocol, ) +from libp2p.host.host_interface import ( + IHost, +) +from typing import List + ID = TProtocol("/ipfs/ping/1.0.0") PING_LENGTH = 32 RESP_TIMEOUT = 60 @@ -65,7 +71,43 @@ async def handle_ping(stream: INetStream) -> None: try: should_continue = await _handle_ping(stream, peer_id) if not should_continue: + stream.close() return except Exception: await stream.reset() return + + +async def _ping(stream: INetStream) -> int: + """ + Helper function to perform a single ping operation on a given stream, + returns integer value rtt - which denotes round trip time for a ping request in ms + """ + ping_bytes = secrets.token_bytes(PING_LENGTH) + before = time.time() + await stream.write(ping_bytes) + pong_bytes = await stream.read(PING_LENGTH) + rtt = int((time.time() - before) * (10 ** 6)) + if ping_bytes != pong_bytes: + logger.debug("invalid pong response") + raise + return rtt + +class PingService: + """ PingService executes pings and returns RTT in miliseconds. """ + + def __init__(self, host: IHost): + self._host = host + + async def ping(self, peer_id: PeerID, ping_amt: int = 1) -> List[int]: + stream = await self._host.new_stream(peer_id, [ID]) + + try: + rtts = [ + await _ping(stream) for _ in range(ping_amt) + ] + await stream.close() + return rtts + except Exception: + await stream.close() + raise \ No newline at end of file From 996e689511536d26307df4d28ce08a2a06919262 Mon Sep 17 00:00:00 2001 From: mystical-prog Date: Sat, 26 Oct 2024 21:10:07 +0530 Subject: [PATCH 2/4] fixed lint --- examples/ping/ping.py | 4 ++-- libp2p/host/ping.py | 29 +++++++++++++++-------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/examples/ping/ping.py b/examples/ping/ping.py index 3b99f78a..4f03d143 100644 --- a/examples/ping/ping.py +++ b/examples/ping/ping.py @@ -26,13 +26,13 @@ async def handle_ping(stream: INetStream) -> None: try: payload = await stream.read(PING_LENGTH) peer_id = stream.muxed_conn.peer_id - if payload != None: + if payload is not None: print(f"received ping from {peer_id}") await stream.write(payload) print(f"responded with pong to {peer_id}") - except: + except Exception: await stream.reset() diff --git a/libp2p/host/ping.py b/libp2p/host/ping.py index af2b5855..4c864776 100644 --- a/libp2p/host/ping.py +++ b/libp2p/host/ping.py @@ -1,8 +1,15 @@ import logging +import secrets import time +from typing import ( + List, +) + import trio -import secrets +from libp2p.host.host_interface import ( + IHost, +) from libp2p.network.stream.exceptions import ( StreamClosed, StreamEOF, @@ -16,11 +23,6 @@ TProtocol, ) -from libp2p.host.host_interface import ( - IHost, -) -from typing import List - ID = TProtocol("/ipfs/ping/1.0.0") PING_LENGTH = 32 RESP_TIMEOUT = 60 @@ -71,7 +73,7 @@ async def handle_ping(stream: INetStream) -> None: try: should_continue = await _handle_ping(stream, peer_id) if not should_continue: - stream.close() + await stream.close() return except Exception: await stream.reset() @@ -79,7 +81,7 @@ async def handle_ping(stream: INetStream) -> None: async def _ping(stream: INetStream) -> int: - """ + """ Helper function to perform a single ping operation on a given stream, returns integer value rtt - which denotes round trip time for a ping request in ms """ @@ -87,14 +89,15 @@ async def _ping(stream: INetStream) -> int: before = time.time() await stream.write(ping_bytes) pong_bytes = await stream.read(PING_LENGTH) - rtt = int((time.time() - before) * (10 ** 6)) + rtt = int((time.time() - before) * (10**6)) if ping_bytes != pong_bytes: logger.debug("invalid pong response") raise return rtt + class PingService: - """ PingService executes pings and returns RTT in miliseconds. """ + """PingService executes pings and returns RTT in miliseconds.""" def __init__(self, host: IHost): self._host = host @@ -103,11 +106,9 @@ async def ping(self, peer_id: PeerID, ping_amt: int = 1) -> List[int]: stream = await self._host.new_stream(peer_id, [ID]) try: - rtts = [ - await _ping(stream) for _ in range(ping_amt) - ] + rtts = [await _ping(stream) for _ in range(ping_amt)] await stream.close() return rtts except Exception: await stream.close() - raise \ No newline at end of file + raise From 1073b3cb56c761d238286ba03d3f4963d0e140d8 Mon Sep 17 00:00:00 2001 From: mystical-prog Date: Sun, 27 Oct 2024 01:11:14 +0530 Subject: [PATCH 3/4] added ping_service tests --- tests/core/host/test_ping.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/core/host/test_ping.py b/tests/core/host/test_ping.py index 77387b8f..b181a96e 100644 --- a/tests/core/host/test_ping.py +++ b/tests/core/host/test_ping.py @@ -6,6 +6,7 @@ from libp2p.host.ping import ( ID, PING_LENGTH, + PingService, ) from libp2p.tools.factories import ( host_pair_factory, @@ -47,3 +48,28 @@ async def test_ping_several(security_protocol): # NOTE: this interval can be `0` for this test. await trio.sleep(0) await stream.close() + + +@pytest.mark.trio +async def test_ping_service_once(security_protocol): + async with host_pair_factory(security_protocol=security_protocol) as ( + host_a, + host_b, + ): + ping_service = PingService(host_b) + rtts = await ping_service.ping(host_a.get_id()) + assert len(rtts) == 1 + assert rtts[0] < 10**6 + + +@pytest.mark.trio +async def test_ping_service_several(security_protocol): + async with host_pair_factory(security_protocol=security_protocol) as ( + host_a, + host_b, + ): + ping_service = PingService(host_b) + rtts = await ping_service.ping(host_a.get_id(), ping_amt=SOME_PING_COUNT) + assert len(rtts) == SOME_PING_COUNT + for rtt in rtts: + assert rtt < 10**6 From de0c71c7a49f690f44f0e063fd4ff46c62b5dd99 Mon Sep 17 00:00:00 2001 From: mystical-prog Date: Tue, 29 Oct 2024 21:23:20 +0530 Subject: [PATCH 4/4] added newsfragment for ping_service --- newsfragments/344.feature.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/344.feature.rst diff --git a/newsfragments/344.feature.rst b/newsfragments/344.feature.rst new file mode 100644 index 00000000..9cf7a2ec --- /dev/null +++ b/newsfragments/344.feature.rst @@ -0,0 +1 @@ +Added ``PingService`` class in ``host/ping.py`` which can be used to initiate ping requests to peers and added tests for the same