everscale_types/models/message/
envelope.rs

1use crate::cell::*;
2use crate::error::Error;
3use crate::models::{Lazy, Message, MsgInfo, OwnedMessage};
4use crate::num::Tokens;
5use crate::util::unlikely;
6
7use super::IntMsgInfo;
8
9/// Next-hop address for a message.
10#[derive(Clone, Debug, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize))]
12#[cfg_attr(feature = "serde", serde(tag = "ty"))]
13pub enum IntermediateAddr {
14    /// Destination prefix length whithin the same workchain.
15    Regular(IntermediateAddrRegular),
16    /// Address prefix with a basic workchain id.
17    Simple(IntermediateAddrSimple),
18    /// Address prefix with an extended workchain id.
19    Ext(IntermediateAddrExt),
20}
21
22impl IntermediateAddr {
23    /// Full destination address within the same workchain.
24    pub const FULL_DEST_SAME_WORKCHAIN: Self = Self::Regular(IntermediateAddrRegular {
25        use_dest_bits: IntermediateAddrRegular::FULL_BITS,
26    });
27
28    /// Full source address within the same workchain.
29    pub const FULL_SRC_SAME_WORKCHAIN: Self =
30        Self::Regular(IntermediateAddrRegular { use_dest_bits: 0 });
31
32    /// Full destination address within masterchain.
33    pub const FULL_MASTERCHAIN: Self = Self::Simple(IntermediateAddrSimple {
34        workchain: -1,
35        address_prefix: 0b1 << 63,
36    });
37
38    /// Returns target workchain id if specified.
39    /// Returns `None` if the same workchain is used.
40    pub fn workchain(&self) -> Option<i32> {
41        match self {
42            IntermediateAddr::Regular(_) => None,
43            IntermediateAddr::Simple(simple) => Some(simple.workchain as i32),
44            IntermediateAddr::Ext(ext) => Some(ext.workchain),
45        }
46    }
47
48    /// Returns the address prefix if specified.
49    /// Returns `None` if bits length is used.
50    pub fn address_prefix(&self) -> Option<u64> {
51        match self {
52            IntermediateAddr::Regular(_) => None,
53            IntermediateAddr::Simple(simple) => Some(simple.address_prefix),
54            IntermediateAddr::Ext(ext) => Some(ext.address_prefix),
55        }
56    }
57}
58
59impl From<IntermediateAddrRegular> for IntermediateAddr {
60    #[inline]
61    fn from(addr: IntermediateAddrRegular) -> Self {
62        IntermediateAddr::Regular(addr)
63    }
64}
65
66impl From<IntermediateAddrSimple> for IntermediateAddr {
67    #[inline]
68    fn from(addr: IntermediateAddrSimple) -> Self {
69        IntermediateAddr::Simple(addr)
70    }
71}
72
73impl From<IntermediateAddrExt> for IntermediateAddr {
74    #[inline]
75    fn from(addr: IntermediateAddrExt) -> Self {
76        IntermediateAddr::Ext(addr)
77    }
78}
79
80impl Store for IntermediateAddr {
81    fn store_into(&self, builder: &mut CellBuilder, cx: &mut dyn CellContext) -> Result<(), Error> {
82        match self {
83            IntermediateAddr::Regular(addr) => {
84                ok!(builder.store_bit_zero()); // tag = $0
85                addr.store_into(builder, cx)
86            }
87            IntermediateAddr::Simple(addr) => {
88                ok!(builder.store_small_uint(0b10, 2)); // tag = $10
89                addr.store_into(builder, cx)
90            }
91            IntermediateAddr::Ext(addr) => {
92                ok!(builder.store_small_uint(0b11, 2)); // tag = $11
93                addr.store_into(builder, cx)
94            }
95        }
96    }
97}
98
99impl<'a> Load<'a> for IntermediateAddr {
100    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
101        if unlikely(slice.load_bit()?) {
102            if unlikely(slice.load_bit()?) {
103                // tag = $11
104                IntermediateAddrExt::load_from(slice).map(IntermediateAddr::Ext)
105            } else {
106                // tag = $10
107                IntermediateAddrSimple::load_from(slice).map(IntermediateAddr::Simple)
108            }
109        } else {
110            // tag = $0
111            IntermediateAddrRegular::load_from(slice).map(IntermediateAddr::Regular)
112        }
113    }
114}
115
116/// Destination prefix length whithin the same workchain.
117#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Store, Load)]
118#[cfg_attr(feature = "serde", derive(serde::Serialize))]
119#[tlb(validate_with = "Self::is_valid")]
120pub struct IntermediateAddrRegular {
121    /// Destination address prefix length in bits.
122    use_dest_bits: u8,
123}
124
125impl IntermediateAddrRegular {
126    /// Full address prefix length in bits.
127    pub const FULL_BITS: u8 = 96;
128
129    /// Returns whether the address prefix length is valid.
130    pub const fn is_valid(&self) -> bool {
131        self.use_dest_bits <= Self::FULL_BITS
132    }
133
134    /// Create for the destination address.
135    pub fn with_dest_bits(use_dest_bits: u8) -> Option<Self> {
136        (use_dest_bits <= Self::FULL_BITS).then_some(IntermediateAddrRegular { use_dest_bits })
137    }
138
139    /// Create for the source address.
140    pub fn with_src_bits(use_src_bits: u8) -> Option<Self> {
141        (use_src_bits <= Self::FULL_BITS).then(|| IntermediateAddrRegular {
142            use_dest_bits: Self::FULL_BITS - use_src_bits,
143        })
144    }
145
146    /// Returns the destination address prefix length in bits.
147    pub fn use_dest_bits(&self) -> u8 {
148        self.use_dest_bits
149    }
150
151    /// Returns the source address prefix length in bits.
152    pub fn use_src_bits(&self) -> u8 {
153        Self::FULL_BITS - self.use_dest_bits
154    }
155}
156
157/// Address prefix with a basic workchain id.
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Load, Store)]
159#[cfg_attr(feature = "serde", derive(serde::Serialize))]
160pub struct IntermediateAddrSimple {
161    /// Basic workchain id.
162    ///
163    /// See [`WorkchainFormatBasic`].
164    ///
165    /// [`WorkchainFormatBasic`]: crate::models::WorkchainFormatBasic
166    pub workchain: i8,
167
168    /// High 64 bits of the address.
169    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_account_prefix"))]
170    pub address_prefix: u64,
171}
172
173/// Address prefix with an extended workchain id.
174#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Store, Load)]
175#[cfg_attr(feature = "serde", derive(serde::Serialize))]
176pub struct IntermediateAddrExt {
177    /// Workchain ID
178    pub workchain: i32,
179
180    /// High 64 bits of the address.
181    #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_account_prefix"))]
182    pub address_prefix: u64,
183}
184
185/// Message with routing information.
186#[derive(Clone, Debug, Eq, PartialEq, Store, Load)]
187#[cfg_attr(feature = "serde", derive(serde::Serialize))]
188#[tlb(tag = "#4")]
189pub struct MsgEnvelope {
190    /// Current address.
191    pub cur_addr: IntermediateAddr,
192    /// Next-hop address.
193    pub next_addr: IntermediateAddr,
194    /// Remaining transit fee.
195    pub fwd_fee_remaining: Tokens,
196    /// The message itself.
197    #[cfg_attr(feature = "serde", serde(serialize_with = "Lazy::serialize_repr_hash"))]
198    pub message: Lazy<OwnedMessage>,
199}
200
201impl MsgEnvelope {
202    /// Load only message info.
203    pub fn load_message_info(&self) -> Result<IntMsgInfo, Error> {
204        if let MsgInfo::Int(info) = ok!(<_>::load_from(&mut ok!(self.message.cell.as_slice()))) {
205            Ok(info)
206        } else {
207            Err(Error::InvalidData)
208        }
209    }
210
211    /// Load a non-owned message.
212    pub fn load_message(&self) -> Result<Message<'_>, Error> {
213        self.message.cast_ref::<Message<'_>>().load()
214    }
215
216    /// Load an owned message.
217    pub fn load_message_owned(&self) -> Result<OwnedMessage, Error> {
218        self.message.load()
219    }
220
221    /// Returns a hash of the message.
222    pub fn message_hash(&self) -> &HashBytes {
223        self.message.cell.repr_hash()
224    }
225
226    /// Tries to substract transfer fee from envelope.
227    pub fn collect_fee(&mut self, fee: Tokens) -> bool {
228        match self.fwd_fee_remaining.checked_sub(fee) {
229            Some(remaining) => {
230                self.fwd_fee_remaining = remaining;
231                true
232            }
233            None => false,
234        }
235    }
236}
237
238#[cfg(feature = "serde")]
239fn serialize_account_prefix<S>(prefix: &u64, serializer: S) -> Result<S::Ok, S::Error>
240where
241    S: serde::Serializer,
242{
243    serializer.serialize_str(&format!("{:08x}", prefix))
244}