use crate::cell::*;
use crate::dict::*;
use crate::error::*;
use crate::num::*;
use crate::models::currency::CurrencyCollection;
use crate::models::message::IntAddr;
use crate::models::Lazy;
#[derive(Debug, Default, Clone, Eq, PartialEq, Store, Load)]
pub struct StorageUsed {
pub cells: VarUint56,
pub bits: VarUint56,
pub public_cells: VarUint56,
}
impl StorageUsed {
pub const ZERO: Self = Self {
cells: VarUint56::ZERO,
bits: VarUint56::ZERO,
public_cells: VarUint56::ZERO,
};
}
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Store, Load)]
pub struct StorageUsedShort {
pub cells: VarUint56,
pub bits: VarUint56,
}
impl StorageUsedShort {
pub const ZERO: Self = Self {
cells: VarUint56::ZERO,
bits: VarUint56::ZERO,
};
}
#[derive(Debug, Default, Clone, Eq, PartialEq, Store, Load)]
pub struct StorageInfo {
pub used: StorageUsed,
pub last_paid: u32,
pub due_payment: Option<Tokens>,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AccountStatus {
Uninit = 0b00,
Frozen = 0b01,
Active = 0b10,
NotExists = 0b11,
}
impl AccountStatus {
pub const BITS: u16 = 2;
}
impl Store for AccountStatus {
#[inline]
fn store_into(&self, builder: &mut CellBuilder, _: &mut dyn Finalizer) -> Result<(), Error> {
builder.store_small_uint(*self as u8, 2)
}
}
impl<'a> Load<'a> for AccountStatus {
#[inline]
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
match slice.load_small_uint(2) {
Ok(ty) => Ok(match ty {
0b00 => Self::Uninit,
0b01 => Self::Frozen,
0b10 => Self::Active,
0b11 => Self::NotExists,
_ => {
debug_assert!(false, "unexpected small uint");
unsafe { std::hint::unreachable_unchecked() }
}
}),
Err(e) => Err(e),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
pub struct ShardAccount {
pub account: Lazy<OptionalAccount>,
pub last_trans_hash: HashBytes,
pub last_trans_lt: u64,
}
impl ShardAccount {
pub fn load_account(&self) -> Result<Option<Account>, Error> {
let OptionalAccount(account) = ok!(self.account.load());
Ok(account)
}
}
#[derive(Default, Debug, Clone, Eq, PartialEq)]
pub struct OptionalAccount(pub Option<Account>);
impl OptionalAccount {
pub const EMPTY: Self = Self(None);
}
impl Store for OptionalAccount {
fn store_into(
&self,
builder: &mut CellBuilder,
finalizer: &mut dyn Finalizer,
) -> Result<(), Error> {
match &self.0 {
None => builder.store_bit_zero(),
Some(account) => {
let with_init_code_hash = account.init_code_hash.is_some();
ok!(if with_init_code_hash {
builder.store_small_uint(0b0001, 4)
} else {
builder.store_bit_one()
});
ok!(account.address.store_into(builder, finalizer));
ok!(account.storage_stat.store_into(builder, finalizer));
ok!(builder.store_u64(account.last_trans_lt));
ok!(account.balance.store_into(builder, finalizer));
ok!(account.state.store_into(builder, finalizer));
if let Some(init_code_hash) = &account.init_code_hash {
ok!(builder.store_bit_one());
builder.store_u256(init_code_hash)
} else {
Ok(())
}
}
}
}
}
impl<'a> Load<'a> for OptionalAccount {
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
let with_init_code_hash = if ok!(slice.load_bit()) {
false } else if slice.is_data_empty() {
return Ok(Self::EMPTY);
} else {
let tag = ok!(slice.load_small_uint(3));
match tag {
0 => false, 1 => true, _ => return Err(Error::InvalidData),
}
};
Ok(Self(Some(Account {
address: ok!(IntAddr::load_from(slice)),
storage_stat: ok!(StorageInfo::load_from(slice)),
last_trans_lt: ok!(slice.load_u64()),
balance: ok!(CurrencyCollection::load_from(slice)),
state: ok!(AccountState::load_from(slice)),
init_code_hash: if with_init_code_hash {
ok!(Option::<HashBytes>::load_from(slice))
} else {
None
},
})))
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Account {
pub address: IntAddr,
pub storage_stat: StorageInfo,
pub last_trans_lt: u64,
pub balance: CurrencyCollection,
pub state: AccountState,
pub init_code_hash: Option<HashBytes>,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum AccountState {
Uninit,
Active(StateInit),
Frozen(HashBytes),
}
impl Store for AccountState {
fn store_into(
&self,
builder: &mut CellBuilder,
finalizer: &mut dyn Finalizer,
) -> Result<(), Error> {
match self {
Self::Uninit => builder.store_small_uint(0b00, 2),
Self::Active(state) => {
ok!(builder.store_bit_one());
state.store_into(builder, finalizer)
}
Self::Frozen(hash) => {
ok!(builder.store_small_uint(0b01, 2));
builder.store_u256(hash)
}
}
}
}
impl<'a> Load<'a> for AccountState {
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
Ok(if ok!(slice.load_bit()) {
match StateInit::load_from(slice) {
Ok(state) => Self::Active(state),
Err(e) => return Err(e),
}
} else if ok!(slice.load_bit()) {
match slice.load_u256() {
Ok(state) => Self::Frozen(state),
Err(e) => return Err(e),
}
} else {
Self::Uninit
})
}
}
#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
pub struct StateInit {
pub split_depth: Option<SplitDepth>,
pub special: Option<SpecialFlags>,
pub code: Option<Cell>,
pub data: Option<Cell>,
pub libraries: Dict<HashBytes, SimpleLib>,
}
impl Default for StateInit {
fn default() -> Self {
Self {
split_depth: None,
special: None,
code: None,
data: None,
libraries: Dict::new(),
}
}
}
impl StateInit {
pub const fn bit_len(&self) -> u16 {
(1 + self.split_depth.is_some() as u16 * SplitDepth::BITS)
+ (1 + self.special.is_some() as u16 * SpecialFlags::BITS)
+ 3
}
pub const fn reference_count(&self) -> u8 {
self.code.is_some() as u8 + self.data.is_some() as u8 + !self.libraries.is_empty() as u8
}
}
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
pub struct SpecialFlags {
pub tick: bool,
pub tock: bool,
}
impl SpecialFlags {
pub const BITS: u16 = 2;
}
impl Store for SpecialFlags {
fn store_into(&self, builder: &mut CellBuilder, _: &mut dyn Finalizer) -> Result<(), Error> {
builder.store_small_uint(((self.tick as u8) << 1) | self.tock as u8, 2)
}
}
impl<'a> Load<'a> for SpecialFlags {
fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
match slice.load_small_uint(2) {
Ok(data) => Ok(Self {
tick: data & 0b10 != 0,
tock: data & 0b01 != 0,
}),
Err(e) => Err(e),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
pub struct SimpleLib {
pub public: bool,
pub root: Cell,
}