Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- BlockhashStore
- Optimization enabled
- true
- Compiler version
- v0.6.6+commit.6c089d02
- Optimization runs
- 200
- EVM Version
- istanbul
- Verified at
- 2026-02-15T22:17:12.162852Z
browser/BlockhashStore.sol
// File: contracts/dev/BlockhashStore.sol
pragma solidity 0.6.6;
/**
* @title BlockhashStore
* @notice This contract provides a way to access blockhashes older than
* the 256 block limit imposed by the BLOCKHASH opcode.
* You may assume that any blockhash stored by the contract is correct.
* Note that the contract depends on the format of serialized Ethereum
* blocks. If a future hardfork of Ethereum changes that format, the
* logic in this contract may become incorrect and an updated version
* would have to be deployed.
*/
contract BlockhashStore {
mapping(uint => bytes32) internal s_blockhashes;
/**
* @notice stores blockhash of a given block, assuming it is available through BLOCKHASH
* @param n the number of the block whose blockhash should be stored
*/
function store(uint256 n) public {
bytes32 h = blockhash(n);
require(h != 0x0, "blockhash(n) failed");
s_blockhashes[n] = h;
}
/**
* @notice stores blockhash of the earliest block still available through BLOCKHASH.
*/
function storeEarliest() external {
store(block.number - 256);
}
/**
* @notice stores blockhash after verifying blockheader of child/subsequent block
* @param n the number of the block whose blockhash should be stored
* @param header the rlp-encoded blockheader of block n+1. We verify its correctness by checking
* that it hashes to a stored blockhash, and then extract parentHash to get the n-th blockhash.
*/
function storeVerifyHeader(uint256 n, bytes memory header) public {
require(keccak256(header) == s_blockhashes[n + 1], "header has unknown blockhash");
// At this point, we know that header is the correct blockheader for block n+1.
// The header is an rlp-encoded list. The head item of that list is the 32-byte blockhash of the parent block.
// Based on how rlp works, we know that blockheaders always have the following form:
// 0xf9____a0PARENTHASH...
// ^ ^ ^
// | | |
// | | +--- PARENTHASH is 32 bytes. rlpenc(PARENTHASH) is 0xa || PARENTHASH.
// | |
// | +--- 2 bytes containing the sum of the lengths of the encoded list items
// |
// +--- 0xf9 because we have a list and (sum of lengths of encoded list items) fits exactly into two bytes.
//
// As a consequence, the PARENTHASH is always at offset 4 of the rlp-encoded block header.
bytes32 parentHash;
assembly {
parentHash := mload(add(header, 36)) // 36 = 32 byte offset for length prefix of ABI-encoded array
// + 4 byte offset of PARENTHASH (see above)
}
s_blockhashes[n] = parentHash;
}
/**
* @notice gets a blockhash from the store. If no hash is known, this function reverts.
* @param n the number of the block whose blockhash should be returned
*/
function getBlockhash(uint256 n) external view returns (bytes32) {
bytes32 h = s_blockhashes[n];
require(h != 0x0, "blockhash not found in store");
return h;
}
}
Compiler Settings
{"remappings":[],"optimizer":{"runs":200,"enabled":true},"metadata":{"bytecodeHash":"ipfs"},"libraries":{},"evmVersion":"istanbul","compilationTarget":{"browser/BlockhashStore.sol":"BlockhashStore"}}
Contract ABI
[{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getBlockhash","inputs":[{"type":"uint256","name":"n","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"store","inputs":[{"type":"uint256","name":"n","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"storeEarliest","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"storeVerifyHeader","inputs":[{"type":"uint256","name":"n","internalType":"uint256"},{"type":"bytes","name":"header","internalType":"bytes"}]}]
Contract Creation Code
0x608060405234801561001057600080fd5b506102e2806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80636057361d1461005157806383b6d6b714610070578063e9413d3814610078578063fadff0e1146100a7575b600080fd5b61006e6004803603602081101561006757600080fd5b5035610154565b005b61006e6101b0565b6100956004803603602081101561008e57600080fd5b50356101bf565b60408051918252519081900360200190f35b61006e600480360360408110156100bd57600080fd5b813591908101906040810160208201356401000000008111156100df57600080fd5b8201836020820111156100f157600080fd5b8035906020019184600183028401116401000000008311171561011357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610226945050505050565b80408061019e576040805162461bcd60e51b8152602060048201526013602482015272189b1bd8dada185cda0a1b8a4819985a5b1959606a1b604482015290519081900360640190fd5b60009182526020829052604090912055565b6101bd6101004303610154565b565b60008181526020819052604081205480610220576040805162461bcd60e51b815260206004820152601c60248201527f626c6f636b68617368206e6f7420666f756e6420696e2073746f726500000000604482015290519081900360640190fd5b92915050565b60008083600101815260200190815260200160002054818051906020012014610296576040805162461bcd60e51b815260206004820152601c60248201527f6865616465722068617320756e6b6e6f776e20626c6f636b6861736800000000604482015290519081900360640190fd5b602401516000918252602082905260409091205556fea2646970667358221220abdf30c7ff36f3e37f20137b753f00ed2b677cb4992ca7a999b971aaacff062864736f6c63430006060033
Deployed ByteCode
0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80636057361d1461005157806383b6d6b714610070578063e9413d3814610078578063fadff0e1146100a7575b600080fd5b61006e6004803603602081101561006757600080fd5b5035610154565b005b61006e6101b0565b6100956004803603602081101561008e57600080fd5b50356101bf565b60408051918252519081900360200190f35b61006e600480360360408110156100bd57600080fd5b813591908101906040810160208201356401000000008111156100df57600080fd5b8201836020820111156100f157600080fd5b8035906020019184600183028401116401000000008311171561011357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610226945050505050565b80408061019e576040805162461bcd60e51b8152602060048201526013602482015272189b1bd8dada185cda0a1b8a4819985a5b1959606a1b604482015290519081900360640190fd5b60009182526020829052604090912055565b6101bd6101004303610154565b565b60008181526020819052604081205480610220576040805162461bcd60e51b815260206004820152601c60248201527f626c6f636b68617368206e6f7420666f756e6420696e2073746f726500000000604482015290519081900360640190fd5b92915050565b60008083600101815260200190815260200160002054818051906020012014610296576040805162461bcd60e51b815260206004820152601c60248201527f6865616465722068617320756e6b6e6f776e20626c6f636b6861736800000000604482015290519081900360640190fd5b602401516000918252602082905260409091205556fea2646970667358221220abdf30c7ff36f3e37f20137b753f00ed2b677cb4992ca7a999b971aaacff062864736f6c63430006060033