1use 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#[derive(Debug, Default, Clone, Eq, PartialEq, Store, Load)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct StorageUsed {
16 pub cells: VarUint56,
18 pub bits: VarUint56,
20 pub public_cells: VarUint56,
22}
23
24impl StorageUsed {
25 pub const ZERO: Self = Self {
27 cells: VarUint56::ZERO,
28 bits: VarUint56::ZERO,
29 public_cells: VarUint56::ZERO,
30 };
31
32 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#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Store, Load)]
69#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
70pub struct StorageUsedShort {
71 pub cells: VarUint56,
73 pub bits: VarUint56,
75}
76
77impl StorageUsedShort {
78 pub const ZERO: Self = Self {
80 cells: VarUint56::ZERO,
81 bits: VarUint56::ZERO,
82 };
83}
84
85#[derive(Debug, Default, Clone, Eq, PartialEq, Store, Load)]
87#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
88pub struct StorageInfo {
89 pub used: StorageUsed,
91 pub last_paid: u32,
93 pub due_payment: Option<Tokens>,
95}
96
97#[derive(Debug, Clone, Copy, Eq, PartialEq)]
99#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
100pub enum AccountStatus {
101 Uninit = 0b00,
103 Frozen = 0b01,
105 Active = 0b10,
107 NotExists = 0b11,
109}
110
111impl AccountStatus {
112 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 unsafe { std::hint::unreachable_unchecked() }
136 }
137 }),
138 Err(e) => Err(e),
139 }
140 }
141}
142
143#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
146pub struct ShardAccount {
147 pub account: Lazy<OptionalAccount>,
149 pub last_trans_hash: HashBytes,
151 pub last_trans_lt: u64,
153}
154
155impl ShardAccount {
156 pub fn load_account(&self) -> Result<Option<Account>, Error> {
158 let OptionalAccount(account) = ok!(self.account.load());
159 Ok(account)
160 }
161}
162
163#[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 pub const EMPTY: Self = Self(None);
171
172 pub fn status(&self) -> AccountStatus {
174 match &self.0 {
175 None => AccountStatus::NotExists,
176 Some(account) => account.state.status(),
177 }
178 }
179
180 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 #[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 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 } 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, 1 => true, _ => 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#[derive(Debug, Clone, Eq, PartialEq)]
291#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
292pub struct Account {
293 pub address: IntAddr,
295 pub storage_stat: StorageInfo,
297 pub last_trans_lt: u64,
299 pub balance: CurrencyCollection,
301 pub state: AccountState,
303 pub init_code_hash: Option<HashBytes>,
305}
306
307#[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 Uninit,
314 Active(StateInit),
316 Frozen(HashBytes),
318}
319
320impl AccountState {
321 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#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
371#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
372pub struct StateInit {
373 pub split_depth: Option<SplitDepth>,
375 pub special: Option<SpecialFlags>,
377 #[cfg_attr(feature = "serde", serde(with = "crate::boc::Boc"))]
379 pub code: Option<Cell>,
380 #[cfg_attr(feature = "serde", serde(with = "crate::boc::Boc"))]
382 pub data: Option<Cell>,
383 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 pub const fn exact_size_const(&self) -> Size {
402 Size {
403 bits: self.bit_len(),
404 refs: self.reference_count(),
405 }
406 }
407
408 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 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#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
430#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
431pub struct SpecialFlags {
432 pub tick: bool,
434 pub tock: bool,
436}
437
438impl SpecialFlags {
439 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#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
463#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
464pub struct SimpleLib {
465 pub public: bool,
467 #[cfg_attr(feature = "serde", serde(with = "crate::boc::Boc"))]
469 pub root: Cell,
470}