Skip to content

Commit 9d2db92

Browse files
committed
core/state: introduce the TransitionState object
1 parent 4906c99 commit 9d2db92

12 files changed

+248
-80
lines changed

consensus/beacon/consensus.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -354,9 +354,9 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.
354354

355355
// FinalizeAndAssemble implements consensus.Engine, setting the final state and
356356
// assembling the block.
357-
func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
357+
func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, statedb *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
358358
if !beacon.IsPoSHeader(header) {
359-
return beacon.ethone.FinalizeAndAssemble(chain, header, state, body, receipts)
359+
return beacon.ethone.FinalizeAndAssemble(chain, header, statedb, body, receipts)
360360
}
361361
shanghai := chain.Config().IsShanghai(header.Number, header.Time)
362362
if shanghai {
@@ -370,30 +370,32 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
370370
}
371371
}
372372
// Finalize and assemble the block.
373-
beacon.Finalize(chain, header, state, body)
373+
beacon.Finalize(chain, header, statedb, body)
374374

375375
// Assign the final state root to header.
376-
header.Root = state.IntermediateRoot(true)
376+
header.Root = statedb.IntermediateRoot(true)
377377

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

381381
// Create the block witness and attach to block.
382382
// This step needs to happen as late as possible to catch all access events.
383383
if chain.Config().IsVerkle(header.Number, header.Time) {
384-
keys := state.AccessEvents().Keys()
384+
// TODO(gballet) move this to the end of the overlay conversion function in a subsequent PR
385+
statedb.Database().SaveTransitionState(header.Root, &state.TransitionState{Ended: true})
386+
keys := statedb.AccessEvents().Keys()
385387

386388
// Open the pre-tree to prove the pre-state against
387389
parent := chain.GetHeaderByNumber(header.Number.Uint64() - 1)
388390
if parent == nil {
389391
return nil, fmt.Errorf("nil parent header for block %d", header.Number)
390392
}
391-
preTrie, err := state.Database().OpenTrie(parent.Root)
393+
preTrie, err := statedb.Database().OpenTrie(parent.Root)
392394
if err != nil {
393395
return nil, fmt.Errorf("error opening pre-state tree root: %w", err)
394396
}
395397
vktPreTrie, okpre := preTrie.(*trie.VerkleTrie)
396-
vktPostTrie, okpost := state.GetTrie().(*trie.VerkleTrie)
398+
vktPostTrie, okpost := statedb.GetTrie().(*trie.VerkleTrie)
397399

398400
// The witness is only attached iff both parent and current block are
399401
// using verkle tree.

core/blockchain.go

+1-6
Original file line numberDiff line numberDiff line change
@@ -283,12 +283,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
283283
if cacheConfig == nil {
284284
cacheConfig = defaultCacheConfig
285285
}
286-
// Open trie database with provided config
287-
enableVerkle, err := EnableVerkleAtGenesis(db, genesis)
288-
if err != nil {
289-
return nil, err
290-
}
291-
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(enableVerkle))
286+
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(genesis.IsVerkle()))
292287

293288
// Write the supplied genesis to the database if it has not been initialized
294289
// yet. The corresponding chain config will be returned, either from the

core/chain_makers.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,10 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
536536
return block, b.receipts
537537
}
538538

539+
sdb := state.NewDatabase(trdb, nil)
540+
539541
for i := 0; i < n; i++ {
540-
statedb, err := state.New(parent.Root(), state.NewDatabase(trdb, nil))
542+
statedb, err := state.New(parent.Root(), sdb)
541543
if err != nil {
542544
panic(err)
543545
}
@@ -575,6 +577,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
575577

576578
func GenerateVerkleChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, gen func(int, *BlockGen)) (common.Hash, ethdb.Database, []*types.Block, []types.Receipts, []*verkle.VerkleProof, []verkle.StateDiff) {
577579
db := rawdb.NewMemoryDatabase()
580+
saveVerkleTransitionStatusAtVerlkeGenesis(db)
578581
cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme)
579582
cacheConfig.SnapshotLimit = 0
580583
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true))

core/genesis.go

+31-24
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package core
1818

