Skip to content

test_bls12_381_uncachable()

Documentation for tests/benchmark/compute/precompile/test_bls12_381.py::test_bls12_381_uncachable@ffe48572.

Generate fixtures for these test cases for Bogota with:

fill -v tests/benchmark/compute/precompile/test_bls12_381.py::test_bls12_381_uncachable --gas-benchmark-values 1

Benchmark BLS12_381 with unique input per call.

Each iteration writes the precompile output back to the start of the input so every call receives a distinct input, avoiding precompile result caching in clients.

Source code in tests/benchmark/compute/precompile/test_bls12_381.py
@pytest.mark.repricing
@pytest.mark.parametrize(
    "precompile_address,ret_size,generate_calldata,target",
    [
        pytest.param(
            bls12381_spec.Spec.G1ADD,
            128,
            _g1add_calldata,
            Precompile.BLS12_G1ADD,
            id="bls12_g1add",
        ),
        pytest.param(
            bls12381_spec.Spec.G2ADD,
            256,
            _g2add_calldata,
            Precompile.BLS12_G2ADD,
            id="bls12_g2add",
        ),
        pytest.param(
            bls12381_spec.Spec.G1MSM,
            128,
            _g1msm_calldata,
            Precompile.BLS12_G1MSM,
            id="bls12_g1msm",
        ),
        pytest.param(
            bls12381_spec.Spec.G2MSM,
            256,
            _g2msm_calldata,
            Precompile.BLS12_G2MSM,
            id="bls12_g2msm",
        ),
        pytest.param(
            bls12381_spec.Spec.MAP_FP_TO_G1,
            64,
            _fp_to_g1_calldata,
            Precompile.BLS12_MAP_FP_TO_G1,
            id="bls12_fp_to_g1",
        ),
        pytest.param(
            bls12381_spec.Spec.MAP_FP2_TO_G2,
            128,
            _fp2_to_g2_calldata,
            Precompile.BLS12_MAP_FP2_TO_G2,
            id="bls12_fp_to_g2",
        ),
    ],
)
def test_bls12_381_uncachable(
    benchmark_test: BenchmarkTestFiller,
    pre: Alloc,
    fork: Fork,
    gas_benchmark_value: int,
    tx_gas_limit: int,
    precompile_address: Address,
    ret_size: int,
    generate_calldata: Callable[[int], Bytes],
    target: OpcodeTarget,
) -> None:
    """
    Benchmark BLS12_381 with unique input per call.

    Each iteration writes the precompile output back to the
    start of the input so every call receives a distinct input,
    avoiding precompile result caching in clients.
    """
    if precompile_address not in fork.precompiles():
        pytest.skip("Precompile not enabled")

    intrinsic_gas_calculator = fork.transaction_intrinsic_cost_calculator()
    gas_calc_map = build_gas_calculation_function_map(fork.gas_costs())
    input_size = len(generate_calldata(0))
    precompile_cost = gas_calc_map[int(precompile_address)](input_size)

    attack_block = Op.POP(
        Op.STATICCALL(
            gas=Op.GAS,
            address=precompile_address,
            args_size=Op.CALLDATASIZE,
            ret_size=ret_size,
            # gas accounting
            address_warm=True,
            inner_call_cost=precompile_cost,
        ),
    )

    setup = Op.CALLDATACOPY(
        0,
        0,
        Op.CALLDATASIZE,
        # gas accounting
        data_size=input_size,
        new_memory_size=input_size,
    )
    setup_cost = setup.gas_cost(fork)

    loop = WhileGas(body=attack_block, fork=fork)

    code = setup + loop
    attack_contract_address = pre.deploy_contract(code=code)

    iteration_cost = loop.gas_cost(fork)

    txs: list[Transaction] = []
    remaining_gas = gas_benchmark_value
    seed = 0
    expected_opcode_count = 0
    while remaining_gas > 0:
        per_tx_gas = min(tx_gas_limit, remaining_gas)
        calldata = generate_calldata(seed)

        intrinsic = intrinsic_gas_calculator(
            calldata=calldata,
            return_cost_deducted_prior_execution=True,
        )
        gas_for_loop = per_tx_gas - intrinsic - setup_cost
        if gas_for_loop < iteration_cost:
            break
        expected_opcode_count += gas_for_loop // iteration_cost

        txs.append(
            Transaction(
                to=attack_contract_address,
                sender=pre.fund_eoa(),
                gas_limit=per_tx_gas,
                data=calldata,
            )
        )
        remaining_gas -= per_tx_gas
        seed += 1

    assert len(txs) != 0, "No transactions were added to the test."

    benchmark_test(
        target_opcode=target,
        skip_gas_used_validation=True,
        verifications=[ReceiptStatusExpected()],
        blocks=[Block(txs=txs)],
        expected_opcode_count=expected_opcode_count,
    )

Parametrized Test Cases

This test generates 6 parametrized test cases across 4 forks.