Skip to content

Commit

Permalink
cmd/db: add inspect-enodedb cli to analyze enode database (#649)
Browse files Browse the repository at this point in the history
inspect-enodedb command inspects nodes in the enode db, calculates the peer (outbound) rate with them
  • Loading branch information
sonhv0212 authored Dec 18, 2024
1 parent 1d3b00e commit 2509c2e
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 0 deletions.
92 changes: 92 additions & 0 deletions cmd/ronin/dbcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package main

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"os"
Expand All @@ -33,9 +34,14 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/console/prompt"
"github.com/ethereum/go-ethereum/core/forkid"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/urfave/cli/v2"
)
Expand Down Expand Up @@ -69,6 +75,7 @@ Remove blockchain and state databases`,
dbDumpFreezerIndex,
dbImportCmd,
dbExportCmd,
dbInspectEnodeDBCmd,
},
}
dbInspectCmd = &cli.Command{
Expand Down Expand Up @@ -243,8 +250,93 @@ WARNING: This is a low-level operation which may cause database corruption!`,
},
Description: "Exports the specified chain data to an RLP encoded stream, optionally gzip-compressed.",
}
dbInspectEnodeDBCmd = &cli.Command{
Action: dbInspectEnodeDB,
Name: "inspect-enodedb",
Usage: "Inspect nodes in enode db",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "enodedb",
Usage: "Path to the enode database directory",
Required: true,
},
&cli.StringFlag{
Name: "peersfile",
Usage: "File containing a list of peers from admin.peers",
},
},
Category: "DATABASE COMMANDS",
}
)

func dbInspectEnodeDB(ctx *cli.Context) error {
path := ctx.String("enodedb")
db, err := enode.OpenDB(path)
if err != nil {
return err
}

nodeCount := 0
inspectedNodes := make(map[string]*enode.Node)
unknownNodes := []*enode.Node{}
db.IterateNodes(func(n *enode.Node) error {
nodeCount++
var eth struct {
ForkID forkid.ID
Tail []rlp.RawValue `rlp:"tail"`
}
if n.Record().Load(enr.WithEntry("eth", &eth)) == nil {
log.Info("Node", "ID", n.ID(), "IP", n.IP(), "UDP", n.UDP(), "TCP", n.TCP(), "eth", eth)
} else {
unknownNodes = append(unknownNodes, n)
}
inspectedNodes[n.ID().String()] = n
return nil
})

for _, n := range unknownNodes {
log.Info("Unknown node", "ID", n.ID(), "IP", n.IP(), "UDP", n.UDP(), "TCP", n.TCP())
}
log.Info("Total nodes", "count", nodeCount, "unknown", len(unknownNodes))

// Peers file is optional to calculate the rate of peers in Enode DB
if ctx.IsSet("peersfile") {
f, err := os.Open(ctx.String("peersfile"))
if err != nil {
return err
}

peersInfo := []*p2p.PeerInfo{}
decoder := json.NewDecoder(f)
err = decoder.Decode(&peersInfo)
if err != nil {
return err
}

foundInEnodeDB := 0
outbound := 0
for _, peerInfo := range peersInfo {
if peerInfo.Network.Inbound {
continue
}

outbound++
if _, ok := inspectedNodes[peerInfo.ID]; ok {
foundInEnodeDB++
log.Info("Found peer in EnodeDB", "ID", peerInfo.ID, "Network", peerInfo.Network)
} else {
log.Info("Peer not found in EnodeDB", "ID", peerInfo.ID, "Network", peerInfo.Network)
}
}

log.Info("Peers in EnodeDB", "total", len(peersInfo), "found", foundInEnodeDB,
"not_found", outbound-foundInEnodeDB, "rate", float64(foundInEnodeDB)/float64(outbound),
"inbound", len(peersInfo)-outbound, "outbound", outbound)
}

return nil
}

func removeDB(ctx *cli.Context) error {
stack, config := makeConfigNode(ctx)

Expand Down
23 changes: 23 additions & 0 deletions p2p/enode/nodedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"sync"
"time"

"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/errors"
Expand Down Expand Up @@ -481,6 +482,28 @@ seek:
return nodes
}

// Testing purposes only.
func (db *DB) IterateNodes(f func(n *Node) error) {
it := db.lvl.NewIterator(util.BytesPrefix([]byte(dbNodePrefix)), nil)
defer it.Release()

for it.Next() {
id, rest := splitNodeKey(it.Key())
if string(rest) != dbDiscoverRoot {
continue
}
node := mustDecodeNode(id[:], it.Value())
if node == nil {
return
}

if err := f(node); err != nil {
log.Error("error during node iteration", "err", err)
return
}
}
}

// reads the next node record from the iterator, skipping over other
// database entries.
func nextNode(it iterator.Iterator) *Node {
Expand Down

0 comments on commit 2509c2e

Please sign in to comment.