1#[cfg(feature = "sync")]
4use std::sync::OnceLock;
5
6use crate::cell::*;
7use crate::dict::Dict;
8use crate::error::*;
9
10use crate::models::block::{BlockRef, ShardIdent};
11use crate::models::currency::CurrencyCollection;
12use crate::models::Lazy;
13
14#[cfg(feature = "tycho")]
15use crate::models::ShardIdentFull;
16
17pub use self::shard_accounts::*;
18pub use self::shard_extra::*;
19
20#[cfg(feature = "venom")]
21use super::ShardBlockRefs;
22
23mod shard_accounts;
24mod shard_extra;
25
26#[cfg(test)]
27mod tests;
28
29#[allow(clippy::large_enum_variant)]
31#[derive(Debug, Clone, Eq, PartialEq)]
32pub enum ShardState {
33 Unsplit(ShardStateUnsplit),
35 Split(ShardStateSplit),
37}
38
39impl Store for ShardState {
40 fn store_into(
41 &self,
42 builder: &mut CellBuilder,
43 context: &mut dyn CellContext,
44 ) -> Result<(), Error> {
45 match self {
46 Self::Unsplit(state) => state.store_into(builder, context),
47 Self::Split(state) => state.store_into(builder, context),
48 }
49 }
50}
51
52impl<'a> Load<'a> for ShardState {
53 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
54 Ok(if ok!(slice.get_bit(0)) {
55 match ShardStateUnsplit::load_from(slice) {
56 Ok(state) => Self::Unsplit(state),
57 Err(e) => return Err(e),
58 }
59 } else {
60 match ShardStateSplit::load_from(slice) {
61 Ok(state) => Self::Split(state),
62 Err(e) => return Err(e),
63 }
64 })
65 }
66}
67
68#[derive(Debug, Clone, Eq, PartialEq)]
70pub struct ShardStateUnsplit {
71 pub global_id: i32,
73 pub shard_ident: ShardIdent,
75 pub seqno: u32,
77 pub vert_seqno: u32,
79 pub gen_utime: u32,
81 #[cfg(any(feature = "venom", feature = "tycho"))]
83 pub gen_utime_ms: u16,
84 pub gen_lt: u64,
86 pub min_ref_mc_seqno: u32,
88
89 #[cfg(not(feature = "tycho"))]
91 pub out_msg_queue_info: Cell,
92
93 #[cfg(feature = "tycho")]
95 pub processed_upto: Lazy<ProcessedUptoInfo>,
96
97 pub before_split: bool,
99 pub accounts: Lazy<ShardAccounts>,
101 pub overload_history: u64,
103 pub underload_history: u64,
105 pub total_balance: CurrencyCollection,
107 pub total_validator_fees: CurrencyCollection,
109 pub libraries: Dict<HashBytes, LibDescr>,
111 pub master_ref: Option<BlockRef>,
113 pub custom: Option<Lazy<McStateExtra>>,
115 #[cfg(feature = "venom")]
117 pub shard_block_refs: Option<ShardBlockRefs>,
118}
119
120#[cfg(feature = "sync")]
121impl Default for ShardStateUnsplit {
122 fn default() -> Self {
123 Self {
124 global_id: 0,
125 shard_ident: ShardIdent::MASTERCHAIN,
126 seqno: 0,
127 vert_seqno: 0,
128 gen_utime: 0,
129 #[cfg(any(feature = "venom", feature = "tycho"))]
130 gen_utime_ms: 0,
131 gen_lt: 0,
132 min_ref_mc_seqno: 0,
133 #[cfg(not(feature = "tycho"))]
134 out_msg_queue_info: Cell::default(),
135 #[cfg(feature = "tycho")]
136 processed_upto: Self::empty_processed_upto_info().clone(),
137 before_split: false,
138 accounts: Self::empty_shard_accounts().clone(),
139 overload_history: 0,
140 underload_history: 0,
141 total_balance: CurrencyCollection::ZERO,
142 total_validator_fees: CurrencyCollection::ZERO,
143 libraries: Dict::new(),
144 master_ref: None,
145 custom: None,
146 #[cfg(feature = "venom")]
147 shard_block_refs: None,
148 }
149 }
150}
151
152impl ShardStateUnsplit {
153 const TAG_V1: u32 = 0x9023afe2;
154 #[cfg(any(feature = "venom", feature = "tycho"))]
155 const TAG_V2: u32 = 0x9023aeee;
156
157 #[cfg(all(feature = "sync", feature = "tycho"))]
159 pub fn empty_processed_upto_info() -> &'static Lazy<ProcessedUptoInfo> {
160 static PROCESSED_UPTO_INFO: OnceLock<Lazy<ProcessedUptoInfo>> = OnceLock::new();
161 PROCESSED_UPTO_INFO.get_or_init(|| Lazy::new(&ProcessedUptoInfo::default()).unwrap())
162 }
163
164 #[cfg(feature = "sync")]
166 pub fn empty_shard_accounts() -> &'static Lazy<ShardAccounts> {
167 static SHARD_ACCOUNTS: OnceLock<Lazy<ShardAccounts>> = OnceLock::new();
168 SHARD_ACCOUNTS.get_or_init(|| Lazy::new(&ShardAccounts::new()).unwrap())
169 }
170
171 pub fn load_accounts(&self) -> Result<ShardAccounts, Error> {
173 self.accounts.load()
174 }
175
176 pub fn load_custom(&self) -> Result<Option<McStateExtra>, Error> {
178 match &self.custom {
179 Some(custom) => match custom.load() {
180 Ok(custom) => Ok(Some(custom)),
181 Err(e) => Err(e),
182 },
183 None => Ok(None),
184 }
185 }
186
187 pub fn set_custom(&mut self, value: Option<&McStateExtra>) -> Result<(), Error> {
189 match (&mut self.custom, value) {
190 (None, None) => Ok(()),
191 (None, Some(value)) => {
192 self.custom = Some(ok!(Lazy::new(value)));
193 Ok(())
194 }
195 (Some(_), None) => {
196 self.custom = None;
197 Ok(())
198 }
199 (Some(custom), Some(value)) => custom.set(value),
200 }
201 }
202}
203
204impl Store for ShardStateUnsplit {
205 fn store_into(
206 &self,
207 builder: &mut CellBuilder,
208 context: &mut dyn CellContext,
209 ) -> Result<(), Error> {
210 let child_cell = {
211 let mut builder = CellBuilder::new();
212 ok!(builder.store_u64(self.overload_history));
213 ok!(builder.store_u64(self.underload_history));
214 ok!(self.total_balance.store_into(&mut builder, context));
215 ok!(self.total_validator_fees.store_into(&mut builder, context));
216 ok!(self.libraries.store_into(&mut builder, context));
217 ok!(self.master_ref.store_into(&mut builder, context));
218 ok!(builder.build_ext(context))
219 };
220
221 #[cfg(not(any(feature = "venom", feature = "tycho")))]
222 ok!(builder.store_u32(Self::TAG_V1));
223 #[cfg(any(feature = "venom", feature = "tycho"))]
224 ok!(builder.store_u32(Self::TAG_V2));
225
226 ok!(builder.store_u32(self.global_id as u32));
227 ok!(self.shard_ident.store_into(builder, context));
228 ok!(builder.store_u32(self.seqno));
229 ok!(builder.store_u32(self.vert_seqno));
230 ok!(builder.store_u32(self.gen_utime));
231
232 #[cfg(any(feature = "venom", feature = "tycho"))]
233 ok!(builder.store_u16(self.gen_utime_ms));
234
235 ok!(builder.store_u64(self.gen_lt));
236 ok!(builder.store_u32(self.min_ref_mc_seqno));
237 #[cfg(not(feature = "tycho"))]
238 ok!(self.out_msg_queue_info.store_into(builder, context));
239 #[cfg(feature = "tycho")]
240 ok!(self.processed_upto.store_into(builder, context));
241 ok!(builder.store_bit(self.before_split));
242 ok!(builder.store_reference(self.accounts.cell.clone()));
243 ok!(builder.store_reference(child_cell));
244
245 #[cfg(not(feature = "venom"))]
246 ok!(self.custom.store_into(builder, context));
247
248 #[cfg(feature = "venom")]
249 if self.custom.is_some() && self.shard_block_refs.is_some() {
250 return Err(Error::InvalidData);
251 } else if let Some(refs) = &self.shard_block_refs {
252 ok!(refs.store_into(builder, context));
253 } else {
254 ok!(self.custom.store_into(builder, context));
255 }
256
257 Ok(())
258 }
259}
260
261impl<'a> Load<'a> for ShardStateUnsplit {
262 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
263 let fast_finality = match slice.load_u32() {
264 Ok(Self::TAG_V1) => false,
265 #[cfg(any(feature = "venom", feature = "tycho"))]
266 Ok(Self::TAG_V2) => true,
267 Ok(_) => return Err(Error::InvalidTag),
268 Err(e) => return Err(e),
269 };
270
271 #[cfg(not(any(feature = "venom", feature = "tycho")))]
272 let _ = fast_finality;
273
274 #[cfg(not(feature = "tycho"))]
275 let out_msg_queue_info = ok!(<_>::load_from(slice));
276
277 #[cfg(feature = "tycho")]
278 let processed_upto = ok!(Lazy::load_from(slice));
279
280 let accounts = ok!(Lazy::load_from(slice));
281
282 let child_slice = &mut ok!(slice.load_reference_as_slice());
283
284 let global_id = ok!(slice.load_u32()) as i32;
285 let shard_ident = ok!(ShardIdent::load_from(slice));
286
287 Ok(Self {
288 global_id,
289 shard_ident,
290 seqno: ok!(slice.load_u32()),
291 vert_seqno: ok!(slice.load_u32()),
292 gen_utime: ok!(slice.load_u32()),
293 #[cfg(any(feature = "venom", feature = "tycho"))]
294 gen_utime_ms: if fast_finality {
295 ok!(slice.load_u16())
296 } else {
297 0
298 },
299 gen_lt: ok!(slice.load_u64()),
300 min_ref_mc_seqno: ok!(slice.load_u32()),
301 before_split: ok!(slice.load_bit()),
302 accounts,
303 overload_history: ok!(child_slice.load_u64()),
304 underload_history: ok!(child_slice.load_u64()),
305 total_balance: ok!(CurrencyCollection::load_from(child_slice)),
306 total_validator_fees: ok!(CurrencyCollection::load_from(child_slice)),
307 libraries: ok!(Dict::load_from(child_slice)),
308 master_ref: ok!(Option::<BlockRef>::load_from(child_slice)),
309 #[cfg(not(feature = "tycho"))]
310 out_msg_queue_info,
311 #[cfg(feature = "tycho")]
312 processed_upto,
313 #[allow(unused_labels)]
314 custom: 'custom: {
315 #[cfg(feature = "venom")]
316 if !shard_ident.is_masterchain() {
317 break 'custom None;
318 }
319 ok!(Option::<Lazy<McStateExtra>>::load_from(slice))
320 },
321 #[cfg(feature = "venom")]
322 shard_block_refs: if shard_ident.is_masterchain() {
323 None
324 } else {
325 Some(ok!(ShardBlockRefs::load_from(slice)))
326 },
327 })
328 }
329}
330
331#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
333#[tlb(tag = "#5f327da5")]
334pub struct ShardStateSplit {
335 pub left: Lazy<ShardStateUnsplit>,
337 pub right: Lazy<ShardStateUnsplit>,
339}
340
341#[derive(Debug, Clone, Eq, PartialEq)]
343pub struct LibDescr {
344 pub lib: Cell,
346 pub publishers: Dict<HashBytes, ()>,
348}
349
350impl Store for LibDescr {
351 fn store_into(&self, builder: &mut CellBuilder, _: &mut dyn CellContext) -> Result<(), Error> {
352 ok!(builder.store_small_uint(0, 2));
353 ok!(builder.store_reference(self.lib.clone()));
354 match self.publishers.root() {
355 Some(root) => builder.store_reference(root.clone()),
356 None => Err(Error::InvalidData),
357 }
358 }
359}
360
361impl<'a> Load<'a> for LibDescr {
362 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
363 if ok!(slice.load_small_uint(2)) != 0 {
364 return Err(Error::InvalidTag);
365 }
366 Ok(Self {
367 lib: ok!(slice.load_reference_cloned()),
368 publishers: ok!(Dict::load_from_root_ext(slice, &mut Cell::empty_context())),
369 })
370 }
371}
372
373#[cfg(feature = "tycho")]
375#[derive(Debug, Default, Clone, Store, Load)]
376pub struct ProcessedUptoInfo {
377 pub externals: Option<ExternalsProcessedUpto>,
381 pub internals: Dict<ShardIdentFull, InternalsProcessedUpto>,
385 pub processed_offset: u32,
388}
389
390#[cfg(feature = "tycho")]
400#[derive(Debug, Clone, Store, Load)]
401pub struct ExternalsProcessedUpto {
402 pub processed_to: (u32, u64),
408 pub read_to: (u32, u64),
410}
411
412#[cfg(feature = "tycho")]
426#[derive(Debug, Clone, Store, Load)]
427pub struct InternalsProcessedUpto {
428 pub processed_to_msg: (u64, HashBytes),
434 pub read_to_msg: (u64, HashBytes),
436}