Skip to content

Fix incomplete event indexing for SEI based EVM chains#426

Open
lorrod wants to merge 2 commits intosubquery:mainfrom
Devs-Infrastructure:main
Open

Fix incomplete event indexing for SEI based EVM chains#426
lorrod wants to merge 2 commits intosubquery:mainfrom
Devs-Infrastructure:main

Conversation

@lorrod
Copy link
Copy Markdown

@lorrod lorrod commented Apr 9, 2026

This PR fixes incomplete event indexing for Cosmos/Sei-based EVM chains where synthetic logs are injected at the block level.

In these environments, some logs are emitted from transactions that are not returned via eth_getBlockByNumber, but are still discoverable through eth_getLogs due to block-level bloom filtering. These logs were previously skipped because the indexer only processed logs tied to visible transactions.

What was changed

  • Added additional handling in IndexerManager to process synthetic logs whose transactionHash is not present in the block’s transaction list.

  • Introduced a fallback mechanism that:

    • Collects all transaction hashes from the block
    • Iterates over all logs in the block
    • Indexes logs that belong to unknown (synthetic) transactions
  • Improved rewind logic in UnfinalizedBlocksService:

    • Replaced unsafe POI fallback with a direct call to getHeaderForHeight
    • Ensures consistent and safer rewind behavior when POI is not enabled

Motivation

Without this fix:

  • Some valid events on Cosmos/Sei EVM chains were silently ignored
  • This could lead to data inconsistency, missing indexed events, and incorrect downstream state

This change ensures compatibility with hybrid EVM implementations that inject logs outside standard Ethereum transaction visibility.

Fixes # (issue)


Type of change

  • Bug fix (non-breaking change which fixes an issue)

Checklist

  • I have tested locally
  • I have performed a self review of my changes
  • Updated any relevant documentation
  • Linked to any relevant issues
  • I have added tests relevant to my changes
  • Any dependent changes have been merged and published in downstream modules
  • My code is up to date with the base branch
  • I have updated relevant changelogs.

Summary by CodeRabbit

Bug Fixes

  • Fixed indexing of synthetic Cosmos/Sei logs that were previously missed during full block processing.
  • Improved accuracy of finalized block header retrieval by ensuring complete header data is fetched when using standard confirmation methods.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

📝 Walkthrough

Walkthrough

Two files in the indexer module are modified. The first adds logic to index synthetic Cosmos/Sei logs with transaction hashes not found in the block's transactions. The second changes how fallback headers are retrieved from manual construction to a service method call.

Changes

Cohort / File(s) Summary
Synthetic Log Indexing
packages/node/src/indexer/indexer.manager.ts
Added a supplemental pass over block logs in indexBlockData to index synthetic logs whose transaction hashes are absent from block transactions. Executes only in full-block branch after standard indexing.
Header Retrieval Refactor
packages/node/src/indexer/unfinalizedBlocks.service.ts
Modified getLastCorrectFinalizedBlock fallback to call blockchainService.getHeaderForHeight() instead of constructing a partial Header object with only blockHeight.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • subquery/subql-ethereum#417: Updates getLastCorrectFinalizedBlock to retrieve real headers via blockchainService.getHeaderForHeight() instead of constructing partial headers, mirroring changes in this PR.

Poem

🐰 Synthetic logs are now found with care,
While headers fetch from the service fair,
Both small but sure, the changes align,
In indexer paths where data does shine! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix incomplete event indexing for SEI based EVM chains' directly and clearly summarizes the main change: addressing incomplete event indexing for Cosmos/Sei-based EVM chains by handling synthetic logs.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/node/src/indexer/indexer.manager.ts (1)

132-137: Harden hash normalization to avoid runtime crashes on malformed log payloads.

Line 136 assumes log.transactionHash is always present. If an RPC response ever returns a null/undefined hash for an anomalous log, this path throws and aborts block indexing. Consider a defensive guard.

Proposed hardening
-      const txHashes = new Set(
-        block.transactions.map((tx) => tx.hash.toLowerCase()),
-      );
+      const txHashes = new Set(
+        block.transactions
+          .map((tx) => tx.hash?.toLowerCase())
+          .filter((h): h is string => Boolean(h)),
+      );
       for (const log of block.logs ?? []) {
-        if (!txHashes.has(log.transactionHash.toLowerCase())) {
+        const logTxHash = log.transactionHash?.toLowerCase();
+        if (!logTxHash || !txHashes.has(logTxHash)) {
           await this.indexEvent(log, dataSources, getVM);
         }
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/node/src/indexer/indexer.manager.ts` around lines 132 - 137, The
loop over block.logs assumes log.transactionHash is always defined and calls
.toLowerCase(), which can crash on null/undefined; in the indexer.manager.ts
where txHashes is created and the for-loop calls this.indexEvent(log,
dataSources, getVM), add a defensive guard that extracts transactionHash from
each log, ensures it's a string (e.g., typeof === 'string' &&
transactionHash.length > 0) before calling .toLowerCase(), and skip or otherwise
handle logs with missing/invalid transactionHash so they do not trigger the
.toLowerCase() call or abort block indexing; keep the existing behavior of
calling indexEvent only for logs whose normalized hash is not in the txHashes
Set.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/node/src/indexer/indexer.manager.ts`:
- Around line 132-137: The loop over block.logs assumes log.transactionHash is
always defined and calls .toLowerCase(), which can crash on null/undefined; in
the indexer.manager.ts where txHashes is created and the for-loop calls
this.indexEvent(log, dataSources, getVM), add a defensive guard that extracts
transactionHash from each log, ensures it's a string (e.g., typeof === 'string'
&& transactionHash.length > 0) before calling .toLowerCase(), and skip or
otherwise handle logs with missing/invalid transactionHash so they do not
trigger the .toLowerCase() call or abort block indexing; keep the existing
behavior of calling indexEvent only for logs whose normalized hash is not in the
txHashes Set.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5120baf2-bc38-48d2-9c9b-6a84146dc4b0

📥 Commits

Reviewing files that changed from the base of the PR and between fc1f641 and 215d6ed.

📒 Files selected for processing (2)
  • packages/node/src/indexer/indexer.manager.ts
  • packages/node/src/indexer/unfinalizedBlocks.service.ts

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.

1 participant