core, cmd, internal: rework BAL json marshalling to adhere EELS (#34972)
Some checks are pending
/ Linux Build (arm) (push) Waiting to run
/ Keeper Build (push) Waiting to run
/ Windows Build (push) Waiting to run
/ Docker Image (push) Waiting to run
/ Linux Build (push) Waiting to run

It's a change to BAL json marshalling and t8n tooling to adhere the EELS
definition.
This commit is contained in:
rjl493456442 2026-05-20 21:12:13 +08:00 committed by GitHub
parent 50ae34c1d8
commit 918d46b942
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 581 additions and 204 deletions

View file

@ -56,6 +56,8 @@ type header struct {
BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"`
ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"`
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
BlockAccessListHash *common.Hash `json:"blockAccessListHash" rlp:"optional"`
SlotNumber *uint64 `json:"slotNumber" rlp:"optional"`
}
@ -119,26 +121,28 @@ func (c *cliqueInput) UnmarshalJSON(input []byte) error {
// ToBlock converts i into a *types.Block
func (i *bbInput) ToBlock() *types.Block {
header := &types.Header{
ParentHash: i.Header.ParentHash,
UncleHash: types.EmptyUncleHash,
Coinbase: common.Address{},
Root: i.Header.Root,
TxHash: types.EmptyTxsHash,
ReceiptHash: types.EmptyReceiptsHash,
Bloom: i.Header.Bloom,
Difficulty: common.Big0,
Number: i.Header.Number,
GasLimit: i.Header.GasLimit,
GasUsed: i.Header.GasUsed,
Time: i.Header.Time,
Extra: i.Header.Extra,
MixDigest: i.Header.MixDigest,
BaseFee: i.Header.BaseFee,
WithdrawalsHash: i.Header.WithdrawalsHash,
BlobGasUsed: i.Header.BlobGasUsed,
ExcessBlobGas: i.Header.ExcessBlobGas,
ParentBeaconRoot: i.Header.ParentBeaconBlockRoot,
SlotNumber: i.Header.SlotNumber,
ParentHash: i.Header.ParentHash,
UncleHash: types.EmptyUncleHash,
Coinbase: common.Address{},
Root: i.Header.Root,
TxHash: types.EmptyTxsHash,
ReceiptHash: types.EmptyReceiptsHash,
Bloom: i.Header.Bloom,
Difficulty: common.Big0,
Number: i.Header.Number,
GasLimit: i.Header.GasLimit,
GasUsed: i.Header.GasUsed,
Time: i.Header.Time,
Extra: i.Header.Extra,
MixDigest: i.Header.MixDigest,
BaseFee: i.Header.BaseFee,
WithdrawalsHash: i.Header.WithdrawalsHash,
BlobGasUsed: i.Header.BlobGasUsed,
ExcessBlobGas: i.Header.ExcessBlobGas,
ParentBeaconRoot: i.Header.ParentBeaconBlockRoot,
RequestsHash: i.Header.RequestsHash,
BlockAccessListHash: i.Header.BlockAccessListHash,
SlotNumber: i.Header.SlotNumber,
}
// Fill optional values.

View file

@ -76,6 +76,9 @@ type ExecutionResult struct {
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
RequestsHash *common.Hash `json:"requestsHash,omitempty"`
Requests [][]byte `json:"requests"`
BlockAccessList *bal.BlockAccessList `json:"blockAccessList,omitempty"`
BlockAccessListHash *common.Hash `json:"blockAccessListHash,omitempty"`
}
type executionResultMarshaling struct {
@ -153,8 +156,10 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
return h
}
var (
isEIP4762 = chainConfig.IsUBT(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp)
statedb *state.StateDB
statedb *state.StateDB
isEIP4762 = chainConfig.IsUBT(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp)
isAmsterdam = chainConfig.IsAmsterdam(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp)
)
if pre.AllocPath != "" {
var err error
@ -299,9 +304,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
receipts = append(receipts, receipt)
blockAccessList.Merge(bal)
}
statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber))
// TODO(rjl493456442) call engine.Finalize() instead
// Add mining reward? (-1 means rewards are disabled)
if miningReward >= 0 {
// Add mining reward. The mining reward may be `0`, which only makes a difference in the cases
@ -330,11 +335,22 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
for _, w := range pre.Env.Withdrawals {
// Amount is in gwei, turn into wei
amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei))
statedb.AddBalance(w.Address, uint256.MustFromBig(amount), tracing.BalanceIncreaseWithdrawal)
prev := statedb.AddBalance(w.Address, uint256.MustFromBig(amount), tracing.BalanceIncreaseWithdrawal)
if isEIP4762 {
statedb.AccessEvents().AddAccount(w.Address, true, stdmath.MaxUint64)
}
if isAmsterdam {
if w.Amount == 0 {
// Zero amount withdrawal, account is accessed potential
// without state changes.
blockAccessList.AccountRead(w.Address)
} else {
// Non-zero amount withdrawal, account is accessed with
// a balance change.
blockAccessList.BalanceChange(uint32(len(receipts)+1), w.Address, new(uint256.Int).Add(&prev, uint256.MustFromBig(amount)))
}
}
}
// Gather the execution-layer triggered requests.
@ -379,6 +395,12 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
execRs.RequestsHash = &h
execRs.Requests = requests
}
if isAmsterdam {
bal := blockAccessList.ToEncodingObj()
balHash := bal.Hash()
execRs.BlockAccessListHash = &balHash
execRs.BlockAccessList = bal
}
// Re-create statedb instance with new root for MPT mode
statedb, err = state.New(root, statedb.Database())

View file

@ -10,6 +10,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types/bal"
)
var _ = (*executionResultMarshaling)(nil)
@ -32,6 +33,8 @@ func (e ExecutionResult) MarshalJSON() ([]byte, error) {
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
RequestsHash *common.Hash `json:"requestsHash,omitempty"`
Requests []hexutil.Bytes `json:"requests"`
BlockAccessList *bal.BlockAccessList `json:"blockAccessList,omitempty"`
BlockAccessListHash *common.Hash `json:"blockAccessListHash,omitempty"`
}
var enc ExecutionResult
enc.StateRoot = e.StateRoot
@ -54,6 +57,8 @@ func (e ExecutionResult) MarshalJSON() ([]byte, error) {
enc.Requests[k] = v
}
}
enc.BlockAccessList = e.BlockAccessList
enc.BlockAccessListHash = e.BlockAccessListHash
return json.Marshal(&enc)
}
@ -75,6 +80,8 @@ func (e *ExecutionResult) UnmarshalJSON(input []byte) error {
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed,omitempty"`
RequestsHash *common.Hash `json:"requestsHash,omitempty"`
Requests []hexutil.Bytes `json:"requests"`
BlockAccessList *bal.BlockAccessList `json:"blockAccessList,omitempty"`
BlockAccessListHash *common.Hash `json:"blockAccessListHash,omitempty"`
}
var dec ExecutionResult
if err := json.Unmarshal(input, &dec); err != nil {
@ -130,5 +137,11 @@ func (e *ExecutionResult) UnmarshalJSON(input []byte) error {
e.Requests[k] = v
}
}
if dec.BlockAccessList != nil {
e.BlockAccessList = dec.BlockAccessList
}
if dec.BlockAccessListHash != nil {
e.BlockAccessListHash = dec.BlockAccessListHash
}
return nil
}

View file

@ -38,6 +38,8 @@ func (h header) MarshalJSON() ([]byte, error) {
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed" rlp:"optional"`
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas" rlp:"optional"`
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
BlockAccessListHash *common.Hash `json:"blockAccessListHash" rlp:"optional"`
SlotNumber *math.HexOrDecimal64 `json:"slotNumber" rlp:"optional"`
}
var enc header
@ -61,6 +63,8 @@ func (h header) MarshalJSON() ([]byte, error) {
enc.BlobGasUsed = (*math.HexOrDecimal64)(h.BlobGasUsed)
enc.ExcessBlobGas = (*math.HexOrDecimal64)(h.ExcessBlobGas)
enc.ParentBeaconBlockRoot = h.ParentBeaconBlockRoot
enc.RequestsHash = h.RequestsHash
enc.BlockAccessListHash = h.BlockAccessListHash
enc.SlotNumber = (*math.HexOrDecimal64)(h.SlotNumber)
return json.Marshal(&enc)
}
@ -88,6 +92,8 @@ func (h *header) UnmarshalJSON(input []byte) error {
BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed" rlp:"optional"`
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas" rlp:"optional"`
ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
BlockAccessListHash *common.Hash `json:"blockAccessListHash" rlp:"optional"`
SlotNumber *math.HexOrDecimal64 `json:"slotNumber" rlp:"optional"`
}
var dec header
@ -158,6 +164,12 @@ func (h *header) UnmarshalJSON(input []byte) error {
if dec.ParentBeaconBlockRoot != nil {
h.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot
}
if dec.RequestsHash != nil {
h.RequestsHash = dec.RequestsHash
}
if dec.BlockAccessListHash != nil {
h.BlockAccessListHash = dec.BlockAccessListHash
}
if dec.SlotNumber != nil {
h.SlotNumber = (*uint64)(dec.SlotNumber)
}

View file

@ -121,7 +121,7 @@ func hasStorageWrite(b *bal.BlockAccessList, addr common.Address, key common.Has
return false
}
want := new(uint256.Int).SetBytes(key[:])
for _, w := range aa.StorageWrites {
for _, w := range aa.StorageChanges {
if w.Slot.Cmp(want) == 0 {
return true
}
@ -147,7 +147,7 @@ func assertAbsent(t *testing.T, b *bal.BlockAccessList, addr common.Address) {
func assertEmpty(t *testing.T, aa *bal.AccountAccess) {
t.Helper()
if len(aa.StorageWrites) != 0 || len(aa.StorageReads) != 0 ||
if len(aa.StorageChanges) != 0 || len(aa.StorageReads) != 0 ||
len(aa.BalanceChanges) != 0 || len(aa.NonceChanges) != 0 || len(aa.CodeChanges) != 0 {
t.Fatalf("expected empty change set for %x, got %+v", aa.Address, aa)
}
@ -181,14 +181,14 @@ func TestBALTxSenderAndRecipient(t *testing.T) {
})
sender := assertPresent(t, b, env.from)
if len(sender.NonceChanges) == 0 || sender.NonceChanges[0].Nonce != 1 {
if len(sender.NonceChanges) == 0 || sender.NonceChanges[0].PostNonce != 1 {
t.Fatalf("sender nonce not bumped: %+v", sender.NonceChanges)
}
if len(sender.BalanceChanges) == 0 {
t.Fatalf("sender missing balance change")
}
recipient := assertPresent(t, b, to)
if len(recipient.BalanceChanges) != 1 || recipient.BalanceChanges[0].Balance.Uint64() != 1000 {
if len(recipient.BalanceChanges) != 1 || recipient.BalanceChanges[0].PostBalance.Uint64() != 1000 {
t.Fatalf("recipient balance: %+v", recipient.BalanceChanges)
}
}
@ -236,7 +236,7 @@ func TestBALCoinbaseTipCapturesBalance(t *testing.T) {
})
cb := assertPresent(t, b, coinbase)
if len(cb.BalanceChanges) == 0 || cb.BalanceChanges[0].Balance.Sign() == 0 {
if len(cb.BalanceChanges) == 0 || cb.BalanceChanges[0].PostBalance.Sign() == 0 {
t.Fatalf("coinbase missing positive balance change: %+v", cb.BalanceChanges)
}
}
@ -264,7 +264,7 @@ func TestBALSystemAddressIncludedWhenTouched(t *testing.T) {
})
aa := assertPresent(t, b, sys)
if len(aa.BalanceChanges) != 1 || aa.BalanceChanges[0].Balance.Uint64() != 1000 {
if len(aa.BalanceChanges) != 1 || aa.BalanceChanges[0].PostBalance.Uint64() != 1000 {
t.Fatalf("system-address balance change missing: %+v", aa.BalanceChanges)
}
}
@ -319,7 +319,7 @@ func TestBALPrecompileValueTransferRecordsBalance(t *testing.T) {
})
aa := assertPresent(t, b, identity)
if len(aa.BalanceChanges) != 1 || aa.BalanceChanges[0].Balance.Uint64() != 5 {
if len(aa.BalanceChanges) != 1 || aa.BalanceChanges[0].PostBalance.Uint64() != 5 {
t.Fatalf("precompile balance change wrong: %+v", aa.BalanceChanges)
}
}
@ -537,7 +537,7 @@ func TestBALSenderRecordedOnRevert(t *testing.T) {
})
sender := assertPresent(t, b, env.from)
if len(sender.NonceChanges) == 0 || sender.NonceChanges[0].Nonce != 1 {
if len(sender.NonceChanges) == 0 || sender.NonceChanges[0].PostNonce != 1 {
t.Fatalf("sender nonce must be bumped even on revert: %+v", sender.NonceChanges)
}
if len(sender.BalanceChanges) == 0 {
@ -667,10 +667,10 @@ func TestBALStorageWriteZeroIsAWrite(t *testing.T) {
if !hasStorageWrite(b, contract, slot) {
t.Fatalf("SSTORE to zero must record a write\n%s", b.PrettyPrint())
}
for _, w := range aa.StorageWrites {
for _, w := range aa.StorageChanges {
if w.Slot.Uint64() == 0x03 {
if len(w.Accesses) != 1 || !w.Accesses[0].ValueAfter.IsZero() {
t.Fatalf("expected post-value 0 for slot 0x03, got %+v", w.Accesses)
if len(w.SlotChanges) != 1 || !w.SlotChanges[0].PostValue.IsZero() {
t.Fatalf("expected post-value 0 for slot 0x03, got %+v", w.SlotChanges)
}
}
}
@ -692,13 +692,13 @@ func TestBALCreateDeploysCode(t *testing.T) {
created := receipts[0].ContractAddress
aa := assertPresent(t, b, created)
if len(aa.NonceChanges) != 1 || aa.NonceChanges[0].Nonce != 1 {
if len(aa.NonceChanges) != 1 || aa.NonceChanges[0].PostNonce != 1 {
t.Fatalf("expected nonce 0→1, got %+v", aa.NonceChanges)
}
if len(aa.CodeChanges) != 1 || !bytes.Equal(aa.CodeChanges[0].Code, []byte{0x00}) {
if len(aa.CodeChanges) != 1 || !bytes.Equal(aa.CodeChanges[0].NewCode, []byte{0x00}) {
t.Fatalf("expected code [0x00], got %+v", aa.CodeChanges)
}
if len(aa.BalanceChanges) != 1 || aa.BalanceChanges[0].Balance.Uint64() != 7 {
if len(aa.BalanceChanges) != 1 || aa.BalanceChanges[0].PostBalance.Uint64() != 7 {
t.Fatalf("expected balance 7, got %+v", aa.BalanceChanges)
}
}
@ -716,7 +716,7 @@ func TestBALCreateEmptyRuntimeNoCodeEntry(t *testing.T) {
created := receipts[0].ContractAddress
aa := assertPresent(t, b, created)
if len(aa.NonceChanges) != 1 || aa.NonceChanges[0].Nonce != 1 {
if len(aa.NonceChanges) != 1 || aa.NonceChanges[0].PostNonce != 1 {
t.Fatalf("expected nonce 0→1, got %+v", aa.NonceChanges)
}
if len(aa.CodeChanges) != 0 {
@ -849,7 +849,7 @@ func TestBALInEVMCreateDeploysContract(t *testing.T) {
// which is the factory's genesis nonce (1).
deployed := crypto.CreateAddress(factory, 1)
aa := assertPresent(t, b, deployed)
if len(aa.NonceChanges) != 1 || aa.NonceChanges[0].Nonce != 1 {
if len(aa.NonceChanges) != 1 || aa.NonceChanges[0].PostNonce != 1 {
t.Fatalf("deployed contract nonce: %+v", aa.NonceChanges)
}
}
@ -900,7 +900,7 @@ func TestBALSelfDestructBeneficiaryWithValueTransfer(t *testing.T) {
})
ben := assertPresent(t, b, beneficiary)
if len(ben.BalanceChanges) != 1 || ben.BalanceChanges[0].Balance.Uint64() != 100 {
if len(ben.BalanceChanges) != 1 || ben.BalanceChanges[0].PostBalance.Uint64() != 100 {
t.Fatalf("beneficiary balance must be credited with 100: %+v", ben.BalanceChanges)
}
}
@ -925,11 +925,11 @@ func TestBALSelfDestructPreExistingContract(t *testing.T) {
})
aa := assertPresent(t, b, suicidal)
if len(aa.BalanceChanges) != 1 || !aa.BalanceChanges[0].Balance.IsZero() {
if len(aa.BalanceChanges) != 1 || !aa.BalanceChanges[0].PostBalance.IsZero() {
t.Fatalf("suicidal contract balance should drop to 0: %+v", aa.BalanceChanges)
}
ben := assertPresent(t, b, beneficiary)
if len(ben.BalanceChanges) != 1 || ben.BalanceChanges[0].Balance.Uint64() != 50 {
if len(ben.BalanceChanges) != 1 || ben.BalanceChanges[0].PostBalance.Uint64() != 50 {
t.Fatalf("beneficiary should receive 50: %+v", ben.BalanceChanges)
}
}
@ -1041,7 +1041,7 @@ func TestBALWithdrawalNonZeroAmountRecordsBalance(t *testing.T) {
})
r := assertPresent(t, b, recipient)
if len(r.BalanceChanges) != 1 || r.BalanceChanges[0].Balance.Sign() == 0 {
if len(r.BalanceChanges) != 1 || r.BalanceChanges[0].PostBalance.Sign() == 0 {
t.Fatalf("withdrawal balance change missing: %+v", r.BalanceChanges)
}
}
@ -1266,7 +1266,7 @@ func TestBALAuthCodeRoundTripNoCodeEntry(t *testing.T) {
})
aa := assertPresent(t, b, authority)
if len(aa.NonceChanges) != 1 || aa.NonceChanges[0].Nonce != 2 {
if len(aa.NonceChanges) != 1 || aa.NonceChanges[0].PostNonce != 2 {
t.Fatalf("expected final nonce 2, got %+v", aa.NonceChanges)
}
if len(aa.CodeChanges) != 0 {
@ -1310,10 +1310,10 @@ func TestBALAuthCodeOverwrittenFinalRecorded(t *testing.T) {
t.Fatalf("expected exactly 1 code change (final), got %+v", aa.CodeChanges)
}
want := types.AddressToDelegation(delegateB)
if !bytes.Equal(aa.CodeChanges[0].Code, want) {
t.Fatalf("final code mismatch: want %x, got %x", want, aa.CodeChanges[0].Code)
if !bytes.Equal(aa.CodeChanges[0].NewCode, want) {
t.Fatalf("final code mismatch: want %x, got %x", want, aa.CodeChanges[0].NewCode)
}
if len(aa.NonceChanges) != 1 || aa.NonceChanges[0].Nonce != 2 {
if len(aa.NonceChanges) != 1 || aa.NonceChanges[0].PostNonce != 2 {
t.Fatalf("expected final nonce 2, got %+v", aa.NonceChanges)
}
}

View file

@ -27,6 +27,7 @@ import (
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
@ -99,7 +100,7 @@ func (e *BlockAccessList) Validate(blockGasLimit uint64, blockTxCount int) error
func (e *BlockAccessList) itemCount() uint64 {
count := uint64(len(*e)) // distinct addresses
for i := range *e {
count += uint64(len((*e)[i].StorageWrites)) + uint64(len((*e)[i].StorageReads))
count += uint64(len((*e)[i].StorageChanges)) + uint64(len((*e)[i].StorageReads))
}
return count
}
@ -130,28 +131,38 @@ func (e *BlockAccessList) Hash() common.Hash {
return crypto.Keccak256Hash(enc.Bytes())
}
// encodingBalanceChange is the encoding format of BalanceChange.
type encodingBalanceChange struct {
TxIdx uint32
Balance *uint256.Int
}
// EIP-7928 encoding types. Field names and JSON keys mirror the
// execution-spec-tests Pydantic models in
// `src/ethereum_test_types/block_access_list/account_changes.py`. Hex
// formatting on JSON output is supplied via the gencodec overrides
// below.
// encodingAccountNonce is the encoding format of NonceChange.
type encodingAccountNonce struct {
TxIdx uint32
Nonce uint64
}
//go:generate go run github.com/fjl/gencodec -type encodingStorageWrite -field-override encodingStorageWriteMarshaling -out gen_encoding_storage_write_json.go
//go:generate go run github.com/fjl/gencodec -type encodingSlotChanges -field-override encodingSlotChangesMarshaling -out gen_encoding_slot_changes_json.go
//go:generate go run github.com/fjl/gencodec -type encodingBalanceChange -field-override encodingBalanceChangeMarshaling -out gen_encoding_balance_change_json.go
//go:generate go run github.com/fjl/gencodec -type encodingAccountNonce -field-override encodingAccountNonceMarshaling -out gen_encoding_account_nonce_json.go
//go:generate go run github.com/fjl/gencodec -type encodingCodeChange -field-override encodingCodeChangeMarshaling -out gen_encoding_code_change_json.go
//go:generate go run github.com/fjl/gencodec -type AccountAccess -field-override accountAccessMarshaling -out gen_account_access_json.go
// encodingStorageWrite is the encoding format of StorageWrites.
// encodingStorageWrite is one transaction's write to a storage slot.
type encodingStorageWrite struct {
TxIdx uint32
ValueAfter *uint256.Int
BlockAccessIndex uint32 `json:"blockAccessIndex"`
PostValue *uint256.Int `json:"postValue"`
}
// encodingStorageWrite is the encoding format of SlotWrites.
type encodingSlotWrites struct {
Slot *uint256.Int
Accesses []encodingStorageWrite
type encodingStorageWriteMarshaling struct {
BlockAccessIndex hexutil.Uint64
PostValue *hexutil.U256
}
// encodingSlotChanges aggregates all per-tx writes to a single storage slot.
type encodingSlotChanges struct {
Slot *uint256.Int `json:"slot"`
SlotChanges []encodingStorageWrite `json:"slotChanges"`
}
type encodingSlotChangesMarshaling struct {
Slot *hexutil.U256
}
func isStrictlySortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool {
@ -166,33 +177,63 @@ func isStrictlySortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool {
// validate asserts that the encodingSlotWrites contain storage modfications
// which are ordered ascending by transaction index and contain no duplicate
// modifications for a given index.
func (e *encodingSlotWrites) validate(maxBALIndex int) error {
if !isStrictlySortedFunc(e.Accesses, func(a, b encodingStorageWrite) int {
return cmp.Compare(a.TxIdx, b.TxIdx)
func (e *encodingSlotChanges) validate(maxBALIndex int) error {
if !isStrictlySortedFunc(e.SlotChanges, func(a, b encodingStorageWrite) int {
return cmp.Compare(a.BlockAccessIndex, b.BlockAccessIndex)
}) {
return errors.New("storage write indexes must be unique and sorted")
}
if len(e.Accesses) > 0 && int(e.Accesses[len(e.Accesses)-1].TxIdx) > maxBALIndex {
return fmt.Errorf("storage write index exceeds limit, index: %d, limit: %d", e.Accesses[len(e.Accesses)-1].TxIdx, maxBALIndex)
if len(e.SlotChanges) > 0 && int(e.SlotChanges[len(e.SlotChanges)-1].BlockAccessIndex) > maxBALIndex {
return fmt.Errorf("storage write index exceeds limit, index: %d, limit: %d", e.SlotChanges[len(e.SlotChanges)-1].BlockAccessIndex, maxBALIndex)
}
return nil
}
// encodingCodeChange contains the runtime bytecode deployed at an address
// and the transaction index where the deployment took place.
// encodingBalanceChange is one transaction's post-state balance for an account.
type encodingBalanceChange struct {
BlockAccessIndex uint32 `json:"blockAccessIndex"`
PostBalance *uint256.Int `json:"postBalance"`
}
type encodingBalanceChangeMarshaling struct {
BlockAccessIndex hexutil.Uint64
PostBalance *hexutil.U256
}
// encodingAccountNonce is one transaction's post-state nonce for an account.
type encodingAccountNonce struct {
BlockAccessIndex uint32 `json:"blockAccessIndex"`
PostNonce uint64 `json:"postNonce"`
}
type encodingAccountNonceMarshaling struct {
BlockAccessIndex hexutil.Uint64
PostNonce hexutil.Uint64
}
// encodingCodeChange is one transaction's deployed runtime bytecode for an account.
type encodingCodeChange struct {
TxIndex uint32
Code []byte
BlockAccessIndex uint32 `json:"blockAccessIndex"`
NewCode []byte `json:"newCode"`
}
type encodingCodeChangeMarshaling struct {
BlockAccessIndex hexutil.Uint64
NewCode hexutil.Bytes
}
// AccountAccess is the encoding format of ConstructionAccountAccess.
type AccountAccess struct {
Address [20]byte // 20-byte Ethereum address
StorageWrites []encodingSlotWrites // Storage changes (slot -> [tx_index -> new_value])
StorageReads []*uint256.Int // Read-only storage keys
BalanceChanges []encodingBalanceChange // Balance changes ([tx_index -> post_balance])
NonceChanges []encodingAccountNonce // Nonce changes ([tx_index -> new_nonce])
CodeChanges []encodingCodeChange // Code changes ([tx_index -> new_code])
Address common.Address `json:"address"`
StorageChanges []encodingSlotChanges `json:"storageChanges"`
StorageReads []*uint256.Int `json:"storageReads"`
BalanceChanges []encodingBalanceChange `json:"balanceChanges"`
NonceChanges []encodingAccountNonce `json:"nonceChanges"`
CodeChanges []encodingCodeChange `json:"codeChanges"`
}
type accountAccessMarshaling struct {
StorageReads []*hexutil.U256
}
// validate converts the account accesses out of encoding format.
@ -200,13 +241,13 @@ type AccountAccess struct {
// spec, an error is returned.
func (e *AccountAccess) validate(maxBALIndex int) error {
// Check the storage writes are sorted in order, and unique by slot
if !isStrictlySortedFunc(e.StorageWrites, func(a, b encodingSlotWrites) int {
if !isStrictlySortedFunc(e.StorageChanges, func(a, b encodingSlotChanges) int {
return a.Slot.Cmp(b.Slot)
}) {
return errors.New("storage write slots must be unique and sorted")
}
// Check the validity of each storage slot's mutations
for _, slotWrites := range e.StorageWrites {
for _, slotWrites := range e.StorageChanges {
if err := slotWrites.validate(maxBALIndex); err != nil {
return err
}
@ -223,13 +264,13 @@ func (e *AccountAccess) validate(maxBALIndex int) error {
// set of read slots.
var (
readKeys = make(map[common.Hash]struct{}, len(e.StorageReads))
writeKeys = make(map[common.Hash]struct{}, len(e.StorageWrites))
writeKeys = make(map[common.Hash]struct{}, len(e.StorageChanges))
)
for _, rk := range e.StorageReads {
readKey := common.BytesToHash(rk.Bytes())
readKeys[readKey] = struct{}{}
}
for _, write := range e.StorageWrites {
for _, write := range e.StorageChanges {
writeKey := common.BytesToHash(write.Slot.Bytes())
writeKeys[writeKey] = struct{}{}
}
@ -241,42 +282,42 @@ func (e *AccountAccess) validate(maxBALIndex int) error {
// Check the balance changes are sorted in order, and unique by tx index
if !isStrictlySortedFunc(e.BalanceChanges, func(a, b encodingBalanceChange) int {
return cmp.Compare(a.TxIdx, b.TxIdx)
return cmp.Compare(a.BlockAccessIndex, b.BlockAccessIndex)
}) {
return errors.New("balance changes must be unique and sorted")
}
// check that the tx index is not greater than the max allowed for the block
if len(e.BalanceChanges) > 0 && int(e.BalanceChanges[len(e.BalanceChanges)-1].TxIdx) > maxBALIndex {
return fmt.Errorf("balance change index exceeds limit, index: %d, limit: %d", e.BalanceChanges[len(e.BalanceChanges)-1].TxIdx, maxBALIndex)
if len(e.BalanceChanges) > 0 && int(e.BalanceChanges[len(e.BalanceChanges)-1].BlockAccessIndex) > maxBALIndex {
return fmt.Errorf("balance change index exceeds limit, index: %d, limit: %d", e.BalanceChanges[len(e.BalanceChanges)-1].BlockAccessIndex, maxBALIndex)
}
// Check the nonce changes are sorted in order, and unique by tx index
if !isStrictlySortedFunc(e.NonceChanges, func(a, b encodingAccountNonce) int {
return cmp.Compare(a.TxIdx, b.TxIdx)
return cmp.Compare(a.BlockAccessIndex, b.BlockAccessIndex)
}) {
return errors.New("nonce changes must be unique and sorted")
}
// check that the tx index of the highest nonce change is not greater than
// the max allowed for the block
if len(e.NonceChanges) > 0 && int(e.NonceChanges[len(e.NonceChanges)-1].TxIdx) > maxBALIndex {
return fmt.Errorf("nonce change index exceeds limit, index: %d, limit: %d", e.NonceChanges[len(e.NonceChanges)-1].TxIdx, maxBALIndex)
if len(e.NonceChanges) > 0 && int(e.NonceChanges[len(e.NonceChanges)-1].BlockAccessIndex) > maxBALIndex {
return fmt.Errorf("nonce change index exceeds limit, index: %d, limit: %d", e.NonceChanges[len(e.NonceChanges)-1].BlockAccessIndex, maxBALIndex)
}
// Check the code changes are sorted in order, and unique by tx index
if !isStrictlySortedFunc(e.CodeChanges, func(a, b encodingCodeChange) int {
return cmp.Compare(a.TxIndex, b.TxIndex)
return cmp.Compare(a.BlockAccessIndex, b.BlockAccessIndex)
}) {
return errors.New("code changes must be unique and sorted")
}
// check that the tx index of the highest code changeis not greater than the
// max allowed for the block
if len(e.CodeChanges) > 0 && int(e.CodeChanges[len(e.CodeChanges)-1].TxIndex) > maxBALIndex {
return fmt.Errorf("code change index exceeds limit, index: %d, limit: %d", e.CodeChanges[len(e.CodeChanges)-1].TxIndex, maxBALIndex)
if len(e.CodeChanges) > 0 && int(e.CodeChanges[len(e.CodeChanges)-1].BlockAccessIndex) > maxBALIndex {
return fmt.Errorf("code change index exceeds limit, index: %d, limit: %d", e.CodeChanges[len(e.CodeChanges)-1].BlockAccessIndex, maxBALIndex)
}
// Check that none of the code changes report a new code which is larger
// than the max allowed by the protocol
for _, change := range e.CodeChanges {
if len(change.Code) > params.MaxCodeSizeAmsterdam {
if len(change.NewCode) > params.MaxCodeSizeAmsterdam {
return errors.New("code change contained oversized code")
}
}
@ -290,7 +331,7 @@ func (e *AccountAccess) Copy() AccountAccess {
StorageReads: make([]*uint256.Int, 0, len(e.StorageReads)),
BalanceChanges: make([]encodingBalanceChange, 0, len(e.BalanceChanges)),
NonceChanges: slices.Clone(e.NonceChanges),
StorageWrites: make([]encodingSlotWrites, 0, len(e.StorageWrites)),
StorageChanges: make([]encodingSlotChanges, 0, len(e.StorageChanges)),
CodeChanges: make([]encodingCodeChange, 0, len(e.CodeChanges)),
}
for _, slot := range e.StorageReads {
@ -298,27 +339,27 @@ func (e *AccountAccess) Copy() AccountAccess {
}
for _, change := range e.BalanceChanges {
res.BalanceChanges = append(res.BalanceChanges, encodingBalanceChange{
TxIdx: change.TxIdx,
Balance: change.Balance.Clone(),
BlockAccessIndex: change.BlockAccessIndex,
PostBalance: change.PostBalance.Clone(),
})
}
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(),
for _, slot := range e.StorageChanges {
writes := make([]encodingStorageWrite, 0, len(slot.SlotChanges))
for _, w := range slot.SlotChanges {
writes = append(writes, encodingStorageWrite{
BlockAccessIndex: w.BlockAccessIndex,
PostValue: w.PostValue.Clone(),
})
}
res.StorageWrites = append(res.StorageWrites, encodingSlotWrites{
Slot: storageWrite.Slot.Clone(),
Accesses: accesses,
res.StorageChanges = append(res.StorageChanges, encodingSlotChanges{
Slot: slot.Slot.Clone(),
SlotChanges: writes,
})
}
for _, codeChange := range e.CodeChanges {
res.CodeChanges = append(res.CodeChanges, encodingCodeChange{
TxIndex: codeChange.TxIndex,
Code: bytes.Clone(codeChange.Code),
BlockAccessIndex: codeChange.BlockAccessIndex,
NewCode: bytes.Clone(codeChange.NewCode),
})
}
return res
@ -336,7 +377,7 @@ var _ rlp.Encoder = &ConstructionBlockAccessList{}
func (a *ConstructionAccountAccess) toEncodingObj(addr common.Address) AccountAccess {
res := AccountAccess{
Address: addr,
StorageWrites: make([]encodingSlotWrites, 0, len(a.StorageWrites)),
StorageChanges: make([]encodingSlotChanges, 0, len(a.StorageWrites)),
StorageReads: make([]*uint256.Int, 0, len(a.StorageReads)),
BalanceChanges: make([]encodingBalanceChange, 0, len(a.BalanceChanges)),
NonceChanges: make([]encodingAccountNonce, 0, len(a.NonceChanges)),
@ -347,22 +388,22 @@ func (a *ConstructionAccountAccess) toEncodingObj(addr common.Address) AccountAc
writeSlots := slices.Collect(maps.Keys(a.StorageWrites))
slices.SortFunc(writeSlots, common.Hash.Cmp)
for _, slot := range writeSlots {
obj := encodingSlotWrites{
obj := encodingSlotChanges{
Slot: new(uint256.Int).SetBytes(slot[:]),
}
slotWrites := a.StorageWrites[slot]
obj.Accesses = make([]encodingStorageWrite, 0, len(slotWrites))
obj.SlotChanges = make([]encodingStorageWrite, 0, len(slotWrites))
indices := slices.Collect(maps.Keys(slotWrites))
slices.SortFunc(indices, cmp.Compare[uint32])
slices.SortFunc(indices, cmp.Compare)
for _, index := range indices {
val := slotWrites[index]
obj.Accesses = append(obj.Accesses, encodingStorageWrite{
TxIdx: index,
ValueAfter: new(uint256.Int).SetBytes(val[:]),
obj.SlotChanges = append(obj.SlotChanges, encodingStorageWrite{
BlockAccessIndex: index,
PostValue: new(uint256.Int).SetBytes(val[:]),
})
}
res.StorageWrites = append(res.StorageWrites, obj)
res.StorageChanges = append(res.StorageChanges, obj)
}
// Convert read slots
@ -374,36 +415,36 @@ func (a *ConstructionAccountAccess) toEncodingObj(addr common.Address) AccountAc
// Convert balance changes
balanceIndices := slices.Collect(maps.Keys(a.BalanceChanges))
slices.SortFunc(balanceIndices, cmp.Compare[uint32])
slices.SortFunc(balanceIndices, cmp.Compare)
for _, idx := range balanceIndices {
res.BalanceChanges = append(res.BalanceChanges, encodingBalanceChange{
TxIdx: idx,
Balance: a.BalanceChanges[idx].Clone(),
BlockAccessIndex: idx,
PostBalance: a.BalanceChanges[idx].Clone(),
})
}
// Convert nonce changes
nonceIndices := slices.Collect(maps.Keys(a.NonceChanges))
slices.SortFunc(nonceIndices, cmp.Compare[uint32])
slices.SortFunc(nonceIndices, cmp.Compare)
for _, idx := range nonceIndices {
res.NonceChanges = append(res.NonceChanges, encodingAccountNonce{
TxIdx: idx,
Nonce: a.NonceChanges[idx],
BlockAccessIndex: idx,
PostNonce: a.NonceChanges[idx],
})
}
// Convert code change
codeIndices := slices.Collect(maps.Keys(a.CodeChange))
slices.SortFunc(codeIndices, cmp.Compare[uint32])
slices.SortFunc(codeIndices, cmp.Compare)
for _, idx := range codeIndices {
res.CodeChanges = append(res.CodeChanges, encodingCodeChange{
TxIndex: idx,
BlockAccessIndex: idx,
// TODO(rjl493456442) the contract code is not deep-copied.
// In theory the deep-copy is unnecessary, the semantics of
// the function should be probably changed that the returned
// AccessList is unsafe for modification.
Code: a.CodeChange[idx],
NewCode: a.CodeChange[idx],
})
}
return res
@ -432,33 +473,28 @@ func (e *BlockAccessList) PrettyPrint() string {
}
for _, accountDiff := range *e {
printWithIndent(0, fmt.Sprintf("%x:", accountDiff.Address))
printWithIndent(1, "storage writes:")
for _, sWrite := range accountDiff.StorageWrites {
printWithIndent(2, fmt.Sprintf("%s:", sWrite.Slot.Hex()))
for _, access := range sWrite.Accesses {
printWithIndent(3, fmt.Sprintf("%d: %s", access.TxIdx, access.ValueAfter.Hex()))
printWithIndent(1, "storage changes:")
for _, slot := range accountDiff.StorageChanges {
printWithIndent(2, fmt.Sprintf("%s:", slot.Slot.Hex()))
for _, access := range slot.SlotChanges {
printWithIndent(3, fmt.Sprintf("%d: %s", access.BlockAccessIndex, access.PostValue.Hex()))
}
}
printWithIndent(1, "storage reads:")
for _, slot := range accountDiff.StorageReads {
printWithIndent(2, slot.Hex())
}
printWithIndent(1, "balance changes:")
for _, change := range accountDiff.BalanceChanges {
printWithIndent(2, fmt.Sprintf("%d: %s", change.TxIdx, change.Balance))
printWithIndent(2, fmt.Sprintf("%d: %s", change.BlockAccessIndex, change.PostBalance))
}
printWithIndent(1, "nonce changes:")
for _, change := range accountDiff.NonceChanges {
printWithIndent(2, fmt.Sprintf("%d: %d", change.TxIdx, change.Nonce))
printWithIndent(2, fmt.Sprintf("%d: %d", change.BlockAccessIndex, change.PostNonce))
}
printWithIndent(1, "code changes:")
for _, change := range accountDiff.CodeChanges {
printWithIndent(2, fmt.Sprintf("%d: %x", change.TxIndex, change.Code))
printWithIndent(2, fmt.Sprintf("%d: %x", change.BlockAccessIndex, change.NewCode))
}
}
return res.String()

View file

@ -2,6 +2,7 @@
package bal
import "github.com/ethereum/go-ethereum/common"
import "github.com/ethereum/go-ethereum/rlp"
import "github.com/holiman/uint256"
import "io"
@ -11,7 +12,7 @@ func (obj *AccountAccess) EncodeRLP(_w io.Writer) error {
_tmp0 := w.List()
w.WriteBytes(obj.Address[:])
_tmp1 := w.List()
for _, _tmp2 := range obj.StorageWrites {
for _, _tmp2 := range obj.StorageChanges {
_tmp3 := w.List()
if _tmp2.Slot == nil {
w.Write(rlp.EmptyString)
@ -19,13 +20,13 @@ func (obj *AccountAccess) EncodeRLP(_w io.Writer) error {
w.WriteUint256(_tmp2.Slot)
}
_tmp4 := w.List()
for _, _tmp5 := range _tmp2.Accesses {
for _, _tmp5 := range _tmp2.SlotChanges {
_tmp6 := w.List()
w.WriteUint64(uint64(_tmp5.TxIdx))
if _tmp5.ValueAfter == nil {
w.WriteUint64(uint64(_tmp5.BlockAccessIndex))
if _tmp5.PostValue == nil {
w.Write(rlp.EmptyString)
} else {
w.WriteUint256(_tmp5.ValueAfter)
w.WriteUint256(_tmp5.PostValue)
}
w.ListEnd(_tmp6)
}
@ -45,11 +46,11 @@ func (obj *AccountAccess) EncodeRLP(_w io.Writer) error {
_tmp9 := w.List()
for _, _tmp10 := range obj.BalanceChanges {
_tmp11 := w.List()
w.WriteUint64(uint64(_tmp10.TxIdx))
if _tmp10.Balance == nil {
w.WriteUint64(uint64(_tmp10.BlockAccessIndex))
if _tmp10.PostBalance == nil {
w.Write(rlp.EmptyString)
} else {
w.WriteUint256(_tmp10.Balance)
w.WriteUint256(_tmp10.PostBalance)
}
w.ListEnd(_tmp11)
}
@ -57,16 +58,16 @@ func (obj *AccountAccess) EncodeRLP(_w io.Writer) error {
_tmp12 := w.List()
for _, _tmp13 := range obj.NonceChanges {
_tmp14 := w.List()
w.WriteUint64(uint64(_tmp13.TxIdx))
w.WriteUint64(_tmp13.Nonce)
w.WriteUint64(uint64(_tmp13.BlockAccessIndex))
w.WriteUint64(_tmp13.PostNonce)
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.WriteUint64(uint64(_tmp16.BlockAccessIndex))
w.WriteBytes(_tmp16.NewCode)
w.ListEnd(_tmp17)
}
w.ListEnd(_tmp15)
@ -81,18 +82,18 @@ func (obj *AccountAccess) DecodeRLP(dec *rlp.Stream) error {
return err
}
// Address:
var _tmp1 [20]byte
var _tmp1 common.Address
if err := dec.ReadBytes(_tmp1[:]); err != nil {
return err
}
_tmp0.Address = _tmp1
// StorageWrites:
var _tmp2 []encodingSlotWrites
// StorageChanges:
var _tmp2 []encodingSlotChanges
if _, err := dec.List(); err != nil {
return err
}
for dec.MoreDataInList() {
var _tmp3 encodingSlotWrites
var _tmp3 encodingSlotChanges
{
if _, err := dec.List(); err != nil {
return err
@ -103,7 +104,7 @@ func (obj *AccountAccess) DecodeRLP(dec *rlp.Stream) error {
return err
}
_tmp3.Slot = &_tmp4
// Accesses:
// SlotChanges:
var _tmp5 []encodingStorageWrite
if _, err := dec.List(); err != nil {
return err
@ -114,18 +115,18 @@ func (obj *AccountAccess) DecodeRLP(dec *rlp.Stream) error {
if _, err := dec.List(); err != nil {
return err
}
// TxIdx:
// BlockAccessIndex:
_tmp7, err := dec.Uint32()
if err != nil {
return err
}
_tmp6.TxIdx = _tmp7
// ValueAfter:
_tmp6.BlockAccessIndex = _tmp7
// PostValue:
var _tmp8 uint256.Int
if err := dec.ReadUint256(&_tmp8); err != nil {
return err
}
_tmp6.ValueAfter = &_tmp8
_tmp6.PostValue = &_tmp8
if err := dec.ListEnd(); err != nil {
return err
}
@ -135,7 +136,7 @@ func (obj *AccountAccess) DecodeRLP(dec *rlp.Stream) error {
if err := dec.ListEnd(); err != nil {
return err
}
_tmp3.Accesses = _tmp5
_tmp3.SlotChanges = _tmp5
if err := dec.ListEnd(); err != nil {
return err
}
@ -145,7 +146,7 @@ func (obj *AccountAccess) DecodeRLP(dec *rlp.Stream) error {
if err := dec.ListEnd(); err != nil {
return err
}
_tmp0.StorageWrites = _tmp2
_tmp0.StorageChanges = _tmp2
// StorageReads:
var _tmp9 []*uint256.Int
if _, err := dec.List(); err != nil {
@ -173,18 +174,18 @@ func (obj *AccountAccess) DecodeRLP(dec *rlp.Stream) error {
if _, err := dec.List(); err != nil {
return err
}
// TxIdx:
// BlockAccessIndex:
_tmp13, err := dec.Uint32()
if err != nil {
return err
}
_tmp12.TxIdx = _tmp13
// Balance:
_tmp12.BlockAccessIndex = _tmp13
// PostBalance:
var _tmp14 uint256.Int
if err := dec.ReadUint256(&_tmp14); err != nil {
return err
}
_tmp12.Balance = &_tmp14
_tmp12.PostBalance = &_tmp14
if err := dec.ListEnd(); err != nil {
return err
}
@ -206,18 +207,18 @@ func (obj *AccountAccess) DecodeRLP(dec *rlp.Stream) error {
if _, err := dec.List(); err != nil {
return err
}
// TxIdx:
// BlockAccessIndex:
_tmp17, err := dec.Uint32()
if err != nil {
return err
}
_tmp16.TxIdx = _tmp17
// Nonce:
_tmp16.BlockAccessIndex = _tmp17
// PostNonce:
_tmp18, err := dec.Uint64()
if err != nil {
return err
}
_tmp16.Nonce = _tmp18
_tmp16.PostNonce = _tmp18
if err := dec.ListEnd(); err != nil {
return err
}
@ -239,18 +240,18 @@ func (obj *AccountAccess) DecodeRLP(dec *rlp.Stream) error {
if _, err := dec.List(); err != nil {
return err
}
// TxIndex:
// BlockAccessIndex:
_tmp21, err := dec.Uint32()
if err != nil {
return err
}
_tmp20.TxIndex = _tmp21
// Code:
_tmp20.BlockAccessIndex = _tmp21
// NewCode:
_tmp22, err := dec.Bytes()
if err != nil {
return err
}
_tmp20.Code = _tmp22
_tmp20.NewCode = _tmp22
if err := dec.ListEnd(); err != nil {
return err
}

View file

@ -160,7 +160,7 @@ func TestConstructionBALMerge(t *testing.T) {
func makeTestAccountAccess(sort bool) AccountAccess {
var (
storageWrites []encodingSlotWrites
storageWrites []encodingSlotChanges
storageReads []*uint256.Int
balances []encodingBalanceChange
nonces []encodingAccountNonce
@ -170,24 +170,24 @@ func makeTestAccountAccess(sort bool) AccountAccess {
return new(uint256.Int).SetBytes(testrand.Bytes(32))
}
for i := 0; i < 5; i++ {
slot := encodingSlotWrites{
slot := encodingSlotChanges{
Slot: randSlot(),
}
for j := 0; j < 3; j++ {
slot.Accesses = append(slot.Accesses, encodingStorageWrite{
TxIdx: uint32(2 * j),
ValueAfter: randSlot(),
slot.SlotChanges = append(slot.SlotChanges, encodingStorageWrite{
BlockAccessIndex: uint32(2 * j),
PostValue: randSlot(),
})
}
if sort {
slices.SortFunc(slot.Accesses, func(a, b encodingStorageWrite) int {
return cmp.Compare[uint32](a.TxIdx, b.TxIdx)
slices.SortFunc(slot.SlotChanges, func(a, b encodingStorageWrite) int {
return cmp.Compare(a.BlockAccessIndex, b.BlockAccessIndex)
})
}
storageWrites = append(storageWrites, slot)
}
if sort {
slices.SortFunc(storageWrites, func(a, b encodingSlotWrites) int {
slices.SortFunc(storageWrites, func(a, b encodingSlotChanges) int {
return a.Slot.Cmp(b.Slot)
})
}
@ -203,43 +203,43 @@ func makeTestAccountAccess(sort bool) AccountAccess {
for i := 0; i < 5; i++ {
balances = append(balances, encodingBalanceChange{
TxIdx: uint32(2 * i),
Balance: new(uint256.Int).SetBytes(testrand.Bytes(16)),
BlockAccessIndex: uint32(2 * i),
PostBalance: new(uint256.Int).SetBytes(testrand.Bytes(16)),
})
}
if sort {
slices.SortFunc(balances, func(a, b encodingBalanceChange) int {
return cmp.Compare[uint32](a.TxIdx, b.TxIdx)
return cmp.Compare(a.BlockAccessIndex, b.BlockAccessIndex)
})
}
for i := 0; i < 5; i++ {
nonces = append(nonces, encodingAccountNonce{
TxIdx: uint32(2 * i),
Nonce: uint64(i + 100),
BlockAccessIndex: uint32(2 * i),
PostNonce: uint64(i + 100),
})
}
if sort {
slices.SortFunc(nonces, func(a, b encodingAccountNonce) int {
return cmp.Compare[uint32](a.TxIdx, b.TxIdx)
return cmp.Compare(a.BlockAccessIndex, b.BlockAccessIndex)
})
}
for i := 0; i < 5; i++ {
codes = append(codes, encodingCodeChange{
TxIndex: uint32(2 * i),
Code: testrand.Bytes(256),
BlockAccessIndex: uint32(2 * i),
NewCode: testrand.Bytes(256),
})
}
if sort {
slices.SortFunc(codes, func(a, b encodingCodeChange) int {
return cmp.Compare[uint32](a.TxIndex, b.TxIndex)
return cmp.Compare(a.BlockAccessIndex, b.BlockAccessIndex)
})
}
return AccountAccess{
Address: [20]byte(testrand.Bytes(20)),
StorageWrites: storageWrites,
Address: common.Address(testrand.Bytes(20)),
StorageChanges: storageWrites,
StorageReads: storageReads,
BalanceChanges: balances,
NonceChanges: nonces,
@ -289,14 +289,14 @@ func TestBlockAccessListItemCount(t *testing.T) {
t.Fatalf("empty BAL item count: got %d, want 0", got)
}
addr1 := [20]byte(testrand.Bytes(20))
addr2 := [20]byte(testrand.Bytes(20))
addr1 := common.Address(testrand.Bytes(20))
addr2 := common.Address(testrand.Bytes(20))
one := func() *uint256.Int { return new(uint256.Int).SetBytes(testrand.Bytes(32)) }
bal := &BlockAccessList{
AccountAccess{
Address: addr1,
StorageWrites: []encodingSlotWrites{
{Slot: one(), Accesses: []encodingStorageWrite{{TxIdx: 0, ValueAfter: one()}, {TxIdx: 1, ValueAfter: one()}}},
StorageChanges: []encodingSlotChanges{
{Slot: one(), SlotChanges: []encodingStorageWrite{{BlockAccessIndex: 0, PostValue: one()}, {BlockAccessIndex: 1, PostValue: one()}}},
{Slot: one()},
},
StorageReads: []*uint256.Int{one()},
@ -316,10 +316,10 @@ func TestBlockAccessListValidateSize(t *testing.T) {
one := func() *uint256.Int { return new(uint256.Int).SetBytes(testrand.Bytes(32)) }
bal := make(BlockAccessList, 3)
for i := range bal {
bal[i].Address = [20]byte(testrand.Bytes(20))
bal[i].Address = common.Address(testrand.Bytes(20))
for j := 0; j < 5; j++ {
bal[i].StorageWrites = append(bal[i].StorageWrites, encodingSlotWrites{
Slot: one(), Accesses: []encodingStorageWrite{{TxIdx: 0, ValueAfter: one()}},
bal[i].StorageChanges = append(bal[i].StorageChanges, encodingSlotChanges{
Slot: one(), SlotChanges: []encodingStorageWrite{{BlockAccessIndex: 0, PostValue: one()}},
})
}
for j := 0; j < 4; j++ {

View file

@ -0,0 +1,76 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package bal
import (
"encoding/json"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/holiman/uint256"
)
var _ = (*accountAccessMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (a AccountAccess) MarshalJSON() ([]byte, error) {
type AccountAccess struct {
Address common.Address `json:"address"`
StorageChanges []encodingSlotChanges `json:"storageChanges"`
StorageReads []*hexutil.U256 `json:"storageReads"`
BalanceChanges []encodingBalanceChange `json:"balanceChanges"`
NonceChanges []encodingAccountNonce `json:"nonceChanges"`
CodeChanges []encodingCodeChange `json:"codeChanges"`
}
var enc AccountAccess
enc.Address = a.Address
enc.StorageChanges = a.StorageChanges
if a.StorageReads != nil {
enc.StorageReads = make([]*hexutil.U256, len(a.StorageReads))
for k, v := range a.StorageReads {
enc.StorageReads[k] = (*hexutil.U256)(v)
}
}
enc.BalanceChanges = a.BalanceChanges
enc.NonceChanges = a.NonceChanges
enc.CodeChanges = a.CodeChanges
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (a *AccountAccess) UnmarshalJSON(input []byte) error {
type AccountAccess struct {
Address *common.Address `json:"address"`
StorageChanges []encodingSlotChanges `json:"storageChanges"`
StorageReads []*hexutil.U256 `json:"storageReads"`
BalanceChanges []encodingBalanceChange `json:"balanceChanges"`
NonceChanges []encodingAccountNonce `json:"nonceChanges"`
CodeChanges []encodingCodeChange `json:"codeChanges"`
}
var dec AccountAccess
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Address != nil {
a.Address = *dec.Address
}
if dec.StorageChanges != nil {
a.StorageChanges = dec.StorageChanges
}
if dec.StorageReads != nil {
a.StorageReads = make([]*uint256.Int, len(dec.StorageReads))
for k, v := range dec.StorageReads {
a.StorageReads[k] = (*uint256.Int)(v)
}
}
if dec.BalanceChanges != nil {
a.BalanceChanges = dec.BalanceChanges
}
if dec.NonceChanges != nil {
a.NonceChanges = dec.NonceChanges
}
if dec.CodeChanges != nil {
a.CodeChanges = dec.CodeChanges
}
return nil
}

View file

@ -0,0 +1,42 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package bal
import (
"encoding/json"
"github.com/ethereum/go-ethereum/common/hexutil"
)
var _ = (*encodingAccountNonceMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (e encodingAccountNonce) MarshalJSON() ([]byte, error) {
type encodingAccountNonce struct {
BlockAccessIndex hexutil.Uint64 `json:"blockAccessIndex"`
PostNonce hexutil.Uint64 `json:"postNonce"`
}
var enc encodingAccountNonce
enc.BlockAccessIndex = hexutil.Uint64(e.BlockAccessIndex)
enc.PostNonce = hexutil.Uint64(e.PostNonce)
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (e *encodingAccountNonce) UnmarshalJSON(input []byte) error {
type encodingAccountNonce struct {
BlockAccessIndex *hexutil.Uint64 `json:"blockAccessIndex"`
PostNonce *hexutil.Uint64 `json:"postNonce"`
}
var dec encodingAccountNonce
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.BlockAccessIndex != nil {
e.BlockAccessIndex = uint32(*dec.BlockAccessIndex)
}
if dec.PostNonce != nil {
e.PostNonce = uint64(*dec.PostNonce)
}
return nil
}

View file

@ -0,0 +1,43 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package bal
import (
"encoding/json"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/holiman/uint256"
)
var _ = (*encodingBalanceChangeMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (e encodingBalanceChange) MarshalJSON() ([]byte, error) {
type encodingBalanceChange struct {
BlockAccessIndex hexutil.Uint64 `json:"blockAccessIndex"`
PostBalance *hexutil.U256 `json:"postBalance"`
}
var enc encodingBalanceChange
enc.BlockAccessIndex = hexutil.Uint64(e.BlockAccessIndex)
enc.PostBalance = (*hexutil.U256)(e.PostBalance)
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (e *encodingBalanceChange) UnmarshalJSON(input []byte) error {
type encodingBalanceChange struct {
BlockAccessIndex *hexutil.Uint64 `json:"blockAccessIndex"`
PostBalance *hexutil.U256 `json:"postBalance"`
}
var dec encodingBalanceChange
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.BlockAccessIndex != nil {
e.BlockAccessIndex = uint32(*dec.BlockAccessIndex)
}
if dec.PostBalance != nil {
e.PostBalance = (*uint256.Int)(dec.PostBalance)
}
return nil
}

View file

@ -0,0 +1,42 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package bal
import (
"encoding/json"
"github.com/ethereum/go-ethereum/common/hexutil"
)
var _ = (*encodingCodeChangeMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (e encodingCodeChange) MarshalJSON() ([]byte, error) {
type encodingCodeChange struct {
BlockAccessIndex hexutil.Uint64 `json:"blockAccessIndex"`
NewCode hexutil.Bytes `json:"newCode"`
}
var enc encodingCodeChange
enc.BlockAccessIndex = hexutil.Uint64(e.BlockAccessIndex)
enc.NewCode = e.NewCode
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (e *encodingCodeChange) UnmarshalJSON(input []byte) error {
type encodingCodeChange struct {
BlockAccessIndex *hexutil.Uint64 `json:"blockAccessIndex"`
NewCode *hexutil.Bytes `json:"newCode"`
}
var dec encodingCodeChange
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.BlockAccessIndex != nil {
e.BlockAccessIndex = uint32(*dec.BlockAccessIndex)
}
if dec.NewCode != nil {
e.NewCode = *dec.NewCode
}
return nil
}

View file

@ -0,0 +1,43 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package bal
import (
"encoding/json"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/holiman/uint256"
)
var _ = (*encodingSlotChangesMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (e encodingSlotChanges) MarshalJSON() ([]byte, error) {
type encodingSlotChanges struct {
Slot *hexutil.U256 `json:"slot"`
SlotChanges []encodingStorageWrite `json:"slotChanges"`
}
var enc encodingSlotChanges
enc.Slot = (*hexutil.U256)(e.Slot)
enc.SlotChanges = e.SlotChanges
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (e *encodingSlotChanges) UnmarshalJSON(input []byte) error {
type encodingSlotChanges struct {
Slot *hexutil.U256 `json:"slot"`
SlotChanges []encodingStorageWrite `json:"slotChanges"`
}
var dec encodingSlotChanges
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Slot != nil {
e.Slot = (*uint256.Int)(dec.Slot)
}
if dec.SlotChanges != nil {
e.SlotChanges = dec.SlotChanges
}
return nil
}

View file

@ -0,0 +1,43 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package bal
import (
"encoding/json"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/holiman/uint256"
)
var _ = (*encodingStorageWriteMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (e encodingStorageWrite) MarshalJSON() ([]byte, error) {
type encodingStorageWrite struct {
BlockAccessIndex hexutil.Uint64 `json:"blockAccessIndex"`
PostValue *hexutil.U256 `json:"postValue"`
}
var enc encodingStorageWrite
enc.BlockAccessIndex = hexutil.Uint64(e.BlockAccessIndex)
enc.PostValue = (*hexutil.U256)(e.PostValue)
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (e *encodingStorageWrite) UnmarshalJSON(input []byte) error {
type encodingStorageWrite struct {
BlockAccessIndex *hexutil.Uint64 `json:"blockAccessIndex"`
PostValue *hexutil.U256 `json:"postValue"`
}
var dec encodingStorageWrite
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.BlockAccessIndex != nil {
e.BlockAccessIndex = uint32(*dec.BlockAccessIndex)
}
if dec.PostValue != nil {
e.PostValue = (*uint256.Int)(dec.PostValue)
}
return nil
}

View file

@ -101,7 +101,7 @@ type Header struct {
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
// BlockAccessListHash was added by EIP-7928 and is ignored in legacy headers.
BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"`
BlockAccessListHash *common.Hash `json:"blockAccessListHash" rlp:"optional"`
// SlotNumber was added by EIP-7843 and is ignored in legacy headers.
SlotNumber *uint64 `json:"slotNumber" rlp:"optional"`

View file

@ -37,7 +37,7 @@ func (h Header) MarshalJSON() ([]byte, error) {
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"`
BlockAccessListHash *common.Hash `json:"blockAccessListHash" rlp:"optional"`
SlotNumber *hexutil.Uint64 `json:"slotNumber" rlp:"optional"`
Hash common.Hash `json:"hash"`
}
@ -93,7 +93,7 @@ func (h *Header) UnmarshalJSON(input []byte) error {
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
BlockAccessListHash *common.Hash `json:"balHash" rlp:"optional"`
BlockAccessListHash *common.Hash `json:"blockAccessListHash" rlp:"optional"`
SlotNumber *hexutil.Uint64 `json:"slotNumber" rlp:"optional"`
}
var dec Header

View file

@ -1002,7 +1002,7 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} {
result["requestsHash"] = head.RequestsHash
}
if head.BlockAccessListHash != nil {
result["balHash"] = head.BlockAccessListHash
result["blockAccessListHash"] = head.BlockAccessListHash
}
if head.SlotNumber != nil {
result["slotNumber"] = hexutil.Uint64(*head.SlotNumber)