-
Notifications
You must be signed in to change notification settings - Fork 56
fix(explorer): prevent block skipping in live view #438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this 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
|
@Zygimantass could you please sync the branch with main? |
7d08145 to
1f1b664
Compare
|
@Zygimantass could you please sync the branch with main? done |
Cloudflare Deployments
|
0c5b2fd to
9447a77
Compare
Bundle Size Report
Chunk changes (>1KB)
Compared against main branch (baseline from 1/14/2026, 4:02:04 PM) |
|
@Zygimantass blocks are still skipping here 🤔 https://54118d5b-explorer-moderato.porto.workers.dev/blocks
|
|
hmmm, true |
|
this is all amp, so might be very wrong. we probably need to fetch the range between last fetched block and newest known block |
4533fe4 to
9e90dc5
Compare
|
@bpierre no skips anymore |
|
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.
9e90dc5 to
740ec8c
Compare

Problem
The live block view could skip blocks when multiple blocks arrived faster than they could be fetched.
Root cause
The code used
useBlockhook with a singlelatestBlockNumberstate:useWatchBlockNumberdetects block N → setslatestBlockNumber = NuseBlockstarts fetching block NuseWatchBlockNumberdetects block N+1 → setslatestBlockNumber = N+1useBlocknow fetches N+1 instead (query key changed), block N is never added toliveBlocksSolution
Replaced the reactive
useBlockapproach with a queue-based system:pendingBlocksRefqueueprocessPendingBlocksfunction fetches blocks sequentially from the queueGreptile Summary
Replaces reactive
useBlockhook with a queue-based system to prevent block skipping when multiple blocks arrive faster than they can be fetched. The new implementation maintains apendingBlocksRefqueue and processes blocks sequentially using aprocessPendingBlocksfunction with anisFetchingRefguard to prevent concurrent fetches.Key Changes:
useBlockhook dependency that caused race condition whenlatestBlockNumberstate updated mid-fetchliveBlocksstateMinor Changes:
og-params.tsandog.ts(split long conditionals)address/$address.tsxandtx/$hash.tsxfilesIssue Found:
processPendingBlockswhere blocks added during execution may not be processed until the next block arrives (see inline comment)Confidence Score: 4/5
apps/explorer/src/routes/_layout/blocks.tsxfor the race condition mentioned in the inline commentImportant Files Changed
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