forest/state_migration/nv21fix2/
migration.rs

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