Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions consensus/beacon/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,9 +354,9 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.

// FinalizeAndAssemble implements consensus.Engine, setting the final state and
// assembling the block.
func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, statedb *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
if !beacon.IsPoSHeader(header) {
return beacon.ethone.FinalizeAndAssemble(chain, header, state, body, receipts)
return beacon.ethone.FinalizeAndAssemble(chain, header, statedb, body, receipts)
}
shanghai := chain.Config().IsShanghai(header.Number, header.Time)
if shanghai {
Expand All @@ -370,30 +370,30 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
}
}
// Finalize and assemble the block.
beacon.Finalize(chain, header, state, body)
beacon.Finalize(chain, header, statedb, body)

// Assign the final state root to header.
header.Root = state.IntermediateRoot(true)
header.Root = statedb.IntermediateRoot(true)

// Assemble the final block.
block := types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))

// Create the block witness and attach to block.
// This step needs to happen as late as possible to catch all access events.
if chain.Config().IsVerkle(header.Number, header.Time) {
keys := state.AccessEvents().Keys()
keys := statedb.AccessEvents().Keys()

// Open the pre-tree to prove the pre-state against
parent := chain.GetHeaderByNumber(header.Number.Uint64() - 1)
if parent == nil {
return nil, fmt.Errorf("nil parent header for block %d", header.Number)
}
preTrie, err := state.Database().OpenTrie(parent.Root)
preTrie, err := statedb.Database().OpenTrie(parent.Root)
if err != nil {
return nil, fmt.Errorf("error opening pre-state tree root: %w", err)
}
vktPreTrie, okpre := preTrie.(*trie.VerkleTrie)
vktPostTrie, okpost := state.GetTrie().(*trie.VerkleTrie)
vktPostTrie, okpost := statedb.GetTrie().(*trie.VerkleTrie)

// The witness is only attached iff both parent and current block are
// using verkle tree.
Expand Down
7 changes: 1 addition & 6 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,12 +283,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
if cacheConfig == nil {
cacheConfig = defaultCacheConfig
}
// Open trie database with provided config
enableVerkle, err := EnableVerkleAtGenesis(db, genesis)
if err != nil {
return nil, err
}
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(enableVerkle))
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(genesis.IsVerkle()))

// Write the supplied genesis to the database if it has not been initialized
// yet. The corresponding chain config will be returned, either from the
Expand Down
4 changes: 3 additions & 1 deletion core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,8 +536,10 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
return block, b.receipts
}

sdb := state.NewDatabase(trdb, nil)

for i := 0; i < n; i++ {
statedb, err := state.New(parent.Root(), state.NewDatabase(trdb, nil))
statedb, err := state.New(parent.Root(), sdb)
if err != nil {
panic(err)
}
Expand Down
32 changes: 8 additions & 24 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/overlay"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing"
Expand Down Expand Up @@ -443,7 +444,7 @@ func (g *Genesis) chainConfigOrDefault(ghash common.Hash, stored *params.ChainCo
// IsVerkle indicates whether the state is already stored in a verkle
// tree at genesis time.
func (g *Genesis) IsVerkle() bool {
return g.Config.IsVerkleGenesis()
return g != nil && g.Config != nil && g.Config.VerkleTime != nil && *g.Config.VerkleTime == g.Timestamp
}

// ToBlock returns the genesis block according to genesis specification.
Expand Down Expand Up @@ -556,6 +557,12 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
rawdb.WriteHeadFastBlockHash(batch, block.Hash())
rawdb.WriteHeadHeaderHash(batch, block.Hash())
rawdb.WriteChainConfig(batch, block.Hash(), config)

// In case of verkle-at-genesis, we need to ensure that the conversion
// markers are indicating that the conversion has completed.
if g.IsVerkle() {
overlay.StoreTransitionState(batch, block.Root(), &overlay.TransitionState{Ended: true})
}
return block, batch.Write()
}

Expand All @@ -569,29 +576,6 @@ func (g *Genesis) MustCommit(db ethdb.Database, triedb *triedb.Database) *types.
return block
}

// EnableVerkleAtGenesis 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) {
if genesis != nil {
if genesis.Config == nil {
return false, errGenesisNoConfig
}
return genesis.Config.EnableVerkleAtGenesis, nil
}
if ghash := rawdb.ReadCanonicalHash(db, 0); ghash != (common.Hash{}) {
chainCfg := rawdb.ReadChainConfig(db, ghash)
if chainCfg != nil {
return chainCfg.EnableVerkleAtGenesis, nil
}
}
return false, nil
}

// DefaultGenesisBlock returns the Ethereum main net genesis block.
func DefaultGenesisBlock() *Genesis {
return &Genesis{
Expand Down
1 change: 0 additions & 1 deletion core/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,6 @@ func TestVerkleGenesisCommit(t *testing.T) {
OsakaTime: &verkleTime,
VerkleTime: &verkleTime,
TerminalTotalDifficulty: big.NewInt(0),
EnableVerkleAtGenesis: true,
Ethash: nil,
Clique: nil,
BlobScheduleConfig: &params.BlobScheduleConfig{
Expand Down
123 changes: 123 additions & 0 deletions core/overlay/state_transition.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright 2025 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 <http://www.gnu.org/licenses/>.

package overlay

import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
)

// TransitionState represents the progress of the Verkle transition process,
// tracking which parts of the legacy MPT-based state have already been
// migrated to the Verkle-based state.
type TransitionState struct {
// CurrentAccountHash is the hash of the next account to be migrated
// from the MPT state to the Verkle state.
CurrentAccountHash common.Hash

// CurrentSlotHash is the hash of the next storage slot (within the
// current account) to be migrated from the MPT state to the Verkle state.
// This field is irrelevant if StorageProcessed is true, indicating that
// all storage slots for the current account have already been migrated.
CurrentSlotHash common.Hash

// StorageProcessed indicates whether all storage slots for the current
// account have been fully migrated. This is useful in cases where the
// transition was interrupted before all state entries were processed
// (e.g., due to a configured migration step limit).
StorageProcessed bool

// CurrentPreimageOffset is the byte offset in the preimage file from
// which the migration should resume.
CurrentPreimageOffset uint64

// Started is true if the transition process has begun. Note that the
// transition is considered started only after the MPT state referenced
// by BaseRoot has been finalized.
Started bool

// Ended is true if the transition process has completed, meaning the entire
// MPT-based state has been fully migrated. When true, the complete Ethereum
// state is available in the Verkle state, and constructing a mixed state
// view is no longer necessary.
Ended bool

// BaseRoot is the MPT root hash of the read-only base state, the original
// state prior to Verkle activation.
BaseRoot common.Hash
}

// InTransition returns true if the translation process is in progress.
func (ts *TransitionState) InTransition() bool {
return ts != nil && ts.Started && !ts.Ended
}

// Transitioned returns true if the translation process has been completed.
func (ts *TransitionState) Transitioned() bool {
return ts != nil && ts.Ended
}

// LogAttrs returns a list of attributes for logging purpose.
func (ts *TransitionState) LogAttrs(root common.Hash) []any {
var attrs []any
if !ts.Started {
attrs = append(attrs, "started", false)
return attrs
}
if ts.Ended {
attrs = append(attrs, "ended", true)
return attrs
}
attrs = append(attrs, []interface{}{"root", root, "base", ts.BaseRoot}...)

if ts.StorageProcessed {
attrs = append(attrs, []interface{}{"at", ts.CurrentAccountHash}...)
} else {
attrs = append(attrs, []interface{}{
"in", ts.CurrentAccountHash,
"at", ts.CurrentSlotHash,
}...)
}
return attrs
}

// LoadTransitionState retrieves the Verkle transition state associated with
// the given state root hash from the database.
func LoadTransitionState(db ethdb.KeyValueReader, root common.Hash) (*TransitionState, error) {
data := rawdb.ReadVerkleTransitionState(db, root)
if len(data) == 0 {
return nil, nil
}
var ts TransitionState
if err := rlp.DecodeBytes(data, &ts); err != nil {
return nil, err
}
return &ts, nil
}

// StoreTransitionState serializes and writes the provided Verkle transition state
// to the database with the given state root hash.
func StoreTransitionState(db ethdb.KeyValueWriter, root common.Hash, ts *TransitionState) error {
data, err := rlp.EncodeToBytes(ts)
if err != nil {
return err
}
rawdb.WriteVerkleTransitionState(db, root, data)
return nil
}
13 changes: 0 additions & 13 deletions core/rawdb/accessors_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,3 @@ func UpdateUncleanShutdownMarker(db ethdb.KeyValueStore) {
log.Warn("Failed to write unclean-shutdown marker", "err", err)
}
}

// ReadTransitionStatus retrieves the eth2 transition status from the database
func ReadTransitionStatus(db ethdb.KeyValueReader) []byte {
data, _ := db.Get(transitionStatusKey)
return data
}

// WriteTransitionStatus stores the eth2 transition status to the database
func WriteTransitionStatus(db ethdb.KeyValueWriter, data []byte) {
if err := db.Put(transitionStatusKey, data); err != nil {
log.Crit("Failed to store the eth2 transition status", "err", err)
}
}
36 changes: 36 additions & 0 deletions core/rawdb/accessors_overlay.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2025 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 <http://www.gnu.org/licenses/>.

package rawdb

import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
)

// ReadVerkleTransitionState reads the verkle transition data from the database.
func ReadVerkleTransitionState(db ethdb.KeyValueReader, hash common.Hash) []byte {
data, _ := db.Get(transitionStateKey(hash))
return data
}

// WriteVerkleTransitionState writes the verkle transition data into the database.
func WriteVerkleTransitionState(db ethdb.KeyValueWriter, hash common.Hash, state []byte) {
if err := db.Put(transitionStateKey(hash), state); err != nil {
log.Crit("Failed to write the verkle transition state", "hash", hash, "err", err)
}
}
2 changes: 1 addition & 1 deletion core/rawdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ var knownMetadataKeys = [][]byte{
snapshotGeneratorKey, snapshotRecoveryKey, txIndexTailKey, fastTxLookupLimitKey,
uncleanShutdownKey, badBlockKey, transitionStatusKey, skeletonSyncStatusKey,
persistentStateIDKey, trieJournalKey, snapshotSyncStatusKey, snapSyncStatusFlagKey,
filterMapsRangeKey,
filterMapsRangeKey, verkleTransitionStatePrefix,
}

// printChainMetadata prints out chain metadata to stderr.
Expand Down
10 changes: 9 additions & 1 deletion core/rawdb/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ var (
uncleanShutdownKey = []byte("unclean-shutdown") // config prefix for the db

// transitionStatusKey tracks the eth2 transition status.
transitionStatusKey = []byte("eth2-transition")
transitionStatusKey = []byte("eth2-transition") // deprecated!

// snapSyncStatusFlagKey flags that status of snap sync.
snapSyncStatusFlagKey = []byte("SnapSyncStatus")
Expand Down Expand Up @@ -147,6 +147,9 @@ var (
preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil)
preimageHitsCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil)
preimageMissCounter = metrics.NewRegisteredCounter("db/preimage/miss", nil)

// Verkle transition information
verkleTransitionStatePrefix = []byte("verkle-transition-state-")
)

// LegacyTxLookupEntry is the legacy TxLookupEntry definition with some unnecessary
Expand Down Expand Up @@ -362,3 +365,8 @@ func filterMapBlockLVKey(number uint64) []byte {
binary.BigEndian.PutUint64(key[l:], number)
return key
}

// transitionStateKey = verkleTransitionStatePrefix + hash
func transitionStateKey(hash common.Hash) []byte {
return append(verkleTransitionStatePrefix, hash.Bytes()...)
}
Loading