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