Skip to content

Commit a10660b

Browse files
authored
cmd/geth: extend traverseRawState command (ethereum#24954)
This PR adds node verification into traverseRawState command, so corrupted trie nodes can also be detected.
1 parent 86af788 commit a10660b

File tree

2 files changed

+24
-6
lines changed

2 files changed

+24
-6
lines changed

cmd/geth/dbcmd.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ func checkStateContent(ctx *cli.Context) error {
307307
start []byte
308308
)
309309
if ctx.NArg() > 1 {
310-
return fmt.Errorf("Max 1 argument: %v", ctx.Command.ArgsUsage)
310+
return fmt.Errorf("max 1 argument: %v", ctx.Command.ArgsUsage)
311311
}
312312
if ctx.NArg() > 0 {
313313
if d, err := hexutil.Decode(ctx.Args().First()); err != nil {
@@ -332,8 +332,8 @@ func checkStateContent(ctx *cli.Context) error {
332332
)
333333
for it.Next() {
334334
count++
335-
v := it.Value()
336335
k := it.Key()
336+
v := it.Value()
337337
hasher.Reset()
338338
hasher.Write(v)
339339
hasher.Read(got)

cmd/geth/snapshot.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ data, and verifies that all snapshot storage data has a corresponding account.
105105
},
106106
{
107107
Name: "traverse-state",
108-
Usage: "Traverse the state with given root hash for verification",
108+
Usage: "Traverse the state with given root hash and perform quick verification",
109109
ArgsUsage: "<root>",
110110
Action: utils.MigrateFlags(traverseState),
111111
Category: "MISCELLANEOUS COMMANDS",
@@ -121,7 +121,7 @@ It's also usable without snapshot enabled.
121121
},
122122
{
123123
Name: "traverse-rawstate",
124-
Usage: "Traverse the state with given root hash for verification",
124+
Usage: "Traverse the state with given root hash and perform detailed verification",
125125
ArgsUsage: "<root>",
126126
Action: utils.MigrateFlags(traverseRawState),
127127
Category: "MISCELLANEOUS COMMANDS",
@@ -367,6 +367,8 @@ func traverseRawState(ctx *cli.Context) error {
367367
codes int
368368
lastReport time.Time
369369
start = time.Now()
370+
hasher = crypto.NewKeccakState()
371+
got = make([]byte, 32)
370372
)
371373
accIter := t.NodeIterator(nil)
372374
for accIter.Next(true) {
@@ -376,10 +378,18 @@ func traverseRawState(ctx *cli.Context) error {
376378
// Check the present for non-empty hash node(embedded node doesn't
377379
// have their own hash).
378380
if node != (common.Hash{}) {
379-
if !rawdb.HasTrieNode(chaindb, node) {
381+
blob := rawdb.ReadTrieNode(chaindb, node)
382+
if len(blob) == 0 {
380383
log.Error("Missing trie node(account)", "hash", node)
381384
return errors.New("missing account")
382385
}
386+
hasher.Reset()
387+
hasher.Write(blob)
388+
hasher.Read(got)
389+
if !bytes.Equal(got, node.Bytes()) {
390+
log.Error("Invalid trie node(account)", "hash", node.Hex(), "value", blob)
391+
return errors.New("invalid account node")
392+
}
383393
}
384394
// If it's a leaf node, yes we are touching an account,
385395
// dig into the storage trie further.
@@ -404,10 +414,18 @@ func traverseRawState(ctx *cli.Context) error {
404414
// Check the present for non-empty hash node(embedded node doesn't
405415
// have their own hash).
406416
if node != (common.Hash{}) {
407-
if !rawdb.HasTrieNode(chaindb, node) {
417+
blob := rawdb.ReadTrieNode(chaindb, node)
418+
if len(blob) == 0 {
408419
log.Error("Missing trie node(storage)", "hash", node)
409420
return errors.New("missing storage")
410421
}
422+
hasher.Reset()
423+
hasher.Write(blob)
424+
hasher.Read(got)
425+
if !bytes.Equal(got, node.Bytes()) {
426+
log.Error("Invalid trie node(storage)", "hash", node.Hex(), "value", blob)
427+
return errors.New("invalid storage node")
428+
}
411429
}
412430
// Bump the counter if it's leaf node.
413431
if storageIter.Leaf() {

0 commit comments

Comments
 (0)