Skip to content

Commit f59d013

Browse files
authored
core/rawdb, triedb, cmd: create an isolated disk namespace for verkle (#30105)
* core, triedb/pathdb, cmd: define verkle state ancient store * core/rawdb, triedb: add verkle namespace in pathdb
1 parent c54294b commit f59d013

File tree

10 files changed

+84
-20
lines changed

10 files changed

+84
-20
lines changed

cmd/geth/dbcmd.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,8 @@ func removeDB(ctx *cli.Context) error {
248248
// Delete state data
249249
statePaths := []string{
250250
rootDir,
251-
filepath.Join(ancientDir, rawdb.StateFreezerName),
251+
filepath.Join(ancientDir, rawdb.MerkleStateFreezerName),
252+
filepath.Join(ancientDir, rawdb.VerkleStateFreezerName),
252253
}
253254
confirmAndRemoveDB(statePaths, "state data", ctx, removeStateDataFlag.Name)
254255

core/genesis_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
311311
}
312312

313313
db := rawdb.NewMemoryDatabase()
314-
triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, PathDB: pathdb.Defaults})
314+
triedb := triedb.NewDatabase(db, triedb.VerkleDefaults)
315315
block := genesis.MustCommit(db, triedb)
316316
if !bytes.Equal(block.Root().Bytes(), expected) {
317317
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, block.Root())
@@ -321,8 +321,8 @@ func TestVerkleGenesisCommit(t *testing.T) {
321321
if !triedb.IsVerkle() {
322322
t.Fatalf("expected trie to be verkle")
323323
}
324-
325-
if !rawdb.HasAccountTrieNode(db, nil) {
324+
vdb := rawdb.NewTable(db, string(rawdb.VerklePrefix))
325+
if !rawdb.HasAccountTrieNode(vdb, nil) {
326326
t.Fatal("could not find node")
327327
}
328328
}

core/rawdb/accessors_trie.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, has
245245

246246
// ReadStateScheme reads the state scheme of persistent state, or none
247247
// if the state is not present in database.
248-
func ReadStateScheme(db ethdb.Reader) string {
248+
func ReadStateScheme(db ethdb.Database) string {
249249
// Check if state in path-based scheme is present.
250250
if HasAccountTrieNode(db, nil) {
251251
return PathScheme
@@ -255,6 +255,16 @@ func ReadStateScheme(db ethdb.Reader) string {
255255
if id := ReadPersistentStateID(db); id != 0 {
256256
return PathScheme
257257
}
258+
// Check if verkle state in path-based scheme is present.
259+
vdb := NewTable(db, string(VerklePrefix))
260+
if HasAccountTrieNode(vdb, nil) {
261+
return PathScheme
262+
}
263+
// The root node of verkle might be deleted during the initial snap sync,
264+
// check the persistent state id then.
265+
if id := ReadPersistentStateID(vdb); id != 0 {
266+
return PathScheme
267+
}
258268
// In a hash-based scheme, the genesis state is consistently stored
259269
// on the disk. To assess the scheme of the persistent state, it
260270
// suffices to inspect the scheme of the genesis state.

core/rawdb/ancient_scheme.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,22 +72,29 @@ var stateFreezerNoSnappy = map[string]bool{
7272

7373
// The list of identifiers of ancient stores.
7474
var (
75-
ChainFreezerName = "chain" // the folder name of chain segment ancient store.
76-
StateFreezerName = "state" // the folder name of reverse diff ancient store.
75+
ChainFreezerName = "chain" // the folder name of chain segment ancient store.
76+
MerkleStateFreezerName = "state" // the folder name of state history ancient store.
77+
VerkleStateFreezerName = "state_verkle" // the folder name of state history ancient store.
7778
)
7879

7980
// freezers the collections of all builtin freezers.
80-
var freezers = []string{ChainFreezerName, StateFreezerName}
81+
var freezers = []string{ChainFreezerName, MerkleStateFreezerName, VerkleStateFreezerName}
8182

8283
// NewStateFreezer initializes the ancient store for state history.
8384
//
8485
// - if the empty directory is given, initializes the pure in-memory
8586
// state freezer (e.g. dev mode).
8687
// - if non-empty directory is given, initializes the regular file-based
8788
// state freezer.
88-
func NewStateFreezer(ancientDir string, readOnly bool) (ethdb.ResettableAncientStore, error) {
89+
func NewStateFreezer(ancientDir string, verkle bool, readOnly bool) (ethdb.ResettableAncientStore, error) {
8990
if ancientDir == "" {
9091
return NewMemoryFreezer(readOnly, stateFreezerNoSnappy), nil
9192
}
92-
return newResettableFreezer(filepath.Join(ancientDir, StateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
93+
var name string
94+
if verkle {
95+
name = filepath.Join(ancientDir, VerkleStateFreezerName)
96+
} else {
97+
name = filepath.Join(ancientDir, MerkleStateFreezerName)
98+
}
99+
return newResettableFreezer(name, "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
93100
}

core/rawdb/ancient_utils.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,12 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
8888
}
8989
infos = append(infos, info)
9090

91-
case StateFreezerName:
91+
case MerkleStateFreezerName, VerkleStateFreezerName:
9292
datadir, err := db.AncientDatadir()
9393
if err != nil {
9494
return nil, err
9595
}
96-
f, err := NewStateFreezer(datadir, true)
96+
f, err := NewStateFreezer(datadir, freezer == VerkleStateFreezerName, true)
9797
if err != nil {
9898
continue // might be possible the state freezer is not existent
9999
}
@@ -124,7 +124,7 @@ func InspectFreezerTable(ancient string, freezerName string, tableName string, s
124124
switch freezerName {
125125
case ChainFreezerName:
126126
path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy
127-
case StateFreezerName:
127+
case MerkleStateFreezerName, VerkleStateFreezerName:
128128
path, tables = filepath.Join(ancient, freezerName), stateFreezerNoSnappy
129129
default:
130130
return fmt.Errorf("unknown freezer, supported ones: %v", freezers)

core/rawdb/database.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,10 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
481481
beaconHeaders stat
482482
cliqueSnaps stat
483483

484+
// Verkle statistics
485+
verkleTries stat
486+
verkleStateLookups stat
487+
484488
// Les statistic
485489
chtTrieNodes stat
486490
bloomTrieNodes stat
@@ -550,6 +554,24 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
550554
bytes.HasPrefix(key, BloomTrieIndexPrefix) ||
551555
bytes.HasPrefix(key, BloomTriePrefix): // Bloomtrie sub
552556
bloomTrieNodes.Add(size)
557+
558+
// Verkle trie data is detected, determine the sub-category
559+
case bytes.HasPrefix(key, VerklePrefix):
560+
remain := key[len(VerklePrefix):]
561+
switch {
562+
case IsAccountTrieNode(remain):
563+
verkleTries.Add(size)
564+
case bytes.HasPrefix(remain, stateIDPrefix) && len(remain) == len(stateIDPrefix)+common.HashLength:
565+
verkleStateLookups.Add(size)
566+
case bytes.Equal(remain, persistentStateIDKey):
567+
metadata.Add(size)
568+
case bytes.Equal(remain, trieJournalKey):
569+
metadata.Add(size)
570+
case bytes.Equal(remain, snapSyncStatusFlagKey):
571+
metadata.Add(size)
572+
default:
573+
unaccounted.Add(size)
574+
}
553575
default:
554576
var accounted bool
555577
for _, meta := range [][]byte{
@@ -590,6 +612,8 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
590612
{"Key-Value store", "Path trie state lookups", stateLookups.Size(), stateLookups.Count()},
591613
{"Key-Value store", "Path trie account nodes", accountTries.Size(), accountTries.Count()},
592614
{"Key-Value store", "Path trie storage nodes", storageTries.Size(), storageTries.Count()},
615+
{"Key-Value store", "Verkle trie nodes", verkleTries.Size(), verkleTries.Count()},
616+
{"Key-Value store", "Verkle trie state lookups", verkleStateLookups.Size(), verkleStateLookups.Count()},
593617
{"Key-Value store", "Trie preimages", preimages.Size(), preimages.Count()},
594618
{"Key-Value store", "Account snapshot", accountSnaps.Size(), accountSnaps.Count()},
595619
{"Key-Value store", "Storage snapshot", storageSnaps.Size(), storageSnaps.Count()},

core/rawdb/schema.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ var (
117117
TrieNodeStoragePrefix = []byte("O") // TrieNodeStoragePrefix + accountHash + hexPath -> trie node
118118
stateIDPrefix = []byte("L") // stateIDPrefix + state root -> state id
119119

120+
// VerklePrefix is the database prefix for Verkle trie data, which includes:
121+
// (a) Trie nodes
122+
// (b) In-memory trie node journal
123+
// (c) Persistent state ID
124+
// (d) State ID lookups, etc.
125+
VerklePrefix = []byte("v")
126+
120127
PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage
121128
configPrefix = []byte("ethereum-config-") // config prefix for the db
122129
genesisPrefix = []byte("ethereum-genesis-") // genesis state prefix for the db

triedb/database.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,18 @@ type Config struct {
4242
// default settings.
4343
var HashDefaults = &Config{
4444
Preimages: false,
45+
IsVerkle: false,
4546
HashDB: hashdb.Defaults,
4647
}
4748

49+
// VerkleDefaults represents a config for holding verkle trie data
50+
// using path-based scheme with default settings.
51+
var VerkleDefaults = &Config{
52+
Preimages: false,
53+
IsVerkle: true,
54+
PathDB: pathdb.Defaults,
55+
}
56+
4857
// backend defines the methods needed to access/update trie nodes in different
4958
// state scheme.
5059
type backend interface {
@@ -84,7 +93,6 @@ type backend interface {
8493
// relevant with trie nodes and node preimages.
8594
type Database struct {
8695
config *Config // Configuration for trie database
87-
diskdb ethdb.Database // Persistent database to store the snapshot
8896
preimages *preimageStore // The store for caching preimages
8997
backend backend // The backend for managing trie nodes
9098
}
@@ -102,7 +110,6 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
102110
}
103111
db := &Database{
104112
config: config,
105-
diskdb: diskdb,
106113
preimages: preimages,
107114
}
108115
if config.HashDB != nil && config.PathDB != nil {

triedb/pathdb/database.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,14 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database {
152152
}
153153
config = config.sanitize()
154154

155+
// Establish a dedicated database namespace tailored for verkle-specific
156+
// data, ensuring the isolation of both verkle and merkle tree data. It's
157+
// important to note that the introduction of a prefix won't lead to
158+
// substantial storage overhead, as the underlying database will efficiently
159+
// compress the shared key prefix.
160+
if isVerkle {
161+
diskdb = rawdb.NewTable(diskdb, string(rawdb.VerklePrefix))
162+
}
155163
db := &Database{
156164
readOnly: config.ReadOnly,
157165
isVerkle: isVerkle,
@@ -190,7 +198,7 @@ func (db *Database) repairHistory() error {
190198
// all of them. Fix the tests first.
191199
return nil
192200
}
193-
freezer, err := rawdb.NewStateFreezer(ancient, db.readOnly)
201+
freezer, err := rawdb.NewStateFreezer(ancient, db.isVerkle, db.readOnly)
194202
if err != nil {
195203
log.Crit("Failed to open state history freezer", "err", err)
196204
}

triedb/pathdb/history_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func TestTruncateHeadHistory(t *testing.T) {
129129
roots []common.Hash
130130
hs = makeHistories(10)
131131
db = rawdb.NewMemoryDatabase()
132-
freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false)
132+
freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false)
133133
)
134134
defer freezer.Close()
135135

@@ -157,7 +157,7 @@ func TestTruncateTailHistory(t *testing.T) {
157157
roots []common.Hash
158158
hs = makeHistories(10)
159159
db = rawdb.NewMemoryDatabase()
160-
freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false)
160+
freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false)
161161
)
162162
defer freezer.Close()
163163

@@ -200,7 +200,7 @@ func TestTruncateTailHistories(t *testing.T) {
200200
roots []common.Hash
201201
hs = makeHistories(10)
202202
db = rawdb.NewMemoryDatabase()
203-
freezer, _ = rawdb.NewStateFreezer(t.TempDir()+fmt.Sprintf("%d", i), false)
203+
freezer, _ = rawdb.NewStateFreezer(t.TempDir()+fmt.Sprintf("%d", i), false, false)
204204
)
205205
defer freezer.Close()
206206

@@ -228,7 +228,7 @@ func TestTruncateOutOfRange(t *testing.T) {
228228
var (
229229
hs = makeHistories(10)
230230
db = rawdb.NewMemoryDatabase()
231-
freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false)
231+
freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false)
232232
)
233233
defer freezer.Close()
234234

0 commit comments

Comments
 (0)