Skip to content

Conversation

@LesnyRumcajs
Copy link
Member

@LesnyRumcajs LesnyRumcajs commented Jan 9, 2026

Summary of changes

Changes introduced in this pull request:

  • changed the data structure returned by the newHeads response to Ethereum block (it was an array of tipset headers (???)). filecoin-subway doesn't complain anymore.

Reference issue to close (if applicable)

Closes #6400

Other information and links

Change checklist

  • I have performed a self-review of my own code,
  • I have made corresponding changes to the documentation. All new code adheres to the team's documentation standards,
  • I have added tests that prove my fix is effective or that my feature works (if possible),
  • I have made sure the CHANGELOG is up-to-date. All user-facing changes should be reflected in this document.

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Fixed eth_subscribe newHeads to return Ethereum-compatible block headers instead of Filecoin block format.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 9, 2026

Walkthrough

The PR fixes the eth_subscribe newHeads RPC method to return Ethereum block format instead of Filecoin tipset headers. Changes include updating method signatures to accept new context patterns, converting Filecoin tipsets to Ethereum blocks, and modifying the ApiHeaders type to carry Block objects.

Changes

Cohort / File(s) Summary
Documentation
CHANGELOG.md
Added changelog entry documenting the fix for eth_subscribe newHeads returning incorrect Filecoin block format.
Chain RPC Handler
src/rpc/methods/chain.rs
Updated new_heads signature to accept Ctx<DB> instead of &RPCState<DB>. Modified head-change handling to convert Filecoin tipsets to Ethereum blocks via EthBlock::from_filecoin_tipset with full transaction info; logs errors and continues on conversion failure.
Ethereum Block Conversion
src/rpc/methods/eth.rs
Added public TxInfo enum (Hash/Full variants) to control transaction detail level. Introduced public async method Block::from_filecoin_tipset for converting Filecoin tipsets to Ethereum blocks. Updated block_from_filecoin_tipset signature to use TxInfo parameter instead of boolean; updated all call sites accordingly.
Subscription Handler
src/rpc/methods/eth/pubsub.rs
Changed chain::new_heads call from passing reference (&ctx) to passing owned Arc (ctx), reflecting updated function signature.
Type Definition
src/rpc/methods/eth/types.rs
Changed ApiHeaders struct field from Vec<CachingBlockHeader> to Block to carry Ethereum block data instead of Filecoin headers.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant PubSub as Subscription Handler
    participant Chain as Chain Methods
    participant BlockConv as Block Converter
    participant DB as Blockstore
    participant Sender as Stream Sender

    Client->>PubSub: eth_subscribe(newHeads)
    PubSub->>Chain: chain::new_heads(ctx)
    Chain->>Chain: create subscriber & spawn handler
    Chain-->>PubSub: (Subscriber, JoinHandle)
    PubSub-->>Client: subscription_id

    Note over Chain: Awaiting Apply events
    Chain->>Chain: receive tipset (Apply event)
    Chain->>BlockConv: EthBlock::from_filecoin_tipset(ctx, tipset, TxInfo::Full)
    BlockConv->>DB: fetch transaction data
    DB-->>BlockConv: transaction data
    BlockConv->>BlockConv: build Ethereum block
    BlockConv-->>Chain: Result<EthBlock>
    
    alt Conversion Success
        Chain->>Chain: wrap in ApiHeaders(block)
        Chain->>Sender: send headers
        Sender-->>Client: eth_subscription notification
    else Conversion Error
        Chain->>Chain: log error
        Chain->>Chain: continue loop
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • PR #5749 — Directly modifies the same new_heads function and ApiHeaders type that are updated in this PR to emit Ethereum blocks.
  • PR #6227 — Updates src/rpc/methods/chain.rs with Arc<Tipset> ownership changes that align with the Arc usage patterns introduced here.

Suggested labels

RPC

Suggested reviewers

  • hanabi1224
  • sudo-shashank
  • akaladarshi
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: use ethereum block in eth_subscribe newHeads' clearly and specifically describes the main change: converting the eth_subscribe newHeads response from Filecoin format to Ethereum block format.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #6400: returns EthBlock instead of TipsetHeader array, uses enum-based TxInfo parameter, converts Filecoin tipsets to Ethereum blocks asynchronously, and includes error handling.
Out of Scope Changes check ✅ Passed All changes are directly aligned with fixing eth_subscribe newHeads behavior: API signature updates for new_heads and block construction, enum introduction for transaction details, and type adjustments for ApiHeaders. No unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

@LesnyRumcajs LesnyRumcajs force-pushed the fix-eth-subscribe-heads branch from d6912e8 to 6eabb3d Compare January 13, 2026 16:31
@LesnyRumcajs LesnyRumcajs marked this pull request as ready for review January 13, 2026 17:11
@LesnyRumcajs LesnyRumcajs requested a review from a team as a code owner January 13, 2026 17:11
@LesnyRumcajs LesnyRumcajs requested review from hanabi1224 and sudo-shashank and removed request for a team January 13, 2026 17:11
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 (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 and ApiEthTx construction. While the non-caching behavior is intentional for the eth_subscribe use 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 implementing From<bool> for TxInfo to reduce repetition.

The bool-to-enum conversion pattern is repeated in three handlers. A From implementation 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

📥 Commits

Reviewing files that changed from the base of the PR and between 2c87fa1 and cce1f2e.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • src/rpc/methods/chain.rs
  • src/rpc/methods/eth.rs
  • src/rpc/methods/eth/pubsub.rs
  • src/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.rs
  • src/rpc/methods/eth/pubsub.rs
  • src/rpc/methods/chain.rs
  • src/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.rs
  • src/rpc/methods/eth/pubsub.rs
  • src/rpc/methods/chain.rs
  • src/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 require JsonSchema for subscription payload types. If subscriptions are included in OpenRPC/schemars output, ApiHeaders may need #[derive(JsonSchema)] (and any necessary schemars(...) attrs) to avoid doc/test breakage.

src/rpc/methods/eth/pubsub.rs (1)

121-130: Call-site update matches the new chain::new_heads(Ctx<DB>) signature.

src/rpc/methods/chain.rs (1)

81-113: Double-check TxInfo::Full for newHeads (payload size + performance). If consumers only expect header-ish fields or tx hashes, consider emitting TxInfo::Hash instead 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 Copy trait 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
Copy link

codecov bot commented Jan 13, 2026

Codecov Report

❌ Patch coverage is 12.00000% with 66 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.47%. Comparing base (2c87fa1) to head (cce1f2e).

Files with missing lines Patch % Lines
src/rpc/methods/eth.rs 13.84% 53 Missing and 3 partials ⚠️
src/rpc/methods/chain.rs 0.00% 9 Missing ⚠️
src/rpc/methods/eth/pubsub.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
Files with missing lines Coverage Δ
src/rpc/methods/eth/types.rs 65.03% <ø> (ø)
src/rpc/methods/eth/pubsub.rs 0.00% <0.00%> (ø)
src/rpc/methods/chain.rs 52.59% <0.00%> (-0.36%) ⬇️
src/rpc/methods/eth.rs 66.18% <13.84%> (-1.28%) ⬇️

... and 2 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2c87fa1...cce1f2e. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment on lines +1735 to +1739
let tx_info = if full_tx_info {
TxInfo::Full
} else {
TxInfo::Hash
};
Copy link
Contributor

Choose a reason for hiding this comment

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

we can add an impl From<bool> for TxInfo to avoid doing this multiple times

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd prefer to be more verbose. That said, I noticed there's some existing code I didn't know of that could be reused.

@LesnyRumcajs LesnyRumcajs marked this pull request as draft January 13, 2026 18:20
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.

eth_subscribe returns wrong data structure for newHeads

3 participants