Skip to content

test_deposit_high_count()

Documentation for tests/prague/eip6110_deposits/test_deposits.py::test_deposit_high_count@ffe48572.

Generate fixtures for these test cases for Bogota with:

fill -v tests/prague/eip6110_deposits/test_deposits.py::test_deposit_high_count --fork Bogota

Test a single block carrying more deposits than a consensus layer payload is allowed to contain, since EIP-6110 leaves the execution layer request list unbounded.

The deposits are driven by a relay contract that loops over one deposit call, so they only differ in the index the deposit contract assigns them.

Source code in tests/prague/eip6110_deposits/test_deposits.py
@pytest.mark.parametrize(
    "deposit_count",
    [
        pytest.param(
            Spec.MAX_DEPOSIT_REQUESTS_PER_PAYLOAD + 1,
            id="over_consensus_layer_payload_maximum",
        ),
    ],
)
@pytest.mark.slow()
def test_deposit_high_count(
    blockchain_test: BlockchainTestFiller,
    pre: Alloc,
    fork: Fork,
    deposit_count: int,
) -> None:
    """
    Test a single block carrying more deposits than a consensus layer payload
    is allowed to contain, since EIP-6110 leaves the execution layer request
    list unbounded.

    The deposits are driven by a relay contract that loops over one deposit
    call, so they only differ in the index the deposit contract assigns them.
    """
    deposit = DepositRequest(
        pubkey=0x01,
        withdrawal_credentials=0x02,
        amount=Spec.MIN_DEPOSIT_AMOUNT,
        signature=0x03,
        index=0x0,
    )
    sender = pre.fund_eoa()

    relay_setup_code = Op.CALLDATACOPY(
        0, 32, len(deposit.calldata)
    ) + Op.CALLDATALOAD(0)
    relay_loop_code = While(
        body=Op.POP(
            Op.CALL(
                address=deposit.system_contract_address,
                value=deposit.value,
                args_offset=0,
                args_size=len(deposit.calldata),
                value_transfer=True,
                address_warm=True,
            )
        ),
        condition=Op.PUSH1(1) + Op.SWAP1 + Op.SUB + Op.DUP1,
    )

    deposit_relay_code = relay_setup_code + relay_loop_code
    deposit_relay_iteration_gas = relay_loop_code.gas_cost(fork)

    relay_contract = pre.deploy_contract(
        code=deposit_relay_code,
        balance=deposit.value * deposit_count,
    )

    intrinsic_gas_calculator = fork.transaction_intrinsic_cost_calculator()
    # The deposit contract's Merkle branch loop runs once per trailing zero
    # bit of the new deposit count, so no deposit iterates it more often than
    # the count's bit length. Budgeting that depth for every deposit, rather
    # than the single iteration they average, leaves room for the storage
    # slots each transaction writes for the first time.
    gas_per_deposit = (
        deposit_relay_iteration_gas
        + deposit_contract_execution_gas(
            fork, branch_updates=deposit_count.bit_length()
        )
    )

    deposits_per_transaction = deposit_count
    gas_limit_cap = fork.transaction_gas_limit_cap()
    if gas_limit_cap is not None:
        deposits_per_transaction = (
            gas_limit_cap
            - intrinsic_gas_calculator(
                calldata=Hash(deposit_count) + deposit.calldata
            )
            - relay_setup_code.gas_cost(fork)
        ) // gas_per_deposit

    txs: List[Transaction] = []
    for start in range(0, deposit_count, deposits_per_transaction):
        count = min(deposits_per_transaction, deposit_count - start)
        data = Hash(count) + deposit.calldata
        txs.append(
            Transaction(
                sender=sender,
                to=relay_contract,
                data=data,
                gas_limit=intrinsic_gas_calculator(calldata=data)
                + (count * gas_per_deposit),
            )
        )

    blockchain_test(
        genesis_environment=Environment(
            gas_limit=sum(int(tx.gas_limit) for tx in txs)
        ),
        pre=pre,
        post={relay_contract: Account(balance=0)},
        blocks=[
            Block(
                txs=txs,
                header_verify=Header(
                    requests_hash=Requests(
                        *[
                            deposit.copy(index=index)
                            for index in range(deposit_count)
                        ]
                    ),
                ),
                # Constrain fixture size.
                include_receipts_in_output=False,
            )
        ],
    )

Parametrized Test Cases

This test generates 1 parametrized test case across 4 forks.