Skip to main content

forest/state_migration/nv21fix2/
migration.rs

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