mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 11:20:45 +00:00
trie: add combined depth summary
This commit is contained in:
parent
a596a0aba3
commit
07015878c7
2 changed files with 123 additions and 4 deletions
|
|
@ -328,9 +328,11 @@ func Summarize(dumpPath string, config *InspectConfig) error {
|
||||||
}
|
}
|
||||||
summary.StorageCount++
|
summary.StorageCount++
|
||||||
summary.DepthHistogram[snapshot.MaxDepth]++
|
summary.DepthHistogram[snapshot.MaxDepth]++
|
||||||
summary.StorageTotals.Short += snapshot.Summary.Short
|
for i := 0; i < trieStatLevels; i++ {
|
||||||
summary.StorageTotals.Full += snapshot.Summary.Full
|
summary.StorageLevels[i].Short += record.Levels[i].Short
|
||||||
summary.StorageTotals.Value += snapshot.Summary.Value
|
summary.StorageLevels[i].Full += record.Levels[i].Full
|
||||||
|
summary.StorageLevels[i].Value += record.Levels[i].Value
|
||||||
|
}
|
||||||
|
|
||||||
depthTop.TryInsert(snapshot)
|
depthTop.TryInsert(snapshot)
|
||||||
totalTop.TryInsert(snapshot)
|
totalTop.TryInsert(snapshot)
|
||||||
|
|
@ -339,6 +341,11 @@ func Summarize(dumpPath string, config *InspectConfig) error {
|
||||||
if summary.Account == nil {
|
if summary.Account == nil {
|
||||||
return fmt.Errorf("dump file %s does not contain the account trie sentinel record", dumpPath)
|
return fmt.Errorf("dump file %s does not contain the account trie sentinel record", dumpPath)
|
||||||
}
|
}
|
||||||
|
for i := 0; i < trieStatLevels; i++ {
|
||||||
|
summary.StorageTotals.Short += summary.StorageLevels[i].Short
|
||||||
|
summary.StorageTotals.Full += summary.StorageLevels[i].Full
|
||||||
|
summary.StorageTotals.Value += summary.StorageLevels[i].Value
|
||||||
|
}
|
||||||
summary.TopByDepth = depthTop.Sorted()
|
summary.TopByDepth = depthTop.Sorted()
|
||||||
summary.TopByTotalNodes = totalTop.Sorted()
|
summary.TopByTotalNodes = totalTop.Sorted()
|
||||||
summary.TopByValueNodes = valueTop.Sorted()
|
summary.TopByValueNodes = valueTop.Sorted()
|
||||||
|
|
@ -522,6 +529,7 @@ type inspectSummary struct {
|
||||||
Account *storageStats
|
Account *storageStats
|
||||||
StorageCount uint64
|
StorageCount uint64
|
||||||
StorageTotals jsonLevel
|
StorageTotals jsonLevel
|
||||||
|
StorageLevels [trieStatLevels]jsonLevel
|
||||||
DepthHistogram [trieStatLevels]uint64
|
DepthHistogram [trieStatLevels]uint64
|
||||||
TopByDepth []*storageStats
|
TopByDepth []*storageStats
|
||||||
TopByTotalNodes []*storageStats
|
TopByTotalNodes []*storageStats
|
||||||
|
|
@ -529,6 +537,7 @@ type inspectSummary struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *inspectSummary) display() {
|
func (s *inspectSummary) display() {
|
||||||
|
s.displayCombinedDepthTable()
|
||||||
s.Account.toLevelStats().display("Accounts trie")
|
s.Account.toLevelStats().display("Accounts trie")
|
||||||
fmt.Println("Storage trie aggregate summary")
|
fmt.Println("Storage trie aggregate summary")
|
||||||
fmt.Printf("Total storage tries: %d\n", s.StorageCount)
|
fmt.Printf("Total storage tries: %d\n", s.StorageCount)
|
||||||
|
|
@ -553,6 +562,30 @@ func (s *inspectSummary) display() {
|
||||||
s.displayTop("Top storage tries by value (slot) count", s.TopByValueNodes)
|
s.displayTop("Top storage tries by value (slot) count", s.TopByValueNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *inspectSummary) displayCombinedDepthTable() {
|
||||||
|
accountTotal := s.Account.Summary.Short + s.Account.Summary.Full + s.Account.Summary.Value
|
||||||
|
storageTotal := s.StorageTotals.Short + s.StorageTotals.Full + s.StorageTotals.Value
|
||||||
|
|
||||||
|
fmt.Println("Trie Depth Distribution")
|
||||||
|
fmt.Printf("Account Trie: %d nodes\n", accountTotal)
|
||||||
|
fmt.Printf("Storage Tries: %d nodes across %d tries\n", storageTotal, s.StorageCount)
|
||||||
|
|
||||||
|
b := new(strings.Builder)
|
||||||
|
table := tablewriter.NewWriter(b)
|
||||||
|
table.SetHeader([]string{"Depth", "Account Nodes", "Storage Nodes"})
|
||||||
|
for i := 0; i < trieStatLevels; i++ {
|
||||||
|
accountNodes := s.Account.Levels[i].Short + s.Account.Levels[i].Full + s.Account.Levels[i].Value
|
||||||
|
storageNodes := s.StorageLevels[i].Short + s.StorageLevels[i].Full + s.StorageLevels[i].Value
|
||||||
|
if accountNodes == 0 && storageNodes == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
table.AppendBulk([][]string{{fmt.Sprint(i), fmt.Sprint(accountNodes), fmt.Sprint(storageNodes)}})
|
||||||
|
}
|
||||||
|
table.Render()
|
||||||
|
fmt.Print(b.String())
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *inspectSummary) displayTop(title string, list []*storageStats) {
|
func (s *inspectSummary) displayTop(title string, list []*storageStats) {
|
||||||
fmt.Println(title)
|
fmt.Println(title)
|
||||||
if len(list) == 0 {
|
if len(list) == 0 {
|
||||||
|
|
@ -575,6 +608,7 @@ func (s *inspectSummary) MarshalJSON() ([]byte, error) {
|
||||||
type jsonStorageSummary struct {
|
type jsonStorageSummary struct {
|
||||||
TotalStorageTries uint64 `json:"TotalStorageTries"`
|
TotalStorageTries uint64 `json:"TotalStorageTries"`
|
||||||
Totals jsonLevel `json:"Totals"`
|
Totals jsonLevel `json:"Totals"`
|
||||||
|
Levels []jsonLevel `json:"Levels"`
|
||||||
DepthHistogram [trieStatLevels]uint64 `json:"DepthHistogram"`
|
DepthHistogram [trieStatLevels]uint64 `json:"DepthHistogram"`
|
||||||
}
|
}
|
||||||
type jsonInspectSummary struct {
|
type jsonInspectSummary struct {
|
||||||
|
|
@ -593,6 +627,7 @@ func (s *inspectSummary) MarshalJSON() ([]byte, error) {
|
||||||
StorageSummary: jsonStorageSummary{
|
StorageSummary: jsonStorageSummary{
|
||||||
TotalStorageTries: s.StorageCount,
|
TotalStorageTries: s.StorageCount,
|
||||||
Totals: s.StorageTotals,
|
Totals: s.StorageTotals,
|
||||||
|
Levels: trimLevels(s.StorageLevels),
|
||||||
DepthHistogram: s.DepthHistogram,
|
DepthHistogram: s.DepthHistogram,
|
||||||
},
|
},
|
||||||
TopByDepth: s.TopByDepth,
|
TopByDepth: s.TopByDepth,
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,11 @@
|
||||||
package trie
|
package trie
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
|
@ -56,12 +59,93 @@ func TestInspect(t *testing.T) {
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
t.Fatalf("inspect failed: %v", err)
|
t.Fatalf("inspect failed: %v", err)
|
||||||
}
|
}
|
||||||
|
reanalysisPath := filepath.Join(tempDir, "trie-summary-reanalysis.json")
|
||||||
if err := Summarize(dumpPath, &InspectConfig{
|
if err := Summarize(dumpPath, &InspectConfig{
|
||||||
TopN: 1,
|
TopN: 1,
|
||||||
Path: filepath.Join(tempDir, "trie-summary-reanalysis.json"),
|
Path: reanalysisPath,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
t.Fatalf("summarize failed: %v", err)
|
t.Fatalf("summarize failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inspectSummaryPath := filepath.Join(tempDir, "trie-summary.json")
|
||||||
|
inspectOut := loadInspectJSON(t, inspectSummaryPath)
|
||||||
|
reanalysisOut := loadInspectJSON(t, reanalysisPath)
|
||||||
|
|
||||||
|
if len(inspectOut.StorageSummary.Levels) == 0 {
|
||||||
|
t.Fatal("expected StorageSummary.Levels to be populated")
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(inspectOut.AccountTrie, reanalysisOut.AccountTrie) {
|
||||||
|
t.Fatal("account trie summary mismatch between inspect and summarize")
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(inspectOut.StorageSummary, reanalysisOut.StorageSummary) {
|
||||||
|
t.Fatal("storage summary mismatch between inspect and summarize")
|
||||||
|
}
|
||||||
|
|
||||||
|
assertStorageTotalsMatchLevels(t, inspectOut)
|
||||||
|
assertStorageTotalsMatchLevels(t, reanalysisOut)
|
||||||
|
assertAccountTotalsMatchLevels(t, inspectOut.AccountTrie)
|
||||||
|
assertAccountTotalsMatchLevels(t, reanalysisOut.AccountTrie)
|
||||||
|
|
||||||
|
var histogramTotal uint64
|
||||||
|
for _, count := range inspectOut.StorageSummary.DepthHistogram {
|
||||||
|
histogramTotal += count
|
||||||
|
}
|
||||||
|
if histogramTotal != inspectOut.StorageSummary.TotalStorageTries {
|
||||||
|
t.Fatalf("depth histogram total %d does not match total storage tries %d", histogramTotal, inspectOut.StorageSummary.TotalStorageTries)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type inspectJSONOutput struct {
|
||||||
|
// Reuse storageStats for AccountTrie JSON to avoid introducing a parallel
|
||||||
|
// account summary test type. AccountTrie JSON includes Levels+Summary,
|
||||||
|
// which map directly; other storageStats fields remain zero-values.
|
||||||
|
AccountTrie storageStats `json:"AccountTrie"`
|
||||||
|
|
||||||
|
StorageSummary struct {
|
||||||
|
TotalStorageTries uint64 `json:"TotalStorageTries"`
|
||||||
|
Totals jsonLevel `json:"Totals"`
|
||||||
|
Levels []jsonLevel `json:"Levels"`
|
||||||
|
DepthHistogram [trieStatLevels]uint64 `json:"DepthHistogram"`
|
||||||
|
} `json:"StorageSummary"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadInspectJSON(t *testing.T, path string) inspectJSONOutput {
|
||||||
|
t.Helper()
|
||||||
|
raw, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read %s: %v", path, err)
|
||||||
|
}
|
||||||
|
var out inspectJSONOutput
|
||||||
|
if err := json.Unmarshal(raw, &out); err != nil {
|
||||||
|
t.Fatalf("failed to decode %s: %v", path, err)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertStorageTotalsMatchLevels(t *testing.T, out inspectJSONOutput) {
|
||||||
|
t.Helper()
|
||||||
|
var fromLevels jsonLevel
|
||||||
|
for _, level := range out.StorageSummary.Levels {
|
||||||
|
fromLevels.Short += level.Short
|
||||||
|
fromLevels.Full += level.Full
|
||||||
|
fromLevels.Value += level.Value
|
||||||
|
}
|
||||||
|
if fromLevels.Short != out.StorageSummary.Totals.Short || fromLevels.Full != out.StorageSummary.Totals.Full || fromLevels.Value != out.StorageSummary.Totals.Value {
|
||||||
|
t.Fatalf("storage totals mismatch: levels=%+v totals=%+v", fromLevels, out.StorageSummary.Totals)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertAccountTotalsMatchLevels(t *testing.T, account storageStats) {
|
||||||
|
t.Helper()
|
||||||
|
var fromLevels jsonLevel
|
||||||
|
for _, level := range account.Levels {
|
||||||
|
fromLevels.Short += level.Short
|
||||||
|
fromLevels.Full += level.Full
|
||||||
|
fromLevels.Value += level.Value
|
||||||
|
}
|
||||||
|
if fromLevels.Short != account.Summary.Short || fromLevels.Full != account.Summary.Full || fromLevels.Value != account.Summary.Value {
|
||||||
|
t.Fatalf("account totals mismatch: levels=%+v totals=%+v", fromLevels, account.Summary)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeAccountsWithStorage(db *testDb, size int, storage bool) (addresses [][20]byte, accounts [][]byte) {
|
func makeAccountsWithStorage(db *testDb, size int, storage bool) (addresses [][20]byte, accounts [][]byte) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue