Impl state fork handler in state manager call_raw#7061
Conversation
WalkthroughDetects expensive state‑migration epochs, refuses explicit RPC calls that would trigger them (Error::ExpensiveFork), runs required migrations before VM execution in StateManager::call_raw, adds Lotus‑compatible retry logic for StateCall, and adds snapshot tests targeting expensive‑fork epochs. ChangesExpensive fork handling across state simulation and RPC
Sequence Diagram(s)sequenceDiagram
participant Client
participant StateManager
participant ChainConfig
participant StateMigrations
participant VM
Client->>StateManager: Filecoin.StateCall / eth.apply_message (state_cid?, tipset?)
StateManager->>ChainConfig: has_expensive_fork_between(parent.epoch(), target_epoch)
alt expensive fork detected
ChainConfig-->>StateManager: true
StateManager-->>Client: Error::ExpensiveFork
else safe
StateManager->>StateMigrations: run_state_migrations(initial_state_cid)
StateMigrations-->>StateManager: migrated_state_cid
StateManager->>VM: execute with migrated_state_cid and chain_rand
VM-->>Client: execution result
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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 |
prepare_parent_state in state manager call_raw
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/state_manager/message_simulation.rs`:
- Around line 42-44: The call to exec.prepare_parent_state(genesis_timestamp,
VMTrace::NotTraced, &mut no_cb)? lacks any error context; change it to use
anyhow::Context so failures include call-site info (e.g., use
exec.prepare_parent_state(...).context(format!("failed to prepare parent state
for genesis_timestamp={}", genesis_timestamp))?), ensuring the returned
(state_cid, _, _) bind remains the same and still handles the Result from
prepare_parent_state with context attached.
🪄 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: 418976d3-f7ec-4592-a04e-233e6206d71f
📒 Files selected for processing (1)
src/state_manager/message_simulation.rs
prepare_parent_state in state manager call_rawThere 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/networks/mod.rs`:
- Around line 542-550: The has_expensive_fork_between function incorrectly
includes the parent epoch in its search window causing a migration at parent to
make the next tipset appear to require migration; update the lower bound check
so it excludes parent by using info.epoch > parent (instead of info.epoch >=
parent) when scanning self.height_infos.values() for info.expensive, i.e. change
the predicate in has_expensive_fork_between to info.expensive && info.epoch >
parent && info.epoch < height so parent-side migrations are not double-counted.
In `@src/state_manager/errors.rs`:
- Around line 15-17: The error message for the ExpensiveFork variant is not
self-contained because it mentions "at epoch" but the variant carries no epoch;
fix by either (A) adding an epoch field to the variant (e.g., change
ExpensiveFork to ExpensiveFork { epoch: u64 } or similar type and update the
#[error(...)] to include the epoch placeholder like #[error("refusing explicit
call due to state fork at epoch {epoch}")] and then update all places that
construct ExpensiveFork to pass the epoch, or (B) remove the dangling suffix by
changing the #[error(...)] text to a self-contained message such as
#[error("refusing explicit call due to state fork")]; touch the ExpensiveFork
variant and its usages accordingly to keep types/constructors consistent.
In `@src/state_manager/message_simulation.rs`:
- Around line 30-56: The code currently performs the expensive-fork check
(chain_config.has_expensive_fork_between) and runs migration prep even when the
caller supplied a state (state_cid is Some), which can reject or re-mutate a
caller-provided post-fork state; in call_on_state, guard the expensive-fork
rejection and run_state_migrations() so they only execute when
state_cid.is_none() (i.e., when we derive state from a tipset), by moving the
chain_config.has_expensive_fork_between checks and the run_state_migrations()
calls inside the state_cid.is_none() branch; apply the same change for the other
occurrence around the code referenced at 58-79 and keep references to
chain_index().load_required_tipset, has_expensive_fork_between,
run_state_migrations, and call_on_state to locate the spots to change.
🪄 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: 8082d114-8347-4a81-b4bb-2fa3b521a995
📒 Files selected for processing (3)
src/networks/mod.rssrc/state_manager/errors.rssrc/state_manager/message_simulation.rs
c2ff120 to
23e2128
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/networks/mod.rs (1)
731-737: ⚡ Quick winPin the inclusive lower-bound case in this regression test.
This currently locks in the exclusive upper bound only. Adding an assertion like
assert!(cfg.has_expensive_fork_between(shark, shark + 1));would protect the intended[parent, height)behavior from regressing again.Based on learnings:
ChainConfig::has_expensive_fork_between(parent, height)intentionally uses an inclusive lower bound matching Lotus’s[parent, height)semantics.🤖 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/networks/mod.rs` around lines 731 - 737, Update the test has_expensive_fork_between_matches_upgrade_epochs to pin the inclusive lower-bound case by adding an assertion that the fork exists at the lower bound: insert assert!(cfg.has_expensive_fork_between(shark, shark + 1)); inside the test (the test uses ChainConfig::mainnet(), variable shark = cfg.epoch(Height::Shark)) so update that function to include this new assertion that calls ChainConfig::has_expensive_fork_between with (shark, shark + 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/tool/subcommands/api_cmd/api_compare_tests.rs`:
- Around line 2450-2456: The code computing expensive_fork_epoch uses
.max().expect(...) which can panic; update this in the helper that returns
anyhow::Result to return an error instead of aborting: replace the
.max().expect(...) pattern on
chain_config.height_infos.values().filter(...).map(...).max() with
.ok_or_else(|| anyhow::anyhow!("calibnet must define at least one expensive
fork"))? so the function returns Err(...) when no epoch is found, propagating
the anyhow::Result; keep references to expensive_fork_epoch, chain_config,
heaviest_tipset, and height_infos so the change is localized.
---
Nitpick comments:
In `@src/networks/mod.rs`:
- Around line 731-737: Update the test
has_expensive_fork_between_matches_upgrade_epochs to pin the inclusive
lower-bound case by adding an assertion that the fork exists at the lower bound:
insert assert!(cfg.has_expensive_fork_between(shark, shark + 1)); inside the
test (the test uses ChainConfig::mainnet(), variable shark =
cfg.epoch(Height::Shark)) so update that function to include this new assertion
that calls ChainConfig::has_expensive_fork_between with (shark, shark + 1).
🪄 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: 4821a8ea-e361-4550-aaaf-255a36880eac
📒 Files selected for processing (6)
src/networks/mod.rssrc/rpc/methods/eth.rssrc/rpc/methods/state.rssrc/state_manager/errors.rssrc/state_manager/message_simulation.rssrc/tool/subcommands/api_cmd/api_compare_tests.rs
Codecov Report❌ Patch coverage is Additional details and impacted files
... and 13 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/tool/subcommands/api_cmd/api_compare_tests.rs (1)
2456-2456: ⚡ Quick winEnhance error message with diagnostic context.
The change from
.expect()to.ok_or_else()correctly addresses the past review feedback. However, the error message could be more diagnostic by including the heaviest tipset epoch, as suggested in the original review comment.📋 Suggested improvement for diagnostics
- .ok_or_else(|| anyhow::anyhow!("calibnet must define at least one expensive fork"))?; + .ok_or_else(|| { + anyhow::anyhow!( + "no expensive fork epoch <= heaviest tipset epoch {} for calibnet snapshot", + heaviest_tipset.epoch() + ) + })?;🤖 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/tool/subcommands/api_cmd/api_compare_tests.rs` at line 2456, The error created by .ok_or_else currently uses a generic message "calibnet must define at least one expensive fork"; update the closure to include diagnostic context by appending the heaviest tipset epoch (e.g., heaviest_tipset_epoch or heaviest_tipset.epoch()) so the error shows the epoch value when no expensive fork is found; locate the call site where .ok_or_else(|| anyhow::anyhow!(...)) is used and interpolate the existing heaviest tipset variable into the anyhow message to produce a clearer, actionable error.
🤖 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/tool/subcommands/api_cmd/api_compare_tests.rs`:
- Line 2456: The error created by .ok_or_else currently uses a generic message
"calibnet must define at least one expensive fork"; update the closure to
include diagnostic context by appending the heaviest tipset epoch (e.g.,
heaviest_tipset_epoch or heaviest_tipset.epoch()) so the error shows the epoch
value when no expensive fork is found; locate the call site where .ok_or_else(||
anyhow::anyhow!(...)) is used and interpolate the existing heaviest tipset
variable into the anyhow message to produce a clearer, actionable error.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 3494d18e-f244-4632-b2a5-c3084f080270
📒 Files selected for processing (1)
src/tool/subcommands/api_cmd/api_compare_tests.rs
There was a problem hiding this comment.
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/eth.rs (1)
1792-1804:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPreserve
ExpensiveForkas a typed RPC error in gas estimation.Line 1803 wraps non-revert failures into a generic message, which also hides
crate::state_manager::Error::ExpensiveForkinstead of returning it directly.Suggested fix
if let Err(e) = apply_message(ctx, Some(tipset), msg).await { // if the error is an execution reverted, return it directly if e.downcast_ref::<EthErrors>() .is_some_and(|eth_err| matches!(eth_err, EthErrors::ExecutionReverted { .. })) { return Err(e.into()); } + // Preserve expensive-fork refusal as a typed error. + if e.downcast_ref::<crate::state_manager::Error>() + .is_some_and(|sm_err| matches!(sm_err, crate::state_manager::Error::ExpensiveFork)) + { + return Err(e.into()); + } err = e.into(); }🤖 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 1792 - 1804, The current gas estimation error handling wraps non-revert failures into a generic anyhow error which hides crate::state_manager::Error::ExpensiveFork; update the branch after apply_message so that if the error downcasts to state_manager::Error::ExpensiveFork (or otherwise identifies ExpensiveFork) you return that error directly (preserving its typed RPC representation) instead of converting it into the generic "failed to estimate gas" anyhow; keep the existing special-case for EthErrors::ExecutionReverted but add a second special-case that checks for ExpensiveFork and returns it unchanged, only falling back to Err(anyhow::anyhow!("failed to estimate gas: {}", err.message()).into()) for other errors.
🧹 Nitpick comments (1)
src/networks/mod.rs (1)
705-710: ⚡ Quick winAdd calibnet fix-epoch coverage to expensive-fork tests.
This test only asserts mainnet
Shark. Please add assertions aroundWatermelonFix/WatermelonFix2/DragonFix/TockFixon calibnet to lock in the key behavior this PR is enabling.🤖 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/networks/mod.rs` around lines 705 - 710, The test has_expensive_fork_between_matches_upgrade_epochs only checks mainnet Shark; add equivalent assertions for calibnet by creating cfg = ChainConfig::calibnet() and for each epoch Height::WatermelonFix, Height::WatermelonFix2, Height::DragonFix, and Height::TockFix assert that cfg.has_expensive_fork_between(epoch - 1, epoch + 1) is true and cfg.has_expensive_fork_between(epoch - 1, epoch) is false (mirroring the Shark checks) so the test locks in the new calibnet fix-epoch behavior.
🤖 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.
Outside diff comments:
In `@src/rpc/methods/eth.rs`:
- Around line 1792-1804: The current gas estimation error handling wraps
non-revert failures into a generic anyhow error which hides
crate::state_manager::Error::ExpensiveFork; update the branch after
apply_message so that if the error downcasts to
state_manager::Error::ExpensiveFork (or otherwise identifies ExpensiveFork) you
return that error directly (preserving its typed RPC representation) instead of
converting it into the generic "failed to estimate gas" anyhow; keep the
existing special-case for EthErrors::ExecutionReverted but add a second
special-case that checks for ExpensiveFork and returns it unchanged, only
falling back to Err(anyhow::anyhow!("failed to estimate gas: {}",
err.message()).into()) for other errors.
---
Nitpick comments:
In `@src/networks/mod.rs`:
- Around line 705-710: The test
has_expensive_fork_between_matches_upgrade_epochs only checks mainnet Shark; add
equivalent assertions for calibnet by creating cfg = ChainConfig::calibnet() and
for each epoch Height::WatermelonFix, Height::WatermelonFix2, Height::DragonFix,
and Height::TockFix assert that cfg.has_expensive_fork_between(epoch - 1, epoch
+ 1) is true and cfg.has_expensive_fork_between(epoch - 1, epoch) is false
(mirroring the Shark checks) so the test locks in the new calibnet fix-epoch
behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 12798021-fb2c-4181-8ff1-490f592749a6
📒 Files selected for processing (8)
src/networks/butterflynet/mod.rssrc/networks/calibnet/mod.rssrc/networks/devnet/mod.rssrc/networks/mainnet/mod.rssrc/networks/mod.rssrc/rpc/methods/eth.rssrc/state_manager/message_simulation.rssrc/state_migration/mod.rs
hanabi1224
left a comment
There was a problem hiding this comment.
I think we could avoid having 2 sources of expensive fork heights
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/tool/subcommands/api_cmd/api_compare_tests.rs`:
- Around line 2451-2455: The code picks the latest migration epoch overall
instead of the latest expensive-fork epoch; update the chain of iterators from
crate::state_migration::get_all_migrations::<crate::db::DbImpl>(&NetworkChain::Calibnet)
so it first filters migrations to only those that represent an expensive fork
(inspect the migration value from the tuple returned by get_all_migrations and
check its expensive/fork-type flag or method, e.g. migration.is_expensive() or
migration.fork_type == Expensive) before calling filter_map(...).max() so that
expensive_fork_epoch reflects the latest expensive migration only.
🪄 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: c6698981-0c39-4593-adcf-50a0a1e2eabd
📒 Files selected for processing (4)
src/networks/mod.rssrc/rpc/methods/eth.rssrc/state_migration/mod.rssrc/tool/subcommands/api_cmd/api_compare_tests.rs
hanabi1224
left a comment
There was a problem hiding this comment.
I would define a migration function that returns unimplemented state migration at height {height} error for these migrations. None would just bypass the migration and result in state mismatch without clear error message.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/networks/mod.rs (1)
698-703: ⚡ Quick winAdd a calibnet
*Fixepoch assertion in the expensive-fork test.Current test only validates
Height::Sharkon mainnet. A small calibnet assertion (e.g.,WatermelonFixboundary) would lock in the regression that this PR is addressing.Suggested test extension
#[test] fn has_expensive_fork_between_matches_upgrade_epochs() { let cfg = ChainConfig::mainnet(); let shark = cfg.epoch(Height::Shark); assert!(cfg.has_expensive_fork_between(shark - 1, shark + 1)); assert!(!cfg.has_expensive_fork_between(shark - 1, shark)); + + let calib = ChainConfig::calibnet(); + let wf = calib.epoch(Height::WatermelonFix); + assert!(calib.has_expensive_fork_between(wf - 1, wf + 1)); }Based on learnings: calibnet
*Fixmigration heights previously caused expensive-fork detection drift and should be guarded by tests.🤖 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/networks/mod.rs` around lines 698 - 703, Extend the test function has_expensive_fork_between_matches_upgrade_epochs to also cover calibnet: create a calibnet config with ChainConfig::calibnet(), get the WatermelonFix epoch via cfg.epoch(Height::WatermelonFix), then add assertions mirroring the mainnet ones using cfg.has_expensive_fork_between(watermelon - 1, watermelon + 1) (should be true) and cfg.has_expensive_fork_between(watermelon - 1, watermelon) (should be false) so the calibnet *Fix migration boundary is locked in.
🤖 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/state_migration/mod.rs`:
- Around line 137-145: The loop over mappings currently skips when
chain_config.height_infos lacks an entry for a migration height; change it to
fail fast: in the for (height, migrate) in &mappings loop, after checking the
migrate pointer (the unimplemented_migration::<DB> as RunMigration<DB> check),
explicitly check if chain_config.height_infos.get(height) is None and
panic/assert with a clear message that the migration height is missing (include
the height), otherwise continue to assert that info.bundle.is_some() for the
Some(info) case; reference the mappings iteration, unimplemented_migration::<DB>
as RunMigration<DB>, and chain_config.height_infos.get(height) when locating the
change.
---
Nitpick comments:
In `@src/networks/mod.rs`:
- Around line 698-703: Extend the test function
has_expensive_fork_between_matches_upgrade_epochs to also cover calibnet: create
a calibnet config with ChainConfig::calibnet(), get the WatermelonFix epoch via
cfg.epoch(Height::WatermelonFix), then add assertions mirroring the mainnet ones
using cfg.has_expensive_fork_between(watermelon - 1, watermelon + 1) (should be
true) and cfg.has_expensive_fork_between(watermelon - 1, watermelon) (should be
false) so the calibnet *Fix migration boundary is locked in.
🪄 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: 904795d1-66e0-4149-85e2-77952b7cd5cc
📒 Files selected for processing (3)
src/networks/mod.rssrc/state_migration/mod.rssrc/tool/subcommands/api_cmd/api_compare_tests.rs
30bb907 to
3a08213
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/state_migration/mod.rs`:
- Around line 123-125: The BUNDLE_CHECKED flag is being set before validation
finishes, which can suppress future checks on error; move the
BUNDLE_CHECKED.store(true, atomic::Ordering::Relaxed) call to after the
validation loop over mappings completes successfully (i.e., only set
BUNDLE_CHECKED when the for height in mappings loop has finished without
returning/propagating an error), keeping the same atomic ordering and leaving
the validation logic in the same function/block.
🪄 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: 69b6e1e0-6f52-4154-ae4b-7bc9c2e92f31
📒 Files selected for processing (4)
src/networks/mod.rssrc/state_migration/mod.rssrc/tool/subcommands/api_cmd/api_compare_tests.rssrc/tool/subcommands/shed_cmd/migration.rs
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/networks/mod.rs (1)
698-703: ⚡ Quick winAdd explicit calibnet
*Fixexpensive-fork coverage.This test only validates
Height::Sharkon mainnet. Please add at least one calibnet*Fixepoch assertion (e.g.,WatermelonFix) to lock the regression surface you just fixed.Suggested test addition
#[test] fn has_expensive_fork_between_matches_upgrade_epochs() { let cfg = ChainConfig::mainnet(); let shark = cfg.epoch(Height::Shark); assert!(cfg.has_expensive_fork_between(shark - 1, shark + 1)); assert!(!cfg.has_expensive_fork_between(shark - 1, shark)); } + +#[test] +fn has_expensive_fork_between_matches_calibnet_fix_epochs() { + let cfg = ChainConfig::calibnet(); + let watermelon_fix = cfg.epoch(Height::WatermelonFix); + assert!(cfg.has_expensive_fork_between(watermelon_fix - 1, watermelon_fix + 1)); + assert!(!cfg.has_expensive_fork_between(watermelon_fix - 1, watermelon_fix)); +}🤖 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/networks/mod.rs` around lines 698 - 703, The test has_expensive_fork_between_matches_upgrade_epochs only checks mainnet Shark; add a parallel assertion for calibnet to cover the Fix-era you fixed (e.g., use let cfg = ChainConfig::calibnet(); let fix_epoch = cfg.epoch(Height::WatermelonFix); then assert!(cfg.has_expensive_fork_between(fix_epoch - 1, fix_epoch + 1)); and assert!(!cfg.has_expensive_fork_between(fix_epoch - 1, fix_epoch)); this mirrors the existing Shark checks and locks the calibnet *Fix regression surface.
🤖 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/networks/mod.rs`:
- Around line 698-703: The test
has_expensive_fork_between_matches_upgrade_epochs only checks mainnet Shark; add
a parallel assertion for calibnet to cover the Fix-era you fixed (e.g., use let
cfg = ChainConfig::calibnet(); let fix_epoch = cfg.epoch(Height::WatermelonFix);
then assert!(cfg.has_expensive_fork_between(fix_epoch - 1, fix_epoch + 1)); and
assert!(!cfg.has_expensive_fork_between(fix_epoch - 1, fix_epoch)); this mirrors
the existing Shark checks and locks the calibnet *Fix regression surface.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 82b0be70-dd10-400c-8535-5f5fb14e9e09
📒 Files selected for processing (4)
src/networks/mod.rssrc/state_migration/mod.rssrc/tool/subcommands/api_cmd/api_compare_tests.rssrc/tool/subcommands/shed_cmd/migration.rs
Summary of changes
Changes introduced in this pull request:
Reference issue to close (if applicable)
Closes #6446
Closes #5965
Other information and links
Change checklist
Outside contributions
Summary by CodeRabbit
Bug Fixes
New Features
Tests
Chores