Skip to content

Fix resolve_to_key in message pool to be reorg stable #6910

Open
sudo-shashank wants to merge 11 commits intomainfrom
shashank/fix-resolve-to-key-mpool
Open

Fix resolve_to_key in message pool to be reorg stable #6910
sudo-shashank wants to merge 11 commits intomainfrom
shashank/fix-resolve-to-key-mpool

Conversation

@sudo-shashank
Copy link
Copy Markdown
Contributor

@sudo-shashank sudo-shashank commented Apr 15, 2026

Summary of changes

Changes introduced in this pull request:

  • Resolve to deterministic address at finality, to ensure the resolved address is reorg-stable.

Reference issue to close (if applicable)

Closes #6891

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.

Outside contributions

  • I have read and agree to the CONTRIBUTING document.
  • I have read and agree to the AI Policy document. I understand that failure to comply with the guidelines will lead to rejection of the pull request.

Summary by CodeRabbit

  • Bug Fixes

    • Improved address resolution logic to properly respect finality lookback windows when determining key addresses for message pool operations.
    • Enhanced protocol-specific address handling to correctly reject actor address types that cannot be resolved.
  • Tests

    • Expanded test coverage for address resolution behavior with finality lookback windows.

@sudo-shashank sudo-shashank added the RPC requires calibnet RPC checks to run on CI label Apr 15, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 15, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7def56bb-bc97-44e0-8653-26db54f97557

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch shashank/fix-resolve-to-key-mpool
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch shashank/fix-resolve-to-key-mpool

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

@sudo-shashank sudo-shashank marked this pull request as ready for review April 16, 2026 07:52
@sudo-shashank sudo-shashank requested a review from a team as a code owner April 16, 2026 07:52
@sudo-shashank sudo-shashank requested review from LesnyRumcajs and hanabi1224 and removed request for a team April 16, 2026 07:52
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 16, 2026

Codecov Report

❌ Patch coverage is 90.27778% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.90%. Comparing base (919b53e) to head (45d58f9).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/message_pool/msgpool/provider.rs 63.15% 5 Missing and 2 partials ⚠️
Additional details and impacted files
Files with missing lines Coverage Δ
src/message_pool/msgpool/msg_pool.rs 89.25% <100.00%> (+0.60%) ⬆️
src/message_pool/msgpool/provider.rs 54.83% <63.15%> (+0.67%) ⬆️

... and 4 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 919b53e...45d58f9. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.


let api = TestApi::default();
let bls_sig_cache = SizeTrackingLruCache::new_mocked();
let key_cache = SizeTrackingLruCache::new_mocked();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I added a similar cache to state manager in #6928 we should consolidate them. @coderabbitai create a tracking issue.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

Let me first look at PR #6928 to understand the cache that was added there.


🏁 Script executed:

#!/bin/bash
gh pr view 6928 --repo ChainSafe/forest --json title,body,url,state | jq .

Length of output: 75


I have enough context to create the tracking issue. Let me do that now.


🏁 Script executed:

#!/bin/bash
gh issue create \
  --repo ChainSafe/forest \
  --title "Consolidate finality-lookback resolve caches in mpool and state manager" \
  --body "## Overview

PR `#6910` introduces a finality-lookback cache in \`resolve_to_key\` inside \`src/message_pool/msgpool/provider.rs\` (message pool) to make ID→key address resolution reorg-stable.

PR `#6928` adds a similar cache to the state manager.

These two caches serve related purposes and should be consolidated into a shared abstraction to avoid duplication and keep the logic in sync.

## Tasks

