-
Notifications
You must be signed in to change notification settings - Fork 4
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
Protocol interface refinement #98
Conversation
Some thoughts about the protocol interfaces:
|
|
|
|
An alternate proposal that would allow extensible configuration: // RoutingProtocol defines the methods necessary for routing in a network.
type RoutingProtocol[K Key[K], N NodeID[K], A Address[A]] interface {
// FindNode sends a message to a node requesting that it return its closest nodes to the target key.
FindNode(ctx context.Context, to N, target K, cfg *RequestConfig) ([]NodeInfo[K, A], error)
// Ping sends a message to a node to perform a liveness check.
Ping(ctx context.Context, to N, cfg *RequestConfig) error
}
// RecordProtocol defines the methods for storing and retrieving records in a network.
type RecordProtocol[K Key[K], N NodeID[K], A Address[A]] interface {
// Get sends a message to a node requesting that it return the records associated with the target key.
// The node may also return a list of closer nodes that may also store records for that key.
Get(ctx context.Context, to N, target K, cfg *RequestConfig) ([]Record, []NodeInfo[K, A], error)
// Put sends a message to a node requesting that it store the record.
Put(ctx context.Context, to N, record Record, cfg *RequestConfig) error
}
// RequestConfig defines common configuration options for protocol requests.
type RequestConfig struct {
// Deadline sets the time by which the request must be completed.
Deadline time.Time
// could be extended in future to set a request trace to measure latency profile
} Note I used Deadline rather then Timeout. In general deadlines should be preferred, especially when we are scheduling actions that may not be executed immediately. The caller may have its own deadline so if there is a delay starting the request then the timeout won't correspond with the caller's expectations. |
I like the idea of having a single go-kademlia only needs the request to contain the target kademlia key (and termination condition, which can be a closure), and the response needs to have a |
My thinking was that you'd need to implement the
I would advocate for using context deadlines and not introducing a new mechanism to configure timeouts etc.
👍 though the Ping protocol is controversial in the libp2p case: libp2p/go-libp2p-kad-dht#810 (comment). In the general go-kademlia context, it makes sense IMO.
That's cool and addresses my comment above 👍
Accoding to the original Kademlia paper, the number of closer nodes is a network wide parameter. I don't think this should be configurable. If go-kademlia -> go-dht then it might make sense - though, I'd need to think about it a bit more.
Shouldn't this rather be part of the protocol like a
In go-libp2p-kad-dht the key is on the record. So, alternatively, we could require a |
IMO this interface should be defined on the However, when we will implement a more optimized query mechanism, the interface may have different needs. A concrete example of another query mechanism, is using a low concurrency parameter for the first hops of the lookup, and a larger concurrency parameter for the last hops, optimizing network usage. Another example is the use of soft timeouts, we could have a query mechanism with a concurrency With both examples, it seems to me like they could all share the same interface described in this PR. This interface could be the generic one (that all |
As a first |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO the dependency should be as follows (A --> B
means A
depends on an implementation of B
):
A query
should be given the target Kademlia Key as well as the marshalled message to be sent. It is the responsibility of the DHT implementation to create the message (and potentially ask for more/less than 20 closer peers). A query_builder
could be used to build queries that use the same routing_table
, scheduler
, transport_endpoint
, concurrency_factor
, timeout
etc.
Again, the PUT
operation shouldn't belong to go-kademlia, because what it is doing is simply passing a message formatted by the DHT implementation down to a transport endpoint. There is no need to use any component of go-kademlia for this.
The simplequery
package should be a good starting point.
My main takeover is that go-kademlia is supposed to be a toolbox, and hence shouldn't have a massive package defining all possible interfaces on which all users would depend. But rather to have small packages that can easily be imported and swapped with another implementation. e.g you don't like the routing table implementation, the key format, the message endpoint, the query mechanism? no problem, go ahead and implement yours, you're good to go as long as it implements the minimal interface. So we shouldn't have general PUT
and GET
interfaces for go-kademlia, but rather expose the right functions in the right modules. In this case we can define a query
interface, but it isn't even required, because no other component of go-kademlia depends on query
.
Change the return values of FindNode and Get. We need to return a list of NodeInfo instead of a list of NodeID.