Skip to content

test_call_value_new_account_state_gas_consumed_on_caller_halt()

Documentation for tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_call.py::test_call_value_new_account_state_gas_consumed_on_caller_halt@2119b382.

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_call_value_new_account_state_gas_consumed_on_caller_halt --fork Amsterdam

Consume a spilled NEW_ACCOUNT charge when the caller exceptionally halts.

The caller value-CALLs a zero-balance target, charging NEW_ACCOUNT state gas in its own frame; with an empty reservoir the charge spills into gas_left. Two child outcomes share identical accounting: a plain new account, where the CALL materializes it and succeeds, and the bn256 pairing precompile forwarded only the value stipend, where the CALL fails in the child and the charge is refilled to gas_left in LIFO order. The caller then hits INVALID; the halt burns all of gas_left, including the spilled charge, and resets the reservoir to its start-of-frame value. The sender pays the full regular budget: the whole gas_limit in-cap, or the EIP-7825 gas cap over-cap (the restored reservoir is refunded). The value transfer is rolled back, leaving target absent and the caller balance intact.

Both target_kind variants assert the same totals by design; the child-failure refill itself is pinned by the probe in test_call_value_precompile_halt_refunds_new_account_state_gas.

Source code in tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_call.py
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
@pytest.mark.parametrize("target_kind", ["new_account", "precompile"])
@pytest.mark.parametrize("reservoir", ["in_cap", "over_cap"])
@pytest.mark.valid_from("EIP8037")
def test_call_value_new_account_state_gas_consumed_on_caller_halt(
    state_test: StateTestFiller,
    pre: Alloc,
    fork: Fork,
    reservoir: str,
    target_kind: str,
) -> None:
    """
    Consume a spilled NEW_ACCOUNT charge when the caller exceptionally halts.

    The caller value-CALLs a zero-balance `target`, charging `NEW_ACCOUNT`
    state gas in its own frame; with an empty reservoir the charge spills into
    `gas_left`. Two child outcomes share identical accounting: a plain new
    account, where the CALL materializes it and succeeds, and the bn256
    pairing precompile forwarded only the value stipend, where the CALL fails
    in the child and the charge is refilled to `gas_left` in LIFO order. The
    caller then hits `INVALID`; the halt burns all of `gas_left`, including
    the spilled charge, and resets the reservoir to its start-of-frame value.
    The sender pays the full regular budget: the whole `gas_limit` in-cap, or
    the EIP-7825 gas cap over-cap (the restored reservoir is refunded). The
    value transfer is rolled back, leaving `target` absent and the caller
    balance intact.

    Both `target_kind` variants assert the same totals by design; the
    child-failure refill itself is pinned by the probe in
    `test_call_value_precompile_halt_refunds_new_account_state_gas`.
    """
    value = 1
    # gas=0 forwards only the value stipend: ignored by the empty account
    # (CALL succeeds), far below the precompile base cost (CALL fails).
    target = (
        Address(0x08)
        if target_kind == "precompile"
        else pre.nonexistent_account()
    )
    caller = pre.deploy_contract(
        code=Op.CALL(gas=0, address=target, value=value) + Op.INVALID,
        balance=value,
    )
    sender = pre.fund_eoa()

    gas_limit_cap = fork.transaction_gas_limit_cap()
    assert gas_limit_cap is not None

    if reservoir == "over_cap":
        # The excess over the EIP-7825 cap becomes the reservoir.
        gas_limit = gas_limit_cap + fork.gas_costs().NEW_ACCOUNT // 2
        expected_gas_used = gas_limit_cap
    else:
        gas_limit = 1_000_000
        expected_gas_used = gas_limit

    tx = Transaction(
        to=caller,
        sender=sender,
        gas_limit=gas_limit,
        expected_receipt=TransactionReceipt(
            cumulative_gas_used=expected_gas_used
        ),
    )

    post = {
        caller: Account(balance=value),
        target: Account.NONEXISTENT,
    }
    state_test(pre=pre, post=post, tx=tx)

Parametrized Test Cases

This test generates 4 parametrized test cases across 1 fork.