use crate::cell::*;
use crate::dict::{self, Dict};
use crate::error::*;
use crate::num::*;
use crate::models::account::AccountStatus;
use crate::models::currency::CurrencyCollection;
use crate::models::message::Message;
use crate::models::Lazy;
pub use self::phases::*;
mod phases;
#[cfg(test)]
mod tests;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Transaction {
pub account: HashBytes,
pub lt: u64,
pub prev_trans_hash: HashBytes,
pub prev_trans_lt: u64,
pub now: u32,
pub out_msg_count: Uint15,
pub orig_status: AccountStatus,
pub end_status: AccountStatus,
pub in_msg: Option<Cell>,
pub out_msgs: Dict<Uint15, Cell>,
pub total_fees: CurrencyCollection,
pub state_update: Lazy<HashUpdate>,
pub info: Lazy<TxInfo>,
}
impl Transaction {
pub fn load_in_msg(&self) -> Result<Option<Message<'_>>, Error> {
match &self.in_msg {
Some(in_msg) => match in_msg.parse::<Message>() {
Ok(message) => Ok(Some(message)),
Err(e) => Err(e),
},
None => Ok(None),
}
}
pub fn load_info(&self) -> Result<TxInfo, Error> {
self.info.load()
}
}
impl Transaction {
pub fn iter_out_msgs(&'_ self) -> TxOutMsgIter<'_> {
TxOutMsgIter {
inner: self.out_msgs.raw_values(),
}
}
}
#[derive(Clone)]
pub struct TxOutMsgIter<'a> {
inner: dict::RawValues<'a>,
}
impl<'a> Iterator for TxOutMsgIter<'a> {
type Item = Result<Message<'a>, Error>;
fn next(&mut self) -> Option<Self::Item> {
match self.inner.next()? {
Ok(mut value) => {
let e = match value.load_reference_as_slice() {
Ok(mut value) => match Message::<'a>::load_from(&mut value) {
Ok(message) => return Some(Ok(message)),
Err(e) => e,
},
Err(e) => e,
};
Some(Err(self.inner.finish(e)))
}
Err(e) => Some(Err(e)),
}
}
}
impl Transaction {
const TAG: u8 = 0b0111;
}
impl Store for Transaction {
fn store_into(
&self,
builder: &mut CellBuilder,
finalizer: &mut dyn Finalizer,
) -> Result<(), Error> {
let messages = {
let mut builder = CellBuilder::new();
ok!(self.in_msg.store_into(&mut builder, finalizer));
ok!(self.out_msgs.store_into(&mut builder, finalizer));
ok!(builder.build_ext(finalizer))
};
ok!(builder.store_small_uint(Self::TAG, 4));
ok!(builder.store_u256(&self.account));
ok!(builder.store_u64(self.lt));
ok!(builder.store_u256(&self.prev_trans_hash));
ok!(builder.store_u64(self.prev_trans_lt));
ok!(builder.store_u32(self.now));
ok!(self.out_msg_count.store_into(builder, finalizer));
ok!(self.orig_status.store_into(builder, finalizer));
ok!(self.end_status.store_into(builder, finalizer));
ok!(builder.store_reference(messages));
ok!(self.total_fees.store_into(builder, finalizer));
ok!(self.state_update.store_into(builder, finalizer));
self.info.store_into(builder, finalizer)
}
}
impl<'a> Load<'a> for Transaction {
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
match slice.load_small_uint(4) {
Ok(Self::TAG) => {}
Ok(_) => return Err(Error::InvalidTag),
Err(e) => return Err(e),
}
let (in_msg, out_msgs) = {
let slice = &mut ok!(slice.load_reference_as_slice());
let in_msg = ok!(Option::<Cell>::load_from(slice));
let out_msgs = ok!(Dict::load_from(slice));
(in_msg, out_msgs)
};
Ok(Self {
account: ok!(slice.load_u256()),
lt: ok!(slice.load_u64()),
prev_trans_hash: ok!(slice.load_u256()),
prev_trans_lt: ok!(slice.load_u64()),
now: ok!(slice.load_u32()),
out_msg_count: ok!(Uint15::load_from(slice)),
orig_status: ok!(AccountStatus::load_from(slice)),
end_status: ok!(AccountStatus::load_from(slice)),
in_msg,
out_msgs,
total_fees: ok!(CurrencyCollection::load_from(slice)),
state_update: ok!(Lazy::<HashUpdate>::load_from(slice)),
info: ok!(Lazy::<TxInfo>::load_from(slice)),
})
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum TxInfo {
Ordinary(OrdinaryTxInfo),
TickTock(TickTockTxInfo),
}
impl Store for TxInfo {
fn store_into(
&self,
builder: &mut CellBuilder,
finalizer: &mut dyn Finalizer,
) -> Result<(), Error> {
match self {
Self::Ordinary(info) => {
ok!(builder.store_small_uint(0b0000, 4));
info.store_into(builder, finalizer)
}
Self::TickTock(info) => {
ok!(builder.store_small_uint(0b001, 3));
info.store_into(builder, finalizer)
}
}
}
}
impl<'a> Load<'a> for TxInfo {
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
let tag_part = ok!(slice.load_small_uint(3));
Ok(if tag_part == 0b001 {
match TickTockTxInfo::load_from(slice) {
Ok(info) => Self::TickTock(info),
Err(e) => return Err(e),
}
} else if tag_part == 0b000 && !ok!(slice.load_bit()) {
match OrdinaryTxInfo::load_from(slice) {
Ok(info) => Self::Ordinary(info),
Err(e) => return Err(e),
}
} else {
return Err(Error::InvalidTag);
})
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct OrdinaryTxInfo {
pub credit_first: bool,
pub storage_phase: Option<StoragePhase>,
pub credit_phase: Option<CreditPhase>,
pub compute_phase: ComputePhase,
pub action_phase: Option<ActionPhase>,
pub aborted: bool,
pub bounce_phase: Option<BouncePhase>,
pub destroyed: bool,
}
impl Store for OrdinaryTxInfo {
fn store_into(
&self,
builder: &mut CellBuilder,
finalizer: &mut dyn Finalizer,
) -> Result<(), Error> {
let action_phase = match &self.action_phase {
Some(action_phase) => {
let mut builder = CellBuilder::new();
ok!(action_phase.store_into(&mut builder, finalizer));
Some(ok!(builder.build_ext(finalizer)))
}
None => None,
};
ok!(builder.store_bit(self.credit_first));
ok!(self.storage_phase.store_into(builder, finalizer));
ok!(self.credit_phase.store_into(builder, finalizer));
ok!(self.compute_phase.store_into(builder, finalizer));
ok!(action_phase.store_into(builder, finalizer));
ok!(builder.store_bit(self.aborted));
ok!(self.bounce_phase.store_into(builder, finalizer));
builder.store_bit(self.destroyed)
}
}
impl<'a> Load<'a> for OrdinaryTxInfo {
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
Ok(Self {
credit_first: ok!(slice.load_bit()),
storage_phase: ok!(Option::<StoragePhase>::load_from(slice)),
credit_phase: ok!(Option::<CreditPhase>::load_from(slice)),
compute_phase: ok!(ComputePhase::load_from(slice)),
action_phase: match ok!(Option::<Cell>::load_from(slice)) {
Some(cell) => Some(ok!(cell.as_ref().parse::<ActionPhase>())),
None => None,
},
aborted: ok!(slice.load_bit()),
bounce_phase: ok!(Option::<BouncePhase>::load_from(slice)),
destroyed: ok!(slice.load_bit()),
})
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TickTockTxInfo {
pub kind: TickTock,
pub storage_phase: StoragePhase,
pub compute_phase: ComputePhase,
pub action_phase: Option<ActionPhase>,
pub aborted: bool,
pub destroyed: bool,
}
impl Store for TickTockTxInfo {
fn store_into(
&self,
builder: &mut CellBuilder,
finalizer: &mut dyn Finalizer,
) -> Result<(), Error> {
let action_phase = match &self.action_phase {
Some(action_phase) => {
let mut builder = CellBuilder::new();
ok!(action_phase.store_into(&mut builder, finalizer));
Some(ok!(builder.build_ext(finalizer)))
}
None => None,
};
let flags = ((self.aborted as u8) << 1) | (self.destroyed as u8);
ok!(self.kind.store_into(builder, finalizer));
ok!(self.storage_phase.store_into(builder, finalizer));
ok!(self.compute_phase.store_into(builder, finalizer));
ok!(action_phase.store_into(builder, finalizer));
builder.store_small_uint(flags, 2)
}
}
impl<'a> Load<'a> for TickTockTxInfo {
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
let kind = ok!(TickTock::load_from(slice));
let storage_phase = ok!(StoragePhase::load_from(slice));
let compute_phase = ok!(ComputePhase::load_from(slice));
let action_phase = match ok!(Option::<Cell>::load_from(slice)) {
Some(cell) => Some(ok!(cell.as_ref().parse::<ActionPhase>())),
None => None,
};
let flags = ok!(slice.load_small_uint(2));
Ok(Self {
kind,
storage_phase,
compute_phase,
action_phase,
aborted: flags & 0b10 != 0,
destroyed: flags & 0b01 != 0,
})
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum TickTock {
Tick = 0,
Tock = 1,
}
impl Store for TickTock {
#[inline]
fn store_into(&self, builder: &mut CellBuilder, _: &mut dyn Finalizer) -> Result<(), Error> {
builder.store_bit(*self == Self::Tock)
}
}
impl<'a> Load<'a> for TickTock {
#[inline]
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
match slice.load_bit() {
Ok(false) => Ok(Self::Tick),
Ok(true) => Ok(Self::Tock),
Err(e) => Err(e),
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Store, Load)]
#[tlb(tag = "#72")]
pub struct HashUpdate {
pub old: HashBytes,
pub new: HashBytes,
}