Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions libp2p/host/basic_host.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,11 @@ async def _swarm_stream_handler(self, net_stream: INetStream) -> None:
protocol, handler = await self.multiselect.negotiate(
MultiselectCommunicator(net_stream), self.negotiate_timeout
)
if protocol is None:
await net_stream.reset()
raise StreamFailure(
"Failed to negotiate protocol: no protocol selected"
)
except MultiselectError as error:
peer_id = net_stream.muxed_conn.peer_id
logger.debug(
Expand Down
4 changes: 3 additions & 1 deletion libp2p/security/security_multistream.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ async def select_transport(
# Select protocol if non-initiator
protocol, _ = await self.multiselect.negotiate(communicator)
if protocol is None:
raise MultiselectError("fail to negotiate a security protocol")
raise MultiselectError(
"fail to negotiate a security protocol: no protocl selected"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"fail to negotiate a security protocol: no protocl selected"
"Failed to negotiate a security protocol: no protocol selected"

)
# Return transport from protocol
return self.transports[protocol]
4 changes: 3 additions & 1 deletion libp2p/stream_muxer/muxer_multistream.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ async def select_transport(self, conn: IRawConnection) -> TMuxerClass:
else:
protocol, _ = await self.multiselect.negotiate(communicator)
if protocol is None:
raise MultiselectError("fail to negotiate a stream muxer protocol")
raise MultiselectError(
"fail to negotiate a stream muxer protocol: no protocol selected"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"fail to negotiate a stream muxer protocol: no protocol selected"
"Failed to negotiate a stream muxer protocol: no protocol selected"

)
return self.transports[protocol]

async def new_conn(self, conn: ISecureConn, peer_id: ID) -> IMuxedConn:
Expand Down
1 change: 1 addition & 0 deletions newsfragments/837.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added multiselect type consistency in negotiate method. Updates all the usages of the method.
37 changes: 37 additions & 0 deletions tests/core/host/test_basic_host.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
from unittest.mock import (
AsyncMock,
MagicMock,
)

import pytest

from libp2p import (
new_swarm,
)
Expand All @@ -10,6 +17,9 @@
from libp2p.host.defaults import (
get_default_protocols,
)
from libp2p.host.exceptions import (
StreamFailure,
)


def test_default_protocols():
Expand All @@ -22,3 +32,30 @@ def test_default_protocols():
# NOTE: comparing keys for equality as handlers may be closures that do not compare
# in the way this test is concerned with
assert handlers.keys() == get_default_protocols(host).keys()


@pytest.mark.trio
async def test_swarm_stream_handler_no_protocol_selected(monkeypatch):
key_pair = create_new_key_pair()
swarm = new_swarm(key_pair)
host = BasicHost(swarm)

# Create a mock net_stream
net_stream = MagicMock()
net_stream.reset = AsyncMock()
net_stream.muxed_conn.peer_id = "peer-test"

# Monkeypatch negotiate to simulate "no protocol selected"
async def fake_negotiate(comm, timeout):
return None, None

monkeypatch.setattr(host.multiselect, "negotiate", fake_negotiate)

# Now run the handler and expect StreamFailure
with pytest.raises(
StreamFailure, match="Failed to negotiate protocol: no protocol selected"
):
await host._swarm_stream_handler(net_stream)

# Ensure reset was called since negotiation failed
net_stream.reset.assert_awaited()
Loading