Blockhash refactoring
EIP-210, titled "Blockhash Refactoring," proposes storing block hashes in the state, reducing the protocol complexity and the need for client implementation complexity to process the BLOCKHASH opcode. It also extends the range of how far back blockhash checking can go, creating direct links between blocks with very distant block numbers, which facilitates much more efficient initial light client syncing.
The EIP introduces a new contract, the BLOCKHASH_CONTRACT, with its address and code specified. When the block number equals the CONSTANTINOPLE_FORK_BLKNUM, the code of the BLOCKHASH_CONTRACT_ADDR is set to BLOCKHASH_CONTRACT_CODE. When the block number is greater than or equal to the CONSTANTINOPLE_FORK_BLKNUM, a call is executed before processing any transactions, with the parameters: SENDER: SUPER_USER, GAS: 1000000, TO: BLOCKHASH_CONTRACT_ADDR, VALUE: 0, DATA: <32 bytes corresponding to the blockâs prevhash>.
The EIP also provides the Serpent source code and the EVM init code for the BLOCKHASH_CONTRACT_CODE. The rationale behind this EIP is to remove the need for implementations to have an explicit way to look into historical block hashes, simplifying the protocol definition and removing a large component of the "implied state."
Video
Original
Summary
Stores blockhashes in the state, reducing the protocol complexity and the need for client implementation complexity in order to process the BLOCKHASH opcode. Also extends the range of how far back blockhash checking can go, with the side effect of creating direct links between blocks with very distant block numbers, facilitating much more efficient initial light client syncing.
Parameters
CONSTANTINOPLE_FORK_BLKNUM
: TBDSUPER_USER
: 2**160 - 2BLOCKHASH_CONTRACT_ADDR
: 0xf0 (ie. 240)BLOCKHASH_CONTRACT_CODE
: see below
Specification
If block.number == CONSTANTINOPLE_FORK_BLKNUM
, then when processing the block, before processing any transactions set the code of BLOCKHASH_CONTRACT_ADDR to BLOCKHASH_CONTRACT_CODE.
If block.number >= CONSTANTINOPLE_FORK_BLKNUM
, then when processing a block, before processing any transactions execute a call with the parameters:
SENDER
: SUPER_USERGAS
: 1000000TO
: BLOCKHASH_CONTRACT_ADDRVALUE
: 0DATA
: <32 bytes corresponding to the block's prevhash>
If block.number >= CONSTANTINOPLE_FORK_BLKNUM + 256
, then the BLOCKHASH opcode instead returns the result of executing a call (NOT a transaction) with the parameters:
SENDER
: <account from which the opcode was called>GAS
: 1000000TO
: BLOCKHASH_CONTRACT_ADDRVALUE
: 0DATA
: 32 byte zero-byte-leftpadded integer representing the stack argument with which the opcode was called
Also, for blocks where block.number >= CONSTANTINOPLE_FORK_BLKNUM
, the gas cost is increased from 20 to 800 to reflect the higher costs of processing the algorithm in the contract code.
BLOCKHASH_CONTRACT_CODE
The Serpent source code is:
with offset = 0: if msg.sender == 0xfffffffffffffffffffffffffffffffffffffffe: with bn = block.number - 1: while bn: ~sstore(offset + ~mod(bn, 256), ~calldataload(0)) if ~mod(bn, 256): ~stop() bn = ~div(bn, 256) offset += 256 elif ~calldataload(0) >= 0 and ~calldataload(0) < block.number: with tbn = ~calldataload(0): with dist_minus_one = block.number - tbn - 1: while dist_minus_one >= 256 && ~mod(tbn, 256) == 0: offset += 256 tbn = ~div(tbn, 256) dist_minus_one = ~div(dist_minus_one, 256) if dist_minus_one >= 256: return(0) return(~sload(offset + ~mod(tbn, 256))) else: return(0)
The EVM init code is:
0x6100f58061000e60003961010356600073fffffffffffffffffffffffffffffffffffffffe33141561005857600143035b801561005257600035610100820683015561010081061561003f57005b6101008104905061010082019150610022565b506100f3565b600060003512151561006e574360003512610071565b60005b156100e7576000356001814303035b6101008112151561009857600061010083061461009b565b60005b156100ba57610100830192506101008204915061010081049050610080565b610100811215156100d057600060a052602060a0f35b610100820683015460c052602060c0f350506100f2565b600060e052602060e0f35b5b505b6000f3
The EVM bytecode that the contract code should be set to is:
0x600073fffffffffffffffffffffffffffffffffffffffe33141561005857600143035b801561005257600035610100820683015561010081061561003f57005b6101008104905061010082019150610022565b506100f3565b600060003512151561006e574360003512610071565b60005b156100e7576000356001814303035b6101008112151561009857600061010083061461009b565b60005b156100ba57610100830192506101008204915061010081049050610080565b610100811215156100d057600060a052602060a0f35b610100820683015460c052602060c0f350506100f2565b600060e052602060e0f35b5b50
Rationale
This removes the need for implementations to have an explicit way to look into historical block hashes, simplifying the protocol definition and removing a large component of the "implied state" (information that is technically state but is not part of the state tree) and thereby making the protocol more "pure". Additionally, it allows blocks to directly point to blocks far behind them, which enables extremely efficient and secure light client protocols.
Adopted by projects
Not miss a beat of EIPs' update?
Subscribe EIPs Fun to receive the latest updates of EIPs Good for Buidlers to follow up.
View all