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
}