@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)