tycho_types/models/message/
envelope.rs

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