forest/state_migration/nv22fix/
migration.rs

1// Copyright 2019-2025 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3//
4//! This module contains the migration logic for the `NV22fix` upgrade.
5//! Corresponding
6use std::sync::Arc;
7
8use super::{SystemStateOld, system, verifier::Verifier};
9use crate::networks::{ChainConfig, Height, NetworkChain};
10use crate::shim::{
11    address::Address,
12    clock::ChainEpoch,
13    machine::{BuiltinActor, BuiltinActorManifest},
14    state_tree::{StateTree, StateTreeVersion},
15};
16use crate::state_migration::common::PostMigrationCheck;
17use crate::state_migration::common::{StateMigration, migrators::nil_migrator};
18use crate::utils::db::CborStoreExt as _;
19use anyhow::{Context, bail};
20use cid::Cid;
21use fvm_ipld_blockstore::Blockstore;
22
23impl<BS: Blockstore> StateMigration<BS> {
24    pub fn add_nv22fix_migrations(
25        &mut self,
26        store: &Arc<BS>,
27        state: &Cid,
28        new_manifest: &BuiltinActorManifest,
29    ) -> anyhow::Result<()> {
30        let state_tree = StateTree::new_from_root(store.clone(), state)?;
31        let system_actor = state_tree.get_required_actor(&Address::new_id(0))?;
32
33        let system_actor_state = store.get_cbor_required::<SystemStateOld>(&system_actor.state)?;
34
35        let current_manifest_data = system_actor_state.builtin_actors;
36
37        let current_manifest =
38            BuiltinActorManifest::load_v1_actor_list(store, &current_manifest_data)?;
39
40        for (name, code) in current_manifest.builtin_actors() {
41            let new_code = new_manifest.get(name)?;
42            self.add_migrator(code, nil_migrator(new_code))
43        }
44
45        self.add_migrator(
46            current_manifest.get_system(),
47            system::system_migrator(new_manifest),
48        );
49
50        Ok(())
51    }
52}
53
54struct PostMigrationVerifier {
55    state_pre: Cid,
56}
57
58impl<BS: Blockstore> PostMigrationCheck<BS> for PostMigrationVerifier {
59    fn post_migrate_check(&self, store: &BS, actors_out: &StateTree<BS>) -> anyhow::Result<()> {
60        let actors_in = StateTree::new_from_root(Arc::new(store), &self.state_pre)?;
61        let system_actor = actors_in.get_required_actor(&Address::new_id(0))?;
62
63        let system_actor_state = store.get_cbor_required::<SystemStateOld>(&system_actor.state)?;
64
65        let current_manifest_data = system_actor_state.builtin_actors;
66
67        let current_manifest =
68            BuiltinActorManifest::load_v1_actor_list(store, &current_manifest_data)?;
69
70        actors_in.for_each(|address, actor_in| {
71            let actor_out = actors_out.get_required_actor(&address)?;
72
73            if actor_in.sequence != actor_out.sequence {
74                bail!(
75                    "actor {address} sequence mismatch: pre-migration: {}, post-migration: {}",
76                    actor_in.sequence,
77                    actor_out.sequence
78                );
79            }
80
81            if actor_in.balance != actor_out.balance {
82                bail!(
83                    "actor {address} balance mismatch: pre-migration: {}, post-migration: {}",
84                    actor_in.balance,
85                    actor_out.balance
86                );
87            }
88
89            if actor_in.state != actor_out.state && actor_in.code != current_manifest.get_system() {
90                bail!(
91                    "actor {address} state mismatch: pre-migration: {}, post-migration: {}",
92                    actor_in.state,
93                    actor_out.state
94                );
95            }
96
97            if actor_in.code != current_manifest.get(BuiltinActor::VerifiedRegistry)?
98                && actor_in.code != actor_out.code
99            {
100                bail!(
101                    "actor {address} code mismatch: pre-migration: {}, post-migration: {}",
102                    actor_in.code,
103                    actor_out.code
104                );
105            }
106
107            Ok(())
108        })?;
109
110        Ok(())
111    }
112}
113
114/// Runs the migration for `NV22`. Returns the new state root.
115pub fn run_migration<DB>(
116    chain_config: &ChainConfig,
117    blockstore: &Arc<DB>,
118    state: &Cid,
119    epoch: ChainEpoch,
120) -> anyhow::Result<Cid>
121where
122    DB: Blockstore + Send + Sync,
123{
124    assert_eq!(
125        chain_config.network,
126        NetworkChain::Calibnet,
127        "NV22fix only supported on Calibnet"
128    );
129
130    let new_manifest_cid = chain_config
131        .height_infos
132        .get(&Height::DragonFix)
133        .context("no height info for network version NV22")?
134        .bundle
135        .as_ref()
136        .context("no bundle for network version NV22")?;
137
138    blockstore.get(new_manifest_cid)?.context(format!(
139        "manifest for network version NV22fix not found in blockstore: {new_manifest_cid}"
140    ))?;
141
142    // Add migration specification verification
143    let verifier = Arc::new(Verifier::default());
144
145    let new_manifest = BuiltinActorManifest::load_manifest(blockstore, new_manifest_cid)?;
146    let mut migration = StateMigration::<DB>::new(Some(verifier));
147    migration.add_nv22fix_migrations(blockstore, state, &new_manifest)?;
148    migration.add_post_migration_check(Arc::new(PostMigrationVerifier { state_pre: *state }));
149
150    let actors_in = StateTree::new_from_root(blockstore.clone(), state)?;
151    let actors_out = StateTree::new(blockstore.clone(), StateTreeVersion::V5)?;
152    let new_state = migration.migrate_state_tree(blockstore, epoch, actors_in, actors_out)?;
153
154    Ok(new_state)
155}