Skip to content

fix(database): BlockHashCache incorrectly returns zero for block 0#3319

Merged
rakita merged 3 commits intobluealloy:mainfrom
bshastry:fix/block-hash-cache-block-zero
Jan 16, 2026
Merged

fix(database): BlockHashCache incorrectly returns zero for block 0#3319
rakita merged 3 commits intobluealloy:mainfrom
bshastry:fix/block-hash-cache-block-zero

Conversation

@bshastry
Copy link
Contributor

Fixes regression caused by #3299

The ring buffer cache introduced in #3299 was initialized with (0, B256::ZERO) for all entries. This caused get(0) to incorrectly match the default entry and return B256::ZERO instead of None, preventing the database fallback from being invoked.

Fix: Use Option<B256> instead of B256 to explicitly distinguish between "not cached" (None) and "cached with value" (Some(hash)).

🤖 Generated with Claude Code

The ring buffer cache introduced in bluealloy#3299 was initialized with
`(0, B256::ZERO)` for all entries. This caused `get(0)` to incorrectly
match the default entry and return `B256::ZERO` instead of `None`,
preventing the database fallback from being invoked.

This is a consensus bug for any chain at low block numbers (< 256)
where BLOCKHASH(0) should return the genesis block hash.

Fix: Use `Option<B256>` instead of `B256` to explicitly distinguish
between "not cached" (`None`) and "cached with value" (`Some(hash)`).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@codspeed-hq
Copy link

codspeed-hq bot commented Jan 16, 2026

Merging this PR will not alter performance

✅ 173 untouched benchmarks


Comparing bshastry:fix/block-hash-cache-block-zero (98d1770) with main (8d8eb83)

Open in CodSpeed

@bshastry bshastry force-pushed the fix/block-hash-cache-block-zero branch from de59c02 to 1463bd8 Compare January 16, 2026 07:11
/// The reason we store block number alongside its hash is to handle the case where it wraps around,
/// so we can verify the block number. Uses `Option<B256>` to distinguish between "not cached"
/// and "cached with value" - this is important because block 0 is a valid block number.
hashes: Box<[(u64, Option<B256>); BLOCK_HASH_HISTORY_USIZE]>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A slightly better approach would be to have Option as block number is used to deduce if block hash is up to date

/// Inserts a block hash for the given block number.
#[inline]
pub const fn insert(&mut self, block_number: u64, block_hash: B256) {
pub fn insert(&mut self, block_number: u64, block_hash: B256) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to remove consts, right?

Address review feedback:
- Use Option<u64> for block number instead of Option<B256> for hash
- Keep const on insert and get functions
Some(stored_hash)
} else {
None
if let Some(stored) = stored_block_number {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be simplified with if Some(block_number) == stored_block_number {

Use direct Option comparison as suggested in review.
@rakita rakita merged commit ecd3fc5 into bluealloy:main Jan 16, 2026
30 checks passed
@github-actions github-actions bot mentioned this pull request Jan 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants