@pytest.mark.ported_from(
[
"https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/VMTests/vmTests/calldatasizeFiller.yml",
],
pr=["https://github.com/ethereum/execution-spec-tests/pull/1236"],
)
@pytest.mark.parametrize(
"args_size",
[0, 2, 16, 33, 257],
)
@pytest.mark.parametrize("calldata_source", ["contract", "tx"])
@pytest.mark.slow()
def test_calldatasize(
state_test: StateTestFiller,
fork: Fork,
args_size: int,
pre: Alloc,
calldata_source: str,
) -> None:
"""
Test `CALLDATASIZE` opcode.
Tests two scenarios:
- calldata_source is "contract": CALLDATASIZE reads from calldata
passed by another contract
- calldata_source is "tx": CALLDATASIZE reads directly from
transaction calldata
Based on
https://github.com/ethereum/tests/blob/
81862e4848585a438d64f911a19b3825f0f4cd95/src/
GeneralStateTestsFiller/VMTests/vmTests/calldatasizeFiller.yml
"""
contract_code = Op.SSTORE(key=0x0, value=Op.CALLDATASIZE)
contract_address = pre.deploy_contract(contract_code)
calldata = b"\x01" * args_size
intrinsic = fork.transaction_intrinsic_cost_calculator()
# EIP-1706 sentry: SSTORE fails if gas_left <= CALL_STIPEND (2300)
# before its base cost is deducted, so the inner frame needs that
# much headroom on top of the SSTORE cost.
sstore_sentry_slack = fork.gas_costs().CALL_STIPEND + 1
# Outer's CALL reserves this many gas units (`Op.SUB(Op.GAS(), N)`)
# before forwarding the rest to the inner frame.
outer_call_reserve = 256
if calldata_source == "contract":
outer_code = Om.MSTORE(calldata, 0x0) + Op.CALL(
gas=Op.SUB(Op.GAS(), outer_call_reserve),
address=contract_address,
value=0x0,
args_offset=0x0,
args_size=args_size,
ret_offset=0x0,
ret_size=0x0,
)
to = pre.deploy_contract(code=outer_code)
tx = Transaction(
gas_limit=(
intrinsic()
+ outer_code.gas_cost(fork)
+ outer_call_reserve
+ contract_code.gas_cost(fork)
+ sstore_sentry_slack
+ Op.SSTORE(new_value=1).state_cost(fork)
),
protected=fork.supports_protected_txs(),
sender=pre.fund_eoa(),
to=to,
)
else:
tx = Transaction(
data=calldata,
gas_limit=(
intrinsic(calldata=calldata)
+ contract_code.gas_cost(fork)
+ sstore_sentry_slack
+ Op.SSTORE(new_value=1).state_cost(fork)
),
protected=fork.supports_protected_txs(),
sender=pre.fund_eoa(),
to=contract_address,
)
post = {contract_address: Account(storage={0x00: args_size})}
state_test(pre=pre, post=post, tx=tx)