-
Notifications
You must be signed in to change notification settings - Fork 32
Optional event processing on historical indexing #830
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?
Optional event processing on historical indexing #830
Conversation
WalkthroughAdds a per-event readiness flag ( Changes
Sequence Diagram(s)sequenceDiagram
participant Config as Config file
participant Parser as Human/System Parser
participant CodeGen as Code generator
participant Runtime as ChainFetcher/FetchState
Config->>Parser: Read EventConfig (only_when_ready / onlyWhenReady)
Parser->>CodeGen: Pass event with only_when_ready value
CodeGen->>Runtime: Emit event definitions including onlyWhenReady flag
rect rgb(247,250,255)
note right of Runtime: Compute readiness from timestampCaughtUpToHeadOrEndblock
Runtime->>Runtime: Compute isReady
end
alt isReady == true
Runtime->>Runtime: Include all events and onBlock handlers
else isReady == false
alt enableRawEvents == true
Runtime->>Runtime: Include event (raw override)
else onlyWhenReady == false
Runtime->>Runtime: Include event
else onlyWhenReady == true
Runtime->>Runtime: Defer event/onBlock handler (collect into deferred lists)
end
end
note right of Runtime: On transition to ready -> FetchState.activateDeferredEventsAndHandlers -> integrate deferred events/handlers into partitions & onBlockConfigs
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
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. Comment |
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.
Actionable comments posted: 0
🧹 Nitpick comments (3)
scenarios/test_codegen/config.yaml (1)
15-16: LGTM: Test event added for new feature.The
OnlyWhenReadyEventwithonly_when_ready: trueprovides test coverage for the new functionality.Consider adding additional test scenarios to cover:
- Events with
only_when_ready: falseexplicitly set- Multiple events with mixed
only_when_readyvalues on the same contract- Interaction with
raw_events: trueconfigurationcodegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (1)
80-95: Core logic is correct; consider simplification.The filtering logic correctly implements the feature: events marked
onlyWhenReady: trueare excluded during historical sync (when!isReady), and always included once the chain is ready or whenenableRawEventsis true.The
shouldIncludeBasedOnReadinessboolean logic can be simplified for clarity:- let shouldIncludeBasedOnReadiness = if onlyWhenReady && !isReady { - false - } else { - true - } + let shouldIncludeBasedOnReadiness = !onlyWhenReady || isReadyThis is logically equivalent (De Morgan's law) and more concise.
codegenerator/cli/src/config_parsing/system_config.rs (1)
1419-1419: Approve with optional refactor suggestion.The
only_when_readyfield is correctly set for all five Fuel event types (LogData, Mint, Burn, Transfer, Call) with proper backward-compatible defaults. The repetition follows the existing pattern used forfield_selection.Optional refactor: Consider extracting Event construction into a helper function to reduce the repetition across all five event type branches. However, the current explicit approach is acceptable and may be preferred for clarity.
Also applies to: 1427-1427, 1434-1434, 1441-1441, 1448-1448
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
scenarios/test_codegen/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (11)
codegenerator/cli/npm/envio/evm.schema.json(1 hunks)codegenerator/cli/npm/envio/fuel.schema.json(1 hunks)codegenerator/cli/npm/envio/src/Internal.res(1 hunks)codegenerator/cli/src/cli_args/init_config.rs(1 hunks)codegenerator/cli/src/cli_args/interactive_init/fuel_prompts.rs(2 hunks)codegenerator/cli/src/config_parsing/graph_migration/mod.rs(1 hunks)codegenerator/cli/src/config_parsing/human_config.rs(2 hunks)codegenerator/cli/src/config_parsing/system_config.rs(3 hunks)codegenerator/cli/src/hbs_templating/codegen_templates.rs(6 hunks)codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res(2 hunks)scenarios/test_codegen/config.yaml(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
codegenerator/cli/**
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
The Rust CLI lives in codegenerator/cli
Files:
codegenerator/cli/src/config_parsing/graph_migration/mod.rscodegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.rescodegenerator/cli/src/config_parsing/human_config.rscodegenerator/cli/npm/envio/src/Internal.rescodegenerator/cli/npm/envio/fuel.schema.jsoncodegenerator/cli/src/cli_args/init_config.rscodegenerator/cli/src/config_parsing/system_config.rscodegenerator/cli/src/hbs_templating/codegen_templates.rscodegenerator/cli/src/cli_args/interactive_init/fuel_prompts.rscodegenerator/cli/npm/envio/evm.schema.json
codegenerator/cli/templates/static/**/*.res
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Static templates are raw ReScript files copied verbatim under codegenerator/cli/templates/static
Files:
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
{codegenerator/cli/templates/static/codegen/src/**,codegenerator/cli/templates/dynamic/codegen/src/**}
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Template versions of runtime live under templates/{static,dynamic}/codegen/src and are the recommended editing targets
Files:
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
**/*.res
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Prefer reading ReScript .res modules directly
Files:
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.rescodegenerator/cli/npm/envio/src/Internal.res
codegenerator/cli/npm/envio/**
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Shared library-fied runtime lives in codegenerator/cli/npm/envio
Files:
codegenerator/cli/npm/envio/src/Internal.rescodegenerator/cli/npm/envio/fuel.schema.jsoncodegenerator/cli/npm/envio/evm.schema.json
codegenerator/cli/src/hbs_templating/codegen_templates.rs
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
hbs_templating/codegen_templates.rs feeds templates
Files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
🧠 Learnings (6)
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Verify tests by running `pnpm rescript` then `pnpm mocha`; use `_only` to focus tests
Applied to files:
scenarios/test_codegen/config.yaml
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/ChainFetcher.res : In generated runtime, ChainFetcher.res is part of the fetch side
Applied to files:
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/ChainManager.res : In generated runtime, ChainManager.res is part of the fetch side
Applied to files:
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to codegenerator/cli/src/human_config.rs : human_config.rs reads user files and JSON schemas
Applied to files:
codegenerator/cli/src/config_parsing/human_config.rs
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to codegenerator/cli/src/system_config.rs : system_config.rs converts to internal structs
Applied to files:
codegenerator/cli/src/config_parsing/system_config.rscodegenerator/cli/src/hbs_templating/codegen_templates.rs
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to codegenerator/cli/src/hbs_templating/codegen_templates.rs : hbs_templating/codegen_templates.rs feeds templates
Applied to files:
codegenerator/cli/src/hbs_templating/codegen_templates.rs
⏰ 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 (15)
codegenerator/cli/npm/envio/fuel.schema.json (1)
146-152: LGTM: Schema field addition is well-defined.The
onlyWhenReadyfield is properly defined with clear documentation and correct typing (boolean | null for optional). The description accurately explains that events with this flag will only be tracked post-backfill.codegenerator/cli/src/cli_args/init_config.rs (1)
61-61: LGTM: Consistent field initialization.The
only_when_ready: Noneinitialization follows the established pattern for optional EventConfig fields.codegenerator/cli/npm/envio/src/Internal.res (1)
106-108: LGTM: Internal type extension is correct.The
onlyWhenReady: boolfield is appropriately typed as a non-optional boolean for the internal runtime representation (defaults will be applied during config parsing). The comment clearly explains the field's purpose.codegenerator/cli/src/config_parsing/graph_migration/mod.rs (1)
345-345: LGTM: Consistent initialization in migration path.The
only_when_ready: Noneinitialization maintains consistency with other EventConfig construction paths.codegenerator/cli/src/cli_args/interactive_init/fuel_prompts.rs (1)
137-137: LGTM: Field initialization in event creation paths.Both EventConfig construction sites (lines 137 and 151) properly initialize
only_when_ready: None, maintaining consistency across log-based and predefined event creation flows.codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (2)
58-60: LGTM: Readiness check is clear.The
isReadycomputation based ontimestampCaughtUpToHeadOrEndblock !== Nonecorrectly identifies when the chain has completed historical sync.
65-65: LGTM: Field destructuring added.Extracting
onlyWhenReadyalongsideisWildcardis clean and follows the existing pattern.codegenerator/cli/src/config_parsing/human_config.rs (2)
545-553: LGTM: EVM EventConfig field addition is well-structured.The
only_when_readyfield is properly defined with:
- Appropriate type (
Option<bool>)- Correct serde attributes to skip None during serialization
- Clear, comprehensive schema documentation explaining behavior and default
713-721: LGTM: Fuel EventConfig field mirrors EVM implementation.The Fuel module's
only_when_readyfield is consistently implemented with the same pattern as the EVM module, maintaining cross-ecosystem consistency.codegenerator/cli/src/hbs_templating/codegen_templates.rs (3)
341-341: LGTM! Clean field addition to EventMod.The
only_when_readyfield is correctly added as a public boolean field and will be propagated through the event code generation pipeline.
421-430: LGTM! Code generation correctly emits the onlyWhenReady field.The logic cleanly converts the boolean value to a string literal (
"true"or"false") and includes it in the generated event configuration code. The field will be available at runtime asInternal.eventConfig.onlyWhenReady.
661-661: LGTM! Field propagation is consistent across all event types.The
only_when_readyfield is correctly propagated fromconfig_eventtoEventModin all construction paths:
- Fuel supply events (line 661)
- Fuel transfer events (line 689)
- EVM events with params (line 753)
- Fuel LogData events (line 782)
This ensures the field is available for all supported event kinds.
Also applies to: 689-689, 753-753, 782-782
codegenerator/cli/npm/envio/evm.schema.json (1)
208-214: LGTM! Well-documented schema addition.The
only_when_readyfield is correctly defined as an optional boolean with a clear, comprehensive description. The nullable type ensures backward compatibility with existing configurations, and the description provides excellent guidance on the feature's purpose and use cases.codegenerator/cli/src/config_parsing/system_config.rs (2)
1247-1247: LGTM! Event struct field addition is clean.The
only_when_readyboolean field is correctly added to the Event struct. The non-optional type is appropriate since the config parsing layer handles the default value (falsewhen not specified).
1339-1339: LGTM! EVM event configuration correctly handles the optional field.The
unwrap_or(false)pattern provides proper backward compatibility—existing configurations withoutonly_when_readywill default tofalse, maintaining current behavior. The field is cleanly integrated into the Event construction alongsidefield_selection.
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.
Actionable comments posted: 0
🧹 Nitpick comments (1)
scenarios/test_codegen/test/helpers/Mock.res (1)
671-671: Consider extendingitemMocktype for comprehensive integration testing.The hardcoded
onlyWhenReady: falsevalue limits the ability to test event filtering behavior through theSource.makemock. While the dedicated unit tests (OnlyWhenReady_test.res) likely cover the core filtering logic, integration-style tests usingSource.makecannot simulate events withonlyWhenReady: true.If more comprehensive integration testing is needed, consider:
- Adding
onlyWhenReady?: boolto theitemMocktype (lines 469-474)- Passing this value through to the event config construction on line 671
Apply this diff if integration testing via
Source.makebecomes necessary:type itemMock = { blockNumber: int, logIndex: int, handler?: Types.HandlerTypes.loader<unit, unit>, contractRegister?: Types.HandlerTypes.contractRegister<unit>, + onlyWhenReady?: bool, }Then update line 671:
- onlyWhenReady: false, + onlyWhenReady: item.onlyWhenReady->Option.getWithDefault(false),
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
scenarios/test_codegen/test/helpers/Mock.res(3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.res
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Prefer reading ReScript .res modules directly
Files:
scenarios/test_codegen/test/helpers/Mock.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 (1)
scenarios/test_codegen/test/helpers/Mock.res (1)
763-792: LGTM! Parameter addition enables flexible test configurations.The optional
~onlyWhenReadyparameter with a default offalseis correctly added to theevmEventConfighelper function and properly wired into the returned configuration object. This allows tests to create event configs with different readiness requirements while maintaining backward compatibility.
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.
Actionable comments posted: 0
🧹 Nitpick comments (4)
scenarios/test_codegen/test/OnlyWhenReady_test.res (4)
93-96: Consider making the assertion more explicit.While the current assertion is correct (the length check ensures the array access is safe), you could make the test slightly more explicit by verifying the ID directly from the array.
Optional refactor to make the assertion more explicit:
// Only the regular event should be included let eventConfigs = chainFetcher.fetchState.eventConfigs Assert.deep_equal(eventConfigs->Array.length, 1) - Assert.deep_equal(eventConfigs[0]->Option.getExn.id, "regular") + let eventIds = eventConfigs->Array.map(ec => ec.id) + Assert.deep_equal(eventIds, ["regular"])This approach mirrors the pattern used in the second test case and avoids
Option.getExn.
140-144: Consider simplifying the string comparison.The sorting logic is correct but could be slightly more concise using
String.compareif available, or by directly returning the comparison result.Optional refactor:
// Verify both event IDs are present - let eventIds = eventConfigs->Array.map(ec => ec.id)->Array.sort((a, b) => { - if a < b { -1 } else if a > b { 1 } else { 0 } - }) + let eventIds = eventConfigs->Array.map(ec => ec.id)->Array.sort(String.compare) Assert.deep_equal(eventIds, ["onlyWhenReady", "regular"])Note: Verify that
String.compareis available in your ReScript version. The current implementation is correct ifString.compareis not available.
240-242: Consider verifying the event ID for completeness.While the length assertion confirms the event is included, explicitly verifying the event ID would make the test more thorough and self-documenting.
Optional enhancement:
// Event should be included because raw events mode is enabled Assert.deep_equal(chainFetcher.fetchState.eventConfigs->Array.length, 1) + Assert.deep_equal(chainFetcher.fetchState.eventConfigs[0]->Option.getExn.id, "onlyWhenReady")Additionally, you might consider adding a test case that verifies behavior when
enableRawEvents=trueAND the chain IS ready, to ensure the feature works correctly in all combinations.
55-243: Excellent test coverage for the core scenarios.The test suite comprehensively covers the main use cases for the
onlyWhenReadyfeature. Consider adding additional test cases for edge scenarios:
- Multiple
onlyWhenReadyevents mixed with multiple regular events when the chain is not ready (to ensure filtering works correctly with larger event sets)- Behavior when
enableRawEvents=trueand the chain transitions from not ready to ready- Empty event configs array (if applicable)
These additional tests would further strengthen confidence in the feature's robustness.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
scenarios/test_codegen/test/OnlyWhenReady_test.res(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.res
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Prefer reading ReScript .res modules directly
Files:
scenarios/test_codegen/test/OnlyWhenReady_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 (2)
scenarios/test_codegen/test/OnlyWhenReady_test.res (2)
1-7: LGTM!The test suite setup and imports are correct. Standard ReScript test configuration with appropriate test helpers.
8-53: LGTM!The helper functions are well-structured and provide good test data setup. They follow ReScript conventions with labeled arguments and sensible defaults.
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.
Actionable comments posted: 0
🧹 Nitpick comments (2)
scenarios/test_codegen/test/OnlyWhenReady_test.res (2)
141-143: Consider simplifying the sorting comparator.The custom string comparison logic works correctly but could be more concise using ReScript's built-in
String.compare.Apply this diff to simplify the sorting:
- let eventIds = eventConfigs->Array.map(ec => ec.id)->Array.sort((a, b) => { - if a < b { -1 } else if a > b { 1 } else { 0 } - }) + let eventIds = eventConfigs->Array.map(ec => ec.id)->Array.sort(String.compare)
209-242: Consider testing enableRawEvents with mixed event types.The test correctly verifies that
enableRawEventsmode includesonlyWhenReadyevents even when the chain is not ready. For more comprehensive coverage, consider adding a test scenario with both regular andonlyWhenReadyevents to ensure both types are included in raw events mode.Example enhancement:
let regularEvent = (Mock.evmEventConfig( ~id="regular", ~contractName="TestContract", ~onlyWhenReady=false, ) :> Internal.eventConfig) let onlyWhenReadyEvent = (Mock.evmEventConfig( ~id="onlyWhenReady", ~contractName="TestContract", ~onlyWhenReady=true, ) :> Internal.eventConfig) let chainConfig = makeChainConfig(~eventConfigs=[regularEvent, onlyWhenReadyEvent]) // ... rest of test Assert.deep_equal(chainFetcher.fetchState.eventConfigs->Array.length, 2)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
scenarios/test_codegen/test/OnlyWhenReady_test.res(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.res
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Prefer reading ReScript .res modules directly
Files:
scenarios/test_codegen/test/OnlyWhenReady_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 (3)
scenarios/test_codegen/test/OnlyWhenReady_test.res (3)
1-53: LGTM! Well-structured test helpers.The helper functions provide clean, reusable test configuration builders that cover the necessary setup for ChainFetcher tests. The use of named parameters with defaults makes the test code readable and maintainable.
56-97: LGTM! Test correctly validates filtering behavior.The test properly verifies that events marked with
onlyWhenReady: trueare filtered out during historical sync (whentimestampCaughtUpToHeadOrEndblockisNone), while regular events are included. The assertions are safe and comprehensive.
147-207: LGTM! Good explicit coverage for regular events.The test explicitly verifies that regular events (with
onlyWhenReady: false) are always included regardless of chain readiness state. This provides clear documentation of expected behavior and catches potential regressions in the default case.
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.
Actionable comments posted: 0
🧹 Nitpick comments (2)
scenarios/test_codegen/test/OnlyWhenReady_test.res (2)
126-172: LGTM! Consider simplifying the sort comparator.The test correctly validates that both regular and
onlyWhenReadyevents are included once the chain is ready. The assertion logic properly verifies the presence of both event types.The inline sort comparator on lines 168-170 could be simplified:
- let eventIds = eventConfigs->Array.map(ec => ec.id)->Array.sort((a, b) => { - if a < b { -1 } else if a > b { 1 } else { 0 } - }) + let eventIds = eventConfigs->Array.map(ec => ec.id)->Array.sort(String.compare)
82-270: Consider reducing duplication and expanding edge case coverage.While the test suite effectively covers the main scenarios, you could:
- Extract common
ChainFetcher.makeparameters into a helper function to reduce the repetitive boilerplate across tests.- Add edge case tests such as:
- All events marked as
onlyWhenReady=truewhen the chain is not ready (should result in 0 events)- Mixed scenarios with multiple
onlyWhenReadyand regular events to validate correct filtering at scaleExample helper to reduce duplication:
let makeChainFetcherWithDefaults = ( ~chainConfig, ~config, ~registrations, ~timestampCaughtUpToHeadOrEndblock, ) => { ChainFetcher.make( ~chainConfig, ~config, ~registrations, ~dynamicContracts=[], ~startBlock=0, ~endBlock=None, ~firstEventBlockNumber=None, ~progressBlockNumber=-1, ~timestampCaughtUpToHeadOrEndblock, ~numEventsProcessed=0, ~numBatchesFetched=0, ~targetBufferSize=5000, ~logger=Logging.logger, ~isInReorgThreshold=false, ~reorgCheckpoints=[], ~maxReorgDepth=100, ) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
scenarios/test_codegen/test/OnlyWhenReady_test.res(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.res
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Prefer reading ReScript .res modules directly
Files:
scenarios/test_codegen/test/OnlyWhenReady_test.res
🧠 Learnings (1)
📚 Learning: 2025-10-21T16:31:22.127Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: .cursor/rules/navigation.mdc:0-0
Timestamp: 2025-10-21T16:31:22.127Z
Learning: Applies to generated/src/ChainFetcher.res : In generated runtime, ChainFetcher.res is part of the fetch side
Applied to files:
scenarios/test_codegen/test/OnlyWhenReady_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 (4)
scenarios/test_codegen/test/OnlyWhenReady_test.res (4)
83-124: LGTM!The test correctly validates that
onlyWhenReadyevents are filtered out during historical sync (when the chain is not ready). The assertion logic is sound, and the test setup properly simulates the not-ready state.
174-234: LGTM!This test properly validates that regular events (with
onlyWhenReady=false) are always included regardless of the chain's ready state. The dual assertion approach effectively confirms consistent behavior across both states.
236-270: LGTM!This test correctly validates that
enableRawEventsmode overrides theonlyWhenReadyfiltering, ensuring events are included even when the chain is not ready. This is an important edge case that confirms the feature doesn't break raw events functionality.
13-15: The type-unsafe cast is actually safe in this test context.The
evmEventConfigtype extendseventConfigusing spread syntax, and the objects passed through the cast are actualevmEventConfiginstances (created byMock.evmEventConfig()) that contain all required fields. While usingUtils.magicis not ideal style, it is safe here because the runtime objects do have the fields being accessed.
DZakh
left a comment
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.
It looks like the implementation doesn't work correctly, since the ChainFetcher is only created on the application start up. So the filter won't be updated on switch from historical sync to realtime.
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.
Actionable comments posted: 0
🧹 Nitpick comments (2)
codegenerator/cli/npm/envio/src/FetchState.res (1)
1347-1354: Consider callingupdateInternalto ensure derived values are recalculated.The function returns a modified
fetchStatewithout callingupdateInternal. While the partition changes may not affectlatestFullyFetchedBlock, the newly addedonBlockConfigswon't generate block items until the nextupdateInternalcall (which happens during query result handling). This could cause a delay in block handler activation.If immediate activation is desired, consider:
- { - ...fetchState, - partitions: allPartitions, - nextPartitionIndex: fetchState.nextPartitionIndex + newPartitions->Array.length, - normalSelection: updatedNormalSelection, - onBlockConfigs: updatedOnBlockConfigs, - } + { + ...fetchState, + normalSelection: updatedNormalSelection, + onBlockConfigs: updatedOnBlockConfigs, + }->updateInternal( + ~partitions=allPartitions, + ~nextPartitionIndex=fetchState.nextPartitionIndex + newPartitions->Array.length, + )codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (1)
172-184: Minor: Redundant iteration overonBlockConfigsarray.The code iterates over
onBlockConfigstwice - once for filtering and once for collecting deferred handlers. Consider combining into a single pass for clarity:- // Filter out block handlers marked as onlyWhenReady if the chain is not ready yet - let filtered = onBlockConfigs->Array.keep(onBlockConfig => { - !onBlockConfig.onlyWhenReady || isReady - }) - // Collect deferred block handlers - if !isReady { - onBlockConfigs->Array.forEach(onBlockConfig => { - if onBlockConfig.onlyWhenReady { - deferredOnBlockConfigs->Array.push(onBlockConfig) - } - }) - } + // Filter and collect deferred block handlers in a single pass + let filtered = [] + onBlockConfigs->Array.forEach(onBlockConfig => { + if !onBlockConfig.onlyWhenReady || isReady { + filtered->Array.push(onBlockConfig) + } else { + deferredOnBlockConfigs->Array.push(onBlockConfig) + } + })
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
codegenerator/cli/npm/envio/src/FetchState.res(1 hunks)codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res(8 hunks)codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res(2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
codegenerator/cli/templates/static/**/*.res
📄 CodeRabbit inference engine (.cursor/rules/navigation.mdc)
Static ReScript files must be placed in
codegenerator/cli/templates/static/
Files:
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.rescodegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
**/*.{res,resi}
📄 CodeRabbit inference engine (.cursor/rules/rescript.mdc)
**/*.{res,resi}: Always use ReScript 11 documentation
Never suggest ReasonML syntax
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 usingreffunction
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/templates/static/codegen/src/eventFetching/ChainFetcher.rescodegenerator/cli/npm/envio/src/FetchState.rescodegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res
🧠 Learnings (3)
📚 Learning: 2025-11-25T12:41:23.343Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-11-25T12:41:23.343Z
Learning: Applies to codegenerator/cli/templates/static/shared/src/**/*.ts : Never hardcode chainId = 1; always use event.chainId for chain-specific operations
Applied to files:
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
📚 Learning: 2025-11-25T12:41:23.343Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-11-25T12:41:23.343Z
Learning: Applies to codegenerator/cli/templates/static/shared/src/**/*.ts : Prefix all entity IDs with chainId in multichain indexing: ${event.chainId}-${originalId}
Applied to files:
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
📚 Learning: 2025-11-25T12:41:23.343Z
Learnt from: CR
Repo: enviodev/hyperindex PR: 0
File: codegenerator/cli/templates/static/shared/.cursor/rules/subgraph-migration.mdc:0-0
Timestamp: 2025-11-25T12:41:23.343Z
Learning: Applies to codegenerator/cli/templates/static/shared/src/**/*.ts : Register dynamic contracts created by factory events using contractRegister above the handler (e.g., context.addPair(event.params.pair))
Applied to files:
codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res
🔇 Additional comments (4)
codegenerator/cli/templates/static/codegen/src/globalState/GlobalState.res (1)
292-343: LGTM! Clean implementation of the readiness transition detection.The logic correctly captures the "was not ready" state before computing updates, then detects when the chain transitions to ready state to activate deferred events and handlers. The use of
wasNotReady && isNowReadyensures activation happens exactly once at the transition point.codegenerator/cli/templates/static/codegen/src/eventFetching/ChainFetcher.res (2)
86-109: LGTM! Event filtering and deferral logic is correct.The logic properly handles the three cases:
- Events that should be included now (registered and either not
onlyWhenReadyor chain is ready)- Events that should be deferred (registered,
onlyWhenReady, and chain not ready)- Events that are skipped entirely (not registered and not
enableRawEvents)The separation ensures no events are lost and deferred events are correctly tracked for later activation.
503-526: LGTM! Clean activation function with proper cleanup.The function correctly:
- Short-circuits when there's nothing to activate
- Delegates to
FetchState.activateDeferredEventsAndHandlersfor the actual work- Clears the deferred arrays to prevent double-activation
codegenerator/cli/npm/envio/src/FetchState.res (1)
1271-1289: I'll verify the review comment by analyzing howcontractConfigsis used and whether it needs to include deferred event contracts. Let me start by exploring the relevant code.
<function_calls>
#!/bin/bashFirst, let's understand how contractConfigs is used in FetchState.res
rg -n "contractConfigs" codegenerator/cli/npm/envio/src/FetchState.res -A 2 -B 1 | head -100
</function_calls>Let me also check the structure of the file and locate the make function that populates contractConfigs:
<function_calls>
#!/bin/bashFind the make function in FetchState.res to understand contractConfigs initialization
rg -n "let make" codegenerator/cli/npm/envio/src/FetchState.res -A 15 | head -60
</function_calls>Let me search more specifically for where contractConfigs is created and updated:
<function_calls>
#!/bin/bashSearch for contractConfigs field and its assignments
rg -n "contractConfigs\s*=" codegenerator/cli/npm/envio/src/FetchState.res -B 2 -A 2
</function_calls>Now let me look at the actual file to understand the context better:
<function_calls>
#!/bin/bashGet file size first
wc -l codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Let me read the key sections of the file:
<function_calls>
#!/bin/bashRead the make function area to see how contractConfigs is populated
sed -n '980,1020p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Now let me check the activateDeferredEventsAndHandlers function and the surrounding context:
<function_calls>
#!/bin/bashRead activateDeferredEventsAndHandlers function
sed -n '1265,1350p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Let me search for where contractConfigs is used after being set:
<function_calls>
#!/bin/bashLook for all uses of contractConfigs to understand its purpose
rg -n ".contractConfigs|contractConfigs\s*:" codegenerator/cli/npm/envio/src/FetchState.res -B 2 -A 2 | head -120
</function_calls>Now let me check the registerDynamicContracts function mentioned in the review comment:
<function_calls>
#!/bin/bashSearch for registerDynamicContracts function
rg -n "registerDynamicContracts|filterByAddresses" codegenerator/cli/npm/envio/src/FetchState.res -B 3 -A 3
</function_calls>Let me look at how ChainFetcher processes eventConfigs to understand whether deferred events are filtered out:
<function_calls>
#!/bin/bashFind ChainFetcher.make to see how it passes eventConfigs to FetchState
fd ChainFetcher.res codegenerator/cli/npm/envio/src/
</function_calls>Let me search for where deferred events are handled:
<function_calls>
#!/bin/bashSearch for deferred event handling and filtering
rg -n "shouldBeIncluded|isDeferred" codegenerator/cli/npm/envio/src/ --type res -B 2 -A 2
</function_calls>Let me search more broadly for the eventConfig structure and deferred handling:
<function_calls>
#!/bin/bashLook for eventConfig type definition and deferred field
rg -n "deferred|isDeferred" codegenerator/cli/npm/envio/src/ --type res -B 1 -A 1 | head -80
</function_calls>Let me examine the Internal module to understand the eventConfig structure:
<function_calls>
#!/bin/bashFind the Internal module that defines eventConfig
fd -e res codegenerator/cli/npm/envio/src/ | xargs rg -l "type eventConfig"
</function_calls>Let me check the FetchState file itself for Internal module and eventConfig references:
<function_calls>
#!/bin/bashSearch within FetchState.res for eventConfig references and type definitions
sed -n '1,100p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Let me check what happens with the return value of activateDeferredEventsAndHandlers:
<function_calls>
#!/bin/bashSearch for calls to activateDeferredEventsAndHandlers to see how result is used
rg -n "activateDeferredEventsAndHandlers" codegenerator/cli/npm/envio/src/ --type res -B 2 -A 5
</function_calls>Let me look at the full activateDeferredEventsAndHandlers function more carefully:
<function_calls>
#!/bin/bashGet the complete activateDeferredEventsAndHandlers function
sed -n '1271,1320p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Now let me look at the entire return block:
<function_calls>
#!/bin/bashGet more lines to see the complete function
sed -n '1271,1400p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Let me search for the return statement pattern in this function:
<function_calls>
#!/bin/bashFind the return statement in activateDeferredEventsAndHandlers
sed -n '1271,1500p' codegenerator/cli/npm/envio/src/FetchState.res | grep -n "contractConfigs|return|...fetchState" -A 2 -B 2
</function_calls>Let me read the complete function more carefully:
<function_calls>
#!/bin/bashRead a larger section to capture the complete function
sed -n '1271,1450p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Let me search for where this function ends:
<function_calls>
#!/bin/bashFind the end of activateDeferredEventsAndHandlers function
awk '/^let activateDeferredEventsAndHandlers = (/,/^}/' codegenerator/cli/npm/envio/src/FetchState.res | tail -100
</function_calls>Now let me check how contractConfigs is actually used after being populated:
<function_calls>
#!/bin/bashSearch for where contractConfigs is accessed/used (not just assigned)
rg -n ".contractConfigs" codegenerator/cli/npm/envio/src/FetchState.res | head -20
</function_calls>Let me look at those specific uses to understand the impact:
<function_calls>
#!/bin/bashGet context around contractConfigs usage
rg -n ".contractConfigs" codegenerator/cli/npm/envio/src/FetchState.res -B 5 -A 5
</function_calls>Let me check the type definition of t to understand what fields exist:
<function_calls>
#!/bin/bashFind the type t definition in FetchState.res
rg -n "type\s+t\s*=\s*{" codegenerator/cli/npm/envio/src/FetchState.res -A 30
</function_calls>Let me search for the complete type definition more carefully:
<function_calls>
#!/bin/bashSearch for type t and get full definition
sed -n '1,200p' codegenerator/cli/npm/envio/src/FetchState.res | grep -n "type t"
</function_calls>Let me check the module structure:
<function_calls>
#!/bin/bashLook at the beginning of FetchState module
head -300 codegenerator/cli/npm/envio/src/FetchState.res | tail -200
</function_calls>Let me search for where the type t is defined more broadly:
<function_calls>
#!/bin/bashSearch more carefully for type t definition
rg -n "^\s*type t\b" codegenerator/cli/npm/envio/src/FetchState.res -A 50 | head -80
</function_calls>Let me try ast-grep to find the type definition:
<function_calls>
#!/bin/bashUse ast-grep to find type definitions
ast-grep --pattern 'type t = {
$$$
}'
</function_calls>Let me read the first 1000 lines more systematically:
<function_calls>
#!/bin/bashRead specific line ranges to find type t
sed -n '50,150p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Now let me check what the actual field names are in the return statement:
<function_calls>
#!/bin/bashLook for return statements or {...fetchState} patterns
rg -n "...fetchState|{$" codegenerator/cli/npm/envio/src/FetchState.res -A 10 | head -80
</function_calls>Let me check how make function constructs the return record:
<function_calls>
#!/bin/bashRead around the make function return statement
sed -n '980,1050p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Let me try to understand the record structure from how it's used:
<function_calls>
#!/bin/bashLook for all field accesses on fetchState
rg -n "fetchState." codegenerator/cli/npm/envio/src/FetchState.res | cut -d: -f3 | sort -u | head -40
</function_calls>Now let me check the return structure of activateDeferredEventsAndHandlers more directly:
<function_calls>
#!/bin/bashExtract the full function and look at its return value
awk '/^let activateDeferredEventsAndHandlers = (/,/^}/' codegenerator/cli/npm/envio/src/FetchState.res | grep -n "contractConfigs|partitions|normalSelection" -B 2 -A 2
</function_calls>Let me check how ChainFetcher prepares the eventConfigs passed to FetchState:
<function_calls>
#!/bin/bashFind how ChainFetcher passes eventConfigs to FetchState.make
rg -n "FetchState.make" codegenerator/cli/npm/envio/src/ --type res -B 10 | head -80
</function_calls>Let me check what fields eventConfig contains by looking at eventConfigs processing:
<function_calls>
#!/bin/bashSearch for where deferredEventConfigs are created/extracted
rg -n "deferredEventConfigs|~deferredEventConfigs" codegenerator/cli/npm/envio/src/ --type res -B 3 -A 3
</function_calls>Let me search for where deferred events are separated:
<function_calls>
#!/bin/bashSearch for where eventConfigs might be filtered or split
rg -n "notDeferred|dependsOnAddresses|isDeferred" codegenerator/cli/npm/envio/src/ --type res -B 2 -A 2 | head -100
</function_calls>Let me check the eventConfig fields based on what's accessed:
<function_calls>
#!/bin/bashLook at the snippet from the review comment to understand accessed fields
sed -n '1271,1289p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Now let me understand what contractName field is used for by searching through the code:
<function_calls>
#!/bin/bashSearch for how contractName is used in eventConfigs
rg -n ".contractName|ec.contractName" codegenerator/cli/npm/envio/src/ --type res -B 2 -A 2 | head -60
</function_calls>Let me search for where contractConfigs Map is built:
<function_calls>
#!/bin/bashSearch for contractConfigs construction
rg -n "contractConfigs.*=" codegenerator/cli/npm/envio/src/FetchState.res -B 2 -A 8 | head -100
</function_calls>Let me look at that specific area:
<function_calls>
#!/bin/bashRead the area where contractConfigs is assigned
sed -n '995,1020p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Let me read more of that section to see the full logic:
<function_calls>
#!/bin/bashGet more context around contractConfigs assignment
sed -n '1000,1020p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Now let me check if there's any logic that depends on contractConfigs being present:
<function_calls>
#!/bin/bashLook for Map operations on contractConfigs
rg -n "contractConfigs->Map." codegenerator/cli/npm/envio/src/FetchState.res -B 1 -A 3
</function_calls>Let me check what happens in that line 360 mentioned in the scratchpad about registerDynamicContracts:
<function_calls>
#!/bin/bashCheck line 360 area
sed -n '355,375p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Let me get more context around that line:
<function_calls>
#!/bin/bashSearch for Map.has or Map.get on contractConfigs in that area
sed -n '350,380p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Let me search directly for how contractConfigs is queried:
<function_calls>
#!/bin/bashSearch for all uses of contractConfigs with Map operations
rg -n "contractConfigs->Map|Map.*contractConfigs" codegenerator/cli/npm/envio/src/FetchState.res -B 3 -A 3
</function_calls>Let me look at the tests or usage examples to understand if this is a real issue:
<function_calls>
#!/bin/bashCheck if there are tests for activateDeferredEventsAndHandlers
fd -e res codegenerator/cli/npm/envio/ | xargs rg -l "activateDeferredEventsAndHandlers" 2>/dev/null
</function_calls>Let me look at how partitions is updated to understand the pattern better:
<function_calls>
#!/bin/bashLook at how partitions is handled in the return
sed -n '1271,1450p' codegenerator/cli/npm/envio/src/FetchState.res | grep -n "partitions" -B 2 -A 2
</function_calls>Let me extract and examine the complete return statement:
<function_calls>
#!/bin/bashGet the complete return block of activateDeferredEventsAndHandlers
sed -n '1340,1380p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Let me search for the actual pattern of record construction in the function:
<function_calls>
#!/bin/bashLook for {...fetchState pattern or explicit field assignments
awk '/^let activateDeferredEventsAndHandlers/,/^}/' codegenerator/cli/npm/envio/src/FetchState.res | grep -n "partitions|normalSelection|contractConfigs" | tail -20
</function_calls>Let me try a different approach - check if the function creates a new record or modifies existing:
<function_calls>
#!/bin/bashLook at the complete function body more systematically
awk '/^let activateDeferredEventsAndHandlers = (/,/^}/' codegenerator/cli/npm/envio/src/FetchState.res | tail -50
</function_calls>Let me read a large block and search within it:
<function_calls>
#!/bin/bashRead a large block and find the return structure
sed -n '1330,1450p' codegenerator/cli/npm/envio/src/FetchState.res | cat -n
</function_calls>Now let me check what's actually in that return:
<function_calls>
#!/bin/bashGet lines 1380-1400 which should be near the end
sed -n '1380,1400p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Let me find where the else block that handles the deferred events actually returns:
<function_calls>
#!/bin/bashSearch for the return statement in this function more carefully
rg -n "^\s+})" codegenerator/cli/npm/envio/src/FetchState.res | head -20
</function_calls>Let me try a more direct Python approach to parse this:
<function_calls>
#!/bin/bashRead entire activateDeferredEventsAndHandlers function
python3 << 'EOF'
with open('codegenerator/cli/npm/envio/src/FetchState.res', 'r') as f:
lines = f.readlines()in_function = False
function_lines = []
brace_count = 0for i, line in enumerate(lines[1270:1450], start=1271): # start from line 1271
function_lines.append(f"{i:4d}: {line.rstrip()}")
if 'activateDeferredEventsAndHandlers' in line and '(' in line:
in_function = True
if in_function:
brace_count += line.count('{') - line.count('}')
if brace_count == 0 and in_function:
print('\n'.join(function_lines))
breakEOF
</function_calls>Let me search for what the function actually returns by looking at the entire implementation:
<function_calls>
#!/bin/bashGet lines around the return statement
sed -n '1360,1395p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Let me check if contractConfigs should be updated by seeing how it's used downstream:
<function_calls>
#!/bin/bashSearch to understand what uses contractConfigs after activation
rg -n ".contractConfigs|contractConfigs->" codegenerator/cli/npm/envio/src/FetchState.res -B 5 -A 3 | head -150
</function_calls>Let me look at the specific usage in context:
<function_calls>
#!/bin/bashLook at one specific usage of contractConfigs
sed -n '1000,1030p' codegenerator/cli/npm/envio/src/FetchState.res
</function_calls>Now let me create a comprehensive analysis by checking the initialization and usage:
<function_calls>
#!/bin/bashLook for where contractConfigs might be used to filter or process events
rg -n "contractConfigs->Js.Dict|contractConfigs->Map" codegenerator/cli/npm/envio/src/FetchState.res -B 3 -A 5
</function_calls>Let me search to see if there are any checks on contractConfigs after events are added:
<function_calls>
#!/bin/bashCheck what happens after partitions and normalSelection are updated
Look for any Map.get or Map.has on contractConfigs
rg -n "Map.get|Map.has|Dict.get" codegenerator/cli/npm/envio/src/FetchState.res | grep -i config
</function_calls>Let me check how the returned fetchState from activateDeferredEventsAndHandlers is used:
<function_calls>
#!/bin/bashLook at the callsite to see how result is used
rg -n "activateDeferredEventsAndHandlers" codegenerator/cli/npm/envio/src/ --type res -A 20 | head -80
</function_calls>Now let me understand the actual concern - check if contractConfigs is truly used for validation or filtering:
<function_calls>
#!/bin/bashCheck what the comment in the initial code suggests about contractConfigs
rg -n "contractConfigs" codegenerator/cli/npm/envio/src/FetchState.res | head -20
</function_calls>Let me see the complete activation function one more time and check the return values more carefully:
<function_calls>
#!/bin/bashLet's output the lines 1340-1380 which should show us the return
cat -n codegenerator/cli/npm/envio/src/FetchState.res | sed -n '1340,1380p'
</function_calls>Based on the analysis, let me verify one more critical thing - whether deferred events are actually excluded from initial eventConfigs:
<function_calls>
#!/bin/bashSearch for where deferred events are separated or identified
Look in ChainFetcher or similar files
fd -e res codegenerator/cli/npm/envio/src/ -exec rg -l "deferred" {} ; | head -10
</function_calls>Let me check the ChainFetcher specifically:
<function_calls>
#!/bin/bashSearch ChainFetcher files for deferred handling
fd ChainFetcher codegenerator/cli/npm/envio/src/ --type f
</function_calls>Let me look for files that might handle deferred events:
<function_calls>
#!/bin/bashList files in the src directory
ls -la codegenerator/cli/npm/envio/src/*.res | head -20
</function_calls>Let me search across all ReScript files for deferred event handling:
<function_calls>
#!/bin/bashSearch all res files for deferred
find codegenerator/cli/npm/envio/src -name "*.res" -exec rg -l "deferred" {} ;
</function_calls>Let me check if there's any code that would fail if a contract isn't in contractConfigs:
<function_calls>
#!/bin/bashSearch for any error handling or checks related to contractConfigs lookups
rg -n "contractConfigs" codegenerator/cli/npm/envio/src/FetchState.res -C 5 | grep -E "Map.|Option.|->|contract" -A 2 -B 2
</function_calls>Let me check if contractConfigs is actually important for the deferral logic:
<function_calls>
#!/bin/bashLook at the actual code to see how contractConfigs is used after being set
sed -n '1000,1050p' codegenerator/cli/npm/envio/src/FetchState.res | cat -n
</function_calls>Let me do a final check to see if missing contractConfigs entries actually cause failures:
<function_calls>
#!/bin/bashLook at the complete contractConfigs initialization to understand its purpose
sed -n '998,1020p' codegenerator/cli/npm/envio/src/FetchState.res | cat -n
</function_calls>Let me check the practical impact by seeing how contractConfigs is used in partition operations:
<function_calls>
#!/bin/bashCheck the complete make function to see the full picture
sed -n '986,1100p' codegenerator/cli/npm/envio/src/FetchState.res | cat -n
</function_calls>Based on all my analysis, I now have enough information to provide the rewritten review comment. The key findings are:
- The
activateDeferredEventsAndHandlersfunction does NOT updatecontractConfigsin its return statementcontractConfigsis built only once from the initialeventConfigspassed toFetchState.make- If deferred events are separate and not in the initial
eventConfigs, their contracts won't be incontractConfigs- The function successfully adds deferred events to
partitionsandnormalSelectionbut leavescontractConfigsunchangedHowever, I need to verify if this is actually an issue by checking what uses these fields afterward and whether contractConfigs needs to include deferred contracts.
contractConfigsis NOT updated when activating deferred events, but it may not need to be.When
activateDeferredEventsAndHandlersreturns (lines 1355-1375), it updatespartitionsandnormalSelectionbut leavescontractConfigsunchanged. SincecontractConfigsis built duringFetchState.makefrom the initialeventConfigsparameter, contracts from deferred events would only be included if they were part of that initial set.However,
contractConfigsappears to be used primarily during initialization for building the partition structure. The deferred events are added directly topartitionsandnormalSelectionviaArray.pushoperations, which doesn't depend oncontractConfigslookups. If contract configuration information for deferred events is needed later, it would need to be handled separately or included in the deferred event config itself.Consider:
- Verifying whether deferred event contracts need entries in
contractConfigsfor any downstream operations- If needed, updating
contractConfigswhen activating deferred events, or ensuring those contracts are included in the initialcontractConfigsconstruction
Introduction
This PR adds support for tracking events only during live indexing (when the chain is "ready"), skipping them during
historical backfill to improve indexing performance.
Problem / Issue
Some events (e.g., high-frequency Swap events) may only be relevant during live indexing and don't need historical data.
Currently, all configured events are fetched during the entire indexing process, including historical backfill via HyperSync, which can slow down indexing when historical data isn't needed.
Solution
Added a new optional
only_when_readyfield to event configuration that allows events to be tracked only after the chain completes historical synchronization.Key Changes:
Configuration Schema:
only_when_ready: Option<bool>toEventConfiginhuman_config.rsfalsefor backward compatibilityConfig Pipeline:
system_config.rs(Eventstruct)codegen_templates.rs(EventModstruct)onlyWhenReady: boolinInternal.eventConfigRuntime Filtering:
ChainFetcher.resduring event config aggregationonlyWhenReady: trueare filtered whentimestampCaughtUpToHeadOrEndblock === NoneTesting:
Mock.evmEventConfighelper with~onlyWhenReadyparameterOnlyWhenReady_test.rescovering:enableRawEventsmodeExample Usage:
References
Internal feature request to optimize indexing performance for live-only events.
Summary by CodeRabbit
New Features
Behavior
Tests
✏️ Tip: You can customize this high-level summary in your review settings.