iota_genesis_builder/stardust/types/
snapshot.rs

1// Copyright (c) 2024 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use iota_sdk::types::block::{
5    payload::milestone::{MilestoneId, MilestoneIndex, MilestoneOption},
6    protocol::ProtocolParameters,
7};
8use iota_types::stardust::error::StardustError;
9use packable::{
10    Packable, PackableExt,
11    error::{UnpackError, UnpackErrorExt},
12    packer::Packer,
13    unpacker::Unpacker,
14};
15
16/// The snapshot version supported currently
17const SNAPSHOT_VERSION: u8 = 2;
18
19#[derive(Copy, Clone, Debug)]
20struct MilestoneDiffCount(u32);
21
22impl Packable for MilestoneDiffCount {
23    type UnpackVisitor = ();
24    type UnpackError = StardustError;
25
26    fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error> {
27        self.0.pack(packer)?;
28
29        Ok(())
30    }
31
32    fn unpack<U: Unpacker, const VERIFY: bool>(
33        unpacker: &mut U,
34        _: &(),
35    ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> {
36        let milestone_diff_count = u32::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
37
38        if VERIFY && milestone_diff_count != 0 {
39            return Err(UnpackError::Packable(
40                StardustError::InvalidHornetGenesisSnapshot(milestone_diff_count),
41            ));
42        }
43
44        Ok(Self(milestone_diff_count))
45    }
46}
47
48/// Describes a snapshot header specific to full snapshots.
49#[derive(Clone, Debug)]
50pub struct FullSnapshotHeader {
51    genesis_milestone_index: MilestoneIndex,
52    target_milestone_index: MilestoneIndex,
53    target_milestone_timestamp: u32,
54    target_milestone_id: MilestoneId,
55    ledger_milestone_index: MilestoneIndex,
56    treasury_output_milestone_id: MilestoneId,
57    treasury_output_amount: u64,
58    parameters_milestone_option: MilestoneOption,
59    pub(crate) output_count: u64,
60    milestone_diff_count: MilestoneDiffCount,
61    sep_count: u16,
62}
63
64impl FullSnapshotHeader {
65    /// The length of the header in bytes
66    pub const LENGTH: usize = std::mem::size_of::<Self>();
67
68    /// Returns the genesis milestone index of a [`FullSnapshotHeader`].
69    pub fn genesis_milestone_index(&self) -> MilestoneIndex {
70        self.genesis_milestone_index
71    }
72
73    /// Returns the target milestone index of a [`FullSnapshotHeader`].
74    pub fn target_milestone_index(&self) -> MilestoneIndex {
75        self.target_milestone_index
76    }
77
78    /// Returns the target milestone timestamp of a [`FullSnapshotHeader`].
79    pub fn target_milestone_timestamp(&self) -> u32 {
80        self.target_milestone_timestamp
81    }
82
83    /// Returns the target milestone ID of a [`FullSnapshotHeader`].
84    pub fn target_milestone_id(&self) -> &MilestoneId {
85        &self.target_milestone_id
86    }
87
88    /// Returns the ledger milestone index of a [`FullSnapshotHeader`].
89    pub fn ledger_milestone_index(&self) -> MilestoneIndex {
90        self.ledger_milestone_index
91    }
92
93    /// Returns the treasury output milestone ID of a [`FullSnapshotHeader`].
94    pub fn treasury_output_milestone_id(&self) -> &MilestoneId {
95        &self.treasury_output_milestone_id
96    }
97
98    /// Returns the treasury output amount of a [`FullSnapshotHeader`].
99    pub fn treasury_output_amount(&self) -> u64 {
100        self.treasury_output_amount
101    }
102
103    /// Returns the parameters milestone option of a [`FullSnapshotHeader`].
104    pub fn parameters_milestone_option(&self) -> &MilestoneOption {
105        &self.parameters_milestone_option
106    }
107
108    /// Returns the output count of a [`FullSnapshotHeader`].
109    pub fn output_count(&self) -> u64 {
110        self.output_count
111    }
112
113    /// Returns the milestone diff count of a [`FullSnapshotHeader`].
114    ///
115    /// Note: For a genesis snapshot this getter must return 0.
116    pub fn milestone_diff_count(&self) -> u32 {
117        self.milestone_diff_count.0
118    }
119
120    /// Returns the SEP count of a [`FullSnapshotHeader`].
121    pub fn sep_count(&self) -> u16 {
122        self.sep_count
123    }
124}
125
126impl Packable for FullSnapshotHeader {
127    type UnpackVisitor = ();
128    type UnpackError = StardustError;
129
130    fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error> {
131        SNAPSHOT_VERSION.pack(packer)?;
132        SnapshotKind::Full.pack(packer)?;
133
134        self.genesis_milestone_index.pack(packer)?;
135        self.target_milestone_index.pack(packer)?;
136        self.target_milestone_timestamp.pack(packer)?;
137        self.target_milestone_id.pack(packer)?;
138        self.ledger_milestone_index.pack(packer)?;
139        self.treasury_output_milestone_id.pack(packer)?;
140        self.treasury_output_amount.pack(packer)?;
141        // This is only required in Hornet.
142        (self.parameters_milestone_option.packed_len() as u16).pack(packer)?;
143        self.parameters_milestone_option.pack(packer)?;
144        self.output_count.pack(packer)?;
145        self.milestone_diff_count.pack(packer)?;
146        self.sep_count.pack(packer)?;
147
148        Ok(())
149    }
150
151    fn unpack<U: Unpacker, const VERIFY: bool>(
152        unpacker: &mut U,
153        _: &(),
154    ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> {
155        let version = u8::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
156
157        if VERIFY && SNAPSHOT_VERSION != version {
158            return Err(UnpackError::Packable(
159                StardustError::UnsupportedHornetSnapshotVersion(SNAPSHOT_VERSION, version),
160            ));
161        }
162
163        let kind = SnapshotKind::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
164
165        if VERIFY && kind != SnapshotKind::Full {
166            return Err(UnpackError::Packable(
167                StardustError::InvalidHornetSnapshotKind(kind as u8),
168            ));
169        }
170
171        let genesis_milestone_index =
172            MilestoneIndex::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
173        let target_milestone_index = MilestoneIndex::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
174        let target_milestone_timestamp = u32::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
175        let target_milestone_id = MilestoneId::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
176        let ledger_milestone_index = MilestoneIndex::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
177        let treasury_output_milestone_id =
178            MilestoneId::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
179        let treasury_output_amount = u64::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
180        // This is only required in Hornet.
181        let _parameters_milestone_option_length =
182            u16::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
183        let parameters_milestone_option =
184            MilestoneOption::unpack::<_, true>(unpacker, &ProtocolParameters::default())
185                .coerce()?;
186        let output_count = u64::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
187        let milestone_diff_count =
188            MilestoneDiffCount::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
189        let sep_count = u16::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
190
191        Ok(Self {
192            genesis_milestone_index,
193            target_milestone_index,
194            target_milestone_timestamp,
195            target_milestone_id,
196            ledger_milestone_index,
197            treasury_output_milestone_id,
198            treasury_output_amount,
199            parameters_milestone_option,
200            output_count,
201            milestone_diff_count,
202            sep_count,
203        })
204    }
205}
206
207/// The kind of a snapshot.
208#[repr(u8)]
209#[derive(Debug, Copy, Clone, Eq, PartialEq, packable::Packable)]
210#[packable(unpack_error = StardustError)]
211pub enum SnapshotKind {
212    /// Full is a snapshot which contains the full ledger entry for a given
213    /// milestone plus the milestone diffs which subtracted to the ledger
214    /// milestone reduce to the snapshot milestone ledger.
215    Full = 0,
216    /// Delta is a snapshot which contains solely diffs of milestones newer than
217    /// a certain ledger milestone instead of the complete ledger state of a
218    /// given milestone.
219    Delta = 1,
220}