Skip to content

test_storage_warm_status_reverted_by_subcall()

Documentation for tests/berlin/eip2929_gas_cost_increases/test_warm_status_revert.py::test_storage_warm_status_reverted_by_subcall@b47f0253.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/berlin/eip2929_gas_cost_increases/test_warm_status_revert.py::test_storage_warm_status_reverted_by_subcall --fork Amsterdam

Test that storage slot warm status is reverted when a sub-call reverts.

Inner self-call does SLOAD(0) and SSTORE(0, 2) then REVERTs. After revert, SLOAD(0) must be a cold access and storage[0] must still hold its original value.

Source code in tests/berlin/eip2929_gas_cost_increases/test_warm_status_revert.py
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
@pytest.mark.valid_from("Berlin")
def test_storage_warm_status_reverted_by_subcall(
    state_test: StateTestFiller,
    pre: Alloc,
    fork: Fork,
) -> None:
    """
    Test that storage slot warm status is reverted when a sub-call reverts.

    Inner self-call does SLOAD(0) and SSTORE(0, 2) then REVERTs. After
    revert, SLOAD(0) must be a cold access and storage[0] must still
    hold its original value.
    """
    env = Environment()

    # Inner behavior (no calldata): warm slot 0 via SLOAD+SSTORE, revert.
    inner_code = (
        Op.POP(Op.SLOAD(0)) + Op.SSTORE(0, 2) + Op.REVERT(offset=0, size=0)
    )

    # Overhead: PUSH instructions for the SLOAD key argument.
    sload_push_cost = (Op.PUSH1(0) * len(Op.SLOAD.kwargs)).gas_cost(fork)
    cold_sload_cost = Op.SLOAD(key_warm=False).gas_cost(fork)

    # After revert, measure gas of SLOAD(0) — should be cold.
    sload_measure = CodeGasMeasure(
        code=Op.SLOAD(0),
        overhead_cost=sload_push_cost,
        extra_stack_items=1,
        sstore_key=1,
        stop=False,
    )

    # Also verify storage[0] value (should still be 1).
    verify_value = Op.SSTORE(2, Op.SLOAD(0))

    # Outer behavior (has calldata): call self (inner), measure, verify.
    outer_code = (
        Op.POP(Op.CALL(gas=100_000, address=Op.ADDRESS))
        + sload_measure
        + verify_value
        + Op.STOP
    )

    code = Conditional(
        condition=Op.CALLDATASIZE,
        if_true=outer_code,
        if_false=inner_code,
    )

    contract = pre.deploy_contract(code, storage={0: 1})
    sender = pre.fund_eoa()

    state_test(
        env=env,
        pre=pre,
        post={
            contract: Account(
                storage={0: 1, 1: cold_sload_cost, 2: 1},
            ),
        },
        tx=Transaction(
            sender=sender,
            to=contract,
            gas_limit=1_000_000,
            data=b"\x01",
        ),
    )

Parametrized Test Cases

This test generates 1 parametrized test case across 8 forks.