Skip to content

Commit b3113ba

Browse files
all: fix rebasing issues
1 parent 85671f1 commit b3113ba

File tree

10 files changed

+156
-113
lines changed

10 files changed

+156
-113
lines changed

build/checksums.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
# https://github.com/ethereum/execution-spec-tests/releases/download/v5.1.0
66
a3192784375acec7eaec492799d5c5d0c47a2909a3cc40178898e4ecd20cc416 fixtures_develop.tar.gz
77

8-
# version:spec-tests-bal v5.2.0
8+
# version:spec-tests-bal v5.5.1
99
# https://github.com/ethereum/execution-spec-tests/releases
10-
# https://github.com/ethereum/execution-spec-tests/releases/download/bal%40v5.2.0
11-
a0dc6f4070da4dab4831f4e8fddfc087c10a5120a6a683257e963d9c6713378a fixtures_bal.tar.gz
10+
# https://github.com/ethereum/execution-spec-tests/releases/download/bal%40v5.5.1
11+
79f81379bc456b9f05d4e7298eba939855d0147b525cd2cadd1206513284ab9e fixtures_bal.tar.gz
1212

1313
# version:golang 1.25.7
1414
# https://go.dev/dl/

core/blockchain.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2402,6 +2402,11 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
24022402
bc.reportBadBlock(block, res, err)
24032403
return nil, err
24042404
}
2405+
// EIP-7928: Validate BAL items do not exceed block gas limit
2406+
if err := computedAccessList.ValidateGasLimit(block.Header().GasLimit); err != nil {
2407+
bc.reportBadBlock(block, res, err)
2408+
return nil, err
2409+
}
24052410
if block.AccessList() == nil {
24062411
// attach the computed access list to the block so it gets persisted
24072412
// when the block is written to disk

core/parallel_state_processor.go

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -95,28 +95,25 @@ func (p *ParallelStateProcessor) prepareExecResult(block *types.Block, tExecStar
9595
})
9696

9797
var (
98-
// total gas used not applying refunds
99-
blockGas = uint64(0)
100-
// total gas used applying refunds
101-
execGas = uint64(0)
98+
// Per-dimension cumulative sums for 2D block gas (EIP-8037).
99+
sumRegular uint64
100+
sumState uint64
101+
cumulativeReceipt uint64 // cumulative receipt gas (what users pay)
102102
)
103103

104104
var allLogs []*types.Log
105105
var allReceipts []*types.Receipt
106106
for _, result := range results {
107-
blockGas += result.blockGas
108-
execGas += result.execGas
109-
result.receipt.CumulativeGasUsed = blockGas
110-
if blockGas > header.GasLimit {
111-
return &ProcessResultWithMetrics{
112-
ProcessResult: &ProcessResult{Error: fmt.Errorf("gas limit exceeded")},
113-
}
114-
}
107+
sumRegular += result.txRegular
108+
sumState += result.txState
109+
cumulativeReceipt += result.execGas
110+
result.receipt.CumulativeGasUsed = cumulativeReceipt
115111
allLogs = append(allLogs, result.receipt.Logs...)
116112
allReceipts = append(allReceipts, result.receipt)
117113
}
118-
// Block gas limit is enforced against usedGas (pre-refund after Amsterdam, post-refund before).
119-
if blockGas > header.GasLimit {
114+
// Block gas = max(sum_regular, sum_state) per EIP-8037.
115+
blockGasUsed := max(sumRegular, sumState)
116+
if blockGasUsed > header.GasLimit {
120117
return &ProcessResultWithMetrics{
121118
ProcessResult: &ProcessResult{Error: fmt.Errorf("gas limit exceeded")},
122119
}
@@ -177,7 +174,7 @@ func (p *ParallelStateProcessor) prepareExecResult(block *types.Block, tExecStar
177174
Receipts: allReceipts,
178175
Requests: requests,
179176
Logs: allLogs,
180-
GasUsed: execGas,
177+
GasUsed: blockGasUsed,
181178
},
182179
PostProcessTime: tPostprocess,
183180
ExecTime: tExec,
@@ -191,6 +188,10 @@ type txExecResult struct {
191188
blockGas uint64
192189
execGas uint64
193190

191+
// Per-tx dimensional gas for Amsterdam 2D gas accounting (EIP-8037).
192+
txRegular uint64
193+
txState uint64
194+
194195
stateReads bal.StateAccesses
195196
}
196197

@@ -290,7 +291,6 @@ func (p *ParallelStateProcessor) execTx(block *types.Block, tx *types.Transactio
290291
gp := NewGasPool(block.GasLimit())
291292
db.SetTxContext(tx.Hash(), balIdx-1)
292293

293-
var gasUsed uint64
294294
mut, receipt, err := ApplyTransactionWithEVM(msg, gp, db, block.Number(), block.Hash(), context.Time, tx, evm)
295295
if err != nil {
296296
err := fmt.Errorf("could not apply tx %d [%v]: %w", balIdx, tx.Hash().Hex(), err)
@@ -303,11 +303,14 @@ func (p *ParallelStateProcessor) execTx(block *types.Block, tx *types.Transactio
303303
return &txExecResult{err: err}
304304
}
305305

306+
txRegular, txState := gp.AmsterdamDimensions()
306307
return &txExecResult{
307308
idx: balIdx,
308309
receipt: receipt,
309310
execGas: receipt.GasUsed,
310-
blockGas: gasUsed,
311+
blockGas: gp.Used(),
312+
txRegular: txRegular,
313+
txState: txState,
311314
stateReads: db.Reader().(state.StateReaderTracker).GetStateAccessList(),
312315
}
313316
}

core/types/bal/bal_encoding.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,30 @@ func (e BlockAccessList) Validate(blockTxCount int) error {
131131
return nil
132132
}
133133

134+
// ValidateGasLimit checks that the number of BAL items does not exceed the
135+
// block gas limit divided by the per-item cost (EIP-7928).
136+
func (e BlockAccessList) ValidateGasLimit(blockGasLimit uint64) error {
137+
var balItems uint64
138+
for _, account := range e {
139+
// Count each address as one item
140+
balItems++
141+
// Count unique storage keys across both reads and writes
142+
uniqueSlots := make(map[common.Hash]struct{})
143+
for _, sc := range account.StorageChanges {
144+
uniqueSlots[sc.Slot.ToHash()] = struct{}{}
145+
}
146+
for _, sr := range account.StorageReads {
147+
uniqueSlots[sr.ToHash()] = struct{}{}
148+
}
149+
balItems += uint64(len(uniqueSlots))
150+
}
151+
limit := blockGasLimit / params.GasBlockAccessListItem
152+
if balItems > limit {
153+
return fmt.Errorf("block access list exceeds gas limit: %d items exceeds limit of %d", balItems, limit)
154+
}
155+
return nil
156+
}
157+
134158
// Hash computes the keccak256 hash of the access list
135159
func (e *BlockAccessList) Hash() common.Hash {
136160
var enc bytes.Buffer
@@ -391,7 +415,7 @@ func (e *AccountAccess) validate(blockTxCount int) error {
391415
// validate that code changes could plausibly be correct (none exceed
392416
// max code size of a contract)
393417
for _, codeChange := range e.CodeChanges {
394-
if len(codeChange.Code) > params.MaxCodeSize {
418+
if len(codeChange.Code) > params.MaxCodeSizeAmsterdam {
395419
return fmt.Errorf("code change contained oversized code")
396420
}
397421
}

core/vm/evm.go

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasCosts, value *
504504
}(gas)
505505
}
506506
if err != nil {
507-
return nil, common.Address{}, GasCosts{}, GasUsed{}, err
507+
return nil, common.Address{}, gas, GasUsed{}, err
508508
}
509509

510510
// Charge the contract creation init gas in verkle mode
@@ -538,8 +538,10 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasCosts, value *
538538
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
539539
evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution)
540540
}
541+
// Burn all gas on collision
542+
collisionUsed := GasUsed{RegularGasUsed: gas.RegularGas}
541543
gas.RegularGas = 0
542-
return nil, common.Address{}, gas, GasUsed{}, ErrContractAddressCollision
544+
return nil, common.Address{}, gas, collisionUsed, ErrContractAddressCollision
543545
}
544546
// Create a new account on the state only if the object was not present.
545547
// It might be possible the contract code is deployed to a pre-existent
@@ -584,6 +586,9 @@ func (evm *EVM) create(caller common.Address, code []byte, gas GasCosts, value *
584586
if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
585587
evm.StateDB.RevertToSnapshot(snapshot)
586588
if err != ErrExecutionReverted {
589+
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
590+
evm.Config.Tracer.OnGasChange(contract.Gas.RegularGas, 0, tracing.GasChangeCallFailedExecution)
591+
}
587592
contract.GasUsed.RegularGasUsed += contract.Gas.RegularGas
588593
contract.Gas.RegularGas = 0
589594
}
@@ -605,35 +610,39 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b
605610
return ret, ErrInvalidCode
606611
}
607612

