mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
Revert "cmd, core: resolve scheme from a read-write database (#28313)"
This reverts commit 9a372b6518.
This commit is contained in:
parent
408b7aef0e
commit
eaadb8f260
7 changed files with 92 additions and 58 deletions
|
|
@ -474,7 +474,7 @@ func dump(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
triedb := utils.MakeTrieDatabase(ctx, db, true, true) // always enable preimage lookup
|
triedb := utils.MakeTrieDatabase(ctx, db, true, false) // always enable preimage lookup
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
|
|
||||||
state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||||
|
|
|
||||||
|
|
@ -268,6 +268,7 @@ var (
|
||||||
StateSchemeFlag = &cli.StringFlag{
|
StateSchemeFlag = &cli.StringFlag{
|
||||||
Name: "state.scheme",
|
Name: "state.scheme",
|
||||||
Usage: "Scheme to use for storing ethereum state ('hash' or 'path')",
|
Usage: "Scheme to use for storing ethereum state ('hash' or 'path')",
|
||||||
|
Value: rawdb.HashScheme,
|
||||||
Category: flags.StateCategory,
|
Category: flags.StateCategory,
|
||||||
}
|
}
|
||||||
StateHistoryFlag = &cli.Uint64Flag{
|
StateHistoryFlag = &cli.Uint64Flag{
|
||||||
|
|
@ -1720,9 +1721,15 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
if ctx.IsSet(StateHistoryFlag.Name) {
|
if ctx.IsSet(StateHistoryFlag.Name) {
|
||||||
cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name)
|
cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name)
|
||||||
}
|
}
|
||||||
if ctx.IsSet(StateSchemeFlag.Name) {
|
// Parse state scheme, abort the process if it's not compatible.
|
||||||
cfg.StateScheme = ctx.String(StateSchemeFlag.Name)
|
chaindb := tryMakeReadOnlyDatabase(ctx, stack)
|
||||||
|
scheme, err := ParseStateScheme(ctx, chaindb)
|
||||||
|
chaindb.Close()
|
||||||
|
if err != nil {
|
||||||
|
Fatalf("%v", err)
|
||||||
}
|
}
|
||||||
|
cfg.StateScheme = scheme
|
||||||
|
|
||||||
// Parse transaction history flag, if user is still using legacy config
|
// Parse transaction history flag, if user is still using legacy config
|
||||||
// file with 'TxLookupLimit' configured, copy the value to 'TransactionHistory'.
|
// file with 'TxLookupLimit' configured, copy the value to 'TransactionHistory'.
|
||||||
if cfg.TransactionHistory == ethconfig.Defaults.TransactionHistory && cfg.TxLookupLimit != ethconfig.Defaults.TxLookupLimit {
|
if cfg.TransactionHistory == ethconfig.Defaults.TransactionHistory && cfg.TxLookupLimit != ethconfig.Defaults.TxLookupLimit {
|
||||||
|
|
@ -2158,7 +2165,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
||||||
if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
|
if gcmode := ctx.String(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
|
||||||
Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
|
Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
|
||||||
}
|
}
|
||||||
scheme, err := rawdb.ParseStateScheme(ctx.String(StateSchemeFlag.Name), chainDb)
|
scheme, err := ParseStateScheme(ctx, chainDb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("%v", err)
|
Fatalf("%v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2217,12 +2224,47 @@ func MakeConsolePreloads(ctx *cli.Context) []string {
|
||||||
return preloads
|
return preloads
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseStateScheme resolves scheme identifier from CLI flag. If the provided
|
||||||
|
// state scheme is not compatible with the one of persistent scheme, an error
|
||||||
|
// will be returned.
|
||||||
|
//
|
||||||
|
// - none: use the scheme consistent with persistent state, or fallback
|
||||||
|
// to hash-based scheme if state is empty.
|
||||||
|
// - hash: use hash-based scheme or error out if not compatible with
|
||||||
|
// persistent state scheme.
|
||||||
|
// - path: use path-based scheme or error out if not compatible with
|
||||||
|
// persistent state scheme.
|
||||||
|
func ParseStateScheme(ctx *cli.Context, disk ethdb.Database) (string, error) {
|
||||||
|
// If state scheme is not specified, use the scheme consistent
|
||||||
|
// with persistent state, or fallback to hash mode if database
|
||||||
|
// is empty.
|
||||||
|
stored := rawdb.ReadStateScheme(disk)
|
||||||
|
if !ctx.IsSet(StateSchemeFlag.Name) {
|
||||||
|
if stored == "" {
|
||||||
|
// use default scheme for empty database, flip it when
|
||||||
|
// path mode is chosen as default
|
||||||
|
log.Info("State schema set to default", "scheme", "hash")
|
||||||
|
return rawdb.HashScheme, nil
|
||||||
|
}
|
||||||
|
log.Info("State scheme set to already existing", "scheme", stored)
|
||||||
|
return stored, nil // reuse scheme of persistent scheme
|
||||||
|
}
|
||||||
|
// If state scheme is specified, ensure it's compatible with
|
||||||
|
// persistent state.
|
||||||
|
scheme := ctx.String(StateSchemeFlag.Name)
|
||||||
|
if stored == "" || scheme == stored {
|
||||||
|
log.Info("State scheme set by user", "scheme", scheme)
|
||||||
|
return scheme, nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("incompatible state scheme, stored: %s, provided: %s", stored, scheme)
|
||||||
|
}
|
||||||
|
|
||||||
// MakeTrieDatabase constructs a trie database based on the configured scheme.
|
// MakeTrieDatabase constructs a trie database based on the configured scheme.
|
||||||
func MakeTrieDatabase(ctx *cli.Context, disk ethdb.Database, preimage bool, readOnly bool) *trie.Database {
|
func MakeTrieDatabase(ctx *cli.Context, disk ethdb.Database, preimage bool, readOnly bool) *trie.Database {
|
||||||
config := &trie.Config{
|
config := &trie.Config{
|
||||||
Preimages: preimage,
|
Preimages: preimage,
|
||||||
}
|
}
|
||||||
scheme, err := rawdb.ParseStateScheme(ctx.String(StateSchemeFlag.Name), disk)
|
scheme, err := ParseStateScheme(ctx, disk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("%v", err)
|
Fatalf("%v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,8 +120,8 @@ func (ga *GenesisAlloc) UnmarshalJSON(data []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash computes the state root according to the genesis specification.
|
// deriveHash computes the state root according to the genesis specification.
|
||||||
func (ga *GenesisAlloc) hash() (common.Hash, error) {
|
func (ga *GenesisAlloc) deriveHash() (common.Hash, error) {
|
||||||
// Create an ephemeral in-memory database for computing hash,
|
// Create an ephemeral in-memory database for computing hash,
|
||||||
// all the derived states will be discarded to not pollute disk.
|
// all the derived states will be discarded to not pollute disk.
|
||||||
db := state.NewDatabase(rawdb.NewMemoryDatabase())
|
db := state.NewDatabase(rawdb.NewMemoryDatabase())
|
||||||
|
|
@ -142,9 +142,9 @@ func (ga *GenesisAlloc) hash() (common.Hash, error) {
|
||||||
return statedb.Commit(0, false)
|
return statedb.Commit(0, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// flush is very similar with hash, but the main difference is all the generated
|
// flush is very similar with deriveHash, but the main difference is
|
||||||
// states will be persisted into the given database. Also, the genesis state
|
// all the generated states will be persisted into the given database.
|
||||||
// specification will be flushed as well.
|
// Also, the genesis state specification will be flushed as well.
|
||||||
func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error {
|
func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error {
|
||||||
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -179,6 +179,39 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhas
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CommitGenesisState loads the stored genesis state with the given block
|
||||||
|
// hash and commits it into the provided trie database.
|
||||||
|
func CommitGenesisState(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error {
|
||||||
|
var alloc GenesisAlloc
|
||||||
|
blob := rawdb.ReadGenesisStateSpec(db, blockhash)
|
||||||
|
if len(blob) != 0 {
|
||||||
|
if err := alloc.UnmarshalJSON(blob); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Genesis allocation is missing and there are several possibilities:
|
||||||
|
// the node is legacy which doesn't persist the genesis allocation or
|
||||||
|
// the persisted allocation is just lost.
|
||||||
|
// - supported networks(mainnet, testnets), recover with defined allocations
|
||||||
|
// - private network, can't recover
|
||||||
|
var genesis *Genesis
|
||||||
|
switch blockhash {
|
||||||
|
case params.MainnetGenesisHash:
|
||||||
|
genesis = DefaultGenesisBlock()
|
||||||
|
case params.GoerliGenesisHash:
|
||||||
|
genesis = DefaultGoerliGenesisBlock()
|
||||||
|
case params.SepoliaGenesisHash:
|
||||||
|
genesis = DefaultSepoliaGenesisBlock()
|
||||||
|
}
|
||||||
|
if genesis != nil {
|
||||||
|
alloc = genesis.Alloc
|
||||||
|
} else {
|
||||||
|
return errors.New("not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return alloc.flush(db, triedb, blockhash)
|
||||||
|
}
|
||||||
|
|
||||||
// GenesisAccount is an account in the state of the genesis block.
|
// GenesisAccount is an account in the state of the genesis block.
|
||||||
type GenesisAccount struct {
|
type GenesisAccount struct {
|
||||||
Code []byte `json:"code,omitempty"`
|
Code []byte `json:"code,omitempty"`
|
||||||
|
|
@ -411,7 +444,7 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
|
||||||
|
|
||||||
// ToBlock returns the genesis block according to genesis specification.
|
// ToBlock returns the genesis block according to genesis specification.
|
||||||
func (g *Genesis) ToBlock() *types.Block {
|
func (g *Genesis) ToBlock() *types.Block {
|
||||||
root, err := g.Alloc.hash()
|
root, err := g.Alloc.deriveHash()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ func TestReadWriteGenesisAlloc(t *testing.T) {
|
||||||
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
|
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
|
||||||
{2}: {Balance: big.NewInt(2), Storage: map[common.Hash]common.Hash{{2}: {2}}},
|
{2}: {Balance: big.NewInt(2), Storage: map[common.Hash]common.Hash{{2}: {2}}},
|
||||||
}
|
}
|
||||||
hash, _ = alloc.hash()
|
hash, _ = alloc.deriveHash()
|
||||||
)
|
)
|
||||||
blob, _ := json.Marshal(alloc)
|
blob, _ := json.Marshal(alloc)
|
||||||
rawdb.WriteGenesisStateSpec(db, hash, blob)
|
rawdb.WriteGenesisStateSpec(db, hash, blob)
|
||||||
|
|
|
||||||
|
|
@ -305,38 +305,3 @@ func ReadStateScheme(db ethdb.Reader) string {
|
||||||
}
|
}
|
||||||
return HashScheme
|
return HashScheme
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseStateScheme checks if the specified state scheme is compatible with
|
|
||||||
// the stored state.
|
|
||||||
//
|
|
||||||
// - If the provided scheme is none, use the scheme consistent with persistent
|
|
||||||
// state, or fallback to hash-based scheme if state is empty.
|
|
||||||
//
|
|
||||||
// - If the provided scheme is hash, use hash-based scheme or error out if not
|
|
||||||
// compatible with persistent state scheme.
|
|
||||||
//
|
|
||||||
// - If the provided scheme is path: use path-based scheme or error out if not
|
|
||||||
// compatible with persistent state scheme.
|
|
||||||
func ParseStateScheme(provided string, disk ethdb.Database) (string, error) {
|
|
||||||
// If state scheme is not specified, use the scheme consistent
|
|
||||||
// with persistent state, or fallback to hash mode if database
|
|
||||||
// is empty.
|
|
||||||
stored := ReadStateScheme(disk)
|
|
||||||
if provided == "" {
|
|
||||||
if stored == "" {
|
|
||||||
// use default scheme for empty database, flip it when
|
|
||||||
// path mode is chosen as default
|
|
||||||
log.Info("State schema set to default", "scheme", "hash")
|
|
||||||
return HashScheme, nil
|
|
||||||
}
|
|
||||||
log.Info("State scheme set to already existing", "scheme", stored)
|
|
||||||
return stored, nil // reuse scheme of persistent scheme
|
|
||||||
}
|
|
||||||
// If state scheme is specified, ensure it's compatible with
|
|
||||||
// persistent state.
|
|
||||||
if stored == "" || provided == stored {
|
|
||||||
log.Info("State scheme set by user", "scheme", provided)
|
|
||||||
return provided, nil
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("incompatible state scheme, stored: %s, provided: %s", stored, provided)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -133,12 +133,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
scheme, err := rawdb.ParseStateScheme(config.StateScheme, chainDb)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Try to recover offline state pruning only in hash-based.
|
// Try to recover offline state pruning only in hash-based.
|
||||||
if scheme == rawdb.HashScheme {
|
if config.StateScheme == rawdb.HashScheme {
|
||||||
if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb); err != nil {
|
if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb); err != nil {
|
||||||
log.Error("Failed to recover state", "error", err)
|
log.Error("Failed to recover state", "error", err)
|
||||||
}
|
}
|
||||||
|
|
@ -198,7 +194,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
SnapshotLimit: config.SnapshotCache,
|
SnapshotLimit: config.SnapshotCache,
|
||||||
Preimages: config.Preimages,
|
Preimages: config.Preimages,
|
||||||
StateHistory: config.StateHistory,
|
StateHistory: config.StateHistory,
|
||||||
StateScheme: scheme,
|
StateScheme: config.StateScheme,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
// Override the chain config with provided settings.
|
// Override the chain config with provided settings.
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/clique"
|
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
|
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
|
|
@ -63,6 +64,7 @@ var Defaults = Config{
|
||||||
TxLookupLimit: 2350000,
|
TxLookupLimit: 2350000,
|
||||||
TransactionHistory: 2350000,
|
TransactionHistory: 2350000,
|
||||||
StateHistory: params.FullImmutabilityThreshold,
|
StateHistory: params.FullImmutabilityThreshold,
|
||||||
|
StateScheme: rawdb.HashScheme,
|
||||||
LightPeers: 100,
|
LightPeers: 100,
|
||||||
DatabaseCache: 512,
|
DatabaseCache: 512,
|
||||||
TrieCleanCache: 154,
|
TrieCleanCache: 154,
|
||||||
|
|
@ -103,11 +105,7 @@ type Config struct {
|
||||||
TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved.
|
TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved.
|
||||||
TransactionHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved.
|
TransactionHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved.
|
||||||
StateHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose state histories are reserved.
|
StateHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose state histories are reserved.
|
||||||
|
StateScheme string `toml:",omitempty"` // State scheme used to store ethereum state and merkle trie nodes on top
|
||||||
// State scheme represents the scheme used to store ethereum states and trie
|
|
||||||
// nodes on top. It can be 'hash', 'path', or none which means use the scheme
|
|
||||||
// consistent with persistent state.
|
|
||||||
StateScheme string `toml:",omitempty"`
|
|
||||||
|
|
||||||
// RequiredBlocks is a set of block number -> hash mappings which must be in the
|
// RequiredBlocks is a set of block number -> hash mappings which must be in the
|
||||||
// canonical chain of all remote peers. Setting the option makes geth verify the
|
// canonical chain of all remote peers. Setting the option makes geth verify the
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue