Skip to content

test_account_warming()

Documentation for tests/prague/eip7702_set_code_tx/test_gas.py::test_account_warming@ffe48572.

Generate fixtures for these test cases for Bogota with:

fill -v tests/prague/eip7702_set_code_tx/test_gas.py::test_account_warming --fork Bogota

Test warming of the authority and authorized accounts for set-code transactions.

Source code in tests/prague/eip7702_set_code_tx/test_gas.py
@pytest.mark.parametrize("check_delegated_account_first", [True, False])
@pytest.mark.parametrize(
    **gas_test_parameter_args(include_many=False, include_data=False)
)
@pytest.mark.eels_base_coverage
def test_account_warming(
    state_test: StateTestFiller,
    pre: Alloc,
    fork: Fork,
    authorization_list_with_properties: List[AuthorizationWithProperties],
    authorization_list: List[AuthorizationTuple],
    access_list: List[AccessList],
    data: bytes,
    sender: EOA,
    check_delegated_account_first: bool,
) -> None:
    """
    Test warming of the authority and authorized accounts for set-code
    transactions.
    """
    # Overhead cost is the single push operation required for the address to
    # check.
    overhead_cost = 3 * len(Op.CALL.kwargs)

    gas_costs = fork.gas_costs()
    cold_account_cost = gas_costs.COLD_ACCOUNT_ACCESS
    warm_account_cost = gas_costs.WARM_ACCESS

    access_list_addresses = {
        access_list.address for access_list in access_list
    }

    # Dictionary to keep track of the addresses to check for warming, and the
    # expected cost of accessing such account.
    addresses_to_check: Dict[Address, int] = {}

    for authorization_with_properties in authorization_list_with_properties:
        authority = authorization_with_properties.tuple.signer
        assert authority is not None, "authority address is not set"
        delegated_account = authorization_with_properties.tuple.address

        authority_contains_delegation_after_authorization = (
            authorization_with_properties.invalidity_type is None
            # If the authority already contained a delegation prior to the
            # transaction, even if the authorization is invalid, there will be
            # a delegation when we check the address.
            or authorization_with_properties.authority_type
            == AddressType.EOA_WITH_SET_CODE
        )

        if check_delegated_account_first:
            if delegated_account not in addresses_to_check:
                addresses_to_check[delegated_account] = (
                    warm_account_cost
                    if delegated_account in access_list_addresses
                    else cold_account_cost
                )

            if authority not in addresses_to_check:
                if not authorization_with_properties.skip:
                    if (
                        authorization_with_properties.invalidity_type is None
                        or (
                            authorization_with_properties.invalidity_type
                            != AuthorizationInvalidityType.INVALID_CHAIN_ID
                        )
                        or authority in access_list_addresses
                    ):
                        access_cost = warm_account_cost
                    else:
                        access_cost = cold_account_cost
                else:
                    access_cost = (
                        cold_account_cost
                        if Address(sender)
                        != authorization_with_properties.tuple.signer
                        else warm_account_cost
                    )

                if authority_contains_delegation_after_authorization:
                    # The double charge for accessing the delegated account,
                    # only if the account ends up with a delegation in its
                    # code.
                    access_cost += warm_account_cost

                addresses_to_check[authority] = access_cost

        else:
            if authority not in addresses_to_check:
                access_cost = (
                    cold_account_cost
                    if Address(sender)
                    != authorization_with_properties.tuple.signer
                    else warm_account_cost
                )
                if not authorization_with_properties.skip and (
                    authorization_with_properties.invalidity_type is None
                    or (
                        authorization_with_properties.invalidity_type
                        != AuthorizationInvalidityType.INVALID_CHAIN_ID
                    )
                    or authority in access_list_addresses
                ):
                    access_cost = warm_account_cost

                if (
                    # We can only charge the delegated account access cost if
                    # the authorization went through
                    authority_contains_delegation_after_authorization
                ):
                    if (
                        delegated_account in addresses_to_check
                        or delegated_account in access_list_addresses
                    ):
                        access_cost += warm_account_cost
                    else:
                        access_cost += cold_account_cost

                addresses_to_check[authority] = access_cost

            if delegated_account not in addresses_to_check:
                if (
                    authority_contains_delegation_after_authorization
                    or delegated_account in access_list_addresses
                ):
                    access_cost = warm_account_cost
                else:
                    access_cost = cold_account_cost
                addresses_to_check[delegated_account] = access_cost

    callee_code: Bytecode = sum(  # type: ignore
        (
            CodeGasMeasure(
                code=Op.CALL(gas=0, address=check_address),
                overhead_cost=overhead_cost,
                extra_stack_items=1,
                sstore_key=check_address,
            )
            for check_address in addresses_to_check
        )
    )
    callee_code += Op.STOP
    callee_address = pre.deploy_contract(
        callee_code,
        storage=dict.fromkeys(addresses_to_check, 0xDEADBEEF),
    )

    tx = Transaction(
        to=callee_address,
        authorization_list=authorization_list if authorization_list else None,
        access_list=access_list,
        sender=sender,
        data=data,
    )
    post = {
        callee_address: Account(
            storage=addresses_to_check,
        ),
    }

    state_test(
        pre=pre,
        tx=tx,
        post=post,
    )

Parametrized Test Cases

This test generates 60 parametrized test cases across 4 forks.