Skip to content

Commit f651600

Browse files
lightclientfynnssMariusVanDerWijden
committed
trie: add inspector
Co-authored-by: Fynn <zcheng1004@gmail.com> Co-authored-by: lightclient <lightclient@protonmail.com> Co-authored-by: MariusVanDerWijden <m.vanderwijden@live.de>
1 parent 4074f74 commit f651600

File tree

3 files changed

+388
-0
lines changed

3 files changed

+388
-0
lines changed

cmd/geth/dbcmd.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ package main
1919
import (
2020
"bytes"
2121
"fmt"
22+
"math"
2223
"os"
2324
"os/signal"
2425
"path/filepath"
26+
"runtime"
2527
"slices"
2628
"strconv"
2729
"strings"
@@ -75,6 +77,7 @@ Remove blockchain and state databases`,
7577
dbCompactCmd,
7678
dbGetCmd,
7779
dbDeleteCmd,
80+
dbInspectTrieCmd,
7881
dbPutCmd,
7982
dbGetSlotsCmd,
8083
dbDumpFreezerIndex,
@@ -93,6 +96,18 @@ Remove blockchain and state databases`,
9396
Usage: "Inspect the storage size for each type of data in the database",
9497
Description: `This commands iterates the entire database. If the optional 'prefix' and 'start' arguments are provided, then the iteration is limited to the given subset of data.`,
9598
}
99+
dbInspectTrieCmd = &cli.Command{
100+
Action: inspectTrie,
101+
Name: "inspect-trie",
102+
ArgsUsage: "<blocknum> <jobnum>",
103+
Flags: []cli.Flag{
104+
utils.DataDirFlag,
105+
},
106+
Usage: "Print detailed trie information about the structure of account trie and storage tries.",
107+
Description: `This commands iterates the entrie trie-backed state. If the 'blocknum' is not specified,
108+
the latest block number will be used by default. 'jobnum' indicates the number of coroutines concurrently traversing
109+
the account and storage trie.`,
110+
}
96111
dbCheckStateContentCmd = &cli.Command{
97112
Action: checkStateContent,
98113
Name: "check-state-content",
@@ -386,6 +401,87 @@ func checkStateContent(ctx *cli.Context) error {
386401
return nil
387402
}
388403

404+
func inspectTrie(ctx *cli.Context) error {
405+
if ctx.NArg() > 2 {
406+
return fmt.Errorf("excessive number of arguments: %v", ctx.Command.ArgsUsage)
407+
}
408+
409+
var (
410+
blockNumber uint64
411+
trieRootHash common.Hash
412+
jobnum uint64
413+
)
414+
415+
stack, _ := makeConfigNode(ctx)
416+
defer stack.Close()
417+
418+
db := utils.MakeChainDatabase(ctx, stack, false)
419+
defer db.Close()
420+
421+
var headerBlockHash common.Hash
422+
switch {
423+
case ctx.NArg() == 0 || ctx.Args().Get(0) == "latest":
424+
headerHash := rawdb.ReadHeadHeaderHash(db)
425+
n, ok := rawdb.ReadHeaderNumber(db, headerHash)
426+
if !ok {
427+
return fmt.Errorf("could not load head block hash")
428+
}
429+
blockNumber = n
430+
case ctx.Args().Get(0) == "snapshot":
431+
trieRootHash = rawdb.ReadSnapshotRoot(db)
432+
blockNumber = math.MaxUint64
433+
default:
434+
var err error
435+
blockNumber, err = strconv.ParseUint(ctx.Args().Get(0), 10, 64)
436+
if err != nil {
437+
return fmt.Errorf("failed to parse blocknum, Args[0]: %v, err: %v", ctx.Args().Get(0), err)
438+
}
439+
}
440+
441+
// Configure number of threads.
442+
if ctx.NArg() <= 1 {
443+
jobnum = uint64(runtime.NumCPU())
444+
} else {
445+
var err error
446+
jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64)
447+
if err != nil {
448+
return fmt.Errorf("failed to parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
449+
}
450+
}
451+
452+
// Load head block number based on canonical hash, if applicable.
453+
if blockNumber != math.MaxUint64 {
454+
headerBlockHash = rawdb.ReadCanonicalHash(db, blockNumber)
455+
if headerBlockHash == (common.Hash{}) {
456+
return fmt.Errorf("canonical hash for block %d not found", blockNumber)
457+
}
458+
blockHeader := rawdb.ReadHeader(db, headerBlockHash, blockNumber)
459+
trieRootHash = blockHeader.Root
460+
}
461+
462+
if (trieRootHash == common.Hash{}) {
463+
log.Error("Empty root hash")
464+
}
465+
466+
log.Debug("Inspecting trie", "root", trieRootHash, "block", blockNumber)
467+
468+
triedb := utils.MakeTrieDatabase(ctx, stack, db, false, true, false)
469+
defer triedb.Close()
470+
471+
theTrie, err := trie.New(trie.TrieID(trieRootHash), triedb)
472+
if err != nil {
473+
fmt.Printf("fail to new trie tree, err: %v, rootHash: %v\n", err, trieRootHash.String())
474+
return err
475+
}
476+
inspector, err := trie.NewInspector(theTrie, triedb, trieRootHash, blockNumber, jobnum)
477+
if err != nil {
478+
return err
479+
}
480+
inspector.Run()
481+
inspector.DisplayResult()
482+
return nil
483+
}
484+
389485
func showDBStats(db ethdb.KeyValueStater) {
390486
stats, err := db.Stat()
391487
if err != nil {

0 commit comments

Comments
 (0)