From 589c24bbfc117179736b16feb2d62769df10a7d5 Mon Sep 17 00:00:00 2001 From: MariusVanDerWijden Date: Tue, 28 Apr 2026 23:05:48 +0200 Subject: [PATCH] core: merge bal --- core/types/bal/bal_encoding.go | 236 +++++++++---------- core/types/bal/bal_encoding_rlp_generated.go | 11 +- core/types/bal/bal_test.go | 10 +- params/protocol_params.go | 6 + tests/transaction_test_util.go | 4 - 5 files changed, 131 insertions(+), 136 deletions(-) diff --git a/core/types/bal/bal_encoding.go b/core/types/bal/bal_encoding.go index e23b157fd2..0b02e4341e 100644 --- a/core/types/bal/bal_encoding.go +++ b/core/types/bal/bal_encoding.go @@ -162,11 +162,12 @@ func (e BlockAccessList) ValidateGasLimit(blockGasLimit uint64) error { // Hash computes the keccak256 hash of the access list func (e *BlockAccessList) Hash() common.Hash { var enc bytes.Buffer - 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{} + 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) } /* bal, err := json.MarshalIndent(e.StringableRepresentation(), "", " ") @@ -189,116 +190,6 @@ type encodingAccountNonce struct { Nonce uint64 `json:"nonce"` } -// encodingStorageWrite is the encoding format of StorageWrites. -type encodingStorageWrite struct { - TxIdx uint32 `json:"txIndex"` - ValueAfter *EncodedStorage `json:"valueAfter"` -} - -// EncodedStorage can represent either a storage key or value -type EncodedStorage struct { - inner *uint256.Int -} - -var _ rlp.Encoder = &EncodedStorage{} -var _ rlp.Decoder = &EncodedStorage{} - -func (s *EncodedStorage) ToHash() common.Hash { - if s == nil { - return common.Hash{} - } - return s.inner.Bytes32() -} - -func NewEncodedStorageFromHash(hash common.Hash) *EncodedStorage { - return &EncodedStorage{ - new(uint256.Int).SetBytes(hash[:]), - } -} - -func (s *EncodedStorage) UnmarshalJSON(b []byte) error { - var str string - if err := json.Unmarshal(b, &str); err != nil { - return err - } - - str = strings.TrimLeft(str, "0x") - if len(str) == 0 { - return nil - } - - if len(str)%2 == 1 { - str = "0" + str - } - - val, err := hex.DecodeString(str) - if err != nil { - return err - } - - if len(val) > 32 { - return fmt.Errorf("storage key/value cannot be greater than 32 bytes") - } - - // TODO: check is s == nil ?? should be programmer error - - *s = EncodedStorage{ - inner: new(uint256.Int).SetBytes(val), - } - return nil -} - -func (s EncodedStorage) MarshalJSON() ([]byte, error) { - return json.Marshal(s.inner.Hex()) -} - -func (s *EncodedStorage) EncodeRLP(_w io.Writer) error { - return s.inner.EncodeRLP(_w) -} - -func (s *EncodedStorage) DecodeRLP(dec *rlp.Stream) error { - if s == nil { - *s = EncodedStorage{} - } - s.inner = uint256.NewInt(0) - return dec.ReadUint256(s.inner) -} - -// encodingStorageWrite is the encoding format of SlotWrites. -type encodingSlotWrites struct { - Slot *EncodedStorage `json:"slot"` - Accesses []encodingStorageWrite `json:"accesses"` -} - -// validate returns an instance of the encoding-representation slot writes in -// working representation. -func (e *encodingSlotWrites) validate(blockTxCount int) error { - if e.Slot == nil { - return errors.New("nil slot key") - } - if !slices.IsSortedFunc(e.Accesses, func(a, b encodingStorageWrite) int { - return cmp.Compare[uint32](a.TxIdx, b.TxIdx) - }) { - return errors.New("storage write tx indices not in order") - } - for i, access := range e.Accesses { - if access.ValueAfter == nil { - return errors.New("nil storage write post") - } - if i > 0 && e.Accesses[i-1].TxIdx == access.TxIdx { - return errors.New("duplicate storage write index") - } - } - // TODO: add test that covers there are actually storage modifications here - // if there aren't, it should be a bad block - if len(e.Accesses) == 0 { - return fmt.Errorf("empty storage writes") - } else if int(e.Accesses[len(e.Accesses)-1].TxIdx) >= blockTxCount+2 { - return fmt.Errorf("storage access reported index higher than allowed") - } - return nil -} - // encodingCodeChange contains the runtime bytecode deployed at an address // and the transaction index where the deployment took place. type encodingCodeChange struct { @@ -430,7 +321,7 @@ func (e *AccountAccess) Copy() AccountAccess { res := AccountAccess{ Address: e.Address, StorageReads: slices.Clone(e.StorageReads), - BalanceChanges: make([]encodingBalanceChange, 0, len(e.BalanceChanges)), + BalanceChanges: slices.Clone(e.BalanceChanges), NonceChanges: slices.Clone(e.NonceChanges), } for _, storageWrite := range e.StorageChanges { @@ -476,7 +367,6 @@ func (a *ConstructionAccountAccesses) toEncodingObj(addr common.Address) Account indices := slices.Collect(maps.Keys(slotWrites)) slices.SortFunc(indices, cmp.Compare[uint32]) for _, index := range indices { - val := slotWrites[index] obj.Accesses = append(obj.Accesses, encodingStorageWrite{ TxIdx: index, ValueAfter: NewEncodedStorageFromHash(slotWrites[index]), @@ -536,7 +426,7 @@ func (c *ConstructionBlockAccessList) ToEncodingObj() *BlockAccessList { } slices.SortFunc(addresses, common.Address.Cmp) - res := make(BlockAccessList, 0, len(addresses)) + var res BlockAccessList for _, addr := range addresses { res = append(res, c.list[addr].toEncodingObj(addr)) } @@ -544,3 +434,113 @@ func (c *ConstructionBlockAccessList) ToEncodingObj() *BlockAccessList { } type ContractCode []byte + +// encodingStorageWrite is the encoding format of StorageWrites. +type encodingStorageWrite struct { + TxIdx uint32 `json:"txIndex"` + ValueAfter *EncodedStorage `json:"valueAfter"` +} + +// EncodedStorage can represent either a storage key or value +type EncodedStorage struct { + inner *uint256.Int +} + +var _ rlp.Encoder = &EncodedStorage{} +var _ rlp.Decoder = &EncodedStorage{} + +func (s *EncodedStorage) ToHash() common.Hash { + if s == nil { + return common.Hash{} + } + return s.inner.Bytes32() +} + +func NewEncodedStorageFromHash(hash common.Hash) *EncodedStorage { + return &EncodedStorage{ + new(uint256.Int).SetBytes(hash[:]), + } +} + +func (s *EncodedStorage) UnmarshalJSON(b []byte) error { + var str string + if err := json.Unmarshal(b, &str); err != nil { + return err + } + + str = strings.TrimLeft(str, "0x") + if len(str) == 0 { + return nil + } + + if len(str)%2 == 1 { + str = "0" + str + } + + val, err := hex.DecodeString(str) + if err != nil { + return err + } + + if len(val) > 32 { + return fmt.Errorf("storage key/value cannot be greater than 32 bytes") + } + + // TODO: check is s == nil ?? should be programmer error + + *s = EncodedStorage{ + inner: new(uint256.Int).SetBytes(val), + } + return nil +} + +func (s EncodedStorage) MarshalJSON() ([]byte, error) { + return json.Marshal(s.inner.Hex()) +} + +func (s *EncodedStorage) EncodeRLP(_w io.Writer) error { + return s.inner.EncodeRLP(_w) +} + +func (s *EncodedStorage) DecodeRLP(dec *rlp.Stream) error { + if s == nil { + *s = EncodedStorage{} + } + s.inner = uint256.NewInt(0) + return dec.ReadUint256(s.inner) +} + +// encodingStorageWrite is the encoding format of SlotWrites. +type encodingSlotWrites struct { + Slot *EncodedStorage `json:"slot"` + Accesses []encodingStorageWrite `json:"accesses"` +} + +// validate returns an instance of the encoding-representation slot writes in +// working representation. +func (e *encodingSlotWrites) validate(blockTxCount int) error { + if e.Slot == nil { + return errors.New("nil slot key") + } + if !slices.IsSortedFunc(e.Accesses, func(a, b encodingStorageWrite) int { + return cmp.Compare[uint32](a.TxIdx, b.TxIdx) + }) { + return errors.New("storage write tx indices not in order") + } + for i, access := range e.Accesses { + if access.ValueAfter == nil { + return errors.New("nil storage write post") + } + if i > 0 && e.Accesses[i-1].TxIdx == access.TxIdx { + return errors.New("duplicate storage write index") + } + } + // TODO: add test that covers there are actually storage modifications here + // if there aren't, it should be a bad block + if len(e.Accesses) == 0 { + return fmt.Errorf("empty storage writes") + } else if int(e.Accesses[len(e.Accesses)-1].TxIdx) >= blockTxCount+2 { + return fmt.Errorf("storage access reported index higher than allowed") + } + return nil +} diff --git a/core/types/bal/bal_encoding_rlp_generated.go b/core/types/bal/bal_encoding_rlp_generated.go index 6db8ba0bcf..f65a688929 100644 --- a/core/types/bal/bal_encoding_rlp_generated.go +++ b/core/types/bal/bal_encoding_rlp_generated.go @@ -2,13 +2,10 @@ package bal -import ( - "io" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/rlp" - "github.com/holiman/uint256" -) +import "github.com/ethereum/go-ethereum/common" +import "github.com/ethereum/go-ethereum/rlp" +import "github.com/holiman/uint256" +import "io" func (obj *AccountAccess) EncodeRLP(_w io.Writer) error { w := rlp.NewEncoderBuffer(_w) diff --git a/core/types/bal/bal_test.go b/core/types/bal/bal_test.go index 2bc29fe091..ebf3abf4a2 100644 --- a/core/types/bal/bal_test.go +++ b/core/types/bal/bal_test.go @@ -95,7 +95,7 @@ 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()), 0)); err != nil { + if err := dec.DecodeRLP(rlp.NewStream(bytes.NewReader(buf.Bytes()), 10000000)); err != nil { t.Fatalf("decoding failed: %v\n", err) } if dec.Hash() != bal.ToEncodingObj().Hash() { @@ -114,11 +114,7 @@ func makeTestAccountAccess(sort bool) AccountAccess { storageReads []common.Hash balances []encodingBalanceChange nonces []encodingAccountNonce - codes []encodingCodeChange ) - randSlot := func() *uint256.Int { - return new(uint256.Int).SetBytes(testrand.Bytes(32)) - } for i := 0; i < 5; i++ { slot := encodingSlotWrites{ Slot: NewEncodedStorageFromHash(testrand.Hash()), @@ -143,7 +139,7 @@ func makeTestAccountAccess(sort bool) AccountAccess { } for i := 0; i < 5; i++ { - storageReads = append(storageReads, randSlot()) + storageReads = append(storageReads, testrand.Hash()) } if sort { slices.SortFunc(storageReads, func(a, b common.Hash) int { @@ -204,7 +200,7 @@ func makeTestBAL(sort bool) BlockAccessList { return bytes.Compare(a.Address[:], b.Address[:]) }) } - return &list + return list } func TestBlockAccessListCopy(t *testing.T) { diff --git a/params/protocol_params.go b/params/protocol_params.go index 2043bd32dc..d76ed62b15 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -189,6 +189,12 @@ const ( MaxBlockSize = 8_388_608 // maximum size of an RLP-encoded block + TargetStateGrowthPerYear = 100 * 1024 * 1024 * 1024 // 100GB + AccountCreationSize = 112 + StorageCreationSize = 32 + AuthorizationCreationSize = 23 + SystemMaxSstoresPerCall = 16 // EIP-8037: upper bound on new SSTOREs per system call + GasBlockAccessListItem = 2000 // EIP-7928: gas cost per BAL item for gas limit check ) diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 59e3c7804b..e38bcea410 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -81,11 +81,7 @@ func (tt *TransactionTest) Run() error { return } // Intrinsic gas -<<<<<<< HEAD - cost, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, rules) -======= cost, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, rules, 1) ->>>>>>> eip-8037-rewrite if err != nil { return }