Skip to content

test_pointer_call_followed_by_direct_call()

Documentation for tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py::test_pointer_call_followed_by_direct_call@01f496f4.

Generate fixtures for these test cases for Prague with:

fill -v tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py::test_pointer_call_followed_by_direct_call --fork Prague

If we first call by pointer then direct call, will the call/sload be hot The direct call will warm because pointer access marks it warm But the sload is still cold because storage marked hot from pointer's account in a pointer call.

Source code in tests/prague/eip7702_set_code_tx/test_set_code_txs_2.py
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
@pytest.mark.valid_from("Prague")
def test_pointer_call_followed_by_direct_call(
    state_test: StateTestFiller,
    pre: Alloc,
    fork: Fork,
):
    """
    If we first call by pointer then direct call, will the call/sload be hot
    The direct call will warm because pointer access marks it warm
    But the sload is still cold because
    storage marked hot from pointer's account in a pointer call.
    """
    env = Environment()

    sender = pre.fund_eoa()
    pointer_a = pre.fund_eoa()
    gas_costs: GasCosts = fork.gas_costs()
    call_worked = 1
    opcodes_price: int = 37
    pointer_call_gas = (
        gas_costs.G_STORAGE_SET
        + gas_costs.G_WARM_ACCOUNT_ACCESS  # pointer is warm
        + gas_costs.G_COLD_ACCOUNT_ACCESS  # contract is cold
        + gas_costs.G_COLD_SLOAD  # storage access under pointer call is cold
        + opcodes_price
    )
    direct_call_gas = (
        gas_costs.G_STORAGE_SET
        + gas_costs.G_WARM_ACCOUNT_ACCESS  # since previous pointer call, contract is now warm
        + gas_costs.G_COLD_SLOAD  # but storage is cold, because it's contract's direct
        + opcodes_price
    )

    contract = pre.deploy_contract(code=Op.SSTORE(call_worked, Op.ADD(Op.SLOAD(call_worked), 1)))

    storage_test_gas: Storage = Storage()
    contract_test_gas = pre.deploy_contract(
        code=Op.GAS()
        + Op.POP(Op.CALL(gas=100_000, address=pointer_a))
        + Op.SSTORE(
            storage_test_gas.store_next(pointer_call_gas, "pointer_call_price"),
            Op.SUB(Op.SWAP1(), Op.GAS()),
        )
        + Op.GAS()
        + Op.POP(Op.CALL(gas=100_000, address=contract))
        + Op.SSTORE(
            storage_test_gas.store_next(direct_call_gas, "direct_call_price"),
            Op.SUB(Op.SWAP1(), Op.GAS()),
        )
    )

    tx = Transaction(
        to=contract_test_gas,
        gas_limit=3_000_000,
        data=b"",
        value=0,
        sender=sender,
        authorization_list=(
            [
                AuthorizationTuple(
                    address=contract,
                    nonce=0,
                    signer=pointer_a,
                )
            ]
        ),
    )

    post = {
        contract: Account(storage={call_worked: 1}),
        pointer_a: Account(storage={call_worked: 1}),
        contract_test_gas: Account(storage=storage_test_gas),
    }
    state_test(
        env=env,
        pre=pre,
        post=post,
        tx=tx,
    )

Parametrized Test Cases

This test case is only parametrized by fork and fixture format.

Test ID (Abbreviated)
...fork_Prague-state_test
...fork_Prague-blockchain_test_from_state_test
...fork_Osaka-state_test
...fork_Osaka-blockchain_test_from_state_test