mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-20 11:46:44 +00:00
cmd/geth, core/rawdb: add inspect-contract
This commit is contained in:
parent
4d057b2c49
commit
b4083957d7
2 changed files with 114 additions and 0 deletions
|
|
@ -71,6 +71,7 @@ Remove blockchain and state databases`,
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
dbInspectCmd,
|
dbInspectCmd,
|
||||||
dbInspectTrieCmd,
|
dbInspectTrieCmd,
|
||||||
|
dbInspectContractCmd,
|
||||||
dbStatCmd,
|
dbStatCmd,
|
||||||
dbCompactCmd,
|
dbCompactCmd,
|
||||||
dbGetCmd,
|
dbGetCmd,
|
||||||
|
|
@ -101,6 +102,14 @@ Remove blockchain and state databases`,
|
||||||
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
|
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
Description: "This command inspects the depth of the trie",
|
Description: "This command inspects the depth of the trie",
|
||||||
}
|
}
|
||||||
|
dbInspectContractCmd = &cli.Command{
|
||||||
|
Action: inspectContract,
|
||||||
|
Name: "inspect-contract",
|
||||||
|
Usage: "Inspect the on-disk footprint of a contract",
|
||||||
|
ArgsUsage: "<address>",
|
||||||
|
Flags: slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
|
||||||
|
Description: "This command inspects the snapshot account, snapshot storage slots, and storage trie nodes for a given contract address.",
|
||||||
|
}
|
||||||
dbCheckStateContentCmd = &cli.Command{
|
dbCheckStateContentCmd = &cli.Command{
|
||||||
Action: checkStateContent,
|
Action: checkStateContent,
|
||||||
Name: "check-state-content",
|
Name: "check-state-content",
|
||||||
|
|
@ -350,6 +359,21 @@ func inspectTrieDepth(ctx *cli.Context) error {
|
||||||
return rawdb.InspectTrieDepth(db)
|
return rawdb.InspectTrieDepth(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func inspectContract(ctx *cli.Context) error {
|
||||||
|
if ctx.NArg() != 1 {
|
||||||
|
return fmt.Errorf("required argument: <address>")
|
||||||
|
}
|
||||||
|
address := common.HexToAddress(ctx.Args().Get(0))
|
||||||
|
|
||||||
|
stack, _ := makeConfigNode(ctx)
|
||||||
|
defer stack.Close()
|
||||||
|
|
||||||
|
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
return rawdb.InspectContract(db, address)
|
||||||
|
}
|
||||||
|
|
||||||
func checkStateContent(ctx *cli.Context) error {
|
func checkStateContent(ctx *cli.Context) error {
|
||||||
var (
|
var (
|
||||||
prefix []byte
|
prefix []byte
|
||||||
|
|
|
||||||
|
|
@ -943,3 +943,93 @@ func InspectTrieDepth(db ethdb.Database) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InspectContract inspects the on-disk footprint of a single contract:
|
||||||
|
// snapshot account, snapshot storage slots, and path-based storage trie
|
||||||
|
// nodes including depth distribution.
|
||||||
|
func InspectContract(db ethdb.Database, address common.Address) error {
|
||||||
|
start := time.Now()
|
||||||
|
accountHash := crypto.Keccak256Hash(address.Bytes())
|
||||||
|
|
||||||
|
log.Info("Inspecting contract", "address", address, "hash", accountHash)
|
||||||
|
|
||||||
|
// 1. Account snapshot
|
||||||
|
accountData := ReadAccountSnapshot(db, accountHash)
|
||||||
|
accountSnapshotSize := len(accountSnapshotKey(accountHash)) + len(accountData)
|
||||||
|
|
||||||
|
// 2. Storage snapshot: iterate all storage slots for this account
|
||||||
|
var storageStat stat
|
||||||
|
storagePrefix := storageSnapshotsKey(accountHash)
|
||||||
|
|
||||||
|
it := db.NewIterator(storagePrefix, nil)
|
||||||
|
for it.Next() {
|
||||||
|
storageStat.add(common.StorageSize(len(it.Key()) + len(it.Value())))
|
||||||
|
}
|
||||||
|
it.Release()
|
||||||
|
if err := it.Error(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Storage trie nodes: iterate and compute depth distribution
|
||||||
|
var (
|
||||||
|
trieStat stat
|
||||||
|
trieDepths [65]stat
|
||||||
|
trieStack = make([]string, 0, 65)
|
||||||
|
)
|
||||||
|
|
||||||
|
it = db.NewIterator(storageTrieNodeKey(accountHash, nil), nil)
|
||||||
|
for it.Next() {
|
||||||
|
ok, hash, path := ResolveStorageTrieNode(it.Key())
|
||||||
|
if !ok || hash != accountHash {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
size := common.StorageSize(len(it.Key()) + len(it.Value()))
|
||||||
|
trieStat.add(size)
|
||||||
|
|
||||||
|
pathStr := string(path)
|
||||||
|
|
||||||
|
// Stack-based depth: pop until top is strict prefix of current
|
||||||
|
for len(trieStack) > 0 {
|
||||||
|
top := trieStack[len(trieStack)-1]
|
||||||
|
if len(top) < len(pathStr) && pathStr[:len(top)] == top {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
trieStack = trieStack[:len(trieStack)-1]
|
||||||
|
}
|
||||||
|
trieDepths[len(trieStack)].add(size)
|
||||||
|
trieStack = append(trieStack, pathStr)
|
||||||
|
}
|
||||||
|
it.Release()
|
||||||
|
if err := it.Error(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Inspection complete", "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
|
|
||||||
|
// Print results
|
||||||
|
fmt.Printf("\n=== Contract Inspection: %s ===\n", address)
|
||||||
|
fmt.Printf("Account hash: %s\n\n", accountHash)
|
||||||
|
|
||||||
|
if len(accountData) == 0 {
|
||||||
|
fmt.Println("Account snapshot: not found")
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Account snapshot: %s\n", common.StorageSize(accountSnapshotSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Snapshot storage: %s slots (%s)\n", storageStat.countString(), storageStat.sizeString())
|
||||||
|
fmt.Printf("Storage trie: %s nodes (%s)\n", trieStat.countString(), trieStat.sizeString())
|
||||||
|
|
||||||
|
fmt.Println("\nStorage Trie Depth Distribution:")
|
||||||
|
fmt.Println("Depth | Nodes | Size")
|
||||||
|
fmt.Println("------|---------------|---------------")
|
||||||
|
for i := 0; i < 65; i++ {
|
||||||
|
if !trieDepths[i].empty() {
|
||||||
|
fmt.Printf("%5d | %13s | %13s\n",
|
||||||
|
i, trieDepths[i].countString(), trieDepths[i].sizeString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue