diff --git a/examples/doc-examples/example_encryption_insecure.py b/examples/doc-examples/example_encryption_insecure.py index dae23a68..c1536808 100644 --- a/examples/doc-examples/example_encryption_insecure.py +++ b/examples/doc-examples/example_encryption_insecure.py @@ -24,6 +24,12 @@ async def main(): insecure_transport = InsecureTransport( # local_key_pair: The key pair used for libp2p identity local_key_pair=key_pair, + # secure_bytes_provider: Optional function to generate secure random bytes + # (defaults to secrets.token_bytes) + secure_bytes_provider=None, # Use default implementation + # peerstore: Optional peerstore to store peer IDs and public keys + # (defaults to None) + peerstore=None, ) # Create a security options dictionary mapping protocol ID to transport diff --git a/libp2p/__init__.py b/libp2p/__init__.py index 64f47243..de07c78b 100644 --- a/libp2p/__init__.py +++ b/libp2p/__init__.py @@ -200,7 +200,9 @@ def new_swarm( key_pair, noise_privkey=noise_key_pair.private_key ), TProtocol(secio.ID): secio.Transport(key_pair), - TProtocol(PLAINTEXT_PROTOCOL_ID): InsecureTransport(key_pair), + TProtocol(PLAINTEXT_PROTOCOL_ID): InsecureTransport( + key_pair, peerstore=peerstore_opt + ), } # Use given muxer preference if provided, otherwise use global default diff --git a/libp2p/kad_dht/common.py b/libp2p/kad_dht/common.py new file mode 100644 index 00000000..392bffd0 --- /dev/null +++ b/libp2p/kad_dht/common.py @@ -0,0 +1,14 @@ +""" +Shared constants and protocol parameters for the Kademlia DHT. +""" + +from libp2p.custom_types import ( + TProtocol, +) + +# Constants for the Kademlia algorithm +ALPHA = 3 # Concurrency parameter +PROTOCOL_ID = TProtocol("/ipfs/kad/1.0.0") +QUERY_TIMEOUT = 10 + +TTL = DEFAULT_TTL = 24 * 60 * 60 # 24 hours in seconds diff --git a/libp2p/kad_dht/kad_dht.py b/libp2p/kad_dht/kad_dht.py index 7daad4cb..dcf323ba 100644 --- a/libp2p/kad_dht/kad_dht.py +++ b/libp2p/kad_dht/kad_dht.py @@ -5,7 +5,9 @@ This module provides a complete Distributed Hash Table (DHT) implementation based on the Kademlia algorithm and protocol. """ -from enum import Enum +from enum import ( + Enum, +) import logging import time @@ -18,9 +20,6 @@ import varint from libp2p.abc import ( IHost, ) -from libp2p.custom_types import ( - TProtocol, -) from libp2p.network.stream.net_stream import ( INetStream, ) @@ -34,6 +33,11 @@ from libp2p.tools.async_service import ( Service, ) +from .common import ( + ALPHA, + PROTOCOL_ID, + QUERY_TIMEOUT, +) from .pb.kademlia_pb2 import ( Message, ) @@ -53,11 +57,7 @@ from .value_store import ( logger = logging.getLogger("kademlia-example.kad_dht") # logger = logging.getLogger("libp2p.kademlia") # Default parameters -PROTOCOL_ID = TProtocol("/ipfs/kad/1.0.0") -ROUTING_TABLE_REFRESH_INTERVAL = 1 * 60 # 1 min in seconds for testing -TTL = 24 * 60 * 60 # 24 hours in seconds -ALPHA = 3 -QUERY_TIMEOUT = 10 # seconds +ROUTING_TABLE_REFRESH_INTERVAL = 60 # 1 min in seconds for testing class DHTMode(Enum): diff --git a/libp2p/kad_dht/peer_routing.py b/libp2p/kad_dht/peer_routing.py index f3689e11..4bcdb647 100644 --- a/libp2p/kad_dht/peer_routing.py +++ b/libp2p/kad_dht/peer_routing.py @@ -15,9 +15,6 @@ from libp2p.abc import ( INetStream, IPeerRouting, ) -from libp2p.custom_types import ( - TProtocol, -) from libp2p.peer.id import ( ID, ) @@ -25,6 +22,10 @@ from libp2p.peer.peerinfo import ( PeerInfo, ) +from .common import ( + ALPHA, + PROTOCOL_ID, +) from .pb.kademlia_pb2 import ( Message, ) @@ -38,10 +39,7 @@ from .utils import ( # logger = logging.getLogger("libp2p.kademlia.peer_routing") logger = logging.getLogger("kademlia-example.peer_routing") -# Constants for the Kademlia algorithm -ALPHA = 3 # Concurrency parameter MAX_PEER_LOOKUP_ROUNDS = 20 # Maximum number of rounds in peer lookup -PROTOCOL_ID = TProtocol("/ipfs/kad/1.0.0") class PeerRouting(IPeerRouting): @@ -62,7 +60,6 @@ class PeerRouting(IPeerRouting): """ self.host = host self.routing_table = routing_table - self.protocol_id = PROTOCOL_ID async def find_peer(self, peer_id: ID) -> PeerInfo | None: """ @@ -247,7 +244,7 @@ class PeerRouting(IPeerRouting): # Open a stream to the peer using the Kademlia protocol logger.debug(f"Opening stream to {peer} for closest peers query") try: - stream = await self.host.new_stream(peer, [self.protocol_id]) + stream = await self.host.new_stream(peer, [PROTOCOL_ID]) logger.debug(f"Stream opened to {peer}") except Exception as e: logger.warning(f"Failed to open stream to {peer}: {e}") diff --git a/libp2p/kad_dht/provider_store.py b/libp2p/kad_dht/provider_store.py index 00ac6010..5c34f0c7 100644 --- a/libp2p/kad_dht/provider_store.py +++ b/libp2p/kad_dht/provider_store.py @@ -29,6 +29,11 @@ from libp2p.peer.peerinfo import ( PeerInfo, ) +from .common import ( + ALPHA, + PROTOCOL_ID, + QUERY_TIMEOUT, +) from .pb.kademlia_pb2 import ( Message, ) @@ -40,9 +45,6 @@ logger = logging.getLogger("kademlia-example.provider_store") PROVIDER_RECORD_REPUBLISH_INTERVAL = 22 * 60 * 60 # 22 hours in seconds PROVIDER_RECORD_EXPIRATION_INTERVAL = 48 * 60 * 60 # 48 hours in seconds PROVIDER_ADDRESS_TTL = 30 * 60 # 30 minutes in seconds -PROTOCOL_ID = TProtocol("/ipfs/kad/1.0.0") -ALPHA = 3 # Number of parallel queries/advertisements -QUERY_TIMEOUT = 10 # Timeout for each query in seconds class ProviderRecord: diff --git a/libp2p/kad_dht/routing_table.py b/libp2p/kad_dht/routing_table.py index 4377c591..15b6721e 100644 --- a/libp2p/kad_dht/routing_table.py +++ b/libp2p/kad_dht/routing_table.py @@ -13,10 +13,9 @@ import trio from libp2p.abc import ( IHost, ) -from libp2p.custom_types import ( - TProtocol, +from libp2p.kad_dht.utils import ( + xor_distance, ) -from libp2p.kad_dht.utils import xor_distance from libp2p.peer.id import ( ID, ) @@ -24,6 +23,9 @@ from libp2p.peer.peerinfo import ( PeerInfo, ) +from .common import ( + PROTOCOL_ID, +) from .pb.kademlia_pb2 import ( Message, ) @@ -242,12 +244,9 @@ class KBucket: if not peer_info: raise ValueError(f"Peer {peer_id} not in bucket") - # Default protocol ID for Kademlia DHT - protocol_id = TProtocol("/ipfs/kad/1.0.0") - try: # Open a stream to the peer with the DHT protocol - stream = await self.host.new_stream(peer_id, [protocol_id]) + stream = await self.host.new_stream(peer_id, [PROTOCOL_ID]) try: # Create ping protobuf message diff --git a/libp2p/kad_dht/value_store.py b/libp2p/kad_dht/value_store.py index a2e54776..b79425fd 100644 --- a/libp2p/kad_dht/value_store.py +++ b/libp2p/kad_dht/value_store.py @@ -19,6 +19,10 @@ from libp2p.peer.id import ( ID, ) +from .common import ( + DEFAULT_TTL, + PROTOCOL_ID, +) from .pb.kademlia_pb2 import ( Message, ) @@ -26,10 +30,6 @@ from .pb.kademlia_pb2 import ( # logger = logging.getLogger("libp2p.kademlia.value_store") logger = logging.getLogger("kademlia-example.value_store") -# Default time to live for values in seconds (24 hours) -DEFAULT_TTL = 24 * 60 * 60 -PROTOCOL_ID = TProtocol("/ipfs/kad/1.0.0") - class ValueStore: """ diff --git a/libp2p/security/insecure/transport.py b/libp2p/security/insecure/transport.py index a230e970..cf92e8d9 100644 --- a/libp2p/security/insecure/transport.py +++ b/libp2p/security/insecure/transport.py @@ -1,4 +1,7 @@ +from collections.abc import Callable + from libp2p.abc import ( + IPeerStore, IRawConnection, ISecureConn, ) @@ -6,6 +9,7 @@ from libp2p.crypto.exceptions import ( MissingDeserializerError, ) from libp2p.crypto.keys import ( + KeyPair, PrivateKey, PublicKey, ) @@ -30,11 +34,15 @@ from libp2p.network.connection.exceptions import ( from libp2p.peer.id import ( ID, ) +from libp2p.peer.peerstore import ( + PeerStoreError, +) from libp2p.security.base_session import ( BaseSession, ) from libp2p.security.base_transport import ( BaseSecureTransport, + default_secure_bytes_provider, ) from libp2p.security.exceptions import ( HandshakeFailure, @@ -102,6 +110,7 @@ async def run_handshake( conn: IRawConnection, is_initiator: bool, remote_peer_id: ID | None, + peerstore: IPeerStore | None = None, ) -> ISecureConn: """Raise `HandshakeFailure` when handshake failed.""" msg = make_exchange_message(local_private_key.get_public_key()) @@ -164,7 +173,14 @@ async def run_handshake( conn=conn, ) - # TODO: Store `pubkey` and `peer_id` to `PeerStore` + # Store `pubkey` and `peer_id` to `PeerStore` + if peerstore is not None: + try: + peerstore.add_pubkey(received_peer_id, received_pubkey) + except PeerStoreError: + # If peer ID and pubkey don't match, it would have already been caught above + # This might happen if the peer is already in the store + pass return secure_conn @@ -175,6 +191,18 @@ class InsecureTransport(BaseSecureTransport): transport does not add any additional security. """ + def __init__( + self, + local_key_pair: KeyPair, + secure_bytes_provider: Callable[[int], bytes] | None = None, + peerstore: IPeerStore | None = None, + ) -> None: + # If secure_bytes_provider is None, use the default one + if secure_bytes_provider is None: + secure_bytes_provider = default_secure_bytes_provider + super().__init__(local_key_pair, secure_bytes_provider) + self.peerstore = peerstore + async def secure_inbound(self, conn: IRawConnection) -> ISecureConn: """ Secure the connection, either locally or by communicating with opposing @@ -183,8 +211,9 @@ class InsecureTransport(BaseSecureTransport): :return: secure connection object (that implements secure_conn_interface) """ + # For inbound connections, we don't know the remote peer ID yet return await run_handshake( - self.local_peer, self.local_private_key, conn, False, None + self.local_peer, self.local_private_key, conn, False, None, self.peerstore ) async def secure_outbound(self, conn: IRawConnection, peer_id: ID) -> ISecureConn: @@ -195,7 +224,7 @@ class InsecureTransport(BaseSecureTransport): :return: secure connection object (that implements secure_conn_interface) """ return await run_handshake( - self.local_peer, self.local_private_key, conn, True, peer_id + self.local_peer, self.local_private_key, conn, True, peer_id, self.peerstore ) diff --git a/newsfragments/631.feature.rst b/newsfragments/631.feature.rst new file mode 100644 index 00000000..1d88c779 --- /dev/null +++ b/newsfragments/631.feature.rst @@ -0,0 +1,7 @@ +Store public key and peer ID in peerstore during handshake + +Modified the InsecureTransport class to accept an optional peerstore parameter and updated the handshake process to store the received public key and peer ID in the peerstore when available. + +Added test cases to verify: +1. The peerstore remains unchanged when handshake fails due to peer ID mismatch +2. The handshake correctly adds a public key to a peer ID that already exists in the peerstore but doesn't have a public key yet diff --git a/tests/core/kad_dht/test_unit_peer_routing.py b/tests/core/kad_dht/test_unit_peer_routing.py index 72320b73..ffe20655 100644 --- a/tests/core/kad_dht/test_unit_peer_routing.py +++ b/tests/core/kad_dht/test_unit_peer_routing.py @@ -89,7 +89,6 @@ class TestPeerRouting: assert peer_routing.host == mock_host assert peer_routing.routing_table == mock_routing_table - assert peer_routing.protocol_id == PROTOCOL_ID @pytest.mark.trio async def test_find_peer_local_host(self, peer_routing, mock_host): diff --git a/tests/core/security/test_insecure_peerstore_integration.py b/tests/core/security/test_insecure_peerstore_integration.py new file mode 100644 index 00000000..9634fc69 --- /dev/null +++ b/tests/core/security/test_insecure_peerstore_integration.py @@ -0,0 +1,314 @@ +import pytest +import trio +from trio.testing import memory_stream_pair + +from libp2p.abc import IRawConnection +from libp2p.crypto.rsa import create_new_key_pair +from libp2p.peer.id import ID +from libp2p.peer.peerdata import PeerData +from libp2p.peer.peerstore import PeerStore +from libp2p.security.exceptions import HandshakeFailure +from libp2p.security.insecure.transport import InsecureTransport + + +# Adapter class to bridge between trio streams and libp2p raw connections +class TrioStreamAdapter(IRawConnection): + def __init__(self, send_stream, receive_stream, is_initiator: bool = False): + self.send_stream = send_stream + self.receive_stream = receive_stream + self.is_initiator = is_initiator + + async def write(self, data: bytes) -> None: + await self.send_stream.send_all(data) + + async def read(self, n: int | None = None) -> bytes: + if n is None or n == -1: + raise ValueError("Reading unbounded not supported") + return await self.receive_stream.receive_some(n) + + async def close(self) -> None: + await self.send_stream.aclose() + await self.receive_stream.aclose() + + def get_remote_address(self) -> tuple[str, int] | None: + # Return None since this is a test adapter without real network info + return None + + +@pytest.mark.trio +async def test_insecure_transport_stores_pubkey_in_peerstore(): + """ + Test that InsecureTransport stores the pubkey and peerid in + peerstore during handshake. + """ + # Create key pairs for both sides + local_key_pair = create_new_key_pair() + remote_key_pair = create_new_key_pair() + + # Create peer IDs + remote_peer_id = ID.from_pubkey(remote_key_pair.public_key) + + # Create peerstore + peerstore = PeerStore() + + # Create memory streams for communication + local_send, remote_receive = memory_stream_pair() + remote_send, local_receive = memory_stream_pair() + + # Create adapters + local_stream = TrioStreamAdapter(local_send, local_receive, is_initiator=True) + remote_stream = TrioStreamAdapter(remote_send, remote_receive, is_initiator=False) + + # Create transports + local_transport = InsecureTransport(local_key_pair, peerstore=peerstore) + remote_transport = InsecureTransport(remote_key_pair, peerstore=None) + + # Run handshake + async def run_local_handshake(nursery_results): + with trio.move_on_after(5): + local_conn = await local_transport.secure_outbound( + local_stream, remote_peer_id + ) + nursery_results["local"] = local_conn + + async def run_remote_handshake(nursery_results): + with trio.move_on_after(5): + remote_conn = await remote_transport.secure_inbound(remote_stream) + nursery_results["remote"] = remote_conn + + nursery_results = {} + async with trio.open_nursery() as nursery: + nursery.start_soon(run_local_handshake, nursery_results) + nursery.start_soon(run_remote_handshake, nursery_results) + await trio.sleep(0.1) # Give tasks a chance to finish + + local_conn = nursery_results.get("local") + remote_conn = nursery_results.get("remote") + + assert local_conn is not None, "Local handshake failed" + assert remote_conn is not None, "Remote handshake failed" + + # Verify that the remote peer ID is in the peerstore + assert remote_peer_id in peerstore.peer_ids() + + # Verify that the public key was stored and matches + stored_pubkey = peerstore.pubkey(remote_peer_id) + assert stored_pubkey is not None + assert stored_pubkey.serialize() == remote_key_pair.public_key.serialize() + + +@pytest.mark.trio +async def test_insecure_transport_without_peerstore(): + """ + Test that InsecureTransport works correctly + without a peerstore. + """ + # Create key pairs for both sides + local_key_pair = create_new_key_pair() + remote_key_pair = create_new_key_pair() + + # Create peer IDs + remote_peer_id = ID.from_pubkey(remote_key_pair.public_key) + + # Create memory streams for communication + local_send, remote_receive = memory_stream_pair() + remote_send, local_receive = memory_stream_pair() + + # Create adapters + local_stream = TrioStreamAdapter(local_send, local_receive, is_initiator=True) + remote_stream = TrioStreamAdapter(remote_send, remote_receive, is_initiator=False) + + # Create transports without peerstore + local_transport = InsecureTransport(local_key_pair, peerstore=None) + remote_transport = InsecureTransport(remote_key_pair, peerstore=None) + + # Run handshake + async def run_local_handshake(nursery_results): + with trio.move_on_after(5): + local_conn = await local_transport.secure_outbound( + local_stream, remote_peer_id + ) + nursery_results["local"] = local_conn + + async def run_remote_handshake(nursery_results): + with trio.move_on_after(5): + remote_conn = await remote_transport.secure_inbound(remote_stream) + nursery_results["remote"] = remote_conn + + nursery_results = {} + async with trio.open_nursery() as nursery: + nursery.start_soon(run_local_handshake, nursery_results) + nursery.start_soon(run_remote_handshake, nursery_results) + await trio.sleep(0.1) # Give tasks a chance to finish + + local_conn = nursery_results.get("local") + remote_conn = nursery_results.get("remote") + + # Verify that handshake still works without a peerstore + assert local_conn is not None, "Local handshake failed" + assert remote_conn is not None, "Remote handshake failed" + + +@pytest.mark.trio +async def test_peerstore_unchanged_when_handshake_fails(): + """ + Test that the peerstore remains unchanged if the handshake fails + due to a peer ID mismatch. + """ + # Create key pairs for both sides + local_key_pair = create_new_key_pair() + remote_key_pair = create_new_key_pair() + + # Create a third key pair to cause a mismatch + mismatch_key_pair = create_new_key_pair() + + # Create peer IDs + remote_peer_id = ID.from_pubkey(remote_key_pair.public_key) + mismatch_peer_id = ID.from_pubkey(mismatch_key_pair.public_key) + + # Create peerstore and add some initial data to verify it stays unchanged + peerstore = PeerStore() + + # Store some initial data in peerstore to verify it remains unchanged + initial_key_pair = create_new_key_pair() + initial_peer_id = ID.from_pubkey(initial_key_pair.public_key) + peerstore.add_pubkey(initial_peer_id, initial_key_pair.public_key) + + # Remember the initial state of the peerstore + initial_peer_ids = set(peerstore.peer_ids()) + + # Create memory streams for communication + local_send, remote_receive = memory_stream_pair() + remote_send, local_receive = memory_stream_pair() + + # Create adapters + local_stream = TrioStreamAdapter(local_send, local_receive, is_initiator=True) + remote_stream = TrioStreamAdapter(remote_send, remote_receive, is_initiator=False) + + # Create transports + local_transport = InsecureTransport(local_key_pair, peerstore=peerstore) + remote_transport = InsecureTransport(remote_key_pair, peerstore=None) + + # Run handshake with mismatched peer_id + # (expecting remote_peer_id but sending mismatch_peer_id to cause a failure) + async def run_local_handshake(nursery_results): + with trio.move_on_after(5): + try: + # Pass mismatch_peer_id instead of remote_peer_id + # to cause a handshake failure + local_conn = await local_transport.secure_outbound( + local_stream, mismatch_peer_id + ) + nursery_results["local"] = local_conn + except HandshakeFailure: + nursery_results["local_error"] = True + + async def run_remote_handshake(nursery_results): + with trio.move_on_after(5): + try: + remote_conn = await remote_transport.secure_inbound(remote_stream) + nursery_results["remote"] = remote_conn + except HandshakeFailure: + nursery_results["remote_error"] = True + + nursery_results = {} + async with trio.open_nursery() as nursery: + nursery.start_soon(run_local_handshake, nursery_results) + nursery.start_soon(run_remote_handshake, nursery_results) + await trio.sleep(0.1) + + # Verify that at least one side encountered an error + assert "local_error" in nursery_results or "remote_error" in nursery_results, ( + "Expected handshake to fail due to peer ID mismatch" + ) + + # Verify that the peerstore remains unchanged + current_peer_ids = set(peerstore.peer_ids()) + assert current_peer_ids == initial_peer_ids, ( + "Peerstore should remain unchanged when handshake fails" + ) + + # Verify that neither the remote_peer_id nor mismatch_peer_id was added + assert remote_peer_id not in peerstore.peer_ids(), ( + "Remote peer ID should not be added on handshake failure" + ) + assert mismatch_peer_id not in peerstore.peer_ids(), ( + "Mismatch peer ID should not be added on handshake failure" + ) + + +@pytest.mark.trio +async def test_handshake_adds_pubkey_to_existing_peer(): + """ + Test that when a peer ID already exists in the peerstore but without + a public key, the handshake correctly adds the public key. + + This tests the case where we might have a peer ID from another source + (like a routing table) but don't yet have its public key. + """ + # Create key pairs for both sides + local_key_pair = create_new_key_pair() + remote_key_pair = create_new_key_pair() + + # Create peer IDs + remote_peer_id = ID.from_pubkey(remote_key_pair.public_key) + + # Create peerstore and add the peer ID without a public key + peerstore = PeerStore() + + # Add the peer ID to the peerstore without its public key + # (adding an address for the peer, which creates the peer entry) + # This simulates having discovered a peer through DHT or other means + # without having its public key yet + peerstore.peer_data_map[remote_peer_id] = PeerData() + + # Verify initial state - the peer ID should exist but without a public key + assert remote_peer_id in peerstore.peer_ids() + with pytest.raises(Exception): + peerstore.pubkey(remote_peer_id) + + # Create memory streams for communication + local_send, remote_receive = memory_stream_pair() + remote_send, local_receive = memory_stream_pair() + + # Create adapters + local_stream = TrioStreamAdapter(local_send, local_receive, is_initiator=True) + remote_stream = TrioStreamAdapter(remote_send, remote_receive, is_initiator=False) + + # Create transports + local_transport = InsecureTransport(local_key_pair, peerstore=peerstore) + remote_transport = InsecureTransport(remote_key_pair, peerstore=None) + + # Run handshake + async def run_local_handshake(nursery_results): + with trio.move_on_after(5): + local_conn = await local_transport.secure_outbound( + local_stream, remote_peer_id + ) + nursery_results["local"] = local_conn + + async def run_remote_handshake(nursery_results): + with trio.move_on_after(5): + remote_conn = await remote_transport.secure_inbound(remote_stream) + nursery_results["remote"] = remote_conn + + nursery_results = {} + async with trio.open_nursery() as nursery: + nursery.start_soon(run_local_handshake, nursery_results) + nursery.start_soon(run_remote_handshake, nursery_results) + await trio.sleep(0.1) # Give tasks a chance to finish + + local_conn = nursery_results.get("local") + remote_conn = nursery_results.get("remote") + + # Verify that the handshake succeeded + assert local_conn is not None, "Local handshake failed" + assert remote_conn is not None, "Remote handshake failed" + + # Verify that the peer ID is still in the peerstore + assert remote_peer_id in peerstore.peer_ids() + + # Verify that the public key was added + stored_pubkey = peerstore.pubkey(remote_peer_id) + assert stored_pubkey is not None + assert stored_pubkey.serialize() == remote_key_pair.public_key.serialize() diff --git a/tests/core/stream_muxer/test_yamux.py b/tests/core/stream_muxer/test_yamux.py index 81d05676..44428851 100644 --- a/tests/core/stream_muxer/test_yamux.py +++ b/tests/core/stream_muxer/test_yamux.py @@ -79,7 +79,7 @@ async def secure_conn_pair(key_pair, peer_id): client_rw = TrioStreamAdapter(client_send, client_receive, is_initiator=True) server_rw = TrioStreamAdapter(server_send, server_receive, is_initiator=False) - insecure_transport = InsecureTransport(key_pair) + insecure_transport = InsecureTransport(key_pair, peerstore=None) async def run_outbound(nursery_results): with trio.move_on_after(5): diff --git a/tests/utils/factories.py b/tests/utils/factories.py index 1beac861..75639e36 100644 --- a/tests/utils/factories.py +++ b/tests/utils/factories.py @@ -161,8 +161,8 @@ def noise_handshake_payload_factory() -> NoiseHandshakePayload: ) -def plaintext_transport_factory(key_pair: KeyPair) -> ISecureTransport: - return InsecureTransport(key_pair) +def plaintext_transport_factory(key_pair: KeyPair, peerstore=None) -> ISecureTransport: + return InsecureTransport(key_pair, peerstore=peerstore) def secio_transport_factory(key_pair: KeyPair) -> ISecureTransport: