diff --git a/beacon/engine/types.go b/beacon/engine/types.go index e12531fbac..826e02384c 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -307,11 +307,7 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H var blockAccessListHash *common.Hash body := types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals} - if data.BlockAccessList != nil { - body.AccessList = data.BlockAccessList - balHash := data.BlockAccessList.Hash() - blockAccessListHash = &balHash - } + header := &types.Header{ ParentHash: data.ParentHash, UncleHash: types.EmptyUncleHash, @@ -336,7 +332,16 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H BlockAccessListHash: blockAccessListHash, SlotNumber: data.SlotNumber, } + + if data.BlockAccessList != nil { + balHash := data.BlockAccessList.Hash() + header.BlockAccessListHash = &balHash + block := types.NewBlockWithHeader(header).WithBody(body).WithAccessList(data.BlockAccessList) + return block, nil + } + return types.NewBlockWithHeader(header).WithBody(body), nil + } // BlockToExecutableData constructs the ExecutableData structure by filling the @@ -360,6 +365,10 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types. Withdrawals: block.Withdrawals(), BlobGasUsed: block.BlobGasUsed(), ExcessBlobGas: block.ExcessBlobGas(), +<<<<<<< HEAD +======= + BlockAccessList: block.AccessList(), +>>>>>>> 959ade7689 (a bunch of changes. mostly bal persistence and removing bal from block body object. wip...) SlotNumber: block.SlotNumber(), BlockAccessList: block.Body().AccessList, } diff --git a/build/checksums.txt b/build/checksums.txt index fdf4453ec5..49a449f539 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,10 +5,10 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v5.1.0 a3192784375acec7eaec492799d5c5d0c47a2909a3cc40178898e4ecd20cc416 fixtures_develop.tar.gz -# version:spec-tests-bal v3.0.1 +# version:spec-tests-bal v5.0.0 # https://github.com/ethereum/execution-spec-tests/releases -# https://github.com/ethereum/execution-spec-tests/releases/download/bal%40v3.0.1 -57d0f109f0557ec33d6ecd6cbd77b55415a658aefe583c4035157e1021ae512a fixtures_bal.tar.gz +# https://github.com/ethereum/execution-spec-tests/releases/download/bal%40v5.0.0 +17aecf8334da7f5d1025635c763a4be0dfbcdb0e659cc70a36e6a81bd3af06f2 fixtures_bal.tar.gz # version:golang 1.25.1 # https://go.dev/dl/ diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 5cb637a81e..c458cbe21c 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -19,6 +19,7 @@ package beacon import ( "errors" "fmt" + "github.com/ethereum/go-ethereum/core/types/bal" "math/big" "github.com/ethereum/go-ethereum/common" @@ -357,9 +358,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, onFinalization func()) (*types.Block, error) { +func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, onFinalizeAccessList func() *bal.BlockAccessList) (*types.Block, error) { if !beacon.IsPoSHeader(header) { - return beacon.ethone.FinalizeAndAssemble(chain, header, state, body, receipts, onFinalization) + return beacon.ethone.FinalizeAndAssemble(chain, header, state, body, receipts, nil) } shanghai := chain.Config().IsShanghai(header.Number, header.Time) if shanghai { @@ -379,12 +380,15 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea // Assign the final state root to header. header.Root = state.IntermediateRoot(true) - if onFinalization != nil { - onFinalization() - } - // Assemble the final block. - return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil + if onFinalizeAccessList != nil { + al := onFinalizeAccessList() + alHash := al.Hash() + header.BlockAccessListHash = &alHash + return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)).WithAccessList(al), nil + } else { + return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil + } } // Seal generates a new sealing request for the given input block and pushes diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index e2127deba1..8935893761 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -21,6 +21,7 @@ import ( "bytes" "errors" "fmt" + "github.com/ethereum/go-ethereum/core/types/bal" "io" "math/big" "math/rand" @@ -581,7 +582,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, onFinalize func()) (*types.Block, error) { +func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, onFinalizeAccessList func() *bal.BlockAccessList) (*types.Block, error) { if len(body.Withdrawals) > 0 { return nil, errors.New("clique does not support withdrawals") } @@ -591,10 +592,9 @@ func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header * // Assign the final state root to header. header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) - if onFinalize != nil { - onFinalize() + if onFinalizeAccessList != nil { + panic("access list embedding not enabled for clique consensus") } - // Assemble and return the final block for sealing. return types.NewBlock(header, &types.Body{Transactions: body.Transactions}, receipts, trie.NewStackTrie(nil)), nil } diff --git a/consensus/consensus.go b/consensus/consensus.go index e1120af36d..0fadbf5e22 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -18,6 +18,7 @@ package consensus import ( + "github.com/ethereum/go-ethereum/core/types/bal" "math/big" "github.com/ethereum/go-ethereum/common" @@ -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, onFinalization func()) (*types.Block, error) + FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, onFinalizeAccessList func() *bal.BlockAccessList) (*types.Block, error) // Seal generates a new sealing request for the given input block and pushes // the result into the given channel. diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 8d125da692..ab7485b7d2 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -19,6 +19,7 @@ package ethash import ( "errors" "fmt" + "github.com/ethereum/go-ethereum/core/types/bal" "math/big" "time" @@ -513,7 +514,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, onFinalize func()) (*types.Block, error) { +func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, onFinalizeAccessList func() *bal.BlockAccessList) (*types.Block, error) { if len(body.Withdrawals) > 0 { return nil, errors.New("ethash does not support withdrawals") } @@ -523,8 +524,8 @@ func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea // Assign the final state root to header. header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) - if onFinalize != nil { - onFinalize() + if onFinalizeAccessList != nil { + panic("access list embedding not supported for ethash consenus") } // Header seems complete, assemble into a block and return return types.NewBlock(header, &types.Body{Transactions: body.Transactions, Uncles: body.Uncles}, receipts, trie.NewStackTrie(nil)), nil diff --git a/core/block_validator.go b/core/block_validator.go index b0f7d0ac0d..5707e940c4 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -116,10 +116,10 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // TODO: verify that this check isn't also done elsewhere return fmt.Errorf("block access list hash not set in header") } - if block.Body().AccessList != nil { - 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 err := block.Body().AccessList.Validate(len(block.Transactions())); err != nil { + if block.AccessList() != nil { + if *block.Header().BlockAccessListHash != block.AccessList().Hash() { + return fmt.Errorf("access list hash mismatch. local: %x. remote: %x\n", block.AccessList().Hash(), *block.Header().BlockAccessListHash) + } else if err := block.AccessList().Validate(len(block.Transactions())); err != nil { return fmt.Errorf("invalid block access list: %v", err) } } @@ -133,7 +133,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { } } else { // if experimental.bal is not enabled, block headers cannot have access list hash and bodies cannot have access lists. - if block.Body().AccessList != nil { + if block.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") diff --git a/core/blockchain.go b/core/blockchain.go index 80286a4ec0..2357faba01 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2201,7 +2201,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s } // TODO: need to check that the block is also postcancun if it contained an access list? // this should be checked during decoding (?) - blockHasAccessList := block.Body().AccessList != nil + blockHasAccessList := block.AccessList() != nil // only construct and embed BALs in the block if: // * it has been enabled for testing purposes (preAmsterdam/postCancun blocks with experimental.bal) // * we are after Amsterdam and the block was provided with bal omitted @@ -2276,7 +2276,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s // Disable tracing for prefetcher executions. vmCfg := bc.cfg.VmConfig vmCfg.Tracer = nil - if block.Body().AccessList == nil { + if block.AccessList() == nil { // only use the state prefetcher for non-BAL blocks. bc.prefetcher.Prefetch(block, throwaway, vmCfg, &interrupt) } @@ -2369,13 +2369,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s return nil, err } - // very ugly... deepcopy 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 = balTracer.AccessList().ToEncodingObj() - block = block.WithBody(*existingBody) + block = block.WithAccessList(balTracer.AccessList().ToEncodingObj()) } else if enableBALFork { computedAccessList := balTracer.AccessList().ToEncodingObj() @@ -2387,16 +2381,12 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s bc.reportBadBlock(block, res, err) return nil, err } - if block.Body().AccessList == nil { - // 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 = computedAccessList - block = block.WithBody(*existingBody) - } else if block.Body().AccessList.Hash() != computedAccessListHash { - err := fmt.Errorf("block access list hash mismatch (remote=%x computed=%x)", block.Body().AccessList.Hash(), computedAccessListHash) + if block.AccessList() == nil { + // attach the computed access list to the block so it gets persisted + // when the block is written to disk + block = block.WithAccessList(computedAccessList) + } else if block.AccessList().Hash() != computedAccessListHash { + err := fmt.Errorf("block access list hash mismatch (remote=%x computed=%x)", block.AccessList().Hash(), computedAccessListHash) bc.reportBadBlock(block, res, err) return nil, err } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 6ae64fb2fd..2d216cee77 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -20,6 +20,7 @@ import ( "bytes" "encoding/binary" "fmt" + "github.com/ethereum/go-ethereum/core/types/bal" "math/big" "slices" @@ -421,6 +422,17 @@ func WriteBodyRLP(db ethdb.KeyValueWriter, hash common.Hash, number uint64, rlp } } +func WriteAccessListRLP(db ethdb.KeyValueWriter, hash common.Hash, number uint64, rlp rlp.RawValue) { + if err := db.Put(accessListKey(number, hash), rlp); err != nil { + log.Crit("failed to store block access list", "err", err) + } +} + +func ReadAccessListRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue { + data, _ := db.Get(accessListKey(number, hash)) + return data +} + // HasBody verifies the existence of a block body corresponding to the hash. func HasBody(db ethdb.Reader, hash common.Hash, number uint64) bool { if isCanon(db, number, hash) { @@ -455,6 +467,25 @@ func WriteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64, body *t WriteBodyRLP(db, hash, number, data) } +func ReadAccessList(db ethdb.Reader, hash common.Hash, number uint64) (al *bal.BlockAccessList) { + data := ReadAccessListRLP(db, hash, number) + if data != nil { + err := rlp.DecodeBytes(data, al) + if err != nil { + log.Crit("failed to RLP decode access list", "err", err) + } + } + return al +} + +func WriteAccessList(db ethdb.KeyValueWriter, hash common.Hash, number uint64, al *bal.BlockAccessList) { + data, err := rlp.EncodeToBytes(al) + if err != nil { + log.Crit("failed to RLP encode block access list", "err", err) + } + WriteAccessListRLP(db, hash, number, data) +} + // DeleteBody removes all block body data associated with a hash. func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { if err := db.Delete(blockBodyKey(number, hash)); err != nil { @@ -659,13 +690,26 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block { if body == nil { return nil } - return types.NewBlockWithHeader(header).WithBody(*body) + + block := types.NewBlockWithHeader(header).WithBody(*body) + + // TODO: only read the access list if the bal hash is set in the header. + // I do it here regardless in order to support --experimental.bal which + // doesn't expect bal hash to be set in header in order to be compatible + // with importing mainnet blocks augmented with BALs + accessList := ReadAccessList(db, hash, number) + if accessList != nil { + block = block.WithAccessList(accessList) + } + + return block } // WriteBlock serializes a block into the database, header and body separately. func WriteBlock(db ethdb.KeyValueWriter, block *types.Block) { WriteBody(db, block.Hash(), block.NumberU64(), block.Body()) WriteHeader(db, block.Header()) + panic("TODO write access list if it exists") } // WriteAncientBlocks writes entire block data into ancient store and returns the total written size. diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index d9140c5fd6..f20cf06b8e 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -111,6 +111,7 @@ var ( headerNumberPrefix = []byte("H") // headerNumberPrefix + hash -> num (uint64 big endian) blockBodyPrefix = []byte("b") // blockBodyPrefix + num (uint64 big endian) + hash -> block body + accessListPrefix = []byte("z") blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts txLookupPrefix = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata @@ -209,6 +210,11 @@ func blockBodyKey(number uint64, hash common.Hash) []byte { return append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...) } +// accessListKey = accessListPrefix + num (uint64 big endian) + hash +func accessListKey(number uint64, hash common.Hash) []byte { + return append(append(accessListPrefix, encodeBlockNumber(number)...), hash.Bytes()...) +} + // blockReceiptsKey = blockReceiptsPrefix + num (uint64 big endian) + hash func blockReceiptsKey(number uint64, hash common.Hash) []byte { return append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...) diff --git a/core/state/bal_reader.go b/core/state/bal_reader.go index 3d76c290d6..c03788796b 100644 --- a/core/state/bal_reader.go +++ b/core/state/bal_reader.go @@ -126,7 +126,7 @@ type BALReader struct { // NewBALReader constructs a new reader from an access list. db is expected to have been instantiated with a reader. func NewBALReader(block *types.Block, reader Reader) *BALReader { r := &BALReader{accesses: make(map[common.Address]*bal.AccountAccess), block: block} - for _, acctDiff := range *block.Body().AccessList { + for _, acctDiff := range *block.AccessList() { r.accesses[acctDiff.Address] = &acctDiff } r.prestateReader.schedule(reader, r.ModifiedAccounts()) diff --git a/core/state_transition.go b/core/state_transition.go index 934ff4fbf1..ce4c3ca2fe 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -462,6 +462,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil { t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas) } + fmt.Printf("gas used %d\n", gas) st.gasRemaining -= gas if rules.IsEIP4762 { @@ -568,8 +569,10 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { } } + fmt.Printf("2 used gas is %d, %d\n", st.gasUsed(), peakGasUsed) + return &ExecutionResult{ - UsedGas: st.gasUsed(), + UsedGas: peakGasUsed, MaxUsedGas: peakGasUsed, Err: vmerr, ReturnData: ret, diff --git a/core/types/bal/bal_test.go b/core/types/bal/bal_test.go index b359300c84..a0538c2b95 100644 --- a/core/types/bal/bal_test.go +++ b/core/types/bal/bal_test.go @@ -93,7 +93,8 @@ func makeTestConstructionBAL() *AccessListBuilder { // TestBALEncoding tests that a populated access list can be encoded/decoded correctly. func TestBALEncoding(t *testing.T) { var buf bytes.Buffer - bal := makeTestConstructionBAL() + balBuilder := makeTestConstructionBAL() + bal := balBuilder.FinalizedAccesses err := bal.EncodeRLP(&buf) if err != nil { t.Fatalf("encoding failed: %v\n", err) @@ -136,7 +137,7 @@ func makeTestAccountAccess(sort bool) AccountAccess { } if sort { slices.SortFunc(storageWrites, func(a, b encodingSlotWrites) int { - return bytes.Compare(a.Slot[:], b.Slot[:]) + return bytes.Compare(a.Slot.inner.Bytes(), b.Slot.inner.Bytes()) }) } @@ -173,7 +174,7 @@ func makeTestAccountAccess(sort bool) AccountAccess { }) } - var encodedStorageReads []EncodedStorage + var encodedStorageReads []*EncodedStorage for _, slot := range storageReads { encodedStorageReads = append(encodedStorageReads, newEncodedStorageFromHash(slot)) } @@ -220,7 +221,7 @@ func TestBlockAccessListCopy(t *testing.T) { // Make sure the mutations on copy won't affect the origin for _, aa := range cpyCpy { for i := 0; i < len(aa.StorageReads); i++ { - aa.StorageReads[i] = testrand.Bytes(32) + aa.StorageReads[i] = &EncodedStorage{new(uint256.Int).SetBytes(testrand.Bytes(32))} } } if !reflect.DeepEqual(list, cpy) { @@ -230,8 +231,9 @@ func TestBlockAccessListCopy(t *testing.T) { func TestBlockAccessListValidation(t *testing.T) { // Validate the block access list after RLP decoding + testBALMaxIndex := 8 enc := makeTestBAL(true) - if err := enc.Validate(); err != nil { + if err := enc.Validate(testBALMaxIndex); err != nil { t.Fatalf("Unexpected validation error: %v", err) } var buf bytes.Buffer @@ -243,14 +245,14 @@ func TestBlockAccessListValidation(t *testing.T) { if err := dec.DecodeRLP(rlp.NewStream(bytes.NewReader(buf.Bytes()), 0)); err != nil { t.Fatalf("Unexpected RLP-decode error: %v", err) } - if err := dec.Validate(); err != nil { + if err := dec.Validate(testBALMaxIndex); err != nil { t.Fatalf("Unexpected validation error: %v", err) } // Validate the derived block access list - cBAL := makeTestConstructionBAL() + cBAL := makeTestConstructionBAL().FinalizedAccesses listB := cBAL.ToEncodingObj() - if err := listB.Validate(); err != nil { + if err := listB.Validate(testBALMaxIndex); err != nil { t.Fatalf("Unexpected validation error: %v", err) } } diff --git a/core/types/block.go b/core/types/block.go index 3597d7f49d..1bf003d1ea 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -182,8 +182,7 @@ func (h *Header) EmptyReceipts() bool { type Body struct { Transactions []*Transaction Uncles []*Header - Withdrawals []*Withdrawal `rlp:"optional"` - AccessList *bal.BlockAccessList `rlp:"optional,nil"` + Withdrawals []*Withdrawal `rlp:"optional"` } // Block represents an Ethereum block. @@ -287,15 +286,17 @@ func NewBlock(header *Header, body *Body, receipts []*Receipt, hasher ListHasher b.withdrawals = slices.Clone(withdrawals) } - if body.AccessList != nil { - balHash := body.AccessList.Hash() - b.header.BlockAccessListHash = &balHash - b.accessList = body.AccessList - } - return b } +func NewBlockWithAccessList(header *Header, body *Body, receipts []*Receipt, accessList *bal.BlockAccessList, hasher ListHasher) *Block { + block := NewBlock(header, body, receipts, hasher) + block.accessList = accessList + balHash := accessList.Hash() + block.header.BlockAccessListHash = &balHash + return block +} + // CopyHeader creates a deep copy of a block header. func CopyHeader(h *Header) *Header { cpy := *h @@ -367,15 +368,16 @@ func (b *Block) EncodeRLP(w io.Writer) error { // Body returns the non-header content of the block. // Note the returned data is not an independent copy. func (b *Block) Body() *Body { - return &Body{b.transactions, b.uncles, b.withdrawals, b.accessList} + return &Body{b.transactions, b.uncles, b.withdrawals} } // Accessors for body data. These do not return a copy because the content // of the body slices does not affect the cached hash/size in block. -func (b *Block) Uncles() []*Header { return b.uncles } -func (b *Block) Transactions() Transactions { return b.transactions } -func (b *Block) Withdrawals() Withdrawals { return b.withdrawals } +func (b *Block) Uncles() []*Header { return b.uncles } +func (b *Block) Transactions() Transactions { return b.transactions } +func (b *Block) Withdrawals() Withdrawals { return b.withdrawals } +func (b *Block) AccessList() *bal.BlockAccessList { return b.accessList } func (b *Block) Transaction(hash common.Hash) *Transaction { for _, transaction := range b.transactions { @@ -522,16 +524,30 @@ func (b *Block) WithBody(body Body) *Block { uncles: make([]*Header, len(body.Uncles)), withdrawals: slices.Clone(body.Withdrawals), } - if body.AccessList != nil { - balCopy := body.AccessList.Copy() - block.accessList = &balCopy - } for i := range body.Uncles { block.uncles[i] = CopyHeader(body.Uncles[i]) } return block } +// WithAccessList returns a copy of the block with the access list embedded. +// It does not set the access list hash in the header of the returned block. +// TODO: ^ when support for --experimental.bal is removed, this function should set the access list hash in the header +func (b *Block) WithAccessList(accessList *bal.BlockAccessList) *Block { + alCopy := accessList.Copy() + block := &Block{ + header: b.header, + transactions: slices.Clone(b.transactions), + uncles: make([]*Header, len(b.uncles)), + withdrawals: slices.Clone(b.withdrawals), + accessList: &alCopy, + } + for i := range b.uncles { + block.uncles[i] = CopyHeader(b.uncles[i]) + } + return block +} + // Hash returns the keccak256 hash of b's header. // The hash is computed on the first call and cached thereafter. func (b *Block) Hash() common.Hash { diff --git a/eth/api_backend.go b/eth/api_backend.go index 2656395b22..a816512eb2 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -514,8 +514,8 @@ func (b *EthAPIBackend) BlockAccessListByNumberOrHash(number rpc.BlockNumberOrHa if block == nil { return nil, fmt.Errorf("block not found") } - if block.Body().AccessList == nil { + if block.AccessList() == nil { return nil, nil } - return block.Body().AccessList.StringableRepresentation(), nil + return block.AccessList().StringableRepresentation(), nil } diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 22290af2b5..29d9f3deda 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -102,7 +102,6 @@ func (f *fetchResult) body() types.Body { Transactions: f.Transactions, Uncles: f.Uncles, Withdrawals: f.Withdrawals, - AccessList: f.AccessList, } } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 25c5f4c788..079a540663 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -970,8 +970,8 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param if block.Withdrawals() != nil { fields["withdrawals"] = block.Withdrawals() } - if block.Body().AccessList != nil { - fields["accessList"] = block.Body().AccessList + if block.AccessList() != nil { + fields["accessList"] = block.AccessList() } return fields } diff --git a/miner/worker.go b/miner/worker.go index 4669c4db2e..d589c8513e 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types/bal" "math/big" "sync/atomic" "time" @@ -147,9 +148,6 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay } } body := types.Body{Transactions: work.txs, Withdrawals: genParam.withdrawals} - if work.alTracer != nil { - body.AccessList = work.alTracer.AccessList().ToEncodingObj() - } allLogs := make([]*types.Log, 0) for _, r := range work.receipts { @@ -184,11 +182,12 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay // I considered trying to instantiate the beacon consensus engine with a tracer. // however, the BAL tracer instance is used once per block, while the engine object // lives for the entire time the client is running. - onBlockFinalization := func() { + onBlockFinalization := func() *bal.BlockAccessList { if miner.chainConfig.IsAmsterdam(work.header.Number, work.header.Time) { work.alTracer.OnBlockFinalization() - body.AccessList = work.alTracer.AccessList().ToEncodingObj() + return work.alTracer.AccessList().ToEncodingObj() } + return nil } block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts, onBlockFinalization)