From 4cd63c916937a39aaf6b2d66622513b5df8229fa Mon Sep 17 00:00:00 2001 From: Fynn Date: Thu, 28 Dec 2023 16:48:15 +0800 Subject: [PATCH 1/7] cmd/dbcmd: add inspect trie tool (#2082) --- cmd/geth/dbcmd.go | 99 ++++++++++++++++ trie/inspect_trie.go | 271 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 370 insertions(+) create mode 100644 trie/inspect_trie.go diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index b409b19260..89fb45bb89 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -38,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/triedb/pathdb" "github.com/olekukonko/tablewriter" "github.com/urfave/cli/v2" ) @@ -62,6 +63,7 @@ Remove blockchain and state databases`, dbCompactCmd, dbGetCmd, dbDeleteCmd, + dbInspectTrieCmd, dbPutCmd, dbGetSlotsCmd, dbDumpFreezerIndex, @@ -81,6 +83,17 @@ Remove blockchain and state databases`, Usage: "Inspect the storage size for each type of data in the database", 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.`, } + dbInspectTrieCmd = &cli.Command{ + Action: inspectTrie, + Name: "inspect-trie", + ArgsUsage: " ", + Flags: []cli.Flag{ + utils.DataDirFlag, + utils.SyncModeFlag, + }, + Usage: "Inspect the MPT tree of the account and contract.", + Description: `This commands iterates the entrie WorldState.`, + } dbCheckStateContentCmd = &cli.Command{ Action: checkStateContent, Name: "check-state-content", @@ -255,6 +268,92 @@ func confirmAndRemoveDB(database string, kind string) { } } +func inspectTrie(ctx *cli.Context) error { + if ctx.NArg() < 1 { + return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage) + } + + if ctx.NArg() > 3 { + return fmt.Errorf("Max 3 arguments: %v", ctx.Command.ArgsUsage) + } + + var ( + blockNumber uint64 + trieRootHash common.Hash + jobnum uint64 + ) + + stack, _ := makeConfigNode(ctx) + defer stack.Close() + + db := utils.MakeChainDatabase(ctx, stack, true, false) + defer db.Close() + + var headerBlockHash common.Hash + if ctx.NArg() >= 1 { + if ctx.Args().Get(0) == "latest" { + headerHash := rawdb.ReadHeadHeaderHash(db) + blockNumber = *(rawdb.ReadHeaderNumber(db, headerHash)) + } else if ctx.Args().Get(0) == "snapshot" { + trieRootHash = rawdb.ReadSnapshotRoot(db) + blockNumber = math.MaxUint64 + } else { + var err error + blockNumber, err = strconv.ParseUint(ctx.Args().Get(0), 10, 64) + if err != nil { + return fmt.Errorf("failed to Parse blocknum, Args[0]: %v, err: %v", ctx.Args().Get(0), err) + } + } + + if ctx.NArg() == 1 { + jobnum = 1000 + } else { + var err error + jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64) + if err != nil { + return fmt.Errorf("failed to Parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err) + } + } + + if blockNumber != math.MaxUint64 { + headerBlockHash = rawdb.ReadCanonicalHash(db, blockNumber) + if headerBlockHash == (common.Hash{}) { + return fmt.Errorf("ReadHeadBlockHash empry hash") + } + blockHeader := rawdb.ReadHeader(db, headerBlockHash, blockNumber) + trieRootHash = blockHeader.Root + } + if (trieRootHash == common.Hash{}) { + log.Error("Empty root hash") + } + fmt.Printf("ReadBlockHeader, root: %v, blocknum: %v\n", trieRootHash, blockNumber) + + dbScheme := rawdb.ReadStateScheme(db) + var config *trie.Config + if dbScheme == rawdb.PathScheme { + config = &trie.Config{ + PathDB: pathdb.ReadOnly, + } + } else if dbScheme == rawdb.HashScheme { + config = trie.HashDefaults + } + + triedb := trie.NewDatabase(db, config) + theTrie, err := trie.New(trie.TrieID(trieRootHash), triedb) + if err != nil { + fmt.Printf("fail to new trie tree, err: %v, rootHash: %v\n", err, trieRootHash.String()) + return err + } + theInspect, err := trie.NewInspector(theTrie, triedb, trieRootHash, blockNumber, jobnum) + if err != nil { + return err + } + theInspect.Run() + theInspect.DisplayResult() + } + return nil +} + func inspect(ctx *cli.Context) error { var ( prefix []byte diff --git a/trie/inspect_trie.go b/trie/inspect_trie.go new file mode 100644 index 0000000000..6f1a38ae76 --- /dev/null +++ b/trie/inspect_trie.go @@ -0,0 +1,271 @@ +package trie + +import ( + "bytes" + "errors" + "fmt" + "math/big" + "os" + "runtime" + "sort" + "strconv" + "sync" + "sync/atomic" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rlp" + "github.com/olekukonko/tablewriter" +) + +type Account struct { + Nonce uint64 + Balance *big.Int + Root common.Hash // merkle root of the storage trie + CodeHash []byte +} + +type Inspector struct { + trie *Trie // traverse trie + db *Database + stateRootHash common.Hash + blocknum uint64 + root node // root of triedb + totalNum uint64 + concurrentQueue chan struct{} + wg sync.WaitGroup + statLock sync.RWMutex + result map[string]*TrieTreeStat +} + +type TrieTreeStat struct { + is_account_trie bool + theNodeStatByLevel [15]NodeStat + totalNodeStat NodeStat +} + +type NodeStat struct { + ShortNodeCnt uint64 + FullNodeCnt uint64 + ValueNodeCnt uint64 +} + +func (trieStat *TrieTreeStat) AtomicAdd(theNode node, height uint32) { + switch (theNode).(type) { + case *shortNode: + atomic.AddUint64(&trieStat.totalNodeStat.ShortNodeCnt, 1) + atomic.AddUint64(&(trieStat.theNodeStatByLevel[height].ShortNodeCnt), 1) + case *fullNode: + atomic.AddUint64(&trieStat.totalNodeStat.FullNodeCnt, 1) + atomic.AddUint64(&trieStat.theNodeStatByLevel[height].FullNodeCnt, 1) + case valueNode: + atomic.AddUint64(&trieStat.totalNodeStat.ValueNodeCnt, 1) + atomic.AddUint64(&((trieStat.theNodeStatByLevel[height]).ValueNodeCnt), 1) + default: + panic(errors.New("Invalid node type to statistics")) + } +} + +func (trieStat *TrieTreeStat) Display(ownerAddress string, treeType string) { + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"-", "Level", "ShortNodeCnt", "FullNodeCnt", "ValueNodeCnt"}) + if ownerAddress == "" { + table.SetCaption(true, fmt.Sprintf("%v", treeType)) + } else { + table.SetCaption(true, fmt.Sprintf("%v-%v", treeType, ownerAddress)) + } + table.SetAlignment(1) + for i := 0; i < len(trieStat.theNodeStatByLevel); i++ { + nodeStat := trieStat.theNodeStatByLevel[i] + if nodeStat.FullNodeCnt == 0 && nodeStat.ShortNodeCnt == 0 && nodeStat.ValueNodeCnt == 0 { + break + } + table.AppendBulk([][]string{ + {"-", strconv.Itoa(i), nodeStat.ShortNodeCount(), nodeStat.FullNodeCount(), nodeStat.ValueNodeCount()}, + }) + } + table.AppendBulk([][]string{ + {"Total", "-", trieStat.totalNodeStat.ShortNodeCount(), trieStat.totalNodeStat.FullNodeCount(), trieStat.totalNodeStat.ValueNodeCount()}, + }) + table.Render() +} + +func Uint64ToString(cnt uint64) string { + return fmt.Sprintf("%v", cnt) +} + +func (nodeStat *NodeStat) ShortNodeCount() string { + return Uint64ToString(nodeStat.ShortNodeCnt) +} + +func (nodeStat *NodeStat) FullNodeCount() string { + return Uint64ToString(nodeStat.FullNodeCnt) +} +func (nodeStat *NodeStat) ValueNodeCount() string { + return Uint64ToString(nodeStat.ValueNodeCnt) +} + +// NewInspector return a inspector obj +func NewInspector(tr *Trie, db *Database, stateRootHash common.Hash, blocknum uint64, jobnum uint64) (*Inspector, error) { + if tr == nil { + return nil, errors.New("trie is nil") + } + + if tr.root == nil { + return nil, errors.New("trie root is nil") + } + + ins := &Inspector{ + trie: tr, + db: db, + stateRootHash: stateRootHash, + blocknum: blocknum, + root: tr.root, + result: make(map[string]*TrieTreeStat), + totalNum: (uint64)(0), + concurrentQueue: make(chan struct{}, jobnum), + wg: sync.WaitGroup{}, + } + + return ins, nil +} + +// Run statistics, external call +func (inspect *Inspector) Run() { + accountTrieStat := new(TrieTreeStat) + path := make([]byte, 0) + + if _, ok := inspect.result[""]; !ok { + inspect.result[""] = accountTrieStat + } + log.Info("Find Account Trie Tree", "rootHash: ", inspect.trie.Hash().String(), "BlockNum: ", inspect.blocknum) + inspect.ConcurrentTraversal(inspect.trie, accountTrieStat, inspect.root, 0, path) + inspect.wg.Wait() +} + +func (inspect *Inspector) SubConcurrentTraversal(theTrie *Trie, theTrieTreeStat *TrieTreeStat, theNode node, height uint32, path []byte) { + inspect.concurrentQueue <- struct{}{} + inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, theNode, height, path) + <-inspect.concurrentQueue + inspect.wg.Done() +} + +func (inspect *Inspector) ConcurrentTraversal(theTrie *Trie, theTrieTreeStat *TrieTreeStat, theNode node, height uint32, path []byte) { + // print process progress + total_num := atomic.AddUint64(&inspect.totalNum, 1) + if total_num%100000 == 0 { + fmt.Printf("Complete progress: %v, go routines Num: %v, inspect concurrentQueue: %v\n", total_num, runtime.NumGoroutine(), len(inspect.concurrentQueue)) + } + + // nil node + if theNode == nil { + return + } + + switch current := (theNode).(type) { + case *shortNode: + inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, current.Val, height, append(path, current.Key...)) + case *fullNode: + for idx, child := range current.Children { + if child == nil { + continue + } + childPath := append(path, byte(idx)) + if len(inspect.concurrentQueue)*2 < cap(inspect.concurrentQueue) { + inspect.wg.Add(1) + dst := make([]byte, len(childPath)) + copy(dst, childPath) + go inspect.SubConcurrentTraversal(theTrie, theTrieTreeStat, child, height+1, dst) + } else { + inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, child, height+1, childPath) + } + } + case hashNode: + n, err := theTrie.resloveWithoutTrack(current, path) + if err != nil { + fmt.Printf("Resolve HashNode error: %v, TrieRoot: %v, Height: %v, Path: %v\n", err, theTrie.Hash().String(), height+1, path) + return + } + inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, n, height, path) + return + case valueNode: + if !hasTerm(path) { + break + } + var account Account + if err := rlp.Decode(bytes.NewReader(current), &account); err != nil { + break + } + if account.Root == (common.Hash{}) { + break + } + ownerAddress := common.BytesToHash(hexToCompact(path)) + contractTrie, err := New(StorageTrieID(inspect.stateRootHash, ownerAddress, account.Root), inspect.db) + if err != nil { + // fmt.Printf("New contract trie node: %v, error: %v, Height: %v, Path: %v\n", theNode, err, height, path) + break + } + trieStat := new(TrieTreeStat) + trieStat.is_account_trie = false + + inspect.statLock.Lock() + if _, ok := inspect.result[ownerAddress.String()]; !ok { + inspect.result[ownerAddress.String()] = trieStat + } + inspect.statLock.Unlock() + + contractPath := make([]byte, 0) + // log.Info("Find Contract Trie Tree, rootHash: ", contractTrie.Hash().String(), "") + inspect.wg.Add(1) + go inspect.SubConcurrentTraversal(contractTrie, trieStat, contractTrie.root, 0, contractPath) + default: + panic(errors.New("Invalid node type to traverse.")) + } + theTrieTreeStat.AtomicAdd(theNode, height) +} + +func (inspect *Inspector) DisplayResult() { + // display root hash + if _, ok := inspect.result[""]; !ok { + log.Info("Display result error", "missing account trie") + return + } + inspect.result[""].Display("", "AccountTrie") + + type SortedTrie struct { + totalNum uint64 + ownerAddress string + } + // display contract trie + var sortedTriesByNums []SortedTrie + var totalContactsNodeStat NodeStat + var contractTrieCnt uint64 = 0 + + for ownerAddress, stat := range inspect.result { + if ownerAddress == "" { + continue + } + contractTrieCnt++ + totalContactsNodeStat.ShortNodeCnt += stat.totalNodeStat.ShortNodeCnt + totalContactsNodeStat.FullNodeCnt += stat.totalNodeStat.FullNodeCnt + totalContactsNodeStat.ValueNodeCnt += stat.totalNodeStat.ValueNodeCnt + totalNodeCnt := stat.totalNodeStat.ShortNodeCnt + stat.totalNodeStat.ValueNodeCnt + stat.totalNodeStat.FullNodeCnt + sortedTriesByNums = append(sortedTriesByNums, SortedTrie{totalNum: totalNodeCnt, ownerAddress: ownerAddress}) + } + sort.Slice(sortedTriesByNums, func(i, j int) bool { + return sortedTriesByNums[i].totalNum > sortedTriesByNums[j].totalNum + }) + // only display top 5 + for i, t := range sortedTriesByNums { + if i > 5 { + break + } + if stat, ok := inspect.result[t.ownerAddress]; !ok { + log.Error("Storage trie stat not found", "ownerAddress", t.ownerAddress) + } else { + stat.Display(t.ownerAddress, "ContractTrie") + } + } + fmt.Printf("Contract Trie, total trie num: %v, ShortNodeCnt: %v, FullNodeCnt: %v, ValueNodeCnt: %v\n", + contractTrieCnt, totalContactsNodeStat.ShortNodeCnt, totalContactsNodeStat.FullNodeCnt, totalContactsNodeStat.ValueNodeCnt) +} From 0117693324a3a10d933a426c2c96dacddb9240c7 Mon Sep 17 00:00:00 2001 From: "will@2012" Date: Wed, 17 Jan 2024 10:39:11 +0800 Subject: [PATCH 2/7] resolve conflict --- cmd/geth/dbcmd.go | 16 +++------------- trie/trie.go | 11 +++++++++++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 89fb45bb89..0e1e2bb22d 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/console/prompt" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" @@ -38,7 +39,6 @@ import ( "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triedb/pathdb" "github.com/olekukonko/tablewriter" "github.com/urfave/cli/v2" ) @@ -286,7 +286,7 @@ func inspectTrie(ctx *cli.Context) error { stack, _ := makeConfigNode(ctx) defer stack.Close() - db := utils.MakeChainDatabase(ctx, stack, true, false) + db := utils.MakeChainDatabase(ctx, stack, true) defer db.Close() var headerBlockHash common.Hash @@ -328,17 +328,7 @@ func inspectTrie(ctx *cli.Context) error { } fmt.Printf("ReadBlockHeader, root: %v, blocknum: %v\n", trieRootHash, blockNumber) - dbScheme := rawdb.ReadStateScheme(db) - var config *trie.Config - if dbScheme == rawdb.PathScheme { - config = &trie.Config{ - PathDB: pathdb.ReadOnly, - } - } else if dbScheme == rawdb.HashScheme { - config = trie.HashDefaults - } - - triedb := trie.NewDatabase(db, config) + triedb := trie.NewDatabase(db) theTrie, err := trie.New(trie.TrieID(trieRootHash), triedb) if err != nil { fmt.Printf("fail to new trie tree, err: %v, rootHash: %v\n", err, trieRootHash.String()) diff --git a/trie/trie.go b/trie/trie.go index d98fe992d5..3a83c37aa7 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -544,6 +544,17 @@ func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) { return mustDecodeNode(n, blob), nil } +func (t *Trie) resloveWithoutTrack(n node, prefix []byte) (node, error) { + if n, ok := n.(hashNode); ok { + blob, err := t.reader.nodeBlob(prefix, common.BytesToHash(n)) + if err != nil { + return nil, err + } + return mustDecodeNode(n, blob), nil + } + return n, nil +} + // Hash returns the root hash of the trie. It does not write to the // database and can be used even if the trie doesn't have one. func (t *Trie) Hash() common.Hash { From c5e7d4f33574aa91b20926bdde7767dbf17fb8a6 Mon Sep 17 00:00:00 2001 From: Fynn Date: Mon, 18 Dec 2023 14:59:48 +0800 Subject: [PATCH 3/7] dbcmd: refactor add eoa account stat --- trie/inspect_trie.go | 89 ++++++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/trie/inspect_trie.go b/trie/inspect_trie.go index 6f1a38ae76..5eb76dd996 100644 --- a/trie/inspect_trie.go +++ b/trie/inspect_trie.go @@ -12,10 +12,16 @@ import ( "sync" "sync/atomic" + "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" "github.com/olekukonko/tablewriter" + + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "golang.org/x/sync/semaphore" ) type Account struct { @@ -26,16 +32,17 @@ type Account struct { } type Inspector struct { - trie *Trie // traverse trie - db *Database - stateRootHash common.Hash - blocknum uint64 - root node // root of triedb - totalNum uint64 - concurrentQueue chan struct{} - wg sync.WaitGroup - statLock sync.RWMutex - result map[string]*TrieTreeStat + trie *Trie // traverse trie + db *Database + stateRootHash common.Hash + blocknum uint64 + root node // root of triedb + totalNum uint64 + wg sync.WaitGroup + statLock sync.RWMutex + result map[string]*TrieTreeStat + sem *semaphore.Weighted + eoaAccountNums uint64 } type TrieTreeStat struct { @@ -116,15 +123,16 @@ func NewInspector(tr *Trie, db *Database, stateRootHash common.Hash, blocknum ui } ins := &Inspector{ - trie: tr, - db: db, - stateRootHash: stateRootHash, - blocknum: blocknum, - root: tr.root, - result: make(map[string]*TrieTreeStat), - totalNum: (uint64)(0), - concurrentQueue: make(chan struct{}, jobnum), - wg: sync.WaitGroup{}, + trie: tr, + db: db, + stateRootHash: stateRootHash, + blocknum: blocknum, + root: tr.root, + result: make(map[string]*TrieTreeStat), + totalNum: (uint64)(0), + wg: sync.WaitGroup{}, + sem: semaphore.NewWeighted(int64(jobnum)), + eoaAccountNums: 0, } return ins, nil @@ -132,21 +140,33 @@ func NewInspector(tr *Trie, db *Database, stateRootHash common.Hash, blocknum ui // Run statistics, external call func (inspect *Inspector) Run() { - accountTrieStat := new(TrieTreeStat) - path := make([]byte, 0) + accountTrieStat := &TrieTreeStat{ + is_account_trie: true, + } + if inspect.db.Scheme() == rawdb.HashScheme { + ticker := time.NewTicker(30 * time.Second) + go func() { + defer ticker.Stop() + for { + select { + case <-ticker.C: + inspect.db.Cap(DEFAULT_TRIEDBCACHE_SIZE) + } + } + }() + } if _, ok := inspect.result[""]; !ok { inspect.result[""] = accountTrieStat } log.Info("Find Account Trie Tree", "rootHash: ", inspect.trie.Hash().String(), "BlockNum: ", inspect.blocknum) - inspect.ConcurrentTraversal(inspect.trie, accountTrieStat, inspect.root, 0, path) + + inspect.ConcurrentTraversal(inspect.trie, accountTrieStat, inspect.root, 0, []byte{}) inspect.wg.Wait() } func (inspect *Inspector) SubConcurrentTraversal(theTrie *Trie, theTrieTreeStat *TrieTreeStat, theNode node, height uint32, path []byte) { - inspect.concurrentQueue <- struct{}{} inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, theNode, height, path) - <-inspect.concurrentQueue inspect.wg.Done() } @@ -154,7 +174,7 @@ func (inspect *Inspector) ConcurrentTraversal(theTrie *Trie, theTrieTreeStat *Tr // print process progress total_num := atomic.AddUint64(&inspect.totalNum, 1) if total_num%100000 == 0 { - fmt.Printf("Complete progress: %v, go routines Num: %v, inspect concurrentQueue: %v\n", total_num, runtime.NumGoroutine(), len(inspect.concurrentQueue)) + fmt.Printf("Complete progress: %v, go routines Num: %v\n", total_num, runtime.NumGoroutine()) } // nil node @@ -171,7 +191,7 @@ func (inspect *Inspector) ConcurrentTraversal(theTrie *Trie, theTrieTreeStat *Tr continue } childPath := append(path, byte(idx)) - if len(inspect.concurrentQueue)*2 < cap(inspect.concurrentQueue) { + if inspect.sem.TryAcquire(1) { inspect.wg.Add(1) dst := make([]byte, len(childPath)) copy(dst, childPath) @@ -196,17 +216,22 @@ func (inspect *Inspector) ConcurrentTraversal(theTrie *Trie, theTrieTreeStat *Tr if err := rlp.Decode(bytes.NewReader(current), &account); err != nil { break } - if account.Root == (common.Hash{}) { + if common.BytesToHash(account.CodeHash) == types.EmptyCodeHash { + inspect.eoaAccountNums++ + } + if account.Root == (common.Hash{}) || account.Root == types.EmptyRootHash { break } ownerAddress := common.BytesToHash(hexToCompact(path)) contractTrie, err := New(StorageTrieID(inspect.stateRootHash, ownerAddress, account.Root), inspect.db) if err != nil { - // fmt.Printf("New contract trie node: %v, error: %v, Height: %v, Path: %v\n", theNode, err, height, path) + fmt.Printf("New contract trie node: %v, error: %v, Height: %v, Path: %v\n", theNode, err, height, path) break } - trieStat := new(TrieTreeStat) - trieStat.is_account_trie = false + contractTrie.tracer.reset() + trieStat := &TrieTreeStat{ + is_account_trie: false, + } inspect.statLock.Lock() if _, ok := inspect.result[ownerAddress.String()]; !ok { @@ -214,10 +239,9 @@ func (inspect *Inspector) ConcurrentTraversal(theTrie *Trie, theTrieTreeStat *Tr } inspect.statLock.Unlock() - contractPath := make([]byte, 0) // log.Info("Find Contract Trie Tree, rootHash: ", contractTrie.Hash().String(), "") inspect.wg.Add(1) - go inspect.SubConcurrentTraversal(contractTrie, trieStat, contractTrie.root, 0, contractPath) + go inspect.SubConcurrentTraversal(contractTrie, trieStat, contractTrie.root, 0, []byte{}) default: panic(errors.New("Invalid node type to traverse.")) } @@ -255,6 +279,7 @@ func (inspect *Inspector) DisplayResult() { sort.Slice(sortedTriesByNums, func(i, j int) bool { return sortedTriesByNums[i].totalNum > sortedTriesByNums[j].totalNum }) + fmt.Println("EOA accounts num: ", inspect.eoaAccountNums) // only display top 5 for i, t := range sortedTriesByNums { if i > 5 { From d94164aa55d7f171d4e8c190f61d996a2fcd9c49 Mon Sep 17 00:00:00 2001 From: Fynn Date: Tue, 9 Jan 2024 09:45:02 +0800 Subject: [PATCH 4/7] dbcmd: fix lint issues --- trie/inspect_trie.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/trie/inspect_trie.go b/trie/inspect_trie.go index 5eb76dd996..5b09cd11ec 100644 --- a/trie/inspect_trie.go +++ b/trie/inspect_trie.go @@ -147,11 +147,8 @@ func (inspect *Inspector) Run() { ticker := time.NewTicker(30 * time.Second) go func() { defer ticker.Stop() - for { - select { - case <-ticker.C: - inspect.db.Cap(DEFAULT_TRIEDBCACHE_SIZE) - } + for range ticker.C { + inspect.db.Cap(DEFAULT_TRIEDBCACHE_SIZE) } }() } From 3ccd43757ad70a8ba5a09084de20eb4f941ea0c5 Mon Sep 17 00:00:00 2001 From: "will@2012" Date: Wed, 17 Jan 2024 10:43:22 +0800 Subject: [PATCH 5/7] resolve conflict --- trie/inspect_trie.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/trie/inspect_trie.go b/trie/inspect_trie.go index 5b09cd11ec..2916caa001 100644 --- a/trie/inspect_trie.go +++ b/trie/inspect_trie.go @@ -11,7 +11,6 @@ import ( "strconv" "sync" "sync/atomic" - "time" "github.com/ethereum/go-ethereum/common" @@ -24,6 +23,10 @@ import ( "golang.org/x/sync/semaphore" ) +const ( + DEFAULT_TRIEDBCACHE_SIZE = 1024 * 1024 * 1024 +) + type Account struct { Nonce uint64 Balance *big.Int From 117cce6b54a3e9df066e0ede4dcf3eb8368caa4b Mon Sep 17 00:00:00 2001 From: "will@2012" Date: Tue, 23 Jan 2024 13:59:05 +0800 Subject: [PATCH 6/7] chore: polish by review tips --- cmd/geth/dbcmd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 0e1e2bb22d..e182b7ed08 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -318,7 +318,7 @@ func inspectTrie(ctx *cli.Context) error { if blockNumber != math.MaxUint64 { headerBlockHash = rawdb.ReadCanonicalHash(db, blockNumber) if headerBlockHash == (common.Hash{}) { - return fmt.Errorf("ReadHeadBlockHash empry hash") + return fmt.Errorf("ReadHeadBlockHash empty hash") } blockHeader := rawdb.ReadHeader(db, headerBlockHash, blockNumber) trieRootHash = blockHeader.Root From 7ff7f3da2e494459e7252bf86b4f988e3a76d4c3 Mon Sep 17 00:00:00 2001 From: "will@2012" Date: Tue, 23 Jan 2024 17:11:26 +0800 Subject: [PATCH 7/7] chore: polish by review tips --- trie/inspect_trie.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/trie/inspect_trie.go b/trie/inspect_trie.go index 2916caa001..f0f706f049 100644 --- a/trie/inspect_trie.go +++ b/trie/inspect_trie.go @@ -49,7 +49,7 @@ type Inspector struct { } type TrieTreeStat struct { - is_account_trie bool + isAccountTrie bool theNodeStatByLevel [15]NodeStat totalNodeStat NodeStat } @@ -144,7 +144,7 @@ func NewInspector(tr *Trie, db *Database, stateRootHash common.Hash, blocknum ui // Run statistics, external call func (inspect *Inspector) Run() { accountTrieStat := &TrieTreeStat{ - is_account_trie: true, + isAccountTrie: true, } if inspect.db.Scheme() == rawdb.HashScheme { ticker := time.NewTicker(30 * time.Second) @@ -230,7 +230,7 @@ func (inspect *Inspector) ConcurrentTraversal(theTrie *Trie, theTrieTreeStat *Tr } contractTrie.tracer.reset() trieStat := &TrieTreeStat{ - is_account_trie: false, + isAccountTrie: false, } inspect.statLock.Lock()