mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-23 21:26:42 +00:00
state: debug_stateSize to retrieve the latest state size
This commit is contained in:
parent
c99f43e41a
commit
70cd55dcd2
7 changed files with 59 additions and 47 deletions
|
|
@ -108,7 +108,7 @@ if one is set. Otherwise it prints the genesis from the datadir.`,
|
||||||
utils.MetricsInfluxDBTokenFlag,
|
utils.MetricsInfluxDBTokenFlag,
|
||||||
utils.MetricsInfluxDBBucketFlag,
|
utils.MetricsInfluxDBBucketFlag,
|
||||||
utils.MetricsInfluxDBOrganizationFlag,
|
utils.MetricsInfluxDBOrganizationFlag,
|
||||||
utils.MetricsStateSizeFlag,
|
utils.StateSizeTrackingFlag,
|
||||||
utils.TxLookupLimitFlag,
|
utils.TxLookupLimitFlag,
|
||||||
utils.VMTraceFlag,
|
utils.VMTraceFlag,
|
||||||
utils.VMTraceJsonConfigFlag,
|
utils.VMTraceJsonConfigFlag,
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,7 @@ var (
|
||||||
utils.MetricsInfluxDBTokenFlag,
|
utils.MetricsInfluxDBTokenFlag,
|
||||||
utils.MetricsInfluxDBBucketFlag,
|
utils.MetricsInfluxDBBucketFlag,
|
||||||
utils.MetricsInfluxDBOrganizationFlag,
|
utils.MetricsInfluxDBOrganizationFlag,
|
||||||
utils.MetricsStateSizeFlag,
|
utils.StateSizeTrackingFlag,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -628,6 +628,12 @@ var (
|
||||||
TakesFile: true,
|
TakesFile: true,
|
||||||
Category: flags.MiscCategory,
|
Category: flags.MiscCategory,
|
||||||
}
|
}
|
||||||
|
StateSizeTrackingFlag = &cli.BoolFlag{
|
||||||
|
Name: "state-size-tracking",
|
||||||
|
Usage: "Enable state size tracking",
|
||||||
|
Value: ethconfig.Defaults.EnableStateSizeTracking,
|
||||||
|
Category: flags.MiscCategory,
|
||||||
|
}
|
||||||
|
|
||||||
// RPC settings
|
// RPC settings
|
||||||
IPCDisabledFlag = &cli.BoolFlag{
|
IPCDisabledFlag = &cli.BoolFlag{
|
||||||
|
|
@ -966,13 +972,6 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
|
||||||
Value: metrics.DefaultConfig.InfluxDBOrganization,
|
Value: metrics.DefaultConfig.InfluxDBOrganization,
|
||||||
Category: flags.MetricsCategory,
|
Category: flags.MetricsCategory,
|
||||||
}
|
}
|
||||||
|
|
||||||
MetricsStateSizeFlag = &cli.BoolFlag{
|
|
||||||
Name: "metrics.statesize",
|
|
||||||
Usage: "Enable state size tracking for metrics collection",
|
|
||||||
Value: ethconfig.Defaults.EnableStateSizeTracking,
|
|
||||||
Category: flags.MetricsCategory,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -1734,7 +1733,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.Bool(MetricsEnabledFlag.Name) && ctx.Bool(MetricsStateSizeFlag.Name) {
|
if ctx.Bool(StateSizeTrackingFlag.Name) {
|
||||||
log.Info("Enabling state size metrics")
|
log.Info("Enabling state size metrics")
|
||||||
cfg.EnableStateSizeTracking = true
|
cfg.EnableStateSizeTracking = true
|
||||||
}
|
}
|
||||||
|
|
@ -2221,8 +2220,8 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
||||||
// - DATADIR/triedb/verkle.journal
|
// - DATADIR/triedb/verkle.journal
|
||||||
TrieJournalDirectory: stack.ResolvePath("triedb"),
|
TrieJournalDirectory: stack.ResolvePath("triedb"),
|
||||||
|
|
||||||
// Enable state size tracking if metrics and state size metrics are both enabled
|
// Enable state size tracking if enabled
|
||||||
EnableStateSizeTracking: ctx.Bool(MetricsEnabledFlag.Name) && ctx.Bool(MetricsStateSizeFlag.Name),
|
EnableStateSizeTracking: ctx.Bool(StateSizeTrackingFlag.Name),
|
||||||
}
|
}
|
||||||
if options.ArchiveMode && !options.Preimages {
|
if options.ArchiveMode && !options.Preimages {
|
||||||
options.Preimages = true
|
options.Preimages = true
|
||||||
|
|
|
||||||
|
|
@ -2814,3 +2814,8 @@ func (bc *BlockChain) SetTrieFlushInterval(interval time.Duration) {
|
||||||
func (bc *BlockChain) GetTrieFlushInterval() time.Duration {
|
func (bc *BlockChain) GetTrieFlushInterval() time.Duration {
|
||||||
return time.Duration(bc.flushInterval.Load())
|
return time.Duration(bc.flushInterval.Load())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StateSizer returns the state size tracker, or nil if it's not initialized
|
||||||
|
func (bc *BlockChain) StateSizer() *state.SizeTracker {
|
||||||
|
return bc.stateSizer
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
|
||||||
"github.com/ethereum/go-ethereum/triedb"
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
@ -40,25 +38,10 @@ const (
|
||||||
statEvictThreshold = 128 // the depth of statistic to be preserved
|
statEvictThreshold = 128 // the depth of statistic to be preserved
|
||||||
)
|
)
|
||||||
|
|
||||||
// Metrics for uploading the state statistics.
|
|
||||||
var (
|
|
||||||
blockInfoGauge = metrics.NewRegisteredGaugeInfo("state/size/block", nil)
|
|
||||||
accountsGauge = metrics.NewRegisteredGauge("state/size/account/count", nil)
|
|
||||||
accountBytesGauge = metrics.NewRegisteredGauge("state/size/account/bytes", nil)
|
|
||||||
storagesGauge = metrics.NewRegisteredGauge("state/size/storage/count", nil)
|
|
||||||
storageBytesGauge = metrics.NewRegisteredGauge("state/size/storage/bytes", nil)
|
|
||||||
accountTrienodesGauge = metrics.NewRegisteredGauge("state/size/trienode/account/count", nil)
|
|
||||||
accountTrienodeBytesGauge = metrics.NewRegisteredGauge("state/size/trienode/account/bytes", nil)
|
|
||||||
storageTrienodesGauge = metrics.NewRegisteredGauge("state/size/trienode/storage/count", nil)
|
|
||||||
storageTrienodeBytesGauge = metrics.NewRegisteredGauge("state/size/trienode/storage/bytes", nil)
|
|
||||||
contractCodesGauge = metrics.NewRegisteredGauge("state/size/contractcode/count", nil)
|
|
||||||
contractCodeBytesGauge = metrics.NewRegisteredGauge("state/size/contractcode/bytes", nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Database key scheme for states.
|
// Database key scheme for states.
|
||||||
var (
|
var (
|
||||||
accountKeySize = int64(len(rawdb.SnapshotAccountPrefix) + common.HashLength)
|
accountKeySize = int64(len(rawdb.SnapshotAccountPrefix) + common.HashLength)
|
||||||
storageKeySize = int64(len(rawdb.SnapshotStoragePrefix) + common.HashLength + common.HashLength)
|
storageKeySize = int64(len(rawdb.SnapshotStoragePrefix) + common.HashLength*2)
|
||||||
accountTrienodePrefixSize = int64(len(rawdb.TrieNodeAccountPrefix))
|
accountTrienodePrefixSize = int64(len(rawdb.TrieNodeAccountPrefix))
|
||||||
storageTrienodePrefixSize = int64(len(rawdb.TrieNodeStoragePrefix) + common.HashLength)
|
storageTrienodePrefixSize = int64(len(rawdb.TrieNodeStoragePrefix) + common.HashLength)
|
||||||
codeKeySize = int64(len(rawdb.CodePrefix) + common.HashLength)
|
codeKeySize = int64(len(rawdb.CodePrefix) + common.HashLength)
|
||||||
|
|
@ -246,6 +229,9 @@ type SizeTracker struct {
|
||||||
abort chan struct{}
|
abort chan struct{}
|
||||||
aborted chan struct{}
|
aborted chan struct{}
|
||||||
updateCh chan *stateUpdate
|
updateCh chan *stateUpdate
|
||||||
|
|
||||||
|
mu sync.RWMutex
|
||||||
|
latestStats *SizeStats
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSizeTracker creates a new state size tracker and starts it automatically
|
// NewSizeTracker creates a new state size tracker and starts it automatically
|
||||||
|
|
@ -313,7 +299,12 @@ func (t *SizeTracker) run() {
|
||||||
}
|
}
|
||||||
stat := base.add(diff)
|
stat := base.add(diff)
|
||||||
stats[u.root] = stat
|
stats[u.root] = stat
|
||||||
t.upload(stat)
|
log.Info("Update state size", "number", stat.BlockNumber, "root", stat.StateRoot, "stat", stat)
|
||||||
|
|
||||||
|
// Update latest stats
|
||||||
|
t.mu.Lock()
|
||||||
|
t.latestStats = &stat
|
||||||
|
t.mu.Unlock()
|
||||||
|
|
||||||
heap.Push(&h, stats[u.root])
|
heap.Push(&h, stats[u.root])
|
||||||
for u.blockNumber-h[0].BlockNumber > statEvictThreshold {
|
for u.blockNumber-h[0].BlockNumber > statEvictThreshold {
|
||||||
|
|
@ -415,6 +406,13 @@ wait:
|
||||||
if err := apply(result.root, result.stat); err != nil {
|
if err := apply(result.root, result.stat); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set initial latest stats
|
||||||
|
stats[result.root] = result.stat
|
||||||
|
t.mu.Lock()
|
||||||
|
t.latestStats = &result.stat
|
||||||
|
t.mu.Unlock()
|
||||||
|
|
||||||
log.Info("Measured persistent state size", "root", result.root, "number", result.blockNumber, "stat", result.stat, "elapsed", common.PrettyDuration(result.elapsed))
|
log.Info("Measured persistent state size", "root", result.root, "number", result.blockNumber, "stat", result.stat, "elapsed", common.PrettyDuration(result.elapsed))
|
||||||
return stats, nil
|
return stats, nil
|
||||||
|
|
||||||
|
|
@ -600,20 +598,9 @@ func (t *SizeTracker) iterateTableParallel(closed chan struct{}, prefix []byte,
|
||||||
return totalCount, totalBytes, nil
|
return totalCount, totalBytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *SizeTracker) upload(stats SizeStats) {
|
// GetLatestStats returns the latest state size statistics, or nil if not available
|
||||||
log.Debug("Uploading state size", "number", stats.BlockNumber, "root", stats.StateRoot, "stat", stats)
|
func (t *SizeTracker) GetLatestStats() *SizeStats {
|
||||||
blockInfoGauge.Update(metrics.GaugeInfoValue{
|
t.mu.RLock()
|
||||||
"number": hexutil.Uint64(stats.BlockNumber).String(),
|
defer t.mu.RUnlock()
|
||||||
"hash": stats.StateRoot.Hex(),
|
return t.latestStats
|
||||||
})
|
|
||||||
accountsGauge.Update(stats.Accounts)
|
|
||||||
accountBytesGauge.Update(stats.AccountBytes)
|
|
||||||
storagesGauge.Update(stats.Storages)
|
|
||||||
storageBytesGauge.Update(stats.StorageBytes)
|
|
||||||
accountTrienodesGauge.Update(stats.AccountTrienodes)
|
|
||||||
accountTrienodeBytesGauge.Update(stats.AccountTrienodeBytes)
|
|
||||||
storageTrienodesGauge.Update(stats.StorageTrienodes)
|
|
||||||
storageTrienodeBytesGauge.Update(stats.StorageTrienodeBytes)
|
|
||||||
contractCodesGauge.Update(stats.ContractCodes)
|
|
||||||
contractCodeBytesGauge.Update(stats.ContractCodeBytes)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -443,3 +443,19 @@ func (api *DebugAPI) GetTrieFlushInterval() (string, error) {
|
||||||
}
|
}
|
||||||
return api.eth.blockchain.GetTrieFlushInterval().String(), nil
|
return api.eth.blockchain.GetTrieFlushInterval().String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StateSize returns the current state size statistics from the state size tracker.
|
||||||
|
// Returns an error if the state size tracker is not initialized or if stats are not ready.
|
||||||
|
func (api *DebugAPI) StateSize() (*state.SizeStats, error) {
|
||||||
|
sizer := api.eth.blockchain.StateSizer()
|
||||||
|
if sizer == nil {
|
||||||
|
return nil, errors.New("state size tracker is not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
stats := sizer.GetLatestStats()
|
||||||
|
if stats == nil {
|
||||||
|
return nil, errors.New("state size statistics are not ready yet")
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -468,6 +468,11 @@ web3._extend({
|
||||||
call: 'debug_sync',
|
call: 'debug_sync',
|
||||||
params: 1
|
params: 1
|
||||||
}),
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'stateSize',
|
||||||
|
call: 'debug_stateSize',
|
||||||
|
params: 0,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
properties: []
|
properties: []
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue