1#[cfg(feature = "sync")]
4use std::sync::OnceLock;
5
6use crate::cell::*;
7use crate::dict::Dict;
8use crate::error::Error;
9use crate::merkle::MerkleUpdate;
10use crate::num::*;
11use crate::util::*;
12
13use crate::models::currency::CurrencyCollection;
14use crate::models::global_version::GlobalVersion;
15use crate::models::Lazy;
16
17pub use self::block_extra::*;
18pub use self::block_id::*;
19pub use self::block_proof::*;
20pub use self::shard_hashes::*;
21
22mod block_extra;
23mod block_id;
24mod block_proof;
25mod shard_hashes;
26
27#[cfg(test)]
28mod tests;
29
30#[derive(Debug, Clone, Eq, PartialEq)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize))]
33pub struct Block {
34 pub global_id: i32,
36 pub info: Lazy<BlockInfo>,
38 pub value_flow: Lazy<ValueFlow>,
40 pub state_update: Lazy<MerkleUpdate>,
42 #[cfg(not(feature = "tycho"))]
44 pub out_msg_queue_updates: Option<Dict<u32, Lazy<MerkleUpdate>>>,
45 #[cfg(feature = "tycho")]
47 pub out_msg_queue_updates: OutMsgQueueUpdates,
48 pub extra: Lazy<BlockExtra>,
50}
51
52impl Block {
53 #[cfg(not(feature = "tycho"))]
54 const TAG_V1: u32 = 0x11ef55aa;
55 const TAG_V2: u32 = 0x11ef55bb;
56
57 const DATA_FOR_SIGN_SIZE: usize = 4 + 32 + 32;
58 const DATA_FOR_SIGN_TAG: [u8; 4] = [0x70, 0x6e, 0x0b, 0xc5];
59
60 pub fn load_info(&self) -> Result<BlockInfo, Error> {
62 self.info.load()
63 }
64
65 pub fn load_value_flow(&self) -> Result<ValueFlow, Error> {
67 self.value_flow.load()
68 }
69
70 pub fn load_state_update(&self) -> Result<MerkleUpdate, Error> {
72 self.state_update.load()
73 }
74
75 pub fn load_extra(&self) -> Result<BlockExtra, Error> {
77 self.extra.load()
78 }
79
80 pub fn build_data_for_sign(block_id: &BlockId) -> [u8; Self::DATA_FOR_SIGN_SIZE] {
82 let mut data = [0u8; Self::DATA_FOR_SIGN_SIZE];
83 data[0..4].copy_from_slice(&Self::DATA_FOR_SIGN_TAG);
84 data[4..36].copy_from_slice(block_id.root_hash.as_ref());
85 data[36..68].copy_from_slice(block_id.file_hash.as_ref());
86 data
87 }
88}
89
90impl Store for Block {
91 fn store_into(
92 &self,
93 builder: &mut CellBuilder,
94 context: &mut dyn CellContext,
95 ) -> Result<(), Error> {
96 #[cfg(not(feature = "tycho"))]
97 let tag = if self.out_msg_queue_updates.is_none() {
98 Self::TAG_V1
99 } else {
100 Self::TAG_V2
101 };
102 #[cfg(feature = "tycho")]
103 let tag = Self::TAG_V2;
104
105 ok!(builder.store_u32(tag));
106 ok!(builder.store_u32(self.global_id as u32));
107 ok!(builder.store_reference(self.info.cell.clone()));
108 ok!(builder.store_reference(self.value_flow.cell.clone()));
109
110 #[cfg(not(feature = "tycho"))]
111 let out_msg_queue_updates = self.out_msg_queue_updates.as_ref();
112 #[cfg(feature = "tycho")]
113 let out_msg_queue_updates = Some(&self.out_msg_queue_updates);
114
115 ok!(if let Some(out_msg_queue_updates) = out_msg_queue_updates {
116 let cell = {
117 let mut builder = CellBuilder::new();
118 ok!(self.state_update.store_into(&mut builder, context));
119 ok!(out_msg_queue_updates.store_into(&mut builder, context));
120 ok!(builder.build_ext(context))
121 };
122 builder.store_reference(cell)
123 } else {
124 self.state_update.store_into(builder, context)
125 });
126
127 self.extra.store_into(builder, context)
128 }
129}
130
131impl<'a> Load<'a> for Block {
132 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
133 #[cfg(not(feature = "tycho"))]
134 let with_out_msg_queue_updates = match ok!(slice.load_u32()) {
135 Self::TAG_V1 => false,
136 Self::TAG_V2 => true,
137 _ => return Err(Error::InvalidTag),
138 };
139
140 #[cfg(feature = "tycho")]
141 if ok!(slice.load_u32()) != Self::TAG_V2 {
142 return Err(Error::InvalidTag);
143 }
144
145 let global_id = ok!(slice.load_u32()) as i32;
146 let info = ok!(Lazy::load_from(slice));
147 let value_flow = ok!(Lazy::load_from(slice));
148
149 #[cfg(not(feature = "tycho"))]
150 let (state_update, out_msg_queue_updates) = if with_out_msg_queue_updates {
151 let slice = &mut ok!(slice.load_reference_as_slice());
152 (
153 ok!(Lazy::load_from(slice)),
154 Some(ok!(Dict::load_from(slice))),
155 )
156 } else {
157 (ok!(Lazy::load_from(slice)), None)
158 };
159
160 #[cfg(feature = "tycho")]
161 let (state_update, out_msg_queue_updates) = {
162 let slice = &mut ok!(slice.load_reference_as_slice());
163 (ok!(<_>::load_from(slice)), ok!(<_>::load_from(slice)))
164 };
165
166 Ok(Self {
167 global_id,
168 info,
169 value_flow,
170 state_update,
171 out_msg_queue_updates,
172 extra: ok!(<_>::load_from(slice)),
173 })
174 }
175}
176
177#[derive(Debug, Clone, Eq, PartialEq)]
179#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
180pub struct BlockInfo {
181 pub version: u32,
183 pub after_merge: bool,
185 pub before_split: bool,
187 pub after_split: bool,
189 pub want_split: bool,
191 pub want_merge: bool,
193 pub key_block: bool,
195
196 pub flags: u8,
200 pub seqno: u32,
202 pub vert_seqno: u32,
204
205 pub shard: ShardIdent,
207 pub gen_utime: u32,
209 #[cfg(any(feature = "venom", feature = "tycho"))]
211 pub gen_utime_ms: u16,
212 pub start_lt: u64,
214 pub end_lt: u64,
216 pub gen_validator_list_hash_short: u32,
218 pub gen_catchain_seqno: u32,
220 pub min_ref_mc_seqno: u32,
222 pub prev_key_block_seqno: u32,
224 pub gen_software: GlobalVersion,
226
227 pub master_ref: Option<Lazy<BlockRef>>,
229 #[cfg_attr(feature = "serde", serde(with = "serde_prev_block_ref"))]
231 pub prev_ref: Cell,
232 pub prev_vert_ref: Option<Lazy<BlockRef>>,
234}
235
236#[cfg(feature = "sync")]
237impl Default for BlockInfo {
238 fn default() -> Self {
239 Self {
240 version: 0,
241 after_merge: false,
242 before_split: false,
243 after_split: false,
244 want_split: false,
245 want_merge: false,
246 key_block: false,
247 flags: 0,
248 seqno: 0,
249 vert_seqno: 0,
250 shard: ShardIdent::MASTERCHAIN,
251 gen_utime: 0,
252 #[cfg(any(feature = "venom", feature = "tycho"))]
253 gen_utime_ms: 0,
254 start_lt: 0,
255 end_lt: 0,
256 gen_validator_list_hash_short: 0,
257 gen_catchain_seqno: 0,
258 min_ref_mc_seqno: 0,
259 prev_key_block_seqno: 0,
260 gen_software: Default::default(),
261 master_ref: None,
262 prev_ref: PrevBlockRef::empty_single_ref().clone(),
263 prev_vert_ref: None,
264 }
265 }
266}
267
268impl BlockInfo {
269 const TAG_V1: u32 = 0x9bc7a987;
270 #[cfg(any(feature = "venom", feature = "tycho"))]
271 const TAG_V2: u32 = 0x9bc7a988;
272 const FLAG_WITH_GEN_SOFTWARE: u8 = 0x1;
273
274 pub fn set_gen_software(&mut self, gen_software: Option<GlobalVersion>) {
276 if let Some(gen_software) = gen_software {
277 self.gen_software = gen_software;
278 self.flags |= BlockInfo::FLAG_WITH_GEN_SOFTWARE;
279 } else {
280 self.gen_software = Default::default();
281 self.flags &= !BlockInfo::FLAG_WITH_GEN_SOFTWARE;
282 }
283 }
284
285 pub fn load_master_ref(&self) -> Result<Option<BlockRef>, Error> {
287 match &self.master_ref {
288 Some(master_ref) => master_ref.load().map(Some),
289 None => Ok(None),
290 }
291 }
292
293 pub fn load_prev_ref(&self) -> Result<PrevBlockRef, Error> {
295 PrevBlockRef::load_from_cell(&self.prev_ref, self.after_merge)
296 }
297
298 pub fn set_prev_ref(&mut self, prev_ref: &PrevBlockRef) {
300 match prev_ref {
301 PrevBlockRef::Single(prev_ref) => self.set_prev_ref_single(prev_ref),
302 PrevBlockRef::AfterMerge { left, right } => self.set_prev_ref_after_merge(left, right),
303 }
304 }
305
306 pub fn set_prev_ref_single(&mut self, prev_ref: &BlockRef) {
308 self.prev_ref = CellBuilder::build_from(prev_ref).unwrap();
310 }
311
312 pub fn set_prev_ref_after_merge(&mut self, left: &BlockRef, right: &BlockRef) {
314 fn store_split_ref(left: &BlockRef, right: &BlockRef) -> Result<Cell, Error> {
315 let cx = &mut Cell::empty_context();
316 let mut builder = CellBuilder::new();
317 ok!(builder.store_reference(ok!(CellBuilder::build_from_ext(left, cx))));
318 ok!(builder.store_reference(ok!(CellBuilder::build_from_ext(right, cx))));
319 builder.build_ext(cx)
320 }
321
322 self.prev_ref = store_split_ref(left, right).unwrap();
324 }
325}
326
327impl Store for BlockInfo {
328 fn store_into(
329 &self,
330 builder: &mut CellBuilder,
331 context: &mut dyn CellContext,
332 ) -> Result<(), Error> {
333 let packed_flags = ((self.master_ref.is_some() as u8) << 7)
334 | ((self.after_merge as u8) << 6)
335 | ((self.before_split as u8) << 5)
336 | ((self.after_split as u8) << 4)
337 | ((self.want_split as u8) << 3)
338 | ((self.want_merge as u8) << 2)
339 | ((self.key_block as u8) << 1)
340 | (self.prev_vert_ref.is_some() as u8);
341
342 #[cfg(not(any(feature = "venom", feature = "tycho")))]
343 ok!(builder.store_u32(Self::TAG_V1));
344 #[cfg(any(feature = "venom", feature = "tycho"))]
345 ok!(builder.store_u32(Self::TAG_V2));
346
347 ok!(builder.store_u32(self.version));
348 ok!(builder.store_u16(u16::from_be_bytes([packed_flags, self.flags])));
349 ok!(builder.store_u32(self.seqno));
350 ok!(builder.store_u32(self.vert_seqno));
351 ok!(self.shard.store_into(builder, context));
352 ok!(builder.store_u32(self.gen_utime));
353 #[cfg(any(feature = "venom", feature = "tycho"))]
354 ok!(builder.store_u16(self.gen_utime_ms));
355 ok!(builder.store_u64(self.start_lt));
356 ok!(builder.store_u64(self.end_lt));
357 ok!(builder.store_u32(self.gen_validator_list_hash_short));
358 ok!(builder.store_u32(self.gen_catchain_seqno));
359 ok!(builder.store_u32(self.min_ref_mc_seqno));
360 ok!(builder.store_u32(self.prev_key_block_seqno));
361
362 if self.flags & Self::FLAG_WITH_GEN_SOFTWARE != 0 {
363 ok!(self.gen_software.store_into(builder, context));
364 }
365
366 if let Some(master_ref) = &self.master_ref {
367 ok!(builder.store_reference(master_ref.cell.clone()));
368 }
369
370 ok!(builder.store_reference(self.prev_ref.clone()));
371
372 if let Some(prev_vert_ref) = &self.prev_vert_ref {
373 builder.store_reference(prev_vert_ref.cell.clone())
374 } else {
375 Ok(())
376 }
377 }
378}
379
380impl<'a> Load<'a> for BlockInfo {
381 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
382 let with_ms = match slice.load_u32() {
383 Ok(Self::TAG_V1) => false,
384 #[cfg(any(feature = "venom", feature = "tycho"))]
385 Ok(Self::TAG_V2) => true,
386 Ok(_) => return Err(Error::InvalidTag),
387 Err(e) => return Err(e),
388 };
389
390 #[cfg(not(any(feature = "venom", feature = "tycho")))]
391 let _ = with_ms;
392
393 let version = ok!(slice.load_u32());
394 let [packed_flags, flags] = ok!(slice.load_u16()).to_be_bytes();
395 let seqno = ok!(slice.load_u32());
396 if seqno == 0 {
397 return Err(Error::InvalidData);
398 }
399 let vert_seqno = ok!(slice.load_u32());
400 let shard = ok!(ShardIdent::load_from(slice));
401 let gen_utime = ok!(slice.load_u32());
402 #[cfg(any(feature = "venom", feature = "tycho"))]
403 let gen_utime_ms = if with_ms { ok!(slice.load_u16()) } else { 0 };
404 let start_lt = ok!(slice.load_u64());
405 let end_lt = ok!(slice.load_u64());
406 let gen_validator_list_hash_short = ok!(slice.load_u32());
407 let gen_catchain_seqno = ok!(slice.load_u32());
408 let min_ref_mc_seqno = ok!(slice.load_u32());
409 let prev_key_block_seqno = ok!(slice.load_u32());
410
411 let gen_software = if flags & Self::FLAG_WITH_GEN_SOFTWARE != 0 {
412 ok!(GlobalVersion::load_from(slice))
413 } else {
414 GlobalVersion::default()
415 };
416
417 let master_ref = if packed_flags & 0b10000000 != 0 {
418 Some(ok!(Lazy::<BlockRef>::load_from(slice)))
419 } else {
420 None
421 };
422
423 let prev_ref = ok!(slice.load_reference_cloned());
424
425 let prev_vert_ref = if packed_flags & 0b00000001 != 0 {
426 Some(ok!(Lazy::<BlockRef>::load_from(slice)))
427 } else {
428 None
429 };
430
431 if vert_seqno < prev_vert_ref.is_some() as u32 {
432 return Err(Error::InvalidData);
433 }
434
435 Ok(Self {
436 version,
437 after_merge: packed_flags & 0b01000000 != 0,
438 before_split: packed_flags & 0b00100000 != 0,
439 after_split: packed_flags & 0b00010000 != 0,
440 want_split: packed_flags & 0b00001000 != 0,
441 want_merge: packed_flags & 0b00000100 != 0,
442 key_block: packed_flags & 0b00000010 != 0,
443 flags,
444 seqno,
445 vert_seqno,
446 shard,
447 gen_utime,
448 #[cfg(any(feature = "venom", feature = "tycho"))]
449 gen_utime_ms,
450 start_lt,
451 end_lt,
452 gen_validator_list_hash_short,
453 gen_catchain_seqno,
454 min_ref_mc_seqno,
455 prev_key_block_seqno,
456 gen_software,
457 master_ref,
458 prev_ref,
459 prev_vert_ref,
460 })
461 }
462}
463
464#[cfg(feature = "serde")]
465mod serde_prev_block_ref {
466 use super::*;
467
468 pub fn serialize<S: serde::Serializer>(value: &Cell, serializer: S) -> Result<S::Ok, S::Error> {
469 use serde::ser::{Error, Serialize};
470
471 if serializer.is_human_readable() {
472 let prev_block_ref = ok!(PrevBlockRef::load_from_cell(
473 value,
474 value.reference_count() > 0
475 )
476 .map_err(Error::custom));
477 prev_block_ref.serialize(serializer)
478 } else {
479 crate::boc::Boc::serialize(value, serializer)
480 }
481 }
482
483 pub fn deserialize<'de, D>(deserializer: D) -> Result<Cell, D::Error>
484 where
485 D: serde::Deserializer<'de>,
486 {
487 use serde::de::{Deserialize, Error};
488
489 if deserializer.is_human_readable() {
490 PrevBlockRef::deserialize(deserializer).and_then(|prev_block_ref| {
491 CellBuilder::build_from(prev_block_ref).map_err(Error::custom)
492 })
493 } else {
494 crate::boc::Boc::deserialize(deserializer)
495 }
496 }
497}
498
499#[derive(Debug, Clone, Eq, PartialEq)]
501#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
502#[cfg_attr(feature = "serde", serde(tag = "type", content = "id"))]
503pub enum PrevBlockRef {
504 Single(BlockRef),
506 AfterMerge {
508 left: BlockRef,
514 right: BlockRef,
520 },
521}
522
523impl PrevBlockRef {
524 #[cfg(feature = "sync")]
526 pub fn empty_single_ref() -> &'static Cell {
527 static CELL: OnceLock<Cell> = OnceLock::new();
528 CELL.get_or_init(|| {
529 CellBuilder::build_from(&BlockRef {
530 end_lt: 0,
531 seqno: 0,
532 root_hash: HashBytes::ZERO,
533 file_hash: HashBytes::ZERO,
534 })
535 .unwrap()
536 })
537 }
538
539 fn load_from_cell(value: &Cell, after_merge: bool) -> Result<Self, Error> {
540 let mut s = ok!(value.as_slice());
541 Ok(if unlikely(after_merge) {
542 let left = ok!(BlockRef::load_from(&mut ok!(s.load_reference_as_slice())));
543 let right = ok!(BlockRef::load_from(&mut ok!(s.load_reference_as_slice())));
544 PrevBlockRef::AfterMerge { left, right }
545 } else {
546 PrevBlockRef::Single(ok!(BlockRef::load_from(&mut s)))
547 })
548 }
549}
550
551impl Store for PrevBlockRef {
552 fn store_into(&self, builder: &mut CellBuilder, cx: &mut dyn CellContext) -> Result<(), Error> {
553 match self {
554 PrevBlockRef::Single(block_ref) => block_ref.store_into(builder, cx),
555 PrevBlockRef::AfterMerge { left, right } => {
556 ok!(builder.store_reference(ok!(CellBuilder::build_from_ext(left, cx))));
557 builder.store_reference(ok!(CellBuilder::build_from_ext(right, cx)))
558 }
559 }
560 }
561}
562
563#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
565#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
566pub struct BlockRef {
567 pub end_lt: u64,
569 pub seqno: u32,
571 pub root_hash: HashBytes,
573 pub file_hash: HashBytes,
575}
576
577impl BlockRef {
578 pub fn as_block_id(&self, shard: ShardIdent) -> BlockId {
580 BlockId {
581 shard,
582 seqno: self.seqno,
583 root_hash: self.root_hash,
584 file_hash: self.file_hash,
585 }
586 }
587}
588
589#[derive(Debug, Clone, Eq, PartialEq, Default)]
591#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
592pub struct ValueFlow {
593 pub from_prev_block: CurrencyCollection,
595 pub to_next_block: CurrencyCollection,
597 pub imported: CurrencyCollection,
599 pub exported: CurrencyCollection,
601
602 pub fees_collected: CurrencyCollection,
604 pub fees_imported: CurrencyCollection,
606 pub recovered: CurrencyCollection,
608 pub created: CurrencyCollection,
610 pub minted: CurrencyCollection,
612
613 pub copyleft_rewards: Dict<HashBytes, Tokens>,
615}
616
617impl ValueFlow {
618 const TAG_V1: u32 = 0xb8e48dfb;
619 const TAG_V2: u32 = 0xe0864f6d;
620}
621
622impl Store for ValueFlow {
623 fn store_into(
624 &self,
625 builder: &mut CellBuilder,
626 context: &mut dyn CellContext,
627 ) -> Result<(), Error> {
628 let tag = if self.copyleft_rewards.is_empty() {
629 Self::TAG_V1
630 } else {
631 Self::TAG_V2
632 };
633
634 let cell1 = {
635 let mut builder = CellBuilder::new();
636 ok!(self.from_prev_block.store_into(&mut builder, context));
637 ok!(self.to_next_block.store_into(&mut builder, context));
638 ok!(self.imported.store_into(&mut builder, context));
639 ok!(self.exported.store_into(&mut builder, context));
640 ok!(builder.build_ext(context))
641 };
642
643 ok!(builder.store_u32(tag));
644 ok!(builder.store_reference(cell1));
645
646 ok!(self.fees_collected.store_into(builder, context));
647
648 let cell2 = {
649 let mut builder = CellBuilder::new();
650 ok!(self.fees_imported.store_into(&mut builder, context));
651 ok!(self.recovered.store_into(&mut builder, context));
652 ok!(self.created.store_into(&mut builder, context));
653 ok!(self.minted.store_into(&mut builder, context));
654 ok!(builder.build_ext(context))
655 };
656 ok!(builder.store_reference(cell2));
657
658 if !self.copyleft_rewards.is_empty() {
659 self.copyleft_rewards.store_into(builder, context)
660 } else {
661 Ok(())
662 }
663 }
664}
665
666impl<'a> Load<'a> for ValueFlow {
667 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
668 let with_copyleft_rewards = match ok!(slice.load_u32()) {
669 Self::TAG_V1 => false,
670 Self::TAG_V2 => true,
671 _ => return Err(Error::InvalidTag),
672 };
673
674 let fees_collected = ok!(CurrencyCollection::load_from(slice));
675 let slice1 = &mut ok!(slice.load_reference_as_slice());
676 let slice2 = &mut ok!(slice.load_reference_as_slice());
677 let copyleft_rewards = if with_copyleft_rewards {
678 ok!(Dict::load_from(slice))
679 } else {
680 Dict::new()
681 };
682
683 Ok(Self {
684 from_prev_block: ok!(CurrencyCollection::load_from(slice1)),
685 to_next_block: ok!(CurrencyCollection::load_from(slice1)),
686 imported: ok!(CurrencyCollection::load_from(slice1)),
687 exported: ok!(CurrencyCollection::load_from(slice1)),
688 fees_collected,
689 fees_imported: ok!(CurrencyCollection::load_from(slice2)),
690 recovered: ok!(CurrencyCollection::load_from(slice2)),
691 created: ok!(CurrencyCollection::load_from(slice2)),
692 minted: ok!(CurrencyCollection::load_from(slice2)),
693 copyleft_rewards,
694 })
695 }
696}
697
698#[cfg(feature = "tycho")]
700#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
701#[cfg_attr(feature = "serde", derive(serde::Serialize))]
702#[tlb(tag = "#1")]
703pub struct OutMsgQueueUpdates {
704 pub diff_hash: HashBytes,
706}