608-
if !evm.chainRules.IsEIP4762 {
609-
if evm.chainRules.IsAmsterdam {
610-
// EIP-8037: Split code deposit into state gas (code storage) and
611-
// regular gas (keccak256 hashing).
612-
stateGas := GasCosts{StateGas: uint64(len(ret)) * evm.Context.CostPerGasByte}
613-
if !contract.UseGas(stateGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
614-
return ret, ErrCodeStoreOutOfGas
615-
}
616-
regularGas := GasCosts{RegularGas: toWordSize(uint64(len(ret))) * params.Keccak256WordGas}
617-
if !contract.UseGas(regularGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
618-
return ret, ErrCodeStoreOutOfGas
619-
}
620-
} else {
621-
createDataGas := GasCosts{RegularGas: uint64(len(ret)) * params.CreateDataGas}
622-
if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
623-
return ret, ErrCodeStoreOutOfGas
624-
}
613+
if evm.chainRules.IsAmsterdam {
614+
// Check max code size BEFORE charging gas so over-max code
615+
// does not consume state gas (which would inflate tx_state).
616+
if err := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret))); err != nil {
617+
return ret, err
625618
}
626-
} else {
619+
// EIP-8037: Charge regular gas (keccak256 hash) first, then state gas
620+
// (code storage). Regular-before-state prevents reservoir inflation.
621+
regularGas := GasCosts{RegularGas: toWordSize(uint64(len(ret))) * params.Keccak256WordGas}
622+
if !contract.UseGas(regularGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
623+
return ret, ErrCodeStoreOutOfGas
624+
}
625+
stateGas := GasCosts{StateGas: uint64(len(ret)) * evm.Context.CostPerGasByte}
626+
if !contract.UseGas(stateGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
627+
return ret, ErrCodeStoreOutOfGas
628+
}
629+
} else if evm.chainRules.IsEIP4762 {
627630
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true, contract.Gas.RegularGas)
628631
contract.UseGas(GasCosts{RegularGas: consumed}, evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk)
629632
if len(ret) > 0 && (consumed < wanted) {
630633
return ret, ErrCodeStoreOutOfGas
631634
}
632-
}
633-
634-
// Verify max code size after gas calculation.
635-
if err := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret))); err != nil {
636-
return ret, err
635+
if err := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret))); err != nil {
636+
return ret, err
637+
}
638+
} else {
639+
createDataGas := GasCosts{RegularGas: uint64(len(ret)) * params.CreateDataGas}
640+
if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
641+
return ret, ErrCodeStoreOutOfGas
642+
}
643+
if err := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret))); err != nil {
644+
return ret, err
645+
}
637646
}
638647

