Skip to content

test_call_value_to_empty()

Documentation for tests/benchmark/stateful/bloatnet/test_call.py::test_call_value_to_empty@49633827.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/benchmark/stateful/bloatnet/test_call.py::test_call_value_to_empty --gas-benchmark-values 1

Benchmark CALL with value transfer to non-existent accounts.

Source code in tests/benchmark/stateful/bloatnet/test_call.py
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
def test_call_value_to_empty(
    benchmark_test: BenchmarkTestFiller,
    pre: Alloc,
    fork: Fork,
    gas_benchmark_value: int,
) -> None:
    """Benchmark CALL with value transfer to non-existent accounts."""
    # Memory layout: MEM[0..31] = counter (incremented each iteration)
    setup = (
        Op.MSTORE(
            0,
            Op.CALLDATALOAD(32),  # salt_offset (starting counter)
            # gas accounting
            old_memory_size=0,
            new_memory_size=32,
        )
        + Op.CALLDATALOAD(0)  # [num_calls]
    )

    # CALL with value=1 to keccak256-derived addresses.
    # gas=0: subcall gets 0 + 2300 stipend. No code at target → succeeds.
    # Value is transferred, new account is created in trie.
    call_value_op = Op.POP(
        Op.CALL(
            gas=0,
            address=Op.SHA3(0, 32, data_size=32),
            value=1,
            args_offset=0,
            args_size=0,
            ret_offset=0,
            ret_size=0,
            # gas accounting
            value_transfer=True,
            account_new=True,
        )
    )

    # Increment counter in memory for next address
    increment_counter = Op.MSTORE(0, Op.ADD(Op.MLOAD(0), 1))

    loop = While(
        body=(call_value_op + increment_counter),
        condition=DECREMENT_COUNTER_CONDITION,
    )

    # Contract Deployment — needs balance for value transfers (1 wei each)
    code = IteratingBytecode(
        setup=setup,
        iterating=loop,
    )

    initial_balance = 10**9
    attack_contract_address = pre.deploy_contract(
        code=code,
        balance=initial_balance,
    )

    def calldata_builder(iteration_count: int, start_iteration: int) -> bytes:
        return bytes(Hash(iteration_count) + Hash(start_iteration))

    txs = list(
        code.transactions_by_gas_limit(
            fork=fork,
            gas_limit=gas_benchmark_value,
            sender=pre.fund_eoa(),
            to=attack_contract_address,
            calldata=calldata_builder,
        )
    )

    total_iterations = sum(int.from_bytes(tx.data[:32], "big") for tx in txs)

    def new_account_address(counter: int) -> Address:
        return Address(bytes(keccak256(counter.to_bytes(32, "big")))[12:])

    post = {
        new_account_address(counter): Account(balance=1)
        for counter in range(total_iterations)
    }
    post[attack_contract_address] = Account(
        balance=initial_balance - total_iterations
    )

    expected_gas_used = (
        sum(tx.gas_cost for tx in txs)
        - fork.gas_costs().CALL_STIPEND * total_iterations
    )

    benchmark_test(
        pre=pre,
        post=post,
        blocks=[Block(txs=txs)],
        expected_benchmark_gas_used=expected_gas_used,
    )

Parametrized Test Cases

This test generates 1 parametrized test case across 3 forks.