Skip to content

test_extcodecopy_bounds()

Documentation for tests/frontier/opcodes/test_extcodecopy.py::test_extcodecopy_bounds@8db70f93.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/frontier/opcodes/test_extcodecopy.py::test_extcodecopy_bounds --fork Amsterdam

Test EXTCODECOPY with out-of-bounds code offset.

Perform three EXTCODECOPY operations on a 15-byte target contract: 1. Huge code offset + large size -> all zeros (beyond code) 2. Huge code offset + small size -> all zeros (beyond code) 3. Offset 5 + size 12 -> partial code copy + zero padding

Each result is read via MLOAD(0) and MLOAD(32) and stored. Only the third operation produces a non-zero result because the dest_offset=1 shifts the copied bytes into the MLOAD(0) word.

Source code in tests/frontier/opcodes/test_extcodecopy.py
16
17
18
19
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
@pytest.mark.ported_from(
    [
        "https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stExtCodeHash/extCodeCopyBoundsFiller.yml",  # noqa: E501
    ],
    pr=["https://github.com/ethereum/execution-specs/pull/2417"],
)
def test_extcodecopy_bounds(
    state_test: StateTestFiller,
    pre: Alloc,
    fork: Fork,
) -> None:
    """
    Test EXTCODECOPY with out-of-bounds code offset.

    Perform three EXTCODECOPY operations on a 15-byte target contract:
    1. Huge code offset + large size  -> all zeros (beyond code)
    2. Huge code offset + small size  -> all zeros (beyond code)
    3. Offset 5 + size 12             -> partial code copy + zero padding

    Each result is read via MLOAD(0) and MLOAD(32) and stored. Only the
    third operation produces a non-zero result because the dest_offset=1
    shifts the copied bytes into the MLOAD(0) word.
    """
    storage = Storage()

    target_code = Op.SSTORE(99, 12) + Op.SSTORE(99, 11) + Op.SSTORE(99, 10)
    target = pre.deploy_contract(target_code)

    huge_offset = 0x010000000000000000000000000000000000000000
    large_size = 5000

    code = (
        # 1. Huge code offset, large size -> all zeros
        Op.EXTCODECOPY(target, 1, huge_offset, large_size)
        + Op.SSTORE(storage.store_next(0), Op.MLOAD(0))
        + Op.SSTORE(storage.store_next(0), Op.MLOAD(32))
        + Op.SSTORE(
            storage.store_next(Bytes(b"\0" * large_size).keccak256()),
            Op.SHA3(1, large_size),
        )
        # 2. Huge code offset, size 12 -> all zeros
        + Op.EXTCODECOPY(target, 1, huge_offset, 12)
        + Op.SSTORE(storage.store_next(0), Op.MLOAD(0))
        + Op.SSTORE(storage.store_next(0), Op.MLOAD(32))
        # 3. Offset 5, size 12 -> partial code copy
        + Op.EXTCODECOPY(target, 1, 5, 12)
        + Op.SSTORE(
            storage.store_next(
                b"\x00" + bytes(target_code)[5:15] + b"\x00" * 21
            ),
            Op.MLOAD(0),
        )
        + Op.SSTORE(storage.store_next(0), Op.MLOAD(32))
    )

    code_address = pre.deploy_contract(code, storage=storage.canary())

    tx = Transaction(
        sender=pre.fund_eoa(),
        to=code_address,
        gas_limit=400_000,
        protected=fork.supports_protected_txs(),
    )

    state_test(
        pre=pre,
        post={code_address: Account(storage=storage)},
        tx=tx,
    )

Parametrized Test Cases

This test generates 1 parametrized test case across 14 forks.