tycho_types/models/message/
mod.rs

1//! Message models.
2
3use std::borrow::Borrow;
4
5pub use self::address::*;
6pub use self::envelope::*;
7pub use self::in_message::*;
8pub use self::out_message::*;
9use crate::cell::*;
10use crate::error::Error;
11use crate::models::account::StateInit;
12use crate::models::currency::CurrencyCollection;
13use crate::num::*;
14
15mod address;
16mod envelope;
17mod in_message;
18mod out_message;
19#[cfg(test)]
20mod tests;
21
22/// Blockchain message (with body as slice).
23pub type Message<'a> = BaseMessage<MsgInfo, CellSlice<'a>>;
24
25impl EquivalentRepr<OwnedMessage> for Message<'_> {}
26impl EquivalentRepr<RelaxedMessage<'_>> for Message<'_> {}
27impl EquivalentRepr<OwnedRelaxedMessage> for Message<'_> {}
28
29/// Blockchain message (with body as slice parts).
30pub type OwnedMessage = BaseMessage<MsgInfo, CellSliceParts>;
31
32impl EquivalentRepr<Message<'_>> for OwnedMessage {}
33impl EquivalentRepr<RelaxedMessage<'_>> for OwnedMessage {}
34impl EquivalentRepr<OwnedRelaxedMessage> for OwnedMessage {}
35
36/// Unfinished blockchain message (with body as slice).
37pub type RelaxedMessage<'a> = BaseMessage<RelaxedMsgInfo, CellSlice<'a>>;
38
39impl EquivalentRepr<Message<'_>> for RelaxedMessage<'_> {}
40impl EquivalentRepr<OwnedMessage> for RelaxedMessage<'_> {}
41impl EquivalentRepr<OwnedRelaxedMessage> for RelaxedMessage<'_> {}
42
43/// Unfinished blockchain message (with body as slice parts).
44pub type OwnedRelaxedMessage = BaseMessage<RelaxedMsgInfo, CellSliceParts>;
45
46impl EquivalentRepr<Message<'_>> for OwnedRelaxedMessage {}
47impl EquivalentRepr<OwnedMessage> for OwnedRelaxedMessage {}
48impl EquivalentRepr<RelaxedMessage<'_>> for OwnedRelaxedMessage {}
49
50/// Blockchain message.
51#[derive(Debug, Clone)]
52pub struct BaseMessage<I, B> {
53    /// Message info.
54    pub info: I,
55    /// Optional state init.
56    pub init: Option<StateInit>,
57    /// Optional payload.
58    pub body: B,
59    /// Optional message layout.
60    pub layout: Option<MessageLayout>,
61}
62
63#[cfg(feature = "serde")]
64impl<I, B> serde::Serialize for BaseMessage<I, B>
65where
66    I: ExactSize + Store + serde::Serialize,
67    B: ExactSize + StoreBody,
68{
69    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
70        use serde::ser::{Error, SerializeStruct};
71
72        struct BodySerializer<'a, B: StoreBody>(&'a B);
73
74        impl<B: StoreBody> serde::Serialize for BodySerializer<'_, B> {
75            fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
76                let mut builder = CellBuilder::new();
77                ok!(self
78                    .0
79                    .store_body(false, &mut builder, Cell::empty_context())
80                    .map_err(Error::custom));
81                let cell = ok!(builder.build().map_err(Error::custom));
82                crate::boc::Boc::serialize(&cell, serializer)
83            }
84        }
85
86        if serializer.is_human_readable() {
87            let mut ser = ok!(serializer.serialize_struct("Message", 4));
88            ok!(ser.serialize_field("info", &self.info));
89            ok!(ser.serialize_field("init", &self.init));
90            ok!(ser.serialize_field("body", &BodySerializer(&self.body)));
91            ok!(ser.serialize_field("layout", &self.layout));
92            ser.end()
93        } else {
94            crate::boc::BocRepr::serialize(self, serializer)
95        }
96    }
97}
98
99#[cfg(feature = "serde")]
100impl<'de, I> serde::Deserialize<'de> for BaseMessage<I, CellSliceParts>
101where
102    for<'a> I: ExactSize + Load<'a> + serde::Deserialize<'de>,
103{
104    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
105    where
106        D: serde::Deserializer<'de>,
107    {
108        #[derive(serde::Deserialize)]
109        struct Message<I> {
110            info: I,
111            #[serde(default)]
112            init: Option<StateInit>,
113            #[serde(with = "crate::boc::Boc", default)]
114            body: Cell,
115            #[serde(default)]
116            layout: Option<MessageLayout>,
117        }
118
119        if deserializer.is_human_readable() {
120            let msg = Message::deserialize(deserializer)?;
121            Ok(Self {
122                info: msg.info,
123                init: msg.init,
124                body: msg.body.into(),
125                layout: msg.layout,
126            })
127        } else {
128            crate::boc::BocRepr::deserialize(deserializer)
129        }
130    }
131}
132
133#[cfg(feature = "arbitrary")]
134impl<'a, I: arbitrary::Arbitrary<'a>> arbitrary::Arbitrary<'a> for BaseMessage<I, CellSliceParts> {
135    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
136        Ok(Self {
137            info: u.arbitrary()?,
138            init: u.arbitrary()?,
139            body: u.arbitrary::<Cell>()?.into(),
140            layout: u.arbitrary()?,
141        })
142    }
143
144    fn size_hint(depth: usize) -> (usize, Option<usize>) {
145        Self::try_size_hint(depth).unwrap_or_default()
146    }
147
148    fn try_size_hint(
149        depth: usize,
150    ) -> arbitrary::Result<(usize, Option<usize>), arbitrary::MaxRecursionReached> {
151        Ok(arbitrary::size_hint::and_all(&[
152            <I as arbitrary::Arbitrary>::try_size_hint(depth)?,
153            <Option<StateInit> as arbitrary::Arbitrary>::try_size_hint(depth)?,
154            <Cell as arbitrary::Arbitrary>::try_size_hint(depth)?,
155            <Option<MessageLayout> as arbitrary::Arbitrary>::try_size_hint(depth)?,
156        ]))
157    }
158}
159
160impl<I: Borrow<MsgInfo>, B> BaseMessage<I, B> {
161    /// Returns the type of this message.
162    pub fn ty(&self) -> MsgType {
163        self.info.borrow().ty()
164    }
165}
166
167impl<I: ExactSize, B: ExactSize> BaseMessage<I, B> {
168    /// Computes the most optimal layout of the message parts.
169    pub fn compute_layout(info: &I, init: Option<&StateInit>, body: &B) -> MessageLayout {
170        let (layout, ..) = MessageLayout::compute(info.exact_size(), init, body.exact_size());
171        layout
172    }
173}
174
175impl<I, B> Store for BaseMessage<I, B>
176where
177    I: Store + ExactSize,
178    B: StoreBody + ExactSize,
179{
180    fn store_into(
181        &self,
182        builder: &mut CellBuilder,
183        context: &dyn CellContext,
184    ) -> Result<(), Error> {
185        let info_size = self.info.exact_size();
186        let body_size = self.body.exact_size();
187        let (layout, size) = match self.layout {
188            Some(layout) => {
189                let size = layout.compute_full_size(info_size, self.init.as_ref(), body_size);
190                (layout, size)
191            }
192            None => MessageLayout::compute(info_size, self.init.as_ref(), body_size),
193        };
194        let Size { bits, refs } = size;
195
196        // Check capacity
197        if !builder.has_capacity(bits, refs) {
198            return Err(Error::CellOverflow);
199        }
200
201        // Try to store info
202        ok!(self.info.store_into(builder, context));
203
204        // Try to store init
205        ok!(match &self.init {
206            Some(value) => {
207                ok!(builder.store_bit_one()); // just$1
208                SliceOrCell {
209                    to_cell: layout.init_to_cell,
210                    value,
211                }
212                .store_into(builder, context)
213            }
214            None => builder.store_bit_zero(), // nothing$0
215        });
216
217        // Try to store body
218        ok!(builder.store_bit(layout.body_to_cell));
219        self.body.store_body(layout.body_to_cell, builder, context)
220    }
221}
222
223impl<'a, I, B> Load<'a> for BaseMessage<I, B>
224where
225    I: Load<'a>,
226    B: LoadBody<'a>,
227{
228    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
229        let info = ok!(I::load_from(slice));
230        let init = ok!(Option::<SliceOrCell<StateInit>>::load_from(slice));
231
232        let body_to_cell = ok!(slice.load_bit());
233        let body = ok!(B::load_body(body_to_cell, slice));
234
235        let (init, init_to_cell) = match init {
236            Some(SliceOrCell { to_cell, value }) => (Some(value), to_cell),
237            None => (None, false),
238        };
239
240        let layout = MessageLayout {
241            init_to_cell,
242            body_to_cell,
243        };
244
245        Ok(Self {
246            info,
247            init,
248            body,
249            layout: Some(layout),
250        })
251    }
252}
253
254trait StoreBody {
255    fn store_body(
256        &self,
257        to_cell: bool,
258        builder: &mut CellBuilder,
259        context: &dyn CellContext,
260    ) -> Result<(), Error>;
261}
262
263impl StoreBody for CellSlice<'_> {
264    fn store_body(
265        &self,
266        to_cell: bool,
267        builder: &mut CellBuilder,
268        context: &dyn CellContext,
269    ) -> Result<(), Error> {
270        SliceOrCell {
271            to_cell,
272            value: self,
273        }
274        .store_only_value_into(builder, context)
275    }
276}
277
278impl StoreBody for CellSliceParts {
279    fn store_body(
280        &self,
281        to_cell: bool,
282        builder: &mut CellBuilder,
283        context: &dyn CellContext,
284    ) -> Result<(), Error> {
285        let (range, cell) = self;
286        if to_cell && range.is_full(cell.as_ref()) {
287            builder.store_reference(cell.clone())
288        } else {
289            SliceOrCell {
290                to_cell,
291                value: ok!(range.apply(cell)),
292            }
293            .store_only_value_into(builder, context)
294        }
295    }
296}
297
298trait LoadBody<'a>: Sized {
299    fn load_body(from_cell: bool, slice: &mut CellSlice<'a>) -> Result<Self, Error>;
300}
301
302impl<'a> LoadBody<'a> for CellSlice<'a> {
303    fn load_body(from_cell: bool, slice: &mut CellSlice<'a>) -> Result<Self, Error> {
304        if from_cell {
305            slice.load_reference_as_slice()
306        } else {
307            Ok(slice.load_remaining())
308        }
309    }
310}
311
312impl<'a> LoadBody<'a> for CellSliceParts {
313    fn load_body(from_cell: bool, slice: &mut CellSlice<'a>) -> Result<Self, Error> {
314        if from_cell {
315            slice.load_reference_cloned()
316        } else {
317            let slice = slice.load_remaining();
318            let mut builder = CellBuilder::new();
319            ok!(builder.store_slice(slice));
320            builder.build()
321        }
322        .map(From::from)
323    }
324}
325
326struct SliceOrCell<T> {
327    to_cell: bool,
328    value: T,
329}
330
331impl<T: Store> SliceOrCell<T> {
332    fn store_only_value_into(
333        &self,
334        builder: &mut CellBuilder,
335        context: &dyn CellContext,
336    ) -> Result<(), Error> {
337        if self.to_cell {
338            let cell = {
339                let mut builder = CellBuilder::new();
340                ok!(self.value.store_into(&mut builder, context));
341                ok!(builder.build_ext(context))
342            };
343            builder.store_reference(cell)
344        } else {
345            self.value.store_into(builder, context)
346        }
347    }
348}
349
350impl<T: Store> Store for SliceOrCell<T> {
351    fn store_into(
352        &self,
353        builder: &mut CellBuilder,
354        context: &dyn CellContext,
355    ) -> Result<(), Error> {
356        ok!(builder.store_bit(self.to_cell));
357        self.store_only_value_into(builder, context)
358    }
359}
360
361impl<'a, T: Load<'a>> Load<'a> for SliceOrCell<T> {
362    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
363        let to_cell = ok!(slice.load_bit());
364
365        let mut child_cell = if to_cell {
366            Some(ok!(slice.load_reference_as_slice()))
367        } else {
368            None
369        };
370
371        let slice = match &mut child_cell {
372            Some(slice) => slice,
373            None => slice,
374        };
375
376        Ok(Self {
377            to_cell,
378            value: ok!(T::load_from(slice)),
379        })
380    }
381}
382
383/// Message payload layout.
384#[derive(Debug, Copy, Clone, Eq, PartialEq)]
385#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
386#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
387pub struct MessageLayout {
388    /// Whether to store state init in a child cell.
389    pub init_to_cell: bool,
390    /// Whether to store payload as a child cell.
391    pub body_to_cell: bool,
392}
393
394impl MessageLayout {
395    /// Returns a plain message layout (init and body stored in the root cell).
396    #[inline]
397    pub const fn plain() -> Self {
398        Self {
399            init_to_cell: false,
400            body_to_cell: false,
401        }
402    }
403
404    /// Computes the number of bits and refs for this layout for the root cell.
405    pub const fn compute_full_size(
406        &self,
407        info_size: Size,
408        init: Option<&StateInit>,
409        body_size: Size,
410    ) -> Size {
411        let l = DetailedMessageLayout::compute(info_size, init, body_size);
412
413        let mut total = l.info;
414
415        // Append init bits and refs
416        if self.init_to_cell {
417            total.refs += 1;
418        } else {
419            total.bits += l.init.bits;
420            total.refs += l.init.refs;
421        }
422
423        // Append body bits and refs
424        if self.body_to_cell {
425            total.refs += 1;
426        } else {
427            total.bits += l.body.bits;
428            total.refs += l.body.refs;
429        }
430
431        total
432    }
433
434    /// Computes the most optimal layout of the message parts.
435    /// Also returns the number of bits and refs for the root cell.
436    pub const fn compute(
437        info_size: Size,
438        init: Option<&StateInit>,
439        body_size: Size,
440    ) -> (Self, Size) {
441        let l = DetailedMessageLayout::compute(info_size, init, body_size);
442
443        // Try plain layout
444        let total_bits = l.info.bits + l.init.bits + l.body.bits;
445        let total_refs = l.info.refs + l.init.refs + l.body.refs;
446        if total_bits <= MAX_BIT_LEN && total_refs <= MAX_REF_COUNT as u8 {
447            let layout = Self {
448                init_to_cell: false,
449                body_to_cell: false,
450            };
451            return (layout, Size {
452                bits: total_bits,
453                refs: total_refs,
454            });
455        }
456
457        // Try body to ref
458        let total_bits = l.info.bits + l.init.bits;
459        let total_refs = l.info.refs + l.init.refs;
460        if total_bits <= MAX_BIT_LEN && total_refs < MAX_REF_COUNT as u8 {
461            let layout = Self {
462                init_to_cell: false,
463                body_to_cell: true,
464            };
465            return (layout, Size {
466                bits: total_bits,
467                refs: total_refs + 1,
468            });
469        }
470
471        // Try init to ref
472        let total_bits = l.info.bits + l.body.bits;
473        let total_refs = l.info.refs + l.body.refs;
474        if total_bits <= MAX_BIT_LEN && total_refs < MAX_REF_COUNT as u8 {
475            let layout = Self {
476                init_to_cell: true,
477                body_to_cell: false,
478            };
479            return (layout, Size {
480                bits: total_bits,
481                refs: total_refs + 1,
482            });
483        }
484
485        // Fallback to init and body to ref
486        let layout = Self {
487            init_to_cell: true,
488            body_to_cell: true,
489        };
490        (layout, Size {
491            bits: l.info.bits,
492            refs: l.info.refs + 2,
493        })
494    }
495}
496
497struct DetailedMessageLayout {
498    info: Size,
499    init: Size,
500    body: Size,
501}
502
503impl DetailedMessageLayout {
504    const fn compute(mut info: Size, init: Option<&StateInit>, body: Size) -> Self {
505        info.bits += 2; // (Maybe X) (1bit) + (Either X) (1bit)
506
507        let init = match init {
508            Some(init) => {
509                info.bits += 1; // (Either X) (1bit)
510                init.exact_size_const()
511            }
512            None => Size::ZERO,
513        };
514
515        Self { info, init, body }
516    }
517}
518
519/// Unfinalized message info.
520#[derive(Debug, Clone, Eq, PartialEq)]
521#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
522#[cfg_attr(feature = "serde", serde(tag = "ty"))]
523#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
524pub enum RelaxedMsgInfo {
525    /// Internal message info,
526    Int(RelaxedIntMsgInfo),
527    /// External outgoing message info,
528    ExtOut(RelaxedExtOutMsgInfo),
529}
530
531impl RelaxedMsgInfo {
532    /// Exact size of this value when it is stored in slice.
533    pub const fn exact_size_const(&self) -> Size {
534        Size {
535            bits: self.bit_len(),
536            refs: self.has_references() as u8,
537        }
538    }
539
540    /// Returns the number of data bits that this struct occupies.
541    const fn bit_len(&self) -> u16 {
542        match self {
543            Self::Int(info) => info.bit_len(),
544            Self::ExtOut(info) => info.bit_len(),
545        }
546    }
547
548    const fn has_references(&self) -> bool {
549        match self {
550            Self::Int(info) => !info.value.other.is_empty(),
551            _ => false,
552        }
553    }
554}
555
556impl From<RelaxedIntMsgInfo> for RelaxedMsgInfo {
557    #[inline]
558    fn from(info: RelaxedIntMsgInfo) -> Self {
559        Self::Int(info)
560    }
561}
562
563impl From<RelaxedExtOutMsgInfo> for RelaxedMsgInfo {
564    #[inline]
565    fn from(info: RelaxedExtOutMsgInfo) -> Self {
566        Self::ExtOut(info)
567    }
568}
569
570impl From<IntMsgInfo> for RelaxedMsgInfo {
571    #[inline]
572    fn from(info: IntMsgInfo) -> Self {
573        Self::Int(RelaxedIntMsgInfo {
574            ihr_disabled: info.ihr_disabled,
575            bounce: info.bounce,
576            bounced: info.bounced,
577            src: Some(info.src),
578            dst: info.dst,
579            value: info.value,
580            ihr_fee: info.ihr_fee,
581            fwd_fee: info.fwd_fee,
582            created_lt: info.created_lt,
583            created_at: info.created_at,
584        })
585    }
586}
587
588impl From<ExtOutMsgInfo> for RelaxedMsgInfo {
589    #[inline]
590    fn from(info: ExtOutMsgInfo) -> Self {
591        Self::ExtOut(RelaxedExtOutMsgInfo {
592            src: Some(info.src),
593            dst: info.dst,
594            created_lt: info.created_lt,
595            created_at: info.created_at,
596        })
597    }
598}
599
600impl ExactSize for RelaxedMsgInfo {
601    #[inline]
602    fn exact_size(&self) -> Size {
603        self.exact_size_const()
604    }
605}
606
607impl Store for RelaxedMsgInfo {
608    fn store_into(
609        &self,
610        builder: &mut CellBuilder,
611        context: &dyn CellContext,
612    ) -> Result<(), Error> {
613        match self {
614            Self::Int(info) => {
615                ok!(builder.store_bit_zero());
616                info.store_into(builder, context)
617            }
618            Self::ExtOut(info) => {
619                ok!(builder.store_small_uint(0b11, 2));
620                info.store_into(builder, context)
621            }
622        }
623    }
624}
625
626impl<'a> Load<'a> for RelaxedMsgInfo {
627    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
628        Ok(if !ok!(slice.load_bit()) {
629            match RelaxedIntMsgInfo::load_from(slice) {
630                Ok(info) => Self::Int(info),
631                Err(e) => return Err(e),
632            }
633        } else if ok!(slice.load_bit()) {
634            match RelaxedExtOutMsgInfo::load_from(slice) {
635                Ok(info) => Self::ExtOut(info),
636                Err(e) => return Err(e),
637            }
638        } else {
639            return Err(Error::InvalidTag);
640        })
641    }
642}
643
644/// Message type.
645#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
646#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
647pub enum MsgType {
648    /// Internal message.
649    Int,
650    /// External incoming message.
651    ExtIn,
652    /// External outgoing message.
653    ExtOut,
654}
655
656impl MsgType {
657    /// Returns whether this message is internal.
658    pub const fn is_internal(&self) -> bool {
659        matches!(self, Self::Int)
660    }
661
662    /// Returns whether this message is external incoming.
663    pub const fn is_external_in(&self) -> bool {
664        matches!(self, Self::ExtIn)
665    }
666
667    /// Returns whether this message is external outgoing.
668    pub const fn is_external_out(&self) -> bool {
669        matches!(self, Self::ExtOut)
670    }
671}
672
673impl Store for MsgType {
674    fn store_into(&self, b: &mut CellBuilder, _: &dyn CellContext) -> Result<(), Error> {
675        match self {
676            Self::Int => b.store_bit_zero(),
677            Self::ExtIn => b.store_small_uint(0b10, 2),
678            Self::ExtOut => b.store_small_uint(0b11, 2),
679        }
680    }
681}
682
683impl<'a> Load<'a> for MsgType {
684    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
685        Ok(if !ok!(slice.load_bit()) {
686            Self::Int
687        } else if !ok!(slice.load_bit()) {
688            Self::ExtIn
689        } else {
690            Self::ExtOut
691        })
692    }
693}
694
695/// Message info.
696#[derive(Debug, Clone, Eq, PartialEq)]
697#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
698#[cfg_attr(feature = "serde", serde(tag = "ty"))]
699#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
700pub enum MsgInfo {
701    /// Internal message info,
702    Int(IntMsgInfo),
703    /// External incoming message info.
704    ExtIn(ExtInMsgInfo),
705    /// External outgoing message info,
706    ExtOut(ExtOutMsgInfo),
707}
708
709impl MsgInfo {
710    /// Returns the type of this message info.
711    pub const fn ty(&self) -> MsgType {
712        match self {
713            Self::Int(_) => MsgType::Int,
714            Self::ExtIn(_) => MsgType::ExtIn,
715            Self::ExtOut(_) => MsgType::ExtOut,
716        }
717    }
718
719    /// Returns whether this message is internal.
720    pub const fn is_internal(&self) -> bool {
721        matches!(self, Self::Int(_))
722    }
723
724    /// Returns whether this message is external incoming.
725    pub const fn is_external_in(&self) -> bool {
726        matches!(self, Self::ExtIn(_))
727    }
728
729    /// Returns whether this message is external outgoing.
730    pub const fn is_external_out(&self) -> bool {
731        matches!(self, Self::ExtOut(_))
732    }
733
734    /// Exact size of this value when it is stored in slice.
735    pub const fn exact_size_const(&self) -> Size {
736        Size {
737            bits: self.bit_len(),
738            refs: self.has_references() as u8,
739        }
740    }
741
742    /// Returns the number of data bits that this struct occupies.
743    const fn bit_len(&self) -> u16 {
744        match self {
745            Self::Int(info) => info.bit_len(),
746            Self::ExtIn(info) => info.bit_len(),
747            Self::ExtOut(info) => info.bit_len(),
748        }
749    }
750
751    const fn has_references(&self) -> bool {
752        match self {
753            Self::Int(info) => !info.value.other.is_empty(),
754            _ => false,
755        }
756    }
757}
758
759impl ExactSize for MsgInfo {
760    #[inline]
761    fn exact_size(&self) -> Size {
762        self.exact_size_const()
763    }
764}
765
766impl Store for MsgInfo {
767    fn store_into(
768        &self,
769        builder: &mut CellBuilder,
770        context: &dyn CellContext,
771    ) -> Result<(), Error> {
772        match self {
773            Self::Int(info) => {
774                ok!(builder.store_bit_zero());
775                info.store_into(builder, context)
776            }
777            Self::ExtIn(info) => {
778                ok!(builder.store_small_uint(0b10, 2));
779                info.store_into(builder, context)
780            }
781            Self::ExtOut(info) => {
782                ok!(builder.store_small_uint(0b11, 2));
783                info.store_into(builder, context)
784            }
785        }
786    }
787}
788
789impl<'a> Load<'a> for MsgInfo {
790    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
791        Ok(if !ok!(slice.load_bit()) {
792            match IntMsgInfo::load_from(slice) {
793                Ok(info) => Self::Int(info),
794                Err(e) => return Err(e),
795            }
796        } else if !ok!(slice.load_bit()) {
797            match ExtInMsgInfo::load_from(slice) {
798                Ok(info) => Self::ExtIn(info),
799                Err(e) => return Err(e),
800            }
801        } else {
802            match ExtOutMsgInfo::load_from(slice) {
803                Ok(info) => Self::ExtOut(info),
804                Err(e) => return Err(e),
805            }
806        })
807    }
808}
809
810impl From<IntMsgInfo> for MsgInfo {
811    #[inline]
812    fn from(value: IntMsgInfo) -> Self {
813        Self::Int(value)
814    }
815}
816
817impl From<ExtInMsgInfo> for MsgInfo {
818    #[inline]
819    fn from(value: ExtInMsgInfo) -> Self {
820        Self::ExtIn(value)
821    }
822}
823
824impl From<ExtOutMsgInfo> for MsgInfo {
825    #[inline]
826    fn from(value: ExtOutMsgInfo) -> Self {
827        Self::ExtOut(value)
828    }
829}
830
831/// Internal message info.
832#[derive(Debug, Clone, Eq, PartialEq)]
833#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
834#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
835pub struct IntMsgInfo {
836    /// Whether IHR is disabled for the message.
837    pub ihr_disabled: bool,
838    /// Whether to bounce this message back if the destination transaction fails.
839    pub bounce: bool,
840    /// Whether this message is a bounced message from some failed transaction.
841    pub bounced: bool,
842    /// Internal source address.
843    pub src: IntAddr,
844    /// Internal destination address.
845    pub dst: IntAddr,
846    /// Attached amounts.
847    pub value: CurrencyCollection,
848    /// IHR fee.
849    ///
850    /// NOTE: currently unused, but can be used to split attached amount.
851    pub ihr_fee: Tokens,
852    /// Forwarding fee paid for using the routing.
853    pub fwd_fee: Tokens,
854    /// Logical time when the message was created.
855    pub created_lt: u64,
856    /// Unix timestamp when the message was created.
857    pub created_at: u32,
858}
859
860impl Default for IntMsgInfo {
861    fn default() -> Self {
862        Self {
863            ihr_disabled: true,
864            bounce: false,
865            bounced: false,
866            src: Default::default(),
867            dst: Default::default(),
868            value: CurrencyCollection::ZERO,
869            ihr_fee: Default::default(),
870            fwd_fee: Default::default(),
871            created_lt: 0,
872            created_at: 0,
873        }
874    }
875}
876
877impl IntMsgInfo {
878    /// Returns the number of data bits that this struct occupies.
879    pub const fn bit_len(&self) -> u16 {
880        3 + self.src.bit_len()
881            + self.dst.bit_len()
882            + self.value.bit_len()
883            + self.ihr_fee.unwrap_bit_len()
884            + self.fwd_fee.unwrap_bit_len()
885            + 64
886            + 32
887    }
888}
889
890impl Store for IntMsgInfo {
891    fn store_into(
892        &self,
893        builder: &mut CellBuilder,
894        context: &dyn CellContext,
895    ) -> Result<(), Error> {
896        let flags =
897            ((self.ihr_disabled as u8) << 2) | ((self.bounce as u8) << 1) | self.bounced as u8;
898        ok!(builder.store_small_uint(flags, 3));
899        ok!(self.src.store_into(builder, context));
900        ok!(self.dst.store_into(builder, context));
901        ok!(self.value.store_into(builder, context));
902        ok!(self.ihr_fee.store_into(builder, context));
903        ok!(self.fwd_fee.store_into(builder, context));
904        ok!(builder.store_u64(self.created_lt));
905        builder.store_u32(self.created_at)
906    }
907}
908
909impl<'a> Load<'a> for IntMsgInfo {
910    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
911        let flags = ok!(slice.load_small_uint(3));
912        Ok(Self {
913            ihr_disabled: flags & 0b100 != 0,
914            bounce: flags & 0b010 != 0,
915            bounced: flags & 0b001 != 0,
916            src: ok!(IntAddr::load_from(slice)),
917            dst: ok!(IntAddr::load_from(slice)),
918            value: ok!(CurrencyCollection::load_from(slice)),
919            ihr_fee: ok!(Tokens::load_from(slice)),
920            fwd_fee: ok!(Tokens::load_from(slice)),
921            created_lt: ok!(slice.load_u64()),
922            created_at: ok!(slice.load_u32()),
923        })
924    }
925}
926
927/// Unfinished internal message info.
928#[derive(Debug, Clone, Eq, PartialEq)]
929#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
930#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
931pub struct RelaxedIntMsgInfo {
932    /// Whether IHR is disabled for the message.
933    pub ihr_disabled: bool,
934    /// Whether to bounce this message back if the destination transaction fails.
935    pub bounce: bool,
936    /// Whether this message is a bounced message from some failed transaction.
937    pub bounced: bool,
938    /// Optional internal source address.
939    pub src: Option<IntAddr>,
940    /// Internal destination address.
941    pub dst: IntAddr,
942    /// Attached amounts.
943    pub value: CurrencyCollection,
944    /// IHR fee.
945    ///
946    /// NOTE: currently unused, but can be used to split attached amount.
947    pub ihr_fee: Tokens,
948    /// Forwarding fee paid for using the routing.
949    pub fwd_fee: Tokens,
950    /// Logical time when the message was created.
951    pub created_lt: u64,
952    /// Unix timestamp when the message was created.
953    pub created_at: u32,
954}
955
956impl Default for RelaxedIntMsgInfo {
957    fn default() -> Self {
958        Self {
959            ihr_disabled: true,
960            bounce: false,
961            bounced: false,
962            src: Default::default(),
963            dst: Default::default(),
964            value: CurrencyCollection::ZERO,
965            ihr_fee: Default::default(),
966            fwd_fee: Default::default(),
967            created_lt: 0,
968            created_at: 0,
969        }
970    }
971}
972
973impl RelaxedIntMsgInfo {
974    /// Returns the number of data bits that this struct occupies.
975    pub const fn bit_len(&self) -> u16 {
976        3 + compute_opt_int_addr_bit_len(&self.src)
977            + self.dst.bit_len()
978            + self.value.bit_len()
979            + self.ihr_fee.unwrap_bit_len()
980            + self.fwd_fee.unwrap_bit_len()
981            + 64
982            + 32
983    }
984}
985
986impl Store for RelaxedIntMsgInfo {
987    fn store_into(
988        &self,
989        builder: &mut CellBuilder,
990        context: &dyn CellContext,
991    ) -> Result<(), Error> {
992        let flags =
993            ((self.ihr_disabled as u8) << 2) | ((self.bounce as u8) << 1) | self.bounced as u8;
994        ok!(builder.store_small_uint(flags, 3));
995        ok!(store_opt_int_addr(builder, context, &self.src));
996        ok!(self.dst.store_into(builder, context));
997        ok!(self.value.store_into(builder, context));
998        ok!(self.ihr_fee.store_into(builder, context));
999        ok!(self.fwd_fee.store_into(builder, context));
1000        ok!(builder.store_u64(self.created_lt));
1001        builder.store_u32(self.created_at)
1002    }
1003}
1004
1005impl<'a> Load<'a> for RelaxedIntMsgInfo {
1006    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
1007        let flags = ok!(slice.load_small_uint(3));
1008        Ok(Self {
1009            ihr_disabled: flags & 0b100 != 0,
1010            bounce: flags & 0b010 != 0,
1011            bounced: flags & 0b001 != 0,
1012            src: ok!(load_opt_int_addr(slice)),
1013            dst: ok!(IntAddr::load_from(slice)),
1014            value: ok!(CurrencyCollection::load_from(slice)),
1015            ihr_fee: ok!(Tokens::load_from(slice)),
1016            fwd_fee: ok!(Tokens::load_from(slice)),
1017            created_lt: ok!(slice.load_u64()),
1018            created_at: ok!(slice.load_u32()),
1019        })
1020    }
1021}
1022
1023/// External incoming message info.
1024#[derive(Debug, Default, Clone, Eq, PartialEq)]
1025#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1026#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1027pub struct ExtInMsgInfo {
1028    /// Optional external source address.
1029    #[cfg_attr(
1030        feature = "serde",
1031        serde(default, skip_serializing_if = "Option::is_none")
1032    )]
1033    pub src: Option<ExtAddr>,
1034    /// Internal destination address.
1035    pub dst: IntAddr,
1036    /// External message import fee.
1037    ///
1038    /// NOTE: currently unused and reserved for future use.
1039    pub import_fee: Tokens,
1040}
1041
1042impl ExtInMsgInfo {
1043    /// Returns the number of data bits that this struct occupies.
1044    pub const fn bit_len(&self) -> u16 {
1045        2 + compute_ext_addr_bit_len(&self.src)
1046            + self.dst.bit_len()
1047            + self.import_fee.unwrap_bit_len()
1048    }
1049}
1050
1051impl Store for ExtInMsgInfo {
1052    fn store_into(
1053        &self,
1054        builder: &mut CellBuilder,
1055        context: &dyn CellContext,
1056    ) -> Result<(), Error> {
1057        if !self.import_fee.is_valid() {
1058            return Err(Error::InvalidData);
1059        }
1060        if !builder.has_capacity(self.bit_len(), 0) {
1061            return Err(Error::CellOverflow);
1062        }
1063        ok!(store_ext_addr(builder, context, &self.src));
1064        ok!(self.dst.store_into(builder, context));
1065        self.import_fee.store_into(builder, context)
1066    }
1067}
1068
1069impl<'a> Load<'a> for ExtInMsgInfo {
1070    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
1071        Ok(Self {
1072            src: ok!(load_ext_addr(slice)),
1073            dst: ok!(IntAddr::load_from(slice)),
1074            import_fee: ok!(Tokens::load_from(slice)),
1075        })
1076    }
1077}
1078
1079/// External outgoing message info.
1080#[derive(Debug, Default, Clone, Eq, PartialEq)]
1081#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1082#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1083pub struct ExtOutMsgInfo {
1084    /// Internal source address.
1085    pub src: IntAddr,
1086    /// Optional external address.
1087    #[cfg_attr(
1088        feature = "serde",
1089        serde(default, skip_serializing_if = "Option::is_none")
1090    )]
1091    pub dst: Option<ExtAddr>,
1092    /// Logical time when the message was created.
1093    pub created_lt: u64,
1094    /// Unix timestamp when the message was created.
1095    pub created_at: u32,
1096}
1097
1098impl ExtOutMsgInfo {
1099    /// Returns the number of data bits that this struct occupies.
1100    pub const fn bit_len(&self) -> u16 {
1101        2 + self.src.bit_len() + compute_ext_addr_bit_len(&self.dst) + 64 + 32
1102    }
1103}
1104
1105impl Store for ExtOutMsgInfo {
1106    fn store_into(
1107        &self,
1108        builder: &mut CellBuilder,
1109        context: &dyn CellContext,
1110    ) -> Result<(), Error> {
1111        if !builder.has_capacity(self.bit_len(), 0) {
1112            return Err(Error::CellOverflow);
1113        }
1114        ok!(self.src.store_into(builder, context));
1115        ok!(store_ext_addr(builder, context, &self.dst));
1116        ok!(builder.store_u64(self.created_lt));
1117        builder.store_u32(self.created_at)
1118    }
1119}
1120
1121impl<'a> Load<'a> for ExtOutMsgInfo {
1122    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
1123        Ok(Self {
1124            src: ok!(IntAddr::load_from(slice)),
1125            dst: ok!(load_ext_addr(slice)),
1126            created_lt: ok!(slice.load_u64()),
1127            created_at: ok!(slice.load_u32()),
1128        })
1129    }
1130}
1131
1132/// Unfinalized external outgoing message info.
1133#[derive(Debug, Default, Clone, Eq, PartialEq)]
1134#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1135#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1136pub struct RelaxedExtOutMsgInfo {
1137    /// Optional internal source address.
1138    pub src: Option<IntAddr>,
1139    /// Optional external address.
1140    #[cfg_attr(
1141        feature = "serde",
1142        serde(default, skip_serializing_if = "Option::is_none")
1143    )]
1144    pub dst: Option<ExtAddr>,
1145    /// Logical time when the message was created.
1146    pub created_lt: u64,
1147    /// Unix timestamp when the message was created.
1148    pub created_at: u32,
1149}
1150
1151impl RelaxedExtOutMsgInfo {
1152    /// Returns the number of data bits that this struct occupies.
1153    pub const fn bit_len(&self) -> u16 {
1154        2 + compute_opt_int_addr_bit_len(&self.src) + compute_ext_addr_bit_len(&self.dst) + 64 + 32
1155    }
1156}
1157
1158impl Store for RelaxedExtOutMsgInfo {
1159    fn store_into(
1160        &self,
1161        builder: &mut CellBuilder,
1162        context: &dyn CellContext,
1163    ) -> Result<(), Error> {
1164        ok!(store_opt_int_addr(builder, context, &self.src));
1165        ok!(store_ext_addr(builder, context, &self.dst));
1166        ok!(builder.store_u64(self.created_lt));
1167        builder.store_u32(self.created_at)
1168    }
1169}
1170
1171impl<'a> Load<'a> for RelaxedExtOutMsgInfo {
1172    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
1173        Ok(Self {
1174            src: ok!(load_opt_int_addr(slice)),
1175            dst: ok!(load_ext_addr(slice)),
1176            created_lt: ok!(slice.load_u64()),
1177            created_at: ok!(slice.load_u32()),
1178        })
1179    }
1180}
1181
1182const fn compute_ext_addr_bit_len(addr: &Option<ExtAddr>) -> u16 {
1183    match addr {
1184        Some(addr) => 2 + addr.bit_len(),
1185        None => 2,
1186    }
1187}
1188
1189fn store_ext_addr(
1190    builder: &mut CellBuilder,
1191    context: &dyn CellContext,
1192    addr: &Option<ExtAddr>,
1193) -> Result<(), Error> {
1194    match addr {
1195        None => builder.store_zeros(2),
1196        Some(ExtAddr { data_bit_len, data }) => {
1197            if !builder.has_capacity(2 + Uint9::BITS + data_bit_len.into_inner(), 0) {
1198                return Err(Error::CellOverflow);
1199            }
1200            ok!(builder.store_bit_zero());
1201            ok!(builder.store_bit_one());
1202            ok!(data_bit_len.store_into(builder, context));
1203            builder.store_raw(data, data_bit_len.into_inner())
1204        }
1205    }
1206}
1207
1208fn load_ext_addr(slice: &mut CellSlice<'_>) -> Result<Option<ExtAddr>, Error> {
1209    if ok!(slice.load_bit()) {
1210        return Err(Error::InvalidTag);
1211    }
1212
1213    if !ok!(slice.load_bit()) {
1214        return Ok(None);
1215    }
1216
1217    let data_bit_len = ok!(Uint9::load_from(slice));
1218    if !slice.has_remaining(data_bit_len.into_inner(), 0) {
1219        return Err(Error::CellUnderflow);
1220    }
1221
1222    let mut data = vec![0; data_bit_len.into_inner().div_ceil(8) as usize];
1223    ok!(slice.load_raw(&mut data, data_bit_len.into_inner()));
1224    Ok(Some(ExtAddr { data_bit_len, data }))
1225}
1226
1227const fn compute_opt_int_addr_bit_len(addr: &Option<IntAddr>) -> u16 {
1228    match addr {
1229        Some(src) => src.bit_len(),
1230        None => 2,
1231    }
1232}
1233
1234fn store_opt_int_addr(
1235    builder: &mut CellBuilder,
1236    context: &dyn CellContext,
1237    addr: &Option<IntAddr>,
1238) -> Result<(), Error> {
1239    match addr {
1240        Some(addr) => addr.store_into(builder, context),
1241        None => builder.store_zeros(2),
1242    }
1243}
1244
1245fn load_opt_int_addr(slice: &mut CellSlice<'_>) -> Result<Option<IntAddr>, Error> {
1246    if ok!(slice.get_bit(0)) {
1247        IntAddr::load_from(slice).map(Some)
1248    } else if ok!(slice.load_small_uint(2)) == 0b00 {
1249        Ok(None)
1250    } else {
1251        Err(Error::InvalidTag)
1252    }
1253}