bee_block/payload/milestone/
essence.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use alloc::vec::Vec;
5
6use crypto::hashes::{blake2b::Blake2b256, Digest};
7use packable::{
8    bounded::BoundedU16,
9    error::{UnpackError, UnpackErrorExt},
10    packer::Packer,
11    prefix::BoxedSlicePrefix,
12    unpacker::Unpacker,
13    Packable, PackableExt,
14};
15
16use crate::{
17    parent::Parents,
18    payload::milestone::{MerkleRoot, MilestoneId, MilestoneIndex, MilestoneOptions},
19    protocol::ProtocolParameters,
20    Error,
21};
22
23pub(crate) type MilestoneMetadataLength = BoundedU16<{ u16::MIN }, { u16::MAX }>;
24
25/// Essence of a milestone payload.
26/// This is the signed part of a milestone payload.
27#[derive(Clone, Debug, Eq, PartialEq)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29pub struct MilestoneEssence {
30    index: MilestoneIndex,
31    timestamp: u32,
32    protocol_version: u8,
33    previous_milestone_id: MilestoneId,
34    parents: Parents,
35    inclusion_merkle_root: MerkleRoot,
36    applied_merkle_root: MerkleRoot,
37    metadata: BoxedSlicePrefix<u8, MilestoneMetadataLength>,
38    options: MilestoneOptions,
39}
40
41impl MilestoneEssence {
42    /// Creates a new [`MilestoneEssence`].
43    #[allow(clippy::too_many_arguments)]
44    pub fn new(
45        index: MilestoneIndex,
46        timestamp: u32,
47        protocol_version: u8,
48        previous_milestone_id: MilestoneId,
49        parents: Parents,
50        inclusion_merkle_root: MerkleRoot,
51        applied_merkle_root: MerkleRoot,
52        metadata: Vec<u8>,
53        options: MilestoneOptions,
54    ) -> Result<Self, Error> {
55        let metadata = metadata
56            .into_boxed_slice()
57            .try_into()
58            .map_err(Error::InvalidMilestoneMetadataLength)?;
59
60        Ok(Self {
61            index,
62            timestamp,
63            protocol_version,
64            previous_milestone_id,
65            parents,
66            inclusion_merkle_root,
67            applied_merkle_root,
68            metadata,
69            options,
70        })
71    }
72
73    /// Returns the index of a [`MilestoneEssence`].
74    pub fn index(&self) -> MilestoneIndex {
75        self.index
76    }
77
78    /// Returns the timestamp of a [`MilestoneEssence`].
79    pub fn timestamp(&self) -> u32 {
80        self.timestamp
81    }
82
83    /// Returns the protocol version of a [`MilestoneEssence`].
84    pub fn protocol_version(&self) -> u8 {
85        self.protocol_version
86    }
87
88    /// Returns the previous milestone ID of a [`MilestoneEssence`].
89    pub fn previous_milestone_id(&self) -> &MilestoneId {
90        &self.previous_milestone_id
91    }
92
93    /// Returns the parents of a [`MilestoneEssence`].
94    pub fn parents(&self) -> &Parents {
95        &self.parents
96    }
97
98    /// Returns the inclusion merkle root of a [`MilestoneEssence`].
99    pub fn inclusion_merkle_root(&self) -> &MerkleRoot {
100        &self.inclusion_merkle_root
101    }
102
103    /// Returns the applied merkle root of a [`MilestoneEssence`].
104    pub fn applied_merkle_root(&self) -> &MerkleRoot {
105        &self.applied_merkle_root
106    }
107
108    /// Returns the metadata.
109    pub fn metadata(&self) -> &[u8] {
110        &self.metadata
111    }
112
113    /// Returns the options of a [`MilestoneEssence`].
114    pub fn options(&self) -> &MilestoneOptions {
115        &self.options
116    }
117
118    /// Hashes the [`MilestoneEssence`] to be signed.
119    pub fn hash(&self) -> [u8; 32] {
120        Blake2b256::digest(&self.pack_to_vec()).into()
121    }
122}
123
124impl Packable for MilestoneEssence {
125    type UnpackError = Error;
126    type UnpackVisitor = ProtocolParameters;
127
128    fn pack<P: Packer>(&self, packer: &mut P) -> Result<(), P::Error> {
129        self.index.pack(packer)?;
130        self.timestamp.pack(packer)?;
131        self.protocol_version.pack(packer)?;
132        self.previous_milestone_id.pack(packer)?;
133        self.parents.pack(packer)?;
134        self.inclusion_merkle_root.pack(packer)?;
135        self.applied_merkle_root.pack(packer)?;
136        self.metadata.pack(packer)?;
137        self.options.pack(packer)?;
138
139        Ok(())
140    }
141
142    fn unpack<U: Unpacker, const VERIFY: bool>(
143        unpacker: &mut U,
144        visitor: &Self::UnpackVisitor,
145    ) -> Result<Self, UnpackError<Self::UnpackError, U::Error>> {
146        let index = MilestoneIndex::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
147        let timestamp = u32::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
148        let protocol_version = u8::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
149
150        if VERIFY && protocol_version != visitor.protocol_version() {
151            return Err(UnpackError::Packable(Error::ProtocolVersionMismatch {
152                expected: visitor.protocol_version(),
153                actual: protocol_version,
154            }));
155        }
156
157        let previous_milestone_id = MilestoneId::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
158        let parents = Parents::unpack::<_, VERIFY>(unpacker, &())?;
159        let inclusion_merkle_root = MerkleRoot::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
160        let applied_merkle_root = MerkleRoot::unpack::<_, VERIFY>(unpacker, &()).coerce()?;
161
162        let metadata = BoxedSlicePrefix::<u8, MilestoneMetadataLength>::unpack::<_, VERIFY>(unpacker, &())
163            .map_packable_err(|e| Error::InvalidMilestoneMetadataLength(e.into_prefix_err().into()))?;
164
165        let options = MilestoneOptions::unpack::<_, VERIFY>(unpacker, visitor)?;
166
167        Ok(Self {
168            index,
169            timestamp,
170            protocol_version,
171            previous_milestone_id,
172            parents,
173            inclusion_merkle_root,
174            applied_merkle_root,
175            metadata,
176            options,
177        })
178    }
179}