core, beacon: add blockAccessList into executionData

This commit is contained in:
Gary Rong 2026-05-18 09:21:18 +08:00
parent 2169065ba6
commit 285a13c43d
4 changed files with 100 additions and 90 deletions

View file

@ -10,6 +10,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types/bal"
) )
var _ = (*executableDataMarshaling)(nil) var _ = (*executableDataMarshaling)(nil)
@ -35,7 +36,7 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
SlotNumber *hexutil.Uint64 `json:"slotNumber,omitempty"` SlotNumber *hexutil.Uint64 `json:"slotNumber,omitempty"`
BlockAccessListHash *common.Hash `json:"blockAccessListHash,omitempty"` BlockAccessList *bal.BlockAccessList `json:"blockAccessList,omitempty"`
} }
var enc ExecutableData var enc ExecutableData
enc.ParentHash = e.ParentHash enc.ParentHash = e.ParentHash
@ -61,7 +62,7 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed) enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas) enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
enc.SlotNumber = (*hexutil.Uint64)(e.SlotNumber) enc.SlotNumber = (*hexutil.Uint64)(e.SlotNumber)
enc.BlockAccessListHash = e.BlockAccessListHash enc.BlockAccessList = e.BlockAccessList
return json.Marshal(&enc) return json.Marshal(&enc)
} }
@ -86,7 +87,7 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
SlotNumber *hexutil.Uint64 `json:"slotNumber,omitempty"` SlotNumber *hexutil.Uint64 `json:"slotNumber,omitempty"`
BlockAccessListHash *common.Hash `json:"blockAccessListHash,omitempty"` BlockAccessList *bal.BlockAccessList `json:"blockAccessList,omitempty"`
} }
var dec ExecutableData var dec ExecutableData
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
@ -163,8 +164,8 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
if dec.SlotNumber != nil { if dec.SlotNumber != nil {
e.SlotNumber = (*uint64)(dec.SlotNumber) e.SlotNumber = (*uint64)(dec.SlotNumber)
} }
if dec.BlockAccessListHash != nil { if dec.BlockAccessList != nil {
e.BlockAccessListHash = dec.BlockAccessListHash e.BlockAccessList = dec.BlockAccessList
} }
return nil return nil
} }

View file

@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types/bal"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
) )
@ -100,7 +101,7 @@ type ExecutableData struct {
BlobGasUsed *uint64 `json:"blobGasUsed"` BlobGasUsed *uint64 `json:"blobGasUsed"`
ExcessBlobGas *uint64 `json:"excessBlobGas"` ExcessBlobGas *uint64 `json:"excessBlobGas"`
SlotNumber *uint64 `json:"slotNumber,omitempty"` SlotNumber *uint64 `json:"slotNumber,omitempty"`
BlockAccessListHash *common.Hash `json:"blockAccessListHash,omitempty"` BlockAccessList *bal.BlockAccessList `json:"blockAccessList,omitempty"`
} }
// JSON type overrides for executableData. // JSON type overrides for executableData.
@ -304,6 +305,16 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
requestsHash = &h requestsHash = &h
} }
// If Amsterdam is enabled, data.BlockAccessList is always non-nil,
// even for empty blocks with no state transitions.
//
// If Amsterdam is not enabled yet, blockAccessListHash is expected
// to be nil.
var blockAccessListHash *common.Hash
if data.BlockAccessList != nil {
hash := data.BlockAccessList.Hash()
blockAccessListHash = &hash
}
header := &types.Header{ header := &types.Header{
ParentHash: data.ParentHash, ParentHash: data.ParentHash,
UncleHash: types.EmptyUncleHash, UncleHash: types.EmptyUncleHash,
@ -326,11 +337,9 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
ParentBeaconRoot: beaconRoot, ParentBeaconRoot: beaconRoot,
RequestsHash: requestsHash, RequestsHash: requestsHash,
SlotNumber: data.SlotNumber, SlotNumber: data.SlotNumber,
BlockAccessListHash: data.BlockAccessListHash, BlockAccessListHash: blockAccessListHash,
} }
return types.NewBlockWithHeader(header). return types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}), nil
WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}),
nil
} }
// BlockToExecutableData constructs the ExecutableData structure by filling the // BlockToExecutableData constructs the ExecutableData structure by filling the
@ -355,7 +364,7 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
BlobGasUsed: block.BlobGasUsed(), BlobGasUsed: block.BlobGasUsed(),
ExcessBlobGas: block.ExcessBlobGas(), ExcessBlobGas: block.ExcessBlobGas(),
SlotNumber: block.SlotNumber(), SlotNumber: block.SlotNumber(),
BlockAccessListHash: block.BlockAccessListHash(), BlockAccessList: block.AccessList(),
} }
// Add blobs. // Add blobs.

