On alternative designs of libp2p-core
and libp2p-swarm
#2078
Replies: 3 comments 3 replies
-
First off, thanks for the detailed write-up @thomaseizinger! Happy to see these new ideas.
Correct.
What these implementations then handle the coordination between substreams in their
As well as multiple connections to the same peer.
Agreed that the "empty" state is somewhat strange and also in combination with keep-alive handling error prone. |
Beta Was this translation helpful? Give feedback.
-
Just an aside, a |
Beta Was this translation helpful? Give feedback.
-
I've sketched out something in this branch here: https://github.com/comit-network/rust-libp2p/blob/single-substream-handler/swarm/src/protocols_handler/substream.rs It did turn out slightly different than originally anticipated. As you've probably noticed, my original intention was to change That is essentially what the above module does. It defines a The module is slightly opinionated in that it assumes:
I think such a module could be very helpful for various kinds of protocols:
Overall, I think such an abstraction would serve as a better foundation for building new protocols than the current Similarly, any event is essentially uniquely attributable to a single substream: This opens up an issue where notifying the wrong handler will end up not delivering the message. In other words, there is a potential problem here: If Curious to hear your thoughts @mxinden ! |
Beta Was this translation helpful? Give feedback.
-
Having worked with rust-libp2p for quite some time now, I noticed that some things are harder to achieve than others and I've been wondering what we can do about that.
Specifically, the abstractions of
NetworkBehaviour
andProtocolsHandler
are essentially driven by the design ofConnectionHandler
in that theConnectionHandler
semantically out-lives all substreams of a connection. I believe that this particular aspect makes it cumbersome to implement protocols that don't need to take advantage of this additional state.For example, any protocol that uses short-lived substreams (identify, ping, rendezvous, request-response and several IPFS ones if I am not mistaken) are harder to implement because all abstraction layers need to deal with the state prior and post the substream's existence.
If there were an abstraction that is tied to the lifetime of a single substream, implementing these protocols could be as simple as:
fn(substream) -> (fn(request) -> response))
.One downside if only such a model is provided is that it is next to impossible to implement protocols that depend on the ability to orchestrate and coordinate between multiple substreams. Examples for this are gossipsub and kademlia.
What seems to be the million-dollar question is: What should the core primitives within libp2p-core look like to allow for both kinds of protocols in an easy way?
To get closer to this answer, I think it would be helpful if we can collect what specific parts and designs of the codebase are already considered in need of an overhaul. From looking at the code, one can see some duplication in the reporting of events.
NetworkEvent
andSwarmEvent
for example a very similar. APoolEvent
in turn is reasonably similar to aNetworkEvent
. AManagerEvent
is very similar to aPoolEvent
.As a starting point for the discussion, I would like to propose the following:
ProtocolsHandler
currently could - in theory - deal with multiple substreams of the same peer simultaneously. Looking at existing implementations though, this is rarely considered. For example, gossipsub simply replaces the current substream with the new one.NetworkBehaviour
already has to deal with the concept of multiple connections by the nature of dealing with multiple peers.Is there a way of "relieving" a
ProtocolsHandler
from having to deal with potentially multiple substreams? If we tie the lifetime of aProtocolsHandler
to that of a substream (and create a new instance per substream), I think its implementations would become a easier:ProtocolsHandler
to create a new instance using the given negotiated substream (i.e.ProtocolsHandler::new_inbound(substream)
) would avoid annoying "empty" states.ProtocolsHandler
to a single substream at all times avoids complexity in that protocol implementors don't need to consider this aspect because it is handled within libp2p-core.Please do point out if I misunderstood anything in the existing design. I am also very happy to submit patches if we can find consensus on how things can/should be changed.
Beta Was this translation helpful? Give feedback.
All reactions