Skip to content

p2p/discover: expose discv5 functions for portal JSON-RPC interface #31117

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

Merged
merged 4 commits into from
Mar 13, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion cmd/devp2p/discv4cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ func discv4Ping(ctx *cli.Context) error {
defer disc.Close()

start := time.Now()
if err := disc.Ping(n); err != nil {
if _, err := disc.Ping(n); err != nil {
return fmt.Errorf("node didn't respond: %v", err)
}
fmt.Printf("node responded to ping (RTT %v).\n", time.Since(start))
Expand Down
3 changes: 2 additions & 1 deletion cmd/devp2p/discv5cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ func discv5Ping(ctx *cli.Context) error {
disc, _ := startV5(ctx)
defer disc.Close()

fmt.Println(disc.Ping(n))
_, err := disc.Ping(n)
fmt.Println(err)
return nil
}

Expand Down
8 changes: 8 additions & 0 deletions p2p/discover/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -694,3 +694,11 @@ func pushNode(list []*tableNode, n *tableNode, max int) ([]*tableNode, *tableNod
list[0] = n
return list, removed
}

// deleteNode removes a node from the table.
func (tab *Table) deleteNode(n *enode.Node) {
tab.mutex.Lock()
defer tab.mutex.Unlock()
b := tab.bucket(n.ID())
tab.deleteInBucket(b, n.ID())
}
19 changes: 13 additions & 6 deletions p2p/discover/v4_udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,6 @@ func (t *UDPv4) ourEndpoint() v4wire.Endpoint {
return v4wire.NewEndpoint(addr, uint16(node.TCP()))
}

// Ping sends a ping message to the given node.
func (t *UDPv4) Ping(n *enode.Node) error {
_, err := t.ping(n)
return err
}

// ping sends a ping message to the given node and waits for a reply.
func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) {
addr, ok := n.UDPEndpoint()
Expand All @@ -229,6 +223,19 @@ func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) {
return seq, err
}

// Ping calls PING on a node and waits for a PONG response.
func (t *UDPv4) Ping(n *enode.Node) (pong *v4wire.Pong, err error) {
addr, ok := n.UDPEndpoint()
if !ok {
return nil, errNoUDPEndpoint
}
rm := t.sendPing(n.ID(), addr, nil)
if err = <-rm.errc; err == nil {
pong = rm.reply.(*v4wire.Pong)
}
return pong, err
}

// sendPing sends a ping message to the given node and invokes the callback
// when the reply arrives.
func (t *UDPv4) sendPing(toid enode.ID, toaddr netip.AddrPort, callback func()) *replyMatcher {
Expand Down
82 changes: 66 additions & 16 deletions p2p/discover/v5_udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,6 @@ func (t *UDPv5) Close() {
})
}

// Ping sends a ping message to the given node.
func (t *UDPv5) Ping(n *enode.Node) error {
_, err := t.ping(n)
return err
}

