mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 13:46:43 +00:00
core/types/bal: remove ssz testdata and add tests
This commit is contained in:
parent
0b3283a030
commit
1dc017c289
53 changed files with 179 additions and 99 deletions
|
|
@ -76,7 +76,7 @@ type ConstructionBlockAccessList struct {
|
||||||
Accounts map[common.Address]*ConstructionAccountAccess
|
Accounts map[common.Address]*ConstructionAccountAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlockAccessList instantiates an empty access list.
|
// NewConstructionBlockAccessList instantiates an empty access list.
|
||||||
func NewConstructionBlockAccessList() ConstructionBlockAccessList {
|
func NewConstructionBlockAccessList() ConstructionBlockAccessList {
|
||||||
return ConstructionBlockAccessList{
|
return ConstructionBlockAccessList{
|
||||||
Accounts: make(map[common.Address]*ConstructionAccountAccess),
|
Accounts: make(map[common.Address]*ConstructionAccountAccess),
|
||||||
|
|
|
||||||
|
|
@ -19,16 +19,16 @@ package bal
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"cmp"
|
"cmp"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"maps"
|
"maps"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
@ -47,19 +47,15 @@ type BlockAccessList struct {
|
||||||
// according to the spec or any code changes are contained which exceed protocol
|
// according to the spec or any code changes are contained which exceed protocol
|
||||||
// max code size.
|
// max code size.
|
||||||
func (e *BlockAccessList) Validate() error {
|
func (e *BlockAccessList) Validate() error {
|
||||||
var (
|
if !slices.IsSortedFunc(e.Accesses, func(a, b AccountAccess) int {
|
||||||
prev *[20]byte
|
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.Accesses {
|
||||||
if prev != nil {
|
|
||||||
if bytes.Compare(entry.Address[:], (*prev)[:]) <= 0 {
|
|
||||||
return fmt.Errorf("block access list accounts not in lexicographic order")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := entry.validate(); err != nil {
|
if err := entry.validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
prev = &entry.Address
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -115,16 +111,12 @@ type encodingSlotWrites struct {
|
||||||
// validate returns an instance of the encoding-representation slot writes in
|
// validate returns an instance of the encoding-representation slot writes in
|
||||||
// working representation.
|
// working representation.
|
||||||
func (e *encodingSlotWrites) validate() error {
|
func (e *encodingSlotWrites) validate() error {
|
||||||
var prev *uint16
|
if slices.IsSortedFunc(e.Accesses, func(a, b encodingStorageWrite) int {
|
||||||
for _, write := range e.Accesses {
|
return cmp.Compare[uint16](a.TxIdx, b.TxIdx)
|
||||||
if prev != nil {
|
}) {
|
||||||
if *prev >= write.TxIdx {
|
return nil
|
||||||
return fmt.Errorf("storage write tx indices not in order")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prev = &write.TxIdx
|
|
||||||
}
|
}
|
||||||
return nil
|
return errors.New("storage write tx indices not in order")
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccountAccess is the encoding format of ConstructionAccountAccess.
|
// AccountAccess is the encoding format of ConstructionAccountAccess.
|
||||||
|
|
@ -141,52 +133,37 @@ type AccountAccess struct {
|
||||||
// If any of the keys in the encoding object are not ordered according to the
|
// If any of the keys in the encoding object are not ordered according to the
|
||||||
// spec, an error is returned.
|
// spec, an error is returned.
|
||||||
func (e *AccountAccess) validate() error {
|
func (e *AccountAccess) validate() error {
|
||||||
// Convert slot writes
|
// Check the storage write slots are sorted in order
|
||||||
var prevSlotWrite *[32]byte
|
if !slices.IsSortedFunc(e.StorageWrites, func(a, b encodingSlotWrites) int {
|
||||||
|
return bytes.Compare(a.Slot[:], b.Slot[:])
|
||||||
|
}) {
|
||||||
|
return errors.New("storage writes slots not in lexicographic order")
|
||||||
|
}
|
||||||
for _, write := range e.StorageWrites {
|
for _, write := range e.StorageWrites {
|
||||||
if prevSlotWrite != nil {
|
|
||||||
if bytes.Compare((*prevSlotWrite)[:], write.Slot[:]) >= 0 {
|
|
||||||
return fmt.Errorf("storage writes slots not in lexicographic order")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prevSlotWrite = &write.Slot
|
|
||||||
|
|
||||||
if err := write.validate(); err != nil {
|
if err := write.validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert slot reads
|
// Check the storage read slots are sorted in order
|
||||||
var prevSlotRead *[32]byte
|
if !slices.IsSortedFunc(e.StorageReads, func(a, b [32]byte) int {
|
||||||
for _, read := range e.StorageReads {
|
return bytes.Compare(a[:], b[:])
|
||||||
if prevSlotRead != nil {
|
}) {
|
||||||
if bytes.Compare((*prevSlotRead)[:], read[:]) >= 0 {
|
return errors.New("storage read slots not in lexicographic order")
|
||||||
return fmt.Errorf("storage read slots not in lexicographic order")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prevSlotRead = &read
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert balance changes
|
// Check the balance changes are sorted in order
|
||||||
var prevBalanceIndex *uint16
|
if !slices.IsSortedFunc(e.BalanceChanges, func(a, b encodingBalanceChange) int {
|
||||||
for _, balanceChange := range e.BalanceChanges {
|
return cmp.Compare[uint16](a.TxIdx, b.TxIdx)
|
||||||
if prevBalanceIndex != nil {
|
}) {
|
||||||
if *prevBalanceIndex >= balanceChange.TxIdx {
|
return errors.New("balance changes not in ascending order by tx index")
|
||||||
return fmt.Errorf("balance changes not in ascending order by tx index")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prevBalanceIndex = &balanceChange.TxIdx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert nonce changes
|
// Check the nonce changes are sorted in order
|
||||||
var prevNonceIndex *uint16
|
if !slices.IsSortedFunc(e.NonceChanges, func(a, b encodingAccountNonce) int {
|
||||||
for _, nonceChange := range e.NonceChanges {
|
return cmp.Compare[uint16](a.TxIdx, b.TxIdx)
|
||||||
if prevNonceIndex != nil {
|
}) {
|
||||||
if *prevNonceIndex >= nonceChange.TxIdx {
|
return errors.New("nonce changes not in ascending order by tx index")
|
||||||
return fmt.Errorf("nonce diffs not in ascending order by tx index")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prevNonceIndex = &nonceChange.TxIdx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert code change
|
// Convert code change
|
||||||
|
|
@ -201,36 +178,15 @@ func (e *AccountAccess) validate() error {
|
||||||
// Copy returns a deep copy of the account access
|
// Copy returns a deep copy of the account access
|
||||||
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),
|
||||||
|
BalanceChanges: slices.Clone(e.BalanceChanges),
|
||||||
|
NonceChanges: slices.Clone(e.NonceChanges),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, storageWrite := range e.StorageWrites {
|
for _, storageWrite := range e.StorageWrites {
|
||||||
cpy := encodingSlotWrites{
|
res.StorageWrites = append(res.StorageWrites, encodingSlotWrites{
|
||||||
Slot: storageWrite.Slot,
|
Slot: storageWrite.Slot,
|
||||||
Accesses: slices.Clone(storageWrite.Accesses),
|
Accesses: slices.Clone(storageWrite.Accesses),
|
||||||
}
|
|
||||||
for _, slotWrite := range storageWrite.Accesses {
|
|
||||||
cpy.Accesses = append(cpy.Accesses, encodingStorageWrite{
|
|
||||||
TxIdx: slotWrite.TxIdx,
|
|
||||||
ValueAfter: slotWrite.ValueAfter,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
res.StorageWrites = append(res.StorageWrites, cpy)
|
|
||||||
}
|
|
||||||
|
|
||||||
res.StorageReads = slices.Clone(e.StorageReads)
|
|
||||||
|
|
||||||
for _, balanceChange := range e.BalanceChanges {
|
|
||||||
res.BalanceChanges = append(res.BalanceChanges, encodingBalanceChange{
|
|
||||||
TxIdx: balanceChange.TxIdx,
|
|
||||||
Balance: balanceChange.Balance,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, nonceChange := range e.NonceChanges {
|
|
||||||
res.NonceChanges = append(res.NonceChanges, encodingAccountNonce{
|
|
||||||
TxIdx: nonceChange.TxIdx,
|
|
||||||
Nonce: nonceChange.Nonce,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if len(e.Code) == 1 {
|
if len(e.Code) == 1 {
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,13 @@ package bal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"cmp"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/testrand"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
@ -33,7 +36,7 @@ func equalBALs(a *BlockAccessList, b *BlockAccessList) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeTestBAL() *ConstructionBlockAccessList {
|
func makeTestConstructionBAL() *ConstructionBlockAccessList {
|
||||||
return &ConstructionBlockAccessList{
|
return &ConstructionBlockAccessList{
|
||||||
map[common.Address]*ConstructionAccountAccess{
|
map[common.Address]*ConstructionAccountAccess{
|
||||||
common.BytesToAddress([]byte{0xff, 0xff}): {
|
common.BytesToAddress([]byte{0xff, 0xff}): {
|
||||||
|
|
@ -90,7 +93,7 @@ func makeTestBAL() *ConstructionBlockAccessList {
|
||||||
// TestBALEncoding tests that a populated access list can be encoded/decoded correctly.
|
// TestBALEncoding tests that a populated access list can be encoded/decoded correctly.
|
||||||
func TestBALEncoding(t *testing.T) {
|
func TestBALEncoding(t *testing.T) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
bal := makeTestBAL()
|
bal := makeTestConstructionBAL()
|
||||||
err := bal.EncodeRLP(&buf)
|
err := bal.EncodeRLP(&buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("encoding failed: %v\n", err)
|
t.Fatalf("encoding failed: %v\n", err)
|
||||||
|
|
@ -107,22 +110,143 @@ func TestBALEncoding(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestBALEncoding tests that a populated access list can be encoded/decoded correctly.
|
func makeTestAccountAccess(sort bool) AccountAccess {
|
||||||
func TestBALFullRLPEncoding(t *testing.T) {
|
var (
|
||||||
var buf bytes.Buffer
|
storageWrites []encodingSlotWrites
|
||||||
bal := makeTestBAL()
|
storageReads [][32]byte
|
||||||
err := bal.EncodeRLP(&buf)
|
balances []encodingBalanceChange
|
||||||
if err != nil {
|
nonces []encodingAccountNonce
|
||||||
t.Fatalf("encoding failed: %v\n", err)
|
)
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
slot := encodingSlotWrites{
|
||||||
|
Slot: testrand.Hash(),
|
||||||
|
}
|
||||||
|
for j := 0; j < 3; j++ {
|
||||||
|
slot.Accesses = append(slot.Accesses, encodingStorageWrite{
|
||||||
|
TxIdx: uint16(2 * j),
|
||||||
|
ValueAfter: testrand.Hash(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if sort {
|
||||||
|
slices.SortFunc(slot.Accesses, func(a, b encodingStorageWrite) int {
|
||||||
|
return cmp.Compare[uint16](a.TxIdx, b.TxIdx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
storageWrites = append(storageWrites, slot)
|
||||||
}
|
}
|
||||||
var dec BlockAccessList
|
if sort {
|
||||||
if err := dec.DecodeRLP(rlp.NewStream(bytes.NewReader(buf.Bytes()), 10000000)); err != nil {
|
slices.SortFunc(storageWrites, func(a, b encodingSlotWrites) int {
|
||||||
t.Fatalf("decoding failed: %v\n", err)
|
return bytes.Compare(a.Slot[:], b.Slot[:])
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if dec.Hash() != bal.toEncodingObj().Hash() {
|
|
||||||
t.Fatalf("encoded block hash doesn't match decoded")
|
for i := 0; i < 5; i++ {
|
||||||
|
storageReads = append(storageReads, testrand.Hash())
|
||||||
}
|
}
|
||||||
if !equalBALs(bal.toEncodingObj(), &dec) {
|
if sort {
|
||||||
t.Fatal("decoded BAL doesn't match")
|
slices.SortFunc(storageReads, func(a, b [32]byte) int {
|
||||||
|
return bytes.Compare(a[:], b[:])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
balances = append(balances, encodingBalanceChange{
|
||||||
|
TxIdx: uint16(2 * i),
|
||||||
|
Balance: [16]byte(testrand.Bytes(16)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if sort {
|
||||||
|
slices.SortFunc(balances, func(a, b encodingBalanceChange) int {
|
||||||
|
return cmp.Compare[uint16](a.TxIdx, b.TxIdx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
nonces = append(nonces, encodingAccountNonce{
|
||||||
|
TxIdx: uint16(2 * i),
|
||||||
|
Nonce: uint64(i + 100),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if sort {
|
||||||
|
slices.SortFunc(nonces, func(a, b encodingAccountNonce) int {
|
||||||
|
return cmp.Compare[uint16](a.TxIdx, b.TxIdx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return AccountAccess{
|
||||||
|
Address: [20]byte(testrand.Bytes(20)),
|
||||||
|
StorageWrites: storageWrites,
|
||||||
|
StorageReads: storageReads,
|
||||||
|
BalanceChanges: balances,
|
||||||
|
NonceChanges: nonces,
|
||||||
|
Code: []CodeChange{
|
||||||
|
{
|
||||||
|
TxIndex: 100,
|
||||||
|
Code: testrand.Bytes(256),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeTestBAL(sort bool) BlockAccessList {
|
||||||
|
list := BlockAccessList{}
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
list.Accesses = append(list.Accesses, makeTestAccountAccess(sort))
|
||||||
|
}
|
||||||
|
if sort {
|
||||||
|
slices.SortFunc(list.Accesses, func(a, b AccountAccess) int {
|
||||||
|
return bytes.Compare(a.Address[:], b.Address[:])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBlockAccessListCopy(t *testing.T) {
|
||||||
|
list := makeTestBAL(true)
|
||||||
|
cpy := list.Copy()
|
||||||
|
cpyCpy := cpy.Copy()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(list, cpy) {
|
||||||
|
t.Fatal("block access mismatch")
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(cpy, cpyCpy) {
|
||||||
|
t.Fatal("block access mismatch")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the mutations on copy won't affect the origin
|
||||||
|
for _, aa := range cpyCpy.Accesses {
|
||||||
|
for i := 0; i < len(aa.StorageReads); i++ {
|
||||||
|
aa.StorageReads[i] = [32]byte(testrand.Bytes(32))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(list, cpy) {
|
||||||
|
t.Fatal("block access mismatch")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBlockAccessListValidation(t *testing.T) {
|
||||||
|
// Validate the block access list after RLP decoding
|
||||||
|
enc := makeTestBAL(true)
|
||||||
|
if err := enc.Validate(); err != nil {
|
||||||
|
t.Fatalf("Unexpected validation error: %v", err)
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := enc.EncodeRLP(&buf); err != nil {
|
||||||
|
t.Fatalf("Unexpected encoding error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dec BlockAccessList
|
||||||
|
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 {
|
||||||
|
t.Fatalf("Unexpected validation error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the derived block access list
|
||||||
|
cBAL := makeTestConstructionBAL()
|
||||||
|
listB := cBAL.toEncodingObj()
|
||||||
|
if err := listB.Validate(); err != nil {
|
||||||
|
t.Fatalf("Unexpected validation error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue