-
Notifications
You must be signed in to change notification settings - Fork 182
fix: use ethereum block in eth_subscribe newHeads
#6402
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
Conversation
WalkthroughReplace Filecoin tipset headers with Ethereum-style Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant PubSub as PubSub Handler
participant Chain as chain::new_heads
participant Conv as Block::from_filecoin_tipset
participant DB as Blockstore
participant Sender as Stream Sender
Client->>PubSub: eth_subscribe("newHeads")
PubSub->>Chain: chain::new_heads(ctx)
Chain-->>PubSub: (Subscriber, JoinHandle)
PubSub-->>Client: subscription_id
Note over Chain: On tipset Apply events
Chain->>Conv: from_filecoin_tipset(ctx.clone(), tipset, TxInfo::Full)
Conv->>DB: fetch state/txs
DB-->>Conv: state/tx data
Conv-->>Chain: Eth Block or error
alt Conversion Success
Chain->>Sender: send ApiHeaders(Block)
Sender-->>Client: eth_subscription notification
else Conversion Error
Chain->>Chain: log error and continue
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
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
Comment |
d6912e8 to
6eabb3d
Compare
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)
src/rpc/methods/eth.rs (2)
557-630: Consider extracting shared transaction processing logic.This new method duplicates significant logic from
block_from_filecoin_tipset(lines 1601-1627), particularly the message iteration andApiEthTxconstruction. While the non-caching behavior is intentional for theeth_subscribeuse case, consider extracting the common transaction-building logic into a helper function to reduce duplication.♻️ Suggested helper extraction
// Helper to build transactions from messages and receipts fn build_eth_transactions<DB: Blockstore>( msgs_and_receipts: &[(ChainMessage, Receipt)], state_tree: &StateTree<DB>, eth_chain_id: EthChainIdType, block_hash: &EthHash, block_number: &EthUint64, ) -> Result<Vec<ApiEthTx>> { let mut transactions = Vec::new(); for (i, (msg, receipt)) in msgs_and_receipts.iter().enumerate() { let ti = EthUint64(i as u64); let smsg = match msg { ChainMessage::Signed(msg) => msg.clone(), ChainMessage::Unsigned(msg) => { let sig = Signature::new_bls(vec![]); SignedMessage::new_unchecked(msg.clone(), sig) } }; let mut tx = new_eth_tx_from_signed_message(&smsg, state_tree, eth_chain_id)?; tx.block_hash = block_hash.clone(); tx.block_number = block_number.clone(); tx.transaction_index = ti; transactions.push(tx); } Ok(transactions) }
1678-1683: Consider implementingFrom<bool>forTxInfoto reduce repetition.The bool-to-enum conversion pattern is repeated in three handlers. A
Fromimplementation would make this more concise.♻️ Optional: Add From implementation
impl From<bool> for TxInfo { fn from(full: bool) -> Self { if full { TxInfo::Full } else { TxInfo::Hash } } }Then call sites become:
let block = block_from_filecoin_tipset(ctx, ts, full_tx_info.into()).await?;
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
CHANGELOG.mdsrc/rpc/methods/chain.rssrc/rpc/methods/eth.rssrc/rpc/methods/eth/pubsub.rssrc/rpc/methods/eth/types.rs
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: LesnyRumcajs
Repo: ChainSafe/forest PR: 5907
File: src/rpc/methods/state.rs:523-570
Timestamp: 2025-08-06T15:44:33.467Z
Learning: LesnyRumcajs prefers to rely on BufWriter's Drop implementation for automatic flushing rather than explicit flush() calls in Forest codebase.
📚 Learning: 2026-01-05T12:54:40.850Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/cron_state.rs:8-8
Timestamp: 2026-01-05T12:54:40.850Z
Learning: In Rust code reviews, do not derive Eq for a struct if any field does not implement Eq (e.g., types from external dependencies). If a type like CronStateLotusJson includes fields wrapping external dependencies that lack Eq, derive PartialEq (or implement PartialEq manually) but avoid deriving Eq. This ensures comparisons compile and reflect actual equivalence semantics. When needed, consider implementing custom PartialEq (and possibly Eq) only after ensuring all fields (or wrappers) implement Eq, or keep PartialEq-only if full equality semantics cannot be expressed.
Applied to files:
src/rpc/methods/eth/types.rssrc/rpc/methods/eth/pubsub.rssrc/rpc/methods/chain.rssrc/rpc/methods/eth.rs
📚 Learning: 2026-01-05T12:56:13.802Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/evm_state.rs:41-44
Timestamp: 2026-01-05T12:56:13.802Z
Learning: In Rust codebases (e.g., Forest), do not add #[cfg(test)] to functions already annotated with #[test]. The #[test] attribute ensures the function is compiled only for tests, so a separate #[cfg(test)] is redundant and can be removed if present. Apply this check to all Rust files that contain #[test] functions.
Applied to files:
src/rpc/methods/eth/types.rssrc/rpc/methods/eth/pubsub.rssrc/rpc/methods/chain.rssrc/rpc/methods/eth.rs
📚 Learning: 2025-10-16T11:05:13.586Z
Learnt from: elmattic
Repo: ChainSafe/forest PR: 6166
File: src/auth/mod.rs:127-150
Timestamp: 2025-10-16T11:05:13.586Z
Learning: In Rust 2024, `std::env::set_var` and `std::env::remove_var` are unsafe functions. They require `unsafe` blocks because they are only safe in single-threaded programs (Windows is an exception). When these functions are used in tests, ensure proper serialization with `#[serial]` or similar mechanisms.
Applied to files:
src/rpc/methods/chain.rs
📚 Learning: 2025-08-08T12:11:55.266Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5867
File: src/ipld/util.rs:461-487
Timestamp: 2025-08-08T12:11:55.266Z
Learning: Forest (src/ipld/util.rs, Rust): In UnorderedChainStream::poll_next, dropping `extract_sender` (when no more tipsets and the extract queue is empty) is the intended shutdown signal for workers. Any subsequent attempt to enqueue work after this drop is a logic error and should be treated as an error; do not change `send()` to ignore a missing sender.
Applied to files:
src/rpc/methods/chain.rs
🧬 Code graph analysis (3)
src/rpc/methods/eth/pubsub.rs (1)
src/rpc/methods/chain.rs (19)
handle(173-197)handle(240-255)handle(269-284)handle(299-313)handle(328-360)handle(373-381)handle(394-405)handle(418-530)handle(543-567)handle(580-587)handle(600-643)handle(656-680)handle(696-705)handle(720-725)handle(740-778)handle(793-809)chain(463-463)chain(501-501)new_heads(81-113)
src/rpc/methods/chain.rs (1)
src/rpc/methods/eth.rs (5)
eth_logs_with_filter(1537-1561)from_filecoin_tipset(561-630)new(544-556)new(783-788)e(2069-2069)
src/rpc/methods/eth.rs (3)
src/shim/state_tree.rs (1)
new_from_root(168-188)src/shim/crypto.rs (1)
new_bls(78-83)src/message/signed_message.rs (1)
new_unchecked(35-37)
⏰ 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). (8)
- GitHub Check: cargo-publish-dry-run
- GitHub Check: Build MacOS
- GitHub Check: Build Ubuntu
- GitHub Check: Build forest binaries on Linux AMD64
- GitHub Check: All lint checks
- GitHub Check: tests-release
- GitHub Check: Coverage
- GitHub Check: rubocop
🔇 Additional comments (9)
CHANGELOG.md (1)
59-60: Changelog entry looks accurate and appropriately scoped.src/rpc/methods/eth/types.rs (1)
424-428: Confirm schema/doc generation doesn’t requireJsonSchemafor subscription payload types. If subscriptions are included in OpenRPC/schemars output,ApiHeadersmay need#[derive(JsonSchema)](and any necessaryschemars(...)attrs) to avoid doc/test breakage.src/rpc/methods/eth/pubsub.rs (1)
121-130: Call-site update matches the newchain::new_heads(Ctx<DB>)signature.src/rpc/methods/chain.rs (1)
81-113: Double-checkTxInfo::FullfornewHeads(payload size + performance). If consumers only expect header-ish fields or tx hashes, consider emittingTxInfo::Hashinstead to reduce per-head execution/serialization cost.Proposed adjustment (if compatible with Lotus/tooling expectations)
- match EthBlock::from_filecoin_tipset(data.clone(), Arc::new(ts), TxInfo::Full) + match EthBlock::from_filecoin_tipset(data.clone(), Arc::new(ts), TxInfo::Hash) .await {src/rpc/methods/eth.rs (5)
534-541: LGTM!Clean enum definition with appropriate derives and clear documentation. The
Copytrait is correctly derived for this simple two-variant enum.
1578-1582: LGTM!Good refactor from boolean to enum parameter - improves code readability at call sites.
1648-1653: LGTM!Correct transformation from boolean condition to enum comparison.
1708-1713: LGTM!Consistent with the conversion pattern used in
EthGetBlockByHash.
1735-1740: LGTM!Consistent implementation across all V2 handlers.
Codecov Report❌ Patch coverage is
Additional details and impacted files
... and 9 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
cc35ba3 to
220ec49
Compare
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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/rpc/methods/chain.rs (1)
80-110: Handle broadcast lag explicitly in the subscription loop.The pattern
while let Ok(v) = subscriber.recv().awaitsilently exits when the broadcast channel returnsRecvError::Lagged, which occurs when this task falls behind the event queue. Since each message now requires anawaited block conversion, lag is more likely under load. Other subscribers in the codebase (state_manager, message_pool, eth/pubsub, rpc/channel) explicitly handleRecvError::Laggedand continue; this function should do the same.Proposed fix
pub(crate) fn new_heads<DB: Blockstore + Send + Sync + 'static>( data: Ctx<DB>, ) -> (Subscriber<ApiHeaders>, JoinHandle<()>) { let (sender, receiver) = broadcast::channel(HEAD_CHANNEL_CAPACITY); let mut subscriber = data.chain_store().publisher().subscribe(); let handle = tokio::spawn(async move { - while let Ok(v) = subscriber.recv().await { + loop { + let v = match subscriber.recv().await { + Ok(v) => v, + Err(tokio::sync::broadcast::error::RecvError::Lagged(n)) => { + tracing::warn!("new_heads lagged; skipped {n} head-change events"); + continue; + } + Err(tokio::sync::broadcast::error::RecvError::Closed) => break, + }; let headers = match v { HeadChange::Apply(ts) => { // Convert the tipset to an Ethereum block with full transaction info // Note: In Filecoin's Eth RPC, a tipset maps to a single Ethereum block match EthBlock::from_filecoin_tipset(data.clone(), ts, TxInfo::Full).await { Ok(block) => ApiHeaders(block), Err(e) => { tracing::error!("Failed to convert tipset to eth block: {}", e); continue; } } } }; if let Err(e) = sender.send(headers) { tracing::error!("Failed to send headers: {}", e); break; } } }); (receiver, handle) }
🧹 Nitpick comments (2)
src/rpc/methods/chain.rs (1)
90-100: ReconsiderTxInfo::FullfornewHeads(payload size + execution cost).
UsingTxInfo::Fullhere likely forces tipset execution and builds full transaction objects for every head update. If consumers only need a “header-like” newHeads (common in Ethereum tooling), preferTxInfo::Hash(or even a header-only type) and let clients calleth_getBlockByHashwhen they need full txs.src/rpc/methods/eth.rs (1)
564-645: Avoid building full transactions whenTxInfo::Hashis requested (especially on cache miss).
Right now,TxInfo::Hashstill constructsTransactions::Full(including state-tree lookups) and only then downgrades to hashes. Ifeth_getBlockBy*is called withfullTxInfo=false, this is avoidable overhead. Consider branching earlier and building only hashes (or caching a lightweight representation) whenTxInfo::Hash.Sketch of the refactor direction
- let mut full_transactions = vec![]; + let mut full_transactions = vec![]; + let mut tx_hashes = vec![]; let mut gas_used = 0; for (i, (msg, receipt)) in msgs_and_receipts.iter().enumerate() { let ti = EthUint64(i as u64); gas_used += receipt.gas_used(); let smsg = match msg { ChainMessage::Signed(msg) => msg.clone(), ChainMessage::Unsigned(msg) => { let sig = Signature::new_bls(vec![]); SignedMessage::new_unchecked(msg.clone(), sig) } }; - let mut tx = new_eth_tx_from_signed_message( - &smsg, - &state_tree, - ctx.chain_config().eth_chain_id, - )?; - tx.block_hash = block_hash.clone(); - tx.block_number = block_number.clone(); - tx.transaction_index = ti; - full_transactions.push(tx); + if tx_info == TxInfo::Full { + let mut tx = new_eth_tx_from_signed_message( + &smsg, + &state_tree, + ctx.chain_config().eth_chain_id, + )?; + tx.block_hash = block_hash.clone(); + tx.block_number = block_number.clone(); + tx.transaction_index = ti; + full_transactions.push(tx); + } else { + // Compute just the hash (delegated eth tx hash vs CID-based for native msgs), + // ideally via a shared helper so it matches other endpoints. + tx_hashes.push(/* ... */); + } } let b = Block { ... - transactions: Transactions::Full(full_transactions), + transactions: if tx_info == TxInfo::Full { + Transactions::Full(full_transactions) + } else { + Transactions::Hash(tx_hashes) + }, ... };
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
CHANGELOG.mdsrc/rpc/methods/chain.rssrc/rpc/methods/eth.rssrc/rpc/methods/eth/pubsub.rssrc/rpc/methods/eth/types.rs
🚧 Files skipped from review as they are similar to previous changes (2)
- src/rpc/methods/eth/pubsub.rs
- CHANGELOG.md
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs: Useanyhow::Result<T>for most operations and add context with.context()when operations fail
Usetokio::task::spawn_blockingfor CPU-intensive work such as VM execution and cryptography operations
Use.get()instead of indexing with[index]for safe element access
Do not useunwrap()in production code; use?orexpect()with descriptive messages instead
Do not usedbg!macro in non-test Rust code
Do not usetodo!macro in non-test Rust code
Usestrumcrate for enum string conversions
Usederive_morecrate for common trait implementations
Document all public functions and structs with doc comments
Use#[cfg(test)]or#[cfg(feature = "doctest-private")]for test-only code
Use channel-based communication (flume, tokio channels) between async tasks
Use consistent formatting followingcargo fmtstandards
Ensure code passescargo clippy --all-targets --no-deps -- --deny=warningslinter checks
Files:
src/rpc/methods/chain.rssrc/rpc/methods/eth/types.rssrc/rpc/methods/eth.rs
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: ChainSafe/forest PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T10:25:49.996Z
Learning: Publisher/Subscriber Pattern: Broadcast `HeadChange` events to multiple subscribers (RPC, message pool, chain indexer)
Learnt from: LesnyRumcajs
Repo: ChainSafe/forest PR: 5907
File: src/rpc/methods/state.rs:523-570
Timestamp: 2025-08-06T15:44:33.467Z
Learning: LesnyRumcajs prefers to rely on BufWriter's Drop implementation for automatic flushing rather than explicit flush() calls in Forest codebase.
📚 Learning: 2026-01-14T10:25:49.996Z
Learnt from: CR
Repo: ChainSafe/forest PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T10:25:49.996Z
Learning: Publisher/Subscriber Pattern: Broadcast `HeadChange` events to multiple subscribers (RPC, message pool, chain indexer)
Applied to files:
src/rpc/methods/chain.rs
📚 Learning: 2025-10-17T14:24:47.046Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6167
File: src/tool/subcommands/state_compute_cmd.rs:89-91
Timestamp: 2025-10-17T14:24:47.046Z
Learning: In `src/tool/subcommands/state_compute_cmd.rs`, when using `ReadOpsTrackingStore` to generate minimal snapshots, `HEAD_KEY` should be written to `db.tracker` (not `db` itself) before calling `export_forest_car()`, because the export reads from the tracker MemoryDB which accumulates only the accessed data during computation.
Applied to files:
src/rpc/methods/chain.rs
📚 Learning: 2026-01-05T12:54:40.850Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/cron_state.rs:8-8
Timestamp: 2026-01-05T12:54:40.850Z
Learning: In Rust code reviews, do not derive Eq for a struct if any field does not implement Eq (e.g., types from external dependencies). If a type like CronStateLotusJson includes fields wrapping external dependencies that lack Eq, derive PartialEq (or implement PartialEq manually) but avoid deriving Eq. This ensures comparisons compile and reflect actual equivalence semantics. When needed, consider implementing custom PartialEq (and possibly Eq) only after ensuring all fields (or wrappers) implement Eq, or keep PartialEq-only if full equality semantics cannot be expressed.
Applied to files:
src/rpc/methods/chain.rssrc/rpc/methods/eth/types.rssrc/rpc/methods/eth.rs
📚 Learning: 2025-08-08T12:11:55.266Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5867
File: src/ipld/util.rs:461-487
Timestamp: 2025-08-08T12:11:55.266Z
Learning: Forest (src/ipld/util.rs, Rust): In UnorderedChainStream::poll_next, dropping `extract_sender` (when no more tipsets and the extract queue is empty) is the intended shutdown signal for workers. Any subsequent attempt to enqueue work after this drop is a logic error and should be treated as an error; do not change `send()` to ignore a missing sender.
Applied to files:
src/rpc/methods/chain.rs
📚 Learning: 2026-01-05T12:56:13.802Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/evm_state.rs:41-44
Timestamp: 2026-01-05T12:56:13.802Z
Learning: In Rust codebases (e.g., Forest), do not add #[cfg(test)] to functions already annotated with #[test]. The #[test] attribute ensures the function is compiled only for tests, so a separate #[cfg(test)] is redundant and can be removed if present. Apply this check to all Rust files that contain #[test] functions.
Applied to files:
src/rpc/methods/chain.rssrc/rpc/methods/eth/types.rssrc/rpc/methods/eth.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). (3)
- GitHub Check: Coverage
- GitHub Check: tests-release
- GitHub Check: Build forest binaries on Linux AMD64
🔇 Additional comments (4)
src/rpc/methods/eth/types.rs (1)
424-428: ConfirmApiHeadersserialization matches “newHeads” expectations (object shape, no accidental wrapping).
ApiHeadersnow wrapsBlock, which is the intended API change, but the#[serde(with = "crate::lotus_json")]on the tuple field makes it easy to accidentally change the emitted JSON shape (especially if lotus_json uses a different representation than standard serde forBlock). Please sanity-check with an actual WSeth_subscribe("newHeads")payload thatresultis a single Ethereum-style object (and that field casing/hex formatting matches Lotus/tooling expectations).src/rpc/methods/eth.rs (3)
534-547:TxInfolooks fine; keep the enum as the public “detail knob”.
This makes call sites clearer than threading a boolean and leaves room for future variants (e.g., HeaderOnly).
590-632: Spec-sensitive: please confirm ordering + state used for address resolution matches Lotus.
from_filecoin_tipsetusesmessages_for_tipsetorder and resolves addresses against a singleStateTreebuilt from the post-tipsetstate_root. If Lotus uses different ordering (BLS/secp grouping) or a different state view for address lookups, hashes/tx objects could diverge from expected tooling behavior.
1608-1666: Call sites updated cleanly to the new API.
Switchingfull_tx_info: booltoTxInfokeeps theRpcMethodsignatures stable while lettingBlock::from_filecoin_tipsetown the behavior.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
220ec49 to
8d05dcf
Compare
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: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/rpc/methods/chain.rs (1)
80-110: Potential perf/compat risk:newHeadshardcodes full transactions (TxInfo::Full), while on-demand RPC methods let clients choose.The subscription always calls
EthBlock::from_filecoin_tipset(..., TxInfo::Full)(line 93), building full transaction objects on every head notification. Meanwhile,eth_getBlockByNumberandeth_getBlockByHashtake a boolean parameter to let clients choose betweenTxInfo::FullandTxInfo::Hash.Standard Ethereum
eth_subscribe("newHeads")typically returns lightweight block headers without full transaction objects. The hardcodedFullvariant likely incurs unnecessary VM execution and serialization overhead per block.Recommendation: Either (1) make transaction detail configurable for
newHeadssubscriptions to match RPC method behavior, or (2) default toTxInfo::Hashand document whyFullis necessary if there's a compatibility reason specific to Filecoin/Lotus.src/rpc/methods/eth/pubsub.rs (1)
121-130: By-valuectxis correct, but add lag logging for observability.The switch to
chain::new_heads(ctx)(line 126) matches the new signature and is appropriate. However,handle_subscriptionsilently ignoresRecvError::Lagged(_)(lines 174-175), which dropsnewHeadsnotifications without visibility into the issue. Given thatEthBlock::from_filecoin_tipsetis expensive andHEAD_CHANNEL_CAPACITYis small (10), lag is plausible.Other parts of the codebase log similar lag events (e.g., message pool, state manager). Add at least a warning log when lag occurs to make this diagnosable:
Suggested fix
- Err(RecvError::Lagged(_)) => { - } + Err(RecvError::Lagged(n)) => { + tracing::warn!("Subscription lagged; skipped {n} messages"); + continue; + }
🤖 Fix all issues with AI agents
In `@src/rpc/methods/eth/types.rs`:
- Around line 424-427: Add a doc comment to the public newtype struct ApiHeaders
explaining its purpose and serialization behavior; specifically, above the
declaration of ApiHeaders (the #[derive(...)] pub struct ApiHeaders(#[serde(with
= "crate::lotus_json")] pub Block);) add a brief docstring describing that this
newtype wrapper emits a single Ethereum-style block object via the lotus_json
serializer (and mention the lotus_json_with_self! macro if helpful) to satisfy
the coding guideline for public structs.
🧹 Nitpick comments (1)
src/rpc/methods/eth.rs (1)
564-645: Consider avoiding “build full txs then downconvert” whentx_info == TxInfo::Hash.Right now
from_filecoin_tipsetalways buildsTransactions::Full(...)(Lines 594-616, 630-631) and only at the end converts to hashes (Lines 637-642). IfTxInfo::Hashbecomes common (e.g., fornewHeads), this will be unnecessary CPU/memory churn.A follow-up optimization could build hashes directly (and optionally use a cache keyed by
(tipset_cid, TxInfo)if you want to cache both forms).
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
CHANGELOG.mdsrc/rpc/methods/chain.rssrc/rpc/methods/eth.rssrc/rpc/methods/eth/pubsub.rssrc/rpc/methods/eth/types.rs
🚧 Files skipped from review as they are similar to previous changes (1)
- CHANGELOG.md
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs: Useanyhow::Result<T>for most operations and add context with.context()when operations fail
Usetokio::task::spawn_blockingfor CPU-intensive work such as VM execution and cryptography operations
Use.get()instead of indexing with[index]for safe element access
Do not useunwrap()in production code; use?orexpect()with descriptive messages instead
Do not usedbg!macro in non-test Rust code
Do not usetodo!macro in non-test Rust code
Usestrumcrate for enum string conversions
Usederive_morecrate for common trait implementations
Document all public functions and structs with doc comments
Use#[cfg(test)]or#[cfg(feature = "doctest-private")]for test-only code
Use channel-based communication (flume, tokio channels) between async tasks
Use consistent formatting followingcargo fmtstandards
Ensure code passescargo clippy --all-targets --no-deps -- --deny=warningslinter checks
Files:
src/rpc/methods/chain.rssrc/rpc/methods/eth/types.rssrc/rpc/methods/eth.rssrc/rpc/methods/eth/pubsub.rs
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: ChainSafe/forest PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T10:25:49.996Z
Learning: Publisher/Subscriber Pattern: Broadcast `HeadChange` events to multiple subscribers (RPC, message pool, chain indexer)
Learnt from: LesnyRumcajs
Repo: ChainSafe/forest PR: 5907
File: src/rpc/methods/state.rs:523-570
Timestamp: 2025-08-06T15:44:33.467Z
Learning: LesnyRumcajs prefers to rely on BufWriter's Drop implementation for automatic flushing rather than explicit flush() calls in Forest codebase.
📚 Learning: 2026-01-14T10:25:49.996Z
Learnt from: CR
Repo: ChainSafe/forest PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T10:25:49.996Z
Learning: Publisher/Subscriber Pattern: Broadcast `HeadChange` events to multiple subscribers (RPC, message pool, chain indexer)
Applied to files:
src/rpc/methods/chain.rssrc/rpc/methods/eth/pubsub.rs
📚 Learning: 2025-10-17T14:24:47.046Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6167
File: src/tool/subcommands/state_compute_cmd.rs:89-91
Timestamp: 2025-10-17T14:24:47.046Z
Learning: In `src/tool/subcommands/state_compute_cmd.rs`, when using `ReadOpsTrackingStore` to generate minimal snapshots, `HEAD_KEY` should be written to `db.tracker` (not `db` itself) before calling `export_forest_car()`, because the export reads from the tracker MemoryDB which accumulates only the accessed data during computation.
Applied to files:
src/rpc/methods/chain.rssrc/rpc/methods/eth/pubsub.rs
📚 Learning: 2025-08-08T12:11:55.266Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5867
File: src/ipld/util.rs:461-487
Timestamp: 2025-08-08T12:11:55.266Z
Learning: Forest (src/ipld/util.rs, Rust): In UnorderedChainStream::poll_next, dropping `extract_sender` (when no more tipsets and the extract queue is empty) is the intended shutdown signal for workers. Any subsequent attempt to enqueue work after this drop is a logic error and should be treated as an error; do not change `send()` to ignore a missing sender.
Applied to files:
src/rpc/methods/chain.rs
📚 Learning: 2026-01-05T12:54:40.850Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/cron_state.rs:8-8
Timestamp: 2026-01-05T12:54:40.850Z
Learning: In Rust code reviews, do not derive Eq for a struct if any field does not implement Eq (e.g., types from external dependencies). If a type like CronStateLotusJson includes fields wrapping external dependencies that lack Eq, derive PartialEq (or implement PartialEq manually) but avoid deriving Eq. This ensures comparisons compile and reflect actual equivalence semantics. When needed, consider implementing custom PartialEq (and possibly Eq) only after ensuring all fields (or wrappers) implement Eq, or keep PartialEq-only if full equality semantics cannot be expressed.
Applied to files:
src/rpc/methods/chain.rssrc/rpc/methods/eth/types.rssrc/rpc/methods/eth.rssrc/rpc/methods/eth/pubsub.rs
📚 Learning: 2026-01-05T12:56:13.802Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/evm_state.rs:41-44
Timestamp: 2026-01-05T12:56:13.802Z
Learning: In Rust codebases (e.g., Forest), do not add #[cfg(test)] to functions already annotated with #[test]. The #[test] attribute ensures the function is compiled only for tests, so a separate #[cfg(test)] is redundant and can be removed if present. Apply this check to all Rust files that contain #[test] functions.
Applied to files:
src/rpc/methods/chain.rssrc/rpc/methods/eth/types.rssrc/rpc/methods/eth.rssrc/rpc/methods/eth/pubsub.rs
🧬 Code graph analysis (2)
src/rpc/methods/chain.rs (1)
src/rpc/methods/eth.rs (2)
from_filecoin_tipset(567-645)e(1992-1992)
src/rpc/methods/eth/pubsub.rs (1)
src/rpc/methods/chain.rs (19)
handle(170-194)handle(237-252)handle(266-281)handle(296-310)handle(325-357)handle(370-378)handle(391-402)handle(415-527)handle(540-564)handle(577-584)handle(597-640)handle(653-677)handle(693-702)handle(717-722)handle(737-775)handle(790-806)chain(460-460)chain(498-498)new_heads(80-110)
⏰ 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). (9)
- GitHub Check: Coverage
- GitHub Check: Check
- GitHub Check: Build Ubuntu
- GitHub Check: Build MacOS
- GitHub Check: cargo-publish-dry-run
- GitHub Check: tests-release
- GitHub Check: All lint checks
- GitHub Check: rubocop
- GitHub Check: Build forest binaries on Linux AMD64
🔇 Additional comments (2)
src/rpc/methods/eth.rs (2)
534-547: TxInfo +From<bool>is a nice API cleanup.Clearer intent at call sites and avoids repeating boolean-to-meaning mapping logic.
1604-1666: Call sites updated cleanly to the new constructor and TxInfo mapping.The switch to
Block::from_filecoin_tipset(..., full_tx_info.into()).awaitis straightforward and keeps error mapping consistent.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
8d05dcf to
e58d247
Compare
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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/rpc/methods/chain.rs (1)
80-109: ChangeTxInfo::FulltoTxInfo::Hashin thenewHeadssubscription and improve structured logging.The
newHeadssubscription currently includes full transaction objects viaTxInfo::Full, which increases payload size without functional benefit. In contrast,eth_getBlockByNumbermethods expose afullTxInfoparameter allowing callers to choose. ThenewHeadssubscription should default toTxInfo::Hash, consistent with standard Ethereum RPC practice (geth, Infura, etc.) where subscriptions typically return block headers only, not transaction bodies. This reduces bandwidth and serialization overhead without sacrificing functionality.Additionally, structured logging should include the tipset key for better debuggability, following the pattern already used in the
logsfunction (line 139).Proposed diff (Hash default + structured logging)
pub(crate) fn new_heads<DB: Blockstore + Send + Sync + 'static>( data: Ctx<DB>, ) -> (Subscriber<ApiHeaders>, JoinHandle<()>) { @@ while let Ok(v) = subscriber.recv().await { let headers = match v { HeadChange::Apply(ts) => { + let ts_key = ts.key().clone(); // Convert the tipset to an Ethereum block with full transaction info // Note: In Filecoin's Eth RPC, a tipset maps to a single Ethereum block - match EthBlock::from_filecoin_tipset(data.clone(), ts, TxInfo::Full).await { + match EthBlock::from_filecoin_tipset(data.clone(), ts, TxInfo::Hash).await { Ok(block) => ApiHeaders(block), Err(e) => { - tracing::error!("Failed to convert tipset to eth block: {}", e); + tracing::error!(error=?e, tipset_key=%ts_key, "Failed to convert tipset to eth block"); continue; } } } };
♻️ Duplicate comments (1)
src/rpc/methods/eth/types.rs (1)
424-427: Add doc comment for publicApiHeaders(required by guidelines). As per coding guidelines, public structs should have doc comments.Proposed diff
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)] +/// Newtype wrapper for `eth_subscribe` payloads. +/// +/// Serialized via `crate::lotus_json` to emit an Ethereum-style `Block` object +/// (instead of Filecoin tipset headers). pub struct ApiHeaders(#[serde(with = "crate::lotus_json")] pub Block);
🧹 Nitpick comments (1)
src/rpc/methods/eth.rs (1)
564-645: Avoid building full transactions whentx_info == TxInfo::Hash. Right nowTxInfo::Hashstill constructs fullApiEthTxobjects, then converts to hashes; this is likely avoidable overhead. Also consider adding.context(...)around tipset execution/conversion steps for better error traces.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
CHANGELOG.mdsrc/rpc/methods/chain.rssrc/rpc/methods/eth.rssrc/rpc/methods/eth/pubsub.rssrc/rpc/methods/eth/types.rs
🚧 Files skipped from review as they are similar to previous changes (2)
- CHANGELOG.md
- src/rpc/methods/eth/pubsub.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs: Useanyhow::Result<T>for most operations and add context with.context()when operations fail
Usetokio::task::spawn_blockingfor CPU-intensive work such as VM execution and cryptography operations
Use.get()instead of indexing with[index]for safe element access
Do not useunwrap()in production code; use?orexpect()with descriptive messages instead
Do not usedbg!macro in non-test Rust code
Do not usetodo!macro in non-test Rust code
Usestrumcrate for enum string conversions
Usederive_morecrate for common trait implementations
Document all public functions and structs with doc comments
Use#[cfg(test)]or#[cfg(feature = "doctest-private")]for test-only code
Use channel-based communication (flume, tokio channels) between async tasks
Use consistent formatting followingcargo fmtstandards
Ensure code passescargo clippy --all-targets --no-deps -- --deny=warningslinter checks
Files:
src/rpc/methods/eth/types.rssrc/rpc/methods/chain.rssrc/rpc/methods/eth.rs
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: ChainSafe/forest PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T10:25:49.996Z
Learning: Publisher/Subscriber Pattern: Broadcast `HeadChange` events to multiple subscribers (RPC, message pool, chain indexer)
Learnt from: LesnyRumcajs
Repo: ChainSafe/forest PR: 5907
File: src/rpc/methods/state.rs:523-570
Timestamp: 2025-08-06T15:44:33.467Z
Learning: LesnyRumcajs prefers to rely on BufWriter's Drop implementation for automatic flushing rather than explicit flush() calls in Forest codebase.
📚 Learning: 2026-01-14T10:25:49.996Z
Learnt from: CR
Repo: ChainSafe/forest PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T10:25:49.996Z
Learning: Applies to **/*.rs : Document all public functions and structs with doc comments
Applied to files:
src/rpc/methods/eth/types.rs
📚 Learning: 2026-01-05T12:54:40.850Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/cron_state.rs:8-8
Timestamp: 2026-01-05T12:54:40.850Z
Learning: In Rust code reviews, do not derive Eq for a struct if any field does not implement Eq (e.g., types from external dependencies). If a type like CronStateLotusJson includes fields wrapping external dependencies that lack Eq, derive PartialEq (or implement PartialEq manually) but avoid deriving Eq. This ensures comparisons compile and reflect actual equivalence semantics. When needed, consider implementing custom PartialEq (and possibly Eq) only after ensuring all fields (or wrappers) implement Eq, or keep PartialEq-only if full equality semantics cannot be expressed.
Applied to files:
src/rpc/methods/eth/types.rssrc/rpc/methods/chain.rssrc/rpc/methods/eth.rs
📚 Learning: 2026-01-05T12:56:13.802Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/evm_state.rs:41-44
Timestamp: 2026-01-05T12:56:13.802Z
Learning: In Rust codebases (e.g., Forest), do not add #[cfg(test)] to functions already annotated with #[test]. The #[test] attribute ensures the function is compiled only for tests, so a separate #[cfg(test)] is redundant and can be removed if present. Apply this check to all Rust files that contain #[test] functions.
Applied to files:
src/rpc/methods/eth/types.rssrc/rpc/methods/chain.rssrc/rpc/methods/eth.rs
📚 Learning: 2026-01-14T10:25:49.996Z
Learnt from: CR
Repo: ChainSafe/forest PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-14T10:25:49.996Z
Learning: Publisher/Subscriber Pattern: Broadcast `HeadChange` events to multiple subscribers (RPC, message pool, chain indexer)
Applied to files:
src/rpc/methods/chain.rs
📚 Learning: 2025-08-08T12:11:55.266Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5867
File: src/ipld/util.rs:461-487
Timestamp: 2025-08-08T12:11:55.266Z
Learning: Forest (src/ipld/util.rs, Rust): In UnorderedChainStream::poll_next, dropping `extract_sender` (when no more tipsets and the extract queue is empty) is the intended shutdown signal for workers. Any subsequent attempt to enqueue work after this drop is a logic error and should be treated as an error; do not change `send()` to ignore a missing sender.
Applied to files:
src/rpc/methods/chain.rs
📚 Learning: 2025-10-17T14:24:47.046Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6167
File: src/tool/subcommands/state_compute_cmd.rs:89-91
Timestamp: 2025-10-17T14:24:47.046Z
Learning: In `src/tool/subcommands/state_compute_cmd.rs`, when using `ReadOpsTrackingStore` to generate minimal snapshots, `HEAD_KEY` should be written to `db.tracker` (not `db` itself) before calling `export_forest_car()`, because the export reads from the tracker MemoryDB which accumulates only the accessed data during computation.
Applied to files:
src/rpc/methods/chain.rs
🧬 Code graph analysis (1)
src/rpc/methods/chain.rs (1)
src/rpc/methods/eth.rs (2)
from_filecoin_tipset(567-645)e(1992-1992)
⏰ 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). (8)
- GitHub Check: All lint checks
- GitHub Check: Build Ubuntu
- GitHub Check: Build MacOS
- GitHub Check: cargo-publish-dry-run
- GitHub Check: tests-release
- GitHub Check: rubocop
- GitHub Check: Coverage
- GitHub Check: Build forest binaries on Linux AMD64
🔇 Additional comments (2)
src/rpc/methods/eth.rs (2)
534-547:TxInfo+From<bool>is a clean API improvement.
1604-1665: Updated handlers to useBlock::from_filecoin_tipset(..., full_tx_info.into())look consistent.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
Summary of changes
Changes introduced in this pull request:
newHeadsresponse to Ethereum block (it was an array of tipset headers (???)).filecoin-subwaydoesn't complain anymore.Reference issue to close (if applicable)
Closes #6400
Other information and links
Change checklist
Summary by CodeRabbit
Bug Fixes
New Features
Compatibility
✏️ Tip: You can customize this high-level summary in your review settings.