Skip to content

Commit

Permalink
core, trie: create verkle namespace
Browse files Browse the repository at this point in the history
  • Loading branch information
rjl493456442 committed Aug 28, 2023
1 parent 186bb05 commit df64a21
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 43 deletions.
3 changes: 3 additions & 0 deletions core/rawdb/accessors_trie.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, has
func ReadStateScheme(db ethdb.Reader) string {
// Check if state in path-based scheme is present
blob := ReadAccountTrieNode(db, nil)
if len(blob) == 0 {
blob = ReadAccountTrieNode(db, []byte(VerklePrefix))
}
if len(blob) != 0 {
return PathScheme
}
Expand Down
15 changes: 11 additions & 4 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.
stateFreezerName = "state" // the folder name of state history
verkleFreezerName = "state/verkle" // the ancient store name of verkle state history
)

// freezers the collections of all builtin freezers.
var freezers = []string{chainFreezerName, stateFreezerName}

// 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, stateFreezerName)
} else {
name = filepath.Join(ancientDir, verkleFreezerName)
}
return NewResettableFreezer(name, "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
}
5 changes: 3 additions & 2 deletions core/rawdb/ancient_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,13 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
}
infos = append(infos, info)

case stateFreezerName:
case stateFreezerName, verkleFreezerName:
datadir, err := db.AncientDatadir()
if err != nil {
return nil, err
}
f, err := NewStateFreezer(datadir, true)
verkle := freezer == verkleFreezerName
f, err := NewStateFreezer(datadir, verkle, true)
if err != nil {
return nil, err
}
Expand Down
6 changes: 5 additions & 1 deletion core/rawdb/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,11 @@ var (
// Path-based storage scheme of merkle patricia trie.
trieNodeAccountPrefix = []byte("A") // trieNodeAccountPrefix + hexPath -> trie node
trieNodeStoragePrefix = []byte("O") // trieNodeStoragePrefix + accountHash + hexPath -> trie node
stateIDPrefix = []byte("L") // stateIDPrefix + state root -> state id
stateIDPrefix = []byte("L") // stateIDPrefix + state root + (verkle suffix) -> state id

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

PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage
configPrefix = []byte("ethereum-config-") // config prefix for the db
Expand Down
31 changes: 16 additions & 15 deletions trie/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Reader interface {
// Config defines all necessary options for database.
type Config struct {
Preimages bool // Flag whether the preimage of node key is recorded
Verkle bool // Flag whether the database is opened in verkle mode
HashDB *hashdb.Config // Configs for hash-based scheme
PathDB *pathdb.Config // Configs for experimental path-based scheme

Expand All @@ -55,9 +56,18 @@ type Config struct {
// default settings.
var HashDefaults = &Config{
Preimages: false,
Verkle: false,
HashDB: hashdb.Defaults,
}

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

// backend defines the methods needed to access/update trie nodes in different
// state scheme.
type backend interface {
Expand Down Expand Up @@ -101,20 +111,6 @@ type Database struct {
backend backend // The backend for managing trie nodes
}

// prepare initializes the database with provided configs, but the
// database backend is still left as nil.
func prepare(diskdb ethdb.Database, config *Config) *Database {
var preimages *preimageStore
if config != nil && config.Preimages {
preimages = newPreimageStore(diskdb)
}
return &Database{
config: config,
diskdb: diskdb,
preimages: preimages,
}
}

// NewDatabase initializes the trie database with default settings, note
// the legacy hash-based scheme is used by default.
func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
Expand All @@ -135,7 +131,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.Verkle, config.PathDB)
} else {
db.backend = hashdb.New(diskdb, config.HashDB, mptResolver{})
}
Expand Down Expand Up @@ -222,6 +218,11 @@ func (db *Database) WritePreimages() {
}
}

// Verkle returns if database is opened in verkle mode.
func (db *Database) Verkle() bool {
return db.config.Verkle
}

// Cap iteratively flushes old but still referenced trie nodes until the total
// memory usage goes below the given threshold. The held pre-images accumulated
// up to this point will be flushed in case the size exceeds the threshold.
Expand Down
8 changes: 4 additions & 4 deletions trie/database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ import (

// newTestDatabase initializes the trie database with specified scheme.
func newTestDatabase(diskdb ethdb.Database, scheme string) *Database {
db := prepare(diskdb, nil)
config := &Config{}
if scheme == rawdb.HashScheme {
db.backend = hashdb.New(diskdb, &hashdb.Config{}, mptResolver{})
config.HashDB = &hashdb.Config{CleanCacheSize: 0}
} else {
db.backend = pathdb.New(diskdb, &pathdb.Config{}) // disable clean/dirty cache
config.PathDB = &pathdb.Config{CleanCacheSize: 0}
}
return db
return NewDatabase(diskdb, config)
}
28 changes: 23 additions & 5 deletions trie/triedb/pathdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ type Database struct {
// It will be set automatically when the database is journaled during
// the shutdown to reject all following unexpected mutations.
readOnly bool // Indicator if database is opened in read only mode
verkle bool // Indicator if database is opened in verkle mode
bufferSize int // Memory allowance (in bytes) for caching dirty nodes
config *Config // Configuration for database
diskdb ethdb.Database // Persistent storage for matured trie nodes
Expand All @@ -141,14 +142,23 @@ type Database struct {
// New attempts to load an already existing layer from a persistent key-value
// store (with a number of memory layers from a journal). If the journal is not
// matched with the base persistent layer, all the recorded diff layers are discarded.
func New(diskdb ethdb.Database, config *Config) *Database {
func New(diskdb ethdb.Database, verkle bool, config *Config) *Database {
if config == nil {
config = Defaults
}
config = config.sanitize()

// Establish a dedicated database namespace tailored for Verkle-specific
// data, ensuring the isolation of both Verkle and MPT tree data. It's
// important to note that the introduction of a prefix won't lead to
// substantial storage overhead, as the underlying database will efficiently
// compress the shared key prefix.
if verkle {
diskdb = rawdb.NewTable(diskdb, rawdb.VerklePrefix)
}
db := &Database{
readOnly: config.ReadOnly,
verkle: verkle,
bufferSize: config.DirtyCacheSize,
config: config,
diskdb: diskdb,
Expand All @@ -164,7 +174,7 @@ func New(diskdb ethdb.Database, config *Config) *Database {
// mechanism also ensures that at most one **non-readOnly** database
// is opened at the same time to prevent accidental mutation.
if ancient, err := diskdb.AncientDatadir(); err == nil && ancient != "" && !db.readOnly {
freezer, err := rawdb.NewStateFreezer(ancient, false)
freezer, err := rawdb.NewStateFreezer(ancient, verkle, false)
if err != nil {
log.Crit("Failed to open state history freezer", "err", err)
}
Expand All @@ -180,13 +190,18 @@ func New(diskdb ethdb.Database, config *Config) *Database {
log.Warn("Truncated extra state histories", "number", pruned)
}
}
log.Warn("Path-based state scheme is an experimental feature")
var contexts []interface{}
if verkle {
contexts = append(contexts, "verkle", true)
}
log.Warn("Path-based state scheme is an experimental feature", contexts...)
return db
}

// reader is a state reader of Database which implements the Reader interface.
type reader struct {
l layer
l layer
verkle bool
}

func (r *reader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) {
Expand All @@ -197,6 +212,9 @@ func (r *reader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte,
// Note, in verkle tree, the hash checking can be ignored/skipped
// if slim node format is used. TODO(rjl493456442) remove it for
// verkle branch.
if r.verkle {
return blob, nil
}
h := newHasher()
defer h.release()

Expand All @@ -212,7 +230,7 @@ func (db *Database) Reader(root common.Hash) (*reader, error) {
if l == nil {
return nil, fmt.Errorf("state %#x is not available", root)
}
return &reader{l: l}, nil
return &reader{l: l, verkle: db.verkle}, nil
}

// Update adds a new layer into the tree, if that can be linked to an existing
Expand Down
6 changes: 3 additions & 3 deletions trie/triedb/pathdb/database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ type tester struct {
func newTester(t *testing.T) *tester {
var (
disk, _ = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
db = New(disk, &Config{CleanCacheSize: 256 * 1024, DirtyCacheSize: 256 * 1024})
db = New(disk, false, &Config{CleanCacheSize: 256 * 1024, DirtyCacheSize: 256 * 1024})
obj = &tester{
db: db,
preimages: make(map[common.Hash]common.Address),
Expand Down Expand Up @@ -506,7 +506,7 @@ func TestJournal(t *testing.T) {
t.Errorf("Failed to journal, err: %v", err)
}
tester.db.Close()
tester.db = New(tester.db.diskdb, nil)
tester.db = New(tester.db.diskdb, false, nil)

// Verify states including disk layer and all diff on top.
for i := 0; i < len(tester.roots); i++ {
Expand Down Expand Up @@ -540,7 +540,7 @@ func TestCorruptedJournal(t *testing.T) {
rawdb.WriteTrieJournal(tester.db.diskdb, blob)

// Verify states, all not-yet-written states should be discarded
tester.db = New(tester.db.diskdb, nil)
tester.db = New(tester.db.diskdb, false, nil)
for i := 0; i < len(tester.roots); i++ {
if tester.roots[i] == root {
if err := tester.verifyState(root); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion trie/triedb/pathdb/difflayer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (

func emptyLayer() *diskLayer {
return &diskLayer{
db: New(rawdb.NewMemoryDatabase(), nil),
db: New(rawdb.NewMemoryDatabase(), false, nil),
buffer: newNodeBuffer(DefaultBufferSize, nil, 0),
}
}
Expand Down
14 changes: 7 additions & 7 deletions trie/triedb/pathdb/disklayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,17 +126,17 @@ func (dl *diskLayer) Node(owner common.Hash, path []byte) ([]byte, error) {
cleanMissMeter.Mark(1)
}
// Try to retrieve the trie node from the disk.
var nBlob []byte
var blob []byte
if owner == (common.Hash{}) {
nBlob = rawdb.ReadAccountTrieNode(dl.db.diskdb, path)
blob = rawdb.ReadAccountTrieNode(dl.db.diskdb, path)
} else {
nBlob = rawdb.ReadStorageTrieNode(dl.db.diskdb, owner, path)
blob = rawdb.ReadStorageTrieNode(dl.db.diskdb, owner, path)
}
if dl.cleans != nil && len(nBlob) > 0 {
dl.cleans.Set(key, nBlob)
cleanWriteMeter.Mark(int64(len(nBlob)))
if dl.cleans != nil && len(blob) > 0 {
dl.cleans.Set(key, blob)
cleanWriteMeter.Mark(int64(len(blob)))
}
return nBlob, nil
return blob, nil
}

// update implements the layer interface, returning a new diff layer on top
Expand Down
2 changes: 1 addition & 1 deletion trie/triedb/pathdb/history_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ func TestTruncateTailHistories(t *testing.T) {

// openFreezer initializes the freezer instance for storing state histories.
func openFreezer(datadir string, readOnly bool) (*rawdb.ResettableFreezer, error) {
return rawdb.NewStateFreezer(datadir, readOnly)
return rawdb.NewStateFreezer(datadir, false, readOnly)
}

func compareSet[k comparable](a, b map[k][]byte) bool {
Expand Down

0 comments on commit df64a21

Please sign in to comment.