Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

State expiry mvp0.1: opt prune stats & state expiry config; #122

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions cmd/geth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import (
"github.com/ethereum/go-ethereum/accounts/scwallet"
"github.com/ethereum/go-ethereum/accounts/usbwallet"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/internal/flags"
Expand Down Expand Up @@ -158,7 +157,6 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
cfg.Ethstats.URL = ctx.String(utils.EthStatsURLFlag.Name)
}
applyMetricConfig(ctx, &cfg)
applyStateExpiryConfig(ctx, &cfg)

return stack, cfg
}
Expand Down Expand Up @@ -272,21 +270,6 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) {
}
}

func applyStateExpiryConfig(ctx *cli.Context, cfg *gethConfig) {

if ctx.IsSet(utils.StateExpiryEnableFlag.Name) {
enableStateExpiry := ctx.Bool(utils.StateExpiryEnableFlag.Name)
if enableStateExpiry && ctx.IsSet(utils.StateSchemeFlag.Name) && ctx.String(utils.StateSchemeFlag.Name) == rawdb.HashScheme {
log.Warn("State expiry is not supported with hash scheme. Disabling state expiry")
enableStateExpiry = false
}
cfg.Eth.StateExpiryEnable = enableStateExpiry
}
if ctx.IsSet(utils.StateExpiryFullStateEndpointFlag.Name) {
cfg.Eth.StateExpiryFullStateEndpoint = ctx.String(utils.StateExpiryFullStateEndpointFlag.Name)
}
}

func deprecated(field string) bool {
switch field {
case "ethconfig.Config.EVMInterpreter":
Expand Down
4 changes: 4 additions & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ var (
stateExpiryFlags = []cli.Flag{
utils.StateExpiryEnableFlag,
utils.StateExpiryFullStateEndpointFlag,
utils.StateExpiryStateEpoch1BlockFlag,
utils.StateExpiryStateEpoch2BlockFlag,
utils.StateExpiryStateEpochPeriodFlag,
utils.StateExpiryEnableLocalReviveFlag,
}
)

Expand Down
5 changes: 2 additions & 3 deletions cmd/geth/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,13 +436,12 @@ func pruneState(ctx *cli.Context) error {
Preimages: cfg.Eth.Preimages,
StateHistory: cfg.Eth.StateHistory,
StateScheme: cfg.Eth.StateScheme,
EnableStateExpiry: cfg.Eth.StateExpiryEnable,
RemoteEndPoint: cfg.Eth.StateExpiryFullStateEndpoint,
StateExpiryCfg: cfg.Eth.StateExpiryCfg,
}
prunerconfig := pruner.Config{
Datadir: stack.ResolvePath(""),
BloomSize: ctx.Uint64(utils.BloomFilterSizeFlag.Name),
EnableStateExpiry: cfg.Eth.StateExpiryEnable,
EnableStateExpiry: cfg.Eth.StateExpiryCfg.EnableExpiry(),
ChainConfig: chainConfig,
CacheConfig: cacheConfig,
}
Expand Down
104 changes: 102 additions & 2 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"encoding/hex"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"math"
"math/big"
"net"
Expand Down Expand Up @@ -1125,6 +1127,26 @@ var (
Usage: "set state expiry remote full state rpc endpoint, every expired state will fetch from remote",
Category: flags.StateExpiryCategory,
}
StateExpiryStateEpoch1BlockFlag = &cli.Uint64Flag{
Name: "state-expiry.epoch1",
Usage: "set state expiry epoch1 block number",
Category: flags.StateExpiryCategory,
}
StateExpiryStateEpoch2BlockFlag = &cli.Uint64Flag{
Name: "state-expiry.epoch2",
Usage: "set state expiry epoch2 block number",
Category: flags.StateExpiryCategory,
}
StateExpiryStateEpochPeriodFlag = &cli.Uint64Flag{
Name: "state-expiry.period",
Usage: "set state expiry epoch period after epoch2",
Category: flags.StateExpiryCategory,
}
StateExpiryEnableLocalReviveFlag = &cli.BoolFlag{
Name: "state-expiry.localrevive",
Usage: "if enable local revive",
Category: flags.StateExpiryCategory,
}
)

func init() {
Expand Down Expand Up @@ -1940,13 +1962,18 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name)
}
// Parse state scheme, abort the process if it's not compatible.
chaindb := tryMakeReadOnlyDatabase(ctx, stack)
chaindb := MakeChainDatabase(ctx, stack, false, false)
scheme, err := ParseStateScheme(ctx, chaindb)
chaindb.Close()
if err != nil {
Fatalf("%v", err)
}
cfg.StateScheme = scheme
seCfg, err := ParseStateExpiryConfig(ctx, chaindb, scheme)
if err != nil {
Fatalf("%v", err)
}
cfg.StateExpiryCfg = seCfg
chaindb.Close()

