radix_engine/updates/
protocol_updates.rs

1use crate::internal_prelude::*;
2
3define_single_versioned! {
4    #[derive(Debug, Clone, PartialEq, Eq, Sbor)]
5    pub ProtocolUpdateStatusSummarySubstate(ProtocolUpdateStatusSummaryVersions) => ProtocolUpdateStatusSummary = ProtocolUpdateStatusSummaryV1,
6    outer_attributes: [
7        #[derive(ScryptoSborAssertion)]
8        #[sbor_assert(backwards_compatible(
9            cuttlefish = "FILE:protocol_update_status_substate_cuttlefish_schema.bin",
10        ))]
11    ]
12}
13
14impl ProtocolUpdateStatusSummarySubstate {
15    pub fn load(database: &impl SubstateDatabase) -> Self {
16        let substate = database.get_substate(
17            TRANSACTION_TRACKER,
18            PROTOCOL_UPDATE_STATUS_PARTITION,
19            ProtocolUpdateStatusField::Summary,
20        );
21        if let Some(value) = substate {
22            return value;
23        }
24        // We are pre-cuttlefish. Need to distinguish between different versions.
25        let protocol_version = if database
26            .get_raw_substate(
27                TRANSACTION_TRACKER,
28                BOOT_LOADER_PARTITION,
29                BootLoaderField::SystemBoot,
30            )
31            .is_some()
32        {
33            ProtocolVersion::Bottlenose
34        } else if database
35            .get_raw_substate(
36                TRANSACTION_TRACKER,
37                BOOT_LOADER_PARTITION,
38                BootLoaderField::VmBoot,
39            )
40            .is_some()
41        {
42            ProtocolVersion::Anemone
43        } else if database
44            .get_raw_substate(
45                TRANSACTION_TRACKER,
46                TYPE_INFO_FIELD_PARTITION,
47                TypeInfoField::TypeInfo,
48            )
49            .is_some()
50        {
51            ProtocolVersion::Babylon
52        } else {
53            ProtocolVersion::Unbootstrapped
54        };
55
56        ProtocolUpdateStatusSummaryV1 {
57            protocol_version,
58            update_status: ProtocolUpdateStatus::Complete,
59        }
60        .into()
61    }
62}
63
64#[derive(Debug, Clone, PartialEq, Eq, Sbor)]
65pub struct ProtocolUpdateStatusSummaryV1 {
66    pub protocol_version: ProtocolVersion,
67    pub update_status: ProtocolUpdateStatus,
68}
69
70#[derive(Debug, Clone, PartialEq, Eq, Sbor)]
71pub enum ProtocolUpdateStatus {
72    Complete,
73    InProgress {
74        latest_commit: LatestProtocolUpdateCommitBatch,
75    },
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, Sbor)]
79pub struct LatestProtocolUpdateCommitBatch {
80    pub batch_group_index: usize,
81    pub batch_group_name: String,
82    pub batch_index: usize,
83    pub batch_name: String,
84}
85
86macro_rules! count {
87    (
88        $ident: ident, $($other_idents: ident),* $(,)?
89    ) => {
90        1 + count!( $($other_idents),* )
91    };
92    (
93        $ident: ident $(,)?
94    ) => {
95        1
96    }
97}
98
99macro_rules! latest {
100    (
101        $enum_ident: ident, $ident: ident, $($other_idents: ident),* $(,)?
102    ) => {
103        latest!( $enum_ident, $($other_idents),* )
104    };
105    (
106        $enum_ident: ident, $ident: ident $(,)?
107    ) => {
108        $enum_ident :: $ident
109    }
110}
111
112macro_rules! define_enum {
113    (
114        $ident:ident,
115        $(
116            (
117                $variant_name: ident,
118                $logical_name: expr,
119                $display_name: expr
120            )
121        ),* $(,)?
122    ) => {
123        #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Sbor)]
124        pub enum $ident {
125            $($variant_name),*
126        }
127
128        impl $ident {
129            const VARIANTS: [Self; count!( $($variant_name),* )] = [
130                $(
131                    Self::$variant_name
132                ),*
133            ];
134
135            pub const LATEST: $ident = latest!( $ident, $($variant_name),* );
136
137            pub const fn logical_name(&self) -> &'static str {
138                match self {
139                    $(
140                        Self::$variant_name => $logical_name
141                    ),*
142                }
143            }
144
145            pub const fn display_name(&self) -> &'static str {
146                match self {
147                    $(
148                        Self::$variant_name => $display_name
149                    ),*
150                }
151            }
152
153            pub fn try_from_logical_name(logical_name: &str) -> Option<Self> {
154                match logical_name {
155                    $(
156                        $logical_name => Some(Self::$variant_name)
157                    ),*,
158                    _ => None
159                }
160            }
161
162            pub fn try_from_display_name(display_name: &str) -> Option<Self> {
163                match display_name {
164                    $(
165                        $display_name => Some(Self::$variant_name)
166                    ),*,
167                    _ => None
168                }
169            }
170        }
171    };
172}
173
174macro_rules! define_protocol_version_and_updates {
175    (
176        pregenesis: {
177            variant_name: $pregenesis_variant_name: ident,
178            logical_name: $pregenesis_logical_name: expr,
179            display_name: $pregenesis_display_name: expr $(,)?
180        },
181        genesis: {
182            variant_name: $genesis_variant_name: ident,
183            logical_name: $genesis_logical_name: expr,
184            display_name: $genesis_display_name: expr $(,)?
185        },
186        protocol_updates: [
187            $(
188                {
189                    variant_name: $protocol_update_variant_name: ident,
190                    logical_name: $protocol_update_logical_name: expr,
191                    display_name: $protocol_update_display_name: expr $(,)?
192                }
193            ),* $(,)?
194        ]
195    ) => {
196        define_enum!(
197            ProtocolVersion,
198            ($pregenesis_variant_name, $pregenesis_logical_name, $pregenesis_display_name),
199            ($genesis_variant_name, $genesis_logical_name, $genesis_display_name),
200            $(($protocol_update_variant_name, $protocol_update_logical_name, $protocol_update_display_name)),*
201        );
202
203        impl ProtocolVersion {
204            pub const PRE_GENESIS: Self = Self::$pregenesis_variant_name;
205            pub const GENESIS: Self = Self::$genesis_variant_name;
206        }
207    };
208}
209
210impl ProtocolVersion {
211    /// This points to `CuttlefishPart2`, for symmetry with updates which didn't need to be
212    /// in two parts.
213    #[allow(non_upper_case_globals)]
214    pub const Cuttlefish: Self = Self::CuttlefishPart2;
215}
216
217// This macro defines the protocol version and the protocol updates enums and all of the methods
218// needed on them.
219//
220// The order in which the protocol updates is defined is very important since many places in our
221// codebase relies on it such as applying the protocol updates in order. If the order is changed
222// then the protocol updates will be applied in a different order. So, only thing we can do to
223// is append to this list, never change.
224define_protocol_version_and_updates! {
225    pregenesis: {
226        variant_name: Unbootstrapped,
227        logical_name: "unbootstrapped",
228        display_name: "Unbootstrapped",
229    },
230    genesis: {
231        variant_name: Babylon,
232        logical_name: "babylon",
233        display_name: "Babylon",
234    },
235    protocol_updates: [
236        {
237            variant_name: Anemone,
238            logical_name: "anemone",
239            display_name: "Anemone",
240        },
241        {
242            variant_name: Bottlenose,
243            logical_name: "bottlenose",
244            display_name: "Bottlenose",
245        },
246        {
247            variant_name: CuttlefishPart1,
248            logical_name: "cuttlefish",
249            display_name: "Cuttlefish (Part 1)",
250        },
251        {
252            variant_name: CuttlefishPart2,
253            logical_name: "cuttlefish-part2",
254            display_name: "Cuttlefish (Part 2)",
255        }
256    ]
257}
258
259impl ProtocolVersion {
260    pub fn all_from(
261        from_version_inclusive: ProtocolVersion,
262    ) -> impl Iterator<Item = ProtocolVersion> {
263        Self::VARIANTS
264            .into_iter()
265            .skip_while(move |v| *v < from_version_inclusive)
266    }
267
268    pub fn all_between_inclusive(
269        from_version_inclusive: ProtocolVersion,
270        to_version_inclusive: ProtocolVersion,
271    ) -> impl Iterator<Item = ProtocolVersion> {
272        Self::VARIANTS
273            .into_iter()
274            .skip_while(move |v| *v < from_version_inclusive)
275            .take_while(move |v| *v <= to_version_inclusive)
276    }
277
278    pub fn all_between(
279        from_version_inclusive: ProtocolVersion,
280        to_version_exclusive: ProtocolVersion,
281    ) -> impl Iterator<Item = ProtocolVersion> {
282        Self::VARIANTS
283            .into_iter()
284            .skip_while(move |v| *v < from_version_inclusive)
285            .take_while(move |v| *v < to_version_exclusive)
286    }
287
288    pub fn next(&self) -> Option<Self> {
289        Self::VARIANTS
290            .iter()
291            .skip_while(|v| v <= &self)
292            .next()
293            .cloned()
294    }
295}
296
297#[cfg(test)]
298mod tests {
299    use super::*;
300
301    #[test]
302    fn assert_latest_protocol_version_is_as_expected() {
303        assert_eq!(ProtocolVersion::LATEST, ProtocolVersion::CuttlefishPart2);
304    }
305
306    #[test]
307    fn test_next() {
308        assert_eq!(
309            ProtocolVersion::PRE_GENESIS.next(),
310            Some(ProtocolVersion::GENESIS)
311        );
312        assert_eq!(
313            ProtocolVersion::GENESIS.next(),
314            Some(ProtocolVersion::Anemone)
315        );
316        assert_eq!(
317            ProtocolVersion::Anemone.next(),
318            Some(ProtocolVersion::Bottlenose)
319        );
320        assert_eq!(ProtocolVersion::LATEST.next(), None);
321    }
322
323    #[test]
324    fn assert_protocol_versions_have_the_expected_order() {
325        let variants =
326            ProtocolVersion::all_from(ProtocolVersion::Unbootstrapped).collect::<Vec<_>>();
327
328        assert_eq!(
329            variants,
330            vec![
331                ProtocolVersion::Unbootstrapped,
332                ProtocolVersion::Babylon,
333                ProtocolVersion::Anemone,
334                ProtocolVersion::Bottlenose,
335                ProtocolVersion::CuttlefishPart1,
336                ProtocolVersion::CuttlefishPart2,
337            ],
338        );
339        assert!(variants.windows(2).all(|item| item[0] < item[1]))
340    }
341
342    #[test]
343    fn assert_protocol_version_range_queries_work() {
344        assert_eq!(
345            ProtocolVersion::all_between(ProtocolVersion::Babylon, ProtocolVersion::Bottlenose,)
346                .collect::<Vec<_>>(),
347            vec![ProtocolVersion::Babylon, ProtocolVersion::Anemone,],
348        );
349        assert_eq!(
350            ProtocolVersion::all_between_inclusive(
351                ProtocolVersion::Babylon,
352                ProtocolVersion::Bottlenose,
353            )
354            .collect::<Vec<_>>(),
355            vec![
356                ProtocolVersion::Babylon,
357                ProtocolVersion::Anemone,
358                ProtocolVersion::Bottlenose,
359            ],
360        );
361    }
362}