use crate::cell::*;
use crate::error::Error;
use crate::num::*;
use crate::models::account::StorageUsedShort;
use crate::models::currency::CurrencyCollection;
#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StoragePhase {
pub storage_fees_collected: Tokens,
pub storage_fees_due: Option<Tokens>,
pub status_change: AccountStatusChange,
}
#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CreditPhase {
pub due_fees_collected: Option<Tokens>,
pub credit: CurrencyCollection,
}
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "ty"))]
pub enum ComputePhase {
Skipped(SkippedComputePhase),
Executed(ExecutedComputePhase),
}
impl Store for ComputePhase {
fn store_into(
&self,
builder: &mut CellBuilder,
context: &mut dyn CellContext,
) -> Result<(), Error> {
match self {
Self::Skipped(phase) => {
ok!(builder.store_bit_zero());
phase.store_into(builder, context)
}
Self::Executed(phase) => {
let cell = {
let mut builder = CellBuilder::new();
ok!(phase.gas_used.store_into(&mut builder, context));
ok!(phase.gas_limit.store_into(&mut builder, context));
ok!(phase.gas_credit.store_into(&mut builder, context));
ok!(builder.store_u8(phase.mode as u8));
ok!(builder.store_u32(phase.exit_code as u32));
ok!(phase.exit_arg.store_into(&mut builder, context));
ok!(builder.store_u32(phase.vm_steps));
ok!(builder.store_u256(&phase.vm_init_state_hash));
ok!(builder.store_u256(&phase.vm_final_state_hash));
ok!(builder.build_ext(context))
};
let flags = 0b1000u8
| ((phase.success as u8) << 2)
| ((phase.msg_state_used as u8) << 1)
| (phase.account_activated as u8);
ok!(builder.store_small_uint(flags, 4));
ok!(phase.gas_fees.store_into(builder, context));
builder.store_reference(cell)
}
}
}
}
impl<'a> Load<'a> for ComputePhase {
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
if !ok!(slice.load_bit()) {
return Ok(Self::Skipped(ok!(SkippedComputePhase::load_from(slice))));
}
let flags = ok!(slice.load_small_uint(3));
let gas_fees = ok!(Tokens::load_from(slice));
let slice = &mut ok!(slice.load_reference_as_slice());
Ok(Self::Executed(ExecutedComputePhase {
success: flags & 0b100 != 0,
msg_state_used: flags & 0b010 != 0,
account_activated: flags & 0b001 != 0,
gas_fees,
gas_used: ok!(VarUint56::load_from(slice)),
gas_limit: ok!(VarUint56::load_from(slice)),
gas_credit: ok!(Option::<VarUint24>::load_from(slice)),
mode: ok!(slice.load_u8()) as i8,
exit_code: ok!(slice.load_u32()) as i32,
exit_arg: ok!(Option::<i32>::load_from(slice)),
vm_steps: ok!(slice.load_u32()),
vm_init_state_hash: ok!(slice.load_u256()),
vm_final_state_hash: ok!(slice.load_u256()),
}))
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ExecutedComputePhase {
pub success: bool,
pub msg_state_used: bool,
pub account_activated: bool,
pub gas_fees: Tokens,
pub gas_used: VarUint56,
pub gas_limit: VarUint56,
pub gas_credit: Option<VarUint24>,
pub mode: i8,
pub exit_code: i32,
pub exit_arg: Option<i32>,
pub vm_steps: u32,
pub vm_init_state_hash: HashBytes,
pub vm_final_state_hash: HashBytes,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Store, Load)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SkippedComputePhase {
pub reason: ComputePhaseSkipReason,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ComputePhaseSkipReason {
NoState,
BadState,
NoGas,
Suspended,
}
impl Store for ComputePhaseSkipReason {
fn store_into(&self, builder: &mut CellBuilder, _: &mut dyn CellContext) -> Result<(), Error> {
let (tag, bits) = match self {
Self::NoState => (0b00, 2),
Self::BadState => (0b01, 2),
Self::NoGas => (0b10, 2),
Self::Suspended => (0b110, 3),
};
builder.store_small_uint(tag, bits)
}
}
impl<'a> Load<'a> for ComputePhaseSkipReason {
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
match slice.load_small_uint(2) {
Ok(0b00) => Ok(Self::NoState),
Ok(0b01) => Ok(Self::BadState),
Ok(0b10) => Ok(Self::NoGas),
Ok(_) => {
if ok!(slice.load_bit()) {
Err(Error::InvalidTag)
} else {
Ok(Self::Suspended)
}
}
Err(e) => Err(e),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ActionPhase {
pub success: bool,
pub valid: bool,
pub no_funds: bool,
pub status_change: AccountStatusChange,
pub total_fwd_fees: Option<Tokens>,
pub total_action_fees: Option<Tokens>,
pub result_code: i32,
pub result_arg: Option<i32>,
pub total_actions: u16,
pub special_actions: u16,
pub skipped_actions: u16,
pub messages_created: u16,
pub action_list_hash: HashBytes,
pub total_message_size: StorageUsedShort,
}
impl Store for ActionPhase {
fn store_into(
&self,
builder: &mut CellBuilder,
context: &mut dyn CellContext,
) -> Result<(), Error> {
let flags = ((self.success as u8) << 2) | ((self.valid as u8) << 1) | self.no_funds as u8;
let counts = ((self.total_actions as u64) << 48)
| ((self.special_actions as u64) << 32)
| ((self.skipped_actions as u64) << 16)
| self.messages_created as u64;
ok!(builder.store_small_uint(flags, 3));
ok!(self.status_change.store_into(builder, context));
ok!(self.total_fwd_fees.store_into(builder, context));
ok!(self.total_action_fees.store_into(builder, context));
ok!(builder.store_u32(self.result_code as u32));
ok!(self.result_arg.store_into(builder, context));
ok!(builder.store_u64(counts));
ok!(builder.store_u256(&self.action_list_hash));
self.total_message_size.store_into(builder, context)
}
}
impl<'a> Load<'a> for ActionPhase {
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
let flags = ok!(slice.load_small_uint(3));
let status_change = ok!(AccountStatusChange::load_from(slice));
let total_fwd_fees = ok!(Option::<Tokens>::load_from(slice));
let total_action_fees = ok!(Option::<Tokens>::load_from(slice));
let result_code = ok!(slice.load_u32()) as i32;
let result_arg = ok!(Option::<i32>::load_from(slice));
let counts = ok!(slice.load_u64());
Ok(Self {
success: flags & 0b100 != 0,
valid: flags & 0b010 != 0,
no_funds: flags & 0b001 != 0,
status_change,
total_fwd_fees,
total_action_fees,
result_code,
result_arg,
total_actions: (counts >> 48) as u16,
special_actions: (counts >> 32) as u16,
skipped_actions: (counts >> 16) as u16,
messages_created: counts as u16,
action_list_hash: ok!(slice.load_u256()),
total_message_size: ok!(StorageUsedShort::load_from(slice)),
})
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "ty"))]
pub enum BouncePhase {
NegativeFunds,
NoFunds(NoFundsBouncePhase),
Executed(ExecutedBouncePhase),
}
impl Store for BouncePhase {
fn store_into(
&self,
builder: &mut CellBuilder,
context: &mut dyn CellContext,
) -> Result<(), Error> {
match self {
Self::NegativeFunds => builder.store_small_uint(0b00, 2),
Self::NoFunds(phase) => {
ok!(builder.store_small_uint(0b01, 2));
phase.store_into(builder, context)
}
Self::Executed(phase) => {
ok!(builder.store_bit_one());
phase.store_into(builder, context)
}
}
}
}
impl<'a> Load<'a> for BouncePhase {
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
Ok(if ok!(slice.load_bit()) {
match ExecutedBouncePhase::load_from(slice) {
Ok(phase) => Self::Executed(phase),
Err(e) => return Err(e),
}
} else if ok!(slice.load_bit()) {
match NoFundsBouncePhase::load_from(slice) {
Ok(phase) => Self::NoFunds(phase),
Err(e) => return Err(e),
}
} else {
Self::NegativeFunds
})
}
}
#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct NoFundsBouncePhase {
pub msg_size: StorageUsedShort,
pub req_fwd_fees: Tokens,
}
#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ExecutedBouncePhase {
pub msg_size: StorageUsedShort,
pub msg_fees: Tokens,
pub fwd_fees: Tokens,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AccountStatusChange {
Unchanged = 0b0,
Frozen = 0b10,
Deleted = 0b11,
}
impl Store for AccountStatusChange {
fn store_into(&self, builder: &mut CellBuilder, _: &mut dyn CellContext) -> Result<(), Error> {
if *self == Self::Unchanged {
builder.store_bit_zero()
} else {
builder.store_small_uint(*self as u8, 2)
}
}
}
impl<'a> Load<'a> for AccountStatusChange {
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
Ok(if !ok!(slice.load_bit()) {
Self::Unchanged
} else if ok!(slice.load_bit()) {
Self::Deleted
} else {
Self::Frozen
})
}
}