Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

protocols/kad: Support client mode #2032

Closed
aschmahmann opened this issue Apr 5, 2021 · 6 comments · Fixed by #3877
Closed

protocols/kad: Support client mode #2032

aschmahmann opened this issue Apr 5, 2021 · 6 comments · Fixed by #3877
Assignees
Labels
difficulty:moderate priority:important The changes needed are critical for libp2p, or are blocking another project

Comments

@aschmahmann
Copy link

From what I understand from #2025 (reply in thread) the Kademlia implementation does not support client mode. Client mode is quite useful as it allows lower quality (e.g. intermittent availability, high latency, low bandwidth, low CPU/RAM/Storage, etc.) nodes to utilize the DHT for discovery without decreasing the quality of the network.

This feature has been very helpful in go-libp2p and in the various consumers of it such as go-ipfs.


To implement client mode all that is really required is that the node does not advertise the DHT protocol (e.g. /ipfs/kad/1.0.0). Additionally, if the node is able to switch between client and server mode at runtime then updates to the supported protocols should be communicated via identify-push/identify-delta.

Once we have the basic client-server mode switching then as a follow up it might be a good idea to, as go-libp2p does, have an "automatic" mode that switches between client and server mode based on educated guessing about what is appropriate for the user (e.g. peers behind relays probably shouldn't be servers, and peers who haven't been online for a while and are stable probably shouldn't either).

@koivunej
Copy link
Contributor

koivunej commented Apr 6, 2021

I remember searching for specs/writeup regarding this behaviour at the time of introduction to go-ipfs (0.5 maybe?). Closest I can still find for in libp2p/specs or ipfs/go-ipfs this is libp2p/specs#108 which doesn't contain "client." @aschmahmann could the spec be in some other place? However your description of it does sound simple enough.

@mxinden
Copy link
Member

mxinden commented Jul 21, 2021

Adding a couple of notes here to help getting started.

For the greater picture I recommend reading the Kademlia paper and the Kademlia specification.

As a first iteration, I would recommend making this a configuration option via KademliaConfig and KademliaHandlerConfig.

When in client mode one can use DeniedUpgrade in order to signal that one does not offer the Kademlia protocol. One would need to return DeniedUpgrade in <KademliaHandlerProto as IntoProtocolsHandler>::inbound_protocol and <KademliaHandler as ProtocolsHandler>::listen_protocol.

A server already detects whether the remote supports the Kademlia protocol via the ProtocolStatus construct in handler.rs. Today we confirm a remote both on successful outbound and inbound Substream negotiation (see inject_fully_negotiated_outbound and inject_fully_negotiated_inbound). To properly support client and server mode, one should only confirm a remote on inject_fully_negotiated_outbound.

@mxinden
Copy link
Member

mxinden commented Jul 21, 2021

Assigning @whereistejas here. Thanks for offering your help.


Edit: I can't assign you directly. Though I guess the comment here is good enough.

@thomaseizinger
Copy link
Contributor

I am now working on this, albeit several layers "down the stack".

In particular, to ship this we need a way for all connections handlers on a connection to communicate. That is somewhat tracked in #2680 (the name is stale as the discussion evolved). There is a draft in #3651.

A dependency of that PR is #2831 which I am working on in #3745.

@mxinden
Copy link
Member

mxinden commented Apr 25, 2023

Discoverability of addresses of clients in client-mode

Roles

  • Server node S
  • Client node C
  • Other node O

Problem

With Kademlia client-mode C will no longer be added to S's routing table. In the case where O asks S of the addresses of C, via the FIND_NODE RPC, S will not be able to tell O the addresses of C as C is not stored in S's routing table.

Possible Solutions

  1. Have S keep a cache of addresses of clients like we do in libp2p-identify.

    /// The addresses of all peers that we have discovered.
    discovered_peers: PeerCache,

  2. Add some mechanism where the libp2p-kad NetworkBehaviour can ask the other NetworkBehaviour implementations for addresses of C, similar to the NetworkBehaviour::addresses_of_peer method.

@thomaseizinger
Copy link
Contributor

Discussed out-of-band with @mxinden : This can be shipped as an additional PR on top of client-mode in a backwards-compatible way, thus deferring for the initial implementation!

mergify bot pushed a commit that referenced this issue May 24, 2023
Previously, a `NetworkBehaviour` could report an `AddressScore` for an external address. This score was a `u32` and addresses would be ranked amongst those.

In reality, an address is either confirmed to be publicly reachable (via a protocol such as AutoNAT) or merely represents a candidate that might be an external address. In a way, addresses are guilty (private) until proven innocent (publicly reachable).

When a `NetworkBehaviour` reports an address candidate, we perform address translation on it to potentially correct for ephemeral ports of TCP. These candidates are then injected back into the `NetworkBehaviour`. Protocols such as AutoNAT can use these addresses as a source for probing their NAT status. Once confirmed, they can emit a `ToSwarm::ExternalAddrConfirmed` event which again will be passed to all `NetworkBehaviour`s.

This simplified approach will allow us implement Kademlia's client-mode (#2032) without additional configuration options: As soon as an address is reported as publicly reachable, we can activate server-mode for that connection.

Related: #3877.
Related: #3953.
Related: #2032.
Related: libp2p/go-libp2p#2229.

Co-authored-by: Max Inden <[email protected]>

Pull-Request: #3954.
@mergify mergify bot closed this as completed in #3877 May 31, 2023
mergify bot pushed a commit that referenced this issue May 31, 2023
Currently, the kademlia behaviour can only learn that the remote node supports kademlia on a particular connection if we successfully negotiate a stream to them.

Using the newly introduced abstractions from #3651, we don't have to attempt to establish a stream to the remote to learn whether they support kademlia on a connection but we can directly learn it from the `ConnectionEvent::RemoteProtocolsChange` event. This happens directly once a connection is established which should overall benefit the DHT.

Clients do not advertise the kademlia protocol and thus we will immediately learn that a given connection is not suitable for kadmelia requests. We may receive inbound messages from it but this does not affect the routing table.

Resolves: #2032.

Pull-Request: #3877.
umgefahren pushed a commit to umgefahren/rust-libp2p that referenced this issue Mar 8, 2024
Previously, a `NetworkBehaviour` could report an `AddressScore` for an external address. This score was a `u32` and addresses would be ranked amongst those.

In reality, an address is either confirmed to be publicly reachable (via a protocol such as AutoNAT) or merely represents a candidate that might be an external address. In a way, addresses are guilty (private) until proven innocent (publicly reachable).

When a `NetworkBehaviour` reports an address candidate, we perform address translation on it to potentially correct for ephemeral ports of TCP. These candidates are then injected back into the `NetworkBehaviour`. Protocols such as AutoNAT can use these addresses as a source for probing their NAT status. Once confirmed, they can emit a `ToSwarm::ExternalAddrConfirmed` event which again will be passed to all `NetworkBehaviour`s.

This simplified approach will allow us implement Kademlia's client-mode (libp2p#2032) without additional configuration options: As soon as an address is reported as publicly reachable, we can activate server-mode for that connection.

Related: libp2p#3877.
Related: libp2p#3953.
Related: libp2p#2032.
Related: libp2p/go-libp2p#2229.

Co-authored-by: Max Inden <[email protected]>

Pull-Request: libp2p#3954.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
difficulty:moderate priority:important The changes needed are critical for libp2p, or are blocking another project
Projects
None yet
4 participants