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
4 changes: 2 additions & 2 deletions cmd/evm/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ func runCmd(ctx *cli.Context) error {
input = append(code, input...)
execFunc = func() ([]byte, uint64, error) {
// don't mutate the state!
runtimeConfig.State = prestate.Copy()
runtimeConfig.State = prestate.Copy().(*state.StateDB)
output, _, gasLeft, err := runtime.Create(input, &runtimeConfig)
return output, gasLeft, err
}
Expand All @@ -326,7 +326,7 @@ func runCmd(ctx *cli.Context) error {
}
execFunc = func() ([]byte, uint64, error) {
// don't mutate the state!
runtimeConfig.State = prestate.Copy()
runtimeConfig.State = prestate.Copy().(*state.StateDB)
output, gasLeft, err := runtime.Call(receiver, input, &runtimeConfig)
return output, initialGas - gasLeft, err
}
Expand Down
1 change: 1 addition & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ var (
utils.BeaconGenesisTimeFlag,
utils.BeaconCheckpointFlag,
utils.BeaconCheckpointFileFlag,
utils.ExperimentalBALFlag,
}, utils.NetworkFlags, utils.DatabaseFlags)

rpcFlags = []cli.Flag{
Expand Down
11 changes: 11 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,14 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
Value: metrics.DefaultConfig.InfluxDBOrganization,
Category: flags.MetricsCategory,
}

// Block Access List flags

ExperimentalBALFlag = &cli.BoolFlag{
Name: "experimentalbal",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--experimental.bal ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sgtm

Usage: "Enable block-access-list building when importing post-Cancun blocks, and validation that access lists contained in post-Cancun blocks correctly correspond to the state changes in those blocks. This is used for development purposes only. Do not enable it otherwise.",
Category: flags.MiscCategory,
}
)

var (
Expand Down Expand Up @@ -1861,6 +1869,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
cfg.VMTraceJsonConfig = ctx.String(VMTraceJsonConfigFlag.Name)
}
}

cfg.ExperimentalBAL = ctx.Bool(ExperimentalBALFlag.Name)
}

// MakeBeaconLightConfig constructs a beacon light client config based on the
Expand Down Expand Up @@ -2256,6 +2266,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
}
options.VmConfig = vmcfg

options.EnableBAL = ctx.Bool(ExperimentalBALFlag.Name)
chain, err := core.NewBlockChain(chainDb, gspec, engine, options)
if err != nil {
Fatalf("Can't create BlockChain: %v", err)
Expand Down
24 changes: 15 additions & 9 deletions consensus/beacon/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ import (
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/holiman/uint256"
Expand Down Expand Up @@ -353,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, st state.BlockProcessingDB, 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, st, body, receipts)
}
shanghai := chain.Config().IsShanghai(header.Number, header.Time)
if shanghai {
Expand All @@ -369,29 +370,34 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
}
}
// Finalize and assemble the block.
beacon.Finalize(chain, header, state, body)
beacon.Finalize(chain, header, st, body)

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

// embed the block access list in the body
if chain.Config().IsAmsterdam(header.Number, header.Time) {
body.AccessList = st.(*state.AccessListCreationDB).ConstructedBlockAccessList().ToEncodingObj()
}

// 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 := st.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 := st.Database().OpenTrie(parent.Root)
if err != nil {
return nil, fmt.Errorf("error opening pre-state tree root: %w", err)
}
postTrie := state.GetTrie()
postTrie := st.GetTrie()
if postTrie == nil {
return nil, errors.New("post-state tree is not available")
}
Expand Down
2 changes: 1 addition & 1 deletion consensus/clique/clique.go
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Heade

// FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
// nor block rewards given, and returns the final block.
func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state state.BlockProcessingDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
if len(body.Withdrawals) > 0 {
return nil, errors.New("clique does not support withdrawals")
}
Expand Down
7 changes: 4 additions & 3 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ package consensus
import (
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)

Expand Down Expand Up @@ -92,7 +93,7 @@ type Engine interface {
//
// Note: The block header and state database might be updated to reflect any
// consensus rules that happen at finalization (e.g. block rewards).
FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error)
FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state state.BlockProcessingDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error)

// Seal generates a new sealing request for the given input block and pushes
// the result into the given channel.
Expand Down
2 changes: 1 addition & 1 deletion consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.

// FinalizeAndAssemble implements consensus.Engine, accumulating the block and
// uncle rewards, setting the final state and assembling the block.
func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state state.BlockProcessingDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
if len(body.Withdrawals) > 0 {
return nil, errors.New("ethash does not support withdrawals")
}
Expand Down
28 changes: 27 additions & 1 deletion core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,31 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
}
}

