Skip to content

test_fee_getter()

Documentation for tests/amsterdam/eip8282_builder_execution_requests/test_request_predeploys.py::test_fee_getter@ffe48572.

Generate fixtures for these test cases for Bogota with:

fill -v tests/amsterdam/eip8282_builder_execution_requests/test_request_predeploys.py::test_fee_getter --fork Bogota

A relay queues requests and then calls the predeploy with empty calldata, which returns the current fee; calling it again with value attached reverts.

Source code in tests/amsterdam/eip8282_builder_execution_requests/test_request_predeploys.py
@pytest.mark.parametrize(
    "beyond_target",
    [
        pytest.param(False, id="nothing_queued"),
        pytest.param(True, id="queued_beyond_target"),
    ],
)
@EIPChecklist.SystemContract.Test.InputLengths.Zero()
def test_fee_getter(
    blockchain_test: BlockchainTestFiller,
    pre: Alloc,
    request_class: Type[FeeSystemContractRequest],
    beyond_target: bool,
) -> None:
    """
    A relay queues requests and then calls the predeploy with empty calldata,
    which returns the current fee; calling it again with value attached
    reverts.
    """
    predeploy = request_class.system_contract_address
    per_block = request_class.max_per_block
    if beyond_target:
        excess = request_class.get_n_fee_increments(1)[0]
        queued = request_class.target_per_block + excess
        sweep_changes = [
            BalStorageSlot(
                slot=request_class.excess_slot,
                slot_changes=[
                    BalStorageChange(block_access_index=2, post_value=excess)
                ],
            ),
            queued_count_changes(request_class, queued, 2),
        ]
        if queued > per_block:
            # The sweep takes a block's worth and moves the head past them.
            sweep_changes.append(
                BalStorageSlot(
                    slot=request_class.queue_head_slot,
                    slot_changes=[
                        BalStorageChange(
                            block_access_index=2, post_value=per_block
                        )
                    ],
                )
            )
            predeploy_bal = BalAccountExpectation(
                storage_changes=sweep_changes
            )
        else:
            predeploy_bal = BalAccountExpectation(
                storage_reads=[request_class.queue_head_slot],
                storage_changes=sweep_changes,
            )
    else:
        excess = 0
        queued = 0
        predeploy_bal = BalAccountExpectation(
            storage_reads=[
                request_class.excess_slot,
                request_class.count_slot,
                request_class.queue_head_slot,
                request_class.queue_tail_slot,
            ],
            storage_changes=[],
        )
    requests = [
        request_class.from_index(i).copy(fee=fee)
        for i, fee in enumerate(request_class.get_enqueue_fees(queued))
    ]
    queued_value = sum(request.value for request in requests)
    # Per-call pricing already counts the requests queued this block;
    # per-block pricing returns the minimum until the system call runs.
    if request_class.excess_fee_processing == "call":
        quoted_fee = request_class.get_fee(excess)
    elif request_class.excess_fee_processing == "block":
        quoted_fee = request_class.get_fee(0)
    else:
        raise ValueError(
            f"unhandled fee processing {request_class.excess_fee_processing}"
        )

    storage = Storage()
    fee_getter = (
        Op.SSTORE(
            storage.store_next(1, "getter_success"),
            Op.CALL(Op.GAS, predeploy, 0, 0, 0, 0, 32),
        )
        + Op.SSTORE(
            storage.store_next(32, "getter_return_size"), Op.RETURNDATASIZE
        )
        + Op.SSTORE(storage.store_next(quoted_fee, "fee"), Op.MLOAD(0))
        + Op.SSTORE(
            storage.store_next(0, "getter_with_value_success"),
            Op.CALL(Op.GAS, predeploy, 1, 0, 0, 0, 0),
        )
    )
    relay = pre.deploy_contract(
        relay_contract_code(
            requests, call_type=Op.CALL, extra_code=fee_getter
        ),
        balance=queued_value + 1,
    )
    tx = Transaction(
        sender=pre.fund_eoa(),
        to=relay,
        data=b"".join(request.calldata for request in requests),
    )

    blockchain_test(
        pre=pre,
        blocks=[
            Block(
                txs=[tx],
                header_verify=Header(
                    requests_hash=Requests(
                        *(
                            r.with_source_address(relay)
                            for r in requests[:per_block]
                        )
                    )
                ),
                expected_block_access_list=BlockAccessListExpectation(
                    account_expectations={
                        relay: BalAccountExpectation(
                            storage_changes=[
                                BalStorageSlot(
                                    slot=slot,
                                    slot_changes=[
                                        BalStorageChange(
                                            block_access_index=1,
                                            post_value=value,
                                        )
                                    ],
                                )
                                for slot, value in storage.root.items()
                                if value != 0
                            ],
                        ),
                        predeploy: predeploy_bal,
                    }
                ),
            )
        ],
        post={
            relay: Account(storage=storage, balance=1),
            predeploy: Account(balance=queued_value),
        },
    )

Parametrized Test Cases

This test generates 8 parametrized test cases across 2 forks.