core/types/bal, eth/protocols/snap: convert the storage key and value

This commit is contained in:
Gary Rong 2026-04-23 10:24:03 +08:00
parent 5a54af9fc9
commit 9b8e379b5e
4 changed files with 80 additions and 42 deletions

View file

@ -88,12 +88,12 @@ type encodingAccountNonce struct {
// encodingStorageWrite is the encoding format of StorageWrites. // encodingStorageWrite is the encoding format of StorageWrites.
type encodingStorageWrite struct { type encodingStorageWrite struct {
TxIdx uint32 TxIdx uint32
ValueAfter [32]byte ValueAfter *uint256.Int
} }
// encodingStorageWrite is the encoding format of SlotWrites. // encodingStorageWrite is the encoding format of SlotWrites.
type encodingSlotWrites struct { type encodingSlotWrites struct {
Slot [32]byte Slot *uint256.Int
Accesses []encodingStorageWrite Accesses []encodingStorageWrite
} }
@ -119,7 +119,7 @@ type encodingCodeChange struct {
type AccountAccess struct { type AccountAccess struct {
Address [20]byte // 20-byte Ethereum address Address [20]byte // 20-byte Ethereum address
StorageWrites []encodingSlotWrites // Storage changes (slot -> [tx_index -> new_value]) StorageWrites []encodingSlotWrites // Storage changes (slot -> [tx_index -> new_value])
StorageReads [][32]byte // Read-only storage keys StorageReads []*uint256.Int // Read-only storage keys
BalanceChanges []encodingBalanceChange // Balance changes ([tx_index -> post_balance]) BalanceChanges []encodingBalanceChange // Balance changes ([tx_index -> post_balance])
NonceChanges []encodingAccountNonce // Nonce changes ([tx_index -> new_nonce]) NonceChanges []encodingAccountNonce // Nonce changes ([tx_index -> new_nonce])
CodeChanges []encodingCodeChange // Code changes ([tx_index -> new_code]) CodeChanges []encodingCodeChange // Code changes ([tx_index -> new_code])
@ -131,7 +131,7 @@ type AccountAccess struct {
func (e *AccountAccess) validate() error { func (e *AccountAccess) validate() error {
// Check the storage write slots are sorted in order // Check the storage write slots are sorted in order
if !slices.IsSortedFunc(e.StorageWrites, func(a, b encodingSlotWrites) int { if !slices.IsSortedFunc(e.StorageWrites, func(a, b encodingSlotWrites) int {
return bytes.Compare(a.Slot[:], b.Slot[:]) return a.Slot.Cmp(b.Slot)
}) { }) {
return errors.New("storage writes slots not in lexicographic order") return errors.New("storage writes slots not in lexicographic order")
} }
@ -142,8 +142,8 @@ func (e *AccountAccess) validate() error {
} }
// Check the storage read slots are sorted in order // Check the storage read slots are sorted in order
if !slices.IsSortedFunc(e.StorageReads, func(a, b [32]byte) int { if !slices.IsSortedFunc(e.StorageReads, func(a, b *uint256.Int) int {
return bytes.Compare(a[:], b[:]) return a.Cmp(b)
}) { }) {
return errors.New("storage read slots not in lexicographic order") return errors.New("storage read slots not in lexicographic order")
} }
@ -182,16 +182,32 @@ func (e *AccountAccess) validate() error {
func (e *AccountAccess) Copy() AccountAccess { func (e *AccountAccess) Copy() AccountAccess {
res := AccountAccess{ res := AccountAccess{
Address: e.Address, Address: e.Address,
StorageReads: slices.Clone(e.StorageReads), StorageReads: make([]*uint256.Int, 0, len(e.StorageReads)),
BalanceChanges: slices.Clone(e.BalanceChanges), BalanceChanges: make([]encodingBalanceChange, 0, len(e.BalanceChanges)),
NonceChanges: slices.Clone(e.NonceChanges), NonceChanges: slices.Clone(e.NonceChanges),
StorageWrites: make([]encodingSlotWrites, 0, len(e.StorageWrites)), StorageWrites: make([]encodingSlotWrites, 0, len(e.StorageWrites)),
CodeChanges: make([]encodingCodeChange, 0, len(e.CodeChanges)), CodeChanges: make([]encodingCodeChange, 0, len(e.CodeChanges)),
} }
for _, slot := range e.StorageReads {
res.StorageReads = append(res.StorageReads, slot.Clone())
}
for _, change := range e.BalanceChanges {
res.BalanceChanges = append(res.BalanceChanges, encodingBalanceChange{
TxIdx: change.TxIdx,
Balance: change.Balance.Clone(),
})
}
for _, storageWrite := range e.StorageWrites { for _, storageWrite := range e.StorageWrites {
accesses := make([]encodingStorageWrite, 0, len(storageWrite.Accesses))
for _, w := range storageWrite.Accesses {
accesses = append(accesses, encodingStorageWrite{
TxIdx: w.TxIdx,
ValueAfter: w.ValueAfter.Clone(),
})
}
res.StorageWrites = append(res.StorageWrites, encodingSlotWrites{ res.StorageWrites = append(res.StorageWrites, encodingSlotWrites{
Slot: storageWrite.Slot, Slot: storageWrite.Slot.Clone(),
Accesses: slices.Clone(storageWrite.Accesses), Accesses: accesses,
}) })
} }
for _, codeChange := range e.CodeChanges { for _, codeChange := range e.CodeChanges {
@ -216,7 +232,7 @@ func (a *ConstructionAccountAccess) toEncodingObj(addr common.Address) AccountAc
res := AccountAccess{ res := AccountAccess{
Address: addr, Address: addr,
StorageWrites: make([]encodingSlotWrites, 0, len(a.StorageWrites)), StorageWrites: make([]encodingSlotWrites, 0, len(a.StorageWrites)),
StorageReads: make([][32]byte, 0, len(a.StorageReads)), StorageReads: make([]*uint256.Int, 0, len(a.StorageReads)),
BalanceChanges: make([]encodingBalanceChange, 0, len(a.BalanceChanges)), BalanceChanges: make([]encodingBalanceChange, 0, len(a.BalanceChanges)),
NonceChanges: make([]encodingAccountNonce, 0, len(a.NonceChanges)), NonceChanges: make([]encodingAccountNonce, 0, len(a.NonceChanges)),
CodeChanges: make([]encodingCodeChange, 0, len(a.CodeChange)), CodeChanges: make([]encodingCodeChange, 0, len(a.CodeChange)),
@ -226,18 +242,19 @@ func (a *ConstructionAccountAccess) toEncodingObj(addr common.Address) AccountAc
writeSlots := slices.Collect(maps.Keys(a.StorageWrites)) writeSlots := slices.Collect(maps.Keys(a.StorageWrites))
slices.SortFunc(writeSlots, common.Hash.Cmp) slices.SortFunc(writeSlots, common.Hash.Cmp)
for _, slot := range writeSlots { for _, slot := range writeSlots {
var obj encodingSlotWrites obj := encodingSlotWrites{
obj.Slot = slot Slot: new(uint256.Int).SetBytes(slot[:]),
}
slotWrites := a.StorageWrites[slot] slotWrites := a.StorageWrites[slot]
obj.Accesses = make([]encodingStorageWrite, 0, len(slotWrites)) obj.Accesses = make([]encodingStorageWrite, 0, len(slotWrites))
indices := slices.Collect(maps.Keys(slotWrites)) indices := slices.Collect(maps.Keys(slotWrites))
slices.SortFunc(indices, cmp.Compare[uint32]) slices.SortFunc(indices, cmp.Compare[uint32])
for _, index := range indices { for _, index := range indices {
val := slotWrites[index]
obj.Accesses = append(obj.Accesses, encodingStorageWrite{ obj.Accesses = append(obj.Accesses, encodingStorageWrite{
TxIdx: index, TxIdx: index,
ValueAfter: slotWrites[index], ValueAfter: new(uint256.Int).SetBytes(val[:]),
}) })
} }
res.StorageWrites = append(res.StorageWrites, obj) res.StorageWrites = append(res.StorageWrites, obj)
@ -247,7 +264,7 @@ func (a *ConstructionAccountAccess) toEncodingObj(addr common.Address) AccountAc
readSlots := slices.Collect(maps.Keys(a.StorageReads)) readSlots := slices.Collect(maps.Keys(a.StorageReads))
slices.SortFunc(readSlots, common.Hash.Cmp) slices.SortFunc(readSlots, common.Hash.Cmp)
for _, slot := range readSlots { for _, slot := range readSlots {
res.StorageReads = append(res.StorageReads, slot) res.StorageReads = append(res.StorageReads, new(uint256.Int).SetBytes(slot[:]))
} }
// Convert balance changes // Convert balance changes
@ -308,15 +325,15 @@ func (e *BlockAccessList) PrettyPrint() string {
printWithIndent(1, "storage writes:") printWithIndent(1, "storage writes:")
for _, sWrite := range accountDiff.StorageWrites { for _, sWrite := range accountDiff.StorageWrites {
printWithIndent(2, fmt.Sprintf("%x:", sWrite.Slot)) printWithIndent(2, fmt.Sprintf("%s:", sWrite.Slot.Hex()))
for _, access := range sWrite.Accesses { for _, access := range sWrite.Accesses {
printWithIndent(3, fmt.Sprintf("%d: %x", access.TxIdx, access.ValueAfter)) printWithIndent(3, fmt.Sprintf("%d: %s", access.TxIdx, access.ValueAfter.Hex()))
} }
} }
printWithIndent(1, "storage reads:") printWithIndent(1, "storage reads:")
for _, slot := range accountDiff.StorageReads { for _, slot := range accountDiff.StorageReads {
printWithIndent(2, fmt.Sprintf("%x", slot)) printWithIndent(2, slot.Hex())
} }
printWithIndent(1, "balance changes:") printWithIndent(1, "balance changes:")

View file

@ -16,12 +16,20 @@ func (obj *BlockAccessList) EncodeRLP(_w io.Writer) error {
_tmp4 := w.List() _tmp4 := w.List()
for _, _tmp5 := range _tmp2.StorageWrites { for _, _tmp5 := range _tmp2.StorageWrites {
_tmp6 := w.List() _tmp6 := w.List()
w.WriteBytes(_tmp5.Slot[:]) if _tmp5.Slot == nil {
w.Write(rlp.EmptyString)
} else {
w.WriteUint256(_tmp5.Slot)
}
_tmp7 := w.List() _tmp7 := w.List()
for _, _tmp8 := range _tmp5.Accesses { for _, _tmp8 := range _tmp5.Accesses {
_tmp9 := w.List() _tmp9 := w.List()
w.WriteUint64(uint64(_tmp8.TxIdx)) w.WriteUint64(uint64(_tmp8.TxIdx))
w.WriteBytes(_tmp8.ValueAfter[:]) if _tmp8.ValueAfter == nil {
w.Write(rlp.EmptyString)
} else {
w.WriteUint256(_tmp8.ValueAfter)
}
w.ListEnd(_tmp9) w.ListEnd(_tmp9)
} }
w.ListEnd(_tmp7) w.ListEnd(_tmp7)
@ -30,7 +38,11 @@ func (obj *BlockAccessList) EncodeRLP(_w io.Writer) error {
w.ListEnd(_tmp4) w.ListEnd(_tmp4)
_tmp10 := w.List() _tmp10 := w.List()
for _, _tmp11 := range _tmp2.StorageReads { for _, _tmp11 := range _tmp2.StorageReads {
w.WriteBytes(_tmp11[:]) if _tmp11 == nil {
w.Write(rlp.EmptyString)
} else {
w.WriteUint256(_tmp11)
}
} }
w.ListEnd(_tmp10) w.ListEnd(_tmp10)
_tmp12 := w.List() _tmp12 := w.List()
@ -103,11 +115,11 @@ func (obj *BlockAccessList) DecodeRLP(dec *rlp.Stream) error {
return err return err
} }
// Slot: // Slot:
var _tmp6 [32]byte var _tmp6 uint256.Int
if err := dec.ReadBytes(_tmp6[:]); err != nil { if err := dec.ReadUint256(&_tmp6); err != nil {
return err return err
} }
_tmp5.Slot = _tmp6 _tmp5.Slot = &_tmp6
// Accesses: // Accesses:
var _tmp7 []encodingStorageWrite var _tmp7 []encodingStorageWrite
if _, err := dec.List(); err != nil { if _, err := dec.List(); err != nil {
@ -126,11 +138,11 @@ func (obj *BlockAccessList) DecodeRLP(dec *rlp.Stream) error {
} }
_tmp8.TxIdx = _tmp9 _tmp8.TxIdx = _tmp9
// ValueAfter: // ValueAfter:
var _tmp10 [32]byte var _tmp10 uint256.Int
if err := dec.ReadBytes(_tmp10[:]); err != nil { if err := dec.ReadUint256(&_tmp10); err != nil {
return err return err
} }
_tmp8.ValueAfter = _tmp10 _tmp8.ValueAfter = &_tmp10
if err := dec.ListEnd(); err != nil { if err := dec.ListEnd(); err != nil {
return err return err
} }
@ -152,16 +164,16 @@ func (obj *BlockAccessList) DecodeRLP(dec *rlp.Stream) error {
} }
_tmp2.StorageWrites = _tmp4 _tmp2.StorageWrites = _tmp4
// StorageReads: // StorageReads:
var _tmp11 [][32]byte var _tmp11 []*uint256.Int
if _, err := dec.List(); err != nil { if _, err := dec.List(); err != nil {
return err return err
} }
for dec.MoreDataInList() { for dec.MoreDataInList() {
var _tmp12 [32]byte var _tmp12 uint256.Int
if err := dec.ReadBytes(_tmp12[:]); err != nil { if err := dec.ReadUint256(&_tmp12); err != nil {
return err return err
} }
_tmp11 = append(_tmp11, _tmp12) _tmp11 = append(_tmp11, &_tmp12)
} }
if err := dec.ListEnd(); err != nil { if err := dec.ListEnd(); err != nil {
return err return err

View file

@ -115,18 +115,21 @@ func TestBALEncoding(t *testing.T) {
func makeTestAccountAccess(sort bool) AccountAccess { func makeTestAccountAccess(sort bool) AccountAccess {
var ( var (
storageWrites []encodingSlotWrites storageWrites []encodingSlotWrites
storageReads [][32]byte storageReads []*uint256.Int
balances []encodingBalanceChange balances []encodingBalanceChange
nonces []encodingAccountNonce nonces []encodingAccountNonce
) )
randSlot := func() *uint256.Int {
return new(uint256.Int).SetBytes(testrand.Bytes(32))
}
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
slot := encodingSlotWrites{ slot := encodingSlotWrites{
Slot: testrand.Hash(), Slot: randSlot(),
} }
for j := 0; j < 3; j++ { for j := 0; j < 3; j++ {
slot.Accesses = append(slot.Accesses, encodingStorageWrite{ slot.Accesses = append(slot.Accesses, encodingStorageWrite{
TxIdx: uint32(2 * j), TxIdx: uint32(2 * j),
ValueAfter: testrand.Hash(), ValueAfter: randSlot(),
}) })
} }
if sort { if sort {
@ -138,16 +141,16 @@ func makeTestAccountAccess(sort bool) AccountAccess {
} }
if sort { if sort {
slices.SortFunc(storageWrites, func(a, b encodingSlotWrites) int { slices.SortFunc(storageWrites, func(a, b encodingSlotWrites) int {
return bytes.Compare(a.Slot[:], b.Slot[:]) return a.Slot.Cmp(b.Slot)
}) })
} }
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
storageReads = append(storageReads, testrand.Hash()) storageReads = append(storageReads, randSlot())
} }
if sort { if sort {
slices.SortFunc(storageReads, func(a, b [32]byte) int { slices.SortFunc(storageReads, func(a, b *uint256.Int) int {
return bytes.Compare(a[:], b[:]) return a.Cmp(b)
}) })
} }
@ -218,7 +221,7 @@ func TestBlockAccessListCopy(t *testing.T) {
// Make sure the mutations on copy won't affect the origin // Make sure the mutations on copy won't affect the origin
for _, aa := range cpyCpy.Accesses { for _, aa := range cpyCpy.Accesses {
for i := 0; i < len(aa.StorageReads); i++ { for i := 0; i < len(aa.StorageReads); i++ {
aa.StorageReads[i] = [32]byte(testrand.Bytes(32)) aa.StorageReads[i] = new(uint256.Int).SetBytes(testrand.Bytes(32))
} }
} }
if !reflect.DeepEqual(list, cpy) { if !reflect.DeepEqual(list, cpy) {

View file

@ -31,16 +31,22 @@ import (
"github.com/ethereum/go-ethereum/core/types/bal" "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/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/holiman/uint256"
) )
func makeTestBAL(minSize int) *bal.BlockAccessList { func makeTestBAL(minSize int) *bal.BlockAccessList {
n := minSize/33 + 1 // 33 bytes per storage read slot in RLP n := minSize/33 + 1 // 33 bytes per storage read slot in RLP
access := bal.AccountAccess{ access := bal.AccountAccess{
Address: common.HexToAddress("0x01"), Address: common.HexToAddress("0x01"),
StorageReads: make([][32]byte, n), StorageReads: make([]*uint256.Int, n),
} }
// Use a full-width 32-byte value (top byte 0xff) so each slot still
// encodes to 33 RLP bytes regardless of the index.
for i := range access.StorageReads { for i := range access.StorageReads {
binary.BigEndian.PutUint64(access.StorageReads[i][24:], uint64(i)) var b [32]byte
b[0] = 0xff
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{Accesses: []bal.AccountAccess{access}}
} }