@pytest.mark.repricing(fixed_src_dst=True)
@pytest.mark.parametrize(
"mem_size",
[0, 32, 256, 1024, 10 * 1024, 1024 * 1024],
)
@pytest.mark.parametrize(
"fixed_src_dst",
[
True,
False,
],
)
@pytest.mark.parametrize(
"calldata_size",
[0, 32, 256, 1024],
)
def test_calldatacopy_from_origin(
benchmark_test: BenchmarkTestFiller,
fork: Fork,
mem_size: int,
fixed_src_dst: bool,
calldata_size: int,
tx_gas_limit: int,
) -> None:
"""Benchmark CALLDATACOPY instruction."""
# Generate calldata of the specified size with deterministic data.
data = Bytes([i % 256 for i in range(calldata_size)])
intrinsic_gas_calculator = fork.transaction_intrinsic_cost_calculator()
min_gas = intrinsic_gas_calculator(calldata=data)
if min_gas > tx_gas_limit:
pytest.skip(
f"Minimum gas required for calldata ({min_gas}) is greater "
"than the gas limit"
)
# Setup pushes the memory size to copy onto the stack.
# The attack block uses DUP1 to reuse this value for the copy length.
setup = Op.PUSH3(mem_size) if mem_size > 0 else Op.PUSH0
src_dst = 0 if fixed_src_dst else Op.AND(Op.GAS, 7)
attack_block = Op.CALLDATACOPY(
src_dst,
src_dst,
Op.CALLDATASIZE,
)
benchmark_test(
target_opcode=Op.CALLDATACOPY,
code_generator=JumpLoopGenerator(
setup=setup,
attack_block=attack_block,
tx_kwargs={"data": data},
),
)