From 9a5140a5902dc9704411102f1e15df6d4a7feb7c Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 30 Apr 2026 14:31:38 +0200 Subject: [PATCH] self-review --- core/blockchain.go | 26 ++++++++++++++++---------- core/blockchain_reader.go | 12 ++++++++++-- core/overlay/state_transition.go | 26 +++++++++++++++++--------- core/rawdb/schema.go | 1 - core/state/database_ubt.go | 8 ++------ core/state/reader.go | 6 +++++- params/config.go | 19 +++---------------- params/protocol_params.go | 8 +------- 8 files changed, 54 insertions(+), 52 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index ce3efe9426..882fb86927 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2149,18 +2149,18 @@ type ExecuteConfig struct { // transition, a transition UBTDatabase is built; otherwise (transition // ended, or chainConfig.UBTTransitionEndTime crossed) a plain UBTDatabase // is returned with the transition wrap disabled. -func (bc *BlockChain) stateDatabase(parentRoot common.Hash, header *types.Header) state.Database { +func (bc *BlockChain) stateDatabase(parentRoot common.Hash, header *types.Header) (state.Database, error) { if !bc.chainConfig.IsUBT(header.Number, header.Time) { - return state.NewMPTDatabase(bc.triedb, bc.codedb).WithSnapshot(bc.snaps) + return state.NewMPTDatabase(bc.triedb, bc.codedb).WithSnapshot(bc.snaps), nil } // Past the configured transition end: pure binary, no wrap, no MPT base. if !bc.chainConfig.UBTTransitionActive(header.Number, header.Time) { - return state.NewUBTDatabase(bc.bintriedbOrMain(), bc.codedb).WithTransitionTreeWrap(false) + return state.NewUBTDatabase(bc.bintriedbOrMain(), bc.codedb).WithTransitionTreeWrap(false), nil } // First UBT block: parent is pre-UBT; seed the transition with parent root. parent := bc.GetHeaderByHash(header.ParentHash) if parent != nil && !bc.chainConfig.IsUBT(parent.Number, parent.Time) { - return state.NewTransitionUBTDatabase(bc.bintriedbOrMain(), bc.triedb, bc.codedb, parentRoot) + return state.NewTransitionUBTDatabase(bc.bintriedbOrMain(), bc.triedb, bc.codedb, parentRoot), nil } // Subsequent UBT block while the transition is active: probe the registry // to see whether a base root is still recorded. @@ -2180,18 +2180,21 @@ func (bc *BlockChain) bintriedbOrMain() *triedb.Database { // probeTransitionDatabase reads the transition registry from the binary trie // at the given root and chooses between a transition-mode UBTDatabase (if // the registry still records a base root) and a plain UBTDatabase otherwise. -func (bc *BlockChain) probeTransitionDatabase(root common.Hash) state.Database { +func (bc *BlockChain) probeTransitionDatabase(root common.Hash) (state.Database, error) { bindb := bc.bintriedbOrMain() plain := state.NewUBTDatabase(bindb, bc.codedb) reader, err := plain.StateReader(root) if err != nil { - return plain + return nil, err + } + ts, err := overlay.LoadTransitionState(storageReaderFunc(reader.Storage)) + if err != nil { + return nil, err } - ts := overlay.LoadTransitionState(storageReaderFunc(reader.Storage), root) if ts == nil || ts.Transitioned() || ts.BaseRoot == (common.Hash{}) { - return plain + return plain, nil } - return state.NewTransitionUBTDatabase(bindb, bc.triedb, bc.codedb, ts.BaseRoot) + return state.NewTransitionUBTDatabase(bindb, bc.triedb, bc.codedb, ts.BaseRoot), nil } // storageReaderFunc adapts a state-reader Storage method to overlay.StorageReader. @@ -2212,7 +2215,10 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash, ) defer interrupt.Store(true) // terminate the prefetch at the end - sdb := bc.stateDatabase(parentRoot, block.Header()) + sdb, err := bc.stateDatabase(parentRoot, block.Header()) + if err != nil { + return nil, err + } // If prefetching is enabled, run that against the current state to pre-cache // transactions and probabilistically some of the account/storage trie nodes. // diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 4dd04b24c4..c9c6671b39 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -421,13 +421,21 @@ func (bc *BlockChain) State() (*state.StateDB, error) { // StateAt returns a new mutable state based on a particular point in time. func (bc *BlockChain) StateAt(header *types.Header) (*state.StateDB, error) { - return state.New(header.Root, bc.stateDatabase(header.Root, header)) + db, err := bc.stateDatabase(header.Root, header) + if err != nil { + return nil, err + } + return state.New(header.Root, db) } // StateAtForkBoundary returns a new mutable state based on the parent state // and the given header, handling the transition across the UBT fork. func (bc *BlockChain) StateAtForkBoundary(parent *types.Header, header *types.Header) (*state.StateDB, error) { - return state.New(parent.Root, bc.stateDatabase(parent.Root, header)) + db, err := bc.stateDatabase(parent.Root, header) + if err != nil { + return nil, err + } + return state.New(parent.Root, db) } // HistoricState returns a historic state specified by the given header. diff --git a/core/overlay/state_transition.go b/core/overlay/state_transition.go index 356c77b794..2976a0fda2 100644 --- a/core/overlay/state_transition.go +++ b/core/overlay/state_transition.go @@ -39,9 +39,8 @@ type StorageReader interface { Storage(addr common.Address, slot common.Hash) (common.Hash, error) } -// TransitionState holds the progress markers of the MPT-to-binary -// translation process. It is reconstructed on demand from the storage of the -// binary transition registry system contract. +// TransitionState is a structure that holds the progress markers of the +// translation process. type TransitionState struct { CurrentAccountAddress *common.Address // address of the last translated account CurrentSlotHash common.Hash // hash of the last translated storage slot @@ -98,10 +97,13 @@ func IsTransitionActive(reader StorageReader) bool { // // The root parameter is unused; it is retained on the signature so callers // can express the state version they intend to read. -func LoadTransitionState(reader StorageReader, root common.Hash) *TransitionState { +func LoadTransitionState(reader StorageReader) (*TransitionState, error) { started, err := reader.Storage(params.BinaryTransitionRegistryAddress, transitionStartedKey) - if err != nil || started == (common.Hash{}) { - return nil + if err != nil { + return nil, err + } + if started == (common.Hash{}) { + return nil, nil } ended, _ := reader.Storage(params.BinaryTransitionRegistryAddress, transitionEndedKey) @@ -114,8 +116,14 @@ func LoadTransitionState(reader StorageReader, root common.Hash) *TransitionStat currentAddr = &addr } - slotHash, _ := reader.Storage(params.BinaryTransitionRegistryAddress, conversionProgressSlotKey) - storageProcessed, _ := reader.Storage(params.BinaryTransitionRegistryAddress, conversionProgressStorageProcessed) + slotHash, err := reader.Storage(params.BinaryTransitionRegistryAddress, conversionProgressSlotKey) + if err != nil { + return nil, err + } + storageProcessed, err := reader.Storage(params.BinaryTransitionRegistryAddress, conversionProgressStorageProcessed) + if err != nil { + return nil, err + } return &TransitionState{ Started: true, @@ -124,5 +132,5 @@ func LoadTransitionState(reader StorageReader, root common.Hash) *TransitionStat CurrentAccountAddress: currentAddr, CurrentSlotHash: slotHash, StorageProcessed: storageProcessed != (common.Hash{}), - } + }, nil } diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index d3f6944316..a5ebb961f7 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -457,4 +457,3 @@ func trienodeHistoryIndexBlockKey(addressHash common.Hash, path []byte, blockID return out } - diff --git a/core/state/database_ubt.go b/core/state/database_ubt.go index 437e2fdaf9..e17dd48b67 100644 --- a/core/state/database_ubt.go +++ b/core/state/database_ubt.go @@ -138,9 +138,7 @@ func (db *UBTDatabase) ReadersWithCacheStats(stateRoot common.Hash) (Reader, Rea return ra, rb, nil } -// OpenTrie opens the main account trie at a specific root hash. During an -// active transition, the binary trie is wrapped in a TransitionTrie so writes -// land on the binary trie while reads fall through to the frozen MPT base. +// OpenTrie opens the main account trie at a specific root hash. func (db *UBTDatabase) OpenTrie(root common.Hash) (Trie, error) { bt, err := bintrie.NewBinaryTrie(root, db.triedb) if err != nil { @@ -157,9 +155,7 @@ func (db *UBTDatabase) OpenTrie(root common.Hash) (Trie, error) { } // OpenStorageTrie opens the storage trie of an account. In binary trie mode -// the unified trie carries all state, so the main trie is reused. During the -// transition, an MPT storage trie is opened for accounts that have not yet -// been migrated. +// the unified trie carries all state, so the main trie is reused. func (db *UBTDatabase) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, self Trie) (Trie, error) { if self != nil && self.IsUBT() { return self, nil diff --git a/core/state/reader.go b/core/state/reader.go index 7b8ff35ac1..140dbc3b60 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -288,7 +288,11 @@ func newUBTTrieReader(root common.Hash, bindb *triedb.Database, mptdb *triedb.Da } var base *trie.StateTrie if wrapInTransitionTrie && mptdb != nil { - if ts := overlay.LoadTransitionState(&binTrieStorageReader{tr: binTrie}, root); ts != nil && ts.BaseRoot != (common.Hash{}) { + ts, err := overlay.LoadTransitionState(&binTrieStorageReader{tr: binTrie}) + if err != nil { + return nil, err + } + if ts != nil && ts.BaseRoot != (common.Hash{}) { base, err = trie.NewStateTrie(trie.StateTrieID(ts.BaseRoot), mptdb) if err != nil { return nil, err diff --git a/params/config.go b/params/config.go index 00752479d6..f02d239ad5 100644 --- a/params/config.go +++ b/params/config.go @@ -469,12 +469,8 @@ type ChainConfig struct { UBTTime *uint64 `json:"ubtTime,omitempty"` // UBT switch time (nil = no fork, 0 = already on UBT) // UBTTransitionEndTime is the timestamp at which the MPT-to-binary - // transition tree is no longer applied. While UBT is active and the - // timestamp is below this value (or nil), state access is wrapped in a - // TransitionTrie that overlays the binary trie on the frozen MPT base. - // Once headers reach this time, the transition wrapper is dropped and - // state is read directly from the binary trie. nil = wrapper stays on - // indefinitely. Mirrors the threshold semantics of TerminalTotalDifficulty. + // transition tree is no longer applied. Mirrors the threshold semantics + // of TerminalTotalDifficulty. UBTTransitionEndTime *uint64 `json:"ubtTransitionEndTime,omitempty"` // TerminalTotalDifficulty is the amount of total difficulty reached by @@ -897,16 +893,7 @@ func (c *ChainConfig) UBTTransitionActive(num *big.Int, time uint64) bool { return c.UBTTransitionEndTime == nil || time < *c.UBTTransitionEndTime } -// IsUBTGenesis checks whether the verkle fork is activated at the genesis block. -// -// Verkle mode is considered enabled if the verkle fork time is configured, -// regardless of whether the local time has surpassed the fork activation time. -// This is a temporary workaround for verkle devnet testing, where verkle 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. +// IsUBTGenesis checks whether the UBT fork is activated at the genesis block. func (c *ChainConfig) IsUBTGenesis() bool { return c.EnableUBTAtGenesis } diff --git a/params/protocol_params.go b/params/protocol_params.go index 831d05a3b9..44a8cc89c3 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -224,13 +224,7 @@ var ( ConsolidationQueueCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd") // BinaryTransitionRegistryAddress is the system contract that exposes the - // MPT-to-binary transition state via storage slots: - // slot 0 = transition started flag - // slot 1 = address of the last translated account - // slot 2 = hash of the last translated storage slot - // slot 3 = "storage processed" flag - // slot 4 = transition ended flag - // slot 5 = frozen MPT base root + // MPT-to-binary transition state via storage slots. BinaryTransitionRegistryAddress = common.HexToAddress("0x1622162216221622162216221622162216221622") )