Skip to content

Refactor reorg detection to use ring buffer parent hash verification #214

@LeoPatOZ

Description

@LeoPatOZ

Summary

Replace the current reorg detection approach (checking if last streamed block hash exists on-chain) with a ring buffer approach that verifies incoming blocks against their parent hashes. This is cleaner to reason about and more performant in common scenarios.

Current Approach

Check whether the last streamed block's hash still exists on-chain. If not, walk back until we find a matching hash, then re-stream from that point.

Proposed Approach

Store block hashes and numbers in a ring buffer as they arrive. For each incoming block, verify its parent hash against the buffer. On mismatch, walk back to find the fork point.

Scenario Analysis

Scenario 1: Stream correctly rewinds to fork point

1 → 2 → 3 → REORG → 2

Current Proposed
RPC calls 3 0
End buffer state 1 (var holds 3) 1, 2, 3

Current: Check block 3 hash on-chain (missing), check block 2 (missing), check block 1 (match). Stream 2..=3, fetch block 3 for future checks.

Proposed: Block 2 arrives, parent hash matches stored block 1 hash. Stream block 2, update buffer, continue.

Scenario 2: Stream returns a block past the fork point

1 → 2 → 3 → (2 reorged) → 3

Current Proposed
RPC calls 3 1
End buffer state 1 (var holds 3) 1, 2, 3

Current: Block 3 arrives, check stored block 3 hash on-chain (missing), check block 2 (missing), check block 1 (match). Stream 2..=3, fetch block 3.

Proposed: Block 3 arrives, parent hash doesn't match stored block 2 hash. Fetch block 2, its parent matches block 1. Stream 2 → 3, update buffer.

Scenario 3: Stream skips a range with reorg mid-gap

1 → 2 → 3 → (6 reorged) → 8

Current Proposed
RPC calls 1 5
End buffer state 1, 2, 3 (var holds 8) 1, 2, ..., 8

Current: Check stored block 3 hash on-chain (exists). No reorg detected. Stream 4 → 8.

Proposed: Fetch hashes for blocks 4–7, verify chain consistency i.e. 4 parents matches 3 and 8 parents matches 7. Stream 4 → 8, update buffer. The scanner will process blocks 4 → 8, which already reflect the post-reorg canonical chain

Edge Cases to Consider

  • Reorg deeper than buffer size : Fetch finalised block and send that range instead.

Conclusion

The proposed approach is cleaner and more performant for the common cases (scenarios 1 and 2). Scenario 3 requires more RPC calls but maintains fuller buffer state which may be beneficial for subsequent reorg detection.

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: mediumShould be done soon but not blockingtype: refactorCode improvement without changing functionality

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions