Arbitrum EIP-2935 historical block hashes#606
Merged
svlachakis merged 3 commits intomainfrom Jan 30, 2026
Merged
Conversation
Contributor
wurdum
approved these changes
Jan 29, 2026
AnkushinDaniil
approved these changes
Jan 29, 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.
Fixes Closes #510
EIP-2935 Historical Block Hash Implementation - Why it's already working
Background
There was concern that Nethermind-Arbitrum doesn't implement EIP-2935 (historical block hash storage) for ArbOS 40+, based on:
ArbitrumTransactionProcessor.csParentBlockHashSupportInvestigation: The implementation should be working correctly and it's already producing identical results to Nitro, based on TestHistoricalBlockhashComparison System Test.
Fixed by PRs:
How Nitro Implements EIP-2935
Nitro uses a custom EIP-2935 contract deployed at ArbOS 40. During internal transaction processing (
internal_tx.go), Nitro:ArbSys.ArbBlockNumber()to get the L2 block numberparentBlockHashat storage slotblockNumber % 393168How Nethermind-Arbitrum Implements EIP-2935
Nethermind-Arbitrum achieves the same result through a different mechanism:
1. Inheritance from base BlockProcessor
2. Base class handles EIP-2935 storage
In the upstream Nethermind
BlockProcessor.ProcessBlock()(line 103):This is called before any transactions are processed.
3. ApplyBlockhashStateChanges() directly writes to state
4. Arbitrum's custom ring buffer size is configured
5. Custom EIP-2935 contract code is deployed at ArbOS 40
Why The Empty Block Is Not A Bug
This is empty because:
BlockProcessor.ProcessBlock()has already calledApplyBlockhashStateChanges()Why TestHistoricalBlockHashComparison Passes
The test passes because:
parentBlockHashto the same storage slotBLOCKHASHopcode reads from the same storage location in both clientsWhen
IsBlockHashInStateAvailableis true (EIP-7709, enabled with ArbOS 40+), theArbitrumBlockhashProviderreads from state:Key Insight
The difference between Nitro and Nethermind is HOW they write, not WHAT they write.
For block hash parity (which is what matters for consensus), both approaches produce identical storage state. The
TestHistoricalBlockHashComparisonsystem test validates this by comparing block hashes between Nitro and Nethermind-Arbitrum.Conclusion
BlockProcessorclass.