Skip to main content

forest/state_migration/nv22fix/
migration.rs

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