View file

@ -92,11 +92,11 @@ func (e *BlockAccessList) Validate() error {
return nil return nil
} }
// ItemCount returns the number of items in the BAL for EIP-7928 size-constraint // itemCount returns the number of items in the BAL for EIP-7928 size-constraint
// purposes: the count of distinct addresses plus every storage key (writes + // purposes: the count of distinct addresses plus every storage key (writes +
// reads) carried by those accounts. A storage slot is counted once regardless // reads) carried by those accounts. A storage slot is counted once regardless
// of how many transactions wrote to it. // of how many transactions wrote to it.
func (e *BlockAccessList) ItemCount() uint64 { func (e *BlockAccessList) itemCount() uint64 {
count := uint64(len(*e)) // distinct addresses count := uint64(len(*e)) // distinct addresses
for i := range *e { for i := range *e {
count += uint64(len((*e)[i].StorageWrites)) + uint64(len((*e)[i].StorageReads)) count += uint64(len((*e)[i].StorageWrites)) + uint64(len((*e)[i].StorageReads))
@ -107,9 +107,9 @@ func (e *BlockAccessList) ItemCount() uint64 {
// ValidateSize returns an error if the BAL violates the EIP-7928 size // ValidateSize returns an error if the BAL violates the EIP-7928 size
// constraint for the given block gas limit: // constraint for the given block gas limit:
// //
// ItemCount() <= blockGasLimit / params.BALItemCost // itemCount() <= blockGasLimit / params.BALItemCost
func (e *BlockAccessList) ValidateSize(blockGasLimit uint64) error { func (e *BlockAccessList) ValidateSize(blockGasLimit uint64) error {
items := e.ItemCount() items := e.itemCount()
limit := blockGasLimit / params.BALItemCost limit := blockGasLimit / params.BALItemCost
if items > limit { if items > limit {
return fmt.Errorf("block access list exceeds size constraint: items=%d, limit=%d (block gas limit %d / %d)", return fmt.Errorf("block access list exceeds size constraint: items=%d, limit=%d (block gas limit %d / %d)",

View file

@ -284,7 +284,7 @@ func TestBlockAccessListCopy(t *testing.T) {
func TestBlockAccessListItemCount(t *testing.T) { func TestBlockAccessListItemCount(t *testing.T) {
empty := &BlockAccessList{} empty := &BlockAccessList{}
if got := empty.ItemCount(); got != 0 { if got := empty.itemCount(); got != 0 {
t.Fatalf("empty BAL item count: got %d, want 0", got) t.Fatalf("empty BAL item count: got %d, want 0", got)
} }
@ -304,7 +304,7 @@ func TestBlockAccessListItemCount(t *testing.T) {
} }
// 2 addresses + 2 write-slots + 1 read-slot = 5 items. // 2 addresses + 2 write-slots + 1 read-slot = 5 items.
// (Multiple TxIdx writes to the same slot count as ONE item.) // (Multiple TxIdx writes to the same slot count as ONE item.)
if got := bal.ItemCount(); got != 5 { if got := bal.itemCount(); got != 5 {
t.Fatalf("item count: got %d, want 5", got) t.Fatalf("item count: got %d, want 5", got)
} }
} }
@ -325,7 +325,7 @@ func TestBlockAccessListValidateSize(t *testing.T) {
bal[i].StorageReads = append(bal[i].StorageReads, one()) bal[i].StorageReads = append(bal[i].StorageReads, one())
} }
} }
if got := bal.ItemCount(); got != 30 { if got := bal.itemCount(); got != 30 {
t.Fatalf("setup: item count = %d, want 30", got) t.Fatalf("setup: item count = %d, want 30", got)
} }