tycho_types/models/
global_version.rs

1//! Global version and capabilities.
2
3use crate::cell::{Load, Store};
4use crate::error::ParseGlobalCapabilityError;
5
6macro_rules! decl_global_capability {
7    ($(#[doc = $doc:expr])* $vis:vis enum $ident:ident {$(
8        $(#[doc = $var_doc:expr])*
9        $field:ident = $descr:literal
10    ),*$(,)?}) => {
11        $(#[doc = $doc])*
12        #[derive(Debug, Copy, Clone, Eq, PartialEq)]
13        #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14        #[repr(u64)]
15        $vis enum $ident {$(
16            $(#[doc = $var_doc])*
17            $field = 1u64 << $descr
18        ),*,}
19
20        impl GlobalCapability {
21            const fn from_bit_offset(bit_offset: u32) -> Option<Self> {
22                Some(match bit_offset {
23                    $($descr => Self::$field),*,
24                    _ => return None,
25                })
26            }
27        }
28
29        impl std::fmt::Display for GlobalCapability {
30            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31                f.write_str(match self {
32                    $(Self::$field => stringify!($field),)*
33                })
34            }
35        }
36
37        impl std::str::FromStr for GlobalCapability {
38            type Err = ParseGlobalCapabilityError;
39
40            fn from_str(s: &str) -> Result<Self, Self::Err> {
41                Ok(match s {
42                    $(stringify!($field) => Self::$field,)*
43                    _ => return Err(ParseGlobalCapabilityError::UnknownCapability),
44                })
45            }
46        }
47    };
48}
49
50decl_global_capability! {
51    /// Node software capabilities.
52    pub enum GlobalCapability {
53        /// Instant Hypercube Routing.
54        ///
55        /// Mask: `0x0000001`.
56        CapIhrEnabled = 0,
57
58        /// Tracking of block collation stats.
59        ///
60        /// Mask: `0x0000002`.
61        CapCreateStatsEnabled = 1,
62
63        /// Body (at most 256 bits) in bounced messages.
64        ///
65        /// Mask: `0x0000004`.
66        CapBounceMsgBody = 2,
67
68        /// Supported software version and capabilities as field in [`BlockInfo`].
69        ///
70        /// Mask: `0x0000008`.
71        ///
72        /// [`BlockInfo`]: crate::models::block::BlockInfo
73        CapReportVersion = 3,
74
75        /// Special transactions on split or merge.
76        ///
77        /// Mask: `0x0000010`.
78        CapSplitMergeTransactions = 4,
79
80        /// Short output messages queue.
81        ///
82        /// Mask: `0x0000020`.
83        CapShortDequeue = 5,
84
85        /// _unknown_ (possibly just a stub).
86        ///
87        /// Mask: `0x0000040`.
88        CapMbppEnabled = 6,
89
90        /// Precompute storage stats for cells and use this info for storage phase.
91        /// NOTE: changes behavior for storage phase, computing stats for non-unique cells.
92        ///
93        /// Mask: `0x0000080`
94        CapFastStorageStat = 7,
95
96        /// Store init code hash in account state.
97        ///
98        /// Mask: `0x0000100`.
99        CapInitCodeHash = 8,
100
101        /// Disable hypercube for message routing.
102        ///
103        /// Mask: `0x0000200`.
104        CapOffHypercube = 9,
105
106        /// `MYCODE` TVM opcode.
107        ///
108        /// Mask: `0x0000400`.
109        CapMyCode = 10,
110
111        /// `CHANGELIB` and `SETLIBCODE` TVM opcodes.
112        ///
113        /// Mask: `0x0000800`.
114        CapSetLibCode = 11,
115
116        /// Fix in `SETINDEX*` TVM opcodes.
117        ///
118        /// Mask: `0x0001000`.
119        CapFixTupleIndexBug = 12,
120
121        /// Reliable External Messaging Protocol.
122        ///
123        /// Mask: `0x0002000`.
124        CapRemp = 13,
125
126        /// Support for decentralized elections.
127        ///
128        /// Mask: `0x0004000`.
129        CapDelections = 14,
130
131        // Capability 15 is reserved (?)
132        /// Full message body in bounced messages (in the first child cell).
133        ///
134        /// Mask: `0x0010000`.
135        CapFullBodyInBounced = 16,
136
137        /// `STORAGEFEE` TVM opcode.
138        ///
139        /// Mask: `0x0020000`.
140        CapStorageFeeToTvm = 17,
141
142        /// Support for copyleft messages.
143        ///
144        /// Mask: `0x0040000`.
145        CapCopyleft = 18,
146
147        /// `FIND_BY_*` TVM opcodes.
148        ///
149        /// Mask: `0x0080000`.
150        CapIndexAccounts = 19,
151
152        /// `DIFF*`, `ZIP`, `UNZIP` TVM opcodes.
153        ///
154        /// Mask: `0x0100000`.
155        CapDiff = 20,
156
157        /// Cumulative patches to TVM and cells (popsave, exception handler, loops).
158        ///
159        /// Mask: `0x0200000`.
160        CapsTvmBugfixes2022 = 21,
161
162        /// Support for message queues between workchains.
163        ///
164        /// Mask: `0x0400000`.
165        CapWorkchains = 22,
166
167        /// New continuation serialization format.
168        ///
169        /// Mask: `0x0800000`.
170        CapStcontNewFormat = 23,
171
172        /// Use fast stats for `*DATASIZE*` TVM opcodes.
173        ///
174        /// Mask: `0x1000000`.
175        CapFastStorageStatBugfix = 24,
176
177        /// Add support for transparent loading of merkle cells.
178        ///
179        /// Mask: `0x2000000`.
180        CapResolveMerkleCell = 25,
181
182        /// Prepend signature with `global_id` for TVM.
183        ///
184        /// Mask: `0x4000000`.
185        CapSignatureWithId = 26,
186
187        /// Execute bounce phase even after failed action phase.
188        ///
189        /// Mask: `0x8000000`.
190        CapBounceAfterFailedAction = 27,
191
192        /// Groth16 support in TVM.
193        ///
194        /// Mask: `0x10000000`
195        CapGroth16 = 28,
196
197        /// Makes all fees in config in gas units.
198        ///
199        /// Mask: `0x20000000`
200        CapFeeInGasUnits = 29,
201
202        /// Big cells support.
203        ///
204        /// Mask: `0x40000000`
205        CapBigCells = 30,
206
207        /// Suspend addresses using a config param.
208        ///
209        /// Mask: `0x80000000`
210        CapSuspendedList = 31,
211
212        /// Adds intershard communication between master blocks.
213        ///
214        /// Mask: `0x100000000`
215        CapFastFinality = 32,
216
217        /// Allows to suspend accounts by special extra currencies.
218        ///
219        /// Mask: `0x200000000`
220        CapSuspendByMarks = 33,
221
222        /// Omits master block history to save storage space.
223        ///
224        /// Mask: `0x400000000`
225        CapOmitMasterBlockHistory = 34,
226
227        /// Apply signature domain to verified data.
228        ///
229        /// It is a newer version of [`GlobalCapability::CapSignatureWithId`]
230        /// and has a higher priority if both are enabled at the same time.
231        ///
232        /// Mask: `0x800000000`
233        CapSignatureDomain = 35,
234    }
235}
236
237impl std::ops::BitOr<GlobalCapability> for GlobalCapability {
238    type Output = GlobalCapabilities;
239
240    #[inline]
241    fn bitor(self, rhs: GlobalCapability) -> Self::Output {
242        GlobalCapabilities(self as u64 | rhs as u64)
243    }
244}
245
246impl std::ops::BitOr<GlobalCapability> for u64 {
247    type Output = GlobalCapabilities;
248
249    #[inline]
250    fn bitor(self, rhs: GlobalCapability) -> Self::Output {
251        GlobalCapabilities(self | rhs as u64)
252    }
253}
254
255impl std::ops::BitOrAssign<GlobalCapability> for u64 {
256    #[inline]
257    fn bitor_assign(&mut self, rhs: GlobalCapability) {
258        *self = (*self | rhs).0;
259    }
260}
261
262impl std::ops::BitOr<u64> for GlobalCapability {
263    type Output = GlobalCapabilities;
264
265    #[inline]
266    fn bitor(self, rhs: u64) -> Self::Output {
267        GlobalCapabilities(self as u64 | rhs)
268    }
269}
270
271impl std::ops::BitOr<GlobalCapability> for GlobalCapabilities {
272    type Output = GlobalCapabilities;
273
274    #[inline]
275    fn bitor(self, rhs: GlobalCapability) -> Self::Output {
276        GlobalCapabilities(self.0 | rhs as u64)
277    }
278}
279
280impl std::ops::BitOr<GlobalCapabilities> for GlobalCapability {
281    type Output = GlobalCapabilities;
282
283    #[inline]
284    fn bitor(self, rhs: GlobalCapabilities) -> Self::Output {
285        GlobalCapabilities(self as u64 | rhs.0)
286    }
287}
288
289impl std::ops::BitOrAssign<u64> for GlobalCapabilities {
290    #[inline]
291    fn bitor_assign(&mut self, rhs: u64) {
292        *self = GlobalCapabilities(self.0 | rhs);
293    }
294}
295
296impl std::ops::BitOrAssign<GlobalCapability> for GlobalCapabilities {
297    #[inline]
298    fn bitor_assign(&mut self, rhs: GlobalCapability) {
299        *self = *self | rhs;
300    }
301}
302
303/// Software info.
304#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Store, Load)]
305#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
306#[tlb(tag = "#c4")]
307pub struct GlobalVersion {
308    /// Software version.
309    pub version: u32,
310    /// Software capability flags.
311    pub capabilities: GlobalCapabilities,
312}
313
314/// A set of enabled capabilities.
315///
316/// See [`GlobalCapability`].
317#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Store, Load)]
318#[repr(transparent)]
319pub struct GlobalCapabilities(u64);
320
321impl GlobalCapabilities {
322    /// Creates a new capabilities set from the inner value.
323    #[inline]
324    pub const fn new(inner: u64) -> Self {
325        Self(inner)
326    }
327
328    /// Returns `true` if the set contains no enabled capabilities.
329    #[inline]
330    pub const fn is_empty(&self) -> bool {
331        self.0 == 0
332    }
333
334    /// Returns the number of enabled capabilities.
335    pub const fn len(&self) -> usize {
336        self.0.count_ones() as usize
337    }
338
339    /// Returns `true` if the specified capability is enabled.
340    #[inline]
341    pub const fn contains(&self, capability: GlobalCapability) -> bool {
342        (self.0 & (capability as u64)) != 0
343    }
344
345    /// Converts this wrapper into an underlying type.
346    #[inline]
347    pub const fn into_inner(self) -> u64 {
348        self.0
349    }
350
351    /// Gets an iterator over the enabled capabilities.
352    #[inline]
353    pub fn iter(&self) -> GlobalCapabilitiesIter {
354        GlobalCapabilitiesIter(self.0)
355    }
356}
357
358impl From<u64> for GlobalCapabilities {
359    #[inline]
360    fn from(value: u64) -> Self {
361        Self(value)
362    }
363}
364
365impl From<GlobalCapabilities> for u64 {
366    #[inline]
367    fn from(value: GlobalCapabilities) -> Self {
368        value.0
369    }
370}
371
372impl PartialEq<u64> for GlobalCapabilities {
373    #[inline]
374    fn eq(&self, other: &u64) -> bool {
375        self.0 == *other
376    }
377}
378
379impl IntoIterator for GlobalCapabilities {
380    type Item = GlobalCapability;
381    type IntoIter = GlobalCapabilitiesIter;
382
383    #[inline]
384    fn into_iter(self) -> Self::IntoIter {
385        GlobalCapabilitiesIter(self.0)
386    }
387}
388
389impl FromIterator<GlobalCapability> for GlobalCapabilities {
390    fn from_iter<T: IntoIterator<Item = GlobalCapability>>(iter: T) -> Self {
391        let mut res = GlobalCapabilities::default();
392        for item in iter {
393            res |= item;
394        }
395        res
396    }
397}
398
399impl<const N: usize> From<[GlobalCapability; N]> for GlobalCapabilities {
400    fn from(value: [GlobalCapability; N]) -> Self {
401        let mut res = GlobalCapabilities::default();
402        for item in value.iter() {
403            res |= *item;
404        }
405        res
406    }
407}
408
409#[cfg(feature = "serde")]
410impl serde::Serialize for GlobalCapabilities {
411    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
412    where
413        S: serde::Serializer,
414    {
415        use serde::ser::SerializeSeq;
416
417        if serializer.is_human_readable() {
418            let mut seq = serializer.serialize_seq(Some(self.len()))?;
419            for capability in self.iter() {
420                seq.serialize_element(&capability)?;
421            }
422            seq.end()
423        } else {
424            serializer.serialize_u64(self.0)
425        }
426    }
427}
428
429#[cfg(feature = "serde")]
430impl<'de> serde::Deserialize<'de> for GlobalCapabilities {
431    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
432    where
433        D: serde::Deserializer<'de>,
434    {
435        use serde::de::Visitor;
436
437        struct GlobalCapabilitiesVisitor;
438
439        impl<'de> Visitor<'de> for GlobalCapabilitiesVisitor {
440            type Value = GlobalCapabilities;
441
442            fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
443                f.write_str("a list of global capabilities")
444            }
445
446            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
447            where
448                A: serde::de::SeqAccess<'de>,
449            {
450                let mut res = GlobalCapabilities::default();
451                while let Some(capacility) = ok!(seq.next_element::<GlobalCapability>()) {
452                    res |= capacility;
453                }
454                Ok(res)
455            }
456        }
457
458        if deserializer.is_human_readable() {
459            deserializer.deserialize_seq(GlobalCapabilitiesVisitor)
460        } else {
461            u64::deserialize(deserializer).map(Self)
462        }
463    }
464}
465
466/// An iterator over the enabled capabilities of [`GlobalCapabilities`].
467///
468/// This struct is created by the [`iter`] method on [`GlobalCapabilities`].
469/// See its documentation for more.
470///
471/// [`iter`]: GlobalCapabilities::iter
472#[derive(Clone)]
473pub struct GlobalCapabilitiesIter(u64);
474
475impl Iterator for GlobalCapabilitiesIter {
476    type Item = GlobalCapability;
477
478    fn next(&mut self) -> Option<Self::Item> {
479        while self.0 != 0 {
480            //  10100 - 1     = 10011
481            // !10011         = 01100
482            //  10100 & 01100 = 00100
483            let mask = self.0 & !(self.0 - 1);
484
485            // 10100 & !00100 -> 10000
486            self.0 &= !mask;
487
488            if let Some(item) = GlobalCapability::from_bit_offset(mask.trailing_zeros()) {
489                return Some(item);
490            }
491        }
492
493        None
494    }
495
496    fn size_hint(&self) -> (usize, Option<usize>) {
497        let len = self.0.count_ones() as usize;
498        (len, Some(len))
499    }
500}
501
502#[cfg(test)]
503mod tests {
504    use super::*;
505
506    #[test]
507    fn capabilities_iter() {
508        let capabilities = GlobalCapability::CapCreateStatsEnabled
509            | GlobalCapability::CapBounceMsgBody
510            | GlobalCapability::CapReportVersion
511            | GlobalCapability::CapShortDequeue
512            | GlobalCapability::CapFastStorageStat
513            | GlobalCapability::CapOffHypercube
514            | GlobalCapability::CapMyCode
515            | GlobalCapability::CapFixTupleIndexBug;
516
517        let capabilities = capabilities.into_iter().collect::<Vec<_>>();
518        assert_eq!(capabilities, [
519            GlobalCapability::CapCreateStatsEnabled,
520            GlobalCapability::CapBounceMsgBody,
521            GlobalCapability::CapReportVersion,
522            GlobalCapability::CapShortDequeue,
523            GlobalCapability::CapFastStorageStat,
524            GlobalCapability::CapOffHypercube,
525            GlobalCapability::CapMyCode,
526            GlobalCapability::CapFixTupleIndexBug
527        ]);
528    }
529}