everscale_types/models/message/
in_message.rs

1use crate::cell::*;
2use crate::dict::AugDictExtra;
3use crate::error::Error;
4use crate::models::{
5    CurrencyCollection, ExtInMsgInfo, IntMsgInfo, Lazy, Message, MsgEnvelope, MsgInfo,
6    OwnedMessage, Transaction,
7};
8use crate::num::Tokens;
9
10/// Inbound message import fees.
11#[derive(Default, PartialEq, Eq, Clone, Debug, Store, Load)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct ImportFees {
14    /// Fees collected from the message.
15    pub fees_collected: Tokens,
16    /// Value imported from the message.
17    pub value_imported: CurrencyCollection,
18}
19
20impl AugDictExtra for ImportFees {
21    fn comp_add(
22        left: &mut CellSlice,
23        right: &mut CellSlice,
24        b: &mut CellBuilder,
25        cx: &mut dyn CellContext,
26    ) -> Result<(), Error> {
27        let left = ok!(Self::load_from(left));
28        let right = ok!(Self::load_from(right));
29
30        Self {
31            fees_collected: ok!(left
32                .fees_collected
33                .checked_add(right.fees_collected)
34                .ok_or(Error::IntOverflow)),
35            value_imported: ok!(left.value_imported.checked_add(&right.value_imported)),
36        }
37        .store_into(b, cx)
38    }
39}
40
41/// Inbound message.
42#[derive(Clone, Debug, Eq, PartialEq)]
43#[cfg_attr(feature = "serde", derive(serde::Serialize))]
44#[cfg_attr(feature = "serde", serde(tag = "ty"))]
45pub enum InMsg {
46    /// Inbound external message.
47    External(InMsgExternal),
48    /// Immediately routed internal message.
49    Immediate(InMsgFinal),
50    /// Internal message with a destination in this block.
51    Final(InMsgFinal),
52    /// Transit internal message.
53    Transit(InMsgTransit),
54}
55
56impl InMsg {
57    const MSG_IMPORT_EXT: u8 = 0b000;
58    const MSG_IMPORT_IMM: u8 = 0b011;
59    const MSG_IMPORT_FIN: u8 = 0b100;
60    const MSG_IMPORT_TR: u8 = 0b101;
61
62    /// Loads a transaction for the inbound message.
63    ///
64    /// Transaction exists only in [`External`], [`Immediate`], and [`Final`] inbound messages.
65    ///
66    /// [`External`]: InMsg::External
67    /// [`Immediate`]: InMsg::Immediate
68    /// [`Final`]: InMsg::Final
69    pub fn load_transaction(&self) -> Result<Option<Transaction>, Error> {
70        match self {
71            Self::External(msg) => msg.load_transaction().map(Some),
72            Self::Immediate(msg) | Self::Final(msg) => msg.load_transaction().map(Some),
73            Self::Transit(_) => Ok(None),
74        }
75    }
76
77    /// Returns a transaction cell for the inbound message.
78    ///
79    /// Transaction exists only in [`External`], [`Immediate`], and [`Final`] inbound messages.
80    ///
81    /// [`External`]: InMsg::External
82    /// [`Immediate`]: InMsg::Immediate
83    /// [`Final`]: InMsg::Final
84    pub fn transaction_cell(&self) -> Option<Cell> {
85        match self {
86            Self::External(msg) => Some(msg.transaction.cell.clone()),
87            Self::Immediate(msg) | Self::Final(msg) => Some(msg.transaction.cell.clone()),
88            Self::Transit(_) => None,
89        }
90    }
91
92    /// Loads a non-owned inbound message.
93    pub fn load_msg(&self) -> Result<Message<'_>, Error> {
94        match self {
95            Self::External(msg) => msg.load_in_msg(),
96            Self::Immediate(msg) => msg.load_in_msg(),
97            Self::Final(msg) => msg.load_in_msg(),
98            Self::Transit(msg) => msg.load_in_msg(),
99        }
100    }
101
102    /// Loads an owned inbound message.
103    pub fn load_msg_owned(&self) -> Result<OwnedMessage, Error> {
104        match self {
105            Self::External(x) => x.load_in_msg_owned(),
106            Self::Immediate(x) => x.load_in_msg_owned(),
107            Self::Final(x) => x.load_in_msg_owned(),
108            Self::Transit(x) => x.load_in_msg_owned(),
109        }
110    }
111
112    /// Loads an inbound message cell.
113    pub fn load_msg_cell(&self) -> Result<Cell, Error> {
114        match self {
115            Self::External(msg) => Ok(msg.in_msg.cell.clone()),
116            Self::Immediate(msg) => msg.load_in_msg_cell(),
117            Self::Final(msg) => msg.load_in_msg_cell(),
118            Self::Transit(msg) => msg.load_in_msg_cell(),
119        }
120    }
121
122    /// Returns an envelope cell of the inbound message.
123    pub fn in_msg_envelope_cell(&self) -> Option<Cell> {
124        match self {
125            Self::External(_) => None,
126            Self::Immediate(msg) => Some(msg.in_msg_envelope.cell.clone()),
127            Self::Final(msg) => Some(msg.in_msg_envelope.cell.clone()),
128            Self::Transit(msg) => Some(msg.in_msg_envelope.cell.clone()),
129        }
130    }
131
132    /// Loads an inbound message envelope.
133    pub fn load_in_msg_envelope(&self) -> Result<Option<MsgEnvelope>, Error> {
134        match self {
135            Self::External(_) => Ok(None),
136            Self::Immediate(msg) => msg.load_in_msg_envelope().map(Some),
137            Self::Final(msg) => msg.load_in_msg_envelope().map(Some),
138            Self::Transit(msg) => msg.load_in_msg_envelope().map(Some),
139        }
140    }
141
142    /// Returns an outbound envelope cell.
143    pub fn out_msg_envelope_cell(&self) -> Option<Cell> {
144        match self {
145            Self::External(_) => None,
146            Self::Immediate(_) => None,
147            Self::Final(_) => None,
148            Self::Transit(msg) => Some(msg.out_msg_envelope.cell.clone()),
149        }
150    }
151
152    /// Loads an outbound message envelope.
153    pub fn load_out_msg_envelope(&self) -> Result<Option<MsgEnvelope>, Error> {
154        match self {
155            Self::External(_) => Ok(None),
156            Self::Immediate(_) => Ok(None),
157            Self::Final(_) => Ok(None),
158            Self::Transit(ref x) => x.load_out_msg_envelope().map(Some),
159        }
160    }
161
162    /// Computes import fees.
163    pub fn compute_fees(&self) -> Result<ImportFees, Error> {
164        Ok(match self {
165            Self::External(_) => ImportFees::default(),
166            Self::Immediate(msg) => {
167                let info = ok!(msg.load_in_msg_info());
168                ImportFees {
169                    fees_collected: info.fwd_fee,
170                    value_imported: CurrencyCollection::ZERO,
171                }
172            }
173            Self::Final(msg) => {
174                let env = ok!(msg.load_in_msg_envelope());
175                if msg.fwd_fee != env.fwd_fee_remaining {
176                    return Err(Error::InvalidData);
177                }
178
179                let info = ok!(env.load_message_info());
180
181                let mut value_imported = info.value;
182                ok!(value_imported.try_add_assign_tokens(info.ihr_fee));
183                ok!(value_imported.try_add_assign_tokens(env.fwd_fee_remaining));
184
185                ImportFees {
186                    fees_collected: env.fwd_fee_remaining,
187                    value_imported,
188                }
189            }
190            Self::Transit(msg) => {
191                let env = ok!(msg.load_in_msg_envelope());
192                if env.fwd_fee_remaining < msg.transit_fee {
193                    return Err(Error::InvalidData);
194                }
195
196                let info = ok!(env.load_message_info());
197
198                let mut value_imported = info.value;
199                ok!(value_imported.try_add_assign_tokens(info.ihr_fee));
200                ok!(value_imported.try_add_assign_tokens(env.fwd_fee_remaining));
201
202                ImportFees {
203                    fees_collected: msg.transit_fee,
204                    value_imported,
205                }
206            }
207        })
208    }
209}
210
211impl Store for InMsg {
212    fn store_into(&self, builder: &mut CellBuilder, cx: &mut dyn CellContext) -> Result<(), Error> {
213        match self {
214            Self::External(msg) => {
215                ok!(builder.store_small_uint(Self::MSG_IMPORT_EXT, 3));
216                msg.store_into(builder, cx)
217            }
218            Self::Immediate(msg) => {
219                ok!(builder.store_small_uint(Self::MSG_IMPORT_IMM, 3));
220                msg.store_into(builder, cx)
221            }
222            Self::Final(msg) => {
223                ok!(builder.store_small_uint(Self::MSG_IMPORT_FIN, 3));
224                msg.store_into(builder, cx)
225            }
226            Self::Transit(msg) => {
227                ok!(builder.store_small_uint(Self::MSG_IMPORT_TR, 3));
228                msg.store_into(builder, cx)
229            }
230        }
231    }
232}
233
234impl<'a> Load<'a> for InMsg {
235    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
236        match ok!(slice.load_small_uint(3)) {
237            Self::MSG_IMPORT_EXT => InMsgExternal::load_from(slice).map(Self::External),
238            Self::MSG_IMPORT_IMM => InMsgFinal::load_from(slice).map(Self::Immediate),
239            Self::MSG_IMPORT_FIN => InMsgFinal::load_from(slice).map(Self::Final),
240            Self::MSG_IMPORT_TR => InMsgTransit::load_from(slice).map(Self::Transit),
241            _ => Err(Error::InvalidTag),
242        }
243    }
244}
245
246/// Inbound external message.
247#[derive(Clone, Debug, Eq, PartialEq, Store, Load)]
248#[cfg_attr(feature = "serde", derive(serde::Serialize))]
249#[cfg_attr(feature = "serde", serde(tag = "ty"))]
250pub struct InMsgExternal {
251    /// External message itself.
252    #[cfg_attr(feature = "serde", serde(serialize_with = "Lazy::serialize_repr_hash"))]
253    pub in_msg: Lazy<OwnedMessage>,
254    /// Executed transaction for this external message.
255    #[cfg_attr(feature = "serde", serde(serialize_with = "Lazy::serialize_repr_hash"))]
256    pub transaction: Lazy<Transaction>,
257}
258
259impl InMsgExternal {
260    /// Loads only message info.
261    pub fn load_in_msg_info(&self) -> Result<ExtInMsgInfo, Error> {
262        if let MsgInfo::ExtIn(info) = ok!(<_>::load_from(&mut ok!(self.in_msg.cell.as_slice()))) {
263            Ok(info)
264        } else {
265            Err(Error::InvalidData)
266        }
267    }
268
269    /// Loads a non-owned message.
270    pub fn load_in_msg(&self) -> Result<Message<'_>, Error> {
271        self.in_msg.cast_ref::<Message<'_>>().load()
272    }
273
274    /// Loads an owned message.
275    pub fn load_in_msg_owned(&self) -> Result<OwnedMessage, Error> {
276        self.in_msg.load()
277    }
278
279    /// Loads transaction.
280    pub fn load_transaction(&self) -> Result<Transaction, Error> {
281        self.transaction.load()
282    }
283}
284
285/// Executed inbound internal message.
286#[derive(Clone, Debug, Eq, PartialEq, Store, Load)]
287#[cfg_attr(feature = "serde", derive(serde::Serialize))]
288pub struct InMsgFinal {
289    /// Old envelope.
290    pub in_msg_envelope: Lazy<MsgEnvelope>,
291    /// Transaction
292    #[cfg_attr(feature = "serde", serde(serialize_with = "Lazy::serialize_repr_hash"))]
293    pub transaction: Lazy<Transaction>,
294    /// Forward fee.
295    pub fwd_fee: Tokens,
296}
297
298impl InMsgFinal {
299    /// Load an inbound message envelope.
300    pub fn load_in_msg_envelope(&self) -> Result<MsgEnvelope, Error> {
301        self.in_msg_envelope.load()
302    }
303
304    /// Load a non-owned inbound message.
305    pub fn load_in_msg(&self) -> Result<Message<'_>, Error> {
306        let mut envelope = ok!(self.in_msg_envelope.cell.as_slice());
307        Message::load_from(&mut ok!(envelope.load_reference_as_slice()))
308    }
309
310    /// Load an inbound message envelope.
311    pub fn load_in_msg_info(&self) -> Result<IntMsgInfo, Error> {
312        let mut envelope = ok!(self.in_msg_envelope.cell.as_slice());
313        let mut message = ok!(envelope.load_reference_as_slice());
314        if let MsgInfo::Int(info) = ok!(<_>::load_from(&mut message)) {
315            Ok(info)
316        } else {
317            Err(Error::InvalidData)
318        }
319    }
320
321    /// Load an owned inbound message.
322    pub fn load_in_msg_owned(&self) -> Result<OwnedMessage, Error> {
323        let mut envelope = ok!(self.in_msg_envelope.cell.as_slice());
324        OwnedMessage::load_from(&mut ok!(envelope.load_reference_as_slice()))
325    }
326
327    /// Loads an inbound message cell.
328    pub fn load_in_msg_cell(&self) -> Result<Cell, Error> {
329        ok!(self.in_msg_envelope.cell.as_slice()).load_reference_cloned()
330    }
331
332    /// Returns a hash of the envelope with the inbound message.
333    pub fn in_msg_envelope_hash(&self) -> &HashBytes {
334        self.in_msg_envelope.cell.repr_hash()
335    }
336
337    /// Loads transaction.
338    pub fn load_transaction(&self) -> Result<Transaction, Error> {
339        self.transaction.load()
340    }
341}
342
343/// Internal message that was not processed in this block.
344#[derive(Clone, Debug, Eq, PartialEq, Store, Load)]
345#[cfg_attr(feature = "serde", derive(serde::Serialize))]
346pub struct InMsgTransit {
347    /// Old envelope.
348    pub in_msg_envelope: Lazy<MsgEnvelope>,
349    /// New envelope.
350    pub out_msg_envelope: Lazy<MsgEnvelope>,
351    /// Transit fee.
352    pub transit_fee: Tokens,
353}
354
355impl InMsgTransit {
356    /// Load a non-owned inbound message.
357    pub fn load_in_msg(&self) -> Result<Message<'_>, Error> {
358        let mut envelope = ok!(self.in_msg_envelope.cell.as_slice());
359        Message::load_from(&mut ok!(envelope.load_reference_as_slice()))
360    }
361
362    /// Load an owned inbound message.
363    pub fn load_in_msg_owned(&self) -> Result<OwnedMessage, Error> {
364        let mut envelope = ok!(self.in_msg_envelope.cell.as_slice());
365        OwnedMessage::load_from(&mut ok!(envelope.load_reference_as_slice()))
366    }
367
368    /// Load a non-owned outbound message.
369    pub fn load_out_msg(&self) -> Result<Message<'_>, Error> {
370        let mut envelope = ok!(self.out_msg_envelope.cell.as_slice());
371        Message::load_from(&mut ok!(envelope.load_reference_as_slice()))
372    }
373
374    /// Load an owned outbound message.
375    pub fn load_out_msg_owned(&self) -> Result<OwnedMessage, Error> {
376        let mut envelope = ok!(self.out_msg_envelope.cell.as_slice());
377        OwnedMessage::load_from(&mut ok!(envelope.load_reference_as_slice()))
378    }
379
380    /// Load inbound message cell.
381    pub fn load_in_msg_cell(&self) -> Result<Cell, Error> {
382        ok!(self.in_msg_envelope.cell.as_slice()).load_reference_cloned()
383    }
384
385    /// Load outbound message cell.
386    pub fn load_out_msg_cell(&self) -> Result<Cell, Error> {
387        ok!(self.out_msg_envelope.cell.as_slice()).load_reference_cloned()
388    }
389
390    /// Load inbound message envelope.
391    pub fn load_in_msg_envelope(&self) -> Result<MsgEnvelope, Error> {
392        self.in_msg_envelope.load()
393    }
394
395    /// Load outbound message envelope.
396    pub fn load_out_msg_envelope(&self) -> Result<MsgEnvelope, Error> {
397        self.out_msg_envelope.load()
398    }
399
400    /// Returns a hash of the envelope with the inbound message.
401    pub fn in_msg_envelope_hash(&self) -> &HashBytes {
402        self.in_msg_envelope.cell.repr_hash()
403    }
404
405    /// Returns a hash of the envelope with the outbound message.
406    pub fn out_msg_envelope_hash(&self) -> &HashBytes {
407        self.out_msg_envelope.cell.repr_hash()
408    }
409}