639648
if len(ret) > 0 {

core/vm/gas_table.go

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -647,17 +647,13 @@ func gasSStore8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo
647647
}
648648
if original == current {
649649
if original == (common.Hash{}) { // create slot (2.1.1)
650-
// EIP-8037: Charge state gas first (before regular gas), matching the
651-
// spec's charge_state_gas → charge_gas ordering. This ensures that
652-
// state_gas_used is recorded even if the subsequent regular gas charge
653-
// fails with OOG.
654-
stateGas := GasCosts{StateGas: params.StorageCreationSize * evm.Context.CostPerGasByte}
655-
if contract.Gas.Underflow(stateGas) {
656-
return GasCosts{}, errors.New("out of gas for state gas")
657-
}
658-
contract.GasUsed.Add(stateGas)
659-
contract.Gas.Sub(stateGas)
660-
return GasCosts{RegularGas: cost.RegularGas + params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929}, nil
650+
// EIP-8037: Return both regular and state gas. The interpreter
651+
// charges regular gas before state gas, preventing reservoir
652+
// inflation when the regular charge OOGs.
653+
return GasCosts{
654+
RegularGas: cost.RegularGas + params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929,
655+
StateGas: params.StorageCreationSize * evm.Context.CostPerGasByte,
656+
}, nil
661657
}
662658
if value == (common.Hash{}) { // delete slot (2.1.2b)
663659
evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP3529)

core/vm/interpreter.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,20 @@ func (evm *EVM) Run(contract *Contract, input []byte, readOnly bool) (ret []byte
226226
return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err)
227227
}
228228
// for tracing: this gas consumption event is emitted below in the debug section.
229-
if contract.Gas.Underflow(dynamicCost) {
229+
if evm.chainRules.IsAmsterdam && dynamicCost.StateGas > 0 {
230+
// EIP-8037: charge regular gas before state gas.
231+
if contract.Gas.RegularGas < dynamicCost.RegularGas {
232+
return nil, ErrOutOfGas
233+
}
234+
contract.GasUsed.RegularGasUsed += dynamicCost.RegularGas
235+
contract.Gas.RegularGas -= dynamicCost.RegularGas
236+
stateOnly := GasCosts{StateGas: dynamicCost.StateGas}
237+
if contract.Gas.Underflow(stateOnly) {
238+
return nil, ErrOutOfGas
239+
}
240+
contract.GasUsed.Add(stateOnly)
241+
contract.Gas.Sub(stateOnly)
242+
} else if contract.Gas.Underflow(dynamicCost) {
230243
return nil, ErrOutOfGas
231244
} else {
232245
contract.GasUsed.Add(dynamicCost)

core/vm/operations_acl.go

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,10 @@ func makeCallVariantGasCallEIP7702(intrinsicFunc intrinsicGasFunc) gasFunc {
354354
// part of the dynamic gas. This will ensure it is correctly reported to
355355
// tracers.
356356
contract.Gas.RegularGas += eip2929Cost + eip7702Cost
357+
// Undo the RegularGasUsed increments from the direct UseGas charges,
358+
// since this gas will be re-charged via the returned cost.
359+
contract.GasUsed.RegularGasUsed -= eip2929Cost
360+
contract.GasUsed.RegularGasUsed -= eip7702Cost
357361

358362
// Aggregate the gas costs from all components, including EIP-2929, EIP-7702,
359363
// the CALL opcode itself, and the cost incurred by nested calls.
@@ -385,7 +389,7 @@ func makeCallVariantGasCallEIP8037(intrinsicFunc intrinsicGasFunc, stateGasFunc
385389
eip7702Cost uint64
386390
addr = common.Address(stack.Back(1).Bytes20())
387391
)
388-
// EIP-2929 cold access check.
392+
// EIP-2929 cold access check (regular gas, directly).
389393
if !evm.StateDB.AddressInAccessList(addr) {
390394
evm.StateDB.AddAddressToAccessList(addr)
391395
eip2929Cost = params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
@@ -399,18 +403,15 @@ func makeCallVariantGasCallEIP8037(intrinsicFunc intrinsicGasFunc, stateGasFunc
399403
if err != nil {
400404
return GasCosts{}, err
401405
}
402-
// Early OOG check before stateful operations.
403-
if contract.Gas.RegularGas < intrinsicCost {
404-
return GasCosts{}, ErrOutOfGas
405-
}
406406

407-
// Compute state gas (new account creation as state gas).
408-
stateGas, err := stateGasFunc(evm, contract, stack, mem, memorySize)
409-
if err != nil {
410-
return GasCosts{}, err
407+
// Charge intrinsic cost directly (regular gas). This must happen
408+
// BEFORE state gas to prevent reservoir inflation, and also serves
409+
// as the OOG guard before stateful operations.
410+
if !contract.UseGas(GasCosts{RegularGas: intrinsicCost}, evm.Config.Tracer, tracing.GasChangeCallOpCode) {
411+
return GasCosts{}, ErrOutOfGas
411412
}
412413

413-
// EIP-7702 delegation check.
414+
// EIP-7702 delegation check (regular gas, directly).
414415
if target, ok := types.ParseDelegation(evm.StateDB.GetCode(addr)); ok {
415416
if evm.StateDB.AddressInAccessList(target) {
416417
eip7702Cost = params.WarmStorageReadCostEIP2929
@@ -423,8 +424,11 @@ func makeCallVariantGasCallEIP8037(intrinsicFunc intrinsicGasFunc, stateGasFunc
423424
}
424425
}
425426

426-
// Charge state gas directly before callGas computation. State gas that
427-
// spills to regular gas must reduce the gas available for callGasTemp.
427+
// Compute and charge state gas (new account creation) AFTER regular gas.
428+
stateGas, err := stateGasFunc(evm, contract, stack, mem, memorySize)
429+
if err != nil {
430+
return GasCosts{}, err
431+
}
428432
if stateGas.StateGas > 0 {
429433
stateGasCost := GasCosts{StateGas: stateGas.StateGas}
430434
if contract.Gas.Underflow(stateGasCost) {
@@ -435,16 +439,15 @@ func makeCallVariantGasCallEIP8037(intrinsicFunc intrinsicGasFunc, stateGasFunc
435439
}
436440

437441
// Calculate the gas budget for the nested call (63/64 rule).
438-
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas.RegularGas, intrinsicCost, stack.Back(0))
442+
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas.RegularGas, 0, stack.Back(0))
439443
if err != nil {
440444
return GasCosts{}, err
441445
}
442446

443-
// Temporarily add gas charges back for tracer reporting.
444-
contract.Gas.RegularGas += eip2929Cost + eip7702Cost
445-
// Undo GasUsed increments from direct UseGas charges.
446-
contract.GasUsed.RegularGasUsed -= eip2929Cost
447-
contract.GasUsed.RegularGasUsed -= eip7702Cost
447+
// Temporarily undo direct regular charges for tracer reporting.
448+
// The interpreter will charge the returned totalCost.
449+
contract.Gas.RegularGas += eip2929Cost + eip7702Cost + intrinsicCost
450+
contract.GasUsed.RegularGasUsed -= eip2929Cost + eip7702Cost + intrinsicCost
448451

449452
// Aggregate total cost.
450453
var (

params/protocol_params.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,7 @@ const (
193193
StorageCreationSize = 32
194194
AuthorizationCreationSize = 23
195195

196-
// TODO: Add when EIP-7928 is implemented
197-
// GasBlockAccessListItem = 2000 // EIP-7928: gas cost per BAL item for gas limit check
196+
GasBlockAccessListItem = 2000 // EIP-7928: gas cost per BAL item for gas limit check
198197
)
199198

200199
// Bls12381G1MultiExpDiscountTable is the gas discount table for BLS12-381 G1 multi exponentiation operation

0 commit comments

Comments
 (0)