// Parse transaction history flag, if user is still using legacy config
// file with 'TxLookupLimit' configured, copy the value to 'TransactionHistory'.
Expand Down Expand Up @@ -2521,6 +2548,79 @@ func ParseStateScheme(ctx *cli.Context, disk ethdb.Database) (string, error) {
return "", fmt.Errorf("incompatible state scheme, stored: %s, provided: %s", stored, scheme)
}

func ParseStateExpiryConfig(ctx *cli.Context, disk ethdb.Database, scheme string) (*types.StateExpiryConfig, error) {
enc := rawdb.ReadStateExpiryCfg(disk)
var stored *types.StateExpiryConfig
if len(enc) > 0 {
var cfg types.StateExpiryConfig
if err := rlp.DecodeBytes(enc, &cfg); err != nil {
return nil, err
}
stored = &cfg
}
newCfg := &types.StateExpiryConfig{StateScheme: scheme}
if ctx.IsSet(StateExpiryEnableFlag.Name) {
newCfg.Enable = ctx.Bool(StateExpiryEnableFlag.Name)
}
if ctx.IsSet(StateExpiryFullStateEndpointFlag.Name) {
newCfg.FullStateEndpoint = ctx.String(StateExpiryFullStateEndpointFlag.Name)
}

// some config will use stored default
if ctx.IsSet(StateExpiryStateEpoch1BlockFlag.Name) {
newCfg.StateEpoch1Block = ctx.Uint64(StateExpiryStateEpoch1BlockFlag.Name)
} else if stored != nil {
newCfg.StateEpoch1Block = stored.StateEpoch1Block
}
if ctx.IsSet(StateExpiryStateEpoch2BlockFlag.Name) {
newCfg.StateEpoch2Block = ctx.Uint64(StateExpiryStateEpoch2BlockFlag.Name)
} else if stored != nil {
newCfg.StateEpoch2Block = stored.StateEpoch2Block
}
if ctx.IsSet(StateExpiryStateEpochPeriodFlag.Name) {
newCfg.StateEpochPeriod = ctx.Uint64(StateExpiryStateEpochPeriodFlag.Name)
} else if stored != nil {
newCfg.StateEpochPeriod = stored.StateEpochPeriod
}
if ctx.IsSet(StateExpiryEnableLocalReviveFlag.Name) {
newCfg.EnableLocalRevive = ctx.Bool(StateExpiryEnableLocalReviveFlag.Name)
}

// override prune level
newCfg.PruneLevel = types.StateExpiryPruneLevel1
switch newCfg.StateScheme {
case rawdb.HashScheme:
// TODO(0xbundler): will stop support HBSS later.
newCfg.PruneLevel = types.StateExpiryPruneLevel0
case rawdb.PathScheme:
newCfg.PruneLevel = types.StateExpiryPruneLevel1
default:
return nil, fmt.Errorf("not support the state scheme: %v", newCfg.StateScheme)
}

if err := newCfg.Validation(); err != nil {
return nil, err
}
if err := stored.CheckCompatible(newCfg); err != nil {
return nil, err
}

log.Info("Apply State Expiry", "cfg", newCfg)
if !newCfg.Enable {
return newCfg, nil
}

// save it into db
enc, err := rlp.EncodeToBytes(newCfg)
if err != nil {
return nil, err
}
if err = rawdb.WriteStateExpiryCfg(disk, enc); err != nil {
return nil, err
}
return newCfg, nil
}

