Skip to content

test_bls12_msm()

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

Generate fixtures for these test cases for Bogota with:

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

Benchmark a BLS12 MSM precompile with varying number of points.

Source code in tests/benchmark/compute/precompile/test_bls12_381.py
@pytest.mark.repricing
@pytest.mark.parametrize(
    "precompile_address,generate_point,target",
    [
        pytest.param(
            bls12381_spec.Spec.G1MSM,
            _generate_bls12_g1_point,
            Precompile.BLS12_G1MSM,
            id="bls12_g1msm",
        ),
        pytest.param(
            bls12381_spec.Spec.G2MSM,
            _generate_bls12_g2_point,
            Precompile.BLS12_G2MSM,
            id="bls12_g2msm",
        ),
    ],
)
@pytest.mark.parametrize(
    "k",
    [
        1,
        16,
        64,
        # A G2 MSM at k=128 costs 1.5M gas.
        pytest.param(128, marks=pytest.mark.slow),
    ],
)
def test_bls12_msm(
    benchmark_test: BenchmarkTestFiller,
    pre: Alloc,
    fork: Fork,
    gas_benchmark_value: int,
    tx_gas_limit: int,
    precompile_address: int,
    generate_point: Callable[[int], Bytes],
    target: OpcodeTarget,
    k: int,
) -> None:
    """Benchmark a BLS12 MSM precompile with varying number of points."""
    if precompile_address not in fork.precompiles():
        pytest.skip(f"{target} precompile not enabled")

    input_data = _msm_worstcase_input(k, generate_point)
    gas_calc_map = build_gas_calculation_function_map(fork.gas_costs())
    precompile_cost = gas_calc_map[precompile_address](len(input_data))
    # Each transaction of the split gets at most this much gas; if one
    # precompile call does not fit, the loop can never complete an iteration.
    if precompile_cost > min(tx_gas_limit, gas_benchmark_value):
        pytest.skip(
            f"one {len(input_data)}-byte MSM call costs {precompile_cost} "
            "gas, more than a single transaction can spend"
        )

    benchmark_test(
        target_opcode=target,
        code_generator=JumpLoopGenerator(
            setup=_load_input_from_code(pre, fork, input_data),
            attack_block=Op.POP(
                Op.STATICCALL(
                    gas=Op.GAS,
                    address=precompile_address,
                    args_size=len(input_data),
                ),
            ),
        ),
    )

Parametrized Test Cases

This test generates 8 parametrized test cases across 4 forks.