From f1d889ddeb6320a0d4b64f0e7493ed9663c5a457 Mon Sep 17 00:00:00 2001 From: chugarchugarr Date: Wed, 26 Aug 2026 12:43:00 -0500 Subject: [PATCH 1/8] test(eip-8038): prove fixed-gas write-prepayment invariant --- .../test_write_prepayment_prototype.py | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py diff --git a/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py b/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py new file mode 100644 index 00000000000..aec13c7afe2 --- /dev/null +++ b/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py @@ -0,0 +1,131 @@ +"""Executable phase-1 proof for Glamsterdam storage-write prepayment. + +This test is intentionally smaller than a consensus change. It pins the +current EELS Osaka and Amsterdam gas constants and proves the two invariants +that must survive before a transaction encoding or EVM implementation is +worth adding: + +1. identical fixed child gas: Osaka PASS -> Amsterdam FAIL -> prepaid PASS; +2. the prepaid path preserves the full Amsterdam execution-resource charge. + +If either invariant fails as the Amsterdam branch changes, this prototype +must stop rather than silently adapt its claim. +""" + +from enum import Enum + +from ethereum.forks.amsterdam.vm.gas import GasCosts as AmsterdamGasCosts +from ethereum.forks.osaka.vm.gas import GasCosts as OsakaGasCosts + + +# Osaka's warm first-change write component. Osaka charges a cold existing +# non-zero -> non-zero first change as COLD_STORAGE_WRITE=5_000 total: +# 2_100 cold access + 2_900 write. Removing the 100 warm-access component +# leaves the historical write component that a prewarmed child frame paid. +LEGACY_STORAGE_WRITE = 2_800 + +# PUSH(value) + PUSH(key) around SSTORE. Both forks price these two PUSHes at +# VERY_LOW=3 each on the branch pinned by this test. +SSTORE_STACK_SETUP = 6 + +# Exactly enough for the minimal cold Osaka existing-slot overwrite. +FIXED_CHILD_GAS = 5_006 + + +class Outcome(Enum): + """Bounded result for the fixed-gas child execution.""" + + PASS = "PASS" + FAIL = "FAIL" + + +def _run_fixed_child(*, access_cost: int, write_cost: int) -> tuple[Outcome, int]: + """Evaluate the minimal SSTORE path against the immutable child budget.""" + required = SSTORE_STACK_SETUP + access_cost + write_cost + outcome = Outcome.PASS if required <= FIXED_CHILD_GAS else Outcome.FAIL + return outcome, required + + +def test_osaka_pass_amsterdam_fail_prepaid_pass() -> None: + """Pin the liveness flip and the proposed rescue under one fixed budget.""" + osaka_write_component = int(OsakaGasCosts.COLD_STORAGE_WRITE) - int( + OsakaGasCosts.COLD_STORAGE_ACCESS + ) + + osaka, osaka_required = _run_fixed_child( + access_cost=int(OsakaGasCosts.COLD_STORAGE_ACCESS), + write_cost=osaka_write_component, + ) + amsterdam, amsterdam_required = _run_fixed_child( + access_cost=int(AmsterdamGasCosts.COLD_STORAGE_ACCESS), + write_cost=int(AmsterdamGasCosts.STORAGE_WRITE), + ) + prepaid, prepaid_required = _run_fixed_child( + access_cost=int(AmsterdamGasCosts.WARM_ACCESS), + write_cost=LEGACY_STORAGE_WRITE, + ) + + assert osaka_write_component == 2_900 + assert osaka_required == 5_006 + assert amsterdam_required == 12_106 + assert prepaid_required == 2_906 + assert (osaka, amsterdam, prepaid) == ( + Outcome.PASS, + Outcome.FAIL, + Outcome.PASS, + ) + + +def test_prepayment_preserves_glamsterdam_execution_resource_charge() -> None: + """Move the repricing delta out of the child without discounting the work.""" + write_repricing_delta = ( + int(AmsterdamGasCosts.STORAGE_WRITE) - LEGACY_STORAGE_WRITE + ) + + # Ordinary Amsterdam path: the child first touches a cold account and a + # cold existing storage slot, then performs the first non-zero overwrite. + baseline_call_access = int(AmsterdamGasCosts.COLD_ACCOUNT_ACCESS) + baseline_storage = int(AmsterdamGasCosts.COLD_STORAGE_ACCESS) + int( + AmsterdamGasCosts.STORAGE_WRITE + ) + baseline_core_charge = baseline_call_access + baseline_storage + + # Proposed accounting split: + # - EIP-2930-style prepayment makes account and slot accesses warm; + # - the 7_200 write-repricing delta is paid outside the immutable child; + # - the child pays only warm access + the 2_800 historical write component. + prepaid_call_access = int(AmsterdamGasCosts.TX_ACCESS_LIST_ADDRESS) + int( + AmsterdamGasCosts.WARM_ACCESS + ) + prepaid_storage = ( + int(AmsterdamGasCosts.TX_ACCESS_LIST_STORAGE_KEY) + + int(AmsterdamGasCosts.WARM_ACCESS) + + write_repricing_delta + + LEGACY_STORAGE_WRITE + ) + prepaid_core_charge = prepaid_call_access + prepaid_storage + + assert write_repricing_delta == 7_200 + assert baseline_call_access == 3_000 + assert prepaid_call_access == baseline_call_access + assert baseline_storage == 12_100 + assert prepaid_storage == baseline_storage + assert prepaid_core_charge == baseline_core_charge == 15_100 + + +def test_prepayment_is_not_a_subsidy() -> None: + """The rescued child gets a smaller local charge, not cheaper global work.""" + local_prepaid_sstore = int(AmsterdamGasCosts.WARM_ACCESS) + LEGACY_STORAGE_WRITE + globally_paid_sstore = ( + int(AmsterdamGasCosts.TX_ACCESS_LIST_STORAGE_KEY) + + local_prepaid_sstore + + int(AmsterdamGasCosts.STORAGE_WRITE) + - LEGACY_STORAGE_WRITE + ) + + assert local_prepaid_sstore == 2_900 + assert globally_paid_sstore == ( + int(AmsterdamGasCosts.COLD_STORAGE_ACCESS) + + int(AmsterdamGasCosts.STORAGE_WRITE) + ) + assert local_prepaid_sstore < FIXED_CHILD_GAS From 395b251ace062098ab263aeb49f2d225257fe953 Mon Sep 17 00:00:00 2001 From: chugarchugarr Date: Wed, 26 Aug 2026 12:43:25 -0500 Subject: [PATCH 2/8] docs: define Glamsterdam write-prepayment proof gate --- .../glamsterdam-write-prepayment/README.md | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 prototypes/glamsterdam-write-prepayment/README.md diff --git a/prototypes/glamsterdam-write-prepayment/README.md b/prototypes/glamsterdam-write-prepayment/README.md new file mode 100644 index 00000000000..5915c6a9fad --- /dev/null +++ b/prototypes/glamsterdam-write-prepayment/README.md @@ -0,0 +1,137 @@ +# Glamsterdam Write Prepayment — Phase 1 + +Base: `ethereum/execution-specs@20f7f6271a720091e5fea0a82e7bc802866ae36a` (`forks/amsterdam`, 2026-08-26). + +## Decision gate + +Do not change consensus semantics and do not scan mainnet until the current +execution-spec constants prove both invariants: + +1. `Osaka PASS -> Amsterdam FAIL -> Amsterdam + prepayment PASS` under the + same immutable child-call gas budget. +2. Moving the repricing delta outside the child preserves the full Amsterdam + execution-resource charge. + +The executable proof is: + +`tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py` + +This phase is deliberately a branch-pinned accounting/liveness proof. It does +**not** yet define a new transaction encoding or modify EVM consensus behavior. +That implementation is the next gate only if this proof survives CI. + +## Minimal reproduction + +Use an existing non-zero storage slot and a child that executes: + +```text +PUSH value +PUSH key +SSTORE +``` + +Two `PUSH` instructions cost 6 execution gas. Give the child an immutable +5,006-gas budget. + +### Osaka + +For the first non-zero -> non-zero overwrite of a cold slot: + +```text +2,100 cold storage access ++ 2,900 write component ++ 6 stack setup += 5,006 +``` + +Result: `PASS`. + +### Amsterdam, unchanged + +Current `forks/amsterdam` constants: + +```text +2,100 COLD_STORAGE_ACCESS ++ 10,000 STORAGE_WRITE ++ 6 stack setup += 12,106 +``` + +The same immutable 5,006-gas child cannot execute it. + +Result: `FAIL`. + +### Amsterdam, write-prepaid + +Decompose the Amsterdam write price: + +```text +10,000 STORAGE_WRITE += 2,800 historical write component ++ 7,200 repricing delta +``` + +Prepay the 7,200 delta outside the child and prewarm the storage key. The +child sees: + +```text +100 warm access ++ 2,800 historical write component ++ 6 stack setup += 2,906 +``` + +Result: `PASS` under the same 5,006-gas child budget. + +## Conservation proof + +The mechanism is invalid if it makes Amsterdam work cheaper globally. + +Ordinary cold Amsterdam storage write: + +```text +2,100 cold access + 10,000 write = 12,100 +``` + +Prepaid split: + +```text +2,000 access-list storage-key prepayment ++ 100 warm access in the child ++ 7,200 write-repricing prepayment ++ 2,800 historical write component in the child += 12,100 +``` + +Account access conserves independently: + +```text +ordinary: 3,000 cold account access +prepaid: 2,900 access-list address prepayment + 100 warm runtime access + = 3,000 +``` + +Therefore the core state/call resource accounting is identical: + +```text +ordinary Amsterdam core charge = 3,000 + 12,100 = 15,100 +prepaid Amsterdam core charge = 3,000 + 12,100 = 15,100 +``` + +The proposal changes **where** the repricing delta is charged, not whether it +is charged. + +## Next gate + +Only after the phase-1 test passes: + +1. choose an explicit opt-in transaction representation for write vouchers; +2. implement voucher state and rollback semantics in EELS; +3. prove change -> restore -> change net-metering, nested-call revert/halt + behavior, duplicate voucher handling, and EIP-8037 state-gas interaction; +4. run the Amsterdam/Osaka test suites and independent client fixtures; +5. only then scan deployed mainnet bytecode for fixed-gas asset-release paths + and quantify value reachable only through failing paths. + +A mainnet value estimate before those gates would measure a hypothesis rather +than a demonstrated compatibility failure. From 1238b954768835c9a2203930fd57c51dc9dc05c5 Mon Sep 17 00:00:00 2001 From: chugarchugarr Date: Wed, 26 Aug 2026 12:46:34 -0500 Subject: [PATCH 3/8] fix: satisfy execution-specs static formatting --- .../test_write_prepayment_prototype.py | 67 ++++++++++--------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py b/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py index aec13c7afe2..498a8b0da27 100644 --- a/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py +++ b/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py @@ -1,4 +1,5 @@ -"""Executable phase-1 proof for Glamsterdam storage-write prepayment. +""" +Executable phase-1 proof for Glamsterdam storage-write prepayment. This test is intentionally smaller than a consensus change. It pins the current EELS Osaka and Amsterdam gas constants and proves the two invariants @@ -14,17 +15,17 @@ from enum import Enum -from ethereum.forks.amsterdam.vm.gas import GasCosts as AmsterdamGasCosts -from ethereum.forks.osaka.vm.gas import GasCosts as OsakaGasCosts +from ethereum.forks.amsterdam.vm import gas as amsterdam_gas +from ethereum.forks.osaka.vm import gas as osaka_gas -# Osaka's warm first-change write component. Osaka charges a cold existing +# Osaka's warm first-change write component. Osaka charges a cold existing # non-zero -> non-zero first change as COLD_STORAGE_WRITE=5_000 total: -# 2_100 cold access + 2_900 write. Removing the 100 warm-access component +# 2_100 cold access + 2_900 write. Removing the 100 warm-access component # leaves the historical write component that a prewarmed child frame paid. LEGACY_STORAGE_WRITE = 2_800 -# PUSH(value) + PUSH(key) around SSTORE. Both forks price these two PUSHes at +# PUSH(value) + PUSH(key) around SSTORE. Both forks price these two PUSHes at # VERY_LOW=3 each on the branch pinned by this test. SSTORE_STACK_SETUP = 6 @@ -39,7 +40,9 @@ class Outcome(Enum): FAIL = "FAIL" -def _run_fixed_child(*, access_cost: int, write_cost: int) -> tuple[Outcome, int]: +def _run_fixed_child( + *, access_cost: int, write_cost: int +) -> tuple[Outcome, int]: """Evaluate the minimal SSTORE path against the immutable child budget.""" required = SSTORE_STACK_SETUP + access_cost + write_cost outcome = Outcome.PASS if required <= FIXED_CHILD_GAS else Outcome.FAIL @@ -47,21 +50,21 @@ def _run_fixed_child(*, access_cost: int, write_cost: int) -> tuple[Outcome, int def test_osaka_pass_amsterdam_fail_prepaid_pass() -> None: - """Pin the liveness flip and the proposed rescue under one fixed budget.""" - osaka_write_component = int(OsakaGasCosts.COLD_STORAGE_WRITE) - int( - OsakaGasCosts.COLD_STORAGE_ACCESS + """Pin the liveness flip and proposed rescue under one fixed budget.""" + osaka_write_component = int(osaka_gas.GasCosts.COLD_STORAGE_WRITE) - int( + osaka_gas.GasCosts.COLD_STORAGE_ACCESS ) osaka, osaka_required = _run_fixed_child( - access_cost=int(OsakaGasCosts.COLD_STORAGE_ACCESS), + access_cost=int(osaka_gas.GasCosts.COLD_STORAGE_ACCESS), write_cost=osaka_write_component, ) amsterdam, amsterdam_required = _run_fixed_child( - access_cost=int(AmsterdamGasCosts.COLD_STORAGE_ACCESS), - write_cost=int(AmsterdamGasCosts.STORAGE_WRITE), + access_cost=int(amsterdam_gas.GasCosts.COLD_STORAGE_ACCESS), + write_cost=int(amsterdam_gas.GasCosts.STORAGE_WRITE), ) prepaid, prepaid_required = _run_fixed_child( - access_cost=int(AmsterdamGasCosts.WARM_ACCESS), + access_cost=int(amsterdam_gas.GasCosts.WARM_ACCESS), write_cost=LEGACY_STORAGE_WRITE, ) @@ -77,29 +80,29 @@ def test_osaka_pass_amsterdam_fail_prepaid_pass() -> None: def test_prepayment_preserves_glamsterdam_execution_resource_charge() -> None: - """Move the repricing delta out of the child without discounting the work.""" + """Move repricing out of the child without discounting the work.""" write_repricing_delta = ( - int(AmsterdamGasCosts.STORAGE_WRITE) - LEGACY_STORAGE_WRITE + int(amsterdam_gas.GasCosts.STORAGE_WRITE) - LEGACY_STORAGE_WRITE ) # Ordinary Amsterdam path: the child first touches a cold account and a # cold existing storage slot, then performs the first non-zero overwrite. - baseline_call_access = int(AmsterdamGasCosts.COLD_ACCOUNT_ACCESS) - baseline_storage = int(AmsterdamGasCosts.COLD_STORAGE_ACCESS) + int( - AmsterdamGasCosts.STORAGE_WRITE - ) + baseline_call_access = int(amsterdam_gas.GasCosts.COLD_ACCOUNT_ACCESS) + baseline_storage = int( + amsterdam_gas.GasCosts.COLD_STORAGE_ACCESS + ) + int(amsterdam_gas.GasCosts.STORAGE_WRITE) baseline_core_charge = baseline_call_access + baseline_storage # Proposed accounting split: # - EIP-2930-style prepayment makes account and slot accesses warm; # - the 7_200 write-repricing delta is paid outside the immutable child; # - the child pays only warm access + the 2_800 historical write component. - prepaid_call_access = int(AmsterdamGasCosts.TX_ACCESS_LIST_ADDRESS) + int( - AmsterdamGasCosts.WARM_ACCESS - ) + prepaid_call_access = int( + amsterdam_gas.GasCosts.TX_ACCESS_LIST_ADDRESS + ) + int(amsterdam_gas.GasCosts.WARM_ACCESS) prepaid_storage = ( - int(AmsterdamGasCosts.TX_ACCESS_LIST_STORAGE_KEY) - + int(AmsterdamGasCosts.WARM_ACCESS) + int(amsterdam_gas.GasCosts.TX_ACCESS_LIST_STORAGE_KEY) + + int(amsterdam_gas.GasCosts.WARM_ACCESS) + write_repricing_delta + LEGACY_STORAGE_WRITE ) @@ -114,18 +117,20 @@ def test_prepayment_preserves_glamsterdam_execution_resource_charge() -> None: def test_prepayment_is_not_a_subsidy() -> None: - """The rescued child gets a smaller local charge, not cheaper global work.""" - local_prepaid_sstore = int(AmsterdamGasCosts.WARM_ACCESS) + LEGACY_STORAGE_WRITE + """Prove lower local cost does not make global work cheaper.""" + local_prepaid_sstore = ( + int(amsterdam_gas.GasCosts.WARM_ACCESS) + LEGACY_STORAGE_WRITE + ) globally_paid_sstore = ( - int(AmsterdamGasCosts.TX_ACCESS_LIST_STORAGE_KEY) + int(amsterdam_gas.GasCosts.TX_ACCESS_LIST_STORAGE_KEY) + local_prepaid_sstore - + int(AmsterdamGasCosts.STORAGE_WRITE) + + int(amsterdam_gas.GasCosts.STORAGE_WRITE) - LEGACY_STORAGE_WRITE ) assert local_prepaid_sstore == 2_900 assert globally_paid_sstore == ( - int(AmsterdamGasCosts.COLD_STORAGE_ACCESS) - + int(AmsterdamGasCosts.STORAGE_WRITE) + int(amsterdam_gas.GasCosts.COLD_STORAGE_ACCESS) + + int(amsterdam_gas.GasCosts.STORAGE_WRITE) ) assert local_prepaid_sstore < FIXED_CHILD_GAS From 1113f3ff54f1ba45b5e64e34393ceb4086398502 Mon Sep 17 00:00:00 2001 From: chugarchugarr Date: Wed, 26 Aug 2026 12:48:41 -0500 Subject: [PATCH 4/8] fix: match ruff formatter in prototype test --- .../test_write_prepayment_prototype.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py b/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py index 498a8b0da27..af28fb33bf5 100644 --- a/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py +++ b/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py @@ -13,6 +13,8 @@ must stop rather than silently adapt its claim. """ +# ruff: noqa: I001 + from enum import Enum from ethereum.forks.amsterdam.vm import gas as amsterdam_gas @@ -88,9 +90,9 @@ def test_prepayment_preserves_glamsterdam_execution_resource_charge() -> None: # Ordinary Amsterdam path: the child first touches a cold account and a # cold existing storage slot, then performs the first non-zero overwrite. baseline_call_access = int(amsterdam_gas.GasCosts.COLD_ACCOUNT_ACCESS) - baseline_storage = int( - amsterdam_gas.GasCosts.COLD_STORAGE_ACCESS - ) + int(amsterdam_gas.GasCosts.STORAGE_WRITE) + baseline_storage = int(amsterdam_gas.GasCosts.COLD_STORAGE_ACCESS) + int( + amsterdam_gas.GasCosts.STORAGE_WRITE + ) baseline_core_charge = baseline_call_access + baseline_storage # Proposed accounting split: From 7148798715c78fa5208e89bea6df525d79bb18aa Mon Sep 17 00:00:00 2001 From: chugarchugarr Date: Wed, 26 Aug 2026 12:50:04 -0500 Subject: [PATCH 5/8] test: pin proof directly to fork gas sources --- .../test_write_prepayment_prototype.py | 191 +++++++++--------- 1 file changed, 97 insertions(+), 94 deletions(-) diff --git a/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py b/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py index af28fb33bf5..a0071631d98 100644 --- a/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py +++ b/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py @@ -1,138 +1,141 @@ """ Executable phase-1 proof for Glamsterdam storage-write prepayment. -This test is intentionally smaller than a consensus change. It pins the -current EELS Osaka and Amsterdam gas constants and proves the two invariants -that must survive before a transaction encoding or EVM implementation is -worth adding: - -1. identical fixed child gas: Osaka PASS -> Amsterdam FAIL -> prepaid PASS; -2. the prepaid path preserves the full Amsterdam execution-resource charge. - -If either invariant fails as the Amsterdam branch changes, this prototype -must stop rather than silently adapt its claim. +The proof reads the Osaka and Amsterdam gas constants directly from the +current execution-spec source tree. It must fail if those branch constants +move enough to invalidate either the liveness transition or conservation +claim. """ -# ruff: noqa: I001 - -from enum import Enum - -from ethereum.forks.amsterdam.vm import gas as amsterdam_gas -from ethereum.forks.osaka.vm import gas as osaka_gas - - -# Osaka's warm first-change write component. Osaka charges a cold existing -# non-zero -> non-zero first change as COLD_STORAGE_WRITE=5_000 total: -# 2_100 cold access + 2_900 write. Removing the 100 warm-access component -# leaves the historical write component that a prewarmed child frame paid. -LEGACY_STORAGE_WRITE = 2_800 +OSAKA_GAS_PATH = "src/ethereum/forks/osaka/vm/gas.py" +AMSTERDAM_GAS_PATH = "src/ethereum/forks/amsterdam/vm/gas.py" -# PUSH(value) + PUSH(key) around SSTORE. Both forks price these two PUSHes at -# VERY_LOW=3 each on the branch pinned by this test. -SSTORE_STACK_SETUP = 6 -# Exactly enough for the minimal cold Osaka existing-slot overwrite. -FIXED_CHILD_GAS = 5_006 +def _uint_constant(path: str, name: str) -> int: + """Read a direct ``Uint(...)`` gas constant from a fork gas module.""" + with open(path, encoding="utf-8") as source_file: + for line in source_file: + stripped = line.strip() + if stripped.startswith(f"{name}:") and "Uint(" in stripped: + raw_value = stripped.rsplit("Uint(", 1)[1].split(")", 1)[0] + return int(raw_value) + raise AssertionError(f"direct Uint constant not found: {path}:{name}") -class Outcome(Enum): - """Bounded result for the fixed-gas child execution.""" +def _amsterdam_access_list_formulas_survive() -> None: + """Pin the access-list prepayment formulas used by the proof.""" + with open(AMSTERDAM_GAS_PATH, encoding="utf-8") as source_file: + source = source_file.read() - PASS = "PASS" - FAIL = "FAIL" - - -def _run_fixed_child( - *, access_cost: int, write_cost: int -) -> tuple[Outcome, int]: - """Evaluate the minimal SSTORE path against the immutable child budget.""" - required = SSTORE_STACK_SETUP + access_cost + write_cost - outcome = Outcome.PASS if required <= FIXED_CHILD_GAS else Outcome.FAIL - return outcome, required + assert "TX_ACCESS_LIST_ADDRESS: Final[ExecutionGas] = (" in source + assert "COLD_ACCOUNT_ACCESS - WARM_ACCESS" in source + assert "TX_ACCESS_LIST_STORAGE_KEY: Final[ExecutionGas] = (" in source + assert "COLD_STORAGE_ACCESS - WARM_ACCESS" in source def test_osaka_pass_amsterdam_fail_prepaid_pass() -> None: - """Pin the liveness flip and proposed rescue under one fixed budget.""" - osaka_write_component = int(osaka_gas.GasCosts.COLD_STORAGE_WRITE) - int( - osaka_gas.GasCosts.COLD_STORAGE_ACCESS + """Prove one immutable child budget flips PASS -> FAIL -> PASS.""" + osaka_warm = _uint_constant(OSAKA_GAS_PATH, "WARM_ACCESS") + osaka_cold_storage = _uint_constant( + OSAKA_GAS_PATH, "COLD_STORAGE_ACCESS" ) + osaka_cold_write = _uint_constant(OSAKA_GAS_PATH, "COLD_STORAGE_WRITE") + osaka_push = _uint_constant(OSAKA_GAS_PATH, "VERY_LOW") - osaka, osaka_required = _run_fixed_child( - access_cost=int(osaka_gas.GasCosts.COLD_STORAGE_ACCESS), - write_cost=osaka_write_component, - ) - amsterdam, amsterdam_required = _run_fixed_child( - access_cost=int(amsterdam_gas.GasCosts.COLD_STORAGE_ACCESS), - write_cost=int(amsterdam_gas.GasCosts.STORAGE_WRITE), + amsterdam_warm = _uint_constant(AMSTERDAM_GAS_PATH, "WARM_ACCESS") + amsterdam_cold_storage = _uint_constant( + AMSTERDAM_GAS_PATH, "COLD_STORAGE_ACCESS" ) - prepaid, prepaid_required = _run_fixed_child( - access_cost=int(amsterdam_gas.GasCosts.WARM_ACCESS), - write_cost=LEGACY_STORAGE_WRITE, + amsterdam_write = _uint_constant(AMSTERDAM_GAS_PATH, "STORAGE_WRITE") + amsterdam_push = _uint_constant(AMSTERDAM_GAS_PATH, "VERY_LOW") + + legacy_write = osaka_cold_write - osaka_cold_storage - osaka_warm + fixed_child_gas = osaka_cold_write + 2 * osaka_push + + osaka_required = osaka_cold_write + 2 * osaka_push + amsterdam_required = ( + amsterdam_cold_storage + amsterdam_write + 2 * amsterdam_push ) + prepaid_required = amsterdam_warm + legacy_write + 2 * amsterdam_push - assert osaka_write_component == 2_900 + assert legacy_write == 2_800 + assert fixed_child_gas == 5_006 assert osaka_required == 5_006 assert amsterdam_required == 12_106 assert prepaid_required == 2_906 - assert (osaka, amsterdam, prepaid) == ( - Outcome.PASS, - Outcome.FAIL, - Outcome.PASS, - ) + + assert osaka_required <= fixed_child_gas + assert amsterdam_required > fixed_child_gas + assert prepaid_required <= fixed_child_gas def test_prepayment_preserves_glamsterdam_execution_resource_charge() -> None: - """Move repricing out of the child without discounting the work.""" - write_repricing_delta = ( - int(amsterdam_gas.GasCosts.STORAGE_WRITE) - LEGACY_STORAGE_WRITE + """Prove repricing relocation preserves the full Amsterdam core charge.""" + _amsterdam_access_list_formulas_survive() + + osaka_warm = _uint_constant(OSAKA_GAS_PATH, "WARM_ACCESS") + osaka_cold_storage = _uint_constant( + OSAKA_GAS_PATH, "COLD_STORAGE_ACCESS" ) + osaka_cold_write = _uint_constant(OSAKA_GAS_PATH, "COLD_STORAGE_WRITE") - # Ordinary Amsterdam path: the child first touches a cold account and a - # cold existing storage slot, then performs the first non-zero overwrite. - baseline_call_access = int(amsterdam_gas.GasCosts.COLD_ACCOUNT_ACCESS) - baseline_storage = int(amsterdam_gas.GasCosts.COLD_STORAGE_ACCESS) + int( - amsterdam_gas.GasCosts.STORAGE_WRITE + amsterdam_warm = _uint_constant(AMSTERDAM_GAS_PATH, "WARM_ACCESS") + amsterdam_cold_account = _uint_constant( + AMSTERDAM_GAS_PATH, "COLD_ACCOUNT_ACCESS" + ) + amsterdam_cold_storage = _uint_constant( + AMSTERDAM_GAS_PATH, "COLD_STORAGE_ACCESS" ) + amsterdam_write = _uint_constant(AMSTERDAM_GAS_PATH, "STORAGE_WRITE") + + legacy_write = osaka_cold_write - osaka_cold_storage - osaka_warm + write_repricing_delta = amsterdam_write - legacy_write + access_list_address = amsterdam_cold_account - amsterdam_warm + access_list_storage_key = amsterdam_cold_storage - amsterdam_warm + + baseline_call_access = amsterdam_cold_account + baseline_storage = amsterdam_cold_storage + amsterdam_write baseline_core_charge = baseline_call_access + baseline_storage - # Proposed accounting split: - # - EIP-2930-style prepayment makes account and slot accesses warm; - # - the 7_200 write-repricing delta is paid outside the immutable child; - # - the child pays only warm access + the 2_800 historical write component. - prepaid_call_access = int( - amsterdam_gas.GasCosts.TX_ACCESS_LIST_ADDRESS - ) + int(amsterdam_gas.GasCosts.WARM_ACCESS) + prepaid_call_access = access_list_address + amsterdam_warm prepaid_storage = ( - int(amsterdam_gas.GasCosts.TX_ACCESS_LIST_STORAGE_KEY) - + int(amsterdam_gas.GasCosts.WARM_ACCESS) + access_list_storage_key + + amsterdam_warm + write_repricing_delta - + LEGACY_STORAGE_WRITE + + legacy_write ) prepaid_core_charge = prepaid_call_access + prepaid_storage assert write_repricing_delta == 7_200 - assert baseline_call_access == 3_000 - assert prepaid_call_access == baseline_call_access - assert baseline_storage == 12_100 - assert prepaid_storage == baseline_storage - assert prepaid_core_charge == baseline_core_charge == 15_100 + assert baseline_call_access == prepaid_call_access == 3_000 + assert baseline_storage == prepaid_storage == 12_100 + assert baseline_core_charge == prepaid_core_charge == 15_100 def test_prepayment_is_not_a_subsidy() -> None: - """Prove lower local cost does not make global work cheaper.""" - local_prepaid_sstore = ( - int(amsterdam_gas.GasCosts.WARM_ACCESS) + LEGACY_STORAGE_WRITE + """Prove the rescued local frame does not make global work cheaper.""" + osaka_warm = _uint_constant(OSAKA_GAS_PATH, "WARM_ACCESS") + osaka_cold_storage = _uint_constant( + OSAKA_GAS_PATH, "COLD_STORAGE_ACCESS" ) + osaka_cold_write = _uint_constant(OSAKA_GAS_PATH, "COLD_STORAGE_WRITE") + + amsterdam_warm = _uint_constant(AMSTERDAM_GAS_PATH, "WARM_ACCESS") + amsterdam_cold_storage = _uint_constant( + AMSTERDAM_GAS_PATH, "COLD_STORAGE_ACCESS" + ) + amsterdam_write = _uint_constant(AMSTERDAM_GAS_PATH, "STORAGE_WRITE") + + legacy_write = osaka_cold_write - osaka_cold_storage - osaka_warm + write_repricing_delta = amsterdam_write - legacy_write + access_list_storage_key = amsterdam_cold_storage - amsterdam_warm + + local_prepaid_sstore = amsterdam_warm + legacy_write globally_paid_sstore = ( - int(amsterdam_gas.GasCosts.TX_ACCESS_LIST_STORAGE_KEY) + access_list_storage_key + local_prepaid_sstore - + int(amsterdam_gas.GasCosts.STORAGE_WRITE) - - LEGACY_STORAGE_WRITE + + write_repricing_delta ) assert local_prepaid_sstore == 2_900 - assert globally_paid_sstore == ( - int(amsterdam_gas.GasCosts.COLD_STORAGE_ACCESS) - + int(amsterdam_gas.GasCosts.STORAGE_WRITE) - ) - assert local_prepaid_sstore < FIXED_CHILD_GAS + assert globally_paid_sstore == amsterdam_cold_storage + amsterdam_write From 1ef561e1c545ae9bc64764c8a180896ad2cc1fba Mon Sep 17 00:00:00 2001 From: chugarchugarr Date: Wed, 26 Aug 2026 12:52:10 -0500 Subject: [PATCH 6/8] ci: expose prototype ruff format diff --- .github/workflows/prototype-format-diff.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/prototype-format-diff.yml diff --git a/.github/workflows/prototype-format-diff.yml b/.github/workflows/prototype-format-diff.yml new file mode 100644 index 00000000000..cfc6b34f6b3 --- /dev/null +++ b/.github/workflows/prototype-format-diff.yml @@ -0,0 +1,19 @@ +name: Prototype format diff + +on: + pull_request: + paths: + - "tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py" + - ".github/workflows/prototype-format-diff.yml" + +permissions: + contents: read + +jobs: + diff: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - uses: ./.github/actions/setup-uv + - name: Show Ruff format diff + run: uv run ruff format --diff tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py From ec41330f3d57a10757f9a09ee7da0e01c26cc1b0 Mon Sep 17 00:00:00 2001 From: chugarchugarr Date: Wed, 26 Aug 2026 12:53:09 -0500 Subject: [PATCH 7/8] style: apply Ruff formatter output --- .../test_write_prepayment_prototype.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py b/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py index a0071631d98..75e2b5445c9 100644 --- a/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py +++ b/tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py @@ -36,9 +36,7 @@ def _amsterdam_access_list_formulas_survive() -> None: def test_osaka_pass_amsterdam_fail_prepaid_pass() -> None: """Prove one immutable child budget flips PASS -> FAIL -> PASS.""" osaka_warm = _uint_constant(OSAKA_GAS_PATH, "WARM_ACCESS") - osaka_cold_storage = _uint_constant( - OSAKA_GAS_PATH, "COLD_STORAGE_ACCESS" - ) + osaka_cold_storage = _uint_constant(OSAKA_GAS_PATH, "COLD_STORAGE_ACCESS") osaka_cold_write = _uint_constant(OSAKA_GAS_PATH, "COLD_STORAGE_WRITE") osaka_push = _uint_constant(OSAKA_GAS_PATH, "VERY_LOW") @@ -74,9 +72,7 @@ def test_prepayment_preserves_glamsterdam_execution_resource_charge() -> None: _amsterdam_access_list_formulas_survive() osaka_warm = _uint_constant(OSAKA_GAS_PATH, "WARM_ACCESS") - osaka_cold_storage = _uint_constant( - OSAKA_GAS_PATH, "COLD_STORAGE_ACCESS" - ) + osaka_cold_storage = _uint_constant(OSAKA_GAS_PATH, "COLD_STORAGE_ACCESS") osaka_cold_write = _uint_constant(OSAKA_GAS_PATH, "COLD_STORAGE_WRITE") amsterdam_warm = _uint_constant(AMSTERDAM_GAS_PATH, "WARM_ACCESS") @@ -115,9 +111,7 @@ def test_prepayment_preserves_glamsterdam_execution_resource_charge() -> None: def test_prepayment_is_not_a_subsidy() -> None: """Prove the rescued local frame does not make global work cheaper.""" osaka_warm = _uint_constant(OSAKA_GAS_PATH, "WARM_ACCESS") - osaka_cold_storage = _uint_constant( - OSAKA_GAS_PATH, "COLD_STORAGE_ACCESS" - ) + osaka_cold_storage = _uint_constant(OSAKA_GAS_PATH, "COLD_STORAGE_ACCESS") osaka_cold_write = _uint_constant(OSAKA_GAS_PATH, "COLD_STORAGE_WRITE") amsterdam_warm = _uint_constant(AMSTERDAM_GAS_PATH, "WARM_ACCESS") @@ -132,9 +126,7 @@ def test_prepayment_is_not_a_subsidy() -> None: local_prepaid_sstore = amsterdam_warm + legacy_write globally_paid_sstore = ( - access_list_storage_key - + local_prepaid_sstore - + write_repricing_delta + access_list_storage_key + local_prepaid_sstore + write_repricing_delta ) assert local_prepaid_sstore == 2_900 From f51a4238dc2787f7695177b798d4dd3bbc0c662b Mon Sep 17 00:00:00 2001 From: chugarchugarr Date: Wed, 26 Aug 2026 12:53:20 -0500 Subject: [PATCH 8/8] ci: remove temporary format-diff workflow --- .github/workflows/prototype-format-diff.yml | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 .github/workflows/prototype-format-diff.yml diff --git a/.github/workflows/prototype-format-diff.yml b/.github/workflows/prototype-format-diff.yml deleted file mode 100644 index cfc6b34f6b3..00000000000 --- a/.github/workflows/prototype-format-diff.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Prototype format diff - -on: - pull_request: - paths: - - "tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py" - - ".github/workflows/prototype-format-diff.yml" - -permissions: - contents: read - -jobs: - diff: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - - uses: ./.github/actions/setup-uv - - name: Show Ruff format diff - run: uv run ruff format --diff tests/amsterdam/eip8038_state_access_gas_cost_increase/test_write_prepayment_prototype.py