forest/shim/
sector.rs

1// Copyright 2019-2025 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use crate::shim::version::NetworkVersion;
5use anyhow::bail;
6use cid::Cid;
7use fvm_ipld_encoding::repr::{Deserialize_repr, Serialize_repr};
8use fvm_shared2::sector::{
9    PoStProof as PoStProofV2, RegisteredPoStProof as RegisteredPoStProofV2,
10    RegisteredSealProof as RegisteredSealProofV2, SectorInfo as SectorInfoV2,
11    SectorSize as SectorSizeV2,
12};
13pub use fvm_shared3::sector::{
14    RegisteredPoStProof as RegisteredPoStProofV3, RegisteredSealProof as RegisteredSealProofV3,
15    SectorSize as SectorSizeV3, StoragePower,
16};
17pub use fvm_shared4::sector::{
18    PoStProof as PoStProofV4, RegisteredPoStProof as RegisteredPoStProofV4,
19    RegisteredSealProof as RegisteredSealProofV4, SectorInfo as SectorInfoV4,
20    SectorSize as SectorSizeV4,
21};
22use get_size2::GetSize;
23use num_derive::FromPrimitive;
24use serde::{Deserialize, Serialize};
25use std::hash::{Hash, Hasher};
26use std::ops::Deref;
27
28pub type SectorNumber = fvm_shared4::sector::SectorNumber;
29
30/// Represents a shim over `RegisteredSealProof` from `fvm_shared` with
31/// convenience methods to convert to an older version of the type
32///
33/// # Examples
34/// ```
35/// # use forest::doctest_private::RegisteredSealProof;
36/// // Create FVM2 RegisteredSealProof normally
37/// let fvm2_proof = fvm_shared2::sector::RegisteredSealProof::StackedDRG2KiBV1;
38///
39/// // Create a correspndoning FVM3 RegisteredSealProof
40/// let fvm3_proof = fvm_shared3::sector::RegisteredSealProof::StackedDRG2KiBV1;
41///
42/// // Create a correspndoning FVM4 RegisteredSealProof
43/// let fvm4_proof = fvm_shared4::sector::RegisteredSealProof::StackedDRG2KiBV1;
44///
45/// // Create a shim out of fvm2 proof, ensure conversions are correct
46/// let proof_shim = RegisteredSealProof::from(fvm2_proof);
47/// assert_eq!(fvm4_proof, *proof_shim);
48/// assert_eq!(fvm3_proof, proof_shim.into());
49/// assert_eq!(fvm2_proof, proof_shim.into());
50/// ```
51#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Eq, PartialEq, Debug)]
52pub struct RegisteredSealProof(RegisteredSealProofV4);
53
54impl RegisteredSealProof {
55    pub fn from_sector_size(size: SectorSize, network_version: NetworkVersion) -> Self {
56        RegisteredSealProof(RegisteredSealProofV4::from_sector_size(
57            size.into(),
58            network_version.into(),
59        ))
60    }
61
62    pub fn registered_winning_post_proof(self) -> anyhow::Result<RegisteredPoStProofV4> {
63        use fvm_shared4::sector::RegisteredPoStProof as PoStProof;
64        use fvm_shared4::sector::RegisteredSealProof as SealProof;
65        match self.0 {
66            SealProof::StackedDRG64GiBV1
67            | SealProof::StackedDRG64GiBV1P1
68            | SealProof::StackedDRG64GiBV1P1_Feat_SyntheticPoRep
69            | SealProof::StackedDRG64GiBV1P2_Feat_NiPoRep => {
70                Ok(PoStProof::StackedDRGWinning64GiBV1)
71            }
72            SealProof::StackedDRG32GiBV1
73            | SealProof::StackedDRG32GiBV1P1
74            | SealProof::StackedDRG32GiBV1P1_Feat_SyntheticPoRep
75            | SealProof::StackedDRG32GiBV1P2_Feat_NiPoRep => {
76                Ok(PoStProof::StackedDRGWinning32GiBV1)
77            }
78            SealProof::StackedDRG2KiBV1
79            | SealProof::StackedDRG2KiBV1P1
80            | SealProof::StackedDRG2KiBV1P1_Feat_SyntheticPoRep
81            | SealProof::StackedDRG2KiBV1P2_Feat_NiPoRep => Ok(PoStProof::StackedDRGWinning2KiBV1),
82            SealProof::StackedDRG8MiBV1
83            | SealProof::StackedDRG8MiBV1P1
84            | SealProof::StackedDRG8MiBV1P1_Feat_SyntheticPoRep
85            | SealProof::StackedDRG8MiBV1P2_Feat_NiPoRep => Ok(PoStProof::StackedDRGWinning8MiBV1),
86            SealProof::StackedDRG512MiBV1
87            | SealProof::StackedDRG512MiBV1P1
88            | SealProof::StackedDRG512MiBV1P1_Feat_SyntheticPoRep
89            | SealProof::StackedDRG512MiBV1P2_Feat_NiPoRep => {
90                Ok(PoStProof::StackedDRGWinning512MiBV1)
91            }
92            SealProof::Invalid(_) => bail!(
93                "Unsupported mapping from {:?} to PoSt-winning RegisteredProof",
94                self
95            ),
96        }
97    }
98}
99
100impl Deref for RegisteredSealProof {
101    type Target = RegisteredSealProofV4;
102    fn deref(&self) -> &Self::Target {
103        &self.0
104    }
105}
106
107impl From<i64> for RegisteredSealProof {
108    fn from(value: i64) -> Self {
109        RegisteredSealProof(RegisteredSealProofV4::from(value))
110    }
111}
112
113macro_rules! registered_seal_proof_conversion {
114    ($($internal:ty),+) => {
115        $(
116            impl From<$internal> for RegisteredSealProof {
117                fn from(value: $internal) -> Self {
118                    let num_id: i64 = value.into();
119                    RegisteredSealProof::from(num_id)
120                }
121            }
122            impl From<RegisteredSealProof> for $internal {
123                fn from(value: RegisteredSealProof) -> $internal {
124                    let num_id: i64 = value.0.into();
125                    <$internal>::from(num_id)
126                }
127            }
128        )+
129    };
130}
131
132registered_seal_proof_conversion!(
133    RegisteredSealProofV2,
134    RegisteredSealProofV3,
135    RegisteredSealProofV4
136);
137
138impl RegisteredSealProof {
139    pub fn invalid() -> Self {
140        RegisteredSealProof(RegisteredSealProofV4::Invalid(0))
141    }
142}
143
144#[cfg(test)]
145impl quickcheck::Arbitrary for RegisteredSealProof {
146    fn arbitrary(g: &mut quickcheck::Gen) -> Self {
147        Self(i64::arbitrary(g).into())
148    }
149}
150
151/// Represents a shim over `SectorInfo` from `fvm_shared` with convenience
152/// methods to convert to an older version of the type
153#[derive(
154    Eq, PartialEq, Debug, Clone, derive_more::From, derive_more::Into, Serialize, Deserialize,
155)]
156pub struct SectorInfo(SectorInfoV4);
157
158#[cfg(test)]
159impl quickcheck::Arbitrary for SectorInfo {
160    fn arbitrary(g: &mut quickcheck::Gen) -> Self {
161        Self(SectorInfoV4 {
162            proof: RegisteredSealProof::arbitrary(g).into(),
163            sector_number: u64::arbitrary(g),
164            sealed_cid: cid::Cid::arbitrary(g),
165        })
166    }
167}
168
169impl SectorInfo {
170    pub fn new(
171        proof: RegisteredSealProofV4,
172        sector_number: SectorNumber,
173        sealed_cid: cid::Cid,
174    ) -> Self {
175        SectorInfo(SectorInfoV4 {
176            proof,
177            sector_number,
178            sealed_cid,
179        })
180    }
181}
182
183impl Deref for SectorInfo {
184    type Target = SectorInfoV4;
185    fn deref(&self) -> &Self::Target {
186        &self.0
187    }
188}
189
190impl From<SectorInfo> for SectorInfoV2 {
191    fn from(value: SectorInfo) -> SectorInfoV2 {
192        SectorInfoV2 {
193            proof: RegisteredSealProof(value.0.proof).into(),
194            sealed_cid: value.sealed_cid,
195            sector_number: value.sector_number,
196        }
197    }
198}
199
200/// Information about a sector necessary for PoSt verification
201#[derive(
202    Eq, PartialEq, Debug, Clone, derive_more::From, derive_more::Into, Serialize, Deserialize,
203)]
204pub struct ExtendedSectorInfo {
205    pub proof: RegisteredSealProof,
206    pub sector_number: SectorNumber,
207    pub sector_key: Option<Cid>,
208    pub sealed_cid: Cid,
209}
210
211impl From<&ExtendedSectorInfo> for SectorInfo {
212    fn from(value: &ExtendedSectorInfo) -> SectorInfo {
213        SectorInfo::new(value.proof.into(), value.sector_number, value.sealed_cid)
214    }
215}
216
217#[cfg(test)]
218impl quickcheck::Arbitrary for ExtendedSectorInfo {
219    fn arbitrary(g: &mut quickcheck::Gen) -> Self {
220        Self {
221            proof: RegisteredSealProof::arbitrary(g),
222            sector_number: u64::arbitrary(g),
223            sector_key: Option::<cid::Cid>::arbitrary(g),
224            sealed_cid: cid::Cid::arbitrary(g),
225        }
226    }
227}
228
229#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq, derive_more::Into)]
230pub struct RegisteredPoStProof(RegisteredPoStProofV4);
231
232#[cfg(test)]
233impl quickcheck::Arbitrary for RegisteredPoStProof {
234    fn arbitrary(g: &mut quickcheck::Gen) -> Self {
235        Self(RegisteredPoStProofV4::from(i64::arbitrary(g)))
236    }
237}
238
239impl Deref for RegisteredPoStProof {
240    type Target = RegisteredPoStProofV4;
241    fn deref(&self) -> &Self::Target {
242        &self.0
243    }
244}
245
246impl TryFrom<RegisteredPoStProof> for fil_actors_shared::filecoin_proofs_api::RegisteredPoStProof {
247    type Error = anyhow::Error;
248
249    fn try_from(value: RegisteredPoStProof) -> Result<Self, Self::Error> {
250        value.0.try_into().map_err(|e: String| anyhow::anyhow!(e))
251    }
252}
253
254impl From<i64> for RegisteredPoStProof {
255    fn from(value: i64) -> Self {
256        RegisteredPoStProof(RegisteredPoStProofV4::from(value))
257    }
258}
259
260impl From<RegisteredPoStProofV2> for RegisteredPoStProof {
261    fn from(value: RegisteredPoStProofV2) -> RegisteredPoStProof {
262        let num_id: i64 = value.into();
263        RegisteredPoStProof(RegisteredPoStProofV4::from(num_id))
264    }
265}
266
267impl From<RegisteredPoStProofV3> for RegisteredPoStProof {
268    fn from(value: RegisteredPoStProofV3) -> RegisteredPoStProof {
269        let num_id: i64 = value.into();
270        RegisteredPoStProof(RegisteredPoStProofV4::from(num_id))
271    }
272}
273
274impl From<RegisteredPoStProofV4> for RegisteredPoStProof {
275    fn from(value: RegisteredPoStProofV4) -> RegisteredPoStProof {
276        RegisteredPoStProof(value)
277    }
278}
279
280impl From<RegisteredPoStProof> for RegisteredPoStProofV3 {
281    fn from(value: RegisteredPoStProof) -> RegisteredPoStProofV3 {
282        let num_id: i64 = value.0.into();
283        RegisteredPoStProofV3::from(num_id)
284    }
285}
286
287impl From<RegisteredPoStProof> for RegisteredPoStProofV2 {
288    fn from(value: RegisteredPoStProof) -> RegisteredPoStProofV2 {
289        let num_id: i64 = value.0.into();
290        RegisteredPoStProofV2::from(num_id)
291    }
292}
293
294/// `SectorSize` indicates one of a set of possible sizes in the network.
295#[derive(Clone, Debug, PartialEq, Eq, Copy, FromPrimitive, Serialize_repr, Deserialize_repr)]
296#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
297#[repr(u64)]
298pub enum SectorSize {
299    _2KiB = 2 << 10,
300    _8MiB = 8 << 20,
301    _512MiB = 512 << 20,
302    _32GiB = 32 << 30,
303    _64GiB = 2 * (32 << 30),
304}
305
306macro_rules! sector_size_conversion {
307    ($($internal:ty),+) => {
308        $(
309            impl From<$internal> for SectorSize {
310                fn from(value: $internal) -> Self {
311                    match value {
312                        <$internal>::_2KiB => SectorSize::_2KiB,
313                        <$internal>::_8MiB => SectorSize::_8MiB,
314                        <$internal>::_512MiB => SectorSize::_512MiB,
315                        <$internal>::_32GiB => SectorSize::_32GiB,
316                        <$internal>::_64GiB => SectorSize::_64GiB,
317                    }
318                }
319            }
320            impl From<SectorSize> for $internal {
321                fn from(value: SectorSize) -> $internal {
322                    match value {
323                        SectorSize::_2KiB => <$internal>::_2KiB,
324                        SectorSize::_8MiB => <$internal>::_8MiB,
325                        SectorSize::_512MiB => <$internal>::_512MiB,
326                        SectorSize::_32GiB => <$internal>::_32GiB,
327                        SectorSize::_64GiB => <$internal>::_64GiB,
328                    }
329                }
330            }
331        )+
332    };
333}
334
335sector_size_conversion!(SectorSizeV2, SectorSizeV3, SectorSizeV4);
336
337#[derive(
338    serde::Serialize,
339    serde::Deserialize,
340    Clone,
341    Debug,
342    PartialEq,
343    derive_more::From,
344    derive_more::Into,
345    Eq,
346)]
347#[cfg_attr(test, derive(derive_quickcheck_arbitrary::Arbitrary))]
348pub struct PoStProof(PoStProofV4);
349
350impl Hash for PoStProof {
351    fn hash<H: Hasher>(&self, state: &mut H) {
352        let PoStProofV4 {
353            post_proof,
354            proof_bytes,
355        } = &self.0;
356        post_proof.hash(state);
357        proof_bytes.hash(state);
358    }
359}
360
361impl PoStProof {
362    pub fn new(reg_post_proof: RegisteredPoStProof, proof_bytes: Vec<u8>) -> Self {
363        PoStProof(PoStProofV4 {
364            post_proof: *reg_post_proof,
365            proof_bytes,
366        })
367    }
368}
369
370impl Deref for PoStProof {
371    type Target = PoStProofV4;
372
373    fn deref(&self) -> &Self::Target {
374        &self.0
375    }
376}
377
378impl From<PoStProofV2> for PoStProof {
379    fn from(value: PoStProofV2) -> PoStProof {
380        PoStProof(PoStProofV4 {
381            post_proof: *RegisteredPoStProof::from(value.post_proof),
382            proof_bytes: value.proof_bytes,
383        })
384    }
385}
386
387impl GetSize for PoStProof {
388    fn get_heap_size(&self) -> usize {
389        self.0.proof_bytes.get_heap_size()
390    }
391}
392
393pub fn convert_window_post_proof_v1_to_v1p1(
394    rpp: RegisteredPoStProofV3,
395) -> anyhow::Result<RegisteredPoStProofV3> {
396    match rpp {
397        RegisteredPoStProofV3::StackedDRGWindow2KiBV1
398        | RegisteredPoStProofV3::StackedDRGWindow2KiBV1P1 => {
399            Ok(RegisteredPoStProofV3::StackedDRGWindow2KiBV1P1)
400        }
401        RegisteredPoStProofV3::StackedDRGWindow8MiBV1
402        | RegisteredPoStProofV3::StackedDRGWindow8MiBV1P1 => {
403            Ok(RegisteredPoStProofV3::StackedDRGWindow8MiBV1P1)
404        }
405        RegisteredPoStProofV3::StackedDRGWindow512MiBV1
406        | RegisteredPoStProofV3::StackedDRGWindow512MiBV1P1 => {
407            Ok(RegisteredPoStProofV3::StackedDRGWindow512MiBV1P1)
408        }
409        RegisteredPoStProofV3::StackedDRGWindow32GiBV1
410        | RegisteredPoStProofV3::StackedDRGWindow32GiBV1P1 => {
411            Ok(RegisteredPoStProofV3::StackedDRGWindow32GiBV1P1)
412        }
413        RegisteredPoStProofV3::StackedDRGWindow64GiBV1
414        | RegisteredPoStProofV3::StackedDRGWindow64GiBV1P1 => {
415            Ok(RegisteredPoStProofV3::StackedDRGWindow64GiBV1P1)
416        }
417        other => anyhow::bail!("Invalid proof type: {other:?}"),
418    }
419}
420
421#[cfg(test)]
422mod tests {
423    #[test]
424    fn sector_size_ser_deser() {
425        let orig_sector_size = fvm_shared3::sector::SectorSize::_2KiB;
426        let orig_json_repr = serde_json::to_string(&orig_sector_size).unwrap();
427
428        let shimmed_sector_size = crate::shim::sector::SectorSize::_2KiB;
429        let shimmed_json_repr = serde_json::to_string(&shimmed_sector_size).unwrap();
430
431        assert_eq!(orig_json_repr, shimmed_json_repr);
432
433        let shimmed_deser: crate::shim::sector::SectorSize =
434            serde_json::from_str(&shimmed_json_repr).unwrap();
435        let orig_deser: fvm_shared3::sector::SectorSize =
436            serde_json::from_str(&orig_json_repr).unwrap();
437
438        assert_eq!(shimmed_deser as u64, orig_deser as u64);
439    }
440}