Skip to main content

forest/state_migration/nv17/
migration.rs

1// Copyright 2019-2026 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use std::sync::Arc;
5
6use crate::networks::{ChainConfig, Height, NetworkChain};
7use crate::shim::{
8    address::Address,
9    clock::ChainEpoch,
10    machine::{BuiltinActor, BuiltinActorManifest},
11    state_tree::{StateTree, StateTreeVersion},
12};
13use crate::utils::db::CborStoreExt as _;
14use anyhow::anyhow;
15use cid::Cid;
16use fvm_ipld_blockstore::Blockstore;
17use fvm_ipld_encoding::CborStore as _;
18
19use super::super::common::{
20    StateMigration,
21    migrators::{DeferredMigrator, nil_migrator},
22};
23use super::{
24    SystemStateOld, datacap, miner, system, util::get_pending_verified_deals_and_total_size,
25    verifier::Verifier, verifreg_market::VerifregMarketPostMigrator,
26};
27
28impl<BS: Blockstore + Send + Sync> StateMigration<BS> {
29    pub fn add_nv17_migrations(
30        &mut self,
31        store: &Arc<BS>,
32        actors_in: &mut StateTree<BS>,
33        new_manifest: &BuiltinActorManifest,
34        prior_epoch: ChainEpoch,
35        chain: NetworkChain,
36    ) -> anyhow::Result<()> {
37        let system_actor = actors_in
38            .get_actor(&Address::new_id(0))?
39            .ok_or_else(|| anyhow!("system actor not found"))?;
40
41        let system_actor_state: SystemStateOld = store
42            .get_cbor(&system_actor.state)?
43            .ok_or_else(|| anyhow!("system actor state not found"))?;
44        let current_manifest_data = system_actor_state.builtin_actors;
45
46        let current_manifest =
47            BuiltinActorManifest::load_v1_actor_list(store, &current_manifest_data)?;
48
49        let verifreg_actor_v8 = actors_in
50            .get_required_actor(&fil_actors_shared::v8::VERIFIED_REGISTRY_ACTOR_ADDR.into())?;
51
52        let market_actor_v8 = actors_in
53            .get_required_actor(&fil_actors_shared::v8::STORAGE_MARKET_ACTOR_ADDR.into())?;
54
55        let market_state_v8: fil_actor_market_state::v8::State =
56            store.get_cbor_required(&market_actor_v8.state)?;
57
58        let init_actor_v8 =
59            actors_in.get_required_actor(&fil_actors_shared::v8::INIT_ACTOR_ADDR.into())?;
60
61        let init_state_v8: fil_actor_init_state::v8::State =
62            store.get_cbor_required(&init_actor_v8.state)?;
63
64        let (pending_verified_deals, pending_verified_deal_size) =
65            get_pending_verified_deals_and_total_size(&store, &market_state_v8)?;
66
67        for (actor, cid) in current_manifest.builtin_actors() {
68            match actor {
69                BuiltinActor::Market | BuiltinActor::VerifiedRegistry => {
70                    self.add_migrator(cid, Arc::new(DeferredMigrator))
71                }
72                _ => {
73                    let new_code = new_manifest.get(actor)?;
74                    self.add_migrator(cid, nil_migrator(new_code))
75                }
76            }
77        }
78
79        // https://github.com/filecoin-project/go-state-types/blob/1e6cf0d47cdda75383ef036fc2725d1cf51dbde8/builtin/v9/migration/top.go#L178
80        self.add_migrator(
81            current_manifest.get_system(),
82            system::system_migrator(new_manifest),
83        );
84
85        let miner_v8_actor_code = current_manifest.get(BuiltinActor::Miner)?;
86        let miner_v9_actor_code = new_manifest.get(BuiltinActor::Miner)?;
87
88        self.add_migrator(
89            miner_v8_actor_code,
90            miner::miner_migrator(miner_v9_actor_code, store, market_state_v8.proposals, chain)?,
91        );
92
93        let verifreg_state_v8_cid = verifreg_actor_v8.state;
94        let verifreg_state_v8: fil_actor_verifreg_state::v8::State =
95            store.get_cbor_required(&verifreg_state_v8_cid)?;
96        let verifreg_code = new_manifest.get(BuiltinActor::VerifiedRegistry)?;
97        let market_code = new_manifest.get(BuiltinActor::Market)?;
98
99        self.add_post_migrator(Arc::new(VerifregMarketPostMigrator {
100            prior_epoch,
101            init_state_v8,
102            market_state_v8,
103            verifreg_state_v8,
104            pending_verified_deals,
105            verifreg_actor_v8,
106            market_actor_v8,
107            verifreg_code,
108            market_code,
109        }));
110
111        // Note: The `datacap` actor is handled specially in Go code,
112        // by setting up an empty actor to migrate from with a migrator,
113        // while forest uses a post migrator to simplify the logic.
114        self.add_post_migrator(Arc::new(datacap::DataCapPostMigrator {
115            new_code_cid: new_manifest.get(BuiltinActor::DataCap)?,
116            verifreg_state: store.get_cbor_required(&verifreg_state_v8_cid)?,
117            pending_verified_deal_size,
118        }));
119
120        Ok(())
121    }
122}
123
124/// Runs the migration for `NV17`. Returns the new state root.
125pub fn run_migration<DB>(
126    chain_config: &ChainConfig,
127    blockstore: &Arc<DB>,
128    state: &Cid,
129    epoch: ChainEpoch,
130) -> anyhow::Result<Cid>
131where
132    DB: Blockstore + Send + Sync,
133{
134    let new_manifest_cid = chain_config
135        .height_infos
136        .get(&Height::Shark)
137        .ok_or_else(|| anyhow!("no height info for network version NV17"))?
138        .bundle
139        .as_ref()
140        .ok_or_else(|| anyhow!("no bundle info for network version NV17"))?;
141
142    blockstore.get(new_manifest_cid)?.ok_or_else(|| {
143        anyhow!(
144            "manifest for network version NV17 not found in blockstore: {}",
145            new_manifest_cid
146        )
147    })?;
148
149    let new_manifest = BuiltinActorManifest::load_manifest(blockstore, new_manifest_cid)?;
150
151    let mut actors_in = StateTree::new_from_root(blockstore.clone(), state)?;
152
153    // Add migration specification verification
154    let verifier = Arc::new(Verifier::default());
155
156    let mut migration = StateMigration::<DB>::new(Some(verifier));
157    migration.add_nv17_migrations(
158        blockstore,
159        &mut actors_in,
160        &new_manifest,
161        epoch,
162        chain_config.network.clone(),
163    )?;
164
165    let actors_out = StateTree::new(blockstore.clone(), StateTreeVersion::V4)?;
166
167    let new_state = migration.migrate_state_tree(blockstore, epoch, actors_in, actors_out)?;
168
169    Ok(new_state)
170}