Skip to content

test_reservoir_returned_on_oog()

Documentation for tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_call.py::test_reservoir_returned_on_oog@622620d8.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_call.py::test_reservoir_returned_on_oog --fork Amsterdam

Test state gas reservoir is returned to parent on child OOG.

The child draws the whole reservoir for an SSTORE then halts on its last gas, restoring it. Repeating that leaves the parent with only one SSTORE's execution cost, so its own SSTORE has nothing to spill from: it lands only if the reservoir came back.

Source code in tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_call.py
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
@pytest.mark.valid_from("EIP8037")
def test_reservoir_returned_on_oog(
    state_test: StateTestFiller,
    pre: Alloc,
    fork: Fork,
) -> None:
    """
    Test state gas reservoir is returned to parent on child OOG.

    The child draws the whole reservoir for an SSTORE then halts on its
    last gas, restoring it. Repeating that leaves the parent with only
    one SSTORE's execution cost, so its own SSTORE has nothing to spill
    from: it lands only if the reservoir came back.
    """
    sstore_state_gas = Op.SSTORE(new_value=1).state_cost(fork)

    child_code = Op.SSTORE(0, 1) + Op.INVALID
    child = pre.deploy_contract(code=child_code)

    parent_storage = Storage()
    final_sstore = Op.SSTORE(parent_storage.store_next(1), 1)
    # Without this metadata `WhileGas` sizes an iteration from the call
    # opcode alone, misses the forwarded gas, and exits too low.
    child_gas = child_code.execution_cost(fork)
    parent_code = (
        WhileGas(
            body=Op.POP(
                Op.CALL(
                    gas=child_gas,
                    address=child,
                    # gas accounting
                    address_warm=True,
                    inner_call_cost=child_gas,
                )
            ),
            fork=fork,
            extra_gas=final_sstore.execution_cost(fork),
        )
        + final_sstore
    )
    parent = pre.deploy_contract(code=parent_code)

    tx = Transaction(
        to=parent,
        state_gas_reservoir=sstore_state_gas,
        sender=pre.fund_eoa(),
    )

    post = {parent: Account(storage=parent_storage)}
    state_test(pre=pre, post=post, tx=tx)

Parametrized Test Cases

This test generates 1 parametrized test case across 1 fork.