Skip to main content

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