// Resolve searches for a specific node with the given ID and tries to get the most recent
// version of the node record for it. It returns n if the node could not be resolved.
func (t *UDPv5) Resolve(n *enode.Node) *enode.Node {
Expand All @@ -226,6 +220,36 @@ func (t *UDPv5) Resolve(n *enode.Node) *enode.Node {
return n
}

// ResolveNodeId searches for a specific Node with the given ID.
// It returns nil if the nodeId could not be resolved.
func (t *UDPv5) ResolveNodeId(id enode.ID) *enode.Node {
if id == t.Self().ID() {
return t.Self()
}

n := t.tab.getNode(id)
if n != nil {
// Try asking directly. This works if the Node is still responding on the endpoint we have.
if resp, err := t.RequestENR(n); err == nil {
return resp
}
}

// Otherwise do a network lookup.
result := t.Lookup(id)
for _, rn := range result {
if rn.ID() == id {
if n != nil && rn.Seq() <= n.Seq() {
return n
} else {
return rn
}
}
}

return n
}

// AllNodes returns all the nodes stored in the local table.
func (t *UDPv5) AllNodes() []*enode.Node {
t.tab.mutex.Lock()
Expand All @@ -240,7 +264,18 @@ func (t *UDPv5) AllNodes() []*enode.Node {
return nodes
}

// LocalNode returns the current local node running the
// AddKnownNode adds a node to the routing table.
// The function should be used for testing only.
func (t *UDPv5) AddKnownNode(n *enode.Node) bool {
return t.tab.addFoundNode(n, true)
}

// DeleteNode removes a node from the routing table. Used for Portal discv5 DeleteEnr API.
func (t *UDPv5) DeleteNode(n *enode.Node) {
t.tab.deleteNode(n)
}

// LocalNode returns the current local Node running the
// protocol.
func (t *UDPv5) LocalNode() *enode.LocalNode {
return t.localNode
Expand Down Expand Up @@ -328,7 +363,7 @@ func (t *UDPv5) lookupWorker(destNode *enode.Node, target enode.ID) ([]*enode.No
err error
)
var r []*enode.Node
r, err = t.findnode(destNode, dists)
r, err = t.Findnode(destNode, dists)
if errors.Is(err, errClosed) {
return nil, err
}
Expand Down Expand Up @@ -359,21 +394,31 @@ func lookupDistances(target, dest enode.ID) (dists []uint) {

// ping calls PING on a node and waits for a PONG response.
func (t *UDPv5) ping(n *enode.Node) (uint64, error) {
pong, err := t.Ping(n)
if err != nil {
return 0, err
}

return pong.ENRSeq, nil
}

// Ping calls PING on a node and waits for a PONG response.
func (t *UDPv5) Ping(n *enode.Node) (*v5wire.Pong, error) {
req := &v5wire.Ping{ENRSeq: t.localNode.Node().Seq()}
resp := t.callToNode(n, v5wire.PongMsg, req)
defer t.callDone(resp)

select {
case pong := <-resp.ch:
return pong.(*v5wire.Pong).ENRSeq, nil
return pong.(*v5wire.Pong), nil
case err := <-resp.err:
return 0, err
return nil, err
}
}

// RequestENR requests n's record.
func (t *UDPv5) RequestENR(n *enode.Node) (*enode.Node, error) {
nodes, err := t.findnode(n, []uint{0})
nodes, err := t.Findnode(n, []uint{0})
if err != nil {
return nil, err
}
Expand All @@ -383,8 +428,8 @@ func (t *UDPv5) RequestENR(n *enode.Node) (*enode.Node, error) {
return nodes[0], nil
}

// findnode calls FINDNODE on a node and waits for responses.
func (t *UDPv5) findnode(n *enode.Node, distances []uint) ([]*enode.Node, error) {
// Findnode calls FINDNODE on a node and waits for responses.
func (t *UDPv5) Findnode(n *enode.Node, distances []uint) ([]*enode.Node, error) {
resp := t.callToNode(n, v5wire.NodesMsg, &v5wire.Findnode{Distances: distances})
return t.waitForNodes(resp, distances)
}
Expand Down Expand Up @@ -736,8 +781,8 @@ func (t *UDPv5) handleCallResponse(fromID enode.ID, fromAddr netip.AddrPort, p v
return true
}

// getNode looks for a node record in table and database.
func (t *UDPv5) getNode(id enode.ID) *enode.Node {
// GetNode looks for a node record in table and database.
func (t *UDPv5) GetNode(id enode.ID) *enode.Node {
if n := t.tab.getNode(id); n != nil {
return n
}
Expand All @@ -747,6 +792,11 @@ func (t *UDPv5) getNode(id enode.ID) *enode.Node {
return nil
}

// Nodes returns the nodes in the routing table.
func (t *UDPv5) Nodes() [][]BucketNode {
return t.tab.Nodes()
}

// handle processes incoming packets according to their message type.
func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr netip.AddrPort) {
switch p := p.(type) {
Expand Down Expand Up @@ -776,7 +826,7 @@ func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr netip.AddrPort
func (t *UDPv5) handleUnknown(p *v5wire.Unknown, fromID enode.ID, fromAddr netip.AddrPort) {
challenge := &v5wire.Whoareyou{Nonce: p.Nonce}
crand.Read(challenge.IDNonce[:])
if n := t.getNode(fromID); n != nil {
if n := t.GetNode(fromID); n != nil {
challenge.Node = n
challenge.RecordSeq = n.Seq()
}
Expand Down
4 changes: 2 additions & 2 deletions p2p/discover/v5_udp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ func TestUDPv5_findnodeCall(t *testing.T) {
)
go func() {
var err error
response, err = test.udp.findnode(remote, distances)
response, err = test.udp.Findnode(remote, distances)
done <- err
}()

Expand Down Expand Up @@ -398,7 +398,7 @@ func TestUDPv5_callTimeoutReset(t *testing.T) {
done = make(chan error, 1)
)
go func() {
_, err := test.udp.findnode(remote, []uint{distance})
_, err := test.udp.Findnode(remote, []uint{distance})
done <- err
}()

Expand Down