Verify the 63/64 forwarding budget is computed after the repriced
cold access charge.
A wrapper performs a cold, zero-value CALL requesting maximum
gas. The spec charges the repriced COLD_ACCOUNT_ACCESS
up front and only then forwards floor(63/64 * gas_left) to the
child. The wrapper is handed an exact budget so that, net of the
access charge, gas_left equals child_execution * 64 // 63;
forwarding then yields exactly the child's execution need
(child_execution) and its cold SSTORE takes effect. With one
gas less the floor drops below child_execution and the child OOGs,
so the slot stays zero. This pins that the floor is taken over
gas_left already net of the post-8038 cold access cost (not
before it, and not double-charging it).
Source code in tests/amsterdam/eip8038_state_access_gas_cost_increase/test_call_gas.py
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535 | @EIPChecklist.GasCostChanges.Test.GasUpdatesMeasurement()
@pytest.mark.parametrize(
"sufficient_gas", [True, False], ids=["sufficient", "insufficient"]
)
def test_call_forwarded_gas_63_64(
state_test: StateTestFiller,
pre: Alloc,
fork: Fork,
sufficient_gas: bool,
) -> None:
"""
Verify the 63/64 forwarding budget is computed after the repriced
cold access charge.
A wrapper performs a cold, zero-value ``CALL`` requesting maximum
gas. The spec charges the repriced ``COLD_ACCOUNT_ACCESS``
up front and only then forwards ``floor(63/64 * gas_left)`` to the
child. The wrapper is handed an exact budget so that, net of the
access charge, ``gas_left`` equals ``child_execution * 64 // 63``;
forwarding then yields exactly the child's execution need
(``child_execution``) and its cold ``SSTORE`` takes effect. With one
gas less the floor drops below ``child_execution`` and the child OOGs,
so the slot stays zero. This pins that the floor is taken over
``gas_left`` already net of the post-8038 cold access cost (not
before it, and not double-charging it).
"""
sstore_state_gas = Op.SSTORE(new_value=1).state_cost(fork)
# Child: a single cold zero-to-nonzero SSTORE as proof of execution.
# Its execution need is the two operand pushes plus the cold storage
# write (the state portion is funded separately via the reservoir,
# which is passed to the child in full with no 63/64 rule).
child_code = Op.SSTORE(0, 1)
child = pre.deploy_contract(child_code)
child_execution = child_code.execution_cost(fork)
# Smallest budget whose 63/64 floor still reaches `child_execution`.
forward_budget = child_execution * 64 // 63
if not sufficient_gas:
forward_budget -= 1
# Wrapper: cold zero-value CALL requesting max gas (so the forwarded
# amount is bound by `gas_left`, not by the request). ret_size=0
# avoids any memory-expansion term.
wrapper_call = Op.CALL(
gas=0xFFFFFFFF,
address=child,
value=0,
args_offset=0,
args_size=0,
ret_offset=0,
ret_size=0,
)
wrapper = pre.deploy_contract(wrapper_call)
# At the wrapper's CALL the cold access charge is deducted first
# (folded with the operand pushes into its execution cost), leaving
# exactly `forward_budget` as `gas_left` for the 63/64 floor.
wrapper_gas = wrapper_call.execution_cost(fork) + forward_budget
# Outer caller hands the wrapper exactly `wrapper_gas`.
caller = pre.deploy_contract(
Op.POP(Op.CALL(gas=wrapper_gas, address=wrapper))
)
tx = Transaction(
to=caller,
sender=pre.fund_eoa(),
state_gas_reservoir=sstore_state_gas,
)
# Child SSTORE lands only when the forwarded floor reaches its need.
post = {child: Account(storage={0: 1 if sufficient_gas else 0})}
state_test(pre=pre, post=post, tx=tx)
|