- [ ] Review the cache implementations in `#6910` (\`src/message_pool/msgpool/provider.rs\`) and `#6928` (state manager)
- [ ] Identify the common interface / shared logic
- [ ] Extract a shared utility or trait that both the message pool and state manager can use
- [ ] Update both call sites to use the consolidated implementation
- [ ] Add/update tests as appropriate

## References

- PR `#6910`: https://github.com/ChainSafe/forest/pull/6910
- PR `#6928`: https://github.com/ChainSafe/forest/pull/6928
- Requested by `@hanabi1224` in https://github.com/ChainSafe/forest/pull/6910#discussion_r3109534232" \
  --assignee hanabi1224

Length of output: 75


@hanabi1224, I'm unable to create the GitHub issue directly from this environment due to a missing authentication token. Here are the full details so you (or anyone on the team) can open it manually:


Title: Consolidate finality-lookback resolve caches in mpool and state manager

Body:

## Overview

PR `#6910` introduces a finality-lookback cache in `resolve_to_key` inside
`src/message_pool/msgpool/provider.rs` (message pool) to make ID→key address
resolution reorg-stable.

PR `#6928` adds a similar cache to the state manager.

These two caches serve related purposes and should be consolidated into a shared
abstraction to avoid duplication and keep the logic in sync.

## Tasks

- [ ] Review the cache implementations in `#6910` (`src/message_pool/msgpool/provider.rs`)
      and `#6928` (state manager)
- [ ] Identify the common interface / shared logic
- [ ] Extract a shared utility or trait that both the message pool and state manager can use
- [ ] Update both call sites to use the consolidated implementation
- [ ] Add/update tests as appropriate

## References

- PR `#6910`: https://github.com/ChainSafe/forest/pull/6910
- PR `#6928`: https://github.com/ChainSafe/forest/pull/6928
- Requested by `@hanabi1224` in https://github.com/ChainSafe/forest/pull/6910#discussion_r3109534232

Assignee: hanabi1224


Apologies for not being able to create it directly — please let me know if you'd like me to retry or adjust any details.


🧠 Learnings used
Learnt from: sudo-shashank
Repo: ChainSafe/forest PR: 6788
File: src/message_pool/msgpool/msg_pool.rs:286-300
Timestamp: 2026-03-31T15:27:58.502Z
Learning: In Forest's `src/message_pool/msgpool/msg_pool.rs`, the `key_cache: SizeTrackingLruCache<Address, Address>` (used in `resolve_to_key`) is intentionally keyed only by `Address` with no tipset component. This directly matches Lotus's `keyCache *lru.Cache[address.Address, address.Address]` in `chain/messagepool/messagepool.go`. ID→key address mappings are stable across reorgs because they are derived from actor creation (content-addressed), so a tipset-aware cache key or cache flush on head changes is not needed. Do not flag this as a reorg-safety bug.

Learnt from: sudo-shashank
Repo: ChainSafe/forest PR: 6788
File: src/rpc/methods/mpool.rs:301-306
Timestamp: 2026-03-25T09:06:55.615Z
Learning: In Forest's `MpoolGetNonce` handler (src/rpc/methods/mpool.rs), returning bare `mpool.get_sequence()` without going through `NonceTracker` is intentional and matches Lotus behavior. Lotus documents `MpoolGetNonce` as explicitly non-atomic and recommends using `MpoolPushMessage` instead. Do not flag the discrepancy between `MpoolGetNonce` (mpool.get_sequence) and `MpoolPushMessage` (NonceTracker.sign_and_push) as a bug.

Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6761
File: src/state_manager/mod.rs:496-511
Timestamp: 2026-03-18T14:19:21.819Z
Learning: In `src/state_manager/mod.rs` (Forest, ChainSafe/forest), the process-global `static CACHE: LazyLock<SizeTrackingLruCache<TipsetKey, ExecutedTipset>>` inside `load_executed_tipset` is intentionally shared across all `StateManager` instances. This is safe because `TipsetKey` values are CID-based (content-addressed, cryptographic hashes of block headers), so the same key always maps to the same deterministic `ExecutedTipset` result regardless of which `StateManager` or `ChainStore` instance processes it. Do not flag this as a bug in code review.

Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5978
File: .github/workflows/unit-tests.yml:72-76
Timestamp: 2025-08-25T09:57:27.412Z
Learning: hanabi1224's strategy for RPC snapshot cache versioning: branch isolation is not needed currently, but if snapshot generation logic changes in the future, a version string can be added to the cache key to handle the evolution.

Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5944
File: src/chain/store/index.rs:0-0
Timestamp: 2025-08-18T03:09:47.932Z
Learning: In Forest's tipset_by_height caching implementation, hanabi1224 prefers performance-conscious solutions that leverage finality guarantees rather than expensive chain walking for fork detection. The approach of constraining cache lookups to finalized epochs (using CHECKPOINT_INTERVAL >= CHAIN_FINALITY) provides fork safety without the performance cost of ancestry verification.

Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5978
File: .github/workflows/unit-tests.yml:72-76
Timestamp: 2025-08-25T09:53:37.443Z
Learning: hanabi1224 intentionally designs RPC snapshot test cache to be OS/arch-agnostic, sharing cached snapshot files across different platforms using enableCrossOsArchive: true and hash-based cache keys to improve cache efficiency and reduce redundant downloads.

Learnt from: sudo-shashank
Repo: ChainSafe/forest PR: 6788
File: src/message_pool/msgpool/mod.rs:0-0
Timestamp: 2026-03-31T15:28:12.127Z
Learning: In Forest's `head_change` function (`src/message_pool/msgpool/mod.rs`), reverted messages are stored in `rmsgs` keyed by the resolved key address (via `resolve_to_key`), and when re-adding them to the pending pool after a reorg, `msg.from()` is re-resolved against the new head tipset. This mirrors Lotus's `HeadChange` implementation in `chain/messagepool/messagepool.go`, which also uses the raw `m.Message.From` field (unresolved) throughout the revert and re-add path. Do not flag the re-resolution of `msg.from()` at re-add time as incorrect; this is the accepted design matching Lotus behavior.

Learnt from: akaladarshi
Repo: ChainSafe/forest PR: 6000
File: src/tool/subcommands/api_cmd/state_decode_params_tests/miner.rs:4-9
Timestamp: 2025-09-11T16:03:14.328Z
Learning: In the Forest codebase's state_decode_params_tests module, common imports like `to_vec`, `TokenAmount`, `Cid`, etc. are centralized in the mod.rs file and made available to submodules through `use super::*;`, eliminating the need for duplicate imports in individual test files.

Learnt from: akaladarshi
Repo: ChainSafe/forest PR: 6000
File: src/tool/subcommands/api_cmd/state_decode_params_tests/miner.rs:4-9
Timestamp: 2025-09-11T16:03:14.328Z
Learning: In the Forest codebase's state_decode_params_tests module, common imports like `to_vec`, `TokenAmount`, `Cid`, etc. are centralized in the mod.rs file and made available to submodules through `use super::*;`, eliminating the need for duplicate imports in individual test files.

Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6712
File: src/chain/store/chain_store.rs:172-174
Timestamp: 2026-03-10T13:22:53.227Z
Learning: In `src/chain/store/chain_store.rs` (Forest, ChainSafe/forest PR `#6712`), `get_required_tipset_key` was changed to use `TipsetKey::load(self.blockstore(), &hash.to_cid())` instead of reading from `eth_mappings`. This is backward compatible because the old `put_tipset_key` already persisted tipset key bytes to the blockstore via `put_cbor_default`, with the EthHash derived from that CID (`hash = tsk_cid.into()`). Since `EthHash::from(cid)` and `hash.to_cid()` are mutual inverses, existing databases can serve old tipset-key lookups without any backfill.

Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5930
File: build.rs:64-77
Timestamp: 2025-08-13T09:43:20.301Z
Learning: hanabi1224 prefers hard compile-time errors in build scripts rather than runtime safeguards or collision detection, believing it's better to fail fast and fix root causes of issues like malformed snapshot names.

Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6057
File: src/cli/subcommands/f3_cmd.rs:0-0
Timestamp: 2025-09-09T10:37:17.947Z
Learning: hanabi1224 prefers having default timeouts (like 10m for --no-progress-timeout) to prevent commands from hanging indefinitely, even when the timeout flag isn't explicitly provided by users. This fail-fast approach is preferred over requiring explicit flag usage.

Learnt from: sudo-shashank
Repo: ChainSafe/forest PR: 6710
File: src/wallet/subcommands/wallet_cmd.rs:641-649
Timestamp: 2026-03-11T10:10:29.857Z
Learning: In `src/wallet/subcommands/wallet_cmd.rs` (ChainSafe/forest, PR `#6710`), `resolve_target_address` intentionally returns `is_0x_recipient = false` for Filecoin-form f410f addresses (even though they resolve to Delegated/ETH-mapped addresses) and `true` only for `0x`-prefixed hex input. This is a deliberate choice to mirror Lotus CLI behavior, where method selection (InvokeContract vs METHOD_SEND) is driven by whether the user typed a `0x` address, not the resolved address protocol. The test `test_resolve_method_num_send_to_delegated` (f1 → f410f → METHOD_SEND) reflects this intentional design. Do not flag the `false` return for f410f-form Filecoin addresses as a bug.

Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6780
File: src/chain/store/index.rs:188-200
Timestamp: 2026-03-25T09:23:15.859Z
Learning: In Forest's `src/chain/store/index.rs`, the `ts_height_cache` write guard uses a global `is_finalized_fn` (comparing `ts.epoch() <= heaviest_tipset.epoch() - CHAIN_FINALITY`, optionally stricter with F3 finalized epoch) rather than a per-call `from_epoch - CHAIN_FINALITY` bound. This is correct and fork-safe: EC finality guarantees the chain cannot reorg past `heaviest - CHAIN_FINALITY`, so any tipset at or below that threshold is necessarily on the canonical chain regardless of which `from` tipset started the walk. Do not flag this as a fork-safety bug.

Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6780
File: src/chain/store/chain_store.rs:181-183
Timestamp: 2026-03-25T09:33:03.318Z
Learning: In Forest (ChainSafe/forest, src/chain/store/chain_store.rs), `set_f3_finalized_tipset` unconditionally replaces the cached F3 finalized tipset without a monotonicity guard. This is intentional: even if a delayed startup fetch races with a later `F3.Finalize` call and temporarily overwrites a newer epoch with an older one, eventual correctness is not broken. Do not suggest adding an epoch-monotonicity guard to `set_f3_finalized_tipset`.

Learnt from: akaladarshi
Repo: ChainSafe/forest PR: 6685
File: src/rpc/methods/eth.rs:3540-3549
Timestamp: 2026-03-10T13:30:38.793Z
Learning: In Forest's `debug_trace_transaction` (src/rpc/methods/eth.rs), the prestate tracer resolves top-level sender/recipient into `touched` via `EthAddress::from_filecoin_address`. This is intentional and sufficient: `debug_traceTransaction` is an Ethereum-namespace API whose callers only ever supply ETH-format transaction hashes, which always correspond to delegated f410f senders. Native Filecoin f1/f3 messages produce CID-derived hashes that are never surfaced by Ethereum tooling, so f1/f3 senders cannot reach this code path in practice. Do not flag the direct `from_filecoin_address` conversion as insufficient for the prestate tracer in this function.

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.

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.

Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6666
File: src/tool/subcommands/archive_cmd.rs:628-631
Timestamp: 2026-03-02T09:43:34.946Z
Learning: In Rust sources related to Forest snapshot handling, implement the rule: enable message_receipts and events (message_receipts: true, events: true) only for GC snapshots as defined in src/db/gc/snapshot.rs, since these are internal snapshots created during garbage collection. For user-facing export commands such as src/tool/subcommands/archive_cmd.rs, disable receipts and events by default (message_receipts: false, events: false) to keep user-facing snapshots smaller, unless explicitly requested. This guidance targets Rust files; apply consistently across similar snapshot-related modules, using the narrowest applicable scope when extending beyond the two specified files.

Learnt from: LesnyRumcajs
Repo: ChainSafe/forest PR: 6903
File: src/shim/executor.rs:243-251
Timestamp: 2026-04-14T17:24:13.631Z
Learning: In the ChainSafe/forest (LesnyRumcajs) codebase, do not require rustdoc comments on public methods when the method’s purpose is clearly self-explanatory from its name (e.g., `entries(&self)`, `into_entries(self)`). When reviewing Rust (`.rs`) files, avoid flagging missing documentation for these obviously named public APIs, reserving doc requirements for less clear or non-obvious public methods.

let lookback_ts = if ts.epoch() > self.chain_config().policy.chain_finality {
self.chain_index()
.tipset_by_height(
ts.epoch() - self.chain_config().policy.chain_finality,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What if ts is at a finalized epoch already?

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

Labels

RPC requires calibnet RPC checks to run on CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

resolve_to_key in message pool should resolve at finality for reorg-safety

2 participants