everscale_types/models/block/
mod.rs

1//! Block models.
2
3#[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/// Shard block.
31#[derive(Debug, Clone, Eq, PartialEq)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize))]
33pub struct Block {
34    /// Global network id.
35    pub global_id: i32,
36    /// Block info.
37    pub info: Lazy<BlockInfo>,
38    /// Tokens flow info.
39    pub value_flow: Lazy<ValueFlow>,
40    /// Merkle update for the shard state.
41    pub state_update: Lazy<MerkleUpdate>,
42    /// Merkle updates for the outgoing messages queue.
43    #[cfg(not(feature = "tycho"))]
44    pub out_msg_queue_updates: Option<Dict<u32, Lazy<MerkleUpdate>>>,
45    /// Out messages queue info.
46    #[cfg(feature = "tycho")]
47    pub out_msg_queue_updates: OutMsgQueueUpdates,
48    /// Block content.
49    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    /// Tries to load block info.
61    pub fn load_info(&self) -> Result<BlockInfo, Error> {
62        self.info.load()
63    }
64
65    /// Tries to load tokens flow info.
66    pub fn load_value_flow(&self) -> Result<ValueFlow, Error> {
67        self.value_flow.load()
68    }
69
70    /// Tries to load state update.
71    pub fn load_state_update(&self) -> Result<MerkleUpdate, Error> {
72        self.state_update.load()
73    }
74
75    /// Tries to load block content.
76    pub fn load_extra(&self) -> Result<BlockExtra, Error> {
77        self.extra.load()
78    }
79
80    /// Builds a data for validators to sign.
81    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/// Block info.
178#[derive(Debug, Clone, Eq, PartialEq)]
179#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
180pub struct BlockInfo {
181    /// Block model version.
182    pub version: u32,
183    /// Whether this block was produced after the shards were merged.
184    pub after_merge: bool,
185    /// Whether this block was produced before the shards split.
186    pub before_split: bool,
187    /// Whether this block was produced after the shards split.
188    pub after_split: bool,
189    /// Hint that the shard with this block should split.
190    pub want_split: bool,
191    /// Hint that the shard with this block should merge.
192    pub want_merge: bool,
193    /// Whether this block is a key block.
194    pub key_block: bool,
195
196    /// Block flags (currently only bit 1 is used, for [`gen_software`])
197    ///
198    /// [`gen_software`]: Self::gen_software
199    pub flags: u8,
200    /// Block sequence number.
201    pub seqno: u32,
202    /// Block vertical sequence number.
203    pub vert_seqno: u32,
204
205    /// Shard id where this block was produced.
206    pub shard: ShardIdent,
207    /// Unix timestamp when the block was created.
208    pub gen_utime: u32,
209    /// Milliseconds part of the timestamp when the block was created.
210    #[cfg(any(feature = "venom", feature = "tycho"))]
211    pub gen_utime_ms: u16,
212    /// Logical time range start.
213    pub start_lt: u64,
214    /// Logical time range end.
215    pub end_lt: u64,
216    /// Last 4 bytes of the hash of the validator list.
217    pub gen_validator_list_hash_short: u32,
218    /// Seqno of the catchain session where this block was produced.
219    pub gen_catchain_seqno: u32,
220    /// Minimal referenced seqno of the masterchain block.
221    pub min_ref_mc_seqno: u32,
222    /// Previous key block seqno.
223    pub prev_key_block_seqno: u32,
224    /// The version and capabilities of the software that created this block.
225    pub gen_software: GlobalVersion,
226
227    /// Reference to the masterchain block which was used during the creation of this block.
228    pub master_ref: Option<Lazy<BlockRef>>,
229    /// Reference to the previous block (or blocks).
230    #[cfg_attr(feature = "serde", serde(with = "serde_prev_block_ref"))]
231    pub prev_ref: Cell,
232    /// Optional reference to the previous vertical block.
233    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    /// Set the version and capabilities of the software that created this block.
275    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    /// Tries to load a reference to the masterchain block.
286    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    /// Tries to load a reference to the previous block (or blocks).
294    pub fn load_prev_ref(&self) -> Result<PrevBlockRef, Error> {
295        PrevBlockRef::load_from_cell(&self.prev_ref, self.after_merge)
296    }
297
298    /// Set previous block reference.
299    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    /// Set previous block reference (direct).
307    pub fn set_prev_ref_single(&mut self, prev_ref: &BlockRef) {
308        // NOTE: Unwrap is ok because we control the input.
309        self.prev_ref = CellBuilder::build_from(prev_ref).unwrap();
310    }
311
312    /// Set previous block reference (split).
313    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        // NOTE: Unwrap is ok because we control the input.
323        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/// Reference to the previous block.
500#[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    /// Reference to the parent block (simple case).
505    Single(BlockRef),
506    /// Reference to both parent blocks (case after merge).
507    AfterMerge {
508        /// Block id from the "left" shard.
509        ///
510        /// See [`is_left_child`].
511        ///
512        /// [`is_left_child`]: ShardIdent::is_left_child
513        left: BlockRef,
514        /// Block id from the "right" shard.
515        ///
516        /// See [`is_right_child`].
517        ///
518        /// [`is_right_child`]: ShardIdent::is_right_child
519        right: BlockRef,
520    },
521}
522
523impl PrevBlockRef {
524    /// Returns a static reference to an empty single reference.
525    #[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/// Reference to the external block.
564#[derive(Debug, Clone, Eq, PartialEq, Store, Load)]
565#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
566pub struct BlockRef {
567    /// The end of the logical time of the referenced block.
568    pub end_lt: u64,
569    /// Sequence number of the referenced block.
570    pub seqno: u32,
571    /// Representation hash of the root cell of the referenced block.
572    pub root_hash: HashBytes,
573    /// Hash of the BOC encoded root cell of the referenced block.
574    pub file_hash: HashBytes,
575}
576
577impl BlockRef {
578    /// Converts a `BlockRef` to a `BlockId` given a shard identifier.
579    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/// Tokens flow info.
590#[derive(Debug, Clone, Eq, PartialEq, Default)]
591#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
592pub struct ValueFlow {
593    /// Total amount transferred from the previous block.
594    pub from_prev_block: CurrencyCollection,
595    /// Total amount transferred to the next block.
596    pub to_next_block: CurrencyCollection,
597    /// Sum of all imported amounts from messages.
598    pub imported: CurrencyCollection,
599    /// Sum of all exported amounts of messages.
600    pub exported: CurrencyCollection,
601
602    /// Total fees collected in this block.
603    pub fees_collected: CurrencyCollection,
604    /// Shard fees imported to this block.
605    pub fees_imported: CurrencyCollection,
606    /// Fee recovery (?)
607    pub recovered: CurrencyCollection,
608    /// Block creation fees.
609    pub created: CurrencyCollection,
610    /// Minted extra currencies.
611    pub minted: CurrencyCollection,
612
613    /// Optional copyleft rewards.
614    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/// Outgoing message queue updates.
699#[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    /// Hash of the serialized queue diff.
705    pub diff_hash: HashBytes,
706}