diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index cbf0dac55f..9625bf6203 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -390,7 +390,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, isBintrie bool) *state.StateDB { - tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true, IsVerkle: isBintrie}) + tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true, IsUBT: isBintrie}) sdb := state.NewDatabase(tdb, nil) root := types.EmptyRootHash diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 5f0903b4f8..331dc5ff9f 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -473,7 +473,7 @@ func BinKeys(ctx *cli.Context) error { return err } } - db := triedb.NewDatabase(rawdb.NewMemoryDatabase(), triedb.VerkleDefaults) + db := triedb.NewDatabase(rawdb.NewMemoryDatabase(), triedb.UBTDefaults) defer db.Close() bt, err := genBinTrieFromAlloc(alloc, db) @@ -517,7 +517,7 @@ func BinTrieRoot(ctx *cli.Context) error { return err } } - db := triedb.NewDatabase(rawdb.NewMemoryDatabase(), triedb.VerkleDefaults) + db := triedb.NewDatabase(rawdb.NewMemoryDatabase(), triedb.UBTDefaults) defer db.Close() bt, err := genBinTrieFromAlloc(alloc, db) diff --git a/cmd/geth/bintrie_convert.go b/cmd/geth/bintrie_convert.go index b87ecea129..c1917ecad6 100644 --- a/cmd/geth/bintrie_convert.go +++ b/cmd/geth/bintrie_convert.go @@ -144,7 +144,7 @@ func convertToBinaryTrie(ctx *cli.Context) error { defer srcTriedb.Close() destTriedb := triedb.NewDatabase(chaindb, &triedb.Config{ - IsVerkle: true, + IsUBT: true, PathDB: &pathdb.Config{ JournalDirectory: stack.ResolvePath("triedb-bintrie"), }, diff --git a/cmd/geth/bintrie_convert_test.go b/cmd/geth/bintrie_convert_test.go index 9b95f6a70f..50ae752358 100644 --- a/cmd/geth/bintrie_convert_test.go +++ b/cmd/geth/bintrie_convert_test.go @@ -82,8 +82,8 @@ func TestBintrieConvert(t *testing.T) { defer srcTriedb2.Close() destTriedb := triedb.NewDatabase(chaindb, &triedb.Config{ - IsVerkle: true, - PathDB: pathdb.Defaults, + IsUBT: true, + PathDB: pathdb.Defaults, }) defer destTriedb.Close() @@ -190,8 +190,8 @@ func TestBintrieConvertDeleteSource(t *testing.T) { }) destTriedb := triedb.NewDatabase(chaindb, &triedb.Config{ - IsVerkle: true, - PathDB: pathdb.Defaults, + IsUBT: true, + PathDB: pathdb.Defaults, }) bt, err := bintrie.NewBinaryTrie(types.EmptyBinaryHash, destTriedb) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 08a187d812..78a5e71319 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -298,7 +298,7 @@ func initGenesis(ctx *cli.Context) error { chaindb := utils.MakeChainDatabase(ctx, stack, false, false) defer chaindb.Close() - triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle()) + triedb := utils.MakeTrieDatabase(ctx, stack, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsUBT()) defer triedb.Close() _, hash, compatErr, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 4cf7034c1f..f374e695e1 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2604,10 +2604,10 @@ func MakeConsolePreloads(ctx *cli.Context) []string { } // MakeTrieDatabase constructs a trie database based on the configured scheme. -func MakeTrieDatabase(ctx *cli.Context, stack *node.Node, disk ethdb.Database, preimage bool, readOnly bool, isVerkle bool) *triedb.Database { +func MakeTrieDatabase(ctx *cli.Context, stack *node.Node, disk ethdb.Database, preimage bool, readOnly bool, isUBT bool) *triedb.Database { config := &triedb.Config{ Preimages: preimage, - IsVerkle: isVerkle, + IsUBT: isUBT, } scheme, err := rawdb.ParseStateScheme(ctx.String(StateSchemeFlag.Name), disk) if err != nil { diff --git a/core/blockchain.go b/core/blockchain.go index e7da9d4e74..2983b1fcd2 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -318,10 +318,10 @@ func (cfg BlockChainConfig) GetTriesInMemory() uint64 { } // triedbConfig derives the configures for trie database. -func (cfg *BlockChainConfig) triedbConfig(isVerkle bool) *triedb.Config { +func (cfg *BlockChainConfig) triedbConfig(isUBT bool) *triedb.Config { config := &triedb.Config{ Preimages: cfg.Preimages, - IsVerkle: isVerkle, + IsUBT: isUBT, } if cfg.StateScheme == rawdb.HashScheme { config.HashDB = &hashdb.Config{ @@ -383,7 +383,7 @@ type BlockChain struct { lastWrite uint64 // Last block when the state was flushed flushInterval atomic.Int64 // Time interval (processing time) after which to flush a state triedb *triedb.Database // The database handler for maintaining trie nodes. - statedb *state.CachingDB // State database to reuse between imports (contains state cache) + statedb *state.MPTDatabase // State database to reuse between imports (contains state cache) txIndexer *txIndexer // Transaction indexer, might be nil if not enabled hc *HeaderChain @@ -454,7 +454,7 @@ func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine, } // Open trie database with provided config - enableVerkle, err := EnableVerkleAtGenesis(db, genesis) + enableVerkle, err := EnableUBTAtGenesis(db, genesis) if err != nil { return nil, err } @@ -508,7 +508,7 @@ func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine, bc.flushInterval.Store(int64(cfg.TrieTimeLimit)) bc.forker = NewForkChoice(bc, cfg.ShouldPreserve, cfg.Checker) - bc.statedb = state.NewDatabase(bc.triedb, nil) + bc.statedb = state.NewMPTDatabase(bc.triedb, nil) bc.validator = NewBlockValidator(chainConfig, bc) bc.prefetcher = NewStatePrefetcher(chainConfig, bc.hc) bc.processor = NewStateProcessor(bc.hc) @@ -1032,7 +1032,7 @@ func (bc *BlockChain) setupSnapshot() { bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root) // Re-initialize the state database with snapshot - bc.statedb = state.NewDatabase(bc.triedb, bc.snaps) + bc.statedb = state.NewMPTDatabase(bc.triedb, bc.snaps) } } diff --git a/core/blockchain_sethead_test.go b/core/blockchain_sethead_test.go index d04d4f353d..0ee8ed8f00 100644 --- a/core/blockchain_sethead_test.go +++ b/core/blockchain_sethead_test.go @@ -2041,7 +2041,7 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme dbconfig.HashDB = hashdb.Defaults } chain.triedb = triedb.NewDatabase(chain.db, dbconfig) - chain.statedb = state.NewDatabase(chain.triedb, chain.snaps) + chain.statedb = state.NewMPTDatabase(chain.triedb, chain.snaps) // Force run a freeze cycle type freezer interface { diff --git a/core/chain_makers.go b/core/chain_makers.go index 51eac3c144..16f6e33ecd 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -128,7 +128,7 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti // Merge the tx-local access event into the "block-local" one, in order to collect // all values, so that the witness can be built. - if b.statedb.Database().TrieDB().IsVerkle() { + if b.statedb.Database().Type().Is(state.TypeUBT) { b.statedb.AccessEvents().Merge(evm.AccessEvents) } b.txs = append(b.txs, tx) @@ -445,7 +445,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse // Forcibly use hash-based state scheme for retaining all nodes in disk. var triedbConfig *triedb.Config = triedb.HashDefaults if config.IsVerkle(config.ChainID) { - triedbConfig = triedb.VerkleDefaults + triedbConfig = triedb.UBTDefaults } triedb := triedb.NewDatabase(db, triedbConfig) defer triedb.Close() @@ -494,7 +494,7 @@ func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, db := rawdb.NewMemoryDatabase() var triedbConfig *triedb.Config = triedb.HashDefaults if genesis.Config != nil && genesis.Config.IsVerkle(genesis.Config.ChainID) { - triedbConfig = triedb.VerkleDefaults + triedbConfig = triedb.UBTDefaults } genesisTriedb := triedb.NewDatabase(db, triedbConfig) block, err := genesis.Commit(db, genesisTriedb) diff --git a/core/genesis.go b/core/genesis.go index a2dd89ef07..263772e5e1 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -144,22 +144,22 @@ func ReadGenesis(db ethdb.Database) (*Genesis, error) { } // hashAlloc computes the state root according to the genesis specification. -func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { +func hashAlloc(ga *types.GenesisAlloc, isUBT bool) (common.Hash, error) { // If a genesis-time verkle trie is requested, create a trie config // with the verkle trie enabled so that the tree can be initialized // as such. var config *triedb.Config - if isVerkle { + if isUBT { config = &triedb.Config{ - PathDB: pathdb.Defaults, - IsVerkle: true, + PathDB: pathdb.Defaults, + IsUBT: true, } } // Create an ephemeral in-memory database for computing hash, // all the derived states will be discarded to not pollute disk. emptyRoot := types.EmptyRootHash - if isVerkle { - emptyRoot = types.EmptyVerkleHash + if isUBT { + emptyRoot = types.EmptyBinaryHash } db := rawdb.NewMemoryDatabase() statedb, err := state.New(emptyRoot, state.NewDatabase(triedb.NewDatabase(db, config), nil)) @@ -184,8 +184,8 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { // generated states will be persisted into the given database. func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database) (common.Hash, error) { emptyRoot := types.EmptyRootHash - if triedb.IsVerkle() { - emptyRoot = types.EmptyVerkleHash + if triedb.IsUBT() { + emptyRoot = types.EmptyBinaryHash } statedb, err := state.New(emptyRoot, state.NewDatabase(triedb, nil)) if err != nil { @@ -474,15 +474,15 @@ func (g *Genesis) chainConfigOrDefault(ghash common.Hash, stored *params.ChainCo } } -// IsVerkle indicates whether the state is already stored in a verkle +// IsUBT indicates whether the state is already stored in a unified binary // tree at genesis time. -func (g *Genesis) IsVerkle() bool { +func (g *Genesis) IsUBT() bool { return false } // ToBlock returns the genesis block according to genesis specification. func (g *Genesis) ToBlock() *types.Block { - root, err := hashAlloc(&g.Alloc, g.IsVerkle()) + root, err := hashAlloc(&g.Alloc, g.IsUBT()) if err != nil { panic(err) } @@ -631,14 +631,14 @@ func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big return g.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults)) } -// EnableVerkleAtGenesis indicates whether the verkle fork should be activated +// EnableUBTAtGenesis indicates whether the verkle fork should be activated // at genesis. This is a temporary solution only for verkle devnet testing, where // verkle fork is activated at genesis, and the configured activation date has // already passed. // // In production networks (mainnet and public testnets), verkle activation always // occurs after the genesis block, making this function irrelevant in those cases. -func EnableVerkleAtGenesis(db ethdb.Database, genesis *Genesis) (bool, error) { +func EnableUBTAtGenesis(db ethdb.Database, genesis *Genesis) (bool, error) { if genesis != nil { if genesis.Config == nil { return false, errGenesisNoConfig diff --git a/core/genesis_test.go b/core/genesis_test.go index 0754fa8a16..aa45cffa04 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -343,8 +343,8 @@ func TestVerkleGenesisCommit(t *testing.T) { config.NoAsyncFlush = true triedb := triedb.NewDatabase(db, &triedb.Config{ - IsVerkle: true, - PathDB: &config, + IsUBT: true, + PathDB: &config, }) block := genesis.MustCommit(db, triedb) if !bytes.Equal(block.Root().Bytes(), expected) { @@ -352,7 +352,7 @@ func TestVerkleGenesisCommit(t *testing.T) { } // Test that the trie is verkle - if !triedb.IsVerkle() { + if !triedb.IsUBT() { t.Fatalf("expected trie to be verkle") } vdb := rawdb.NewTable(db, string(rawdb.VerklePrefix)) diff --git a/core/state/database.go b/core/state/database.go index b120b6b187..3777ee291b 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -18,15 +18,11 @@ package state import ( "fmt" - "sync" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/lru" - "github.com/ethereum/go-ethereum/core/overlay" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/bintrie" @@ -43,8 +39,27 @@ const ( codeCacheSize = 256 * 1024 * 1024 ) +// DatabaseType represents the type of trie backing the state database. +type DatabaseType int + +const ( + // TypeMPT indicates a Merkle Patricia Trie (MPT) backed database. + TypeMPT DatabaseType = iota + + // TypeUBT indicates a Unified Binary Trie (UBT) backed database. + TypeUBT +) + +// Is returns the flag indicating the database type equals to the given one. +func (typ DatabaseType) Is(t DatabaseType) bool { + return typ == t +} + // Database wraps access to tries and contract code. type Database interface { + // Type returns the trie type backing this database (MPT or UBT). + Type() DatabaseType + // Reader returns a state reader associated with the specified state root. Reader(root common.Hash) (Reader, error) @@ -146,204 +161,26 @@ type Trie interface { // with the node that proves the absence of the key. Prove(key []byte, proofDb ethdb.KeyValueWriter) error - // IsVerkle returns true if the trie is verkle-tree based - IsVerkle() bool -} - -// CachingDB is an implementation of Database interface. It leverages both trie and -// state snapshot to provide functionalities for state access. It's meant to be a -// long-live object and has a few caches inside for sharing between blocks. -type CachingDB struct { - disk ethdb.KeyValueStore - triedb *triedb.Database - snap *snapshot.Tree - codeCache *lru.SizeConstrainedCache[common.Hash, []byte] - codeSizeCache *lru.Cache[common.Hash, int] - snapMu sync.RWMutex // Protects useSnapInReader - useSnapInReader bool - - // Transition-specific fields - TransitionStatePerRoot *lru.Cache[common.Hash, *overlay.TransitionState] + // IsUBT returns true if the trie is unified binary trie based. + IsUBT() bool } -// NewDatabase creates a state database with the provided data sources. -func NewDatabase(triedb *triedb.Database, snap *snapshot.Tree) *CachingDB { - return &CachingDB{ - disk: triedb.Disk(), - triedb: triedb, - snap: snap, - codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), - codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), - TransitionStatePerRoot: lru.NewCache[common.Hash, *overlay.TransitionState](1000), - useSnapInReader: true, +// NewDatabase creates a state database with the provided data sources. The +// snapshot is only consulted by the merkle database; unified binary tries +// have no snapshot layer. +// +// Deprecated, please use NewMPTDatabase or NewUBTDatabase directly. +func NewDatabase(tdb *triedb.Database, snap *snapshot.Tree) Database { + if tdb.IsUBT() { + return NewUBTDatabase(tdb) } -} - -func (db *CachingDB) DisableSnapInReader() { - db.snapMu.Lock() - db.useSnapInReader = false - db.snapMu.Unlock() -} - -func (db *CachingDB) EnableSnapInReader() { - db.snapMu.Lock() - db.useSnapInReader = true - db.snapMu.Unlock() + return NewMPTDatabase(tdb, snap) } // NewDatabaseForTesting is similar to NewDatabase, but it initializes the caching // db by using an ephemeral memory db with default config for testing. -func NewDatabaseForTesting() *CachingDB { - return NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil) -} - -// Reader returns a state reader associated with the specified state root. -func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) { - var readers []StateReader - - // Configure the state reader using the standalone snapshot in hash mode. - // This reader offers improved performance but is optional and only - // partially useful if the snapshot is not fully generated. - db.snapMu.RLock() - useSnap := db.useSnapInReader - db.snapMu.RUnlock() - if db.TrieDB().Scheme() == rawdb.HashScheme && db.snap != nil && useSnap { - snap := db.snap.Snapshot(stateRoot) - if snap != nil { - readers = append(readers, newFlatReader(snap)) - } - } - // Configure the state reader using the path database in path mode. - // This reader offers improved performance but is optional and only - // partially useful if the snapshot data in path database is not - // fully generated. - if db.TrieDB().Scheme() == rawdb.PathScheme && useSnap { - reader, err := db.triedb.StateReader(stateRoot) - if err == nil { - readers = append(readers, newFlatReader(reader)) - } - } - // Configure the trie reader, which is expected to be available as the - // gatekeeper unless the state is corrupted. - tr, err := newTrieReader(stateRoot, db.triedb) - if err != nil { - return nil, err - } - readers = append(readers, tr) - - combined, err := newMultiStateReader(readers...) - if err != nil { - return nil, err - } - return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil -} - -// ReaderTrieOnly creates a state reader that only uses the trie, skipping -// snapshot layers. Useful for V2 parallel execution where the snapshot reader -// may have thread-safety issues under concurrent access from multiple workers. -func (db *CachingDB) ReaderTrieOnly(stateRoot common.Hash) (Reader, error) { - tr, err := newTrieReader(stateRoot, db.triedb) - if err != nil { - return nil, err - } - combined, err := newMultiStateReader(tr) - if err != nil { - return nil, err - } - return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil -} - -// ReadersWithCacheStats creates a pair of state readers sharing the same internal cache and -// same backing Reader, but exposing separate statistics. -func (db *CachingDB) ReadersWithCacheStats(stateRoot common.Hash) (ReaderWithStats, ReaderWithStats, error) { - reader, err := db.Reader(stateRoot) - if err != nil { - return nil, nil, err - } - shared := newReaderWithCache(reader) - return newReaderWithCacheStats(shared, rolePrefetch), newReaderWithCacheStats(shared, roleProcess), nil -} - -// ReadersWithCacheStatsTriple creates three state readers sharing the same -// internal cache: prefetch, process (serial), and parallel (V2). -// The shared cache means prefetcher warms data that V2 reads for free. -func (db *CachingDB) ReadersWithCacheStatsTriple(stateRoot common.Hash) (ReaderWithStats, ReaderWithStats, ReaderWithStats, error) { - reader, err := db.Reader(stateRoot) - if err != nil { - return nil, nil, nil, err - } - shared := newReaderWithCache(reader) - return newReaderWithCacheStats(shared, rolePrefetch), - newReaderWithCacheStats(shared, roleProcess), - newReaderWithCacheStats(shared, roleProcess), // V2 shares same cache - nil -} - -// OpenTrie opens the main account trie at a specific root hash. -func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) { - if db.triedb.IsVerkle() { - ts := overlay.LoadTransitionState(db.TrieDB().Disk(), root, db.triedb.IsVerkle()) - if ts.InTransition() { - panic("state tree transition isn't supported yet") - } - if ts.Transitioned() { - // Use BinaryTrie instead of VerkleTrie when IsVerkle is set - // (IsVerkle actually means Binary Trie mode in this codebase) - return bintrie.NewBinaryTrie(root, db.triedb) - } - } - tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb) - if err != nil { - return nil, err - } - - return tr, nil -} - -// OpenStorageTrie opens the storage trie of an account. -func (db *CachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) { - if db.triedb.IsVerkle() { - return self, nil - } - tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, crypto.Keccak256Hash(address.Bytes()), root), db.triedb) - if err != nil { - return nil, err - } - - return tr, nil -} - -// ContractCodeWithPrefix retrieves a particular contract's code. If the -// code can't be found in the cache, then check the existence with **new** -// db scheme. -func (db *CachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) []byte { - code, _ := db.codeCache.Get(codeHash) - if len(code) > 0 { - return code - } - - code = rawdb.ReadCodeWithPrefix(db.disk, codeHash) - - if len(code) > 0 { - db.codeCache.Add(codeHash, code) - db.codeSizeCache.Add(codeHash, len(code)) - } - return code -} - -// TrieDB retrieves any intermediate trie-node caching layer. -func (db *CachingDB) TrieDB() *triedb.Database { - return db.triedb -} - -// Snapshot returns the underlying state snapshot. -func (db *CachingDB) Snapshot() *snapshot.Tree { - return db.snap -} - -// Iteratee returns a state iteratee associated with the specified state root. -func (db *CachingDB) Iteratee(root common.Hash) (Iteratee, error) { - return newStateIteratee(!db.triedb.IsVerkle(), root, db.triedb, db.snap) +func NewDatabaseForTesting() *MPTDatabase { + return NewMPTDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil) } // mustCopyTrie returns a deep-copied trie. diff --git a/core/state/database_history.go b/core/state/database_history.go index fed8b6530d..4e299f37fd 100644 --- a/core/state/database_history.go +++ b/core/state/database_history.go @@ -228,6 +228,12 @@ type HistoricDB struct { codeSizeCache *lru.Cache[common.Hash, int] } +// Type returns the trie type of the underlying database. +func (db *HistoricDB) Type() DatabaseType { + // TODO(rjl493456442) support UBT in the future + return TypeMPT +} + // NewHistoricDatabase creates a historic state database. func NewHistoricDatabase(disk ethdb.KeyValueStore, triedb *triedb.Database) *HistoricDB { return &HistoricDB{ diff --git a/core/state/database_mpt.go b/core/state/database_mpt.go new file mode 100644 index 0000000000..715a93d788 --- /dev/null +++ b/core/state/database_mpt.go @@ -0,0 +1,206 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package state + +import ( + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/triedb" +) + +// MPTDatabase is an implementation of Database interface for Merkle Patricia Tries. +// It leverages both trie and state snapshot to provide functionalities for state +// access. It's meant to be a long-live object and has a few caches inside for +// sharing between blocks. +type MPTDatabase struct { + disk ethdb.KeyValueStore + triedb *triedb.Database + snap *snapshot.Tree + codeCache *lru.SizeConstrainedCache[common.Hash, []byte] + codeSizeCache *lru.Cache[common.Hash, int] + snapMu sync.RWMutex // Protects useSnapInReader + useSnapInReader bool +} + +// Type returns TypeMPT, indicating this database is backed by a Merkle Patricia Trie. +func (db *MPTDatabase) Type() DatabaseType { return TypeMPT } + +// NewMPTDatabase creates a state database with the Merkle Patricia Trie manner. +func NewMPTDatabase(tdb *triedb.Database, snap *snapshot.Tree) *MPTDatabase { + return &MPTDatabase{ + disk: tdb.Disk(), + triedb: tdb, + snap: snap, + codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), + codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), + useSnapInReader: true, + } +} + +func (db *MPTDatabase) DisableSnapInReader() { + db.snapMu.Lock() + db.useSnapInReader = false + db.snapMu.Unlock() +} + +func (db *MPTDatabase) EnableSnapInReader() { + db.snapMu.Lock() + db.useSnapInReader = true + db.snapMu.Unlock() +} + +// Reader returns a state reader associated with the specified state root. +func (db *MPTDatabase) Reader(stateRoot common.Hash) (Reader, error) { + var readers []StateReader + + // Configure the state reader using the standalone snapshot in hash mode. + // This reader offers improved performance but is optional and only + // partially useful if the snapshot is not fully generated. + db.snapMu.RLock() + useSnap := db.useSnapInReader + db.snapMu.RUnlock() + if db.TrieDB().Scheme() == rawdb.HashScheme && db.snap != nil && useSnap { + snap := db.snap.Snapshot(stateRoot) + if snap != nil { + readers = append(readers, newFlatReader(snap)) + } + } + // Configure the state reader using the path database in path mode. + // This reader offers improved performance but is optional and only + // partially useful if the snapshot data in path database is not + // fully generated. + if db.TrieDB().Scheme() == rawdb.PathScheme && useSnap { + reader, err := db.triedb.StateReader(stateRoot) + if err == nil { + readers = append(readers, newFlatReader(reader)) + } + } + // Configure the trie reader, which is expected to be available as the + // gatekeeper unless the state is corrupted. + tr, err := newTrieReader(stateRoot, db.triedb) + if err != nil { + return nil, err + } + readers = append(readers, tr) + + combined, err := newMultiStateReader(readers...) + if err != nil { + return nil, err + } + return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil +} + +// ReaderTrieOnly creates a state reader that only uses the trie, skipping +// snapshot layers. Useful for V2 parallel execution where the snapshot reader +// may have thread-safety issues under concurrent access from multiple workers. +func (db *MPTDatabase) ReaderTrieOnly(stateRoot common.Hash) (Reader, error) { + tr, err := newTrieReader(stateRoot, db.triedb) + if err != nil { + return nil, err + } + combined, err := newMultiStateReader(tr) + if err != nil { + return nil, err + } + return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil +} + +// ReadersWithCacheStats creates a pair of state readers sharing the same internal cache and +// same backing Reader, but exposing separate statistics. +func (db *MPTDatabase) ReadersWithCacheStats(stateRoot common.Hash) (ReaderWithStats, ReaderWithStats, error) { + reader, err := db.Reader(stateRoot) + if err != nil { + return nil, nil, err + } + shared := newReaderWithCache(reader) + return newReaderWithCacheStats(shared, rolePrefetch), newReaderWithCacheStats(shared, roleProcess), nil +} + +// ReadersWithCacheStatsTriple creates three state readers sharing the same +// internal cache: prefetch, process (serial), and parallel (V2). +// The shared cache means prefetcher warms data that V2 reads for free. +func (db *MPTDatabase) ReadersWithCacheStatsTriple(stateRoot common.Hash) (ReaderWithStats, ReaderWithStats, ReaderWithStats, error) { + reader, err := db.Reader(stateRoot) + if err != nil { + return nil, nil, nil, err + } + shared := newReaderWithCache(reader) + return newReaderWithCacheStats(shared, rolePrefetch), + newReaderWithCacheStats(shared, roleProcess), + newReaderWithCacheStats(shared, roleProcess), // V2 shares same cache + nil +} + +// OpenTrie opens the main account trie at a specific root hash. +func (db *MPTDatabase) OpenTrie(root common.Hash) (Trie, error) { + tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb) + if err != nil { + return nil, err + } + + return tr, nil +} + +// OpenStorageTrie opens the storage trie of an account. +func (db *MPTDatabase) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) { + tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, crypto.Keccak256Hash(address.Bytes()), root), db.triedb) + if err != nil { + return nil, err + } + + return tr, nil +} + +// ContractCodeWithPrefix retrieves a particular contract's code. If the +// code can't be found in the cache, then check the existence with **new** +// db scheme. +func (db *MPTDatabase) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) []byte { + code, _ := db.codeCache.Get(codeHash) + if len(code) > 0 { + return code + } + + code = rawdb.ReadCodeWithPrefix(db.disk, codeHash) + + if len(code) > 0 { + db.codeCache.Add(codeHash, code) + db.codeSizeCache.Add(codeHash, len(code)) + } + return code +} + +// TrieDB retrieves any intermediate trie-node caching layer. +func (db *MPTDatabase) TrieDB() *triedb.Database { + return db.triedb +} + +// Snapshot returns the underlying state snapshot. +func (db *MPTDatabase) Snapshot() *snapshot.Tree { + return db.snap +} + +// Iteratee returns a state iteratee associated with the specified state root. +func (db *MPTDatabase) Iteratee(root common.Hash) (Iteratee, error) { + return newStateIteratee(true, root, db.triedb, db.snap) +} diff --git a/core/state/database_ubt.go b/core/state/database_ubt.go new file mode 100644 index 0000000000..5737c7350a --- /dev/null +++ b/core/state/database_ubt.go @@ -0,0 +1,110 @@ +// Copyright 2026 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package state + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/trie/bintrie" + "github.com/ethereum/go-ethereum/triedb" +) + +// UBTDatabase is an implementation of Database interface for Unified Binary Trie. +// It provides the same functionality as MPTDatabase but uses unified binary +// trie for state hashing instead of Merkle Patricia Tries. +// +// Bor never constructs this outside of tooling and tests: the Verkle/UBT fork is +// dormant on every preset, so NewDatabase only reaches it when a triedb is +// explicitly opened with triedb.UBTDefaults. +type UBTDatabase struct { + disk ethdb.KeyValueStore + triedb *triedb.Database + codeCache *lru.SizeConstrainedCache[common.Hash, []byte] + codeSizeCache *lru.Cache[common.Hash, int] +} + +// Type returns TypeUBT, indicating this database is backed by a Unified Binary Trie. +func (db *UBTDatabase) Type() DatabaseType { return TypeUBT } + +// NewUBTDatabase creates a state database with the Unified binary trie manner. +func NewUBTDatabase(tdb *triedb.Database) *UBTDatabase { + return &UBTDatabase{ + disk: tdb.Disk(), + triedb: tdb, + codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), + codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), + } +} + +// Reader returns a state reader associated with the specified state root. +func (db *UBTDatabase) Reader(stateRoot common.Hash) (Reader, error) { + var readers []StateReader + + // Configure the state reader using the path database in path mode. + // This reader offers improved performance but is optional and only + // partially useful if the snapshot data in path database is not + // fully generated. + if db.TrieDB().Scheme() == rawdb.PathScheme { + reader, err := db.triedb.StateReader(stateRoot) + if err == nil { + readers = append(readers, newFlatReader(reader)) + } + } + // Configure the trie reader, which is expected to be available as the + // gatekeeper unless the state is corrupted. + tr, err := newTrieReader(stateRoot, db.triedb) + if err != nil { + return nil, err + } + readers = append(readers, tr) + + combined, err := newMultiStateReader(readers...) + if err != nil { + return nil, err + } + return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil +} + +// OpenTrie opens the main account trie at a specific root hash. +func (db *UBTDatabase) OpenTrie(root common.Hash) (Trie, error) { + return bintrie.NewBinaryTrie(root, db.triedb) +} + +// OpenStorageTrie opens the storage trie of an account. In binary trie mode, +// all state objects share one unified trie, so the main trie is returned. +func (db *UBTDatabase) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) { + return self, nil +} + +// TrieDB retrieves any intermediate trie-node caching layer. +func (db *UBTDatabase) TrieDB() *triedb.Database { + return db.triedb +} + +// Snapshot implements Database. A unified binary trie has no snapshot layer. +func (db *UBTDatabase) Snapshot() *snapshot.Tree { + return nil +} + +// Iteratee returns a state iteratee associated with the specified state root, +// through which the account iterator and storage iterator can be created. +func (db *UBTDatabase) Iteratee(root common.Hash) (Iteratee, error) { + return newStateIteratee(false, root, db.triedb, nil) +} diff --git a/core/state/reader.go b/core/state/reader.go index 987641d23b..699ef4bd1c 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -270,10 +270,10 @@ func newTrieReader(root common.Hash, db *triedb.Database) (*trieReader, error) { tr Trie err error ) - if !db.IsVerkle() { + if !db.IsUBT() { tr, err = trie.NewStateTrie(trie.StateTrieID(root), db) } else { - // When IsVerkle() is true, create a BinaryTrie wrapped in TransitionTrie + // When IsUBT() is true, create a BinaryTrie wrapped in TransitionTrie binTrie, binErr := bintrie.NewBinaryTrie(root, db) if binErr != nil { return nil, binErr @@ -459,7 +459,7 @@ func (r *trieReader) subTrieConcurrent(addr common.Address) (Trie, error) { // subTrieLocked is the legacy mutex-protected path. Verkle uses the // merged main trie; MPT uses per-address sub tries cached in subTries. func (r *trieReader) subTrieLocked(addr common.Address) (Trie, error) { - if r.db.IsVerkle() { + if r.db.IsUBT() { return r.mainTrie, nil } if v, ok := r.subTries.Load(addr); ok { diff --git a/core/state/reader_test.go b/core/state/reader_test.go index d8163d1b59..f6339ed1c2 100644 --- a/core/state/reader_test.go +++ b/core/state/reader_test.go @@ -35,7 +35,7 @@ func TestCacheAttribution_PrefetchToProcess(t *testing.T) { // Setup: Create a state database with some accounts db := rawdb.NewMemoryDatabase() triedb := triedb.NewDatabase(db, nil) - statedb := NewDatabase(triedb, nil) + statedb := NewMPTDatabase(triedb, nil) // Create initial state with some accounts state, err := New(types.EmptyRootHash, statedb) @@ -180,7 +180,7 @@ func TestCacheAttribution_UniqueUsageTracking(t *testing.T) { // Setup: Create a state database with an account db := rawdb.NewMemoryDatabase() triedb := triedb.NewDatabase(db, nil) - statedb := NewDatabase(triedb, nil) + statedb := NewMPTDatabase(triedb, nil) // Create initial state state, err := New(types.EmptyRootHash, statedb) @@ -285,7 +285,7 @@ func TestReaderWithCache_ConcurrentAccess(t *testing.T) { // Setup: Create a state database with many accounts db := rawdb.NewMemoryDatabase() triedb := triedb.NewDatabase(db, nil) - statedb := NewDatabase(triedb, nil) + statedb := NewMPTDatabase(triedb, nil) // Create initial state with 100 accounts state, err := New(types.EmptyRootHash, statedb) diff --git a/core/state/state_object.go b/core/state/state_object.go index d3a86e69c8..6933322d38 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -159,7 +159,7 @@ func (s *stateObject) getTrie() (Trie, error) { func (s *stateObject) getPrefetchedTrie() Trie { // If there's nothing to meaningfully return, let the user figure it out by // pulling the trie from disk. - if (s.data.Root == types.EmptyRootHash && !s.db.db.TrieDB().IsVerkle()) || s.db.prefetcher == nil { + if (s.data.Root == types.EmptyRootHash && s.db.db.Type().Is(TypeMPT)) || s.db.prefetcher == nil { return nil } // Attempt to retrieve the trie from the prefetcher @@ -483,7 +483,7 @@ func (s *stateObject) commit() (*accountUpdate, *trienode.NodeSet, error) { // The main account trie commit in stateDB.commit() already calls // CollectNodes on this trie, so calling Commit here again would // redundantly traverse and serialize the entire tree per dirty account. - if s.db.GetTrie().IsVerkle() { + if s.db.GetTrie().IsUBT() { s.origin = s.data.Copy() return op, nil, nil } diff --git a/core/state/statedb.go b/core/state/statedb.go index fe4b1f50cb..87001d2cda 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -210,7 +210,7 @@ func NewWithReader(root common.Hash, db Database, reader Reader) (*StateDB, erro accessList: newAccessList(), transientStorage: newTransientStorage(), } - if db.TrieDB().IsVerkle() { + if db.Type().Is(TypeUBT) { sdb.accessEvents = NewAccessEvents() } @@ -1601,7 +1601,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { if !s.skipTimers { start = time.Now() } - if s.db.TrieDB().IsVerkle() { + if s.db.Type().Is(TypeUBT) { // Bypass per-account updateTrie() for binary trie. In binary trie mode // there is only one unified trie (OpenStorageTrie returns self), so the // per-account trie setup in updateTrie() (getPrefetchedTrie, getTrie, @@ -1665,9 +1665,9 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { } } // If witness building is enabled, gather all the read-only accesses. - // Skip witness collection in Verkle mode, they will be gathered - // together at the end. - if s.witness != nil && !s.db.TrieDB().IsVerkle() { + // Skip witness collection in Unified-binary-trie mode, they will be + // gathered together at the end. + if s.witness != nil && s.db.Type().Is(TypeMPT) { witStart := time.Now() // Pull in anything that has been accessed before destruction for _, obj := range s.stateObjectsDestruct { @@ -1714,7 +1714,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { if !s.skipTimers { start = time.Now() } - if s.prefetcher != nil && !s.db.TrieDB().IsVerkle() { + if s.prefetcher != nil && s.db.Type().Is(TypeMPT) { if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil { log.Error("Failed to retrieve account pre-fetcher trie") } else { @@ -1874,7 +1874,7 @@ func (s *StateDB) handleDestruction(noStorageWiping bool) (map[common.Hash]*acco deletes[addrHash] = op // Short circuit if the origin storage was empty. - if prev.Root == types.EmptyRootHash || s.db.TrieDB().IsVerkle() { + if prev.Root == types.EmptyRootHash || s.db.Type().Is(TypeUBT) { continue } if noStorageWiping { diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index f13fd01ae8..dd29d0feb4 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -2387,12 +2387,10 @@ func BenchmarkMVReadOverhead(b *testing.B) { // type *bintrie.BinaryTrie", because the type switch only covered *trie.StateTrie // and *transitiontrie.TransitionTrie. // -// Upstream names this TestStateDBCopyUBT and reaches the binary tree via -// triedb.UBTDefaults; Bor kept the pre-rename triedb.VerkleDefaults, which sets -// IsVerkle and so yields the same binary trie now that go-verkle is gone. +// Upstream names this TestStateDBCopyUBT. func TestStateDBCopyBinaryTrie(t *testing.T) { disk := rawdb.NewMemoryDatabase() - tdb := triedb.NewDatabase(disk, triedb.VerkleDefaults) + tdb := triedb.NewDatabase(disk, triedb.UBTDefaults) sdb := NewDatabase(tdb, nil) orig, err := New(types.EmptyRootHash, sdb) diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 062b5c5196..4ffdaedf1b 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -41,7 +41,7 @@ var ( // // Note, the prefetcher's API is not thread safe. type triePrefetcher struct { - verkle bool // Flag whether the prefetcher is in verkle mode + isUBT bool // Flag whether the prefetcher is in UBT mode db Database // Database to fetch trie nodes through root common.Hash // Root hash of the account trie for metrics fetchers map[string]*subfetcher // Subfetchers for each trie @@ -74,7 +74,7 @@ type triePrefetcher struct { func newTriePrefetcher(db Database, root common.Hash, namespace string, noreads bool) *triePrefetcher { prefix := triePrefetchMetricsPrefix + namespace return &triePrefetcher{ - verkle: db.TrieDB().IsVerkle(), + isUBT: db.Type().Is(TypeUBT), db: db, root: root, fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map @@ -243,8 +243,8 @@ func (p *triePrefetcher) used(owner common.Hash, root common.Hash, usedAddr []co // trieID returns an unique trie identifier consists the trie owner and root hash. func (p *triePrefetcher) trieID(owner common.Hash, root common.Hash) string { - // The trie in verkle is only identified by state root - if p.verkle { + // The trie in ubt is only identified by state root + if p.isUBT { return p.root.Hex() } // The trie in merkle is either identified by state root (account trie), @@ -410,12 +410,12 @@ func (sf *subfetcher) terminate(async bool) { // openTrie resolves the target trie from database for prefetching. func (sf *subfetcher) openTrie() error { - // Open the verkle tree if the sub-fetcher is in verkle mode. Note, there is - // only a single fetcher for verkle. - if sf.db.TrieDB().IsVerkle() { + // Open the ubt tree if the sub-fetcher is in ubt mode. Note, there is + // only a single fetcher for ubt. + if sf.db.Type().Is(TypeUBT) { tr, err := sf.db.OpenTrie(sf.state) if err != nil { - log.Warn("Trie prefetcher failed opening verkle trie", "root", sf.root, "err", err) + log.Warn("Trie prefetcher failed opening UBT trie", "root", sf.root, "err", err) return err } sf.trie = tr diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index da4b898a90..012abd5f3b 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -73,7 +73,7 @@ func TestUseAfterTerminate(t *testing.T) { func TestVerklePrefetcher(t *testing.T) { disk := rawdb.NewMemoryDatabase() - db := triedb.NewDatabase(disk, triedb.VerkleDefaults) + db := triedb.NewDatabase(disk, triedb.UBTDefaults) sdb := NewDatabase(db, nil) state, err := New(types.EmptyRootHash, sdb) diff --git a/core/state_processor.go b/core/state_processor.go index 2b9699fb78..95d35238ef 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -286,7 +286,7 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, } // Merge the tx-local access event into the "block-local" one, in order to collect // all values, so that the witness can be built. - if statedb.Database().TrieDB().IsVerkle() { + if statedb.Database().Type().Is(state.TypeUBT) { statedb.AccessEvents().Merge(evm.AccessEvents) } return MakeReceipt(evm, result, statedb, blockNumber, blockHash, blockTime, tx, gp.CumulativeUsed(), root), nil diff --git a/core/types/hashes.go b/core/types/hashes.go index 22f1f946dc..db8912a66f 100644 --- a/core/types/hashes.go +++ b/core/types/hashes.go @@ -43,9 +43,6 @@ var ( // EmptyRequestsHash is the known hash of an empty request set, sha256(""). EmptyRequestsHash = common.HexToHash("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") - // EmptyVerkleHash is the known hash of an empty verkle trie. - EmptyVerkleHash = common.Hash{} - // EmptyBinaryHash is the known hash of an empty binary trie. EmptyBinaryHash = common.Hash{} ) diff --git a/core/v2_witness_regen_test.go b/core/v2_witness_regen_test.go index 9f1848b938..e6108bb5b5 100644 --- a/core/v2_witness_regen_test.go +++ b/core/v2_witness_regen_test.go @@ -36,7 +36,7 @@ func witnessRegenRoundTrip(pb *preparedBlock, diskdb ethdb.Database, config *par // prefetch-role read warms the author into the shared cache so fee // credits during settle are cache hits, mirroring mainnet where the flat // reader serves hot accounts without touching the trie. - db := state.NewDatabase(pb.tdb, nil) + db := state.NewMPTDatabase(pb.tdb, nil) prefetchReader, _, parallelReader, err := db.ReadersWithCacheStatsTriple(pb.witness.Root()) if err != nil { return fmt.Errorf("readers: %w", err) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 289b5f1007..c3e1a321d9 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -145,10 +145,10 @@ func (t *BlockTest) run(snapshotter bool, scheme string, witness bool, tracer *t db = rawdb.NewMemoryDatabase() tconf = &triedb.Config{ Preimages: true, - IsVerkle: gspec.Config.IsVerkleGenesis(), + IsUBT: gspec.Config.IsVerkleGenesis(), } ) - if scheme == rawdb.PathScheme || tconf.IsVerkle { + if scheme == rawdb.PathScheme || tconf.IsUBT { tconf.PathDB = pathdb.Defaults } else { tconf.HashDB = hashdb.Defaults diff --git a/trie/bintrie/trie.go b/trie/bintrie/trie.go index b1e3c991c0..23d014eb33 100644 --- a/trie/bintrie/trie.go +++ b/trie/bintrie/trie.go @@ -377,8 +377,8 @@ func (t *BinaryTrie) Copy() *BinaryTrie { } } -// IsVerkle returns true if the trie is a Verkle tree. -func (t *BinaryTrie) IsVerkle() bool { +// IsUBT returns true if the trie is a Verkle tree. +func (t *BinaryTrie) IsUBT() bool { // TODO @gballet This is technically NOT a verkle tree, but it has the same // behavior and basic structure, so for all intents and purposes, it can be // treated as such. Rename this when verkle gets removed. diff --git a/trie/secure_trie.go b/trie/secure_trie.go index ee010dd267..bf4fcd2afc 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -330,6 +330,6 @@ func (t *StateTrie) MustNodeIterator(start []byte) NodeIterator { return t.trie.MustNodeIterator(start) } -func (t *StateTrie) IsVerkle() bool { +func (t *StateTrie) IsUBT() bool { return false } diff --git a/trie/transitiontrie/transition.go b/trie/transitiontrie/transition.go index 4c73022082..3e5511be9e 100644 --- a/trie/transitiontrie/transition.go +++ b/trie/transitiontrie/transition.go @@ -202,8 +202,8 @@ func (t *TransitionTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error { panic("not implemented") // TODO: Implement } -// IsVerkle returns true if the trie is verkle-tree based -func (t *TransitionTrie) IsVerkle() bool { +// IsUBT returns true if the trie is verkle-tree based +func (t *TransitionTrie) IsUBT() bool { // For all intents and purposes, the calling code should treat this as a verkle trie return true } diff --git a/triedb/database.go b/triedb/database.go index 6531a6808f..315e37edca 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -33,7 +33,7 @@ import ( // Config defines all necessary options for database. type Config struct { Preimages bool // Flag whether the preimage of node key is recorded - IsVerkle bool // Flag whether the db is holding a verkle tree + IsUBT bool // Flag whether the db is holding a verkle tree HashDB *hashdb.Config // Configs for hash-based scheme PathDB *pathdb.Config // Configs for experimental path-based scheme } @@ -42,15 +42,15 @@ type Config struct { // default settings. var HashDefaults = &Config{ Preimages: false, - IsVerkle: false, + IsUBT: false, HashDB: hashdb.Defaults, } -// VerkleDefaults represents a config for holding verkle trie data +// UBTDefaults represents a config for holding verkle trie data // using path-based scheme with default settings. -var VerkleDefaults = &Config{ +var UBTDefaults = &Config{ Preimages: false, - IsVerkle: true, + IsUBT: true, PathDB: pathdb.Defaults, } @@ -111,7 +111,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, config.IsVerkle) + db.backend = pathdb.New(diskdb, config.PathDB, config.IsUBT) } else { db.backend = hashdb.New(diskdb, config.HashDB) } @@ -384,9 +384,9 @@ func (db *Database) IndexProgress() (uint64, uint64, error) { return pdb.IndexProgress() } -// IsVerkle returns the indicator if the database is holding a verkle tree. -func (db *Database) IsVerkle() bool { - return db.config.IsVerkle +// IsUBT returns the indicator if the database is holding a verkle tree. +func (db *Database) IsUBT() bool { + return db.config.IsUBT } // Disk returns the underlying disk database. diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index e9c763309d..22395ed13f 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -100,7 +100,7 @@ func merkleNodeHasher(blob []byte) (common.Hash, error) { // binaryNodeHasher computes the hash of the given verkle node. func binaryNodeHasher(blob []byte) (common.Hash, error) { if len(blob) == 0 { - return types.EmptyVerkleHash, nil + return types.EmptyBinaryHash, nil } n, err := bintrie.DeserializeNode(blob, 0) if err != nil { @@ -127,7 +127,7 @@ type Database struct { // the shutdown to reject all following unexpected mutations. readOnly bool // Flag if database is opened in read only mode waitSync bool // Flag if database is deactivated due to initial state sync - isVerkle bool // Flag if database is used for verkle tree + isUBT bool // Flag if database is used for verkle tree hasher nodeHasher // Trie node hasher config *Config // Configuration for database @@ -146,7 +146,7 @@ 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, isVerkle bool) *Database { +func New(diskdb ethdb.Database, config *Config, isUBT bool) *Database { if config == nil { config = Defaults } @@ -154,7 +154,7 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database { db := &Database{ readOnly: config.ReadOnly, - isVerkle: isVerkle, + isUBT: isUBT, config: config, diskdb: diskdb, hasher: merkleNodeHasher, @@ -164,7 +164,7 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database { // 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 isVerkle { + if isUBT { db.diskdb = rawdb.NewTable(diskdb, string(rawdb.VerklePrefix)) db.hasher = binaryNodeHasher } @@ -174,7 +174,7 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database { // Repair the history, which might not be aligned with the persistent // state in the key-value store due to an unclean shutdown. - states, trienodes, err := repairHistory(db.diskdb, isVerkle, db.config.ReadOnly, db.tree.bottom().stateID(), db.config.TrienodeHistory >= 0) + states, trienodes, err := repairHistory(db.diskdb, isUBT, db.config.ReadOnly, db.tree.bottom().stateID(), db.config.TrienodeHistory >= 0) if err != nil { log.Crit("Failed to repair history", "err", err) } @@ -196,7 +196,7 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database { db.setHistoryIndexer() fields := config.fields() - if db.isVerkle { + if db.isUBT { fields = append(fields, "verkle", true) } log.Info("Initialized path database", fields...) @@ -265,7 +265,7 @@ func (db *Database) setStateGenerator() error { // - the database is opened in read only mode // - the snapshot build is explicitly disabled // - the database is opened in verkle tree mode - noBuild := db.readOnly || db.config.SnapshotNoBuild || db.isVerkle + noBuild := db.readOnly || db.config.SnapshotNoBuild || db.isUBT // Construct the generator and link it to the disk layer, ensuring that the // generation progress is resolved to prevent accessing uncovered states @@ -412,7 +412,7 @@ func (db *Database) Enable(root common.Hash) error { // Re-construct a new disk layer backed by persistent state // and schedule the state snapshot generation if it's permitted. - db.tree.init(generateSnapshot(db, root, db.isVerkle || db.config.SnapshotNoBuild)) + db.tree.init(generateSnapshot(db, root, db.isUBT || db.config.SnapshotNoBuild)) // After snap sync, the state of the database may have changed completely. // To ensure the history indexer always matches the current state, we must: @@ -590,7 +590,7 @@ func (db *Database) journalPath() string { return "" } var fname string - if db.isVerkle { + if db.isUBT { fname = fmt.Sprintf("verkle.journal") } else { fname = fmt.Sprintf("merkle.journal") diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 2de5847124..5b20ea6c63 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -144,7 +144,7 @@ type testerConfig struct { layers int // Number of state transitions to generate for enableIndex bool // Enable state history indexing or not journalDir string // Directory path for persisting journal files - isVerkle bool // Enables Verkle trie mode if true + isUBT bool // Enables UBT mode if true writeBuffer *int // Optional, the size of memory allocated for write buffer trieCache *int // Optional, the size of memory allocated for trie cache @@ -184,7 +184,7 @@ func newTester(t *testing.T, config *testerConfig) *tester { NoAsyncFlush: true, JournalDirectory: config.journalDir, NoHistoryIndexDelay: true, - }, config.isVerkle) + }, config.isUBT) obj = &tester{ db: db, diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 0a9f7091fa..7f5b0e35ba 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -376,7 +376,7 @@ func syncHistory(stores ...ethdb.AncientWriter) error { // persistent state may appear if the trienode history was disabled during the // previous run. This process detects and resolves such gaps, preventing // unexpected panics. -func repairHistory(db ethdb.Database, isVerkle bool, readOnly bool, stateID uint64, enableTrienode bool) (ethdb.ResettableAncientStore, ethdb.ResettableAncientStore, error) { +func repairHistory(db ethdb.Database, isUBT bool, readOnly bool, stateID uint64, enableTrienode bool) (ethdb.ResettableAncientStore, ethdb.ResettableAncientStore, error) { ancient, err := db.AncientDatadir() if err != nil { // TODO error out if ancient store is disabled. A tons of unit tests @@ -386,7 +386,7 @@ func repairHistory(db ethdb.Database, isVerkle bool, readOnly bool, stateID uint } // State history is mandatory as it is the key component that ensures // resilience to deep reorgs. - states, err := rawdb.NewStateFreezer(ancient, isVerkle, readOnly) + states, err := rawdb.NewStateFreezer(ancient, isUBT, readOnly) if err != nil { log.Crit("Failed to open state history freezer", "err", err) } @@ -395,7 +395,7 @@ func repairHistory(db ethdb.Database, isVerkle bool, readOnly bool, stateID uint // node with state proofs. var trienodes ethdb.ResettableAncientStore if enableTrienode { - trienodes, err = rawdb.NewTrienodeFreezer(ancient, isVerkle, readOnly) + trienodes, err = rawdb.NewTrienodeFreezer(ancient, isUBT, readOnly) if err != nil { log.Crit("Failed to open trienode history freezer", "err", err) } diff --git a/triedb/pathdb/layertree_test.go b/triedb/pathdb/layertree_test.go index a85d6704dc..c75575e8c1 100644 --- a/triedb/pathdb/layertree_test.go +++ b/triedb/pathdb/layertree_test.go @@ -928,7 +928,7 @@ func TestStorageLookup(t *testing.T) { // keccak), so the disk layer's root was never the zero hash in // practice. The bug only surfaces once the disk layer root can // legitimately be zero (for example a fresh verkle/bintrie database -// where the empty binary trie hashes to EmptyVerkleHash == +// where the empty binary trie hashes to EmptyBinaryHash == // common.Hash{}). // // The test constructs a layer tree whose base layer's root IS the zero @@ -949,7 +949,7 @@ func TestStorageLookup(t *testing.T) { func TestLookupZeroBaseRootFallback(t *testing.T) { // Build a layer tree whose disk-layer root is common.Hash{} — // mirrors the bintrie/verkle configuration where the empty trie - // hashes to EmptyVerkleHash. newTestLayerTree can't be reused + // hashes to EmptyBinaryHash. newTestLayerTree can't be reused // because it hard-codes common.Hash{0x1}. db := New(rawdb.NewMemoryDatabase(), nil, false) base := newDiskLayer(common.Hash{}, 0, db, nil, nil, newBuffer(0, 0, nil, nil, 0), nil) diff --git a/triedb/pathdb/lookup.go b/triedb/pathdb/lookup.go index f774dd341f..bd83f58131 100644 --- a/triedb/pathdb/lookup.go +++ b/triedb/pathdb/lookup.go @@ -99,7 +99,7 @@ func newLookup(head layer, descendant func(state common.Hash, ancestor common.Ha // // Note the returned hash may itself be common.Hash{} when the disk layer's // root is zero — as is the case for a fresh verkle/bintrie database whose -// empty trie hashes to EmptyVerkleHash. Callers must therefore consult the +// empty trie hashes to EmptyBinaryHash. Callers must therefore consult the // boolean rather than comparing the returned hash against common.Hash{} // directly. func (l *lookup) accountTip(accountHash common.Hash, stateID common.Hash, base common.Hash) (common.Hash, bool) { diff --git a/triedb/pathdb/reader.go b/triedb/pathdb/reader.go index 0fd7a96d57..fe9c10ebf0 100644 --- a/triedb/pathdb/reader.go +++ b/triedb/pathdb/reader.go @@ -208,7 +208,7 @@ func (db *Database) NodeReader(root common.Hash) (database.NodeReader, error) { return &reader{ db: db, state: root, - noHashCheck: db.isVerkle, + noHashCheck: db.isUBT, layer: layer, }, nil }