Skip to content

test_codecopy_zero_in_create2()

Documentation for tests/constantinople/eip1052_extcodehash/test_extcodehash.py::test_codecopy_zero_in_create2@b314d18e.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/constantinople/eip1052_extcodehash/test_extcodehash.py::test_codecopy_zero_in_create2 --fork Amsterdam

Test CODECOPY inside CREATE2 initcode that deploys empty code.

The initcode does CODECOPY(0,0,32) which copies the first 32 bytes of the initcode itself (not the deployed code). It then checks EXTCODESIZE(ADDRESS) and EXTCODEHASH(ADDRESS) of self during init, which see the account as having empty code. The deployed contract retains the storage set during init.

Source code in tests/constantinople/eip1052_extcodehash/test_extcodehash.py
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
@pytest.mark.ported_from(
    [
        "https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/stExtCodeHash/codeCopyZero_ParisFiller.yml",  # noqa: E501
    ],
)
def test_codecopy_zero_in_create2(
    state_test: StateTestFiller,
    pre: Alloc,
) -> None:
    """
    Test CODECOPY inside CREATE2 initcode that deploys empty code.

    The initcode does CODECOPY(0,0,32) which copies the first 32 bytes
    of the initcode itself (not the deployed code). It then checks
    EXTCODESIZE(ADDRESS) and EXTCODEHASH(ADDRESS) of self during init,
    which see the account as having empty code. The deployed contract
    retains the storage set during init.
    """
    storage = Storage()

    # Build the initcode that queries itself and deploys empty code.
    # During init: CODECOPY copies the initcode, EXTCODESIZE(self)=0,
    # EXTCODEHASH(self)=keccak256("").
    initcode = (
        Op.CODECOPY(0, 0, 32)
        + Op.SSTORE(0x50, Op.MLOAD(0))
        + Op.SSTORE(0x51, Op.EXTCODESIZE(Op.ADDRESS))
        + Op.SSTORE(0x52, Op.EXTCODEHASH(Op.ADDRESS))
        + Op.SSTORE(
            0x53,
            Op.EXTCODESIZE(Op.CALLCODE(50_000, Op.ADDRESS, 0, 0, 0, 0, 0)),
        )
        + Op.EXTCODECOPY(Op.ADDRESS, 0, 0, 32)
        + Op.SSTORE(0x54, Op.MLOAD(0))
        # Return empty code (size 0).
        + Op.RETURN(0, 0)
    )

    # Factory: CREATE2 and return the created address.
    factory_code = (
        Om.MSTORE(initcode, 0)
        + Op.MSTORE(
            0,
            Op.CREATE2(value=0, offset=0, size=len(initcode), salt=0),
        )
        + Op.RETURN(0, 32)
    )

    factory = pre.deploy_contract(factory_code, balance=10**18)

    # Caller: invoke factory and store created address.
    caller_code = Op.CALL(550_000, factory, 0, 0, 0, 0, 32) + Op.SSTORE(
        storage.store_next(0, "created_address"), Op.MLOAD(0)
    )

    caller = pre.deploy_contract(caller_code, storage=storage.canary())

    created = compute_create2_address(
        address=factory, salt=0, initcode=initcode
    )
    storage[0] = created

    # First 32 bytes of initcode — what CODECOPY(0,0,32) returns.
    initcode_word0 = bytes(initcode)[:32]

    tx = Transaction(sender=pre.fund_eoa(), to=caller)

    state_test(
        pre=pre,
        post={
            caller: Account(storage=storage),
            created: Account(
                nonce=1,
                code=b"",
                storage={
                    0x50: initcode_word0,
                    0x51: 0,
                    0x52: keccak256(b""),
                    0x53: 0,
                    0x54: 0,
                },
            ),
        },
        tx=tx,
    )

Parametrized Test Cases

This test generates 1 parametrized test case across 10 forks.