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 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 #[allow(non_upper_case_globals)]
216 pub const Cuttlefish: Self = Self::CuttlefishPart2;
217}
218
219define_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}