@pytest.mark.parametrize(
"modexp_input,modexp_expected",
[
pytest.param(
Spec.modexp_input,
Spec.modexp_expected,
id="valid_input",
),
],
)
@pytest.mark.parametrize("opcode", [Op.CREATE, Op.CREATE2])
@EIPChecklist.Precompile.Test.CallContexts.Initcode.CREATE()
@pytest.mark.valid_from("Berlin")
def test_contract_initcode(
state_test: StateTestFiller,
pre: Alloc,
post: dict,
tx: Transaction,
fork: Fork,
modexp_input: bytes,
modexp_expected: bytes,
opcode: Op,
) -> None:
"""Test ModExp behavior from contract creation."""
sender = pre.fund_eoa()
storage = Storage()
call_modexp_bytecode = (
Op.CODECOPY(
0,
Op.SUB(Op.CODESIZE, len(bytes(modexp_input))),
len(bytes(modexp_input)),
)
+ Op.CALL(
gas=200_000,
address=Spec.MODEXP_ADDRESS,
value=0,
args_offset=0,
args_size=len(bytes(modexp_input)),
ret_offset=0,
ret_size=len(bytes(modexp_expected)),
)
+ Op.SSTORE(storage.store_next(True), Op.DUP1())
+ Op.SSTORE(
storage.store_next(keccak256(bytes(modexp_expected))),
Op.SHA3(0, Op.RETURNDATASIZE()),
)
+ Op.SSTORE(
storage.store_next(len(bytes(modexp_expected))),
Op.RETURNDATASIZE(),
)
+ Op.STOP
)
full_initcode = call_modexp_bytecode + bytes(modexp_input)
total_bytecode_length = len(call_modexp_bytecode) + len(
bytes(modexp_input)
)
create_contract = (
Op.CALLDATACOPY(offset=0, size=total_bytecode_length)
+ opcode(offset=0, size=total_bytecode_length)
+ Op.STOP
)
factory_contract_address = pre.deploy_contract(code=create_contract)
contract_address = compute_create_address(
address=factory_contract_address,
nonce=1,
initcode=full_initcode,
opcode=opcode,
)
tx = Transaction(
sender=sender,
to=factory_contract_address,
data=call_modexp_bytecode + bytes(modexp_input),
)
post = {
contract_address: {
"storage": storage,
}
}
state_test(env=Environment(), pre=pre, post=post, tx=tx)