Skip to content

Don't query reorgable blocks before all chains reach reorg threshold - #680

Merged
DZakh merged 5 commits into
mainfrom
dz/reorg-thresholod
Aug 12, 2025
Merged

Don't query reorgable blocks before all chains reach reorg threshold#680
DZakh merged 5 commits into
mainfrom
dz/reorg-thresholod

Conversation

@DZakh

@DZakh DZakh commented Aug 11, 2025

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Prometheus gauge reporting whether indexing is within the reorg threshold.
    • Automatic entry into reorg threshold when chains meet readiness checks.
  • Refactor

    • Simplified per-chain fetch state and batch construction; unified reorg-threshold flow.
    • Block-lag became a concrete, configurable numeric parameter with a safe default.
  • Tests

    • Updated tests to cover reorg-threshold behavior and block-lag defaulting.

@coderabbitai

coderabbitai Bot commented Aug 11, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

BlockLag is now a non-optional int threaded through FetchState.make/updateInternal; queue-based helper removed and replaced by FetchState.isReadyToEnterReorgThreshold; Prometheus gets a reorg-threshold gauge; ChainFetcher/ChainManager and GlobalState APIs and batch flows updated to use FetchState.t and config-driven blockLag; tests adapted.

Changes

Cohort / File(s) Summary
Fetch state core
codegenerator/cli/npm/envio/src/FetchState.res
blockLag changed from option<int> to int; make defaults ~blockLag=0; updateInternal accepts ~blockLag; getNextQuery uses integer head calculations; removed queueItemIsInReorgThreshold; added isReadyToEnterReorgThreshold.
Metrics
codegenerator/cli/npm/envio/src/Prometheus.res
Added ReorgThreshold gauge (envio_reorg_threshold) and ReorgThreshold.set(~isInReorgThreshold) to set 1/0.
Chain fetcher
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
make now takes ~config and ~isInReorgThreshold (replaces ~enableRawEvents); computes blockLag via combined policy and passes it to FetchState.make; references to enableRawEvents use config.enableRawEvents.
Chain manager
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
Removed wrapper types (isInReorgThresholdRes, fetchStateWithData); APIs now use ChainMap.t<FetchState.t>; simplified createBatch/createOrderedBatch/createUnorderedBatch signatures and logic (no onlyBelowReorgThreshold/isInReorgThreshold gating).
Global state
codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
Added EnterReorgThreshold action replacing SetIsInReorgThreshold; initialize Prometheus.ReorgThreshold.set(...); UpdateQueues now carries ChainMap.t<FetchState.t>; reducer uses FetchState.isReadyToEnterReorgThreshold and dispatches EnterReorgThreshold to apply blockLag.
Tests
scenarios/test_codegen/test/ChainManager_test.res, scenarios/test_codegen/test/lib_tests/FetchState_test.res, scenarios/test_codegen/test/lib_tests/SourceManager_test.res, scenarios/erc20_multichain_factory/test/DynamicContractRecovery_test.res
Tests adapted to use FetchState.t directly (no wrapper), updated createBatch call/result shapes, expect blockLag = 0 instead of None, call isReadyToEnterReorgThreshold(~currentBlockHeight), and adjust ChainFetcher.makeFromDbState/Config call sites.

Sequence Diagram(s)

sequenceDiagram
  participant GS as GlobalState
  participant CM as ChainManager
  participant FS as FetchState
  participant PM as Prometheus.ReorgThreshold

  GS->>CM: getFetchStateWithData() → ChainMap<FetchState.t>
  loop per chain
    GS->>FS: isReadyToEnterReorgThreshold(~currentBlockHeight)
    FS-->>GS: bool
  end
  alt any chain ready
    GS->>GS: dispatch EnterReorgThreshold
    GS->>PM: set(~isInReorgThreshold=true)
    loop per chain
      GS->>FS: updateInternal(~blockLag=..., ...)
      FS-->>GS: updated FetchState.t
    end
  end
  GS->>CM: createBatch(~maxBatchSize)
  CM-->>GS: {items, fetchStates, ...}