// MakeTrieDatabase constructs a trie database based on the configured scheme.
func MakeTrieDatabase(ctx *cli.Context, disk ethdb.Database, preimage bool, readOnly bool) *trie.Database {
config := &trie.Config{
Expand Down
41 changes: 24 additions & 17 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,7 @@ type CacheConfig struct {
SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it

// state expiry feature
EnableStateExpiry bool
RemoteEndPoint string
StateExpiryCfg *types.StateExpiryConfig
}

// TriedbConfig derives the configures for trie database.
Expand All @@ -170,7 +169,7 @@ func (c *CacheConfig) TriedbConfig() *trie.Config {
Cache: c.TrieCleanLimit,
Preimages: c.Preimages,
NoTries: c.NoTries,
EnableStateExpiry: c.EnableStateExpiry,
EnableStateExpiry: c.StateExpiryCfg.EnableExpiry(),
}
if c.StateScheme == rawdb.HashScheme {
config.HashDB = &hashdb.Config{
Expand Down Expand Up @@ -300,8 +299,8 @@ type BlockChain struct {
doubleSignMonitor *monitor.DoubleSignMonitor

// state expiry feature
enableStateExpiry bool
fullStateDB ethdb.FullStateDB
stateExpiryCfg *types.StateExpiryConfig
fullStateDB ethdb.FullStateDB
}

// NewBlockChain returns a fully initialised block chain using information
Expand Down Expand Up @@ -374,10 +373,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
bc.processor = NewStateProcessor(chainConfig, bc, engine)

var err error
if cacheConfig.EnableStateExpiry {
log.Info("enable state expiry feature", "RemoteEndPoint", cacheConfig.RemoteEndPoint)
bc.enableStateExpiry = true
bc.fullStateDB, err = ethdb.NewFullStateRPCServer(cacheConfig.RemoteEndPoint)
if cacheConfig.StateExpiryCfg.EnableExpiry() {
log.Info("enable state expiry feature", "RemoteEndPoint", cacheConfig.StateExpiryCfg.FullStateEndpoint)
bc.stateExpiryCfg = cacheConfig.StateExpiryCfg
bc.fullStateDB, err = ethdb.NewFullStateRPCServer(cacheConfig.StateExpiryCfg.FullStateEndpoint)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -624,7 +623,15 @@ func (bc *BlockChain) cacheBlock(hash common.Hash, block *types.Block) {
}

func (bc *BlockChain) EnableStateExpiry() bool {
return bc.enableStateExpiry
return bc.stateExpiryCfg.EnableExpiry()
}

func (bc *BlockChain) EnableStateExpiryLocalRevive() bool {
if bc.EnableStateExpiry() {
return bc.stateExpiryCfg.EnableLocalRevive
}

return false
}

func (bc *BlockChain) FullStateDB() ethdb.FullStateDB {
Expand Down Expand Up @@ -1052,8 +1059,8 @@ func (bc *BlockChain) StateAtWithSharedPool(root, startAtBlockHash common.Hash,
if err != nil {
return nil, err
}
if bc.enableStateExpiry {
stateDB.InitStateExpiryFeature(bc.chainConfig, bc.fullStateDB, startAtBlockHash, height)
if bc.EnableStateExpiry() {
stateDB.InitStateExpiryFeature(bc.stateExpiryCfg, bc.fullStateDB, startAtBlockHash, height)
}
return stateDB, err
}
Expand Down Expand Up @@ -2059,8 +2066,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
return it.index, err
}
bc.updateHighestVerifiedHeader(block.Header())
if bc.enableStateExpiry {
statedb.InitStateExpiryFeature(bc.chainConfig, bc.fullStateDB, parent.Hash(), block.Number())
if bc.EnableStateExpiry() {
statedb.InitStateExpiryFeature(bc.stateExpiryCfg, bc.fullStateDB, parent.Hash(), block.Number())
}

// Enable prefetching to pull in trie node paths while processing transactions
Expand All @@ -2071,8 +2078,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
// do Prefetch in a separate goroutine to avoid blocking the critical path
// 1.do state prefetch for snapshot cache
throwaway := statedb.CopyDoPrefetch()
if throwaway != nil && bc.enableStateExpiry {
throwaway.InitStateExpiryFeature(bc.chainConfig, bc.fullStateDB, parent.Hash(), block.Number())
if throwaway != nil && bc.EnableStateExpiry() {
throwaway.InitStateExpiryFeature(bc.stateExpiryCfg, bc.fullStateDB, parent.Hash(), block.Number())
}
go bc.prefetcher.Prefetch(block, throwaway, &bc.vmConfig, interruptCh)

Expand Down Expand Up @@ -2156,7 +2163,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
stats.usedGas += usedGas

dirty, _ := bc.triedb.Size()
stats.report(chain, it.index, dirty, setHead)
stats.report(chain, it.index, dirty, setHead, bc.stateExpiryCfg)

if !setHead {
// After merge we expect few side chains. Simply count
Expand Down
5 changes: 4 additions & 1 deletion core/blockchain_insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const statsReportLimit = 8 * time.Second

// report prints statistics if some number of blocks have been processed
// or more than a few seconds have passed since the last message.
func (st *insertStats) report(chain []*types.Block, index int, dirty common.StorageSize, setHead bool) {
func (st *insertStats) report(chain []*types.Block, index int, dirty common.StorageSize, setHead bool, config *types.StateExpiryConfig) {
// Fetch the timings for the batch
var (
now = mclock.Now()
Expand All @@ -60,6 +60,9 @@ func (st *insertStats) report(chain []*types.Block, index int, dirty common.Stor
"blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000,
"elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed),
}
if config.EnableExpiry() {
context = append(context, []interface{}{"stateEpoch", types.GetStateEpoch(config, end.Number())}...)
}
if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute {
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)
}
Expand Down
6 changes: 4 additions & 2 deletions core/blockchain_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,15 +356,17 @@ func (bc *BlockChain) StateAt(startAtRoot common.Hash, startAtBlockHash common.H
if err != nil {
return nil, err
}
if bc.enableStateExpiry {
sdb.InitStateExpiryFeature(bc.chainConfig, bc.fullStateDB, startAtBlockHash, expectHeight)
if bc.EnableStateExpiry() {
sdb.InitStateExpiryFeature(bc.stateExpiryCfg, bc.fullStateDB, startAtBlockHash, expectHeight)
}
return sdb, err
}

// Config retrieves the chain's fork configuration.
func (bc *BlockChain) Config() *params.ChainConfig { return bc.chainConfig }

func (bc *BlockChain) StateExpiryConfig() *types.StateExpiryConfig { return bc.stateExpiryCfg }

// Engine retrieves the blockchain's consensus engine.
func (bc *BlockChain) Engine() consensus.Engine { return bc.engine }

Expand Down
9 changes: 9 additions & 0 deletions core/rawdb/accessors_epoch_meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ func DeleteEpochMetaPlainState(db ethdb.KeyValueWriter, addr common.Hash, path s
return db.Delete(epochMetaPlainStateKey(addr, path))
}

func ReadStateExpiryCfg(db ethdb.Reader) []byte {
val, _ := db.Get(stateExpiryCfgKey)
return val
}

func WriteStateExpiryCfg(db ethdb.KeyValueWriter, val []byte) error {
return db.Put(stateExpiryCfgKey, val)
}

func epochMetaPlainStateKey(addr common.Hash, path string) []byte {
key := make([]byte, len(EpochMetaPlainStatePrefix)+len(addr)+len(path))
copy(key[:], EpochMetaPlainStatePrefix)
Expand Down
6 changes: 5 additions & 1 deletion core/rawdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
accountSnaps stat
storageSnaps stat
snapJournal stat
trieJournal stat
preimages stat
bloomBits stat
cliqueSnaps stat
Expand Down Expand Up @@ -691,6 +692,8 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
epochMetaMetaSize.Add(size)
case bytes.Equal(key, snapshotJournalKey):
snapJournal.Add(size)
case bytes.Equal(key, trieJournalKey):
trieJournal.Add(size)
case bytes.Equal(key, epochMetaSnapshotJournalKey):
epochMetaSnapJournalSize.Add(size)
case bytes.HasPrefix(key, EpochMetaPlainStatePrefix) && len(key) >= (len(EpochMetaPlainStatePrefix)+common.HashLength):
Expand All @@ -702,7 +705,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
lastPivotKey, fastTrieProgressKey, snapshotDisabledKey, SnapshotRootKey,
snapshotGeneratorKey, snapshotRecoveryKey, txIndexTailKey, fastTxLookupLimitKey,
uncleanShutdownKey, badBlockKey, transitionStatusKey, skeletonSyncStatusKey,
persistentStateIDKey, trieJournalKey, snapshotSyncStatusKey,
persistentStateIDKey, snapshotSyncStatusKey,
} {
if bytes.Equal(key, meta) {
metadata.Add(size)
Expand Down Expand Up @@ -735,6 +738,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
{"Key-Value store", "Path trie state lookups", stateLookups.Size(), stateLookups.Count()},
{"Key-Value store", "Path trie account nodes", accountTries.Size(), accountTries.Count()},
{"Key-Value store", "Path trie storage nodes", storageTries.Size(), storageTries.Count()},
{"Key-Value store", "Path trie snap journal", trieJournal.Size(), trieJournal.Count()},
{"Key-Value store", "Trie preimages", preimages.Size(), preimages.Count()},
{"Key-Value store", "Account snapshot", accountSnaps.Size(), accountSnaps.Count()},
{"Key-Value store", "Storage snapshot", storageSnaps.Size(), storageSnaps.Count()},
Expand Down
Loading
Loading