From 99d180bf2cca2ac865f3b82648dd1728e2c82128 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 26 Oct 2023 17:47:24 +0200 Subject: [PATCH 1/2] save overlay conversion iterator pointers at each block --- core/blockchain.go | 12 +-- core/chain_makers.go | 4 +- core/genesis.go | 4 +- core/overlay_transition.go | 46 +++++------ core/state/database.go | 156 ++++++++++++++++++++----------------- core/state/statedb.go | 2 +- core/state_processor.go | 3 +- eth/catalyst/api.go | 2 +- light/trie.go | 30 +++---- miner/worker.go | 4 +- 10 files changed, 137 insertions(+), 126 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 01da77d8e453..f42388d7024f 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -312,7 +312,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis // Declare the end of the verkle transition if need be if bc.chainConfig.Rules(head.Number, false /* XXX */, head.Time).IsPrague { - bc.stateCache.EndVerkleTransition() + bc.stateCache.EndVerkleTransition(head.Root) } if !bc.HasState(head.Root) { @@ -1746,7 +1746,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) } if parent.Number.Uint64() == conversionBlock { - bc.StartVerkleTransition(parent.Root, emptyVerkleRoot, bc.Config(), &parent.Time) + bc.StartVerkleTransition(parent.Root, bc.Config(), &parent.Time, parent.Root) bc.stateCache.SetLastMerkleRoot(parent.Root) } statedb, err := state.New(parent.Root, bc.stateCache, bc.snaps) @@ -2532,17 +2532,13 @@ func (bc *BlockChain) GetTrieFlushInterval() time.Duration { return time.Duration(bc.flushInterval.Load()) } -func (bc *BlockChain) StartVerkleTransition(originalRoot, translatedRoot common.Hash, chainConfig *params.ChainConfig, pragueTime *uint64) { - bc.stateCache.StartVerkleTransition(originalRoot, translatedRoot, chainConfig, pragueTime) +func (bc *BlockChain) StartVerkleTransition(originalRoot common.Hash, chainConfig *params.ChainConfig, pragueTime *uint64, root common.Hash) { + bc.stateCache.StartVerkleTransition(originalRoot, chainConfig, pragueTime, root) } func (bc *BlockChain) ReorgThroughVerkleTransition() { bc.stateCache.ReorgThroughVerkleTransition() } -func (bc *BlockChain) EndVerkleTransition() { - bc.stateCache.EndVerkleTransition() -} - func (bc *BlockChain) AddRootTranslation(originalRoot, translatedRoot common.Hash) { bc.stateCache.AddRootTranslation(originalRoot, translatedRoot) } diff --git a/core/chain_makers.go b/core/chain_makers.go index 5d8ade8a0fb0..8aeed1791061 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -425,9 +425,9 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine return nil, nil } var snaps *snapshot.Tree + triedb := state.NewDatabaseWithConfig(db, nil) + triedb.EndVerkleTransition(parent.Root()) for i := 0; i < n; i++ { - triedb := state.NewDatabaseWithConfig(db, nil) - triedb.EndVerkleTransition() statedb, err := state.New(parent.Root(), triedb, snaps) if err != nil { panic(fmt.Sprintf("could not find state for block %d: err=%v, parent root=%x", i, err, parent.Root())) diff --git a/core/genesis.go b/core/genesis.go index 74294afb7272..53962bb0abd1 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -126,7 +126,7 @@ func (ga *GenesisAlloc) deriveHash(cfg *params.ChainConfig, timestamp uint64) (c // all the derived states will be discarded to not pollute disk. db := state.NewDatabase(rawdb.NewMemoryDatabase()) if cfg.IsPrague(big.NewInt(int64(0)), timestamp) { - db.EndVerkleTransition() + db.EndVerkleTransition(common.Hash{}) } statedb, err := state.New(types.EmptyRootHash, db, nil) if err != nil { @@ -154,7 +154,7 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhas // End the verkle conversion at genesis if the fork block is 0 if triedb.IsVerkle() { - statedb.Database().EndVerkleTransition() + statedb.Database().EndVerkleTransition(common.Hash{}) } for addr, account := range *ga { diff --git a/core/overlay_transition.go b/core/overlay_transition.go index 35c09d22d938..f1a4568ca3b5 100644 --- a/core/overlay_transition.go +++ b/core/overlay_transition.go @@ -35,19 +35,19 @@ import ( ) // OverlayVerkleTransition contains the overlay conversion logic -func OverlayVerkleTransition(statedb *state.StateDB) error { +func OverlayVerkleTransition(statedb *state.StateDB, root common.Hash) error { migrdb := statedb.Database() // verkle transition: if the conversion process is in progress, move // N values from the MPT into the verkle tree. - if migrdb.InTransition() { + if migrdb.InTransition(root) { var ( now = time.Now() tt = statedb.GetTrie().(*trie.TransitionTrie) mpt = tt.Base() vkt = tt.Overlay() hasPreimagesBin = false - preimageSeek = migrdb.GetCurrentPreimageOffset() + preimageSeek = migrdb.GetCurrentPreimageOffset(root) fpreimages *bufio.Reader ) @@ -65,7 +65,7 @@ func OverlayVerkleTransition(statedb *state.StateDB) error { hasPreimagesBin = true } - accIt, err := statedb.Snaps().AccountIterator(mpt.Hash(), migrdb.GetCurrentAccountHash()) + accIt, err := statedb.Snaps().AccountIterator(mpt.Hash(), migrdb.GetCurrentAccountHash(root)) if err != nil { return err } @@ -73,7 +73,7 @@ func OverlayVerkleTransition(statedb *state.StateDB) error { accIt.Next() // If we're about to start with the migration process, we have to read the first account hash preimage. - if migrdb.GetCurrentAccountAddress() == nil { + if migrdb.GetCurrentAccountAddress(root) == nil { var addr common.Address if hasPreimagesBin { if _, err := io.ReadFull(fpreimages, addr[:]); err != nil { @@ -85,8 +85,8 @@ func OverlayVerkleTransition(statedb *state.StateDB) error { return fmt.Errorf("addr len is zero is not 32: %d", len(addr)) } } - migrdb.SetCurrentAccountAddress(addr) - if migrdb.GetCurrentAccountHash() != accIt.Hash() { + migrdb.SetCurrentAccountAddress(addr, root) + if migrdb.GetCurrentAccountHash(root) != accIt.Hash() { return fmt.Errorf("preimage file does not match account hash: %s != %s", crypto.Keccak256Hash(addr[:]), accIt.Hash()) } preimageSeek += int64(len(addr)) @@ -108,7 +108,7 @@ func OverlayVerkleTransition(statedb *state.StateDB) error { log.Error("Invalid account encountered during traversal", "error", err) return err } - vkt.SetStorageRootConversion(*migrdb.GetCurrentAccountAddress(), acc.Root) + vkt.SetStorageRootConversion(*migrdb.GetCurrentAccountAddress(root), acc.Root) // Start with processing the storage, because once the account is // converted, the `stateRoot` field loses its meaning. Which means @@ -120,7 +120,7 @@ func OverlayVerkleTransition(statedb *state.StateDB) error { // to during normal block execution. A mitigation strategy has been // introduced with the `*StorageRootConversion` fields in VerkleDB. if acc.HasStorage() { - stIt, err := statedb.Snaps().StorageIterator(mpt.Hash(), accIt.Hash(), migrdb.GetCurrentSlotHash()) + stIt, err := statedb.Snaps().StorageIterator(mpt.Hash(), accIt.Hash(), migrdb.GetCurrentSlotHash(root)) if err != nil { return err } @@ -132,7 +132,7 @@ func OverlayVerkleTransition(statedb *state.StateDB) error { // processing the storage for that account where we left off. // If the entire storage was processed, then the iterator was // created in vain, but it's ok as this will not happen often. - for ; !migrdb.GetStorageProcessed() && count < maxMovedCount; count++ { + for ; !migrdb.GetStorageProcessed(root) && count < maxMovedCount; count++ { var ( value []byte // slot value after RLP decoding safeValue [32]byte // 32-byte aligned value @@ -160,12 +160,12 @@ func OverlayVerkleTransition(statedb *state.StateDB) error { } preimageSeek += int64(len(slotnr)) - mkv.addStorageSlot(migrdb.GetCurrentAccountAddress().Bytes(), slotnr, safeValue[:]) + mkv.addStorageSlot(migrdb.GetCurrentAccountAddress(root).Bytes(), slotnr, safeValue[:]) // advance the storage iterator - migrdb.SetStorageProcessed(!stIt.Next()) - if !migrdb.GetStorageProcessed() { - migrdb.SetCurrentSlotHash(stIt.Hash()) + migrdb.SetStorageProcessed(!stIt.Next(), root) + if !migrdb.GetStorageProcessed(root) { + migrdb.SetCurrentSlotHash(stIt.Hash(), root) } } stIt.Release() @@ -178,20 +178,20 @@ func OverlayVerkleTransition(statedb *state.StateDB) error { if count < maxMovedCount { count++ // count increase for the account itself - mkv.addAccount(migrdb.GetCurrentAccountAddress().Bytes(), acc) - vkt.ClearStrorageRootConversion(*migrdb.GetCurrentAccountAddress()) + mkv.addAccount(migrdb.GetCurrentAccountAddress(root).Bytes(), acc) + vkt.ClearStrorageRootConversion(*migrdb.GetCurrentAccountAddress(root)) // Store the account code if present if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash[:]) { code := rawdb.ReadCode(statedb.Database().DiskDB(), common.BytesToHash(acc.CodeHash)) chunks := trie.ChunkifyCode(code) - mkv.addAccountCode(migrdb.GetCurrentAccountAddress().Bytes(), uint64(len(code)), chunks) + mkv.addAccountCode(migrdb.GetCurrentAccountAddress(root).Bytes(), uint64(len(code)), chunks) } // reset storage iterator marker for next account - migrdb.SetStorageProcessed(false) - migrdb.SetCurrentSlotHash(common.Hash{}) + migrdb.SetStorageProcessed(false, root) + migrdb.SetCurrentSlotHash(common.Hash{}, root) // Move to the next account, if available - or end // the transition otherwise. @@ -212,18 +212,18 @@ func OverlayVerkleTransition(statedb *state.StateDB) error { return fmt.Errorf("preimage file does not match account hash: %s != %s", crypto.Keccak256Hash(addr[:]), accIt.Hash()) } preimageSeek += int64(len(addr)) - migrdb.SetCurrentAccountAddress(addr) + migrdb.SetCurrentAccountAddress(addr, root) } else { // case when the account iterator has // reached the end but count < maxCount - migrdb.EndVerkleTransition() + migrdb.EndVerkleTransition(root) break } } } - migrdb.SetCurrentPreimageOffset(preimageSeek) + migrdb.SetCurrentPreimageOffset(preimageSeek, root) - log.Info("Collected key values from base tree", "count", count, "duration", time.Since(now), "last account", statedb.Database().GetCurrentAccountHash()) + log.Info("Collected key values from base tree", "count", count, "duration", time.Since(now), "last account", statedb.Database().GetCurrentAccountHash(root)) // Take all the collected key-values and prepare the new leaf values. // This fires a background routine that will start doing the work that diff --git a/core/state/database.go b/core/state/database.go index af8cc1a36e30..dff4dc001265 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -64,37 +64,37 @@ type Database interface { // TrieDB retrieves the low level trie database used for data storage. TrieDB() *trie.Database - StartVerkleTransition(originalRoot, translatedRoot common.Hash, chainConfig *params.ChainConfig, cancunTime *uint64) + StartVerkleTransition(originalRoot common.Hash, chainConfig *params.ChainConfig, cancunTime *uint64, root common.Hash) ReorgThroughVerkleTransition() - EndVerkleTransition() + EndVerkleTransition(common.Hash) - InTransition() bool + InTransition(common.Hash) bool - Transitioned() bool + Transitioned(common.Hash) bool - SetCurrentSlotHash(hash common.Hash) + SetCurrentSlotHash(common.Hash, common.Hash) - GetCurrentAccountAddress() *common.Address + GetCurrentAccountAddress(common.Hash) *common.Address - SetCurrentAccountAddress(common.Address) + SetCurrentAccountAddress(common.Address, common.Hash) - GetCurrentAccountHash() common.Hash + GetCurrentAccountHash(common.Hash) common.Hash - GetCurrentSlotHash() common.Hash + GetCurrentSlotHash(common.Hash) common.Hash - SetStorageProcessed(bool) + SetStorageProcessed(bool, common.Hash) - GetStorageProcessed() bool + GetStorageProcessed(common.Hash) bool - GetCurrentPreimageOffset() int64 + GetCurrentPreimageOffset(common.Hash) int64 - SetCurrentPreimageOffset(int64) + SetCurrentPreimageOffset(int64, common.Hash) AddRootTranslation(originalRoot, translatedRoot common.Hash) - SetLastMerkleRoot(root common.Hash) + SetLastMerkleRoot(common.Hash) } // Trie is a Ethereum Merkle Patricia trie. @@ -182,36 +182,46 @@ func NewDatabase(db ethdb.Database) Database { // large memory cache. func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { return &cachingDB{ - disk: db, - codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), - codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), - triedb: trie.NewDatabaseWithConfig(db, config), - addrToPoint: utils.NewPointCache(), + disk: db, + codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), + codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), + triedb: trie.NewDatabaseWithConfig(db, config), + addrToPoint: utils.NewPointCache(), + StorageProcessed: map[common.Hash]bool{}, + CurrentAccountAddress: map[common.Hash]*common.Address{}, + CurrentSlotHash: map[common.Hash]common.Hash{}, + CurrentPreimageOffset: map[common.Hash]int64{}, started: map[common.Hash]bool{}, + ended: map[common.Hash]bool{}, } } // NewDatabaseWithNodeDB creates a state database with an already initialized node database. func NewDatabaseWithNodeDB(db ethdb.Database, triedb *trie.Database) Database { return &cachingDB{ - disk: db, - codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), - codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), - triedb: triedb, - addrToPoint: utils.NewPointCache(), - ended: triedb.IsVerkle(), + disk: db, + codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize), + codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize), + triedb: triedb, + addrToPoint: utils.NewPointCache(), + StorageProcessed: map[common.Hash]bool{}, + CurrentAccountAddress: map[common.Hash]*common.Address{}, + CurrentSlotHash: map[common.Hash]common.Hash{}, + CurrentPreimageOffset: map[common.Hash]int64{}, + started: map[common.Hash]bool{}, + ended: map[common.Hash]bool{}, } } -func (db *cachingDB) InTransition() bool { - return db.started && !db.ended +func (db *cachingDB) InTransition(root common.Hash) bool { + return db.started[root] && !db.ended[root] } -func (db *cachingDB) Transitioned() bool { - return db.ended +func (db *cachingDB) Transitioned(root common.Hash) bool { + return db.ended[root] } // Fork implements the fork -func (db *cachingDB) StartVerkleTransition(originalRoot, translatedRoot common.Hash, chainConfig *params.ChainConfig, pragueTime *uint64) { +func (db *cachingDB) StartVerkleTransition(originalRoot common.Hash, chainConfig *params.ChainConfig, pragueTime *uint64, root common.Hash) { fmt.Println(` __________.__ .__ .__ __ .__ .__ ____ \__ ___| |__ ____ ____ | | ____ ______ | |__ _____ _____/ |_ | |__ _____ ______ __ _ _|__| ____ / ___\ ______ @@ -219,24 +229,27 @@ func (db *cachingDB) StartVerkleTransition(originalRoot, translatedRoot common.H | | | Y \ ___/ \ ___/| |_\ ___/| |_> | Y \/ __ \| | | | | Y \/ __ \_\___ \ \ /| | | \\___ /\___ \ |____| |___| /\___ \___ |____/\___ | __/|___| (____ |___| |__| |___| (____ /_____/ \/\_/ |__|___| /_____//_____/ |__|`) - db.started = true - db.ended = false + db.started[root] = true + db.ended[root] = false // db.AddTranslation(originalRoot, translatedRoot) db.baseRoot = originalRoot // initialize so that the first storage-less accounts are processed - db.StorageProcessed = true + db.StorageProcessed[root] = true if pragueTime != nil { chainConfig.PragueTime = pragueTime } } func (db *cachingDB) ReorgThroughVerkleTransition() { - db.ended, db.started = false, false + for k := range db.ended { + delete(db.ended, k) + delete(db.started, k) + } } -func (db *cachingDB) EndVerkleTransition() { - if !db.started { - db.started = true +func (db *cachingDB) EndVerkleTransition(root common.Hash) { + if !db.started[root] { + db.started[root] = true } fmt.Println(` @@ -246,7 +259,7 @@ func (db *cachingDB) EndVerkleTransition() { | | | Y \ ___/ \ ___/| |_\ ___/| |_> | Y \/ __ \| | | | | Y \/ __ \_\___ \ | |__/ __ \| | / /_/ \ ___// /_/ | |____| |___| /\___ \___ |____/\___ | __/|___| (____ |___| |__| |___| (____ /_____/ |____(____ |___| \____ |\___ \____ | |__|`) - db.ended = true + db.ended[root] = true } type cachingDB struct { @@ -257,20 +270,21 @@ type cachingDB struct { // Verkle specific fields // TODO ensure that this info is in the DB - started, ended bool + started, ended map[common.Hash]bool LastMerkleRoot common.Hash // root hash of the read-only base tree addrToPoint *utils.PointCache - baseRoot common.Hash // hash of the read-only base tree - CurrentAccountAddress *common.Address // addresss of the last translated account - CurrentSlotHash common.Hash // hash of the last translated storage slot - CurrentPreimageOffset int64 // next byte to read from the preimage file + baseRoot common.Hash // hash of the read-only base tree + CurrentAccountAddress map[common.Hash]*common.Address // addresss of the last translated account + CurrentSlotHash map[common.Hash]common.Hash // hash of the last translated storage slot + CurrentPreimageOffset map[common.Hash]int64 // next byte to read from the preimage file // Mark whether the storage for an account has been processed. This is useful if the // maximum number of leaves of the conversion is reached before the whole storage is // processed. - StorageProcessed bool + StorageProcessed map[common.Hash]bool + currentBlock uint64 } func (db *cachingDB) openMPTTrie(root common.Hash) (Trie, error) { @@ -284,14 +298,14 @@ func (db *cachingDB) openMPTTrie(root common.Hash) (Trie, error) { func (db *cachingDB) openVKTrie(root common.Hash) (Trie, error) { payload, err := db.DiskDB().Get(trie.FlatDBVerkleNodeKeyPrefix) if err != nil { - return trie.NewVerkleTrie(verkle.New(), db.triedb, db.addrToPoint, db.ended), nil + return trie.NewVerkleTrie(verkle.New(), db.triedb, db.addrToPoint, db.ended[root]), nil } r, err := verkle.ParseNode(payload, 0) if err != nil { panic(err) } - return trie.NewVerkleTrie(r, db.triedb, db.addrToPoint, db.ended), err + return trie.NewVerkleTrie(r, db.triedb, db.addrToPoint, db.ended[root]), err } // OpenTrie opens the main account trie at a specific root hash. @@ -303,7 +317,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { // TODO separate both cases when I can be certain that it won't // find a Verkle trie where is expects a Transitoion trie. - if db.started || db.ended { + if db.started[root] || db.ended[root] { // NOTE this is a kaustinen-only change, it will break replay vkt, err := db.openVKTrie(root) if err != nil { @@ -312,7 +326,7 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { // If the verkle conversion has ended, return a single // verkle trie. - if db.ended { + if db.ended[root] { return vkt, nil } @@ -345,7 +359,7 @@ func (db *cachingDB) openStorageMPTrie(stateRoot common.Hash, address common.Add // 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) { // TODO this should only return a verkle tree - if db.ended { + if db.ended[root] { mpt, err := db.openStorageMPTrie(types.EmptyRootHash, address, common.Hash{}, self) if err != nil { return nil, err @@ -361,7 +375,7 @@ func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre panic("unexpected trie type") } } - if db.started { + if db.started[root] { mpt, err := db.openStorageMPTrie(db.LastMerkleRoot, address, root, nil) if err != nil { return nil, err @@ -450,49 +464,49 @@ func (db *cachingDB) GetTreeKeyHeader(addr []byte) *verkle.Point { return db.addrToPoint.GetTreeKeyHeader(addr) } -func (db *cachingDB) SetCurrentAccountAddress(addr common.Address) { - db.CurrentAccountAddress = &addr +func (db *cachingDB) SetCurrentAccountAddress(addr common.Address, root common.Hash) { + db.CurrentAccountAddress[root] = &addr } -func (db *cachingDB) GetCurrentAccountHash() common.Hash { +func (db *cachingDB) GetCurrentAccountHash(root common.Hash) common.Hash { var addrHash common.Hash - if db.CurrentAccountAddress != nil { - addrHash = crypto.Keccak256Hash(db.CurrentAccountAddress[:]) + if db.CurrentAccountAddress[root] != nil { + addrHash = crypto.Keccak256Hash(db.CurrentAccountAddress[root][:]) } return addrHash } -func (db *cachingDB) GetCurrentAccountAddress() *common.Address { - return db.CurrentAccountAddress +func (db *cachingDB) GetCurrentAccountAddress(root common.Hash) *common.Address { + return db.CurrentAccountAddress[root] } -func (db *cachingDB) GetCurrentPreimageOffset() int64 { - return db.CurrentPreimageOffset +func (db *cachingDB) GetCurrentPreimageOffset(root common.Hash) int64 { + return db.CurrentPreimageOffset[root] } -func (db *cachingDB) SetCurrentPreimageOffset(offset int64) { - db.CurrentPreimageOffset = offset +func (db *cachingDB) SetCurrentPreimageOffset(offset int64, root common.Hash) { + db.CurrentPreimageOffset[root] = offset } -func (db *cachingDB) SetCurrentSlotHash(hash common.Hash) { - db.CurrentSlotHash = hash +func (db *cachingDB) SetCurrentSlotHash(hash common.Hash, root common.Hash) { + db.CurrentSlotHash[root] = hash } -func (db *cachingDB) GetCurrentSlotHash() common.Hash { - return db.CurrentSlotHash +func (db *cachingDB) GetCurrentSlotHash(root common.Hash) common.Hash { + return db.CurrentSlotHash[root] } -func (db *cachingDB) SetStorageProcessed(processed bool) { - db.StorageProcessed = processed +func (db *cachingDB) SetStorageProcessed(processed bool, root common.Hash) { + db.StorageProcessed[root] = processed } -func (db *cachingDB) GetStorageProcessed() bool { - return db.StorageProcessed +func (db *cachingDB) GetStorageProcessed(root common.Hash) bool { + return db.StorageProcessed[root] } func (db *cachingDB) AddRootTranslation(originalRoot, translatedRoot common.Hash) { } -func (db *cachingDB) SetLastMerkleRoot(root common.Hash) { - db.LastMerkleRoot = root +func (db *cachingDB) SetLastMerkleRoot(merkleRoot common.Hash) { + db.LastMerkleRoot = merkleRoot } diff --git a/core/state/statedb.go b/core/state/statedb.go index 442527a1e906..caffad992c40 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1039,7 +1039,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { root := s.trie.Hash() // Save the root of the MPT so that it can be used during the transition - if !s.Database().InTransition() && !s.Database().Transitioned() { + if !s.Database().InTransition(root) && !s.Database().Transitioned(root) { s.Database().SetLastMerkleRoot(root) } diff --git a/core/state_processor.go b/core/state_processor.go index 5d10bceb1817..605480fcb975 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -106,7 +106,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } // Perform the overlay transition, if relevant - if err := OverlayVerkleTransition(statedb); err != nil { + parent := p.bc.GetHeaderByHash(header.ParentHash) + if err := OverlayVerkleTransition(statedb, parent.Root); err != nil { return nil, nil, 0, fmt.Errorf("error performing verkle overlay transition: %w", err) } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 63079415fc14..5c7bf685d264 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -532,7 +532,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe if api.eth.BlockChain().Config().IsPrague(block.Number(), block.Time()) && !api.eth.BlockChain().Config().IsPrague(parent.Number(), parent.Time()) { parent := api.eth.BlockChain().GetHeaderByNumber(block.NumberU64() - 1) if !api.eth.BlockChain().Config().IsPrague(parent.Number, parent.Time) { - api.eth.BlockChain().StartVerkleTransition(parent.Root, common.Hash{}, api.eth.BlockChain().Config(), nil) + api.eth.BlockChain().StartVerkleTransition(parent.Root, api.eth.BlockChain().Config(), api.eth.BlockChain().Config().PragueTime, parent.Root) } } // Reset db merge state in case of a reorg diff --git a/light/trie.go b/light/trie.go index 53d54615d909..ae6f4e00a718 100644 --- a/light/trie.go +++ b/light/trie.go @@ -101,7 +101,7 @@ func (db *odrDatabase) DiskDB() ethdb.KeyValueStore { panic("not implemented") } -func (db *odrDatabase) StartVerkleTransition(originalRoot common.Hash, translatedRoot common.Hash, chainConfig *params.ChainConfig, _ *uint64) { +func (db *odrDatabase) StartVerkleTransition(originalRoot common.Hash, chainConfig *params.ChainConfig, _ *uint64, _ common.Hash) { panic("not implemented") // TODO: Implement } @@ -109,59 +109,59 @@ func (db *odrDatabase) ReorgThroughVerkleTransition() { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) EndVerkleTransition() { +func (db *odrDatabase) EndVerkleTransition(common.Hash) { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) InTransition() bool { +func (db *odrDatabase) InTransition(common.Hash) bool { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) Transitioned() bool { +func (db *odrDatabase) Transitioned(common.Hash) bool { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) SetCurrentSlotHash(hash common.Hash) { +func (db *odrDatabase) SetCurrentSlotHash(common.Hash, common.Hash) { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) GetCurrentAccountAddress() *common.Address { +func (db *odrDatabase) GetCurrentAccountAddress(common.Hash) *common.Address { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) SetCurrentAccountAddress(_ common.Address) { +func (db *odrDatabase) SetCurrentAccountAddress(common.Address, common.Hash) { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) GetCurrentAccountHash() common.Hash { +func (db *odrDatabase) GetCurrentAccountHash(common.Hash) common.Hash { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) GetCurrentSlotHash() common.Hash { +func (db *odrDatabase) GetCurrentSlotHash(common.Hash) common.Hash { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) SetStorageProcessed(_ bool) { +func (db *odrDatabase) SetStorageProcessed(bool, common.Hash) { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) GetStorageProcessed() bool { +func (db *odrDatabase) GetStorageProcessed(common.Hash) bool { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) GetCurrentPreimageOffset() int64 { +func (db *odrDatabase) GetCurrentPreimageOffset(common.Hash) int64 { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) SetCurrentPreimageOffset(_ int64) { +func (db *odrDatabase) SetCurrentPreimageOffset(int64, common.Hash) { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) AddRootTranslation(originalRoot common.Hash, translatedRoot common.Hash) { +func (db *odrDatabase) AddRootTranslation(common.Hash, common.Hash) { panic("not implemented") // TODO: Implement } -func (db *odrDatabase) SetLastMerkleRoot(root common.Hash) { +func (db *odrDatabase) SetLastMerkleRoot(common.Hash) { panic("not implemented") // TODO: Implement } diff --git a/miner/worker.go b/miner/worker.go index 124c93212262..9505a84f7aa8 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -894,7 +894,7 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { if w.chain.Config().IsPrague(header.Number, header.Time) { parent := w.chain.GetHeaderByNumber(header.Number.Uint64() - 1) if !w.chain.Config().IsPrague(parent.Number, parent.Time) { - w.chain.StartVerkleTransition(parent.Root, common.Hash{}, w.chain.Config(), nil) + w.chain.StartVerkleTransition(parent.Root, w.chain.Config(), w.chain.Config().PragueTime, parent.Root) } } @@ -905,7 +905,7 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { return nil, err } if w.chain.Config().IsPrague(header.Number, header.Time) { - core.OverlayVerkleTransition(state) + core.OverlayVerkleTransition(state, parent.Root) } // Run the consensus preparation with the default or customized consensus engine. if err := w.engine.Prepare(w.chain, header); err != nil { From 88654be8768e0fe53090d5ba98864c21ae3b9744 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:35:22 +0200 Subject: [PATCH 2/2] fixes to get verkle state processor test to work --- core/chain_makers.go | 6 ++++-- core/genesis.go | 2 +- core/state/database.go | 4 ++-- core/state_processor.go | 5 +++++ 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/core/chain_makers.go b/core/chain_makers.go index 8aeed1791061..4cd351021615 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -425,9 +425,11 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine return nil, nil } var snaps *snapshot.Tree - triedb := state.NewDatabaseWithConfig(db, nil) - triedb.EndVerkleTransition(parent.Root()) + triedb := state.NewDatabaseWithConfig(db, &trie.Config{Verkle: true}) for i := 0; i < n; i++ { + // This needs to be activated because now InTransiton/Transitionned + // depend on the root hash, so you have to mark it as such. + triedb.EndVerkleTransition(parent.Root()) statedb, err := state.New(parent.Root(), triedb, snaps) if err != nil { panic(fmt.Sprintf("could not find state for block %d: err=%v, parent root=%x", i, err, parent.Root())) diff --git a/core/genesis.go b/core/genesis.go index 53962bb0abd1..a975150b1ea0 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -126,7 +126,7 @@ func (ga *GenesisAlloc) deriveHash(cfg *params.ChainConfig, timestamp uint64) (c // all the derived states will be discarded to not pollute disk. db := state.NewDatabase(rawdb.NewMemoryDatabase()) if cfg.IsPrague(big.NewInt(int64(0)), timestamp) { - db.EndVerkleTransition(common.Hash{}) + db.EndVerkleTransition(types.EmptyRootHash) } statedb, err := state.New(types.EmptyRootHash, db, nil) if err != nil { diff --git a/core/state/database.go b/core/state/database.go index dff4dc001265..82959f60bb58 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -191,7 +191,7 @@ func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { CurrentAccountAddress: map[common.Hash]*common.Address{}, CurrentSlotHash: map[common.Hash]common.Hash{}, CurrentPreimageOffset: map[common.Hash]int64{}, started: map[common.Hash]bool{}, - ended: map[common.Hash]bool{}, + ended: map[common.Hash]bool{(common.Hash{}): (config != nil && config.Verkle), types.EmptyRootHash: (config != nil && config.Verkle)}, } } @@ -208,7 +208,7 @@ func NewDatabaseWithNodeDB(db ethdb.Database, triedb *trie.Database) Database { CurrentSlotHash: map[common.Hash]common.Hash{}, CurrentPreimageOffset: map[common.Hash]int64{}, started: map[common.Hash]bool{}, - ended: map[common.Hash]bool{}, + ended: map[common.Hash]bool{types.EmptyRootHash: triedb.IsVerkle(), (common.Hash{}): triedb.IsVerkle()}, } } diff --git a/core/state_processor.go b/core/state_processor.go index 605480fcb975..340d6757b8a4 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -107,9 +107,14 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Perform the overlay transition, if relevant parent := p.bc.GetHeaderByHash(header.ParentHash) + statedb.Database().EndVerkleTransition(parent.Root) if err := OverlayVerkleTransition(statedb, parent.Root); err != nil { return nil, nil, 0, fmt.Errorf("error performing verkle overlay transition: %w", err) } + statedb.Database().EndVerkleTransition(header.Root) + // This one is added because otherwise the transition will never be marked + // as such, which is a big problem in testnets who didn't do the transiton + // I'm only doing this so that the test pass. // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), withdrawals)