bee_tangle/
metadata.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    conflict::{ConflictError, ConflictReason},
6    flags::Flags,
7};
8
9use bee_common::packable::{OptionError, Packable, Read, Write};
10use bee_message::{milestone::MilestoneIndex, MessageId};
11
12use serde::Serialize;
13
14use std::{
15    cmp::Ordering,
16    time::{SystemTime, UNIX_EPOCH},
17};
18
19/// Metadata associated with a tangle message.
20#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Serialize)]
21pub struct MessageMetadata {
22    flags: Flags,
23    milestone_index: Option<MilestoneIndex>,
24    arrival_timestamp: u64,
25    solidification_timestamp: u64,
26    reference_timestamp: u64,
27    omrsi: Option<IndexId>,
28    ymrsi: Option<IndexId>,
29    conflict: ConflictReason,
30}
31
32impl MessageMetadata {
33    /// Create a new instance of a message's metadata.
34    #[allow(clippy::too_many_arguments)]
35    pub fn new(
36        flags: Flags,
37        milestone_index: Option<MilestoneIndex>,
38        arrival_timestamp: u64,
39        solidification_timestamp: u64,
40        reference_timestamp: u64,
41        omrsi: Option<IndexId>,
42        ymrsi: Option<IndexId>,
43        conflict: ConflictReason,
44    ) -> Self {
45        Self {
46            flags,
47            milestone_index,
48            arrival_timestamp,
49            solidification_timestamp,
50            reference_timestamp,
51            omrsi,
52            ymrsi,
53            conflict,
54        }
55    }
56
57    /// Create metadata that corresponds to a just-arrived message using the current system time.
58    pub fn arrived() -> Self {
59        Self {
60            arrival_timestamp: SystemTime::now()
61                .duration_since(UNIX_EPOCH)
62                .expect("Clock may have gone backwards")
63                .as_millis() as u64,
64            ..Self::default()
65        }
66    }
67
68    /// Get the flags associated with this metadata.
69    pub fn flags(&self) -> &Flags {
70        &self.flags
71    }
72
73    /// Get a mutable reference to the flags associated with this metadata.
74    pub fn flags_mut(&mut self) -> &mut Flags {
75        &mut self.flags
76    }
77
78    /// Get the milestone index of this message.
79    pub fn milestone_index(&self) -> Option<MilestoneIndex> {
80        self.milestone_index
81    }
82
83    /// Set the milestone index of this message.
84    pub fn set_milestone_index(&mut self, index: MilestoneIndex) {
85        self.milestone_index = Some(index);
86    }
87
88    /// Get the arrival timestamp (seconds from the unix epoch) of this message.
89    pub fn arrival_timestamp(&self) -> u64 {
90        self.arrival_timestamp
91    }
92
93    /// Get the solidification timestamp (seconds from the unix epoch) of this message.
94    pub fn solidification_timestamp(&self) -> u64 {
95        self.solidification_timestamp
96    }
97
98    /// Get the oldest message root snapshot index of this message.
99    pub fn omrsi(&self) -> Option<IndexId> {
100        self.omrsi
101    }
102
103    /// Set the oldest message root snapshot index of this message.
104    pub fn set_omrsi(&mut self, omrsi: IndexId) {
105        self.omrsi = Some(omrsi);
106    }
107
108    /// Get the youngest message root snapshot index of this message.
109    pub fn ymrsi(&self) -> Option<IndexId> {
110        self.ymrsi
111    }
112
113    /// Set the youngest message root snapshot index of this message.
114    pub fn set_ymrsi(&mut self, ymrsi: IndexId) {
115        self.ymrsi = Some(ymrsi);
116    }
117
118    /// Get the reference timestamp (seconds from the unix epoch) of this message.
119    pub fn reference_timestamp(&self) -> u64 {
120        self.reference_timestamp
121    }
122
123    /// Mark this message as solid at the current system time.
124    pub fn mark_solid(&mut self) {
125        self.flags.set_solid(true);
126        self.solidification_timestamp = SystemTime::now()
127            .duration_since(UNIX_EPOCH)
128            .expect("Clock may have gone backwards")
129            .as_millis() as u64;
130    }
131
132    /// Reference this message with the given timestamp.
133    pub fn reference(&mut self, timestamp: u64) {
134        self.flags.set_referenced(true);
135        self.reference_timestamp = timestamp;
136    }
137
138    /// Get the conflict state of this message.
139    pub fn conflict(&self) -> ConflictReason {
140        self.conflict
141    }
142
143    /// Set the conflict state of this message.
144    pub fn set_conflict(&mut self, conflict: ConflictReason) {
145        self.conflict = conflict;
146    }
147}
148
149/// An error that may occur when manipulating message metadata.
150#[derive(Debug)]
151pub enum MessageMetadataError {
152    /// An IO error occurred.
153    Io(std::io::Error),
154    /// A packing error occurred.
155    OptionIndex(<Option<MilestoneIndex> as Packable>::Error),
156    /// A packing error occurred.
157    OptionIndexId(<Option<IndexId> as Packable>::Error),
158    /// An error relating to a conflict reason occurred.
159    Conflict(ConflictError),
160}
161
162impl From<std::io::Error> for MessageMetadataError {
163    fn from(error: std::io::Error) -> Self {
164        MessageMetadataError::Io(error)
165    }
166}
167
168impl From<OptionError<std::io::Error>> for MessageMetadataError {
169    fn from(error: OptionError<std::io::Error>) -> Self {
170        MessageMetadataError::OptionIndex(error)
171    }
172}
173
174impl From<OptionError<IndexIdError>> for MessageMetadataError {
175    fn from(error: OptionError<IndexIdError>) -> Self {
176        MessageMetadataError::OptionIndexId(error)
177    }
178}
179
180impl Packable for MessageMetadata {
181    type Error = MessageMetadataError;
182
183    fn packed_len(&self) -> usize {
184        self.flags.packed_len()
185            + self.milestone_index.packed_len()
186            + self.arrival_timestamp.packed_len()
187            + self.solidification_timestamp.packed_len()
188            + self.reference_timestamp.packed_len()
189            + self.omrsi.packed_len()
190            + self.ymrsi.packed_len()
191            + self.conflict.packed_len()
192    }
193
194    fn pack<W: Write>(&self, writer: &mut W) -> Result<(), Self::Error> {
195        self.flags.pack(writer)?;
196        self.milestone_index.pack(writer)?;
197        self.arrival_timestamp.pack(writer)?;
198        self.solidification_timestamp.pack(writer)?;
199        self.reference_timestamp.pack(writer)?;
200        self.omrsi.pack(writer)?;
201        self.ymrsi.pack(writer)?;
202        self.conflict.pack(writer).map_err(MessageMetadataError::Conflict)?;
203
204        Ok(())
205    }
206
207    fn unpack_inner<R: Read + ?Sized, const CHECK: bool>(reader: &mut R) -> Result<Self, Self::Error> {
208        Ok(Self {
209            flags: Flags::unpack_inner::<R, CHECK>(reader)?,
210            milestone_index: Option::<MilestoneIndex>::unpack_inner::<R, CHECK>(reader)?,
211            arrival_timestamp: u64::unpack_inner::<R, CHECK>(reader)?,
212            solidification_timestamp: u64::unpack_inner::<R, CHECK>(reader)?,
213            reference_timestamp: u64::unpack_inner::<R, CHECK>(reader)?,
214            omrsi: Option::<IndexId>::unpack_inner::<R, CHECK>(reader)?,
215            ymrsi: Option::<IndexId>::unpack_inner::<R, CHECK>(reader)?,
216            conflict: ConflictReason::unpack_inner::<R, CHECK>(reader).map_err(MessageMetadataError::Conflict)?,
217        })
218    }
219}
220
221/// A type used to associate two particular interesting Cone Root Indexes with a message in the Tangle, i.e. the Oldest
222/// Cone Root Index (OCRI), and the Youngest Cone Root Index (YCRI)
223#[derive(Clone, Copy, Debug, Serialize)]
224pub struct IndexId(MilestoneIndex, MessageId);
225
226impl IndexId {
227    /// Create a new `IndexId`.
228    pub fn new(index: MilestoneIndex, id: MessageId) -> Self {
229        Self(index, id)
230    }
231
232    /// Get the milestone index of this `IndexId`.
233    pub fn index(&self) -> MilestoneIndex {
234        self.0
235    }
236
237    /// Get the message ID of this `IndexId`.
238    pub fn id(&self) -> MessageId {
239        self.1
240    }
241
242    /// Update this `IndexId` with a new milestone index.
243    pub fn set_index(&mut self, index: MilestoneIndex) {
244        self.0 = index;
245    }
246}
247
248impl Ord for IndexId {
249    fn cmp(&self, other: &Self) -> Ordering {
250        self.0.cmp(&other.0)
251    }
252}
253
254impl PartialOrd for IndexId {
255    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
256        self.0.partial_cmp(&other.0)
257    }
258}
259
260impl Eq for IndexId {}
261
262impl PartialEq for IndexId {
263    fn eq(&self, other: &Self) -> bool {
264        self.0 == other.0
265    }
266}
267
268impl Packable for IndexId {
269    type Error = IndexIdError;
270
271    fn packed_len(&self) -> usize {
272        self.0.packed_len() + self.1.packed_len()
273    }
274
275    fn pack<W: Write>(&self, writer: &mut W) -> Result<(), Self::Error> {
276        self.0.pack(writer)?;
277        self.1.pack(writer)?;
278
279        Ok(())
280    }
281
282    fn unpack_inner<R: Read + ?Sized, const CHECK: bool>(reader: &mut R) -> Result<Self, Self::Error> {
283        let index = MilestoneIndex::unpack_inner::<R, CHECK>(reader)?;
284        let id = MessageId::unpack_inner::<R, CHECK>(reader)?;
285
286        Ok(Self(index, id))
287    }
288}
289
290/// An error that may occur when manipulating message indices.
291#[derive(Debug)]
292pub enum IndexIdError {
293    /// An IO error occurred.
294    Io(std::io::Error),
295    /// An message-related error occurred.
296    MessageId(bee_message::Error),
297}
298
299impl From<std::io::Error> for IndexIdError {
300    fn from(error: std::io::Error) -> Self {
301        IndexIdError::Io(error)
302    }
303}
304
305impl From<bee_message::Error> for IndexIdError {
306    fn from(error: bee_message::Error) -> Self {
307        IndexIdError::MessageId(error)
308    }
309}