Skip to content

Conversation

@Zygimantass
Copy link
Member

@Zygimantass Zygimantass commented Jan 14, 2026

Problem

The live block view could skip blocks when multiple blocks arrived faster than they could be fetched.

Root cause

The code used useBlock hook with a single latestBlockNumber state:

  1. useWatchBlockNumber detects block N → sets latestBlockNumber = N
  2. useBlock starts fetching block N
  3. Before fetch completes, useWatchBlockNumber detects block N+1 → sets latestBlockNumber = N+1
  4. useBlock now fetches N+1 instead (query key changed), block N is never added to liveBlocks

Solution

Replaced the reactive useBlock approach with a queue-based system:

  • When a new block number is detected, it's added to a pendingBlocksRef queue
  • A processPendingBlocks function fetches blocks sequentially from the queue
  • Each block is fetched in order, ensuring no blocks are skipped regardless of timing

Greptile Summary

Replaces reactive useBlock hook with a queue-based system to prevent block skipping when multiple blocks arrive faster than they can be fetched. The new implementation maintains a pendingBlocksRef queue and processes blocks sequentially using a processPendingBlocks function with an isFetchingRef guard to prevent concurrent fetches.

Key Changes:

  • Removed useBlock hook dependency that caused race condition when latestBlockNumber state updated mid-fetch
  • Added queue-based processing with sequential block fetching
  • Proper deduplication check prevents duplicate blocks in liveBlocks state
  • Maintains correct block ordering by processing queue in FIFO order

Minor Changes:

  • Formatting improvements in og-params.ts and og.ts (split long conditionals)
  • Import reordering in address/$address.tsx and tx/$hash.tsx files

Issue Found:

  • Potential race condition in processPendingBlocks where blocks added during execution may not be processed until the next block arrives (see inline comment)

Confidence Score: 4/5

  • This PR is safe to merge with minimal risk - it fixes a real issue and the implementation is solid
  • Score reflects that the core fix is correct and well-implemented, solving the original block-skipping race condition. The queue-based approach is the right solution. However, there's a minor race condition where blocks added during processing might not be picked up immediately (requires another block to arrive as trigger). This is unlikely to cause user-facing issues in practice since blocks arrive frequently, but could cause slight delays.
  • Check apps/explorer/src/routes/_layout/blocks.tsx for the race condition mentioned in the inline comment

Important Files Changed

Filename Overview
apps/explorer/src/routes/_layout/blocks.tsx Replaced reactive hook with queue-based block fetching to prevent block skipping. Implementation looks solid with proper deduplication and sequential processing.

Sequence Diagram

sequenceDiagram
    participant Chain as Blockchain
    participant Watch as useWatchBlockNumber
    participant Queue as pendingBlocksRef
    participant Processor as processPendingBlocks
    participant API as getBlock API
    participant State as liveBlocks State

    Chain->>Watch: New Block N detected
    Watch->>Queue: push(Block N)
    Watch->>Processor: processPendingBlocks()
    Processor->>Processor: Check isFetchingRef (false)
    Processor->>Processor: Set isFetchingRef = true
    Processor->>Queue: shift() → Block N
    Processor->>API: getBlock(N)
    
    Note over Chain,State: Block N+1 arrives during fetch
    
    Chain->>Watch: New Block N+1 detected
    Watch->>Queue: push(Block N+1)
    Watch->>Processor: processPendingBlocks()
    Processor->>Processor: Check isFetchingRef (true)
    Processor-->>Watch: Return early
    
    API-->>Processor: Block N data
    Processor->>State: setLiveBlocks([Block N, ...prev])
    Processor->>Queue: Check length (has Block N+1)
    Processor->>Queue: shift() → Block N+1
    Processor->>API: getBlock(N+1)
    API-->>Processor: Block N+1 data
    Processor->>State: setLiveBlocks([Block N+1, Block N, ...prev])
    Processor->>Processor: Set isFetchingRef = false
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@bpierre
Copy link
Member

bpierre commented Jan 14, 2026

@Zygimantass could you please sync the branch with main?

@Zygimantass Zygimantass force-pushed the fix/live-blocks-skip-race-condition branch from 7d08145 to 1f1b664 Compare January 14, 2026 16:48
@Zygimantass
Copy link
Member Author

@Zygimantass could you please sync the branch with main?

done

@github-actions
Copy link

github-actions bot commented Jan 14, 2026

Cloudflare Deployments

App Environment Status Preview
explorer devnet [OK] Deployed View Preview
explorer moderato [OK] Deployed View Preview
explorer presto [OK] Deployed View Preview
explorer testnet [OK] Deployed View Preview
fee-payer devnet [>>] Skipped No changes
fee-payer privy [>>] Skipped No changes
fee-payer testnet [>>] Skipped No changes
og - [>>] Skipped No changes
tokenlist - [>>] Skipped No changes

@Zygimantass Zygimantass force-pushed the fix/live-blocks-skip-race-condition branch 2 times, most recently from 0c5b2fd to 9447a77 Compare January 14, 2026 17:01
@github-actions
Copy link

github-actions bot commented Jan 14, 2026

Bundle Size Report

Metric Size Δ Change
Total 4.5 MB +1.1 KB (+0.0%)
Gzip 1.2 MB +441.0 B (+0.0%)
Brotli 1.1 MB +435.0 B (+0.0%)
Chunk changes (>1KB)
Chunk Change
assets/useBlock.js (removed) -3.3 KB
assets/blocks.js +1.2 KB
assets/_address.js +3.2 KB

Compared against main branch (baseline from 1/14/2026, 4:02:04 PM)

@bpierre
Copy link
Member

bpierre commented Jan 14, 2026

@Zygimantass blocks are still skipping here 🤔 https://54118d5b-explorer-moderato.porto.workers.dev/blocks

image

@Zygimantass
Copy link
Member Author

hmmm, true

@Zygimantass
Copy link
Member Author

Zygimantass commented Jan 14, 2026

this is all amp, so might be very wrong. we probably need to fetch the range between last fetched block and newest known block

@Zygimantass Zygimantass force-pushed the fix/live-blocks-skip-race-condition branch 3 times, most recently from 4533fe4 to 9e90dc5 Compare January 14, 2026 18:06
@Zygimantass
Copy link
Member Author

@bpierre no skips anymore

@Zygimantass
Copy link
Member Author

but much laggier:/

The live block view could skip blocks when multiple blocks arrived faster
than they could be fetched. The issue was that useBlock hook only fetches
the latest blockNumber value - if blocks N and N+1 arrive while N is still
being fetched, the hook switches to fetching N+1 and block N is never added.

Fixed by maintaining a queue of pending block numbers and processing them
sequentially. Each block that arrives is added to the queue and fetched
in order, ensuring no blocks are skipped.
@Zygimantass Zygimantass force-pushed the fix/live-blocks-skip-race-condition branch from 9e90dc5 to 740ec8c Compare January 14, 2026 19:01
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.

3 participants