feat(api): add pending transaction support in the eth subscription API#6941
feat(api): add pending transaction support in the eth subscription API#6941akaladarshi wants to merge 6 commits into
eth subscription API#6941Conversation
WalkthroughRefactors eth_subscribe to stream-based handlers (newHeads/logs/pendingTransactions), adds a broadcast->Stream adapter and tests, exposes an eth tx-hash helper, removes obsolete chain helpers, narrows dead-code allows, and adds end-to-end eth_subscribe tests plus changelog updates. ChangesETH Pubsub Stream-based Refactoring
Sequence Diagram(s)sequenceDiagram
participant Client
participant EthPubSub
participant spawn_newHeads
participant spawn_logs
participant spawn_pendingTransactions
participant pipe_stream_to_sink
participant SubscriptionSink
Client->>EthPubSub: eth_subscribe request
EthPubSub->>spawn_newHeads: spawn stream for newHeads
EthPubSub->>spawn_logs: spawn stream for logs
EthPubSub->>spawn_pendingTransactions: spawn stream for pendingTransactions
spawn_newHeads->>pipe_stream_to_sink: EthBlock items
spawn_logs->>pipe_stream_to_sink: filtered log items
spawn_pendingTransactions->>pipe_stream_to_sink: tx-hash items
pipe_stream_to_sink->>SubscriptionSink: send SubscriptionMessage
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
Comment |
c221f29 to
f4b122e
Compare
f4b122e to
6f51115
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/rpc/methods/eth/pubsub.rs`:
- Around line 126-128: The stream currently iterates only changes.applies so
reverted tipsets are ignored; update the flat_map over
subscription_stream(head_rx) to emit both applies and reverts (e.g., pair each
tipset with a boolean or enum indicating is_revert) instead of only
changes.applies, then adjust the subsequent filter_map closure that binds ts to
accept that (tipset, is_revert) and produce log removal events for reverts and
normal events for applies; target the subscription_stream/head_rx pipeline and
the closure capturing ts in pubsub.rs so reorg-driven log removals are emitted.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 023ea685-f51d-4356-8476-c6eea9c54e3d
📒 Files selected for processing (7)
src/message_pool/msgpool/events.rssrc/message_pool/msgpool/msg_pool.rssrc/rpc/methods/chain.rssrc/rpc/methods/eth.rssrc/rpc/methods/eth/pubsub.rssrc/utils/broadcast/mod.rssrc/utils/broadcast/tests.rs
💤 Files with no reviewable changes (2)
- src/message_pool/msgpool/msg_pool.rs
- src/rpc/methods/chain.rs
Codecov Report❌ Patch coverage is
Additional details and impacted files
... and 7 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
6f51115 to
709de17
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/tool/subcommands/api_cmd/stateful_tests.rs`:
- Around line 529-551: The current loops call next_subscription_payload(&mut
ws_stream, &subscription_id, Duration::from_secs(...)).await with a
per-notification timeout which resets on every unrelated event; change to use a
total deadline by recording let deadline = Instant::now() + TOTAL_DURATION (e.g.
120s for pending tx loop, 300s for logs loop) before the loop, then each
iteration compute remaining = deadline.saturating_duration_since(Instant::now())
and pass that remaining duration into next_subscription_payload; if
remaining.is_zero() or elapsed >= TOTAL_DURATION return an error (or bail) so
the test fails instead of hanging. Apply this same pattern to both the
pendingTransactions loop (using tx_hash, ws_stream, subscription_id) and the
logs loop (the one using 300s budget).
- Around line 182-188: The connect_ws helper currently forces the URL scheme to
"ws" and breaks secure endpoints; update the connect_ws function to derive the
websocket scheme from the rpc::Client's base URL (use "wss" when original scheme
is "https", "ws" when "http", and preserve existing "ws"/"wss" if present), call
url.set_scheme(...) with that derived scheme (handling set_scheme errors as
before), then set_path("/rpc/v1") and proceed to connect_async(url.as_str()) to
return the EthSubStream.
- Around line 596-606: The test currently treats the `eth_subscribe("logs")`
payload as an array; instead require a single object: check
`payload.is_object()` (not `is_array()`), deserialize into a single `LogView`
(not `Vec<LogView>`), remove the empty-array check, and update the matching
logic to compare the single `log`'s `transaction_hash` and `topics` against
`tx_hash` and `tx.topic` (the code around `payload`, `LogView`, `tx_hash`,
`tx.topic`, and the `matched` variable).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 73ae3705-5e85-4aec-9388-62e6528b206f
📒 Files selected for processing (10)
CHANGELOG.mdsrc/message_pool/msgpool/events.rssrc/message_pool/msgpool/msg_pool.rssrc/message_pool/msgpool/pending_store.rssrc/rpc/methods/chain.rssrc/rpc/methods/eth.rssrc/rpc/methods/eth/pubsub.rssrc/tool/subcommands/api_cmd/stateful_tests.rssrc/utils/broadcast/mod.rssrc/utils/broadcast/tests.rs
💤 Files with no reviewable changes (2)
- src/message_pool/msgpool/pending_store.rs
- src/rpc/methods/chain.rs
✅ Files skipped from review due to trivial changes (2)
- CHANGELOG.md
- src/message_pool/msgpool/msg_pool.rs
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CHANGELOG.md`:
- Line 46: Replace the PR reference
"[`#6941`](https://github.com/ChainSafe/forest/pull/6941)" in the changelog entry
that reads "The `eth_subscribe` `logs` subscription now emits one log object per
notification instead of one array of logs per tipset." with the issue reference
"`#6031`" (e.g. "[`#6031`](https://github.com/ChainSafe/forest/issues/6031)") so the
entry references the tracked issue rather than the PR, keeping the rest of the
sentence unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: d5adcb12-68bc-45d4-abd9-fb0add710a1e
📒 Files selected for processing (3)
CHANGELOG.mdsrc/rpc/methods/eth/pubsub.rssrc/tool/subcommands/api_cmd/stateful_tests.rs
|
|
||
| ### Fixed | ||
|
|
||
| - [#6941](https://github.com/ChainSafe/forest/pull/6941): The `eth_subscribe` `logs` subscription now emits one log object per notification instead of one array of logs per tipset. |
There was a problem hiding this comment.
Use the linked issue number instead of PR number in this changelog entry.
Line 46 should reference issue #6031 (the tracked objective) rather than PR #6941, to match the project’s changelog convention.
Suggested edit
-- [`#6941`](https://github.com/ChainSafe/forest/pull/6941): The `eth_subscribe` `logs` subscription now emits one log object per notification instead of one array of logs per tipset.
+- [`#6031`](https://github.com/ChainSafe/forest/issues/6031): The `eth_subscribe` `logs` subscription now emits one log object per notification instead of one array of logs per tipset.Based on learnings: “In CHANGELOG.md entries, when both an issue and a PR exist for a change, reference the issue number… Use PR numbers only if there is no corresponding issue.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CHANGELOG.md` at line 46, Replace the PR reference
"[`#6941`](https://github.com/ChainSafe/forest/pull/6941)" in the changelog entry
that reads "The `eth_subscribe` `logs` subscription now emits one log object per
notification instead of one array of logs per tipset." with the issue reference
"`#6031`" (e.g. "[`#6031`](https://github.com/ChainSafe/forest/issues/6031)") so the
entry references the tracked issue rather than the PR, keeping the rest of the
sentence unchanged.
| Ok(m) => m, | ||
| Err(e) => { | ||
| tracing::error!("Failed to serialize subscription message: {e:?}"); | ||
| break; |
There was a problem hiding this comment.
should we continue here instead of break if we fail to serialize next subscription message?
There was a problem hiding this comment.
I don't think so because we are only sending specific data (logs, hashes, tipset) to the stream, if json is not able to serialised then even if we continue it will fail again.
| let MpoolUpdate::Add(msg) = update else { | ||
| return None; | ||
| }; | ||
| eth_tx_hash_from_signed_message(&msg, eth_chain_id).ok() |
There was a problem hiding this comment.
instead of dropping failures silently we could log them
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/rpc/methods/eth.rs (1)
3106-3118: ⚡ Quick winAdd error context for better debugging.
The function propagates errors without adding context, which makes debugging harder when failures occur. Per coding guidelines, errors should be wrapped with
.context()to create helpful error chains.🔍 Suggested improvement
pub(crate) fn eth_tx_hash_from_signed_message( message: &SignedMessage, eth_chain_id: EthChainIdType, ) -> anyhow::Result<EthHash> { if message.is_delegated() { - let (_, tx) = eth_tx_from_signed_eth_message(message, eth_chain_id)?; - Ok(tx.eth_hash()?.into()) + let (_, tx) = eth_tx_from_signed_eth_message(message, eth_chain_id) + .context("failed to convert delegated message to eth tx")?; + Ok(tx.eth_hash() + .context("failed to compute eth hash from tx")?.into()) } else if message.is_secp256k1() { Ok(message.cid().into()) } else { Ok(message.message().cid().into()) } }As per coding guidelines: Use
anyhow::Result<T>for most operations and add context with.context()when errors occur.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/rpc/methods/eth.rs` around lines 3106 - 3118, The function eth_tx_hash_from_signed_message currently propagates errors raw; update it to wrap error-producing calls with context: when calling eth_tx_from_signed_eth_message(...) add .context("failed to build eth tx from signed eth message") and when calling tx.eth_hash()? add .context("failed to compute eth hash from tx") before converting to EthHash (ensure anyhow::Context is in scope); keep other branches unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/rpc/methods/eth.rs`:
- Around line 3106-3118: The function eth_tx_hash_from_signed_message currently
propagates errors raw; update it to wrap error-producing calls with context:
when calling eth_tx_from_signed_eth_message(...) add .context("failed to build
eth tx from signed eth message") and when calling tx.eth_hash()? add
.context("failed to compute eth hash from tx") before converting to EthHash
(ensure anyhow::Context is in scope); keep other branches unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 32e45654-46b9-45d7-b17b-f00c761fa172
📒 Files selected for processing (2)
CHANGELOG.mdsrc/rpc/methods/eth.rs
✅ Files skipped from review due to trivial changes (1)
- CHANGELOG.md
Summary of changes
Changes introduced in this pull request:
sinkReference issue to close (if applicable)
Closes #6031
Other information and links
Change checklist
Outside contributions
Summary by CodeRabbit
New Features
Refactor
Bug Fixes
Tests
Documentation