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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright 2019-2024 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

use super::*;

use crate::{
    rpc::types::AddressOrEmpty,
    shim::{address::Address, clock::ChainEpoch, sector::SectorSize},
};
use fil_actor_interface::miner::MinerInfo;
use fil_actor_miner_state::v12::{BeneficiaryTerm, PendingBeneficiaryChange};
use fvm_ipld_encoding::BytesDe;
use libp2p::PeerId;

#[derive(Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "PascalCase")]
#[schemars(rename = "MinerInfo")]
pub struct MinerInfoLotusJson {
    #[schemars(with = "LotusJson<Address>")]
    #[serde(with = "crate::lotus_json")]
    pub owner: Address,
    #[schemars(with = "LotusJson<Address>")]
    #[serde(with = "crate::lotus_json")]
    pub worker: Address,
    #[schemars(with = "LotusJson<Option<Address>>")]
    pub new_worker: AddressOrEmpty,
    #[schemars(with = "LotusJson<Vec<Address>>")]
    #[serde(with = "crate::lotus_json")]
    pub control_addresses: Vec<Address>, // Must all be ID addresses.
    pub worker_change_epoch: ChainEpoch,
    #[schemars(with = "LotusJson<Option<String>>")]
    #[serde(with = "crate::lotus_json")]
    pub peer_id: Option<String>,
    #[schemars(with = "LotusJson<Vec<Vec<u8>>>")]
    #[serde(with = "crate::lotus_json")]
    pub multiaddrs: Vec<Vec<u8>>,
    #[schemars(with = "String")]
    pub window_po_st_proof_type: fvm_shared2::sector::RegisteredPoStProof,
    #[schemars(with = "LotusJson<SectorSize>")]
    #[serde(with = "crate::lotus_json")]
    pub sector_size: SectorSize,
    pub window_po_st_partition_sectors: u64,
    pub consensus_fault_elapsed: ChainEpoch,
    #[schemars(with = "LotusJson<Option<Address>>")]
    #[serde(with = "crate::lotus_json")]
    pub pending_owner_address: Option<Address>,
    #[schemars(with = "LotusJson<Address>")]
    #[serde(with = "crate::lotus_json")]
    pub beneficiary: Address,
    #[schemars(with = "LotusJson<BeneficiaryTerm>")]
    #[serde(with = "crate::lotus_json")]
    pub beneficiary_term: BeneficiaryTerm,
    #[schemars(with = "LotusJson<Option<PendingBeneficiaryChange>>")]
    #[serde(with = "crate::lotus_json")]
    pub pending_beneficiary_term: Option<PendingBeneficiaryChange>,
}

impl HasLotusJson for MinerInfo {
    type LotusJson = MinerInfoLotusJson;
    #[cfg(test)]
    fn snapshots() -> Vec<(serde_json::Value, Self)> {
        vec![(
            json!({
                "Beneficiary": "f00",
                "BeneficiaryTerm": {
                    "Expiration": 0,
                    "Quota": "0",
                    "UsedQuota": "0"
                },
                "ConsensusFaultElapsed": 0,
                "ControlAddresses": null,
                "Multiaddrs": null,
                "NewWorker": "<empty>",
                "Owner": "f00",
                "PeerId": null,
                "PendingBeneficiaryTerm": null,
                "PendingOwnerAddress": null,
                "SectorSize": 2048,
                "WindowPoStPartitionSectors": 0,
                "WindowPoStProofType": 0,
                "Worker": "f00",
                "WorkerChangeEpoch": 0
            }),
            Self {
                owner: Address::default().into(),
                worker: Address::default().into(),
                new_worker: Default::default(),
                control_addresses: Default::default(),
                worker_change_epoch: Default::default(),
                peer_id: Default::default(),
                multiaddrs: Default::default(),
                window_post_proof_type:
                    fvm_shared2::sector::RegisteredPoStProof::StackedDRGWinning2KiBV1,
                sector_size: crate::shim::sector::SectorSize::_2KiB.into(),
                window_post_partition_sectors: Default::default(),
                consensus_fault_elapsed: Default::default(),
                pending_owner_address: Default::default(),
                beneficiary: Address::default().into(),
                beneficiary_term: Default::default(),
                pending_beneficiary_term: Default::default(),
            },
        )]
    }
    fn into_lotus_json(self) -> Self::LotusJson {
        MinerInfoLotusJson {
            owner: self.owner.into(),
            worker: self.worker.into(),
            new_worker: AddressOrEmpty(self.new_worker.map(|addr| addr.into())),
            control_addresses: self
                .control_addresses
                .into_iter()
                .map(|a| a.into())
                .collect(),
            worker_change_epoch: self.worker_change_epoch,
            peer_id: PeerId::try_from(self.peer_id).map(|id| id.to_base58()).ok(),
            multiaddrs: self.multiaddrs.into_iter().map(|addr| addr.0).collect(),
            window_po_st_proof_type: self.window_post_proof_type,
            sector_size: self.sector_size.into(),
            window_po_st_partition_sectors: self.window_post_partition_sectors,
            consensus_fault_elapsed: self.consensus_fault_elapsed,
            // NOTE: In Lotus this field is never set for any of the versions, so we have to ignore
            // it too.
            // See: <https://github.com/filecoin-project/lotus/blob/b6a77dfafcf0110e95840fca15a775ed663836d8/chain/actors/builtin/miner/v12.go#L370>.
            pending_owner_address: None,
            beneficiary: self.beneficiary.into(),
            beneficiary_term: self.beneficiary_term,
            pending_beneficiary_term: self.pending_beneficiary_term,
        }
    }
    fn from_lotus_json(lotus_json: Self::LotusJson) -> Self {
        MinerInfo {
            owner: lotus_json.owner.into(),
            worker: lotus_json.worker.into(),
            new_worker: lotus_json.new_worker.0.map(|addr| addr.into()),
            control_addresses: lotus_json
                .control_addresses
                .into_iter()
                .map(|a| a.into())
                .collect(),
            worker_change_epoch: lotus_json.worker_change_epoch,
            peer_id: lotus_json.peer_id.map_or_else(Vec::new, |s| s.into_bytes()),
            multiaddrs: lotus_json.multiaddrs.into_iter().map(BytesDe).collect(),
            window_post_proof_type: lotus_json.window_po_st_proof_type,
            sector_size: lotus_json.sector_size.into(),
            window_post_partition_sectors: lotus_json.window_po_st_partition_sectors,
            consensus_fault_elapsed: lotus_json.consensus_fault_elapsed,
            // Ignore this field as it is never set on Lotus side.
            pending_owner_address: None,
            beneficiary: lotus_json.beneficiary.into(),
            beneficiary_term: lotus_json.beneficiary_term,
            pending_beneficiary_term: lotus_json.pending_beneficiary_term,
        }
    }
}

#[test]
fn snapshots() {
    assert_all_snapshots::<MinerInfo>();
}