Skip to content

Conversation

@m-Peter
Copy link
Collaborator

@m-Peter m-Peter commented Nov 4, 2025

Closes: #906

Description

When eth_subscribe is given the transactionReceipts type, it creates a subscription that fires transaction receipts when transactions are included in blocks. Optional tx hashes can be passed in.


For contributor use:

  • Targeted PR against master branch
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Code follows the standards mentioned here.
  • Updated relevant documentation
  • Re-reviewed Files changed in the Github PR explorer
  • Added appropriate labels

Summary by CodeRabbit

Release Notes

  • New Features

    • New transaction receipts subscription enables streaming receipt data via WebSocket with optional filtering by transaction hashes; receipts delivered in batches
    • Subscription validation enforces maximum transaction hashes per subscription request
  • Tests

    • WebSocket integration tests added to validate transaction receipts streaming functionality and verify receipt accuracy against on-chain data

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 4, 2025

Walkthrough

This pull request implements the new TransactionReceipts subscription type for streaming transaction receipts. It adds a new subscription method to the streaming API, threads a receipts publisher through the bootstrap, ingestion, and API layers, publishes receipts in batches during event processing, validates transaction hash parameters, and includes integration tests.

Changes

Cohort / File(s) Summary
New TransactionReceipts subscription
api/stream.go
Adds TransactionReceipts subscription method with optional filtering by transaction hashes, validates max hash limit (200), marshals receipts to eth_getTransactionReceipt format, and publishes in batches. Adds receiptsPublisher field to StreamAPI and updates NewStreamAPI signature.
Bootstrap wiring
bootstrap/bootstrap.go
Adds Receipts publisher and storage fields to Publishers and Storages structs. Wires receiptsPublisher through StartEventIngestion and StartAPIServer initialization paths.
Ingestion engine updates
services/ingestion/engine.go, services/ingestion/engine_test.go
Adds receiptsPublisher field to Engine, updates NewEventIngestionEngine signature to accept receipts publisher, and emits receipts via publisher in processEvents before log processing. Test calls updated to pass receipts publisher parameter.
Models and error handling
models/errors/errors.go, models/events.go
Adds ErrExceedMaxTxHashes error for exceeding transaction hash limit. Updates NewCadenceEvents to populate BlockTimestamp from block's timestamp for each log.
Integration tests
tests/web3js/eth_streaming_test.js
Adds WebSocket-based integration tests for transactionReceipts subscription: subscribes to receipt stream (with and without hash filters), collects receipts, and validates against on-chain receipts for submitted transactions.

Sequence Diagram

sequenceDiagram
    participant EventSource as Event Source
    participant IngestionEngine as Ingestion Engine
    participant ReceiptsPublisher as Receipts Publisher
    participant StreamAPI as Stream API
    participant Subscriber as Subscriber/WebSocket

    EventSource->>IngestionEngine: processEvents(receipts, logs)
    IngestionEngine->>ReceiptsPublisher: publish([]*Receipt)
    ReceiptsPublisher->>StreamAPI: notify(receipts batch)
    
    Subscriber->>StreamAPI: TransactionReceipts(ctx, filter)
    StreamAPI->>StreamAPI: validate txHashes count
    StreamAPI->>ReceiptsPublisher: subscribe
    
    ReceiptsPublisher->>StreamAPI: batch notification
    StreamAPI->>StreamAPI: filter receipts by txHashes
    StreamAPI->>Subscriber: send batch in notification
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Receipt filtering logic in TransactionReceipts method (hash validation and containment checks)
  • Receipt marshaling to eth_getTransactionReceipt format and batch notification logic
  • Correctness of receiptsPublisher threading through bootstrap, ingestion, and API layers
  • Test coverage validation for both filtered and unfiltered subscription scenarios

Possibly related PRs

Suggested labels

Improvement, Testing

Suggested reviewers

  • zhangchiqing
  • janezpodhostnik
  • peterargue

Poem

🐰 A subscription born for receipts so fine,
Batches flowing through the publisher line,
Hashes filtered, timestamps aligned,
Transaction streams in perfect design,
Through ingestion and API, receipts unwind!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main change: implementing the transactionReceipts subscription API, which is the primary objective of the PR.
Linked Issues check ✅ Passed The PR successfully implements all requirements from issue #906: adds transactionReceipts subscription support to eth_subscribe, emits receipts when transactions are included in blocks, and supports optional transaction hash filtering.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the transactionReceipts subscription feature: API endpoint, event ingestion, publishing infrastructure, error handling, and integration tests are all necessary and relevant.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mpeter/implement-tx-receipt-subscriptions

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.

@m-Peter m-Peter changed the title Implement the new 'transactionReceipts' subscription API Implement the new transactionReceipts subscription API Nov 4, 2025
@m-Peter m-Peter force-pushed the mpeter/enable-fusaka-hard-fork branch 2 times, most recently from ee75cc9 to f9e2865 Compare November 7, 2025 11:34
Base automatically changed from mpeter/enable-fusaka-hard-fork to main November 7, 2025 16:11
@m-Peter m-Peter force-pushed the mpeter/implement-tx-receipt-subscriptions branch from 4925450 to 0bd1756 Compare November 12, 2025 11:05
Copy link
Contributor

@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.

Actionable comments posted: 0

🧹 Nitpick comments (1)
api/stream.go (1)

158-176: Consider precomputing hash lookups.

Right now each receipt does an O(len(txHashes)) slices.Contains. With the 200-hash cap that’s fine, but a tiny helper that builds a map[common.Hash]struct{} up front would make the loop constant time and future-proof us if the cap ever grows.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 404c556 and 0bd1756.

📒 Files selected for processing (7)
  • api/stream.go (6 hunks)
  • bootstrap/bootstrap.go (4 hunks)
  • models/errors/errors.go (1 hunks)
  • models/events.go (1 hunks)
  • services/ingestion/engine.go (4 hunks)
  • services/ingestion/engine_test.go (5 hunks)
  • tests/web3js/eth_streaming_test.js (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-06-19T11:36:25.478Z
Learnt from: m-Peter
Repo: onflow/flow-evm-gateway PR: 831
File: services/requester/batch_tx_pool.go:0-0
Timestamp: 2025-06-19T11:36:25.478Z
Learning: In Go, when copying maps that contain slices (like `map[gethCommon.Address][]pooledEvmTx`), perform deep copies by iterating over the map and copying each slice individually using `make()` and `copy()` to avoid shared references that could lead to race conditions and data corruption.

Applied to files:

  • api/stream.go
🧬 Code graph analysis (5)
tests/web3js/eth_streaming_test.js (2)
tests/web3js/config.js (2)
  • require (1-1)
  • web3 (2-2)
tests/web3js/helpers.js (4)
  • signedTx (66-66)
  • signedTx (79-79)
  • conf (2-2)
  • web3 (5-5)
services/ingestion/engine_test.go (2)
models/stream.go (1)
  • NewPublisher (14-19)
models/receipt.go (1)
  • Receipt (18-36)
api/stream.go (4)
models/stream.go (2)
  • Publisher (9-12)
  • Subscription (49-53)
models/receipt.go (1)
  • Receipt (18-36)
models/errors/errors.go (1)
  • ErrExceedMaxTxHashes (20-20)
eth/types/types.go (1)
  • MarshalReceipt (514-578)
services/ingestion/engine.go (4)
storage/index.go (1)
  • ReceiptIndexer (61-82)
models/stream.go (1)
  • Publisher (9-12)
models/receipt.go (1)
  • Receipt (18-36)
storage/pebble/receipts.go (1)
  • Receipts (20-22)
bootstrap/bootstrap.go (3)
storage/pebble/receipts.go (1)
  • Receipts (20-22)
models/stream.go (2)
  • Publisher (9-12)
  • NewPublisher (14-19)
models/receipt.go (1)
  • Receipt (18-36)
⏰ 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: Test
🔇 Additional comments (6)
models/events.go (1)

80-83: Nice alignment with upstream log schema.

Adding BlockTimestamp to each log keeps our receipts consistent with go-ethereum’s v1.16.x payloads that already ship blockTimestamp, so downstream consumers don’t need an extra block lookup. (chainrelease.info)

models/errors/errors.go (1)

19-21: Error surface matches the new subscription contract.

Exporting ErrExceedMaxTxHashes gives the API layer a precise failure mode when enforcing the hash cap.

services/ingestion/engine_test.go (1)

74-83: Tests updated for the extra publisher.

Thanks for threading the receipts publisher through the test harness—this guards the constructor signature change right away.

services/ingestion/engine.go (1)

208-214: Receipts published post-commit.

Emitting through receiptsPublisher only after indexEvents (and the batch commit) keeps subscribers from racing partially persisted data—good call.

tests/web3js/eth_streaming_test.js (1)

166-204: Coverage for hash-filtered subscriptions.

Great to see the second leg asserting that only the requested hashes surface—this will catch regressions in the filtering logic quickly.

bootstrap/bootstrap.go (1)

58-58: LGTM! Clean wiring of receipts publisher throughout the bootstrap.

The receipts support is correctly threaded through all layers:

  • Storage and publisher infrastructure added to core structs
  • Publisher initialized in the constructor
  • Properly wired to both ingestion engine (for publishing) and stream API (for subscriptions)

The implementation follows the established pattern for blocks, transactions, and logs, ensuring consistency across the codebase.

Also applies to: 65-65, 109-109, 204-204, 344-344

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement the new TransactionReceipts subscription type

2 participants