1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Copyright 2019-2024 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

//! This module contains the migration logic for the `NV17` upgrade for the `datacap`
//! actor.

use std::str::FromStr;

use crate::shim::address::Address;
use crate::shim::bigint::BigInt;
use crate::shim::state_tree::{ActorState, StateTree};
use crate::shim::{econ::TokenAmount, sector::StoragePower};
use crate::state_migration::common::PostMigrator;
use crate::utils::db::CborStoreExt;
use cid::Cid;
use fil_actors_shared::frc46_token::token::state::TokenState;
use fil_actors_shared::fvm_ipld_hamt::BytesKey;
use fvm_ipld_blockstore::Blockstore;
use num_traits::Zero;
use once_cell::sync::Lazy;
use std::ops::Deref;

use super::util::hamt_addr_key_to_key;

const DATA_CAP_GRANULARITY: u64 = TokenAmount::PRECISION;
static INFINITE_ALLOWANCE: Lazy<StoragePower> = Lazy::new(|| {
    StoragePower::from_str("1000000000000000000000").expect("Failed to parse INFINITE_ALLOWANCE")
        * TokenAmount::PRECISION
});

pub(super) struct DataCapPostMigrator {
    pub(super) new_code_cid: Cid,
    pub(super) verifreg_state: fil_actor_verifreg_state::v8::State,
    pub(super) pending_verified_deal_size: u64,
}

impl<BS: Blockstore> PostMigrator<BS> for DataCapPostMigrator {
    fn post_migrate_state(&self, store: &BS, actors_out: &mut StateTree<BS>) -> anyhow::Result<()> {
        use fil_actors_shared::v9::builtin::HAMT_BIT_WIDTH;

        let verified_clients = fil_actors_shared::v8::make_map_with_root::<BS, BigInt>(
            &self.verifreg_state.verified_clients,
            store,
        )?;

        let mut token_supply: num_bigint::BigInt = Zero::zero();

        let mut balances_map =
            fil_actors_shared::v9::make_empty_map::<BS, BigInt>(store, HAMT_BIT_WIDTH);

        let mut allowances_map = fil_actors_shared::v9::make_empty_map(store, HAMT_BIT_WIDTH);

        verified_clients.for_each(|addr_key, value| {
            let key = hamt_addr_key_to_key(addr_key)?;
            let token_amount = value.deref() * DATA_CAP_GRANULARITY;
            token_supply = &token_supply + &token_amount;
            balances_map.set(key.clone(), token_amount.into())?;

            let mut allowances_map_entry =
                fil_actors_shared::v9::make_empty_map::<BS, BigInt>(store, HAMT_BIT_WIDTH);
            allowances_map_entry.set(
                BytesKey(fil_actors_shared::v9::builtin::STORAGE_MARKET_ACTOR_ADDR.payload_bytes()),
                INFINITE_ALLOWANCE.clone().into(),
            )?;
            allowances_map.set(key, allowances_map_entry.flush()?)?;
            Ok(())
        })?;

        let verifreg_balance =
            StoragePower::from(self.pending_verified_deal_size) * DATA_CAP_GRANULARITY;
        token_supply = &token_supply + &verifreg_balance;
        balances_map.set(
            BytesKey(fil_actors_shared::v9::builtin::VERIFIED_REGISTRY_ACTOR_ADDR.payload_bytes()),
            verifreg_balance.into(),
        )?;

        let mut token = TokenState::new_with_bit_width(store, HAMT_BIT_WIDTH)?;
        token.supply = TokenAmount::from_atto(token_supply).into();
        token.balances = balances_map.flush()?;
        token.allowances = allowances_map.flush()?;

        let datacap_state = fil_actor_datacap_state::v9::State {
            governor: fil_actors_shared::v9::builtin::VERIFIED_REGISTRY_ACTOR_ADDR,
            token,
        };

        let new_head = store.put_cbor_default(&datacap_state)?;

        actors_out.set_actor(
            &Address::DATACAP_TOKEN_ACTOR,
            ActorState::new(
                self.new_code_cid,
                new_head,
                Zero::zero(),
                0,
                None, // ActorV4 contains no delegated address
            ),
        )
    }
}