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

core, trie/triedb/pathdb: adjust pathdb for verkle #28297

Closed
wants to merge 1 commit into from
Closed
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
11 changes: 9 additions & 2 deletions cmd/geth/dbcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,18 @@ func removeDB(ctx *cli.Context) error {
ancientDir = config.Node.ResolvePath(ancientDir)
}
// Delete state data
statePaths := []string{rootDir, filepath.Join(ancientDir, rawdb.StateFreezerName)}
statePaths := []string{
rootDir,
filepath.Join(ancientDir, rawdb.MerkleStateFreezerName),
filepath.Join(ancientDir, rawdb.VerkleStateFreezerName),
}
confirmAndRemoveDB(statePaths, "state data", ctx, removeStateDataFlag.Name)

// Delete ancient chain
chainPaths := []string{filepath.Join(ancientDir, rawdb.ChainFreezerName)}
chainPaths := []string{filepath.Join(
ancientDir,
rawdb.ChainFreezerName,
)}
confirmAndRemoveDB(chainPaths, "ancient chain", ctx, removeChainDataFlag.Name)
return nil
}
Expand Down
49 changes: 20 additions & 29 deletions core/rawdb/accessors_trie.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,10 @@ func (h *hasher) release() {
hasherPool.Put(h)
}

// ReadAccountTrieNode retrieves the account trie node and the associated node
// hash with the specified node path.
func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) ([]byte, common.Hash) {
data, err := db.Get(accountTrieNodeKey(path))
if err != nil {
return nil, common.Hash{}
}
h := newHasher()
defer h.release()
return data, h.hash(data)
// ReadAccountTrieNode retrieves the account trie node with the specified node path.
func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) []byte {
data, _ := db.Get(accountTrieNodeKey(path))
return data
}

// HasAccountTrieNode checks the account trie node presence with the specified
Expand Down Expand Up @@ -113,16 +107,10 @@ func DeleteAccountTrieNode(db ethdb.KeyValueWriter, path []byte) {
}
}

// ReadStorageTrieNode retrieves the storage trie node and the associated node
// hash with the specified node path.
func ReadStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) ([]byte, common.Hash) {
data, err := db.Get(storageTrieNodeKey(accountHash, path))
if err != nil {
return nil, common.Hash{}
}
h := newHasher()
defer h.release()
return data, h.hash(data)
// ReadStorageTrieNode retrieves the storage trie node with the specified node path.
func ReadStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) []byte {
data, _ := db.Get(storageTrieNodeKey(accountHash, path))
return data
}

