@pytest.mark.xdist_group(name="bigmem")
@pytest.mark.parametrize(
"contract_code,expected_storage",
[
# Use PUSH0 to set a key for SSTORE.
pytest.param(
Op.SSTORE(Op.PUSH0, 1),
Account(storage={0x00: 0x01}),
id="key_sstore",
),
# Fill stack with PUSH0, then OR all values and save using SSTORE.
pytest.param(
(Op.PUSH0 * 1024) + (Op.OR * 1023) + Op.SSTORE(Op.SWAP1, 1),
Account(storage={0x00: 0x01}),
id="fill_stack",
),
# Stack overflow by using PUSH0 1025 times.
pytest.param(
Op.SSTORE(Op.PUSH0, 1) + (Op.PUSH0 * 1025),
Account(storage={0x00: 0x00}),
id="stack_overflow",
),
# Update an already existing storage value.
pytest.param(
Op.SSTORE(Op.PUSH0, 2) + Op.SSTORE(1, Op.PUSH0),
Account(storage={0x00: 0x02, 0x01: 0x00}),
id="storage_overwrite",
),
# Jump to a JUMPDEST next to a PUSH0, must succeed.
pytest.param(
Op.PUSH1(4)
+ Op.JUMP
+ Op.PUSH0
+ Op.JUMPDEST
+ Op.SSTORE(Op.PUSH0, 1)
+ Op.STOP,
Account(storage={0x00: 0x01}),
id="before_jumpdest",
),
# Test PUSH0 gas cost.
pytest.param(
CodeGasMeasure(
code=Op.PUSH0,
extra_stack_items=1,
),
Account(storage={0x00: 0x02}),
id="gas_cost",
),
],
)
def test_push0_contracts(
state_test: StateTestFiller,
env: Environment,
pre: Alloc,
post: Alloc,
sender: EOA,
fork: Fork,
contract_code: Bytecode,
expected_storage: Account,
) -> None:
"""Tests PUSH0 within various deployed contracts."""
push0_contract = pre.deploy_contract(contract_code)
intrinsic_calc = fork.transaction_intrinsic_cost_calculator()
tx = Transaction(
to=push0_contract,
# `contract_code.gas_cost(fork)` covers regular + (under EIP-8037)
# state work for the parametrized snippets; add EIP-1706 slack for
# the trailing SSTORE.
gas_limit=(
intrinsic_calc()
+ contract_code.gas_cost(fork)
+ Op.SSTORE(new_value=1).state_cost(fork)
),
sender=sender,
)
post[push0_contract] = expected_storage
state_test(env=env, pre=pre, post=post, tx=tx)