Skip to main content

MainnetBlockView

A viewer contract deployed to Ethereum mainnet that provides access to block numbers and hashes. This contract is useful for cross-chain applications that need to verify block data from Ethereum mainnet. To prevent reorg-related issues, it only returns hashes for blocks that are at least 65 blocks old.

This contract is called off-chain via LayerZero's lzRead functionality.

MainnetBlockView.vy

The source code for the MainnetBlockView.vy contract can be found on GitHub. The contract is written using Vyper version 0.4.3.

The contract is deployed on Ethereum at 0xb10CfacE69cc0B7F1AE0Dc8E6aD186914f6e7EEA.

{ }Contract ABI
[{"inputs":[],"name":"get_blockhash","outputs":[{"name":"","type":"uint256"},{"name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"_block_number","type":"uint256"}],"name":"get_blockhash","outputs":[{"name":"","type":"uint256"},{"name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"name":"_block_number","type":"uint256"},{"name":"_avoid_failure","type":"bool"}],"name":"get_blockhash","outputs":[{"name":"","type":"uint256"},{"name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]

get_blockhash

MainnetBlockView.get_blockhash(_block_number: uint256 = block.number - 65, _avoid_failure: bool = False) -> (uint256, bytes32): view

Retrieves the block hash for a given block number. The valid range for historical block hashes is between the last 64 and the last 8192 blocks.

Block Range Constraints:

  • Too recent: Blocks within the last 64 blocks (to mitigate Ethereum Mainnet reorg risk)
  • Too old: Blocks older than 8192 blocks (EVM limit post EIP-2935)
  • Valid range: Between block.number - 8192 and block.number - 64
InputTypeDescription
_block_numberuint256Block number to get the hash for. Defaults to block.number - 65
_avoid_failureboolIf True, returns (0, 0x0) on failure instead of reverting. Useful for cross-chain calls.

Returns: a tuple containing the block number and block hash ((uint256, bytes32)).

<>Source code
from snekmate.utils import block_hash as snekmate_block_hash

@view
@external
def get_blockhash(
_block_number: uint256 = block.number - 65, _avoid_failure: bool = False
) -> (uint256, bytes32):
"""
@notice Get block hash for a given block number.
@dev The valid range for historical block hashes is between the last 64
and the last 8192 blocks.
@param _block_number Block number to get hash for, defaults to block.number - 65.
@param _avoid_failure If True, returns (0, 0x0) on failure instead of reverting.
@return Tuple of (actual block number, block hash).
"""
# Use a local variable for the requested block number.
requested_block_number: uint256 = _block_number

# If the default value was passed as 0 (e.g., from a cross-chain call
# that doesn't know the current block number), set a safe default.
if requested_block_number == 0:
requested_block_number = block.number - 65

# Check for invalid conditions first to exit early.
# The requested block must be at least 64 blocks old for reorg protection
# and not more than 8192 blocks old, which is the EVM's limit post EIP-2935.
is_too_recent: bool = requested_block_number >= block.number - 64
is_too_old: bool = requested_block_number <= block.number - 8192

if is_too_recent or is_too_old:
if _avoid_failure:
# For sensitive callers (like LayerZero), return a zeroed response
# instead of reverting the transaction.
return 0, empty(bytes32)
else:
# Revert with a descriptive custom error.
raise ("Block is too recent or too old")
# If all checks pass, retrieve and return the blockhash.
return requested_block_number, snekmate_block_hash._block_hash(requested_block_number)
Example

Get the default block hash (65 blocks ago):

Get a specific block hash:

>>> MainnetBlockView.get_blockhash(22787600)
(22787600, 0x4bdaa00a7e9b85a9ab25565ef2d2de8817cbba08dd0c6880ecee4ac4674e1378)

Use avoid_failure parameter:

>>> MainnetBlockView.get_blockhash(22787809, True)  # Too recent
(0, 0x0000000000000000000000000000000000000000000000000000000000000000)

Error when block is too recent (without avoid_failure):

>>> MainnetBlockView.get_blockhash(1, False)  # Will revert
Error: Returned error: execution reverted: Block is too recent or too old