forest/chain/
snapshot_format.rs

1// Copyright 2019-2025 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use crate::lotus_json::lotus_json_with_self;
5use cid::Cid;
6use itertools::Itertools as _;
7use num::FromPrimitive as _;
8use num_derive::FromPrimitive;
9use nunny::Vec as NonEmpty;
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Copy, clap::ValueEnum, FromPrimitive, Clone, PartialEq, Eq, JsonSchema)]
14#[repr(u64)]
15pub enum FilecoinSnapshotVersion {
16    V1 = 1,
17    V2 = 2,
18}
19lotus_json_with_self!(FilecoinSnapshotVersion);
20
21impl Serialize for FilecoinSnapshotVersion {
22    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
23    where
24        S: serde::Serializer,
25    {
26        serializer.serialize_u64(*self as u64)
27    }
28}
29
30impl<'de> Deserialize<'de> for FilecoinSnapshotVersion {
31    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
32    where
33        D: serde::Deserializer<'de>,
34    {
35        let i = u64::deserialize(deserializer)?;
36        match FilecoinSnapshotVersion::from_u64(i) {
37            Some(v) => Ok(v),
38            None => Err(serde::de::Error::custom(format!(
39                "invalid snapshot version {i}"
40            ))),
41        }
42    }
43}
44
45/// Defined in <https://github.com/filecoin-project/FIPs/blob/98e33b9fa306959aa0131519eb4cc155522b2081/FRCs/frc-0108.md#snapshotmetadata>
46#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
47#[serde(rename_all = "PascalCase")]
48pub struct FilecoinSnapshotMetadata {
49    /// Snapshot version
50    pub version: FilecoinSnapshotVersion,
51    /// Chain head tipset key
52    pub head_tipset_key: NonEmpty<Cid>,
53    /// F3 snapshot `CID`
54    pub f3_data: Option<Cid>,
55}
56
57impl FilecoinSnapshotMetadata {
58    pub fn new(
59        version: FilecoinSnapshotVersion,
60        head_tipset_key: NonEmpty<Cid>,
61        f3_data: Option<Cid>,
62    ) -> Self {
63        Self {
64            version,
65            head_tipset_key,
66            f3_data,
67        }
68    }
69
70    pub fn new_v2(head_tipset_key: NonEmpty<Cid>, f3_data: Option<Cid>) -> Self {
71        Self::new(FilecoinSnapshotVersion::V2, head_tipset_key, f3_data)
72    }
73}
74
75impl std::fmt::Display for FilecoinSnapshotMetadata {
76    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
77        writeln!(f, "Snapshot version:           {}", self.version as u64)?;
78        let head_tipset_key_string = self
79            .head_tipset_key
80            .iter()
81            .map(Cid::to_string)
82            .join("\n                            ");
83        writeln!(f, "Head Tipset:                {head_tipset_key_string}")?;
84        write!(
85            f,
86            "F3 data:                    {}",
87            self.f3_data
88                .map(|c| c.to_string())
89                .unwrap_or_else(|| "not found".into())
90        )?;
91        Ok(())
92    }
93}