mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-08 07:58:40 +00:00
core, miner: bootstrap the binary transition registry on the first UBT block
Add `core/transition_registry.go` with two helpers:
- `InitializeBinaryTransitionRegistry` deploys the system contract at
`params.BinaryTransitionRegistryAddress`. The contract's bytecode
returns the storage slot indexed by the call's CALLDATA, exposing
the transition state to off-chain readers.
- `WriteBinaryTransitionBaseRoot` writes the frozen MPT base root into
slot 5. The slot constant is kept private so callers go through this
helper.
Wire both calls into the three places that build state for a new block:
- `core/state_processor.go`: in `Process`, after the EIP-2935 system
call, when the current block is on UBT and the parent is not.
- `miner/worker.go`: at the end of `prepareWork`, with the same
fork-boundary check, so locally-built payloads also seed the
registry.
- `core/chain_makers.go`: in `GenerateChain`, between the EIP-2935
handling and the user-supplied `gen` callback, so generated test
chains see the registry deployed identically to a live chain.
This commit is contained in:
parent
40c29ad53a
commit
58518ea2b3
4 changed files with 87 additions and 0 deletions
|
|
@ -399,6 +399,13 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
ProcessParentBlockHash(b.header.ParentHash, evm)
|
ProcessParentBlockHash(b.header.ParentHash, evm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On the first UBT block, deploy the binary transition registry and
|
||||||
|
// record the parent's MPT root as the frozen base root.
|
||||||
|
if config.IsUBT(b.header.Number, b.header.Time) && !config.IsUBT(parent.Number(), parent.Time()) {
|
||||||
|
InitializeBinaryTransitionRegistry(statedb)
|
||||||
|
WriteBinaryTransitionBaseRoot(statedb, parent.Root())
|
||||||
|
}
|
||||||
|
|
||||||
// Execute any user modifications to the block
|
// Execute any user modifications to the block
|
||||||
if gen != nil {
|
if gen != nil {
|
||||||
gen(i, b)
|
gen(i, b)
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,17 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated
|
||||||
if config.IsPrague(block.Number(), block.Time()) || config.IsUBT(block.Number(), block.Time()) {
|
if config.IsPrague(block.Number(), block.Time()) || config.IsUBT(block.Number(), block.Time()) {
|
||||||
ProcessParentBlockHash(block.ParentHash(), evm)
|
ProcessParentBlockHash(block.ParentHash(), evm)
|
||||||
}
|
}
|
||||||
|
// On the first block after the UBT activation, deploy the binary
|
||||||
|
// transition registry system contract and capture the frozen MPT base
|
||||||
|
// root in slot 5. The registry is what every subsequent block reads to
|
||||||
|
// reconstruct the transition state.
|
||||||
|
if config.IsUBT(block.Number(), block.Time()) {
|
||||||
|
parent := p.chain.GetHeaderByHash(block.ParentHash())
|
||||||
|
if parent != nil && !config.IsUBT(parent.Number, parent.Time) {
|
||||||
|
InitializeBinaryTransitionRegistry(statedb)
|
||||||
|
WriteBinaryTransitionBaseRoot(statedb, parent.Root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over and process the individual transactions
|
// Iterate over and process the individual transactions
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
|
|
|
||||||
62
core/transition_registry.go
Normal file
62
core/transition_registry.go
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// transitionStatusByteCode is a minimal contract that returns a single 32-byte
|
||||||
|
// storage slot to the caller. CALLDATALOAD picks the slot index from the call
|
||||||
|
// input and SLOAD reads the value, which is then returned as a 32-byte word.
|
||||||
|
var transitionStatusByteCode = []byte{
|
||||||
|
0x60, 0x00, // PUSH1 0
|
||||||
|
0x35, // CALLDATALOAD (slot index)
|
||||||
|
0x54, // SLOAD
|
||||||
|
0x60, 0x00, // PUSH1 0
|
||||||
|
0x52, // MSTORE
|
||||||
|
0x60, 0x20, // PUSH1 32
|
||||||
|
0x60, 0x00, // PUSH1 0
|
||||||
|
0xf3, // RETURN
|
||||||
|
}
|
||||||
|
|
||||||
|
// transitionRegistryBaseRootSlot is slot 5 of the transition registry, where
|
||||||
|
// the frozen MPT base root is stored. The slot indices match those decoded by
|
||||||
|
// overlay.LoadTransitionState; the layout is intentionally kept private to
|
||||||
|
// the core package so external callers go through these helpers.
|
||||||
|
var transitionRegistryBaseRootSlot = common.BytesToHash([]byte{5})
|
||||||
|
|
||||||
|
// InitializeBinaryTransitionRegistry deploys the binary transition registry
|
||||||
|
// system contract and marks the transition as started by writing 1 into slot
|
||||||
|
// 0. It must be called exactly once, on the first block after the UBT
|
||||||
|
// activation.
|
||||||
|
func InitializeBinaryTransitionRegistry(statedb *state.StateDB) {
|
||||||
|
statedb.SetCode(params.BinaryTransitionRegistryAddress, transitionStatusByteCode, tracing.CodeChangeUnspecified)
|
||||||
|
statedb.SetNonce(params.BinaryTransitionRegistryAddress, 1, tracing.NonceChangeUnspecified)
|
||||||
|
statedb.SetState(params.BinaryTransitionRegistryAddress, common.Hash{}, common.Hash{1})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteBinaryTransitionBaseRoot records the frozen MPT base root in slot 5 of
|
||||||
|
// the transition registry. This must be called on the first UBT block, right
|
||||||
|
// after InitializeBinaryTransitionRegistry, with the parent block's state
|
||||||
|
// root.
|
||||||
|
func WriteBinaryTransitionBaseRoot(statedb *state.StateDB, baseRoot common.Hash) {
|
||||||
|
statedb.SetState(params.BinaryTransitionRegistryAddress, transitionRegistryBaseRootSlot, baseRoot)
|
||||||
|
}
|
||||||
|
|
@ -332,6 +332,13 @@ func (miner *Miner) prepareWork(ctx context.Context, genParams *generateParams,
|
||||||
if miner.chainConfig.IsPrague(header.Number, header.Time) {
|
if miner.chainConfig.IsPrague(header.Number, header.Time) {
|
||||||
core.ProcessParentBlockHash(header.ParentHash, env.evm)
|
core.ProcessParentBlockHash(header.ParentHash, env.evm)
|
||||||
}
|
}
|
||||||
|
// Deploy the binary transition registry on the first UBT block and seed
|
||||||
|
// it with the parent's MPT root. Subsequent blocks read the registry to
|
||||||
|
// reconstruct the transition state.
|
||||||
|
if miner.chainConfig.IsUBT(header.Number, header.Time) && !miner.chainConfig.IsUBT(parent.Number, parent.Time) {
|
||||||
|
core.InitializeBinaryTransitionRegistry(env.state)
|
||||||
|
core.WriteBinaryTransitionBaseRoot(env.state, parent.Root)
|
||||||
|
}
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue