forest/state_migration/nv17/
datacap.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 `NV17` upgrade for the `datacap`
5//! actor.
6
7use crate::shim::address::Address;
8use crate::shim::bigint::BigInt;
9use crate::shim::state_tree::{ActorState, StateTree};
10use crate::shim::{econ::TokenAmount, sector::StoragePower};
11use crate::state_migration::common::PostMigrator;
12use crate::utils::db::CborStoreExt;
13use cid::Cid;
14use fil_actors_shared::frc46_token::token::state::TokenState;
15use fil_actors_shared::fvm_ipld_hamt::BytesKey;
16use fvm_ipld_blockstore::Blockstore;
17use num_traits::Zero;
18use std::ops::Deref;
19use std::str::FromStr;
20use std::sync::LazyLock;
21
22use super::util::hamt_addr_key_to_key;
23
24const DATA_CAP_GRANULARITY: u64 = TokenAmount::PRECISION;
25static INFINITE_ALLOWANCE: LazyLock<StoragePower> = LazyLock::new(|| {
26    StoragePower::from_str("1000000000000000000000").expect("Failed to parse INFINITE_ALLOWANCE")
27        * TokenAmount::PRECISION
28});
29
30pub(super) struct DataCapPostMigrator {
31    pub(super) new_code_cid: Cid,
32    pub(super) verifreg_state: fil_actor_verifreg_state::v8::State,
33    pub(super) pending_verified_deal_size: u64,
34}
35
36impl<BS: Blockstore> PostMigrator<BS> for DataCapPostMigrator {
37    fn post_migrate_state(&self, store: &BS, actors_out: &mut StateTree<BS>) -> anyhow::Result<()> {
38        use fil_actors_shared::v9::builtin::HAMT_BIT_WIDTH;
39
40        let verified_clients = fil_actors_shared::v8::make_map_with_root::<BS, BigInt>(
41            &self.verifreg_state.verified_clients,
42            store,
43        )?;
44
45        let mut token_supply: num_bigint::BigInt = Zero::zero();
46
47        let mut balances_map =
48            fil_actors_shared::v9::make_empty_map::<BS, BigInt>(store, HAMT_BIT_WIDTH);
49
50        let mut allowances_map = fil_actors_shared::v9::make_empty_map(store, HAMT_BIT_WIDTH);
51
52        verified_clients.for_each(|addr_key, value| {
53            let key = hamt_addr_key_to_key(addr_key)?;
54            let token_amount = value.deref() * DATA_CAP_GRANULARITY;
55            token_supply = &token_supply + &token_amount;
56            balances_map.set(key.clone(), token_amount.into())?;
57
58            let mut allowances_map_entry =
59                fil_actors_shared::v9::make_empty_map::<BS, BigInt>(store, HAMT_BIT_WIDTH);
60            allowances_map_entry.set(
61                BytesKey(fil_actors_shared::v9::builtin::STORAGE_MARKET_ACTOR_ADDR.payload_bytes()),
62                INFINITE_ALLOWANCE.clone().into(),
63            )?;
64            allowances_map.set(key, allowances_map_entry.flush()?)?;
65            Ok(())
66        })?;
67
68        let verifreg_balance =
69            StoragePower::from(self.pending_verified_deal_size) * DATA_CAP_GRANULARITY;
70        token_supply = &token_supply + &verifreg_balance;
71        balances_map.set(
72            BytesKey(fil_actors_shared::v9::builtin::VERIFIED_REGISTRY_ACTOR_ADDR.payload_bytes()),
73            verifreg_balance.into(),
74        )?;
75
76        let mut token = TokenState::new_with_bit_width(store, HAMT_BIT_WIDTH)?;
77        token.supply = TokenAmount::from_atto(token_supply).into();
78        token.balances = balances_map.flush()?;
79        token.allowances = allowances_map.flush()?;
80
81        let datacap_state = fil_actor_datacap_state::v9::State {
82            governor: fil_actors_shared::v9::builtin::VERIFIED_REGISTRY_ACTOR_ADDR,
83            token,
84        };
85
86        let new_head = store.put_cbor_default(&datacap_state)?;
87
88        actors_out.set_actor(
89            &Address::DATACAP_TOKEN_ACTOR,
90            ActorState::new(
91                self.new_code_cid,
92                new_head,
93                Zero::zero(),
94                0,
95                None, // ActorV4 contains no delegated address
96            ),
97        )
98    }
99}