// HasStorageTrieNode checks the storage trie node presence with the provided
Expand Down Expand Up @@ -220,16 +208,15 @@ func ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash
case HashScheme:
return ReadLegacyTrieNode(db, hash)
case PathScheme:
var (
blob []byte
nHash common.Hash
)
var blob []byte
if owner == (common.Hash{}) {
blob, nHash = ReadAccountTrieNode(db, path)
blob = ReadAccountTrieNode(db, path)
} else {
blob, nHash = ReadStorageTrieNode(db, owner, path)
blob = ReadStorageTrieNode(db, owner, path)
}
if nHash != hash {
h := newHasher()
defer h.release()
if h.hash(blob) != hash {
return nil
}
return blob
Expand Down Expand Up @@ -287,8 +274,12 @@ func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, has
// ReadStateScheme reads the state scheme of persistent state, or none
// if the state is not present in database.
func ReadStateScheme(db ethdb.Reader) string {
// Check if state in path-based scheme is present
blob, _ := ReadAccountTrieNode(db, nil)
// Check if state in path-based scheme is present, it can be either
// merkle tree or verkle tree.
blob := ReadAccountTrieNode(db, nil)
if len(blob) == 0 {
blob, _ = db.Get(verkleTrieNodeKey(nil)) // FIX HACK(rjl493456442)
}
if len(blob) != 0 {
return PathScheme
}
Expand Down
17 changes: 12 additions & 5 deletions core/rawdb/ancient_scheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,21 @@ var stateFreezerNoSnappy = map[string]bool{

// The list of identifiers of ancient stores.
var (
ChainFreezerName = "chain" // the folder name of chain segment ancient store.
StateFreezerName = "state" // the folder name of reverse diff ancient store.
ChainFreezerName = "chain" // the folder name of chain segment ancient store.
MerkleStateFreezerName = "state" // the folder name of reverse diff ancient store.
VerkleStateFreezerName = "state_verkle" // the folder name of reverse diff ancient store.
)

// freezers the collections of all builtin freezers.
var freezers = []string{ChainFreezerName, StateFreezerName}
var freezers = []string{ChainFreezerName, MerkleStateFreezerName, VerkleStateFreezerName}

// NewStateFreezer initializes the freezer for state history.
func NewStateFreezer(ancientDir string, readOnly bool) (*ResettableFreezer, error) {
return NewResettableFreezer(filepath.Join(ancientDir, StateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
func NewStateFreezer(ancientDir string, verkle bool, readOnly bool) (*ResettableFreezer, error) {
var name string
if verkle {
name = filepath.Join(ancientDir, VerkleStateFreezerName)
} else {
name = filepath.Join(ancientDir, MerkleStateFreezerName)
}
return NewResettableFreezer(name, "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
}
13 changes: 5 additions & 8 deletions core/rawdb/ancient_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,21 +88,18 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
}
infos = append(infos, info)

case StateFreezerName:
if ReadStateScheme(db) != PathScheme {
continue
}
case MerkleStateFreezerName, VerkleStateFreezerName:
datadir, err := db.AncientDatadir()
if err != nil {
return nil, err
}
f, err := NewStateFreezer(datadir, true)
f, err := NewStateFreezer(datadir, freezer == VerkleStateFreezerName, true)
if err != nil {
return nil, err
continue // might be possible the state freezer is not existent
}
defer f.Close()

info, err := inspect(StateFreezerName, stateFreezerNoSnappy, f)
info, err := inspect(freezer, stateFreezerNoSnappy, f)
if err != nil {
return nil, err
}
Expand All @@ -127,7 +124,7 @@ func InspectFreezerTable(ancient string, freezerName string, tableName string, s
switch freezerName {
case ChainFreezerName:
path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy
case StateFreezerName:
case MerkleStateFreezerName, VerkleStateFreezerName:
path, tables = filepath.Join(ancient, freezerName), stateFreezerNoSnappy
default:
return fmt.Errorf("unknown freezer, supported ones: %v", freezers)
Expand Down
20 changes: 20 additions & 0 deletions core/rawdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,10 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
beaconHeaders stat
cliqueSnaps stat

// Verkle statistics
verkleTries stat
verkleStateLookups stat

// Les statistic
chtTrieNodes stat
bloomTrieNodes stat
Expand Down Expand Up @@ -549,6 +553,20 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
bytes.HasPrefix(key, BloomTrieIndexPrefix) ||
bytes.HasPrefix(key, BloomTriePrefix): // Bloomtrie sub
bloomTrieNodes.Add(size)
case bytes.HasPrefix(key, VerklePrefix):
remain := key[len(VerklePrefix):]
switch {
case IsAccountTrieNode(remain):
verkleTries.Add(size)
case bytes.HasPrefix(remain, stateIDPrefix) && len(remain) == len(stateIDPrefix)+common.HashLength:
verkleStateLookups.Add(size)
case bytes.Equal(remain, persistentStateIDKey):
metadata.Add(size)
case bytes.Equal(remain, trieJournalKey):
metadata.Add(size)
case bytes.Equal(remain, snapshotSyncStatusKey):
metadata.Add(size)
}
default:
var accounted bool
for _, meta := range [][]byte{
Expand Down Expand Up @@ -595,6 +613,8 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
{"Key-Value store", "Beacon sync headers", beaconHeaders.Size(), beaconHeaders.Count()},
{"Key-Value store", "Clique snapshots", cliqueSnaps.Size(), cliqueSnaps.Count()},
{"Key-Value store", "Singleton metadata", metadata.Size(), metadata.Count()},
{"Key-Value store", "Verkle trie nodes", verkleTries.Size(), verkleTries.Count()},
{"Key-Value store", "Verkle trie state lookups", verkleStateLookups.Size(), verkleStateLookups.Count()},
{"Light client", "CHT trie nodes", chtTrieNodes.Size(), chtTrieNodes.Count()},
{"Light client", "Bloom trie nodes", bloomTrieNodes.Size(), bloomTrieNodes.Count()},
}
Expand Down
9 changes: 9 additions & 0 deletions core/rawdb/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ var (
trieNodeStoragePrefix = []byte("O") // trieNodeStoragePrefix + accountHash + hexPath -> trie node
stateIDPrefix = []byte("L") // stateIDPrefix + state root -> state id

// VerklePrefix is the prefix of verkle states(verkle trie nodes,
// trie journal, persistent state id, state id lookups).
VerklePrefix = []byte("v")

PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage
configPrefix = []byte("ethereum-config-") // config prefix for the db
genesisPrefix = []byte("ethereum-genesis-") // genesis state prefix for the db
Expand Down Expand Up @@ -270,6 +274,11 @@ func accountTrieNodeKey(path []byte) []byte {
return append(trieNodeAccountPrefix, path...)
}

// verkleTrieNodeKey = verklePrefix + trieNodeAccountPrefix + nodePath.
func verkleTrieNodeKey(path []byte) []byte {
return append(VerklePrefix, append(trieNodeAccountPrefix, path...)...)
}

// storageTrieNodeKey = trieNodeStoragePrefix + accountHash + nodePath.
func storageTrieNodeKey(accountHash common.Hash, path []byte) []byte {
buf := make([]byte, len(trieNodeStoragePrefix)+common.HashLength+len(path))
Expand Down
37 changes: 32 additions & 5 deletions trie/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"errors"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie/triedb/hashdb"
Expand All @@ -28,6 +29,23 @@ import (
"github.com/ethereum/go-ethereum/trie/triestate"
)

// Reader wraps the Node method of a backing trie store.
type Reader interface {
// Node retrieves the trie node blob with the provided trie identifier, node path and
// the corresponding node hash. No error will be returned if the node is not found.
//
// When looking up nodes in the account trie, 'owner' is the zero hash. For contract
// storage trie nodes, 'owner' is the hash of the account address that containing the
// storage.
//
// Notably, the provided hash might be useless in path mode if hash check is
// configured as disabled, e.g. in the verkle context.
//
// Don't modify the returned byte slice since it's not deep-copied and still
// be referenced by database.
Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error)
}

// Config defines all necessary options for database.
type Config struct {
Preimages bool // Flag whether the preimage of node key is recorded
Expand All @@ -40,15 +58,21 @@ type Config struct {
// default settings.
var HashDefaults = &Config{
Preimages: false,
IsVerkle: false,
HashDB: hashdb.Defaults,
}

// PathDefaults represents a config for using path-based scheme with
// default settings.
var PathDefaults = &Config{
Preimages: false,
IsVerkle: false,
PathDB: pathdb.Defaults,
}

// backend defines the methods needed to access/update trie nodes in different
// state scheme.
type backend interface {
// Scheme returns the identifier of used storage scheme.
Scheme() string

// Initialized returns an indicator if the state data is already initialized
// according to the state scheme.
Initialized(genesisRoot common.Hash) bool
Expand Down Expand Up @@ -106,7 +130,7 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
log.Crit("Both 'hash' and 'path' mode are configured")
}
if config.PathDB != nil {
db.backend = pathdb.New(diskdb, config.PathDB)
db.backend = pathdb.New(diskdb, config.PathDB, config.IsVerkle)
} else {
db.backend = hashdb.New(diskdb, config.HashDB, mptResolver{})
}
Expand Down Expand Up @@ -172,7 +196,10 @@ func (db *Database) Initialized(genesisRoot common.Hash) bool {

// Scheme returns the node scheme used in the database.
func (db *Database) Scheme() string {
return db.backend.Scheme()
if db.config.PathDB != nil {
return rawdb.PathScheme
}
return rawdb.HashScheme
}

// Close flushes the dangling preimages to disk and closes the trie database.
Expand Down
8 changes: 4 additions & 4 deletions trie/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package trie
import (
"errors"
"fmt"
"github.com/ethereum/go-ethereum/crypto"
"sync"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -691,13 +692,12 @@ func (s *Sync) hasNode(owner common.Hash, path []byte, hash common.Hash) (exists
}
// If node is running with path scheme, check the presence with node path.
var blob []byte
var dbHash common.Hash
if owner == (common.Hash{}) {
blob, dbHash = rawdb.ReadAccountTrieNode(s.database, path)
blob = rawdb.ReadAccountTrieNode(s.database, path)
} else {
blob, dbHash = rawdb.ReadStorageTrieNode(s.database, owner, path)
blob = rawdb.ReadStorageTrieNode(s.database, owner, path)
}
exists = hash == dbHash
exists = hash == crypto.Keccak256Hash(blob)
inconsistent = !exists && len(blob) != 0
return exists, inconsistent
}
Expand Down
13 changes: 0 additions & 13 deletions trie/trie_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,6 @@ import (
"github.com/ethereum/go-ethereum/trie/triestate"
)

// Reader wraps the Node method of a backing trie store.
type Reader interface {
// Node retrieves the trie node blob with the provided trie identifier, node path and
// the corresponding node hash. No error will be returned if the node is not found.
//
// When looking up nodes in the account trie, 'owner' is the zero hash. For contract
// storage trie nodes, 'owner' is the hash of the account address that containing the
// storage.
//
// TODO(rjl493456442): remove the 'hash' parameter, it's redundant in PBSS.
Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error)
}

// trieReader is a wrapper of the underlying node reader. It's not safe
// for concurrent usage.
type trieReader struct {
Expand Down
5 changes: 0 additions & 5 deletions trie/triedb/hashdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -624,11 +624,6 @@ func (db *Database) Close() error {
return nil
}

// Scheme returns the node scheme used in the database.
func (db *Database) Scheme() string {
return rawdb.HashScheme
}

// Reader retrieves a node reader belonging to the given state root.
// An error will be returned if the requested state is not available.
func (db *Database) Reader(root common.Hash) (*reader, error) {
Expand Down
Loading
Loading