everscale_types/models/message/
mod.rs

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