From a10660b7f8f4fa218ee62a7664b47eb6028fee84 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 30 May 2022 18:37:42 +0800 Subject: [PATCH] cmd/geth: extend traverseRawState command (#24954) This PR adds node verification into traverseRawState command, so corrupted trie nodes can also be detected. --- cmd/geth/dbcmd.go | 4 ++-- cmd/geth/snapshot.go | 26 ++++++++++++++++++++++---- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index ace2849c9..c4fe9251f 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -307,7 +307,7 @@ func checkStateContent(ctx *cli.Context) error { start []byte ) if ctx.NArg() > 1 { - return fmt.Errorf("Max 1 argument: %v", ctx.Command.ArgsUsage) + return fmt.Errorf("max 1 argument: %v", ctx.Command.ArgsUsage) } if ctx.NArg() > 0 { if d, err := hexutil.Decode(ctx.Args().First()); err != nil { @@ -332,8 +332,8 @@ func checkStateContent(ctx *cli.Context) error { ) for it.Next() { count++ - v := it.Value() k := it.Key() + v := it.Value() hasher.Reset() hasher.Write(v) hasher.Read(got) diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 286eeed8e..9ffc5918c 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -105,7 +105,7 @@ data, and verifies that all snapshot storage data has a corresponding account. }, { Name: "traverse-state", - Usage: "Traverse the state with given root hash for verification", + Usage: "Traverse the state with given root hash and perform quick verification", ArgsUsage: "", Action: utils.MigrateFlags(traverseState), Category: "MISCELLANEOUS COMMANDS", @@ -121,7 +121,7 @@ It's also usable without snapshot enabled. }, { Name: "traverse-rawstate", - Usage: "Traverse the state with given root hash for verification", + Usage: "Traverse the state with given root hash and perform detailed verification", ArgsUsage: "", Action: utils.MigrateFlags(traverseRawState), Category: "MISCELLANEOUS COMMANDS", @@ -367,6 +367,8 @@ func traverseRawState(ctx *cli.Context) error { codes int lastReport time.Time start = time.Now() + hasher = crypto.NewKeccakState() + got = make([]byte, 32) ) accIter := t.NodeIterator(nil) for accIter.Next(true) { @@ -376,10 +378,18 @@ func traverseRawState(ctx *cli.Context) error { // Check the present for non-empty hash node(embedded node doesn't // have their own hash). if node != (common.Hash{}) { - if !rawdb.HasTrieNode(chaindb, node) { + blob := rawdb.ReadTrieNode(chaindb, node) + if len(blob) == 0 { log.Error("Missing trie node(account)", "hash", node) return errors.New("missing account") } + hasher.Reset() + hasher.Write(blob) + hasher.Read(got) + if !bytes.Equal(got, node.Bytes()) { + log.Error("Invalid trie node(account)", "hash", node.Hex(), "value", blob) + return errors.New("invalid account node") + } } // If it's a leaf node, yes we are touching an account, // dig into the storage trie further. @@ -404,10 +414,18 @@ func traverseRawState(ctx *cli.Context) error { // Check the present for non-empty hash node(embedded node doesn't // have their own hash). if node != (common.Hash{}) { - if !rawdb.HasTrieNode(chaindb, node) { + blob := rawdb.ReadTrieNode(chaindb, node) + if len(blob) == 0 { log.Error("Missing trie node(storage)", "hash", node) return errors.New("missing storage") } + hasher.Reset() + hasher.Write(blob) + hasher.Read(got) + if !bytes.Equal(got, node.Bytes()) { + log.Error("Invalid trie node(storage)", "hash", node.Hex(), "value", blob) + return errors.New("invalid storage node") + } } // Bump the counter if it's leaf node. if storageIter.Leaf() {