// block access lists must be present after the Amsterdam hard fork
if v.config.IsAmsterdam(block.Number(), block.Time()) {
if block.Body().AccessList == nil {
return fmt.Errorf("access list not present in block body")
} else if block.Header().BlockAccessListHash == nil {
return fmt.Errorf("access list hash not present in block header")
} else if *block.Header().BlockAccessListHash != block.Body().AccessList.Hash() {
return fmt.Errorf("access list hash mismatch. local: %x. remote: %x\n", block.Body().AccessList.Hash(), *block.Header().BlockAccessListHash)
}
} else if !v.bc.cfg.EnableBAL {
// if --experimental-bal is not enabled, block headers cannot have access list hash and bodies cannot have access lists.
if block.Body().AccessList != nil {
return fmt.Errorf("access list not allowed in block body if not in amsterdam or --experimental-bal is set")
} else if block.Header().BlockAccessListHash != nil {
return fmt.Errorf("access list hash in block header not allowed when --experimental-bal is set")
}
} else {
// if --experimental-bal is enabled, the BAL hash is not allowed in the header.
// this is in order that Geth can import pre-existing chains augmented with BALs
// and not have a hash mismatch.
if block.Header().BlockAccessListHash != nil {
return fmt.Errorf("access list hash in block header not allowed pre-amsterdam")
}
}

// Ancestor block must be known.
if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
Expand All @@ -123,7 +148,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {

// ValidateState validates the various changes that happen after a state transition,
// such as amount of used gas, the receipt roots and the state root itself.
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) error {
func (v *BlockValidator) ValidateState(block *types.Block, statedb state.BlockProcessingDB, res *ProcessResult, stateless bool) error {
if res == nil {
return errors.New("nil ProcessResult value")
}
Expand Down Expand Up @@ -160,6 +185,7 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
} else if res.Requests != nil {
return errors.New("block has requests before prague fork")
}

// Validate the state root against the received state root and throw
// an error if they don't match.
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
Expand Down
37 changes: 33 additions & 4 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ type BlockChainConfig struct {
// If the value is -1, indexing is disabled.
TxLookupLimit int64

// EnableBAL enables block access list creation and verification for post-Cancun blocks which contain access lists.
EnableBAL bool

// StateSizeTracking indicates whether the state size tracking is enabled.
StateSizeTracking bool
}
Expand Down Expand Up @@ -1905,9 +1908,17 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
if parent == nil {
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
}

// construct or verify block access lists if BALs are enabled and
// we are post-selfdestruct removal fork.
enableBAL := (bc.cfg.EnableBAL && bc.chainConfig.IsCancun(block.Number(), block.Time())) || bc.chainConfig.IsAmsterdam(block.Number(), block.Time())
blockHasAccessList := block.Body().AccessList != nil
makeBAL := enableBAL && !blockHasAccessList
validateBAL := enableBAL && blockHasAccessList

// The traced section of block import.
start := time.Now()
res, err := bc.processBlock(parent.Root, block, setHead, makeWitness && len(chain) == 1)
res, err := bc.processBlock(parent.Root, block, setHead, makeWitness && len(chain) == 1, makeBAL, validateBAL)
if err != nil {
return nil, it.index, err
}
Expand Down Expand Up @@ -1975,7 +1986,7 @@ type blockProcessingResult struct {

// processBlock executes and validates the given block. If there was no error
// it writes the block and associated state to database.
func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, setHead bool, makeWitness bool) (_ *blockProcessingResult, blockEndErr error) {
func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, setHead bool, makeWitness bool, constructBALForTesting bool, validateBAL bool) (bpr *blockProcessingResult, blockEndErr error) {
var (
err error
startTime = time.Now()
Expand Down Expand Up @@ -2034,6 +2045,9 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
}(time.Now(), throwaway, block)
}

if constructBALForTesting {
statedb.EnableStateDiffRecording()
}
// If we are past Byzantium, enable prefetching to pull in trie node paths
// while processing transactions. Before Byzantium the prefetcher is mostly
// useless due to the intermediate root hashing after each transaction.
Expand Down Expand Up @@ -2071,22 +2085,37 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
}()
}

