1use crate::cell::*;
4use crate::dict::*;
5use crate::error::*;
6use crate::models::currency::CurrencyCollection;
7use crate::models::message::IntAddr;
8use crate::num::*;
9
10#[derive(Debug, Default, Clone, Eq, PartialEq, Store, Load)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
14pub struct StorageUsed {
15 pub cells: VarUint56,
17 pub bits: VarUint56,
19}
20
21impl StorageUsed {
22 pub const ZERO: Self = Self {
24 cells: VarUint56::ZERO,
25 bits: VarUint56::ZERO,
26 };
27
28 pub fn compute(account: &Account, cell_limit: usize) -> Result<Self, Error> {
33 let cell = {
34 let cx = Cell::empty_context();
35 let mut storage = CellBuilder::new();
36 storage.store_u64(account.last_trans_lt)?;
37 account.balance.store_into(&mut storage, cx)?;
38 account.state.store_into(&mut storage, cx)?;
39 storage.build_ext(cx)?
40 };
41
42 let Some(res) = cell.compute_unique_stats(cell_limit) else {
43 return Err(Error::Cancelled);
44 };
45
46 let res = Self {
47 cells: VarUint56::new(res.cell_count),
48 bits: VarUint56::new(res.bit_count),
49 };
50
51 if res.cells.is_valid() || !res.bits.is_valid() {
52 return Err(Error::IntOverflow);
53 }
54
55 Ok(res)
56 }
57}
58
59#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Store, Load)]
61#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
62#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
63pub struct StorageUsedShort {
64 pub cells: VarUint56,
66 pub bits: VarUint56,
68}
69
70impl StorageUsedShort {
71 pub const ZERO: Self = Self {
73 cells: VarUint56::ZERO,
74 bits: VarUint56::ZERO,
75 };
76}
77
78#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
80#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
81#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
82pub enum StorageExtra {
83 #[default]
85 None,
86 DictHash(HashBytes),
88}
89
90impl Store for StorageExtra {
91 fn store_into(&self, builder: &mut CellBuilder, _: &dyn CellContext) -> Result<(), Error> {
92 match self {
93 StorageExtra::None => builder.store_zeros(3)?,
94 StorageExtra::DictHash(dict_hash) => {
95 builder.store_small_uint(1, 3)?;
96 builder.store_u256(dict_hash)?;
97 }
98 }
99 Ok(())
100 }
101}
102
103impl<'a> Load<'a> for StorageExtra {
104 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
105 match slice.load_small_uint(3)? {
106 0b000 => Ok(Self::None),
107 0b001 => Ok(Self::DictHash(slice.load_u256()?)),
108 _ => Err(Error::InvalidTag),
109 }
110 }
111}
112
113#[derive(Debug, Default, Clone, Eq, PartialEq, Store, Load)]
115#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
116#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
117pub struct StorageInfo {
118 pub used: StorageUsed,
120 pub storage_extra: StorageExtra,
122 pub last_paid: u32,
124 pub due_payment: Option<Tokens>,
126}
127
128#[derive(Debug, Clone, Copy, Eq, PartialEq)]
130#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
131#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
132pub enum AccountStatus {
133 Uninit = 0b00,
135 Frozen = 0b01,
137 Active = 0b10,
139 NotExists = 0b11,
141}
142
143impl AccountStatus {
144 pub const BITS: u16 = 2;
146}
147
148impl Store for AccountStatus {
149 #[inline]
150 fn store_into(&self, builder: &mut CellBuilder, _: &dyn CellContext) -> Result<(), Error> {
151 builder.store_small_uint(*self as u8, 2)
152 }
153}
154
155impl<'a> Load<'a> for AccountStatus {
156 #[inline]
157 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
158 match slice.load_small_uint(2) {
159 Ok(ty) => Ok(match ty {
160 0b00 => Self::Uninit,
161 0b01 => Self::Frozen,
162 0b10 => Self::Active,
163 0b11 => Self::NotExists,
164 _ => {
165 debug_assert!(false, "unexpected small uint");
166 unsafe { std::hint::unreachable_unchecked() }
168 }
169 }),
170 Err(e) => Err(e),
171 }
172 }
173}
174
175#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
177#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
178pub struct ShardAccount {
179 pub account: Lazy<OptionalAccount>,
181 pub last_trans_hash: HashBytes,
183 pub last_trans_lt: u64,
185}
186
187impl ShardAccount {
188 pub fn load_account(&self) -> Result<Option<Account>, Error> {
190 let OptionalAccount(account) = ok!(self.account.load());
191 Ok(account)
192 }
193}
194
195#[cfg(feature = "arbitrary")]
196impl<'a> arbitrary::Arbitrary<'a> for ShardAccount {
197 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
198 let account = u.arbitrary::<OptionalAccount>()?;
199 Ok(Self {
200 account: Lazy::new(&account).unwrap(),
201 last_trans_hash: u.arbitrary()?,
202 last_trans_lt: u.arbitrary()?,
203 })
204 }
205
206 #[inline]
207 fn size_hint(depth: usize) -> (usize, Option<usize>) {
208 Self::try_size_hint(depth).unwrap_or_default()
209 }
210
211 fn try_size_hint(
212 depth: usize,
213 ) -> arbitrary::Result<(usize, Option<usize>), arbitrary::MaxRecursionReached> {
214 Ok(arbitrary::size_hint::and_all(&[
215 <OptionalAccount as arbitrary::Arbitrary>::try_size_hint(depth)?,
216 <HashBytes as arbitrary::Arbitrary>::try_size_hint(depth)?,
217 <u64 as arbitrary::Arbitrary>::try_size_hint(depth)?,
218 ]))
219 }
220}
221
222#[derive(Default, Debug, Clone, Eq, PartialEq, Store, Load)]
224#[repr(transparent)]
225#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
226pub struct OptionalAccount(pub Option<Account>);
227
228impl OptionalAccount {
229 pub const EMPTY: Self = Self(None);
231
232 pub fn status(&self) -> AccountStatus {
234 match &self.0 {
235 None => AccountStatus::NotExists,
236 Some(account) => account.state.status(),
237 }
238 }
239
240 pub fn last_trans_lt(&self) -> u64 {
243 match &self.0 {
244 None => 0,
245 Some(account) => account.last_trans_lt,
246 }
247 }
248
249 #[cfg(feature = "sync")]
251 pub fn balance(&self) -> &CurrencyCollection {
252 static DEFAULT_VALANCE: CurrencyCollection = CurrencyCollection::ZERO;
253
254 match &self.0 {
255 None => &DEFAULT_VALANCE,
256 Some(account) => &account.balance,
257 }
258 }
259
260 pub fn state(&self) -> Option<&AccountState> {
262 Some(&self.0.as_ref()?.state)
263 }
264}
265
266impl AsRef<Option<Account>> for OptionalAccount {
267 #[inline]
268 fn as_ref(&self) -> &Option<Account> {
269 &self.0
270 }
271}
272
273impl AsMut<Option<Account>> for OptionalAccount {
274 #[inline]
275 fn as_mut(&mut self) -> &mut Option<Account> {
276 &mut self.0
277 }
278}
279
280impl From<Account> for OptionalAccount {
281 #[inline]
282 fn from(value: Account) -> Self {
283 Self(Some(value))
284 }
285}
286
287#[cfg(feature = "arbitrary")]
288impl<'a> arbitrary::Arbitrary<'a> for OptionalAccount {
289 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
290 u.ratio(9u8, 10u8)?
291 .then(|| u.arbitrary())
292 .transpose()
293 .map(Self)
294 }
295
296 #[inline]
297 fn size_hint(depth: usize) -> (usize, Option<usize>) {
298 Self::try_size_hint(depth).unwrap_or_default()
299 }
300
301 #[inline]
302 fn try_size_hint(
303 depth: usize,
304 ) -> arbitrary::Result<(usize, Option<usize>), arbitrary::MaxRecursionReached> {
305 <Option<Account>>::try_size_hint(depth)
306 }
307}
308
309#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
311#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
312#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
313pub struct Account {
314 pub address: IntAddr,
316 pub storage_stat: StorageInfo,
318 pub last_trans_lt: u64,
320 pub balance: CurrencyCollection,
322 pub state: AccountState,
324}
325
326#[derive(Debug, Clone, Eq, PartialEq)]
328#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
329#[cfg_attr(feature = "serde", serde(tag = "status"))]
330#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
331pub enum AccountState {
332 Uninit,
334 Active(StateInit),
336 Frozen(HashBytes),
338}
339
340impl AccountState {
341 pub fn status(&self) -> AccountStatus {
343 match self {
344 Self::Uninit => AccountStatus::Uninit,
345 Self::Active(_) => AccountStatus::Active,
346 Self::Frozen(_) => AccountStatus::Frozen,
347 }
348 }
349}
350
351impl Store for AccountState {
352 fn store_into(
353 &self,
354 builder: &mut CellBuilder,
355 context: &dyn CellContext,
356 ) -> Result<(), Error> {
357 match self {
358 Self::Uninit => builder.store_small_uint(0b00, 2),
359 Self::Active(state) => {
360 ok!(builder.store_bit_one());
361 state.store_into(builder, context)
362 }
363 Self::Frozen(hash) => {
364 ok!(builder.store_small_uint(0b01, 2));
365 builder.store_u256(hash)
366 }
367 }
368 }
369}
370
371impl<'a> Load<'a> for AccountState {
372 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
373 Ok(if ok!(slice.load_bit()) {
374 match StateInit::load_from(slice) {
375 Ok(state) => Self::Active(state),
376 Err(e) => return Err(e),
377 }
378 } else if ok!(slice.load_bit()) {
379 match slice.load_u256() {
380 Ok(state) => Self::Frozen(state),
381 Err(e) => return Err(e),
382 }
383 } else {
384 Self::Uninit
385 })
386 }
387}
388
389#[derive(Debug, Clone, Default, Eq, PartialEq, Store, Load)]
391#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
392pub struct StateInit {
393 pub split_depth: Option<SplitDepth>,
395 pub special: Option<SpecialFlags>,
397 #[cfg_attr(feature = "serde", serde(with = "crate::boc::Boc"))]
399 pub code: Option<Cell>,
400 #[cfg_attr(feature = "serde", serde(with = "crate::boc::Boc"))]
402 pub data: Option<Cell>,
403 pub libraries: Dict<HashBytes, SimpleLib>,
405}
406
407impl StateInit {
408 pub const fn exact_size_const(&self) -> Size {
410 Size {
411 bits: self.bit_len(),
412 refs: self.reference_count(),
413 }
414 }
415
416 pub const fn bit_len(&self) -> u16 {
418 (1 + self.split_depth.is_some() as u16 * SplitDepth::BITS)
419 + (1 + self.special.is_some() as u16 * SpecialFlags::BITS)
420 + 3
421 }
422
423 pub const fn reference_count(&self) -> u8 {
425 self.code.is_some() as u8 + self.data.is_some() as u8 + !self.libraries.is_empty() as u8
426 }
427}
428
429impl ExactSize for StateInit {
430 #[inline]
431 fn exact_size(&self) -> Size {
432 self.exact_size_const()
433 }
434}
435
436#[cfg(feature = "arbitrary")]
437impl<'a> arbitrary::Arbitrary<'a> for StateInit {
438 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
439 let split_depth = u.ratio(1u8, 50u8)?.then(|| u.arbitrary()).transpose()?;
440 let special = u.ratio(1u8, 50u8)?.then(|| u.arbitrary()).transpose()?;
441 let code = u.ratio(9u8, 10u8)?.then(|| u.arbitrary()).transpose()?;
442 let data = u.ratio(9u8, 10u8)?.then(|| u.arbitrary()).transpose()?;
443
444 let mut libraries = Dict::new();
445 match u.arbitrary::<u8>()? {
446 0..=128 => {}
447 n => {
448 for _ in 128..n {
449 let lib = u.arbitrary::<SimpleLib>()?;
450 if lib.root.level() != 0 || lib.root.has_max_depth() {
451 return Err(arbitrary::Error::IncorrectFormat);
452 }
453 libraries.set(u.arbitrary::<HashBytes>()?, lib).unwrap();
454 }
455 }
456 }
457
458 Ok(Self {
459 split_depth,
460 special,
461 code,
462 data,
463 libraries,
464 })
465 }
466
467 #[inline]
468 fn size_hint(depth: usize) -> (usize, Option<usize>) {
469 Self::try_size_hint(depth).unwrap_or_default()
470 }
471
472 fn try_size_hint(
473 depth: usize,
474 ) -> arbitrary::Result<(usize, Option<usize>), arbitrary::MaxRecursionReached> {
475 Ok(arbitrary::size_hint::and_all(&[
476 <Option<SplitDepth>>::try_size_hint(depth)?,
477 <Option<SpecialFlags>>::try_size_hint(depth)?,
478 <Option<Cell>>::try_size_hint(depth)?,
479 <Option<Cell>>::try_size_hint(depth)?,
480 (1, None),
481 ]))
482 }
483}
484
485#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
487#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
488#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
489pub struct SpecialFlags {
490 pub tick: bool,
492 pub tock: bool,
494}
495
496impl SpecialFlags {
497 pub const BITS: u16 = 2;
499}
500
501impl Store for SpecialFlags {
502 fn store_into(&self, builder: &mut CellBuilder, _: &dyn CellContext) -> Result<(), Error> {
503 builder.store_small_uint(((self.tick as u8) << 1) | self.tock as u8, 2)
504 }
505}
506
507impl<'a> Load<'a> for SpecialFlags {
508 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
509 match slice.load_small_uint(2) {
510 Ok(data) => Ok(Self {
511 tick: data & 0b10 != 0,
512 tock: data & 0b01 != 0,
513 }),
514 Err(e) => Err(e),
515 }
516 }
517}
518
519#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
521#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
522#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
523pub struct SimpleLib {
524 pub public: bool,
526 #[cfg_attr(feature = "serde", serde(with = "crate::boc::Boc"))]
528 pub root: Cell,
529}