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