Loading
sequenceDiagram
  participant CF as ChainFetcher.make
  participant Cfg as Config
  participant FC as FetchState.make

  CF->>Cfg: read shouldRollbackOnReorg & enableRawEvents
  CF->>CF: compute isInReorgThreshold (param)
  CF->>CF: blockLag = max((shouldRollbackOnReorg || isInReorgThreshold) ? 0 : chain.confirmedBlockThreshold, Env.indexingBlockLag|0)
  CF->>FC: make(..., ~blockLag)
  FC-->>CF: FetchState.t
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • moose-code
  • JonoPrest

Poem

I nibble through the change and hop,
Replace None with zero, tidy the crop.
A little gauge now blinks its light,
Fetchers ready for the reorg night.
Hooray — neat hops, and tests run right. 🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f6188e and 733d95b.

📒 Files selected for processing (3)
  • codegenerator/cli/npm/envio/src/FetchState.res (7 hunks)
  • scenarios/erc20_multichain_factory/test/DynamicContractRecovery_test.res (1 hunks)
  • scenarios/test_codegen/test/lib_tests/FetchState_test.res (11 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • codegenerator/cli/npm/envio/src/FetchState.res
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{res,resi}

📄 CodeRabbit Inference Engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • scenarios/erc20_multichain_factory/test/DynamicContractRecovery_test.res
  • scenarios/test_codegen/test/lib_tests/FetchState_test.res
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (7)
scenarios/erc20_multichain_factory/test/DynamicContractRecovery_test.res (1)

146-147: Verified consistent ChainFetcher.makeFromDbState usage

All occurrences of ChainFetcher.makeFromDbState in the repo include both ~config and ~isInReorgThreshold. No missing arguments were found:

  • scenarios/erc20_multichain_factory/test/DynamicContractRecovery_test.res (lines 143–151)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res (lines 91–99)

No further changes required.

scenarios/test_codegen/test/lib_tests/FetchState_test.res (6)

157-157: LGTM: blockLag is now consistently defined as a non-optional int

The change from an optional blockLag to a concrete int value of 0 aligns with the API signature change mentioned in the AI summary. This simplifies the interface and eliminates the need to handle optional values.


226-226: LGTM: Consistent blockLag initialization

All test expectations consistently set blockLag: 0 as the default value, which aligns with the API change to make blockLag a non-optional int.

Also applies to: 289-289, 384-384, 866-866, 905-905, 965-965, 1872-1872, 2186-2186


1126-1130: LGTM: Block lag validation logic is correctly tested

The test correctly verifies that with blockLag=2, queries wait for new blocks when currentBlockHeight - blockLag < 0. Line 1129 includes a helpful message explaining the expected behavior.


2669-2834: Comprehensive test coverage for isReadyToEnterReorgThreshold function

The test suite provides excellent coverage of the new isReadyToEnterReorgThreshold function with various scenarios:

  1. Initial state validation (lines 2670-2684): Tests that the function returns false when starting at block 0
  2. EndBlock reached scenarios (lines 2686-2705): Tests that the function returns true when endBlock is reached and queue is empty
  3. Block lag threshold logic (lines 2707-2789): Tests various combinations of endBlock, blockLag, and current block height to ensure proper threshold calculations
  4. Queue dependency (lines 2791-2814): Tests that non-empty queues override readiness even if thresholds are met
  5. Edge cases (lines 2816-2834): Tests behavior when threshold exceeds current block height

The test scenarios align well with the reorg threshold logic described in the PR objectives and demonstrate proper understanding of when blocks should be considered safe from reorgs.


2672-2672: API rename correctly implemented in all test calls

All test calls correctly use the new isReadyToEnterReorgThreshold(~currentBlockHeight) API instead of the old queueItemIsInReorgThreshold(~currentBlockHeight, ~highestBlockBelowThreshold). The simplified signature eliminates the need for the second parameter, making the API cleaner.

Also applies to: 2680-2680, 2704-2704, 2725-2725, 2746-2746, 2767-2767, 2788-2788, 2811-2811, 2833-2833


2809-2809: Confirmed updateInternal supports ~queue

The FetchState.updateInternal function is defined in codegenerator/cli/npm/envio/src/FetchState.res (lines 224–233) with a labeled ~queue parameter:

let updateInternal = (
  fetchState: t,
  ~partitions=…,
  ~nextPartitionIndex=…,
  ~indexingContracts=…,
  ~dcsToStore=…,
  ~currentBlockHeight=?,
  ~queue=fetchState.queue,
  ~blockLag=…,
): t => { … }

This matches its use in scenarios/test_codegen/test/lib_tests/FetchState_test.res:2809. No changes required.

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dz/reorg-thresholod

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@DZakh
DZakh requested a review from JonoPrest August 11, 2025 15:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
scenarios/test_codegen/test/lib_tests/SourceManager_test.res (1)

297-300: Tests aligned to concrete blockLag

Switching to blockLag: 0 in mockFetchState is correct given the new int field.

Consider adding one test where blockLag > currentBlockHeight to assert we don’t schedule queries and we wait for new blocks (especially if you adopt the headBlock clamp).

codegenerator/cli/npm/envio/src/Prometheus.res (1)

475-485: Global reorg-threshold gauge added; consider per-chain visibility (optional)

The global envio_reorg_threshold gauge is fine if it represents “all chains have entered reorg threshold”. If you need per-chain introspection for debugging, add a labeled gauge variant keyed by chainId.

I can wire a ReorgThresholdPerChain gauge via SafeGauge with chainId labels, and set it alongside the global flag.

scenarios/test_codegen/test/lib_tests/FetchState_test.res (1)

2663-2794: Solid coverage for isReadyToEnterReorgThreshold

Good boundary tests: endBlock reached, head - blockLag boundary, no endBlock, and queue non-empty. If you clamp threshold to non-negative, add a case with currentBlockHeight < blockLag to ensure readiness stays false until at least block 0 is fully fetched.

I can add that extra test if you adopt the clamp.

codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (1)

137-142: Consider refactoring the blockLag calculation for better readability.

The nested ternary operator makes the logic harder to follow. Consider extracting this into a more readable format:

-    ~blockLag=Pervasives.max(
-      !(config->Config.shouldRollbackOnReorg) || isInReorgThreshold
-        ? 0
-        : chainConfig.confirmedBlockThreshold,
-      Env.indexingBlockLag->Option.getWithDefault(0),
-    ),
+    ~blockLag={
+      let reorgBlockLag = if !(config->Config.shouldRollbackOnReorg) || isInReorgThreshold {
+        0
+      } else {
+        chainConfig.confirmedBlockThreshold
+      }
+      Pervasives.max(reorgBlockLag, Env.indexingBlockLag->Option.getWithDefault(0))
+    },
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b127cb and 5a030fc.

📒 Files selected for processing (8)
  • codegenerator/cli/npm/envio/src/FetchState.res (7 hunks)
  • codegenerator/cli/npm/envio/src/Prometheus.res (1 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (8 hunks)
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res (10 hunks)
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res (5 hunks)
  • scenarios/test_codegen/test/ChainManager_test.res (3 hunks)
  • scenarios/test_codegen/test/lib_tests/FetchState_test.res (10 hunks)
  • scenarios/test_codegen/test/lib_tests/SourceManager_test.res (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{res,resi}

📄 CodeRabbit Inference Engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • codegenerator/cli/npm/envio/src/Prometheus.res
  • scenarios/test_codegen/test/lib_tests/SourceManager_test.res
  • scenarios/test_codegen/test/lib_tests/FetchState_test.res
  • codegenerator/cli/npm/envio/src/FetchState.res
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
  • scenarios/test_codegen/test/ChainManager_test.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
codegenerator/cli/npm/envio/**

📄 CodeRabbit Inference Engine (.cursor/rules/navigation.mdc)

Library-fied runtime shared across indexers lives in codegenerator/cli/npm/envio.

Files:

  • codegenerator/cli/npm/envio/src/Prometheus.res
  • codegenerator/cli/npm/envio/src/FetchState.res
codegenerator/cli/templates/{dynamic/**/*.hbs,static/**}

📄 CodeRabbit Inference Engine (.cursor/rules/navigation.mdc)

Templates live under codegenerator/cli/templates: dynamic/ for Handlebars (.hbs), static/ for raw Rescript files copied verbatim.

Files:

  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
{**/generated/src/**/*.res,codegenerator/cli/templates/static/codegen/src/**/*.res,codegenerator/cli/templates/dynamic/codegen/src/**/*.res}

📄 CodeRabbit Inference Engine (.cursor/rules/navigation.mdc)

Runtime code lives in each project’s generated/src, but template versions (good for editing) are under codegenerator/cli/templates/static/codegen/src or codegenerator/cli/templates/dynamic/codegen/src.

Files:

  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (11)
codegenerator/cli/npm/envio/src/FetchState.res (2)

232-233: Threading blockLag via updateInternal looks good

Propagating ~blockLag explicitly makes the state updates clearer and avoids stale reads. Once clamped as suggested, this path is robust.

Also applies to: 288-289


826-835: Validation complete: EndBlock({toBlock: …}) never receives a negative value
I searched all ReasonML files for EndBlock({toBlock: and found only:

  • A type definition in scenarios/helpers/src/Indexer.res
  • Constant instantiations in tests (8 and 0)
  • The existing fallback at line 654 in codegenerator/cli/npm/envio/src/FetchState.res

Since headBlock is clamped upstream and your blockLag logic safely bounds endBlock, no negative toBlock can occur. No further clamping or code changes are needed.

scenarios/test_codegen/test/ChainManager_test.res (2)

280-286: blockLag set to 0 in test fetch states

Setting blockLag: 0 is consistent with the new non-optional field type.


157-171: All outdated references removed – no action needed

  • onlyBelowReorgThreshold is no longer present in the codebase.
  • Remaining fetchStatesMap occurrences in tests (ChainManager_test.res) and GlobalState.res reflect the intended updated API.

No further updates are required.

codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (1)

77-87: LGTM! Clear logic for event inclusion.

The refactored logic properly uses the config to determine event inclusion and provides helpful logging when events won't be indexed.

codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res (3)

916-921: Verify the isBelowReorgThreshold logic when rollback is disabled.

The current logic sets isBelowReorgThreshold to false when shouldRollbackOnReorg is false. This means the reorg threshold check will never trigger when rollback is disabled. Is this intentional?

If rollback is disabled, should the system still track when chains enter the reorg threshold for other purposes (e.g., metrics, history saving)?


654-677: Well-structured implementation of reorg threshold entry.

The action properly updates all chain fetchers with the new blockLag value and sets the appropriate flags. The Prometheus metric update ensures proper monitoring.


939-1005: Excellent simplification of batch processing logic.

The refactored code is much cleaner with:

  • Direct batch handling without nested conditions
  • Clear separation of concerns between reorg threshold checking and batch processing
  • Proper error handling and rollback state management
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainManager.res (3)

44-61: Good simplification of type system.

Removing the intermediate fetchStateWithData type and using FetchState.t directly reduces complexity and improves code readability.


75-83: Consider improving isInReorgThreshold recovery logic.

The comment indicates that the current approach might incorrectly recover the isInReorgThreshold state. While noted as "not a problem," this could lead to subtle issues if other parts of the system rely on this state being accurate after restart.

Consider adding a more reliable way to persist and recover the isInReorgThreshold state, perhaps by storing it explicitly in the database rather than inferring it from the presence of history rows.


251-310: Well-implemented batch creation with proper state management.

The updated batch creation properly:

  • Makes deep copies of fetch states to avoid mutations
  • Correctly chooses between ordered and unordered batch strategies
  • Handles dynamic contracts storage appropriately

Comment thread codegenerator/cli/npm/envio/src/FetchState.res
Comment thread codegenerator/cli/npm/envio/src/FetchState.res Outdated
Comment thread codegenerator/cli/npm/envio/src/FetchState.res

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
scenarios/test_codegen/test/lib_tests/FetchState_test.res (2)

2775-2793: Also gate on in-flight queries, not only queue emptiness.

Right now this test ensures a non-empty queue blocks readiness. Consider adding a case where the queue is empty but a partition has fetchingStateId set (i.e., an in-flight query). If the implementation doesn’t already account for that, readiness could be reported too early.

Follow-up test suggestion to add within this describe block:

it("Returns false when a partition has an active fetch (in-flight query)", () => {
  let fs = makeInitial()
  // Simulate an in-flight query to set fetchingStateId
  let q: FetchState.query = {
    partitionId: "0",
    target: Head,
    selection: fs.normalSelection,
    addressesByContractName: Js.Dict.empty(),
    fromBlock: 0,
    indexingContracts: fs.indexingContracts,
  }
  fs->FetchState.startFetchingQueries(~queries=[q], ~stateId=0)
  Assert.equal(fs->FetchState.isReadyToEnterReorgThreshold(~currentBlockHeight=10), false)
})

2795-2811: Test title is misleading; scenario duplicates the “endBlock reached & empty queue” path.

This case passes because endBlock is reached and the queue is empty. The large blockLag doesn’t affect the outcome here. Consider:

  • Renaming the test to reflect why it passes (endBlock reached with empty queue), or
  • Adjusting the scenario to demonstrate that blockLag alone can gate readiness when endBlock is not reached.

Example rename:

- it("Returns true when the queue is empty and threshold is more than current block height", () => {
+ it("Returns true when endBlock is reached and the queue is empty (irrespective of blockLag)", () => {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5a030fc and 2f6188e.

📒 Files selected for processing (2)
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res (6 hunks)
  • scenarios/test_codegen/test/lib_tests/FetchState_test.res (10 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{res,resi}

📄 CodeRabbit Inference Engine (.cursor/rules/rescript.mdc)

**/*.{res,resi}: Never use [| item |] to create an array. Use [ item ] instead.
Must always use = for setting value to a field. Use := only for ref values created using ref function.
ReScript has record types which require a type definition before hand. You can access record fields by dot like foo.myField.
It's also possible to define an inline object, it'll have quoted fields in this case.
Use records when working with structured data, and objects to conveniently pass payload data between functions.
Never use %raw to access object fields if you know the type.

Files:

  • scenarios/test_codegen/test/lib_tests/FetchState_test.res
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
codegenerator/cli/templates/{dynamic/**/*.hbs,static/**}

📄 CodeRabbit Inference Engine (.cursor/rules/navigation.mdc)

Templates live under codegenerator/cli/templates: dynamic/ for Handlebars (.hbs), static/ for raw Rescript files copied verbatim.

Files:

  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
{**/generated/src/**/*.res,codegenerator/cli/templates/static/codegen/src/**/*.res,codegenerator/cli/templates/dynamic/codegen/src/**/*.res}

📄 CodeRabbit Inference Engine (.cursor/rules/navigation.mdc)

Runtime code lives in each project’s generated/src, but template versions (good for editing) are under codegenerator/cli/templates/static/codegen/src or codegenerator/cli/templates/dynamic/codegen/src.

Files:

  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build_and_test
🔇 Additional comments (9)
scenarios/test_codegen/test/lib_tests/FetchState_test.res (2)

157-157: LGTM: blockLag assertions updated to non-optional int.

Good job updating expected shapes to include blockLag: 0 across tests to reflect the new non-optional field. This keeps the test expectations aligned with the FetchState.t shape change.

Also applies to: 226-226, 289-289, 385-385, 905-905, 966-966, 1867-1867, 2181-2181


2663-2812: Comprehensive coverage for isReadyToEnterReorgThreshold.

The new suite exercises key boundaries: endBlock reached, head - blockLag threshold (including equality), absence of endBlock, and queue non-emptiness gating. This aligns with the PR objective to avoid querying reorgable blocks prematurely.

codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res (7)

78-78: LGTM! Appropriate Prometheus metrics initialization.

Good addition of the reorg threshold metric initialization to track when the indexer enters/exits the reorg threshold state.


610-647: Well-structured reorg threshold detection logic.

The implementation correctly:

  1. Checks all chain fetchers are ready to enter reorg threshold
  2. Updates the isInReorgThreshold state appropriately
  3. Only updates fetchState with blockLag when entering the threshold

The logic flow is clear and handles the state transitions properly.


680-703: Clean implementation of the EnterReorgThreshold action.

The action handler properly:

  1. Logs the threshold entry
  2. Updates Prometheus metrics
  3. Applies blockLag to all chain fetchers
  4. Sets the global reorg threshold state
  5. Triggers re-querying of all chains

The separation of this logic into a dedicated action improves code organization.


733-733: Correct usage of FetchState.t type.

The direct assignment of fetchState from the fetchStatesMap properly reflects the updated type signature where FetchState.t is now used directly instead of being wrapped in another type.


938-960: Effective pre-batch gating for reorg threshold entry.

The logic correctly checks if all chains are ready to enter the reorg threshold before processing a batch, dispatching EnterReorgThreshold when conditions are met. This prevents processing events while transitioning into the threshold state.


963-999: Simplified batch processing with proper metrics updates.

The refactored batch processing logic is cleaner and more maintainable. The switch statement clearly handles empty vs non-empty batches, and the metrics updates are properly implemented per chain.


635-636: Verify blockLag default fallback

There’s a lingering FIXME in Env.res noting that falling back to 0 “broke HS grafana dashboard.” We currently use

let indexingBlockLag = envSafe->EnvSafe.get("ENVIO_INDEXING_BLOCK_LAG", S.option(S.int))
…->Option.getWithDefault(0)

in both ChainFetcher and GlobalState without any external docs calling out the expected default.

Please confirm or adjust as needed:

  • Ensure a default of 0 (via Option.getWithDefault(0)) is the correct semantic when ENVIO_INDEXING_BLOCK_LAG is unset.
  • If another fallback makes more sense (e.g. omitting the parameter, a positive lag, etc.), update the code and remove/fix the FIXME.
  • Consider adding a note to your README or environment docs describing the behavior of ENVIO_INDEXING_BLOCK_LAG.

Key locations:

  • codegenerator/cli/templates/static/codegen/src/Env.res
  • codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
  • codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res

Comment on lines +826 to +827
| 0 => endBlock
| _ =>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit: maybe an if is more appropriate here

Comment on lines -167 to -176
isInReorgThresholdRef :=
isInReorgThresholdRef.contents || {
let {currentBlockHeight, highestBlockBelowThreshold} =
fetchStatesMap->ChainMap.get(chain)
earliestEvent->FetchState.queueItemIsInReorgThreshold(
~currentBlockHeight,
~highestBlockBelowThreshold,
)
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice, simplifies this stuff a lot

Comment on lines -653 to -654
| SetIsInReorgThreshold(isInReorgThreshold) =>
if isInReorgThreshold {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just checking we never used to exit reorg threshold right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes

@JonoPrest JonoPrest left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Cool looks great!

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