Skip to content

Create a library to serve historical block hashes from state (EIP-2935) #5639

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ggonzalez94 opened this issue Apr 18, 2025 · 0 comments · May be fixed by #5642
Open

Create a library to serve historical block hashes from state (EIP-2935) #5639

ggonzalez94 opened this issue Apr 18, 2025 · 0 comments · May be fixed by #5642
Labels
feature New contracts, functions, or helpers.

Comments

@ggonzalez94
Copy link

🧐 Motivation
Before Pectra you can only query the last 256 block hashes. With EIP-2539 the EL will hold in a system contract the last 8192 block hashes(~27 hs) of blocks, this is very useful for rollups and other applications that need to query or proof something against older ethereum state.

📝 Details
Calling the new contract will be more expensive, so you will probably want to still use the precompile for newer blocks - a simple library that abstracts this away seems pretty useful.
Here's a very simple way to implement this. If we use this in our minimal-rollup I'm happy to contribute upstream

/// @dev Reads a block hash up to 8 191 blocks ago after the Pectra fork.
///      Falls back to the BLOCKHASH opcode for <256 blocks.
library BlockhashHistory {
    address constant _HISTORY_ADDR = 0x0000F90827F1C53a10Cb7A02335B175320002935;
    uint256 constant _WINDOW = 8191;

    /// @notice Returns the hash of block `n` or reverts if too old / future.
    function hashOf(uint256 n) internal view returns (bytes32 h) {
        uint256 current = block.number;
        if (n >= current) revert("future block");
        unchecked {
            if (current - n <= 256) {
                return blockhash(n); // cheap path
            }
            if (current - n > _WINDOW) revert("too old");
        }
        bytes memory input = abi.encodePacked(bytes32(n));
        // solhint-disable-next-line no-inline-assembly
        assembly {
            let success := staticcall(gas(), _HISTORY_ADDR, add(input, 32), 32, 0, 32)
            if iszero(success) { revert(0, 0) }
            h := mload(0)
        }
    }
}
@ggonzalez94 ggonzalez94 added the feature New contracts, functions, or helpers. label Apr 18, 2025
@ernestognw ernestognw linked a pull request Apr 21, 2025 that will close this issue
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New contracts, functions, or helpers.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant