core/types/bal: changes blockAccessList to a slice of AccessList

This commit is contained in:
Gary Rong 2026-04-23 10:50:22 +08:00
parent 9b8e379b5e
commit 1b291219f6
5 changed files with 264 additions and 261 deletions

View file

@ -25,7 +25,7 @@ import (
)
// ConstructionAccountAccess contains post-block account state for mutations as well as
// all storage keys that were read during execution. It is used when building block
// all storage keys that were read during execution. It is used when building block
// access list during execution.
type ConstructionAccountAccess struct {
// StorageWrites is the post-state values of an account's storage slots

View file

@ -33,26 +33,58 @@ import (
"github.com/holiman/uint256"
)
//go:generate go run github.com/ethereum/go-ethereum/rlp/rlpgen -out bal_encoding_rlp_generated.go -type BlockAccessList -decoder
//go:generate go run github.com/ethereum/go-ethereum/rlp/rlpgen -out bal_encoding_rlp_generated.go -type AccountAccess -decoder
// These are objects used as input for the access list encoding. They mirror
// the spec format.
// BlockAccessList is the encoding format of ConstructionBlockAccessList.
type BlockAccessList struct {
Accesses []AccountAccess
type BlockAccessList []AccountAccess
// EncodeRLP implements rlp.Encoder. It encodes the access list as a single
// RLP list of AccountAccess entries.
func (e BlockAccessList) EncodeRLP(w io.Writer) error {
buf := rlp.NewEncoderBuffer(w)
l := buf.List()
for i := range e {
if err := e[i].EncodeRLP(buf); err != nil {
return err
}
}
buf.ListEnd(l)
return buf.Flush()
}
// DecodeRLP implements rlp.Decoder.
func (e *BlockAccessList) DecodeRLP(s *rlp.Stream) error {
if _, err := s.List(); err != nil {
return err
}
var list BlockAccessList
for s.MoreDataInList() {
var a AccountAccess
if err := a.DecodeRLP(s); err != nil {
return err
}
list = append(list, a)
}
if err := s.ListEnd(); err != nil {
return err
}
*e = list
return nil
}
// Validate returns an error if the contents of the access list are not ordered
// according to the spec or any code changes are contained which exceed protocol
// max code size.
func (e *BlockAccessList) Validate() error {
if !slices.IsSortedFunc(e.Accesses, func(a, b AccountAccess) int {
if !slices.IsSortedFunc(*e, func(a, b AccountAccess) int {
return bytes.Compare(a.Address[:], b.Address[:])
}) {
return errors.New("block access list accounts not in lexicographic order")
}
for _, entry := range e.Accesses {
for _, entry := range *e {
if err := entry.validate(); err != nil {
return err
}
@ -63,12 +95,11 @@ func (e *BlockAccessList) Validate() error {
// Hash computes the keccak256 hash of the access list
func (e *BlockAccessList) Hash() common.Hash {
var enc bytes.Buffer
err := e.EncodeRLP(&enc)
if err != nil {
// errors here are related to BAL values exceeding maximum size defined
// by the spec. Hard-fail because these cases are not expected to be hit
// under reasonable conditions.
panic(err)
if err := e.EncodeRLP(&enc); err != nil {
// Errors here are related to BAL values exceeding maximum size defined
// by the spec. Return empty hash because these cases are not expected
// to be hit under reasonable conditions.
return common.Hash{}
}
return crypto.Keccak256Hash(enc.Bytes())
}
@ -308,9 +339,9 @@ func (b *ConstructionBlockAccessList) toEncodingObj() *BlockAccessList {
}
slices.SortFunc(addresses, common.Address.Cmp)
var res BlockAccessList
res := make(BlockAccessList, 0, len(addresses))
for _, addr := range addresses {
res.Accesses = append(res.Accesses, b.Accounts[addr].toEncodingObj(addr))
res = append(res, b.Accounts[addr].toEncodingObj(addr))
}
return &res
}
@ -320,7 +351,7 @@ func (e *BlockAccessList) PrettyPrint() string {
printWithIndent := func(indent int, text string) {
fmt.Fprintf(&res, "%s%s\n", strings.Repeat(" ", indent), text)
}
for _, accountDiff := range e.Accesses {
for _, accountDiff := range *e {
printWithIndent(0, fmt.Sprintf("%x:", accountDiff.Address))
printWithIndent(1, "storage writes:")
@ -356,11 +387,9 @@ func (e *BlockAccessList) PrettyPrint() string {
// Copy returns a deep copy of the access list
func (e *BlockAccessList) Copy() *BlockAccessList {
cpy := &BlockAccessList{
Accesses: make([]AccountAccess, 0, len(e.Accesses)),
cpy := make(BlockAccessList, 0, len(*e))
for _, accountAccess := range *e {
cpy = append(cpy, accountAccess.Copy())
}
for _, accountAccess := range e.Accesses {
cpy.Accesses = append(cpy.Accesses, accountAccess.Copy())
}
return cpy
return &cpy
}

View file

@ -6,288 +6,261 @@ import "github.com/ethereum/go-ethereum/rlp"
import "github.com/holiman/uint256"
import "io"
func (obj *BlockAccessList) EncodeRLP(_w io.Writer) error {
func (obj *AccountAccess) EncodeRLP(_w io.Writer) error {
w := rlp.NewEncoderBuffer(_w)
_tmp0 := w.List()
w.WriteBytes(obj.Address[:])
_tmp1 := w.List()
for _, _tmp2 := range obj.Accesses {
for _, _tmp2 := range obj.StorageWrites {
_tmp3 := w.List()
w.WriteBytes(_tmp2.Address[:])
if _tmp2.Slot == nil {
w.Write(rlp.EmptyString)
} else {
w.WriteUint256(_tmp2.Slot)
}
_tmp4 := w.List()
for _, _tmp5 := range _tmp2.StorageWrites {
for _, _tmp5 := range _tmp2.Accesses {
_tmp6 := w.List()
if _tmp5.Slot == nil {
w.WriteUint64(uint64(_tmp5.TxIdx))
if _tmp5.ValueAfter == nil {
w.Write(rlp.EmptyString)
} else {
w.WriteUint256(_tmp5.Slot)
w.WriteUint256(_tmp5.ValueAfter)
}
_tmp7 := w.List()
for _, _tmp8 := range _tmp5.Accesses {
_tmp9 := w.List()
w.WriteUint64(uint64(_tmp8.TxIdx))
if _tmp8.ValueAfter == nil {
w.Write(rlp.EmptyString)
} else {
w.WriteUint256(_tmp8.ValueAfter)
}
w.ListEnd(_tmp9)
}
w.ListEnd(_tmp7)
w.ListEnd(_tmp6)
}
w.ListEnd(_tmp4)
_tmp10 := w.List()
for _, _tmp11 := range _tmp2.StorageReads {
if _tmp11 == nil {
w.Write(rlp.EmptyString)
} else {
w.WriteUint256(_tmp11)
}
}
w.ListEnd(_tmp10)
_tmp12 := w.List()
for _, _tmp13 := range _tmp2.BalanceChanges {
_tmp14 := w.List()
w.WriteUint64(uint64(_tmp13.TxIdx))
if _tmp13.Balance == nil {
w.Write(rlp.EmptyString)
} else {
w.WriteUint256(_tmp13.Balance)
}
w.ListEnd(_tmp14)
}
w.ListEnd(_tmp12)
_tmp15 := w.List()
for _, _tmp16 := range _tmp2.NonceChanges {
_tmp17 := w.List()
w.WriteUint64(uint64(_tmp16.TxIdx))
w.WriteUint64(_tmp16.Nonce)
w.ListEnd(_tmp17)
}
w.ListEnd(_tmp15)
_tmp18 := w.List()
for _, _tmp19 := range _tmp2.CodeChanges {
_tmp20 := w.List()
w.WriteUint64(uint64(_tmp19.TxIndex))
w.WriteBytes(_tmp19.Code)
w.ListEnd(_tmp20)
}
w.ListEnd(_tmp18)
w.ListEnd(_tmp3)
}
w.ListEnd(_tmp1)
_tmp7 := w.List()
for _, _tmp8 := range obj.StorageReads {
if _tmp8 == nil {
w.Write(rlp.EmptyString)
} else {
w.WriteUint256(_tmp8)
}
}
w.ListEnd(_tmp7)
_tmp9 := w.List()
for _, _tmp10 := range obj.BalanceChanges {
_tmp11 := w.List()
w.WriteUint64(uint64(_tmp10.TxIdx))
if _tmp10.Balance == nil {
w.Write(rlp.EmptyString)
} else {
w.WriteUint256(_tmp10.Balance)
}
w.ListEnd(_tmp11)
}
w.ListEnd(_tmp9)
_tmp12 := w.List()
for _, _tmp13 := range obj.NonceChanges {
_tmp14 := w.List()
w.WriteUint64(uint64(_tmp13.TxIdx))
w.WriteUint64(_tmp13.Nonce)
w.ListEnd(_tmp14)
}
w.ListEnd(_tmp12)
_tmp15 := w.List()
for _, _tmp16 := range obj.CodeChanges {
_tmp17 := w.List()
w.WriteUint64(uint64(_tmp16.TxIndex))
w.WriteBytes(_tmp16.Code)
w.ListEnd(_tmp17)
}
w.ListEnd(_tmp15)
w.ListEnd(_tmp0)
return w.Flush()
}
func (obj *BlockAccessList) DecodeRLP(dec *rlp.Stream) error {
var _tmp0 BlockAccessList
func (obj *AccountAccess) DecodeRLP(dec *rlp.Stream) error {
var _tmp0 AccountAccess
{
if _, err := dec.List(); err != nil {
return err
}
// Accesses:
var _tmp1 []AccountAccess
// Address:
var _tmp1 [20]byte
if err := dec.ReadBytes(_tmp1[:]); err != nil {
return err
}
_tmp0.Address = _tmp1
// StorageWrites:
var _tmp2 []encodingSlotWrites
if _, err := dec.List(); err != nil {
return err
}
for dec.MoreDataInList() {
var _tmp2 AccountAccess
var _tmp3 encodingSlotWrites
{
if _, err := dec.List(); err != nil {
return err
}
// Address:
var _tmp3 [20]byte
if err := dec.ReadBytes(_tmp3[:]); err != nil {
// Slot:
var _tmp4 uint256.Int
if err := dec.ReadUint256(&_tmp4); err != nil {
return err
}
_tmp2.Address = _tmp3
// StorageWrites:
var _tmp4 []encodingSlotWrites
_tmp3.Slot = &_tmp4
// Accesses:
var _tmp5 []encodingStorageWrite
if _, err := dec.List(); err != nil {
return err
}
for dec.MoreDataInList() {
var _tmp5 encodingSlotWrites
{
if _, err := dec.List(); err != nil {
return err
}
// Slot:
var _tmp6 uint256.Int
if err := dec.ReadUint256(&_tmp6); err != nil {
return err
}
_tmp5.Slot = &_tmp6
// Accesses:
var _tmp7 []encodingStorageWrite
if _, err := dec.List(); err != nil {
return err
}
for dec.MoreDataInList() {
var _tmp8 encodingStorageWrite
{
if _, err := dec.List(); err != nil {
return err
}
// TxIdx:
_tmp9, err := dec.Uint32()
if err != nil {
return err
}
_tmp8.TxIdx = _tmp9
// ValueAfter:
var _tmp10 uint256.Int
if err := dec.ReadUint256(&_tmp10); err != nil {
return err
}
_tmp8.ValueAfter = &_tmp10
if err := dec.ListEnd(); err != nil {
return err
}
}
_tmp7 = append(_tmp7, _tmp8)
}
if err := dec.ListEnd(); err != nil {
return err
}
_tmp5.Accesses = _tmp7
if err := dec.ListEnd(); err != nil {
return err
}
}
_tmp4 = append(_tmp4, _tmp5)
}
if err := dec.ListEnd(); err != nil {
return err
}
_tmp2.StorageWrites = _tmp4
// StorageReads:
var _tmp11 []*uint256.Int
if _, err := dec.List(); err != nil {
return err
}
for dec.MoreDataInList() {
var _tmp12 uint256.Int
if err := dec.ReadUint256(&_tmp12); err != nil {
return err
}
_tmp11 = append(_tmp11, &_tmp12)
}
if err := dec.ListEnd(); err != nil {
return err
}
_tmp2.StorageReads = _tmp11
// BalanceChanges:
var _tmp13 []encodingBalanceChange
if _, err := dec.List(); err != nil {
return err
}
for dec.MoreDataInList() {
var _tmp14 encodingBalanceChange
var _tmp6 encodingStorageWrite
{
if _, err := dec.List(); err != nil {
return err
}
// TxIdx:
_tmp15, err := dec.Uint32()
_tmp7, err := dec.Uint32()
if err != nil {
return err
}
_tmp14.TxIdx = _tmp15
// Balance:
var _tmp16 uint256.Int
if err := dec.ReadUint256(&_tmp16); err != nil {
_tmp6.TxIdx = _tmp7
// ValueAfter:
var _tmp8 uint256.Int
if err := dec.ReadUint256(&_tmp8); err != nil {
return err
}
_tmp14.Balance = &_tmp16
_tmp6.ValueAfter = &_tmp8
if err := dec.ListEnd(); err != nil {
return err
}
}
_tmp13 = append(_tmp13, _tmp14)
_tmp5 = append(_tmp5, _tmp6)
}
if err := dec.ListEnd(); err != nil {
return err
}
_tmp2.BalanceChanges = _tmp13
// NonceChanges:
var _tmp17 []encodingAccountNonce
if _, err := dec.List(); err != nil {
return err
}
for dec.MoreDataInList() {
var _tmp18 encodingAccountNonce
{
if _, err := dec.List(); err != nil {
return err
}
// TxIdx:
_tmp19, err := dec.Uint32()
if err != nil {
return err
}
_tmp18.TxIdx = _tmp19
// Nonce:
_tmp20, err := dec.Uint64()
if err != nil {
return err
}
_tmp18.Nonce = _tmp20
if err := dec.ListEnd(); err != nil {
return err
}
}
_tmp17 = append(_tmp17, _tmp18)
}
if err := dec.ListEnd(); err != nil {
return err
}
_tmp2.NonceChanges = _tmp17
// CodeChanges:
var _tmp21 []encodingCodeChange
if _, err := dec.List(); err != nil {
return err
}
for dec.MoreDataInList() {
var _tmp22 encodingCodeChange
{
if _, err := dec.List(); err != nil {
return err
}
// TxIndex:
_tmp23, err := dec.Uint32()
if err != nil {
return err
}
_tmp22.TxIndex = _tmp23
// Code:
_tmp24, err := dec.Bytes()
if err != nil {
return err
}
_tmp22.Code = _tmp24
if err := dec.ListEnd(); err != nil {
return err
}
}
_tmp21 = append(_tmp21, _tmp22)
}
if err := dec.ListEnd(); err != nil {
return err
}
_tmp2.CodeChanges = _tmp21
_tmp3.Accesses = _tmp5
if err := dec.ListEnd(); err != nil {
return err
}
}
_tmp1 = append(_tmp1, _tmp2)
_tmp2 = append(_tmp2, _tmp3)
}
if err := dec.ListEnd(); err != nil {
return err
}
_tmp0.Accesses = _tmp1
_tmp0.StorageWrites = _tmp2
// StorageReads:
var _tmp9 []*uint256.Int
if _, err := dec.List(); err != nil {
return err
}
for dec.MoreDataInList() {
var _tmp10 uint256.Int
if err := dec.ReadUint256(&_tmp10); err != nil {
return err
}
_tmp9 = append(_tmp9, &_tmp10)
}
if err := dec.ListEnd(); err != nil {
return err
}
_tmp0.StorageReads = _tmp9
// BalanceChanges:
var _tmp11 []encodingBalanceChange
if _, err := dec.List(); err != nil {
return err
}
for dec.MoreDataInList() {
var _tmp12 encodingBalanceChange
{
if _, err := dec.List(); err != nil {
return err
}
// TxIdx:
_tmp13, err := dec.Uint32()
if err != nil {
return err
}
_tmp12.TxIdx = _tmp13
// Balance:
var _tmp14 uint256.Int
if err := dec.ReadUint256(&_tmp14); err != nil {
return err
}
_tmp12.Balance = &_tmp14
if err := dec.ListEnd(); err != nil {
return err
}
}
_tmp11 = append(_tmp11, _tmp12)
}
if err := dec.ListEnd(); err != nil {
return err
}
_tmp0.BalanceChanges = _tmp11
// NonceChanges:
var _tmp15 []encodingAccountNonce
if _, err := dec.List(); err != nil {
return err
}
for dec.MoreDataInList() {
var _tmp16 encodingAccountNonce
{
if _, err := dec.List(); err != nil {
return err
}
// TxIdx:
_tmp17, err := dec.Uint32()
if err != nil {
return err
}
_tmp16.TxIdx = _tmp17
// Nonce:
_tmp18, err := dec.Uint64()
if err != nil {
return err
}
_tmp16.Nonce = _tmp18
if err := dec.ListEnd(); err != nil {
return err
}
}
_tmp15 = append(_tmp15, _tmp16)
}
if err := dec.ListEnd(); err != nil {
return err
}
_tmp0.NonceChanges = _tmp15
// CodeChanges:
var _tmp19 []encodingCodeChange
if _, err := dec.List(); err != nil {
return err
}
for dec.MoreDataInList() {
var _tmp20 encodingCodeChange
{
if _, err := dec.List(); err != nil {
return err
}
// TxIndex:
_tmp21, err := dec.Uint32()
if err != nil {
return err
}
_tmp20.TxIndex = _tmp21
// Code:
_tmp22, err := dec.Bytes()
if err != nil {
return err
}
_tmp20.Code = _tmp22
if err := dec.ListEnd(); err != nil {
return err
}
}
_tmp19 = append(_tmp19, _tmp20)
}
if err := dec.ListEnd(); err != nil {
return err
}
_tmp0.CodeChanges = _tmp19
if err := dec.ListEnd(); err != nil {
return err
}

View file

@ -29,13 +29,6 @@ import (
"github.com/holiman/uint256"
)
func equalBALs(a *BlockAccessList, b *BlockAccessList) bool {
if !reflect.DeepEqual(a, b) {
return false
}
return true
}
func makeTestConstructionBAL() *ConstructionBlockAccessList {
return &ConstructionBlockAccessList{
map[common.Address]*ConstructionAccountAccess{
@ -101,13 +94,13 @@ func TestBALEncoding(t *testing.T) {
t.Fatalf("encoding failed: %v\n", err)
}
var dec BlockAccessList
if err := dec.DecodeRLP(rlp.NewStream(bytes.NewReader(buf.Bytes()), 10000000)); err != nil {
if err := dec.DecodeRLP(rlp.NewStream(bytes.NewReader(buf.Bytes()), 0)); err != nil {
t.Fatalf("decoding failed: %v\n", err)
}
if dec.Hash() != bal.toEncodingObj().Hash() {
t.Fatalf("encoded block hash doesn't match decoded")
}
if !equalBALs(bal.toEncodingObj(), &dec) {
if !reflect.DeepEqual(bal.toEncodingObj(), &dec) {
t.Fatal("decoded BAL doesn't match")
}
}
@ -118,6 +111,7 @@ func makeTestAccountAccess(sort bool) AccountAccess {
storageReads []*uint256.Int
balances []encodingBalanceChange
nonces []encodingAccountNonce
codes []encodingCodeChange
)
randSlot := func() *uint256.Int {
return new(uint256.Int).SetBytes(testrand.Bytes(32))
@ -178,32 +172,39 @@ func makeTestAccountAccess(sort bool) AccountAccess {
})
}
for i := 0; i < 5; i++ {
codes = append(codes, encodingCodeChange{
TxIndex: uint32(2 * i),
Code: testrand.Bytes(256),
})
}
if sort {
slices.SortFunc(codes, func(a, b encodingCodeChange) int {
return cmp.Compare[uint32](a.TxIndex, b.TxIndex)
})
}
return AccountAccess{
Address: [20]byte(testrand.Bytes(20)),
StorageWrites: storageWrites,
StorageReads: storageReads,
BalanceChanges: balances,
NonceChanges: nonces,
CodeChanges: []encodingCodeChange{
{
TxIndex: 100,
Code: testrand.Bytes(256),
},
},
CodeChanges: codes,
}
}
func makeTestBAL(sort bool) *BlockAccessList {
list := &BlockAccessList{}
list := make(BlockAccessList, 0, 5)
for i := 0; i < 5; i++ {
list.Accesses = append(list.Accesses, makeTestAccountAccess(sort))
list = append(list, makeTestAccountAccess(sort))
}
if sort {
slices.SortFunc(list.Accesses, func(a, b AccountAccess) int {
slices.SortFunc(list, func(a, b AccountAccess) int {
return bytes.Compare(a.Address[:], b.Address[:])
})
}
return list
return &list
}
func TestBlockAccessListCopy(t *testing.T) {
@ -219,7 +220,7 @@ func TestBlockAccessListCopy(t *testing.T) {
}
// Make sure the mutations on copy won't affect the origin
for _, aa := range cpyCpy.Accesses {
for _, aa := range *cpyCpy {
for i := 0; i < len(aa.StorageReads); i++ {
aa.StorageReads[i] = new(uint256.Int).SetBytes(testrand.Bytes(32))
}

View file

@ -48,7 +48,7 @@ func makeTestBAL(minSize int) *bal.BlockAccessList {
binary.BigEndian.PutUint64(b[24:], uint64(i))
access.StorageReads[i] = new(uint256.Int).SetBytes(b[:])
}
return &bal.BlockAccessList{Accesses: []bal.AccountAccess{access}}
return &bal.BlockAccessList{access}
}
// getChainWithBALs creates a minimal test chain with BALs stored for each block.