// Process block using the parent state as reference point
var sdb state.BlockProcessingDB = statedb
if constructBALForTesting {
sdb = state.NewBlockAccessListBuilder(statedb)
}
// Process block using the parent state as reference point
pstart := time.Now()
res, err := bc.processor.Process(block, statedb, bc.cfg.VmConfig)
res, err := bc.processor.Process(block, sdb, bc.cfg.VmConfig)
if err != nil {
bc.reportBlock(block, res, err)
return nil, err
}
ptime := time.Since(pstart)

vstart := time.Now()
if err := bc.validator.ValidateState(block, statedb, res, false); err != nil {
if err := bc.validator.ValidateState(block, sdb, res, false); err != nil {
bc.reportBlock(block, res, err)
return nil, err
}
vtime := time.Since(vstart)

if constructBALForTesting {
// very ugly... deep-copy the block body before setting the block access
// list on it to prevent mutating the block instance passed by the caller.
existingBody := block.Body()
block = block.WithBody(*existingBody)
existingBody = block.Body()
existingBody.AccessList = sdb.(*state.AccessListCreationDB).ConstructedBlockAccessList().ToEncodingObj()
block = block.WithBody(*existingBody)
}

// If witnesses was generated and stateless self-validation requested, do
// that now. Self validation should *never* run in production, it's more of
// a tight integration to enable running *all* consensus tests through the
Expand Down
2 changes: 1 addition & 1 deletion core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ func (b *BlockGen) collectRequests(readonly bool) (requests [][]byte) {
// The system contracts clear themselves on a system-initiated read.
// When reading the requests mid-block, we don't want this behavior, so fork
// off the statedb before executing the system calls.
statedb = statedb.Copy()
statedb = statedb.Copy().(*state.StateDB)
}

if b.cm.config.IsPrague(b.header.Number, b.header.Time) {
Expand Down
39 changes: 21 additions & 18 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,13 @@ type Genesis struct {

// These fields are used for consensus tests. Please don't use them
// in actual genesis blocks.
Number uint64 `json:"number"`
GasUsed uint64 `json:"gasUsed"`
ParentHash common.Hash `json:"parentHash"`
BaseFee *big.Int `json:"baseFeePerGas"` // EIP-1559
ExcessBlobGas *uint64 `json:"excessBlobGas"` // EIP-4844
BlobGasUsed *uint64 `json:"blobGasUsed"` // EIP-4844
Number uint64 `json:"number"`
GasUsed uint64 `json:"gasUsed"`
ParentHash common.Hash `json:"parentHash"`
BaseFee *big.Int `json:"baseFeePerGas"` // EIP-1559
ExcessBlobGas *uint64 `json:"excessBlobGas"` // EIP-4844
BlobGasUsed *uint64 `json:"blobGasUsed"` // EIP-4844
BlockAccessListHash *common.Hash `json:"blockAccessListHash,omitempty"` // EIP-7928
}

// copy copies the genesis.
Expand Down Expand Up @@ -122,6 +123,7 @@ func ReadGenesis(db ethdb.Database) (*Genesis, error) {
genesis.BaseFee = genesisHeader.BaseFee
genesis.ExcessBlobGas = genesisHeader.ExcessBlobGas
genesis.BlobGasUsed = genesisHeader.BlobGasUsed
genesis.BlockAccessListHash = genesisHeader.BlockAccessListHash

return &genesis, nil
}
Expand Down Expand Up @@ -461,18 +463,19 @@ func (g *Genesis) ToBlock() *types.Block {
// toBlockWithRoot constructs the genesis block with the given genesis state root.
func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
head := &types.Header{
Number: new(big.Int).SetUint64(g.Number),
Nonce: types.EncodeNonce(g.Nonce),
Time: g.Timestamp,
ParentHash: g.ParentHash,
Extra: g.ExtraData,
GasLimit: g.GasLimit,
GasUsed: g.GasUsed,
BaseFee: g.BaseFee,
Difficulty: g.Difficulty,
MixDigest: g.Mixhash,
Coinbase: g.Coinbase,
Root: root,
Number: new(big.Int).SetUint64(g.Number),
Nonce: types.EncodeNonce(g.Nonce),
Time: g.Timestamp,
ParentHash: g.ParentHash,
Extra: g.ExtraData,
GasLimit: g.GasLimit,
GasUsed: g.GasUsed,
BaseFee: g.BaseFee,
Difficulty: g.Difficulty,
MixDigest: g.Mixhash,
Coinbase: g.Coinbase,
BlockAccessListHash: g.BlockAccessListHash,
Root: root,
}
if g.GasLimit == 0 {
head.GasLimit = params.GenesisGasLimit
Expand Down
Loading
Loading