Skip to content

test_genesis_hash_available()

Documentation for tests/frontier/opcodes/test_blockhash.py::test_genesis_hash_available@5f132e7c.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/frontier/opcodes/test_blockhash.py::test_genesis_hash_available --fork Amsterdam

Verify BLOCKHASH returns genesis and block 1 hashes.

Regression test: Blockchain test infrastructure must populate block hashes before execution. Without this, BLOCKHASH returns 0, breaking dynamic address computations like BLOCKHASH(0) | TIMESTAMP.

Tests both genesis (block 0) and first executed block (block 1) hash insertion by calling the contract in block 2.

Bug context: revm blockchaintest runner wasn't inserting block_hashes, causing failures in tests with BLOCKHASH-derived addresses.

Source code in tests/frontier/opcodes/test_blockhash.py
 15
 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
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
@pytest.mark.valid_from("Frontier")
@pytest.mark.parametrize(
    "setup_blocks_num,setup_blocks_empty",
    [
        pytest.param(0, True, id="no_blocks"),
        pytest.param(1, False, id="one_empty_block"),
        pytest.param(1, True, id="one_block_with_tx"),
        pytest.param(256, True, id="256_empty_blocks"),
    ],
)
@pytest.mark.slow()
def test_genesis_hash_available(
    blockchain_test: BlockchainTestFiller,
    pre: Alloc,
    fork: Fork,
    setup_blocks_num: int,
    setup_blocks_empty: bool,
) -> None:
    """
    Verify BLOCKHASH returns genesis and block 1 hashes.

    Regression test: Blockchain test infrastructure must populate block hashes
    before execution. Without this, BLOCKHASH returns 0, breaking dynamic
    address computations like BLOCKHASH(0) | TIMESTAMP.

    Tests both genesis (block 0) and first executed block (block 1) hash
    insertion by calling the contract in block 2.

    Bug context: revm blockchaintest runner wasn't inserting block_hashes,
    causing failures in tests with BLOCKHASH-derived addresses.
    """
    # Store ISZERO(BLOCKHASH(0)) and ISZERO(BLOCKHASH(1))
    # Both should be 0 (false) if hashes exist
    code = Op.SSTORE(0, Op.ISZERO(Op.BLOCKHASH(0))) + Op.SSTORE(
        1, Op.ISZERO(Op.BLOCKHASH(1))
    )

    contract = pre.deploy_contract(code=code)
    sender = pre.fund_eoa()

    intrinsic = fork.transaction_intrinsic_cost_calculator()
    tx_gas_limit = (
        intrinsic()
        + code.gas_cost(fork)
        + Op.SSTORE(new_value=1).state_cost(fork)
    )
    blocks = (
        [
            Block(
                txs=[
                    Transaction(
                        sender=sender,
                        to=contract,
                        gas_limit=tx_gas_limit,
                        protected=fork.supports_protected_txs(),
                    )
                ]
                if not setup_blocks_empty
                else []
            )
            for _ in range(setup_blocks_num)
        ]
    ) + (
        [
            Block(
                txs=[
                    Transaction(
                        sender=sender,
                        to=contract,
                        gas_limit=tx_gas_limit,
                        protected=fork.supports_protected_txs(),
                    )
                ]
            )
        ]
    )

    post = {
        contract: Account(
            storage={
                # ISZERO(BLOCKHASH(0)) = 0 (genesis hash exists)
                0: 1 if setup_blocks_num >= 256 else 0,
                # ISZERO(BLOCKHASH(1)) = 0 (if block 1 hash exists)
                1: 1 if setup_blocks_num == 0 else 0,
            }
        )
    }

    blockchain_test(pre=pre, post=post, blocks=blocks)

Parametrized Test Cases

This test generates 4 parametrized test cases across 14 forks.