EIP-4399 Replace the DIFFICULTY opcode with PREVRANDAO (Supplant DIFFICULTY opcode with PREVRANDAO)
Final · EVM & execution · EIP status Final · created 2021-10-30
Changes the DIFFICULTY (0x44) instruction, which loses its meaning when proof of work ends, so that it returns the beacon chain randomness (the RANDAO mix), and renames it PREVRANDAO.
Why it is needed
When Ethereum switches to proof of stake (PoS) (EIP-3675), blocks no longer carry a proof of work (PoW) seal and the difficulty field is fixed at 0. The DIFFICULTY (0x44) instruction, which returned the mining difficulty, then loses its meaning and has no correct value left to return. However, many existing smart contracts commonly mix the return value of this instruction with other values and use it as randomness. This EIP makes the instruction with the same number return the randomness accumulated by the beacon chain (the RANDAO output), so existing contracts can keep obtaining randomness after the PoS transition without being modified. In addition, because a return value greater than 2 to the power of 64 indicates a PoS block, a contract can also determine on its own whether the transition has happened.
What changes
Today
- DIFFICULTY (0x44) returns the mining difficulty of the block
- The mixHash field in the header holds the value of the PoW seal
- Contracts mix the difficulty value with other values and use it as randomness
- It is hard for a contract to know whether the PoS transition has happened
After EIP-4399
- PREVRANDAO (0x44), with the same number, returns the beacon chain RANDAO randomness
- mixHash holds the latest RANDAO mix of the previous block and is renamed prevRandao
- Existing contracts receive beacon chain randomness without any code changes
- If the return value is greater than 2**64, the block is a PoS block
Who is affected
- Smart contract developers: Existing contracts that obtained randomness through DIFFICULTY receive beacon chain randomness without any code changes. However, the bias and predictability characteristics of the randomness differ from those under PoW, so the recommended usage, such as a sufficient lookahead, must be followed.
- Client teams: Starting at the transition block, clients must record the RANDAO mix of the previous block in the header's mixHash and implement the 0x44 instruction so that it returns this value.
- Validators (block proposers): By skipping a block proposal or censoring transactions, a proposer can influence the randomness by 1 bit per slot, which makes proposers a potential source of bias for applications that use the randomness.
- Apps that depended on the size of the return value: The return value changes from a small number to a value across the full 256-bit range, which creates the possibility of overflow or underflow. The source document considers the probability that this leads to a vulnerability to be negligible.
In depth
Block structure: record the RANDAO mix in mixHash
Starting at TRANSITION_BLOCK (the PoS transition block defined by EIP-3675), clients MUST record in mixHash, the 13th field of the block header (counting from 0), the latest RANDAO mix held by the post beacon state of the previous block. Because putting the RANDAO output in the header means the header data is already in the EVM context, it can be read directly inside the EVM, and the execution layer can be fully executed from the block alone without taking extra input from the consensus layer. It also contributes to the uniqueness of the block hash even when other header fields are the same as in another block.
EVM: 0x44 returns the mixHash value
Starting at TRANSITION_BLOCK, the DIFFICULTY (0x44) instruction MUST return the value of the mixHash field. The gas cost of the instruction does not change. It is also RECOMMENDED (SHOULD) that the mixHash field be renamed prevRandao and the DIFFICULTY (0x44) opcode be renamed PREVRANDAO. The reason for reusing the existing number instead of creating a new opcode is that existing contracts commonly obtain randomness by mixing the DIFFICULTY return value with other values, so reuse makes the PoS transition backwards compatible.
Why reuse mixHash instead of difficulty
The randomness is not put in the difficulty field in order to avoid a hidden fork choice bug. The logic before EIP-3675 depends heavily on the difficulty value, because the total difficulty calculation underlies the PoW fork choice. Setting difficulty to 0 after the transition reduces the bug surface that comes from total difficulty continuing to grow, and if the randomness had gone into the difficulty field, the remaining total difficulty calculation would have become vulnerable to overflow. By contrast, mixHash was a field that would have been discarded at the transition and filled with a zero byte array, so reusing it saves 32 bytes per block and revives one field that the upgrade would otherwise discard.
Identify PoS blocks with the 2**64 threshold
If the return value is greater than 2**64, you can conclude that the transaction is running in a PoS block. The probability that a RANDAO value falls between 0 and 2**64 and gets mixed up with a PoW difficulty value is extremely low. Mainnet difficulty was then around 2**54, so the margin may look insufficient, but for this threshold to become unsafe the hashrate would have to grow 1000 times, and the document holds that this cannot happen before the consensus upgrade. Tools such as decompilers can also use this method to distinguish the new meaning of the instruction when they have the block data containing the transaction.
Possible bias: the proposer's 1 bit of influence
In the beacon chain RANDAO, a block proposer has 1 bit of influence per slot. If a proposer gives up the proposal reward and transaction fees and does not propose a block, they can prevent the RANDAO mix from being updated for that slot. If the proposers of n consecutive slots collude, this becomes n bits, but the influence is limited in time, so a single later honest RANDAO reveal removes the bias. Also, given the semantics of PREVRANDAO, if a proposer censors a transaction that rolls the dice so that it is included in the next block, they can force it to use a RANDAO mix they already know, and the opportunity cost in this case is negligibly small.
Predictability and recommendations for developers
Past randomness is 100% predictable, and future randomness can also be predicted to a limited extent over a short range. The inputs that affect future randomness are the accumulated randomness (the RANDAO mix of the last slot of epoch N is the main input that determines the per-slot proposers of epoch N+MIN_SEED_LOOKAHEAD+1), the number of active validators, effective balances, and incidental missed proposals (about 1% on mainnet). The source document recommends a sufficient lookahead. Close entries at the end of epoch K and draw using the mix at slot K+N+ε, keeping N at 4 epochs or more and ε small, such as 2 to 4 slots. The time margin for ε is set by MIN_SEED_LOOKAHEAD and is about 6 minutes on mainnet. If you wait 4 epochs or more, the proposer set of epoch N+1 is not known when entries close, and the probability that a missed proposal occurs in that period is effectively 100%, which makes prediction harder.
Backwards Compatibility and Status
This EIP is based on TRANSITION_BLOCK rather than a block or slot number, so it is tightly coupled to the PoS transition of EIP-3675, and if adopted it MUST be applied at the same time as EIP-3675. Two kinds of apps may be affected. Apps that use the return value as the PoW difficulty itself are already affected by the PoS transition, so this EIP breaks nothing additional. Apps that depend on the return value being a small number relative to the full 256-bit range could hit overflow or underflow, but the probability that this leads to a security vulnerability is considered negligible. The status of this EIP is Final, meaning the specification is settled.