Skip to content

test_invalid_gas_consumption()

Documentation for tests/byzantium/eip196_ec_add_mul/test_gas.py::test_invalid_gas_consumption@ffe48572.

Generate fixtures for these test cases for Bogota with:

fill -v tests/byzantium/eip196_ec_add_mul/test_gas.py::test_invalid_gas_consumption --fork Bogota

Test that invalid inputs to ecadd/ecmul consume all forwarded gas.

Use CodeGasMeasure to verify the STATICCALL with invalid input consumes exactly the warm call cost plus all forwarded gas.

Source code in tests/byzantium/eip196_ec_add_mul/test_gas.py
@pytest.mark.valid_from("Byzantium")
@pytest.mark.parametrize(
    "precompile_address, invalid_input",
    [
        pytest.param(
            Spec.ECADD,
            PointG1(1, 3) + Spec.INF_G1,
            id="ecadd",
        ),
        pytest.param(
            Spec.ECMUL,
            PointG1(1, 3) + Scalar(1),
            id="ecmul",
        ),
    ],
)
@pytest.mark.parametrize(
    "extra_gas",
    [
        pytest.param(0, id="exact"),
        pytest.param(100_000, id="extra_100k"),
    ],
)
def test_invalid_gas_consumption(
    state_test: StateTestFiller,
    pre: Alloc,
    fork: Fork,
    precompile_address: Address,
    precompile_gas: int,
    invalid_input: bytes,
    extra_gas: int,
) -> None:
    """
    Test that invalid inputs to ecadd/ecmul consume all forwarded gas.

    Use CodeGasMeasure to verify the STATICCALL with invalid input
    consumes exactly the warm call cost plus all forwarded gas.
    """
    gas_forward = precompile_gas + extra_gas
    input_size = len(invalid_input)
    storage = Storage()

    staticcall_code = Op.STATICCALL(
        gas=gas_forward,
        address=precompile_address,
        args_size=input_size,
    )
    push_cost = staticcall_code.gas_cost(fork) - Op.STATICCALL(
        address_warm=False
    ).gas_cost(fork)

    # Precompiles are warm from Berlin, flat call cost before.
    staticcall_base = Op.STATICCALL(address_warm=True).gas_cost(fork)

    account = pre.deploy_contract(
        code=(
            Om.MSTORE(invalid_input)
            # Warm the precompile address
            + Op.POP(Op.STATICCALL(gas=0, address=precompile_address))
            + CodeGasMeasure(
                code=staticcall_code,
                overhead_cost=push_cost,
                extra_stack_items=1,
                sstore_key=storage.store_next(staticcall_base + gas_forward),
            )
        ),
        storage=storage.canary(),
    )

    tx = Transaction(
        to=account,
        sender=pre.fund_eoa(),
        gas_limit=1_000_000,
        protected=True,
    )

    post = {account: Account(storage=storage)}

    state_test(pre=pre, post=post, tx=tx)

Parametrized Test Cases

This test generates 4 parametrized test cases across 13 forks.