everscale_types/models/account/
mod.rs

1//! Account state models.
2
3use crate::cell::*;
4use crate::dict::*;
5use crate::error::*;
6use crate::num::*;
7
8use crate::models::currency::CurrencyCollection;
9use crate::models::message::IntAddr;
10use crate::models::Lazy;
11
12/// Amount of unique cells and bits for shard states.
13#[derive(Debug, Default, Clone, Eq, PartialEq, Store, Load)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct StorageUsed {
16    /// Amount of unique cells.
17    pub cells: VarUint56,
18    /// The total number of bits in unique cells.
19    pub bits: VarUint56,
20    /// The number of public libraries in the state.
21    pub public_cells: VarUint56,
22}
23
24impl StorageUsed {
25    /// The additive identity for this type, i.e. `0`.
26    pub const ZERO: Self = Self {
27        cells: VarUint56::ZERO,
28        bits: VarUint56::ZERO,
29        public_cells: VarUint56::ZERO,
30    };
31
32    /// Computes a total storage usage stats.
33    ///
34    /// `cell_limit` is the maximum number of unique cells to visit.
35    /// If the limit is reached, the function will return [`Error::Cancelled`].
36    pub fn compute(account: &Account, cell_limit: usize) -> Result<Self, Error> {
37        let cell = {
38            let cx = &mut Cell::empty_context();
39            let mut storage = CellBuilder::new();
40            storage.store_u64(account.last_trans_lt)?;
41            account.balance.store_into(&mut storage, cx)?;
42            account.state.store_into(&mut storage, cx)?;
43            if account.init_code_hash.is_some() {
44                account.init_code_hash.store_into(&mut storage, cx)?;
45            }
46            storage.build_ext(cx)?
47        };
48
49        let Some(res) = cell.compute_unique_stats(cell_limit) else {
50            return Err(Error::Cancelled);
51        };
52
53        let res = Self {
54            cells: VarUint56::new(res.cell_count),
55            bits: VarUint56::new(res.bit_count),
56            public_cells: Default::default(),
57        };
58
59        if res.cells.is_valid() || !res.bits.is_valid() {
60            return Err(Error::IntOverflow);
61        }
62
63        Ok(res)
64    }
65}
66
67/// Amount of unique cells and bits.
68#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Store, Load)]
69#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
70pub struct StorageUsedShort {
71    /// Amount of unique cells.
72    pub cells: VarUint56,
73    /// The total number of bits in unique cells.
74    pub bits: VarUint56,
75}
76
77impl StorageUsedShort {
78    /// The additive identity for this type, i.e. `0`.
79    pub const ZERO: Self = Self {
80        cells: VarUint56::ZERO,
81        bits: VarUint56::ZERO,
82    };
83}
84
85/// Storage profile of an account.
86#[derive(Debug, Default, Clone, Eq, PartialEq, Store, Load)]
87#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
88pub struct StorageInfo {
89    /// Amount of unique cells and bits which account state occupies.
90    pub used: StorageUsed,
91    /// Unix timestamp of the last storage phase.
92    pub last_paid: u32,
93    /// Account debt for storing its state.
94    pub due_payment: Option<Tokens>,
95}
96
97/// Brief account status.
98#[derive(Debug, Clone, Copy, Eq, PartialEq)]
99#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
100pub enum AccountStatus {
101    /// Account exists but has not yet been deployed.
102    Uninit = 0b00,
103    /// Account exists but has been frozen.
104    Frozen = 0b01,
105    /// Account exists and has been deployed.
106    Active = 0b10,
107    /// Account does not exist.
108    NotExists = 0b11,
109}
110
111impl AccountStatus {
112    /// The number of data bits that this struct occupies.
113    pub const BITS: u16 = 2;
114}
115
116impl Store for AccountStatus {
117    #[inline]
118    fn store_into(&self, builder: &mut CellBuilder, _: &mut dyn CellContext) -> Result<(), Error> {
119        builder.store_small_uint(*self as u8, 2)
120    }
121}
122
123impl<'a> Load<'a> for AccountStatus {
124    #[inline]
125    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
126        match slice.load_small_uint(2) {
127            Ok(ty) => Ok(match ty {
128                0b00 => Self::Uninit,
129                0b01 => Self::Frozen,
130                0b10 => Self::Active,
131                0b11 => Self::NotExists,
132                _ => {
133                    debug_assert!(false, "unexpected small uint");
134                    // SAFETY: `load_small_uint` must return 2 bits
135                    unsafe { std::hint::unreachable_unchecked() }
136                }
137            }),
138            Err(e) => Err(e),
139        }
140    }
141}
142
143/// Shard accounts entry.
144#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
146pub struct ShardAccount {
147    /// Optional reference to account state.
148    pub account: Lazy<OptionalAccount>,
149    /// The exact hash of the last transaction.
150    pub last_trans_hash: HashBytes,
151    /// The exact logical time of the last transaction.
152    pub last_trans_lt: u64,
153}
154
155impl ShardAccount {
156    /// Tries to load account data.
157    pub fn load_account(&self) -> Result<Option<Account>, Error> {
158        let OptionalAccount(account) = ok!(self.account.load());
159        Ok(account)
160    }
161}
162
163/// A wrapper for `Option<Account>` with customized representation.
164#[derive(Default, Debug, Clone, Eq, PartialEq)]
165#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
166pub struct OptionalAccount(pub Option<Account>);
167
168impl OptionalAccount {
169    /// Non-existing account.
170    pub const EMPTY: Self = Self(None);
171
172    /// Returns an optional account status.
173    pub fn status(&self) -> AccountStatus {
174        match &self.0 {
175            None => AccountStatus::NotExists,
176            Some(account) => account.state.status(),
177        }
178    }
179
180    /// Logical time after the last transaction execution if account exists
181    /// or zero otherwise.
182    pub fn last_trans_lt(&self) -> u64 {
183        match &self.0 {
184            None => 0,
185            Some(account) => account.last_trans_lt,
186        }
187    }
188
189    /// Account balance for all currencies.
190    #[cfg(feature = "sync")]
191    pub fn balance(&self) -> &CurrencyCollection {
192        static DEFAULT_VALANCE: CurrencyCollection = CurrencyCollection::ZERO;
193
194        match &self.0 {
195            None => &DEFAULT_VALANCE,
196            Some(account) => &account.balance,
197        }
198    }
199
200    /// Returns an account state if it exists.
201    pub fn state(&self) -> Option<&AccountState> {
202        Some(&self.0.as_ref()?.state)
203    }
204}
205
206impl AsRef<Option<Account>> for OptionalAccount {
207    #[inline]
208    fn as_ref(&self) -> &Option<Account> {
209        &self.0
210    }
211}
212
213impl AsMut<Option<Account>> for OptionalAccount {
214    #[inline]
215    fn as_mut(&mut self) -> &mut Option<Account> {
216        &mut self.0
217    }
218}
219
220impl Store for OptionalAccount {
221    fn store_into(
222        &self,
223        builder: &mut CellBuilder,
224        context: &mut dyn CellContext,
225    ) -> Result<(), Error> {
226        match &self.0 {
227            None => builder.store_bit_zero(),
228            Some(account) => {
229                let with_init_code_hash = account.init_code_hash.is_some();
230                ok!(if with_init_code_hash {
231                    builder.store_small_uint(0b0001, 4)
232                } else {
233                    builder.store_bit_one()
234                });
235
236                ok!(account.address.store_into(builder, context));
237                ok!(account.storage_stat.store_into(builder, context));
238                ok!(builder.store_u64(account.last_trans_lt));
239                ok!(account.balance.store_into(builder, context));
240                ok!(account.state.store_into(builder, context));
241                if let Some(init_code_hash) = &account.init_code_hash {
242                    ok!(builder.store_bit_one());
243                    builder.store_u256(init_code_hash)
244                } else {
245                    Ok(())
246                }
247            }
248        }
249    }
250}
251
252impl<'a> Load<'a> for OptionalAccount {
253    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
254        let with_init_code_hash = if ok!(slice.load_bit()) {
255            false // old version
256        } else if slice.is_data_empty() {
257            return Ok(Self::EMPTY);
258        } else {
259            let tag = ok!(slice.load_small_uint(3));
260            match tag {
261                0 => false, // old version
262                1 => true,  // new version
263                _ => return Err(Error::InvalidData),
264            }
265        };
266
267        Ok(Self(Some(Account {
268            address: ok!(IntAddr::load_from(slice)),
269            storage_stat: ok!(StorageInfo::load_from(slice)),
270            last_trans_lt: ok!(slice.load_u64()),
271            balance: ok!(CurrencyCollection::load_from(slice)),
272            state: ok!(AccountState::load_from(slice)),
273            init_code_hash: if with_init_code_hash {
274                ok!(Option::<HashBytes>::load_from(slice))
275            } else {
276                None
277            },
278        })))
279    }
280}
281
282impl From<Account> for OptionalAccount {
283    #[inline]
284    fn from(value: Account) -> Self {
285        Self(Some(value))
286    }
287}
288
289/// Existing account data.
290#[derive(Debug, Clone, Eq, PartialEq)]
291#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
292pub struct Account {
293    /// Account address.
294    pub address: IntAddr,
295    /// Storage statistics.
296    pub storage_stat: StorageInfo,
297    /// Logical time after the last transaction execution.
298    pub last_trans_lt: u64,
299    /// Account balance for all currencies.
300    pub balance: CurrencyCollection,
301    /// Account state.
302    pub state: AccountState,
303    /// Optional initial code hash.
304    pub init_code_hash: Option<HashBytes>,
305}
306
307/// State of an existing account.
308#[derive(Debug, Clone, Eq, PartialEq)]
309#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
310#[cfg_attr(feature = "serde", serde(tag = "status"))]
311pub enum AccountState {
312    /// Account exists but has not yet been deployed.
313    Uninit,
314    /// Account exists and has been deployed.
315    Active(StateInit),
316    /// Account exists but has been frozen. Contains a hash of the last known [`StateInit`].
317    Frozen(HashBytes),
318}
319
320impl AccountState {
321    /// Returns an account status.
322    pub fn status(&self) -> AccountStatus {
323        match self {
324            Self::Uninit => AccountStatus::Uninit,
325            Self::Active(_) => AccountStatus::Active,
326            Self::Frozen(_) => AccountStatus::Frozen,
327        }
328    }
329}
330
331impl Store for AccountState {
332    fn store_into(
333        &self,
334        builder: &mut CellBuilder,
335        context: &mut dyn CellContext,
336    ) -> Result<(), Error> {
337        match self {
338            Self::Uninit => builder.store_small_uint(0b00, 2),
339            Self::Active(state) => {
340                ok!(builder.store_bit_one());
341                state.store_into(builder, context)
342            }
343            Self::Frozen(hash) => {
344                ok!(builder.store_small_uint(0b01, 2));
345                builder.store_u256(hash)
346            }
347        }
348    }
349}
350
351impl<'a> Load<'a> for AccountState {
352    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
353        Ok(if ok!(slice.load_bit()) {
354            match StateInit::load_from(slice) {
355                Ok(state) => Self::Active(state),
356                Err(e) => return Err(e),
357            }
358        } else if ok!(slice.load_bit()) {
359            match slice.load_u256() {
360                Ok(state) => Self::Frozen(state),
361                Err(e) => return Err(e),
362            }
363        } else {
364            Self::Uninit
365        })
366    }
367}
368
369/// Deployed account state.
370#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
371#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
372pub struct StateInit {
373    /// Optional split depth for large smart contracts.
374    pub split_depth: Option<SplitDepth>,
375    /// Optional special contract flags.
376    pub special: Option<SpecialFlags>,
377    /// Optional contract code.
378    #[cfg_attr(feature = "serde", serde(with = "crate::boc::Boc"))]
379    pub code: Option<Cell>,
380    /// Optional contract data.
381    #[cfg_attr(feature = "serde", serde(with = "crate::boc::Boc"))]
382    pub data: Option<Cell>,
383    /// Libraries used in smart-contract.
384    pub libraries: Dict<HashBytes, SimpleLib>,
385}
386
387impl Default for StateInit {
388    fn default() -> Self {
389        Self {
390            split_depth: None,
391            special: None,
392            code: None,
393            data: None,
394            libraries: Dict::new(),
395        }
396    }
397}
398
399impl StateInit {
400    /// Exact size of this value when it is stored in slice.
401    pub const fn exact_size_const(&self) -> Size {
402        Size {
403            bits: self.bit_len(),
404            refs: self.reference_count(),
405        }
406    }
407
408    /// Returns the number of data bits that this struct occupies.
409    const fn bit_len(&self) -> u16 {
410        (1 + self.split_depth.is_some() as u16 * SplitDepth::BITS)
411            + (1 + self.special.is_some() as u16 * SpecialFlags::BITS)
412            + 3
413    }
414
415    /// Returns the number of references that this struct occupies.
416    const fn reference_count(&self) -> u8 {
417        self.code.is_some() as u8 + self.data.is_some() as u8 + !self.libraries.is_empty() as u8
418    }
419}
420
421impl ExactSize for StateInit {
422    #[inline]
423    fn exact_size(&self) -> Size {
424        self.exact_size_const()
425    }
426}
427
428/// Special transactions execution flags.
429#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
430#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
431pub struct SpecialFlags {
432    /// Account will be called at the beginning of each block.
433    pub tick: bool,
434    /// Account will be called at the end of each block.
435    pub tock: bool,
436}
437
438impl SpecialFlags {
439    /// The number of data bits that this struct occupies.
440    pub const BITS: u16 = 2;
441}
442
443impl Store for SpecialFlags {
444    fn store_into(&self, builder: &mut CellBuilder, _: &mut dyn CellContext) -> Result<(), Error> {
445        builder.store_small_uint(((self.tick as u8) << 1) | self.tock as u8, 2)
446    }
447}
448
449impl<'a> Load<'a> for SpecialFlags {
450    fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
451        match slice.load_small_uint(2) {
452            Ok(data) => Ok(Self {
453                tick: data & 0b10 != 0,
454                tock: data & 0b01 != 0,
455            }),
456            Err(e) => Err(e),
457        }
458    }
459}
460
461/// Simple TVM library.
462#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
463#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
464pub struct SimpleLib {
465    /// Whether this library is accessible from other accounts.
466    pub public: bool,
467    /// Library code.
468    #[cfg_attr(feature = "serde", serde(with = "crate::boc::Boc"))]
469    pub root: Cell,
470}