Open
Conversation
…d building paths Three tests verify the PREVRANDAO opcode behavior in BSC's post-merge EVM: 1. prevrandao_opcode_returns_prevrandao_not_difficulty: confirms opcode 0x44 reads from BlockEnv.prevrandao (not difficulty) in post-merge spec 2. prevrandao_mismatch_between_validation_and_building_paths: reproduces the bug where validation sets prevrandao=difficulty but building (before fix) sets prevrandao=mix_hash, causing different opcode outputs 3. prevrandao_consistency_for_noturn_difficulty: covers the DIFF_NOTURN case Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
will-2012
approved these changes
Mar 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PREVRANDAOopcode returns different values during block building vs block validation, causing state root mismatches for any contract that readsPREVRANDAOprevrandao = mix_hash(B256::ZERO or millisecond timestamp), while validation path setprevrandao = header.difficulty()(Parlia INTURN=2 / NOTURN=1)prev_randaoto the calculated difficulty inprepare_new_attributes, and restore the correctmix_hashinfinalize_new_header(since the assembler derivesmix_hashfromprevrandao)Details
In BSC's Parlia consensus, the
PREVRANDAOEVM opcode returns the block difficulty (not a random value like Ethereum PoS). Two code paths configure the EVM environment:prevrandaovalueBscEvmConfig::evm_env(validation)header.difficulty()BscEvmConfig::next_evm_env(building)attributes.prev_randao=mix_hashThe
mix_hashfield in BSC isB256::ZERO(pre-Lorentz) or encodes the millisecond timestamp part (post-Lorentz) — neither matches the difficulty value. This causes thePREVRANDAOopcode to return different results during building vs validation.Changes in
src/node/miner/util.rsprepare_new_attributes: Changedprev_randaofromnew_header.mix_hashtocalculate_difficulty(&snapshot, signer).into()— matching the validation pathfinalize_new_header: Addedmix_hashrestoration after the assembler sets it fromprevrandao. Recomputes the correct value usingblock_time_for_ramanujan_fork(B256::ZERO pre-Lorentz, millisecond part post-Lorentz)Test plan
cargo checkpasses (confirmed locally)mix_hashin produced block headers matches expected format (zero pre-Lorentz, ms-encoded post-Lorentz)🤖 Generated with Claude Code