1919
import (
2020
"bytes"
21+
"encoding/gob"
2122
"encoding/json"
2223
"errors"
2324
"fmt"
@@ -145,6 +146,9 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
145146
emptyRoot = types.EmptyVerkleHash
146147
}
147148
db := rawdb.NewMemoryDatabase()
149+
if isVerkle {
150+
saveVerkleTransitionStatusAtVerlkeGenesis(db)
151+
}
148152
statedb, err := state.New(emptyRoot, state.NewDatabase(triedb.NewDatabase(db, config), nil))
149153
if err != nil {
150154
return common.Hash{}, err
@@ -276,6 +280,24 @@ func (o *ChainOverrides) apply(cfg *params.ChainConfig) error {
276280
return cfg.CheckConfigForkOrder()
277281
}
278282

283+
// saveVerkleTransitionStatusAtVerlkeGenesis saves a conversion marker
284+
// representing a converted state, which is used in devnets that activate
285+
// verkle at genesis.
286+
func saveVerkleTransitionStatusAtVerlkeGenesis(db ethdb.Database) {
287+
saveVerkleTransitionStatus(db, common.Hash{}, &state.TransitionState{Ended: true})
288+
}
289+
290+
func saveVerkleTransitionStatus(db ethdb.Database, root common.Hash, ts *state.TransitionState) {
291+
var buf bytes.Buffer
292+
enc := gob.NewEncoder(&buf)
293+
err := enc.Encode(ts)
294+
if err != nil {
295+
log.Error("failed to encode transition state", "err", err)
296+
return
297+
}
298+
rawdb.WriteVerkleTransitionState(db, root, buf.Bytes())
299+
}
300+
279301
// SetupGenesisBlock writes or updates the genesis block in db.
280302
// The block that will be used is:
281303
//
@@ -299,6 +321,11 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
299321
if genesis != nil && genesis.Config == nil {
300322
return nil, common.Hash{}, nil, errGenesisNoConfig
301323
}
324+
// In case of verkle-at-genesis, we need to ensure that the conversion
325+
// markers are indicating that the conversion has completed.
326+
if genesis != nil && genesis.Config.VerkleTime != nil && *genesis.Config.VerkleTime == genesis.Timestamp {
327+
saveVerkleTransitionStatusAtVerlkeGenesis(db)
328+
}
302329
// Commit the genesis if the database is empty
303330
ghash := rawdb.ReadCanonicalHash(db, 0)
304331
if (ghash == common.Hash{}) {
@@ -443,7 +470,7 @@ func (g *Genesis) chainConfigOrDefault(ghash common.Hash, stored *params.ChainCo
443470
// IsVerkle indicates whether the state is already stored in a verkle
444471
// tree at genesis time.
445472
func (g *Genesis) IsVerkle() bool {
446-
return g.Config.IsVerkleGenesis()
473+
return g.Config.VerkleTime != nil && *g.Config.VerkleTime == g.Timestamp
447474
}
448475

449476
// ToBlock returns the genesis block according to genesis specification.
@@ -547,6 +574,9 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
547574
if err != nil {
548575
return nil, err
549576
}
577+
if g.IsVerkle() {
578+
saveVerkleTransitionStatus(db, block.Root(), &state.TransitionState{Ended: true})
579+
}
550580
batch := db.NewBatch()
551581
rawdb.WriteGenesisStateSpec(batch, block.Hash(), blob)
552582
rawdb.WriteBlock(batch, block)
@@ -569,29 +599,6 @@ func (g *Genesis) MustCommit(db ethdb.Database, triedb *triedb.Database) *types.
569599
return block
570600
}
571601

572-
// EnableVerkleAtGenesis indicates whether the verkle fork should be activated
573-
// at genesis. This is a temporary solution only for verkle devnet testing, where
574-
// verkle fork is activated at genesis, and the configured activation date has
575-
// already passed.
576-
//
577-
// In production networks (mainnet and public testnets), verkle activation always
578-
// occurs after the genesis block, making this function irrelevant in those cases.
579-
func EnableVerkleAtGenesis(db ethdb.Database, genesis *Genesis) (bool, error) {
580-
if genesis != nil {
581-
if genesis.Config == nil {
582-
return false, errGenesisNoConfig
583-
}
584-
return genesis.Config.EnableVerkleAtGenesis, nil
585-
}
586-
if ghash := rawdb.ReadCanonicalHash(db, 0); ghash != (common.Hash{}) {
587-
chainCfg := rawdb.ReadChainConfig(db, ghash)
588-
if chainCfg != nil {
589-
return chainCfg.EnableVerkleAtGenesis, nil
590-
}
591-
}
592-
return false, nil
593-
}
594-
595602
// DefaultGenesisBlock returns the Ethereum main net genesis block.
596603
func DefaultGenesisBlock() *Genesis {
597604
return &Genesis{

core/genesis_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,6 @@ func TestVerkleGenesisCommit(t *testing.T) {
286286
OsakaTime: &verkleTime,
287287
VerkleTime: &verkleTime,
288288
TerminalTotalDifficulty: big.NewInt(0),
289-
EnableVerkleAtGenesis: true,
290289
Ethash: nil,
291290
Clique: nil,
292291
BlobScheduleConfig: &params.BlobScheduleConfig{
@@ -314,6 +313,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
314313
}
315314

316315
db := rawdb.NewMemoryDatabase()
316+
saveVerkleTransitionStatusAtVerlkeGenesis(db)
317317
triedb := triedb.NewDatabase(db, triedb.VerkleDefaults)
318318
block := genesis.MustCommit(db, triedb)
319319
if !bytes.Equal(block.Root().Bytes(), expected) {

core/rawdb/accessors_overlay.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2025 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package rawdb
18+
19+
import (
20+
"github.com/ethereum/go-ethereum/common"
21+
"github.com/ethereum/go-ethereum/ethdb"
22+
)
23+
24+
func ReadVerkleTransitionState(db ethdb.KeyValueReader, hash common.Hash) ([]byte, error) {
25+
return db.Get(transitionStateKey(hash))
26+
}
27+
28+
func WriteVerkleTransitionState(db ethdb.KeyValueWriter, hash common.Hash, state []byte) error {
29+
return db.Put(transitionStateKey(hash), state)
30+
}

core/rawdb/schema.go

+8
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ var (
147147
preimageCounter = metrics.NewRegisteredCounter("db/preimage/total", nil)
148148
preimageHitsCounter = metrics.NewRegisteredCounter("db/preimage/hits", nil)
149149
preimageMissCounter = metrics.NewRegisteredCounter("db/preimage/miss", nil)
150+
151+
// Verkle transition information
152+
VerkleTransitionStatePrefix = []byte("verkle-transition-state-")
150153
)
151154

152155
// LegacyTxLookupEntry is the legacy TxLookupEntry definition with some unnecessary
@@ -362,3 +365,8 @@ func filterMapBlockLVKey(number uint64) []byte {
362365
binary.BigEndian.PutUint64(key[l:], number)
363366
return key
364367
}
368+
369+
// transitionStateKey = transitionStatusKey + hash
370+
func transitionStateKey(hash common.Hash) []byte {
371+
return append(VerkleTransitionStatePrefix, hash.Bytes()...)
372+
}

0 commit comments

Comments
 (0)