bee_inx/
ledger.rs

1// Copyright 2022 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use bee_block as bee;
5use inx::proto;
6
7use crate::{maybe_missing, Raw};
8
9/// Represents a new output in the ledger.
10#[allow(missing_docs)]
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct LedgerOutput {
13    pub output_id: bee::output::OutputId,
14    pub block_id: bee::BlockId,
15    pub milestone_index_booked: bee::payload::milestone::MilestoneIndex,
16    pub milestone_timestamp_booked: u32,
17    pub output: Raw<bee::output::Output>,
18}
19
20/// Represents a spent output in the ledger.
21#[allow(missing_docs)]
22#[derive(Clone, Debug, PartialEq, Eq)]
23pub struct LedgerSpent {
24    pub output: LedgerOutput,
25    pub transaction_id_spent: bee::payload::transaction::TransactionId,
26    pub milestone_index_spent: bee::payload::milestone::MilestoneIndex,
27    pub milestone_timestamp_spent: u32,
28}
29
30#[allow(missing_docs)]
31#[derive(Clone, Debug, PartialEq, Eq)]
32pub struct UnspentOutput {
33    pub ledger_index: bee::payload::milestone::MilestoneIndex,
34    pub output: LedgerOutput,
35}
36
37#[allow(missing_docs)]
38#[derive(Clone, Debug, PartialEq, Eq)]
39pub struct Marker {
40    pub milestone_index: bee::payload::milestone::MilestoneIndex,
41    pub consumed_count: usize,
42    pub created_count: usize,
43}
44
45#[allow(missing_docs)]
46#[derive(Clone, Debug, PartialEq, Eq)]
47pub enum LedgerUpdate {
48    Consumed(LedgerSpent),
49    Created(LedgerOutput),
50    Begin(Marker),
51    End(Marker),
52}
53
54impl LedgerUpdate {
55    /// If present, returns the contained `LedgerSpent` while consuming `self`.
56    pub fn consumed(self) -> Option<LedgerSpent> {
57        match self {
58            Self::Consumed(ledger_spent) => Some(ledger_spent),
59            _ => None,
60        }
61    }
62
63    /// If present, returns the contained `LedgerOutput` while consuming `self`.
64    pub fn created(self) -> Option<LedgerOutput> {
65        match self {
66            Self::Created(ledger_output) => Some(ledger_output),
67            _ => None,
68        }
69    }
70
71    /// If present, returns the `Marker` that denotes the beginning of a milestone while consuming `self`.
72    pub fn begin(self) -> Option<Marker> {
73        match self {
74            Self::Begin(marker) => Some(marker),
75            _ => None,
76        }
77    }
78
79    /// If present, returns the `Marker` that denotes the end if present while consuming `self`.
80    pub fn end(self) -> Option<Marker> {
81        match self {
82            Self::End(marker) => Some(marker),
83            _ => None,
84        }
85    }
86}
87
88impl From<proto::ledger_update::Marker> for Marker {
89    fn from(value: proto::ledger_update::Marker) -> Self {
90        Self {
91            milestone_index: value.milestone_index.into(),
92            consumed_count: value.consumed_count as usize,
93            created_count: value.created_count as usize,
94        }
95    }
96}
97
98impl From<proto::ledger_update::Marker> for LedgerUpdate {
99    fn from(value: proto::ledger_update::Marker) -> Self {
100        use proto::ledger_update::marker::MarkerType as proto;
101        match value.marker_type() {
102            proto::Begin => Self::Begin(value.into()),
103            proto::End => Self::End(value.into()),
104        }
105    }
106}
107
108impl TryFrom<LedgerUpdate> for proto::ledger_update::Marker {
109    type Error = bee::InxError;
110
111    fn try_from(value: LedgerUpdate) -> Result<Self, Self::Error> {
112        use proto::ledger_update::marker::MarkerType;
113        let marker_type = match &value {
114            LedgerUpdate::Begin(_) => MarkerType::Begin,
115            LedgerUpdate::End(_) => MarkerType::End,
116            _ => {
117                return Err(Self::Error::MissingField("marker_type"));
118            }
119        };
120        if let LedgerUpdate::Begin(marker) | LedgerUpdate::End(marker) = value {
121            Ok(Self {
122                milestone_index: marker.milestone_index.0,
123                marker_type: marker_type.into(),
124                consumed_count: marker.consumed_count as _,
125                created_count: marker.created_count as _,
126            })
127        } else {
128            unreachable!()
129        }
130    }
131}
132
133impl TryFrom<proto::LedgerUpdate> for LedgerUpdate {
134    type Error = bee::InxError;
135
136    fn try_from(value: proto::LedgerUpdate) -> Result<Self, Self::Error> {
137        use proto::ledger_update::Op as proto;
138        Ok(match maybe_missing!(value.op) {
139            proto::BatchMarker(marker) => marker.into(),
140            proto::Consumed(consumed) => LedgerUpdate::Consumed(consumed.try_into()?),
141            proto::Created(created) => LedgerUpdate::Created(created.try_into()?),
142        })
143    }
144}
145
146impl From<LedgerUpdate> for proto::LedgerUpdate {
147    fn from(value: LedgerUpdate) -> Self {
148        use proto::ledger_update::Op;
149        Self {
150            op: match value {
151                LedgerUpdate::Consumed(consumed) => Op::Consumed(consumed.into()),
152                LedgerUpdate::Created(created) => Op::Created(created.into()),
153                marker => Op::BatchMarker(marker.try_into().unwrap()),
154            }
155            .into(),
156        }
157    }
158}
159
160impl TryFrom<proto::LedgerOutput> for LedgerOutput {
161    type Error = bee::InxError;
162
163    fn try_from(value: proto::LedgerOutput) -> Result<Self, Self::Error> {
164        Ok(Self {
165            output_id: maybe_missing!(value.output_id).try_into()?,
166            block_id: maybe_missing!(value.block_id).try_into()?,
167            milestone_index_booked: value.milestone_index_booked.into(),
168            milestone_timestamp_booked: value.milestone_timestamp_booked,
169            output: maybe_missing!(value.output).into(),
170        })
171    }
172}
173
174impl From<LedgerOutput> for proto::LedgerOutput {
175    fn from(value: LedgerOutput) -> Self {
176        Self {
177            output_id: Some(value.output_id.into()),
178            block_id: Some(value.block_id.into()),
179            milestone_index_booked: value.milestone_index_booked.0,
180            milestone_timestamp_booked: value.milestone_timestamp_booked,
181            output: Some(value.output.into()),
182        }
183    }
184}
185
186impl TryFrom<proto::LedgerSpent> for LedgerSpent {
187    type Error = bee::InxError;
188
189    fn try_from(value: proto::LedgerSpent) -> Result<Self, Self::Error> {
190        Ok(Self {
191            output: maybe_missing!(value.output).try_into()?,
192            transaction_id_spent: maybe_missing!(value.transaction_id_spent).try_into()?,
193            milestone_index_spent: value.milestone_index_spent.into(),
194            milestone_timestamp_spent: value.milestone_timestamp_spent,
195        })
196    }
197}
198
199impl From<LedgerSpent> for proto::LedgerSpent {
200    fn from(value: LedgerSpent) -> Self {
201        Self {
202            output: Some(value.output.into()),
203            transaction_id_spent: Some(value.transaction_id_spent.into()),
204            milestone_index_spent: value.milestone_index_spent.0,
205            milestone_timestamp_spent: value.milestone_timestamp_spent,
206        }
207    }
208}
209
210impl TryFrom<proto::UnspentOutput> for UnspentOutput {
211    type Error = bee::InxError;
212
213    fn try_from(value: proto::UnspentOutput) -> Result<Self, Self::Error> {
214        Ok(Self {
215            ledger_index: value.ledger_index.into(),
216            output: maybe_missing!(value.output).try_into()?,
217        })
218    }
219}
220
221impl From<UnspentOutput> for proto::UnspentOutput {
222    fn from(value: UnspentOutput) -> Self {
223        Self {
224            ledger_index: value.ledger_index.0,
225            output: Some(value.output.into()),
226        }
227    }
228}