1use std::borrow::Borrow;
4
5use bitflags::bitflags;
6
7pub use self::address::*;
8pub use self::envelope::*;
9pub use self::in_message::*;
10pub use self::out_message::*;
11use crate::cell::*;
12use crate::error::Error;
13use crate::models::account::StateInit;
14use crate::models::currency::CurrencyCollection;
15use crate::num::*;
16
17mod address;
18mod envelope;
19mod in_message;
20mod out_message;
21#[cfg(test)]
22mod tests;
23
24pub type Message<'a> = BaseMessage<MsgInfo, CellSlice<'a>>;
26
27impl EquivalentRepr<OwnedMessage> for Message<'_> {}
28impl EquivalentRepr<RelaxedMessage<'_>> for Message<'_> {}
29impl EquivalentRepr<OwnedRelaxedMessage> for Message<'_> {}
30
31pub type OwnedMessage = BaseMessage<MsgInfo, CellSliceParts>;
33
34impl EquivalentRepr<Message<'_>> for OwnedMessage {}
35impl EquivalentRepr<RelaxedMessage<'_>> for OwnedMessage {}
36impl EquivalentRepr<OwnedRelaxedMessage> for OwnedMessage {}
37
38pub type RelaxedMessage<'a> = BaseMessage<RelaxedMsgInfo, CellSlice<'a>>;
40
41impl EquivalentRepr<Message<'_>> for RelaxedMessage<'_> {}
42impl EquivalentRepr<OwnedMessage> for RelaxedMessage<'_> {}
43impl EquivalentRepr<OwnedRelaxedMessage> for RelaxedMessage<'_> {}
44
45pub type OwnedRelaxedMessage = BaseMessage<RelaxedMsgInfo, CellSliceParts>;
47
48impl EquivalentRepr<Message<'_>> for OwnedRelaxedMessage {}
49impl EquivalentRepr<OwnedMessage> for OwnedRelaxedMessage {}
50impl EquivalentRepr<RelaxedMessage<'_>> for OwnedRelaxedMessage {}
51
52#[derive(Debug, Clone)]
54pub struct BaseMessage<I, B> {
55 pub info: I,
57 pub init: Option<StateInit>,
59 pub body: B,
61 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, 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 Ok(Self {
124 info: msg.info,
125 init: msg.init,
126 body: msg.body.into(),
127 layout: msg.layout,
128 })
129 } else {
130 crate::boc::BocRepr::deserialize(deserializer)
131 }
132 }
133}
134
135#[cfg(feature = "arbitrary")]
136impl<'a, I: arbitrary::Arbitrary<'a>> arbitrary::Arbitrary<'a> for BaseMessage<I, CellSliceParts> {
137 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
138 Ok(Self {
139 info: u.arbitrary()?,
140 init: u.arbitrary()?,
141 body: u.arbitrary::<Cell>()?.into(),
142 layout: u.arbitrary()?,
143 })
144 }
145
146 fn size_hint(depth: usize) -> (usize, Option<usize>) {
147 Self::try_size_hint(depth).unwrap_or_default()
148 }
149
150 fn try_size_hint(
151 depth: usize,
152 ) -> arbitrary::Result<(usize, Option<usize>), arbitrary::MaxRecursionReached> {
153 Ok(arbitrary::size_hint::and_all(&[
154 <I as arbitrary::Arbitrary>::try_size_hint(depth)?,
155 <Option<StateInit> as arbitrary::Arbitrary>::try_size_hint(depth)?,
156 <Cell as arbitrary::Arbitrary>::try_size_hint(depth)?,
157 <Option<MessageLayout> as arbitrary::Arbitrary>::try_size_hint(depth)?,
158 ]))
159 }
160}
161
162impl<I: Borrow<MsgInfo>, B> BaseMessage<I, B> {
163 pub fn ty(&self) -> MsgType {
165 self.info.borrow().ty()
166 }
167}
168
169impl<I: ExactSize, B: ExactSize> BaseMessage<I, B> {
170 pub fn compute_layout(info: &I, init: Option<&StateInit>, body: &B) -> MessageLayout {
172 let (layout, ..) = MessageLayout::compute(info.exact_size(), init, body.exact_size());
173 layout
174 }
175}
176
177impl<I, B> Store for BaseMessage<I, B>
178where
179 I: Store + ExactSize,
180 B: StoreBody + ExactSize,
181{
182 fn store_into(
183 &self,
184 builder: &mut CellBuilder,
185 context: &dyn CellContext,
186 ) -> Result<(), Error> {
187 let info_size = self.info.exact_size();
188 let body_size = self.body.exact_size();
189 let (layout, size) = match self.layout {
190 Some(layout) => {
191 let size = layout.compute_full_size(info_size, self.init.as_ref(), body_size);
192 (layout, size)
193 }
194 None => MessageLayout::compute(info_size, self.init.as_ref(), body_size),
195 };
196 let Size { bits, refs } = size;
197
198 if !builder.has_capacity(bits, refs) {
200 return Err(Error::CellOverflow);
201 }
202
203 ok!(self.info.store_into(builder, context));
205
206 ok!(match &self.init {
208 Some(value) => {
209 ok!(builder.store_bit_one()); SliceOrCell {
211 to_cell: layout.init_to_cell,
212 value,
213 }
214 .store_into(builder, context)
215 }
216 None => builder.store_bit_zero(), });
218
219 ok!(builder.store_bit(layout.body_to_cell));
221 self.body.store_body(layout.body_to_cell, builder, context)
222 }
223}
224
225impl<'a, I, B> Load<'a> for BaseMessage<I, B>
226where
227 I: Load<'a>,
228 B: LoadBody<'a>,
229{
230 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
231 let info = ok!(I::load_from(slice));
232 let init = ok!(Option::<SliceOrCell<StateInit>>::load_from(slice));
233
234 let body_to_cell = ok!(slice.load_bit());
235 let body = ok!(B::load_body(body_to_cell, slice));
236
237 let (init, init_to_cell) = match init {
238 Some(SliceOrCell { to_cell, value }) => (Some(value), to_cell),
239 None => (None, false),
240 };
241
242 let layout = MessageLayout {
243 init_to_cell,
244 body_to_cell,
245 };
246
247 Ok(Self {
248 info,
249 init,
250 body,
251 layout: Some(layout),
252 })
253 }
254}
255
256trait StoreBody {
257 fn store_body(
258 &self,
259 to_cell: bool,
260 builder: &mut CellBuilder,
261 context: &dyn CellContext,
262 ) -> Result<(), Error>;
263}
264
265impl StoreBody for CellSlice<'_> {
266 fn store_body(
267 &self,
268 to_cell: bool,
269 builder: &mut CellBuilder,
270 context: &dyn CellContext,
271 ) -> Result<(), Error> {
272 SliceOrCell {
273 to_cell,
274 value: self,
275 }
276 .store_only_value_into(builder, context)
277 }
278}
279
280impl StoreBody for CellSliceParts {
281 fn store_body(
282 &self,
283 to_cell: bool,
284 builder: &mut CellBuilder,
285 context: &dyn CellContext,
286 ) -> Result<(), Error> {
287 let (range, cell) = self;
288 if to_cell && range.is_full(cell.as_ref()) {
289 builder.store_reference(cell.clone())
290 } else {
291 SliceOrCell {
292 to_cell,
293 value: ok!(range.apply(cell)),
294 }
295 .store_only_value_into(builder, context)
296 }
297 }
298}
299
300trait LoadBody<'a>: Sized {
301 fn load_body(from_cell: bool, slice: &mut CellSlice<'a>) -> Result<Self, Error>;
302}
303
304impl<'a> LoadBody<'a> for CellSlice<'a> {
305 fn load_body(from_cell: bool, slice: &mut CellSlice<'a>) -> Result<Self, Error> {
306 if from_cell {
307 slice.load_reference_as_slice()
308 } else {
309 Ok(slice.load_remaining())
310 }
311 }
312}
313
314impl<'a> LoadBody<'a> for CellSliceParts {
315 fn load_body(from_cell: bool, slice: &mut CellSlice<'a>) -> Result<Self, Error> {
316 if from_cell {
317 slice.load_reference_cloned()
318 } else {
319 let slice = slice.load_remaining();
320 let mut builder = CellBuilder::new();
321 ok!(builder.store_slice(slice));
322 builder.build()
323 }
324 .map(From::from)
325 }
326}
327
328struct SliceOrCell<T> {
329 to_cell: bool,
330 value: T,
331}
332
333impl<T: Store> SliceOrCell<T> {
334 fn store_only_value_into(
335 &self,
336 builder: &mut CellBuilder,
337 context: &dyn CellContext,
338 ) -> Result<(), Error> {
339 if self.to_cell {
340 let cell = {
341 let mut builder = CellBuilder::new();
342 ok!(self.value.store_into(&mut builder, context));
343 ok!(builder.build_ext(context))
344 };
345 builder.store_reference(cell)
346 } else {
347 self.value.store_into(builder, context)
348 }
349 }
350}
351
352impl<T: Store> Store for SliceOrCell<T> {
353 fn store_into(
354 &self,
355 builder: &mut CellBuilder,
356 context: &dyn CellContext,
357 ) -> Result<(), Error> {
358 ok!(builder.store_bit(self.to_cell));
359 self.store_only_value_into(builder, context)
360 }
361}
362
363impl<'a, T: Load<'a>> Load<'a> for SliceOrCell<T> {
364 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
365 let to_cell = ok!(slice.load_bit());
366
367 let mut child_cell = if to_cell {
368 Some(ok!(slice.load_reference_as_slice()))
369 } else {
370 None
371 };
372
373 let slice = match &mut child_cell {
374 Some(slice) => slice,
375 None => slice,
376 };
377
378 Ok(Self {
379 to_cell,
380 value: ok!(T::load_from(slice)),
381 })
382 }
383}
384
385#[derive(Debug, Copy, Clone, Eq, PartialEq)]
387#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
388#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
389pub struct MessageLayout {
390 pub init_to_cell: bool,
392 pub body_to_cell: bool,
394}
395
396impl MessageLayout {
397 #[inline]
399 pub const fn plain() -> Self {
400 Self {
401 init_to_cell: false,
402 body_to_cell: false,
403 }
404 }
405
406 pub const fn compute_full_size(
408 &self,
409 info_size: Size,
410 init: Option<&StateInit>,
411 body_size: Size,
412 ) -> Size {
413 let l = DetailedMessageLayout::compute(info_size, init, body_size);
414
415 let mut total = l.info;
416
417 if self.init_to_cell {
419 total.refs += 1;
420 } else {
421 total.bits += l.init.bits;
422 total.refs += l.init.refs;
423 }
424
425 if self.body_to_cell {
427 total.refs += 1;
428 } else {
429 total.bits += l.body.bits;
430 total.refs += l.body.refs;
431 }
432
433 total
434 }
435
436 pub const fn compute(
439 info_size: Size,
440 init: Option<&StateInit>,
441 body_size: Size,
442 ) -> (Self, Size) {
443 let l = DetailedMessageLayout::compute(info_size, init, body_size);
444
445 let total_bits = l.info.bits + l.init.bits + l.body.bits;
447 let total_refs = l.info.refs + l.init.refs + l.body.refs;
448 if total_bits <= MAX_BIT_LEN && total_refs <= MAX_REF_COUNT as u8 {
449 let layout = Self {
450 init_to_cell: false,
451 body_to_cell: false,
452 };
453 return (layout, Size {
454 bits: total_bits,
455 refs: total_refs,
456 });
457 }
458
459 let total_bits = l.info.bits + l.init.bits;
461 let total_refs = l.info.refs + l.init.refs;
462 if total_bits <= MAX_BIT_LEN && total_refs < MAX_REF_COUNT as u8 {
463 let layout = Self {
464 init_to_cell: false,
465 body_to_cell: true,
466 };
467 return (layout, Size {
468 bits: total_bits,
469 refs: total_refs + 1,
470 });
471 }
472
473 let total_bits = l.info.bits + l.body.bits;
475 let total_refs = l.info.refs + l.body.refs;
476 if total_bits <= MAX_BIT_LEN && total_refs < MAX_REF_COUNT as u8 {
477 let layout = Self {
478 init_to_cell: true,
479 body_to_cell: false,
480 };
481 return (layout, Size {
482 bits: total_bits,
483 refs: total_refs + 1,
484 });
485 }
486
487 let layout = Self {
489 init_to_cell: true,
490 body_to_cell: true,
491 };
492 (layout, Size {
493 bits: l.info.bits,
494 refs: l.info.refs + 2,
495 })
496 }
497}
498
499struct DetailedMessageLayout {
500 info: Size,
501 init: Size,
502 body: Size,
503}
504
505impl DetailedMessageLayout {
506 const fn compute(mut info: Size, init: Option<&StateInit>, body: Size) -> Self {
507 info.bits += 2; let init = match init {
510 Some(init) => {
511 info.bits += 1; init.exact_size_const()
513 }
514 None => Size::ZERO,
515 };
516
517 Self { info, init, body }
518 }
519}
520
521#[derive(Debug, Clone, Eq, PartialEq)]
523#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
524#[cfg_attr(feature = "serde", serde(tag = "ty"))]
525#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
526pub enum RelaxedMsgInfo {
527 Int(RelaxedIntMsgInfo),
529 ExtOut(RelaxedExtOutMsgInfo),
531}
532
533impl RelaxedMsgInfo {
534 pub const fn exact_size_const(&self) -> Size {
536 Size {
537 bits: self.bit_len(),
538 refs: self.has_references() as u8,
539 }
540 }
541
542 const fn bit_len(&self) -> u16 {
544 match self {
545 Self::Int(info) => info.bit_len(),
546 Self::ExtOut(info) => info.bit_len(),
547 }
548 }
549
550 const fn has_references(&self) -> bool {
551 match self {
552 Self::Int(info) => !info.value.other.is_empty(),
553 _ => false,
554 }
555 }
556}
557
558impl From<RelaxedIntMsgInfo> for RelaxedMsgInfo {
559 #[inline]
560 fn from(info: RelaxedIntMsgInfo) -> Self {
561 Self::Int(info)
562 }
563}
564
565impl From<RelaxedExtOutMsgInfo> for RelaxedMsgInfo {
566 #[inline]
567 fn from(info: RelaxedExtOutMsgInfo) -> Self {
568 Self::ExtOut(info)
569 }
570}
571
572impl From<IntMsgInfo> for RelaxedMsgInfo {
573 #[inline]
574 fn from(info: IntMsgInfo) -> Self {
575 Self::Int(RelaxedIntMsgInfo {
576 ihr_disabled: info.ihr_disabled,
577 bounce: info.bounce,
578 bounced: info.bounced,
579 src: Some(info.src),
580 dst: info.dst,
581 value: info.value,
582 extra_flags: info.extra_flags,
583 fwd_fee: info.fwd_fee,
584 created_lt: info.created_lt,
585 created_at: info.created_at,
586 })
587 }
588}
589
590impl From<ExtOutMsgInfo> for RelaxedMsgInfo {
591 #[inline]
592 fn from(info: ExtOutMsgInfo) -> Self {
593 Self::ExtOut(RelaxedExtOutMsgInfo {
594 src: Some(info.src),
595 dst: info.dst,
596 created_lt: info.created_lt,
597 created_at: info.created_at,
598 })
599 }
600}
601
602impl ExactSize for RelaxedMsgInfo {
603 #[inline]
604 fn exact_size(&self) -> Size {
605 self.exact_size_const()
606 }
607}
608
609impl Store for RelaxedMsgInfo {
610 fn store_into(
611 &self,
612 builder: &mut CellBuilder,
613 context: &dyn CellContext,
614 ) -> Result<(), Error> {
615 match self {
616 Self::Int(info) => {
617 ok!(builder.store_bit_zero());
618 info.store_into(builder, context)
619 }
620 Self::ExtOut(info) => {
621 ok!(builder.store_small_uint(0b11, 2));
622 info.store_into(builder, context)
623 }
624 }
625 }
626}
627
628impl<'a> Load<'a> for RelaxedMsgInfo {
629 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
630 Ok(if !ok!(slice.load_bit()) {
631 match RelaxedIntMsgInfo::load_from(slice) {
632 Ok(info) => Self::Int(info),
633 Err(e) => return Err(e),
634 }
635 } else if ok!(slice.load_bit()) {
636 match RelaxedExtOutMsgInfo::load_from(slice) {
637 Ok(info) => Self::ExtOut(info),
638 Err(e) => return Err(e),
639 }
640 } else {
641 return Err(Error::InvalidTag);
642 })
643 }
644}
645
646#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
648#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
649pub enum MsgType {
650 Int,
652 ExtIn,
654 ExtOut,
656}
657
658impl MsgType {
659 pub const fn is_internal(&self) -> bool {
661 matches!(self, Self::Int)
662 }
663
664 pub const fn is_external_in(&self) -> bool {
666 matches!(self, Self::ExtIn)
667 }
668
669 pub const fn is_external_out(&self) -> bool {
671 matches!(self, Self::ExtOut)
672 }
673}
674
675impl Store for MsgType {
676 fn store_into(&self, b: &mut CellBuilder, _: &dyn CellContext) -> Result<(), Error> {
677 match self {
678 Self::Int => b.store_bit_zero(),
679 Self::ExtIn => b.store_small_uint(0b10, 2),
680 Self::ExtOut => b.store_small_uint(0b11, 2),
681 }
682 }
683}
684
685impl<'a> Load<'a> for MsgType {
686 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
687 Ok(if !ok!(slice.load_bit()) {
688 Self::Int
689 } else if !ok!(slice.load_bit()) {
690 Self::ExtIn
691 } else {
692 Self::ExtOut
693 })
694 }
695}
696
697#[derive(Debug, Clone, Eq, PartialEq)]
699#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
700#[cfg_attr(feature = "serde", serde(tag = "ty"))]
701#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
702pub enum MsgInfo {
703 Int(IntMsgInfo),
705 ExtIn(ExtInMsgInfo),
707 ExtOut(ExtOutMsgInfo),
709}
710
711impl MsgInfo {
712 pub const fn ty(&self) -> MsgType {
714 match self {
715 Self::Int(_) => MsgType::Int,
716 Self::ExtIn(_) => MsgType::ExtIn,
717 Self::ExtOut(_) => MsgType::ExtOut,
718 }
719 }
720
721 pub const fn is_internal(&self) -> bool {
723 matches!(self, Self::Int(_))
724 }
725
726 pub const fn is_external_in(&self) -> bool {
728 matches!(self, Self::ExtIn(_))
729 }
730
731 pub const fn is_external_out(&self) -> bool {
733 matches!(self, Self::ExtOut(_))
734 }
735
736 pub const fn exact_size_const(&self) -> Size {
738 Size {
739 bits: self.bit_len(),
740 refs: self.has_references() as u8,
741 }
742 }
743
744 const fn bit_len(&self) -> u16 {
746 match self {
747 Self::Int(info) => info.bit_len(),
748 Self::ExtIn(info) => info.bit_len(),
749 Self::ExtOut(info) => info.bit_len(),
750 }
751 }
752
753 const fn has_references(&self) -> bool {
754 match self {
755 Self::Int(info) => !info.value.other.is_empty(),
756 _ => false,
757 }
758 }
759}
760
761impl ExactSize for MsgInfo {
762 #[inline]
763 fn exact_size(&self) -> Size {
764 self.exact_size_const()
765 }
766}
767
768impl Store for MsgInfo {
769 fn store_into(
770 &self,
771 builder: &mut CellBuilder,
772 context: &dyn CellContext,
773 ) -> Result<(), Error> {
774 match self {
775 Self::Int(info) => {
776 ok!(builder.store_bit_zero());
777 info.store_into(builder, context)
778 }
779 Self::ExtIn(info) => {
780 ok!(builder.store_small_uint(0b10, 2));
781 info.store_into(builder, context)
782 }
783 Self::ExtOut(info) => {
784 ok!(builder.store_small_uint(0b11, 2));
785 info.store_into(builder, context)
786 }
787 }
788 }
789}
790
791impl<'a> Load<'a> for MsgInfo {
792 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
793 Ok(if !ok!(slice.load_bit()) {
794 match IntMsgInfo::load_from(slice) {
795 Ok(info) => Self::Int(info),
796 Err(e) => return Err(e),
797 }
798 } else if !ok!(slice.load_bit()) {
799 match ExtInMsgInfo::load_from(slice) {
800 Ok(info) => Self::ExtIn(info),
801 Err(e) => return Err(e),
802 }
803 } else {
804 match ExtOutMsgInfo::load_from(slice) {
805 Ok(info) => Self::ExtOut(info),
806 Err(e) => return Err(e),
807 }
808 })
809 }
810}
811
812impl From<IntMsgInfo> for MsgInfo {
813 #[inline]
814 fn from(value: IntMsgInfo) -> Self {
815 Self::Int(value)
816 }
817}
818
819impl From<ExtInMsgInfo> for MsgInfo {
820 #[inline]
821 fn from(value: ExtInMsgInfo) -> Self {
822 Self::ExtIn(value)
823 }
824}
825
826impl From<ExtOutMsgInfo> for MsgInfo {
827 #[inline]
828 fn from(value: ExtOutMsgInfo) -> Self {
829 Self::ExtOut(value)
830 }
831}
832
833#[derive(Debug, Clone, Eq, PartialEq)]
835#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
836#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
837pub struct IntMsgInfo {
838 pub ihr_disabled: bool,
840 pub bounce: bool,
842 pub bounced: bool,
844 pub src: IntAddr,
846 pub dst: IntAddr,
848 pub value: CurrencyCollection,
850 pub extra_flags: MessageExtraFlags,
852 pub fwd_fee: Tokens,
854 pub created_lt: u64,
856 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 extra_flags: Default::default(),
870 fwd_fee: Default::default(),
871 created_lt: 0,
872 created_at: 0,
873 }
874 }
875}
876
877impl IntMsgInfo {
878 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.extra_flags.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.extra_flags.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 extra_flags: ok!(MessageExtraFlags::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#[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 pub ihr_disabled: bool,
934 pub bounce: bool,
936 pub bounced: bool,
938 pub src: Option<IntAddr>,
940 pub dst: IntAddr,
942 pub value: CurrencyCollection,
944 pub extra_flags: MessageExtraFlags,
946 pub fwd_fee: Tokens,
948 pub created_lt: u64,
950 pub created_at: u32,
952}
953
954impl Default for RelaxedIntMsgInfo {
955 fn default() -> Self {
956 Self {
957 ihr_disabled: true,
958 bounce: false,
959 bounced: false,
960 src: Default::default(),
961 dst: Default::default(),
962 value: CurrencyCollection::ZERO,
963 extra_flags: Default::default(),
964 fwd_fee: Default::default(),
965 created_lt: 0,
966 created_at: 0,
967 }
968 }
969}
970
971impl RelaxedIntMsgInfo {
972 pub const fn bit_len(&self) -> u16 {
974 3 + compute_opt_int_addr_bit_len(&self.src)
975 + self.dst.bit_len()
976 + self.value.bit_len()
977 + self.extra_flags.bit_len()
978 + self.fwd_fee.unwrap_bit_len()
979 + 64
980 + 32
981 }
982}
983
984impl Store for RelaxedIntMsgInfo {
985 fn store_into(
986 &self,
987 builder: &mut CellBuilder,
988 context: &dyn CellContext,
989 ) -> Result<(), Error> {
990 let flags =
991 ((self.ihr_disabled as u8) << 2) | ((self.bounce as u8) << 1) | self.bounced as u8;
992 ok!(builder.store_small_uint(flags, 3));
993 ok!(store_opt_int_addr(builder, context, &self.src));
994 ok!(self.dst.store_into(builder, context));
995 ok!(self.value.store_into(builder, context));
996 ok!(self.extra_flags.store_into(builder, context));
997 ok!(self.fwd_fee.store_into(builder, context));
998 ok!(builder.store_u64(self.created_lt));
999 builder.store_u32(self.created_at)
1000 }
1001}
1002
1003impl<'a> Load<'a> for RelaxedIntMsgInfo {
1004 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
1005 let flags = ok!(slice.load_small_uint(3));
1006 Ok(Self {
1007 ihr_disabled: flags & 0b100 != 0,
1008 bounce: flags & 0b010 != 0,
1009 bounced: flags & 0b001 != 0,
1010 src: ok!(load_opt_int_addr(slice)),
1011 dst: ok!(IntAddr::load_from(slice)),
1012 value: ok!(CurrencyCollection::load_from(slice)),
1013 extra_flags: ok!(MessageExtraFlags::load_from(slice)),
1014 fwd_fee: ok!(Tokens::load_from(slice)),
1015 created_lt: ok!(slice.load_u64()),
1016 created_at: ok!(slice.load_u32()),
1017 })
1018 }
1019}
1020
1021#[derive(Debug, Default, Clone, Eq, PartialEq)]
1023#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1024#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1025pub struct ExtInMsgInfo {
1026 #[cfg_attr(
1028 feature = "serde",
1029 serde(default, skip_serializing_if = "Option::is_none")
1030 )]
1031 pub src: Option<ExtAddr>,
1032 pub dst: IntAddr,
1034 pub import_fee: Tokens,
1038}
1039
1040impl ExtInMsgInfo {
1041 pub const fn bit_len(&self) -> u16 {
1043 2 + compute_ext_addr_bit_len(&self.src)
1044 + self.dst.bit_len()
1045 + self.import_fee.unwrap_bit_len()
1046 }
1047}
1048
1049impl Store for ExtInMsgInfo {
1050 fn store_into(
1051 &self,
1052 builder: &mut CellBuilder,
1053 context: &dyn CellContext,
1054 ) -> Result<(), Error> {
1055 if !self.import_fee.is_valid() {
1056 return Err(Error::InvalidData);
1057 }
1058 if !builder.has_capacity(self.bit_len(), 0) {
1059 return Err(Error::CellOverflow);
1060 }
1061 ok!(store_ext_addr(builder, context, &self.src));
1062 ok!(self.dst.store_into(builder, context));
1063 self.import_fee.store_into(builder, context)
1064 }
1065}
1066
1067impl<'a> Load<'a> for ExtInMsgInfo {
1068 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
1069 Ok(Self {
1070 src: ok!(load_ext_addr(slice)),
1071 dst: ok!(IntAddr::load_from(slice)),
1072 import_fee: ok!(Tokens::load_from(slice)),
1073 })
1074 }
1075}
1076
1077#[derive(Debug, Default, Clone, Eq, PartialEq)]
1079#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1080#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1081pub struct ExtOutMsgInfo {
1082 pub src: IntAddr,
1084 #[cfg_attr(
1086 feature = "serde",
1087 serde(default, skip_serializing_if = "Option::is_none")
1088 )]
1089 pub dst: Option<ExtAddr>,
1090 pub created_lt: u64,
1092 pub created_at: u32,
1094}
1095
1096impl ExtOutMsgInfo {
1097 pub const fn bit_len(&self) -> u16 {
1099 2 + self.src.bit_len() + compute_ext_addr_bit_len(&self.dst) + 64 + 32
1100 }
1101}
1102
1103impl Store for ExtOutMsgInfo {
1104 fn store_into(
1105 &self,
1106 builder: &mut CellBuilder,
1107 context: &dyn CellContext,
1108 ) -> Result<(), Error> {
1109 if !builder.has_capacity(self.bit_len(), 0) {
1110 return Err(Error::CellOverflow);
1111 }
1112 ok!(self.src.store_into(builder, context));
1113 ok!(store_ext_addr(builder, context, &self.dst));
1114 ok!(builder.store_u64(self.created_lt));
1115 builder.store_u32(self.created_at)
1116 }
1117}
1118
1119impl<'a> Load<'a> for ExtOutMsgInfo {
1120 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
1121 Ok(Self {
1122 src: ok!(IntAddr::load_from(slice)),
1123 dst: ok!(load_ext_addr(slice)),
1124 created_lt: ok!(slice.load_u64()),
1125 created_at: ok!(slice.load_u32()),
1126 })
1127 }
1128}
1129
1130#[derive(Debug, Default, Clone, Eq, PartialEq)]
1132#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1133#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
1134pub struct RelaxedExtOutMsgInfo {
1135 pub src: Option<IntAddr>,
1137 #[cfg_attr(
1139 feature = "serde",
1140 serde(default, skip_serializing_if = "Option::is_none")
1141 )]
1142 pub dst: Option<ExtAddr>,
1143 pub created_lt: u64,
1145 pub created_at: u32,
1147}
1148
1149impl RelaxedExtOutMsgInfo {
1150 pub const fn bit_len(&self) -> u16 {
1152 2 + compute_opt_int_addr_bit_len(&self.src) + compute_ext_addr_bit_len(&self.dst) + 64 + 32
1153 }
1154}
1155
1156impl Store for RelaxedExtOutMsgInfo {
1157 fn store_into(
1158 &self,
1159 builder: &mut CellBuilder,
1160 context: &dyn CellContext,
1161 ) -> Result<(), Error> {
1162 ok!(store_opt_int_addr(builder, context, &self.src));
1163 ok!(store_ext_addr(builder, context, &self.dst));
1164 ok!(builder.store_u64(self.created_lt));
1165 builder.store_u32(self.created_at)
1166 }
1167}
1168
1169impl<'a> Load<'a> for RelaxedExtOutMsgInfo {
1170 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
1171 Ok(Self {
1172 src: ok!(load_opt_int_addr(slice)),
1173 dst: ok!(load_ext_addr(slice)),
1174 created_lt: ok!(slice.load_u64()),
1175 created_at: ok!(slice.load_u32()),
1176 })
1177 }
1178}
1179
1180const fn compute_ext_addr_bit_len(addr: &Option<ExtAddr>) -> u16 {
1181 match addr {
1182 Some(addr) => 2 + addr.bit_len(),
1183 None => 2,
1184 }
1185}
1186
1187fn store_ext_addr(
1188 builder: &mut CellBuilder,
1189 context: &dyn CellContext,
1190 addr: &Option<ExtAddr>,
1191) -> Result<(), Error> {
1192 match addr {
1193 None => builder.store_zeros(2),
1194 Some(ExtAddr { data_bit_len, data }) => {
1195 if !builder.has_capacity(2 + Uint9::BITS + data_bit_len.into_inner(), 0) {
1196 return Err(Error::CellOverflow);
1197 }
1198 ok!(builder.store_bit_zero());
1199 ok!(builder.store_bit_one());
1200 ok!(data_bit_len.store_into(builder, context));
1201 builder.store_raw(data, data_bit_len.into_inner())
1202 }
1203 }
1204}
1205
1206fn load_ext_addr(slice: &mut CellSlice<'_>) -> Result<Option<ExtAddr>, Error> {
1207 if ok!(slice.load_bit()) {
1208 return Err(Error::InvalidTag);
1209 }
1210
1211 if !ok!(slice.load_bit()) {
1212 return Ok(None);
1213 }
1214
1215 let data_bit_len = ok!(Uint9::load_from(slice));
1216 if !slice.has_remaining(data_bit_len.into_inner(), 0) {
1217 return Err(Error::CellUnderflow);
1218 }
1219
1220 let mut data = vec![0; data_bit_len.into_inner().div_ceil(8) as usize];
1221 ok!(slice.load_raw(&mut data, data_bit_len.into_inner()));
1222 Ok(Some(ExtAddr { data_bit_len, data }))
1223}
1224
1225const fn compute_opt_int_addr_bit_len(addr: &Option<IntAddr>) -> u16 {
1226 match addr {
1227 Some(src) => src.bit_len(),
1228 None => 2,
1229 }
1230}
1231
1232fn store_opt_int_addr(
1233 builder: &mut CellBuilder,
1234 context: &dyn CellContext,
1235 addr: &Option<IntAddr>,
1236) -> Result<(), Error> {
1237 match addr {
1238 Some(addr) => addr.store_into(builder, context),
1239 None => builder.store_zeros(2),
1240 }
1241}
1242
1243fn load_opt_int_addr(slice: &mut CellSlice<'_>) -> Result<Option<IntAddr>, Error> {
1244 if ok!(slice.get_bit(0)) {
1245 IntAddr::load_from(slice).map(Some)
1246 } else if ok!(slice.load_small_uint(2)) == 0b00 {
1247 Ok(None)
1248 } else {
1249 Err(Error::InvalidTag)
1250 }
1251}
1252
1253bitflags! {
1254 #[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
1256 pub struct MessageExtraFlags: u8 {
1257 const NEW_BOUNCE_FORMAT = 0b01;
1259 const FULL_BODY_IN_BOUNCED = 0b10;
1261 }
1262}
1263
1264impl MessageExtraFlags {
1265 #[inline]
1267 pub const fn from_stored(tokens: Tokens) -> Option<Self> {
1268 let value = tokens.into_inner();
1269 if value <= u8::MAX as u128 {
1270 Self::from_bits(value as u8)
1271 } else {
1272 None
1273 }
1274 }
1275
1276 #[inline]
1278 pub const fn as_stored(&self) -> Tokens {
1279 Tokens::new(self.bits() as _)
1280 }
1281
1282 #[inline]
1284 pub const fn is_new_bounce_format(&self) -> bool {
1285 self.contains(Self::NEW_BOUNCE_FORMAT)
1286 }
1287
1288 #[inline]
1290 pub const fn is_full_body_in_bounced(&self) -> bool {
1291 self.contains(Self::FULL_BODY_IN_BOUNCED)
1292 }
1293
1294 pub const fn bit_len(&self) -> u16 {
1296 Tokens::LEN_BITS + 8 * (self.bits() != 0) as u16
1297 }
1298}
1299
1300impl Store for MessageExtraFlags {
1301 #[inline]
1302 fn store_into(
1303 &self,
1304 builder: &mut CellBuilder,
1305 context: &dyn CellContext,
1306 ) -> Result<(), Error> {
1307 self.as_stored().store_into(builder, context)
1308 }
1309}
1310
1311impl<'a> Load<'a> for MessageExtraFlags {
1312 #[inline]
1313 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
1314 Self::from_stored(Tokens::load_from(slice)?).ok_or(Error::InvalidData)
1315 }
1316}
1317
1318#[cfg(feature = "serde")]
1319impl serde::Serialize for MessageExtraFlags {
1320 #[inline]
1321 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
1322 SerdeMessageExtraFlags {
1323 new_bounce_format: self.contains(Self::NEW_BOUNCE_FORMAT),
1324 full_body_in_bounced: self.contains(Self::FULL_BODY_IN_BOUNCED),
1325 }
1326 .serialize(serializer)
1327 }
1328}
1329
1330#[cfg(feature = "serde")]
1331impl<'de> serde::Deserialize<'de> for MessageExtraFlags {
1332 #[inline]
1333 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
1334 let flags = SerdeMessageExtraFlags::deserialize(deserializer)?;
1335 let mut result = Self::empty();
1336 result.set(Self::NEW_BOUNCE_FORMAT, flags.new_bounce_format);
1337 result.set(Self::FULL_BODY_IN_BOUNCED, flags.full_body_in_bounced);
1338 Ok(result)
1339 }
1340}
1341
1342#[cfg(feature = "serde")]
1343#[derive(serde::Serialize, serde::Deserialize)]
1344struct SerdeMessageExtraFlags {
1345 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1346 new_bounce_format: bool,
1347 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
1348 full_body_in_bounced: bool,
1349}
1350
1351#[cfg(feature = "arbitrary")]
1352impl<'a> arbitrary::Arbitrary<'a> for MessageExtraFlags {
1353 #[inline]
1354 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
1355 u.arbitrary::<u8>().map(Self::from_bits_truncate)
1356 }
1357}
1358
1359#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
1361#[tlb(tag = "#fffffffe")]
1362pub struct NewBounceBody {
1363 pub original_body: Cell,
1367 pub original_info: Lazy<NewBounceOriginalInfo>,
1369 pub bounced_by_phase: u8,
1380 pub exit_code: i32,
1382 pub compute_phase: Option<NewBounceComputePhaseInfo>,
1384}
1385
1386impl NewBounceBody {
1387 pub const COMPUTE_PHASE_SKIPPED: u8 = 0;
1389 pub const COMPUTE_PHASE_FAILED: u8 = 1;
1391 pub const ACTION_PHASE_FAILED: u8 = 2;
1393
1394 pub const EXIT_CODE_NO_STATE: i32 = -1;
1396 pub const EXIT_CODE_BAD_STATE: i32 = -2;
1398 pub const EXIT_CODE_NO_GAS: i32 = -3;
1400 pub const EXIT_CODE_SUSPENDED: i32 = -4;
1402
1403 pub const fn bounce_reason(&self) -> Option<BounceReason> {
1405 Some(match self.bounced_by_phase {
1406 0 => BounceReason::ComputePhaseSkipped(match self.exit_code {
1407 Self::EXIT_CODE_NO_STATE => {
1408 crate::models::transaction::ComputePhaseSkipReason::NoState
1409 }
1410 Self::EXIT_CODE_BAD_STATE => {
1411 crate::models::transaction::ComputePhaseSkipReason::BadState
1412 }
1413 Self::EXIT_CODE_NO_GAS => crate::models::transaction::ComputePhaseSkipReason::NoGas,
1414 Self::EXIT_CODE_SUSPENDED => {
1415 crate::models::transaction::ComputePhaseSkipReason::Suspended
1416 }
1417 _ => return None,
1418 }),
1419 1 => BounceReason::ComputePhaseFailed {
1420 exit_code: self.exit_code,
1421 },
1422 2 => BounceReason::ActionPhaseFailed {
1423 result_code: self.exit_code,
1424 },
1425 _ => return None,
1426 })
1427 }
1428}
1429
1430#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1432pub enum BounceReason {
1433 ComputePhaseSkipped(crate::models::transaction::ComputePhaseSkipReason),
1435 ComputePhaseFailed {
1437 exit_code: i32,
1439 },
1440 ActionPhaseFailed {
1442 result_code: i32,
1444 },
1445}
1446
1447impl BounceReason {
1448 pub const fn flatten(&self) -> (u8, i32) {
1451 match self {
1452 Self::ComputePhaseSkipped(reason) => {
1453 let exit_code = match reason {
1454 crate::models::ComputePhaseSkipReason::NoState => {
1455 NewBounceBody::EXIT_CODE_NO_STATE
1456 }
1457 crate::models::ComputePhaseSkipReason::BadState => {
1458 NewBounceBody::EXIT_CODE_BAD_STATE
1459 }
1460 crate::models::ComputePhaseSkipReason::NoGas => NewBounceBody::EXIT_CODE_NO_GAS,
1461 crate::models::ComputePhaseSkipReason::Suspended => {
1462 NewBounceBody::EXIT_CODE_SUSPENDED
1463 }
1464 };
1465 (NewBounceBody::COMPUTE_PHASE_SKIPPED, exit_code)
1466 }
1467 Self::ComputePhaseFailed { exit_code } => {
1468 (NewBounceBody::COMPUTE_PHASE_FAILED, *exit_code)
1469 }
1470 Self::ActionPhaseFailed { result_code } => {
1471 (NewBounceBody::ACTION_PHASE_FAILED, *result_code)
1472 }
1473 }
1474 }
1475}
1476
1477#[derive(Default, Debug, Clone, Eq, PartialEq, Store, Load)]
1479pub struct NewBounceOriginalInfo {
1480 pub value: CurrencyCollection,
1482 pub created_lt: u64,
1484 pub created_at: u32,
1486}
1487
1488#[derive(Clone, Debug, Default, Eq, PartialEq, Store, Load)]
1490pub struct NewBounceComputePhaseInfo {
1491 pub gas_used: u32,
1493 pub vm_steps: u32,
1495}