1pub use self::phases::*;
4use crate::cell::*;
5use crate::dict::{self, Dict};
6use crate::error::*;
7use crate::models::account::AccountStatus;
8use crate::models::currency::CurrencyCollection;
9use crate::models::message::Message;
10use crate::num::*;
11
12mod phases;
13
14#[cfg(test)]
15mod tests;
16
17#[derive(Debug, Clone, Eq, PartialEq)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub struct Transaction {
21 pub account: HashBytes,
23 pub lt: u64,
25 pub prev_trans_hash: HashBytes,
27 pub prev_trans_lt: u64,
29 pub now: u32,
31 pub out_msg_count: Uint15,
33 pub orig_status: AccountStatus,
35 pub end_status: AccountStatus,
37 #[cfg_attr(feature = "serde", serde(with = "serde_in_msg"))]
39 pub in_msg: Option<Cell>,
40 #[cfg_attr(feature = "serde", serde(with = "serde_out_msgs"))]
42 pub out_msgs: Dict<Uint15, Cell>,
43 pub total_fees: CurrencyCollection,
45 pub state_update: Lazy<HashUpdate>,
47 pub info: Lazy<TxInfo>,
49}
50
51impl Transaction {
52 pub fn load_in_msg(&self) -> Result<Option<Message<'_>>, Error> {
54 match &self.in_msg {
55 Some(in_msg) => match in_msg.parse::<Message>() {
56 Ok(message) => Ok(Some(message)),
57 Err(e) => Err(e),
58 },
59 None => Ok(None),
60 }
61 }
62
63 pub fn load_info(&self) -> Result<TxInfo, Error> {
65 self.info.load()
66 }
67}
68
69impl Transaction {
70 pub fn iter_out_msgs(&'_ self) -> TxOutMsgIter<'_> {
76 TxOutMsgIter {
77 inner: self.out_msgs.raw_values(),
78 }
79 }
80}
81
82#[cfg(feature = "serde")]
83mod serde_in_msg {
84 use super::*;
85
86 pub fn serialize<S>(in_msg: &Option<Cell>, serializer: S) -> Result<S::Ok, S::Error>
87 where
88 S: serde::Serializer,
89 {
90 if serializer.is_human_readable() {
91 match in_msg {
92 Some(in_msg) => {
93 let message = ok!(in_msg.parse::<Message>().map_err(serde::ser::Error::custom));
94 serializer.serialize_some(&message)
95 }
96 None => serializer.serialize_none(),
97 }
98 } else {
99 crate::boc::Boc::serialize(in_msg, serializer)
100 }
101 }
102
103 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Cell>, D::Error>
104 where
105 D: serde::Deserializer<'de>,
106 {
107 use serde::de::{Deserialize, Error};
108
109 if deserializer.is_human_readable() {
110 match ok!(Option::<crate::models::OwnedMessage>::deserialize(
111 deserializer
112 )) {
113 Some(message) => CellBuilder::build_from(&message)
114 .map_err(Error::custom)
115 .map(Some),
116 None => Ok(None),
117 }
118 } else {
119 crate::boc::Boc::deserialize(deserializer)
120 }
121 }
122}
123
124#[cfg(feature = "serde")]
125mod serde_out_msgs {
126 use super::*;
127
128 pub fn serialize<S>(out_msgs: &Dict<Uint15, Cell>, serializer: S) -> Result<S::Ok, S::Error>
129 where
130 S: serde::Serializer,
131 {
132 use serde::ser::{Error, SerializeMap};
133
134 if serializer.is_human_readable() {
135 let mut map = ok!(serializer.serialize_map(None));
136 for entry in out_msgs.iter() {
137 match entry {
138 Ok((key, value)) => {
139 let message = ok!(value.parse::<Message>().map_err(Error::custom));
140 ok!(map.serialize_entry(&key, &message));
141 }
142 Err(e) => return Err(Error::custom(e)),
143 }
144 }
145 map.end()
146 } else {
147 crate::boc::BocRepr::serialize(out_msgs, serializer)
148 }
149 }
150
151 pub fn deserialize<'de, D>(deserializer: D) -> Result<Dict<Uint15, Cell>, D::Error>
152 where
153 D: serde::Deserializer<'de>,
154 {
155 use serde::de::{Deserialize, Error};
156
157 if deserializer.is_human_readable() {
158 let messages = ok!(
159 ahash::HashMap::<Uint15, crate::models::OwnedMessage>::deserialize(deserializer)
160 );
161
162 let cx = Cell::empty_context();
163 let mut dict = Dict::new();
164 for (key, value) in &messages {
165 let cell = ok!(CellBuilder::build_from(value).map_err(Error::custom));
166 ok!(dict.set_ext(*key, cell, cx).map_err(Error::custom));
167 }
168 Ok(dict)
169 } else {
170 crate::boc::BocRepr::deserialize(deserializer)
171 }
172 }
173}
174
175#[derive(Clone)]
182pub struct TxOutMsgIter<'a> {
183 inner: dict::RawValues<'a>,
184}
185
186impl<'a> Iterator for TxOutMsgIter<'a> {
187 type Item = Result<Message<'a>, Error>;
188
189 fn next(&mut self) -> Option<Self::Item> {
190 match self.inner.next()? {
191 Ok(mut value) => {
192 let e = match value.load_reference_as_slice() {
193 Ok(mut value) => match Message::<'a>::load_from(&mut value) {
194 Ok(message) => return Some(Ok(message)),
195 Err(e) => e,
196 },
197 Err(e) => e,
198 };
199
200 Some(Err(self.inner.finish(e)))
201 }
202 Err(e) => Some(Err(e)),
203 }
204 }
205}
206
207impl Transaction {
208 const TAG: u8 = 0b0111;
209}
210
211impl Store for Transaction {
212 fn store_into(
213 &self,
214 builder: &mut CellBuilder,
215 context: &dyn CellContext,
216 ) -> Result<(), Error> {
217 let messages = {
218 let mut builder = CellBuilder::new();
219 ok!(self.in_msg.store_into(&mut builder, context));
220 ok!(self.out_msgs.store_into(&mut builder, context));
221 ok!(builder.build_ext(context))
222 };
223
224 ok!(builder.store_small_uint(Self::TAG, 4));
225 ok!(builder.store_u256(&self.account));
226 ok!(builder.store_u64(self.lt));
227 ok!(builder.store_u256(&self.prev_trans_hash));
228 ok!(builder.store_u64(self.prev_trans_lt));
229 ok!(builder.store_u32(self.now));
230 ok!(self.out_msg_count.store_into(builder, context));
231 ok!(self.orig_status.store_into(builder, context));
232 ok!(self.end_status.store_into(builder, context));
233 ok!(builder.store_reference(messages));
234 ok!(self.total_fees.store_into(builder, context));
235 ok!(self.state_update.store_into(builder, context));
236 self.info.store_into(builder, context)
237 }
238}
239
240impl<'a> Load<'a> for Transaction {
241 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
242 match slice.load_small_uint(4) {
243 Ok(Self::TAG) => {}
244 Ok(_) => return Err(Error::InvalidTag),
245 Err(e) => return Err(e),
246 }
247
248 let (in_msg, out_msgs) = {
249 let slice = &mut ok!(slice.load_reference_as_slice());
250 let in_msg = ok!(Option::<Cell>::load_from(slice));
251 let out_msgs = ok!(Dict::load_from(slice));
252 (in_msg, out_msgs)
253 };
254
255 Ok(Self {
256 account: ok!(slice.load_u256()),
257 lt: ok!(slice.load_u64()),
258 prev_trans_hash: ok!(slice.load_u256()),
259 prev_trans_lt: ok!(slice.load_u64()),
260 now: ok!(slice.load_u32()),
261 out_msg_count: ok!(Uint15::load_from(slice)),
262 orig_status: ok!(AccountStatus::load_from(slice)),
263 end_status: ok!(AccountStatus::load_from(slice)),
264 in_msg,
265 out_msgs,
266 total_fees: ok!(CurrencyCollection::load_from(slice)),
267 state_update: ok!(Lazy::<HashUpdate>::load_from(slice)),
268 info: ok!(Lazy::<TxInfo>::load_from(slice)),
269 })
270 }
271}
272
273#[derive(Debug, Clone, Eq, PartialEq)]
275#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
276#[cfg_attr(feature = "serde", serde(tag = "ty"))]
277pub enum TxInfo {
278 Ordinary(OrdinaryTxInfo),
280 TickTock(TickTockTxInfo),
282}
283
284impl Store for TxInfo {
285 fn store_into(
286 &self,
287 builder: &mut CellBuilder,
288 context: &dyn CellContext,
289 ) -> Result<(), Error> {
290 match self {
291 Self::Ordinary(info) => {
292 ok!(builder.store_small_uint(0b0000, 4));
293 info.store_into(builder, context)
294 }
295 Self::TickTock(info) => {
296 ok!(builder.store_small_uint(0b001, 3));
297 info.store_into(builder, context)
298 }
299 }
300 }
301}
302
303impl<'a> Load<'a> for TxInfo {
304 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
305 let tag_part = ok!(slice.load_small_uint(3));
306 Ok(if tag_part == 0b001 {
307 match TickTockTxInfo::load_from(slice) {
308 Ok(info) => Self::TickTock(info),
309 Err(e) => return Err(e),
310 }
311 } else if tag_part == 0b000 && !ok!(slice.load_bit()) {
312 match OrdinaryTxInfo::load_from(slice) {
313 Ok(info) => Self::Ordinary(info),
314 Err(e) => return Err(e),
315 }
316 } else {
317 return Err(Error::InvalidTag);
318 })
319 }
320}
321
322impl From<OrdinaryTxInfo> for TxInfo {
323 #[inline]
324 fn from(value: OrdinaryTxInfo) -> Self {
325 Self::Ordinary(value)
326 }
327}
328
329impl From<TickTockTxInfo> for TxInfo {
330 #[inline]
331 fn from(value: TickTockTxInfo) -> Self {
332 Self::TickTock(value)
333 }
334}
335
336#[derive(Debug, Clone, Eq, PartialEq)]
338#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
339pub struct OrdinaryTxInfo {
340 pub credit_first: bool,
343 pub storage_phase: Option<StoragePhase>,
347 pub credit_phase: Option<CreditPhase>,
351 pub compute_phase: ComputePhase,
353 pub action_phase: Option<ActionPhase>,
357 pub aborted: bool,
359 pub bounce_phase: Option<BouncePhase>,
364 pub destroyed: bool,
366}
367
368impl Store for OrdinaryTxInfo {
369 fn store_into(
370 &self,
371 builder: &mut CellBuilder,
372 context: &dyn CellContext,
373 ) -> Result<(), Error> {
374 let action_phase = match &self.action_phase {
375 Some(action_phase) => {
376 let mut builder = CellBuilder::new();
377 ok!(action_phase.store_into(&mut builder, context));
378 Some(ok!(builder.build_ext(context)))
379 }
380 None => None,
381 };
382
383 ok!(builder.store_bit(self.credit_first));
384 ok!(self.storage_phase.store_into(builder, context));
385 ok!(self.credit_phase.store_into(builder, context));
386 ok!(self.compute_phase.store_into(builder, context));
387 ok!(action_phase.store_into(builder, context));
388 ok!(builder.store_bit(self.aborted));
389 ok!(self.bounce_phase.store_into(builder, context));
390 builder.store_bit(self.destroyed)
391 }
392}
393
394impl<'a> Load<'a> for OrdinaryTxInfo {
395 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
396 Ok(Self {
397 credit_first: ok!(slice.load_bit()),
398 storage_phase: ok!(Option::<StoragePhase>::load_from(slice)),
399 credit_phase: ok!(Option::<CreditPhase>::load_from(slice)),
400 compute_phase: ok!(ComputePhase::load_from(slice)),
401 action_phase: match ok!(Option::<Cell>::load_from(slice)) {
402 Some(cell) => Some(ok!(cell.as_ref().parse::<ActionPhase>())),
403 None => None,
404 },
405 aborted: ok!(slice.load_bit()),
406 bounce_phase: ok!(Option::<BouncePhase>::load_from(slice)),
407 destroyed: ok!(slice.load_bit()),
408 })
409 }
410}
411
412#[derive(Debug, Clone, Eq, PartialEq)]
414#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
415pub struct TickTockTxInfo {
416 pub kind: TickTock,
418 pub storage_phase: StoragePhase,
420 pub compute_phase: ComputePhase,
422 pub action_phase: Option<ActionPhase>,
426 pub aborted: bool,
428 pub destroyed: bool,
430}
431
432impl Store for TickTockTxInfo {
433 fn store_into(
434 &self,
435 builder: &mut CellBuilder,
436 context: &dyn CellContext,
437 ) -> Result<(), Error> {
438 let action_phase = match &self.action_phase {
439 Some(action_phase) => {
440 let mut builder = CellBuilder::new();
441 ok!(action_phase.store_into(&mut builder, context));
442 Some(ok!(builder.build_ext(context)))
443 }
444 None => None,
445 };
446
447 let flags = ((self.aborted as u8) << 1) | (self.destroyed as u8);
448
449 ok!(self.kind.store_into(builder, context));
450 ok!(self.storage_phase.store_into(builder, context));
451 ok!(self.compute_phase.store_into(builder, context));
452 ok!(action_phase.store_into(builder, context));
453 builder.store_small_uint(flags, 2)
454 }
455}
456
457impl<'a> Load<'a> for TickTockTxInfo {
458 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
459 let kind = ok!(TickTock::load_from(slice));
460 let storage_phase = ok!(StoragePhase::load_from(slice));
461 let compute_phase = ok!(ComputePhase::load_from(slice));
462 let action_phase = match ok!(Option::<Cell>::load_from(slice)) {
463 Some(cell) => Some(ok!(cell.as_ref().parse::<ActionPhase>())),
464 None => None,
465 };
466 let flags = ok!(slice.load_small_uint(2));
467
468 Ok(Self {
469 kind,
470 storage_phase,
471 compute_phase,
472 action_phase,
473 aborted: flags & 0b10 != 0,
474 destroyed: flags & 0b01 != 0,
475 })
476 }
477}
478
479#[derive(Debug, Copy, Clone, Eq, PartialEq)]
481#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
482pub enum TickTock {
483 Tick = 0,
485 Tock = 1,
487}
488
489impl Store for TickTock {
490 #[inline]
491 fn store_into(&self, builder: &mut CellBuilder, _: &dyn CellContext) -> Result<(), Error> {
492 builder.store_bit(*self == Self::Tock)
493 }
494}
495
496impl<'a> Load<'a> for TickTock {
497 #[inline]
498 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
499 match slice.load_bit() {
500 Ok(false) => Ok(Self::Tick),
501 Ok(true) => Ok(Self::Tock),
502 Err(e) => Err(e),
503 }
504 }
505}
506
507#[derive(Debug, Clone, Copy, Eq, PartialEq, Store, Load)]
509#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
510#[tlb(tag = "#72")]
511pub struct HashUpdate {
512 pub old: HashBytes,
514 pub new: HashBytes,
516}