1use crate::{FromBytes, ToBytes, io_error};
17
18use enum_iterator::{Sequence, last};
19use snarkvm_algorithms::snark::varuna::VarunaVersion;
20use std::io;
21
22#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, Sequence)]
25#[repr(u16)]
26pub enum ConsensusVersion {
27 V1 = 1,
29 V2 = 2,
31 V3 = 3,
33 V4 = 4,
35 V5 = 5,
37 V6 = 6,
39 V7 = 7,
41 V8 = 8,
43 V9 = 9,
45 V10 = 10,
47 V11 = 11,
49 V12 = 12,
51 V13 = 13,
53 V14 = 14,
58 V15 = 15,
61 V16 = 16,
66 V17 = 17,
69 V18 = 18,
72 V19 = 19,
76 V20 = 20,
79 V21 = 21,
81 V22 = 22,
85}
86
87impl ToBytes for ConsensusVersion {
88 fn write_le<W: io::Write>(&self, writer: W) -> io::Result<()> {
89 (*self as u16).write_le(writer)
90 }
91}
92
93impl FromBytes for ConsensusVersion {
94 fn read_le<R: io::Read>(reader: R) -> io::Result<Self> {
95 match u16::read_le(reader)? {
96 0 => Err(io_error("Zero is not a valid consensus version")),
97 1 => Ok(Self::V1),
98 2 => Ok(Self::V2),
99 3 => Ok(Self::V3),
100 4 => Ok(Self::V4),
101 5 => Ok(Self::V5),
102 6 => Ok(Self::V6),
103 7 => Ok(Self::V7),
104 8 => Ok(Self::V8),
105 9 => Ok(Self::V9),
106 10 => Ok(Self::V10),
107 11 => Ok(Self::V11),
108 12 => Ok(Self::V12),
109 13 => Ok(Self::V13),
110 14 => Ok(Self::V14),
111 15 => Ok(Self::V15),
112 16 => Ok(Self::V16),
113 17 => Ok(Self::V17),
114 18 => Ok(Self::V18),
115 19 => Ok(Self::V19),
116 20 => Ok(Self::V20),
117 21 => Ok(Self::V21),
118 22 => Ok(Self::V22),
119 _ => Err(io_error("Invalid consensus version")),
120 }
121 }
122}
123
124impl ConsensusVersion {
125 pub fn latest() -> Self {
126 last::<ConsensusVersion>().expect("At least one ConsensusVersion should be defined.")
127 }
128}
129
130impl std::fmt::Display for ConsensusVersion {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 write!(f, "{self:?}")
134 }
135}
136
137pub(crate) const NUM_CONSENSUS_VERSIONS: usize = enum_iterator::cardinality::<ConsensusVersion>();
139
140pub const CANARY_V0_CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] = [
142 (ConsensusVersion::V1, 0),
143 (ConsensusVersion::V2, 2_900_000),
144 (ConsensusVersion::V3, 4_560_000),
145 (ConsensusVersion::V4, 5_730_000),
146 (ConsensusVersion::V5, 5_780_000),
147 (ConsensusVersion::V6, 6_240_000),
148 (ConsensusVersion::V7, 6_880_000),
149 (ConsensusVersion::V8, 7_565_000),
150 (ConsensusVersion::V9, 8_028_000),
151 (ConsensusVersion::V10, 8_600_000),
152 (ConsensusVersion::V11, 9_510_000),
153 (ConsensusVersion::V12, 10_030_000),
154 (ConsensusVersion::V13, 10_881_000),
155 (ConsensusVersion::V14, 11_960_000),
156 (ConsensusVersion::V15, u32::MAX),
157 (ConsensusVersion::V16, u32::MAX),
158 (ConsensusVersion::V17, u32::MAX),
159 (ConsensusVersion::V18, u32::MAX),
160 (ConsensusVersion::V19, u32::MAX),
161 (ConsensusVersion::V20, u32::MAX),
162 (ConsensusVersion::V21, u32::MAX),
163 (ConsensusVersion::V22, u32::MAX),
164];
165
166pub const MAINNET_V0_CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] = [
168 (ConsensusVersion::V1, 0),
169 (ConsensusVersion::V2, 2_800_000),
170 (ConsensusVersion::V3, 4_900_000),
171 (ConsensusVersion::V4, 6_135_000),
172 (ConsensusVersion::V5, 7_060_000),
173 (ConsensusVersion::V6, 7_560_000),
174 (ConsensusVersion::V7, 7_570_000),
175 (ConsensusVersion::V8, 9_430_000),
176 (ConsensusVersion::V9, 10_272_000),
177 (ConsensusVersion::V10, 11_205_000),
178 (ConsensusVersion::V11, 12_870_000),
179 (ConsensusVersion::V12, 13_815_000),
180 (ConsensusVersion::V13, 16_850_000),
181 (ConsensusVersion::V14, 17_700_000),
182 (ConsensusVersion::V15, 19_264_000),
183 (ConsensusVersion::V16, 19_860_000),
184 (ConsensusVersion::V17, 19_860_001),
185 (ConsensusVersion::V18, 20_794_000),
186 (ConsensusVersion::V19, 21_342_000),
187 (ConsensusVersion::V20, 22_175_000),
188 (ConsensusVersion::V21, 22_437_000),
190 (ConsensusVersion::V22, 22_962_000),
192];
193
194pub const TESTNET_V0_CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] = [
196 (ConsensusVersion::V1, 0),
197 (ConsensusVersion::V2, 2_950_000),
198 (ConsensusVersion::V3, 4_800_000),
199 (ConsensusVersion::V4, 6_625_000),
200 (ConsensusVersion::V5, 6_765_000),
201 (ConsensusVersion::V6, 7_600_000),
202 (ConsensusVersion::V7, 8_365_000),
203 (ConsensusVersion::V8, 9_173_000),
204 (ConsensusVersion::V9, 9_800_000),
205 (ConsensusVersion::V10, 10_525_000),
206 (ConsensusVersion::V11, 11_952_000),
207 (ConsensusVersion::V12, 12_669_000),
208 (ConsensusVersion::V13, 14_906_000),
209 (ConsensusVersion::V14, 15_370_000),
210 (ConsensusVersion::V15, 16_886_000),
211 (ConsensusVersion::V16, 17_319_000),
212 (ConsensusVersion::V17, 18_295_000),
213 (ConsensusVersion::V18, 18_296_000),
214 (ConsensusVersion::V19, 18_813_000),
215 (ConsensusVersion::V20, 19_374_000),
216 (ConsensusVersion::V21, 20_234_000),
217 (ConsensusVersion::V22, 20_415_000),
219];
220
221pub const TEST_CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] = [
226 (ConsensusVersion::V1, 0),
227 (ConsensusVersion::V2, 5),
228 (ConsensusVersion::V3, 6),
229 (ConsensusVersion::V4, 7),
230 (ConsensusVersion::V5, 8),
231 (ConsensusVersion::V6, 9),
232 (ConsensusVersion::V7, 10),
233 (ConsensusVersion::V8, 11),
234 (ConsensusVersion::V9, 12),
235 (ConsensusVersion::V10, 13),
236 (ConsensusVersion::V11, 14),
237 (ConsensusVersion::V12, 15),
238 (ConsensusVersion::V13, 16),
239 (ConsensusVersion::V14, 17),
240 (ConsensusVersion::V15, 18),
241 (ConsensusVersion::V16, 19),
242 (ConsensusVersion::V17, 20),
243 (ConsensusVersion::V18, 21),
244 (ConsensusVersion::V19, 22),
245 (ConsensusVersion::V20, 23),
246 (ConsensusVersion::V21, 24),
247 (ConsensusVersion::V22, 25),
248];
249
250#[cfg(any(test, feature = "test", feature = "test_consensus_heights", feature = "wasm"))]
255pub(crate) fn verify_consensus_heights(heights: &[(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS]) {
256 assert_eq!(heights[0].1, 0, "Genesis height must be 0.");
257 for window in heights.windows(2) {
258 let ((previous_version, previous_height), (version, height)) = (window[0], window[1]);
259 if previous_height == u32::MAX {
260 assert!(
261 height == u32::MAX,
262 "{previous_version:?} is unscheduled, so all later versions must be unscheduled, but {version:?} is at height {height}."
263 );
264 } else {
265 assert!(
266 height > previous_height,
267 "Scheduled heights must strictly increase, but {previous_version:?} is at height {previous_height} and {version:?} is at height {height}."
268 );
269 }
270 }
271}
272
273#[cfg(any(test, feature = "test", feature = "test_consensus_heights"))]
274pub fn load_test_consensus_heights() -> [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] {
275 load_test_consensus_heights_inner(std::env::var("CONSENSUS_VERSION_HEIGHTS").ok())
277}
278
279#[cfg(any(test, feature = "test", feature = "test_consensus_heights", feature = "wasm"))]
280pub(crate) fn load_test_consensus_heights_inner(
281 consensus_version_heights: Option<String>,
282) -> [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] {
283 let mut test_consensus_heights = TEST_CONSENSUS_VERSION_HEIGHTS;
285
286 match consensus_version_heights {
288 Some(height_string) => {
289 let parsing_error = format!("Expected exactly {NUM_CONSENSUS_VERSIONS} ConsensusVersion heights.");
290 let parsed_test_consensus_heights: [u32; NUM_CONSENSUS_VERSIONS] = height_string
292 .replace(" ", "")
293 .split(",")
294 .map(|height| height.parse::<u32>().expect("Heights should be valid u32 values."))
295 .collect::<Vec<u32>>()
296 .try_into()
297 .expect(&parsing_error);
298 for (i, height) in parsed_test_consensus_heights.into_iter().enumerate() {
300 test_consensus_heights[i] = (TEST_CONSENSUS_VERSION_HEIGHTS[i].0, height);
301 }
302 verify_consensus_heights(&test_consensus_heights);
304 test_consensus_heights
305 }
306 None => {
307 verify_consensus_heights(&test_consensus_heights);
309 test_consensus_heights
310 }
311 }
312}
313
314#[macro_export]
321macro_rules! consensus_config_value {
322 ($network:ident, $constant:ident, $seek_height:expr) => {
323 $network::CONSENSUS_VERSION($seek_height).map_or(None, |seek_version| {
325 match $network::$constant.binary_search_by(|(version, _)| version.cmp(&seek_version)) {
328 Ok(index) => Some($network::$constant[index].1),
330 Err(index) => {
332 if index == 0 {
334 None
335 } else {
337 Some($network::$constant[index - 1].1)
338 }
339 }
340 }
341 })
342 };
343}
344
345#[macro_export]
352macro_rules! consensus_config_value_by_version {
353 ($network:ident, $constant:ident, $seek_version:expr) => {
354 match $network::$constant.binary_search_by(|(version, _)| version.cmp(&$seek_version)) {
356 Ok(index) => Some($network::$constant[index].1),
358 Err(index) => {
360 if index == 0 {
362 None
363 } else {
365 Some($network::$constant[index - 1].1)
366 }
367 }
368 }
369 };
370}
371
372pub fn varuna_version_from_consensus(consensus_version: ConsensusVersion) -> VarunaVersion {
374 if consensus_version >= ConsensusVersion::V21 {
376 VarunaVersion::V3
377 } else if consensus_version >= ConsensusVersion::V4 {
378 VarunaVersion::V2
379 } else {
380 VarunaVersion::V1
381 }
382}
383
384#[cfg(test)]
385mod tests {
386 use super::*;
387 use crate::{CanaryV0, MainnetV0, Network, TestnetV0};
388
389 fn consensus_constants_at_genesis<N: Network>() {
392 let height = N::_CONSENSUS_VERSION_HEIGHTS.first().unwrap().1;
393 assert_eq!(height, 0);
394 let consensus_version = N::_CONSENSUS_VERSION_HEIGHTS.first().unwrap().0;
395 assert_eq!(consensus_version, ConsensusVersion::V1);
396 assert_eq!(consensus_version as usize, 1);
397 }
398
399 fn consensus_versions<N: Network>() {
401 let mut previous_version = N::_CONSENSUS_VERSION_HEIGHTS.first().unwrap().0;
402 assert_eq!(previous_version as usize, 1);
404 for (version, _) in N::_CONSENSUS_VERSION_HEIGHTS.iter().skip(1) {
406 assert_eq!(*version as usize, previous_version as usize + 1);
407 previous_version = *version;
408 }
409 let mut previous_version = N::MAX_CERTIFICATES.first().unwrap().0;
411 for (version, _) in N::MAX_CERTIFICATES.iter().skip(1) {
412 assert!(*version > previous_version);
413 previous_version = *version;
414 }
415 let mut previous_version = N::TRANSACTION_SPEND_LIMIT.first().unwrap().0;
416 for (version, _) in N::TRANSACTION_SPEND_LIMIT.iter().skip(1) {
417 assert!(*version > previous_version);
418 previous_version = *version;
419 }
420 let mut previous_version = N::CREDITS_PER_SECOND_OF_RUNTIME.first().unwrap().0;
421 for (version, _) in N::CREDITS_PER_SECOND_OF_RUNTIME.iter().skip(1) {
422 assert!(*version > previous_version);
423 previous_version = *version;
424 }
425 let mut previous_version = N::MAX_ARRAY_ELEMENTS.first().unwrap().0;
426 for (version, _) in N::MAX_ARRAY_ELEMENTS.iter().skip(1) {
427 assert!(*version > previous_version);
428 previous_version = *version;
429 }
430 let mut previous_version = N::MAX_MAPPINGS.first().unwrap().0;
431 for (version, _) in N::MAX_MAPPINGS.iter().skip(1) {
432 assert!(*version > previous_version);
433 previous_version = *version;
434 }
435 let mut previous_version = N::MAX_PROGRAM_SIZE.first().unwrap().0;
436 for (version, _) in N::MAX_PROGRAM_SIZE.iter().skip(1) {
437 assert!(*version > previous_version);
438 previous_version = *version;
439 }
440 let mut previous_version = N::MAX_TRANSACTION_SIZE.first().unwrap().0;
441 for (version, _) in N::MAX_TRANSACTION_SIZE.iter().skip(1) {
442 assert!(*version > previous_version);
443 previous_version = *version;
444 }
445 let mut previous_version = N::MAX_WRITES.first().unwrap().0;
446 for (version, _) in N::MAX_WRITES.iter().skip(1) {
447 assert!(*version > previous_version);
448 previous_version = *version;
449 }
450 let mut previous_version = N::ANCHOR_TIMES.first().unwrap().0;
451 for (version, _) in N::ANCHOR_TIMES.iter().skip(1) {
452 assert!(*version > previous_version);
453 previous_version = *version;
454 }
455 }
456
457 fn consensus_constants_increasing_heights<N: Network>() {
459 let mut previous_height = N::CONSENSUS_VERSION_HEIGHTS().first().unwrap().1;
460 for (version, height) in N::CONSENSUS_VERSION_HEIGHTS().iter().skip(1) {
461 assert!(*height > previous_height);
462 previous_height = *height;
463 assert_eq!(N::CONSENSUS_VERSION(*height).unwrap(), *version);
465 assert_eq!(N::CONSENSUS_HEIGHT(*version).unwrap(), *height);
467 }
468 }
469
470 fn consensus_constants_valid_heights<N: Network>() {
472 for (version, value) in N::MAX_CERTIFICATES.iter() {
473 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
475 assert_eq!(consensus_config_value!(N, MAX_CERTIFICATES, height).unwrap(), *value);
477 }
478 for (version, value) in N::TRANSACTION_SPEND_LIMIT.iter() {
479 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
481 assert_eq!(consensus_config_value!(N, TRANSACTION_SPEND_LIMIT, height).unwrap(), *value);
483 }
484 for (version, value) in N::CREDITS_PER_SECOND_OF_RUNTIME.iter() {
485 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
487 assert_eq!(consensus_config_value!(N, CREDITS_PER_SECOND_OF_RUNTIME, height).unwrap(), *value);
489 }
490 for (version, value) in N::MAX_ARRAY_ELEMENTS.iter() {
491 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
493 assert_eq!(consensus_config_value!(N, MAX_ARRAY_ELEMENTS, height).unwrap(), *value);
495 }
496 for (version, value) in N::MAX_MAPPINGS.iter() {
497 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
499 assert_eq!(consensus_config_value!(N, MAX_MAPPINGS, height).unwrap(), *value);
501 }
502 for (version, value) in N::MAX_PROGRAM_SIZE.iter() {
503 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
505 assert_eq!(consensus_config_value!(N, MAX_PROGRAM_SIZE, height).unwrap(), *value);
507 }
508 for (version, value) in N::MAX_TRANSACTION_SIZE.iter() {
509 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
511 assert_eq!(consensus_config_value!(N, MAX_TRANSACTION_SIZE, height).unwrap(), *value);
513 }
514 for (version, value) in N::MAX_WRITES.iter() {
515 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
517 assert_eq!(consensus_config_value!(N, MAX_WRITES, height).unwrap(), *value);
519 }
520 for (version, value) in N::ANCHOR_TIMES.iter() {
521 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| c_version == version).unwrap().1;
522 assert_eq!(consensus_config_value!(N, ANCHOR_TIMES, height).unwrap(), *value);
523 }
524 }
525
526 fn consensus_config_returns_some<N: Network>() {
528 for (_, height) in N::CONSENSUS_VERSION_HEIGHTS().iter() {
529 assert!(consensus_config_value!(N, MAX_CERTIFICATES, *height).is_some());
530 assert!(consensus_config_value!(N, TRANSACTION_SPEND_LIMIT, *height).is_some());
531 assert!(consensus_config_value!(N, CREDITS_PER_SECOND_OF_RUNTIME, *height).is_some());
532 assert!(consensus_config_value!(N, MAX_ARRAY_ELEMENTS, *height).is_some());
533 assert!(consensus_config_value!(N, MAX_MAPPINGS, *height).is_some());
534 assert!(consensus_config_value!(N, MAX_PROGRAM_SIZE, *height).is_some());
535 assert!(consensus_config_value!(N, MAX_TRANSACTION_SIZE, *height).is_some());
536 assert!(consensus_config_value!(N, MAX_WRITES, *height).is_some());
537 assert!(consensus_config_value!(N, ANCHOR_TIMES, *height).is_some());
538 }
539 }
540
541 fn max_certificates_increasing<N: Network>(exempt_versions: &[ConsensusVersion]) {
545 let mut previous_value = N::MAX_CERTIFICATES.first().unwrap().1;
546 for (version, value) in N::MAX_CERTIFICATES.iter().skip(1) {
547 if !exempt_versions.contains(version) {
548 assert!(*value >= previous_value, "MAX_CERTIFICATES must not decrease at {version:?}");
549 }
550 previous_value = *value;
551 }
552 }
553
554 fn max_array_elements_increasing<N: Network>() {
557 let mut previous_value = N::MAX_ARRAY_ELEMENTS.first().unwrap().1;
558 for (_, value) in N::MAX_ARRAY_ELEMENTS.iter().skip(1) {
559 assert!(*value >= previous_value);
560 previous_value = *value;
561 }
562 }
563
564 fn max_mappings_increasing<N: Network>() {
566 let mut previous_value = N::MAX_MAPPINGS.first().unwrap().1;
567 for (_, value) in N::MAX_MAPPINGS.iter().skip(1) {
568 assert!(*value >= previous_value);
569 previous_value = *value;
570 }
571 }
572
573 fn transaction_size_exceeds_program_size<N: Network>() {
576 const MIN_OVERHEAD: usize = 28_000; for (_, height) in N::CONSENSUS_VERSION_HEIGHTS().iter() {
579 let max_program_size = consensus_config_value!(N, MAX_PROGRAM_SIZE, *height).unwrap();
580 let max_transaction_size = consensus_config_value!(N, MAX_TRANSACTION_SIZE, *height).unwrap();
581
582 assert!(
583 max_transaction_size >= max_program_size + MIN_OVERHEAD,
584 "At height {height}: MAX_TRANSACTION_SIZE ({max_transaction_size}) must be at least {MIN_OVERHEAD} bytes greater than MAX_PROGRAM_SIZE ({max_program_size})"
585 );
586 }
587 }
588
589 fn program_and_transaction_size_aligned<N: Network>() {
595 assert_eq!(
597 N::MAX_PROGRAM_SIZE.len(),
598 N::MAX_TRANSACTION_SIZE.len(),
599 "MAX_PROGRAM_SIZE and MAX_TRANSACTION_SIZE must define the same number of entries"
600 );
601 for (index, (program_version, program_size)) in N::MAX_PROGRAM_SIZE.iter().enumerate() {
604 let (transaction_version, transaction_size) = &N::MAX_TRANSACTION_SIZE[index];
605 assert_eq!(
606 program_version, transaction_version,
607 "MAX_PROGRAM_SIZE and MAX_TRANSACTION_SIZE must be keyed by the same consensus version at index {index}, but found {program_version} and {transaction_version}"
608 );
609 assert!(
610 transaction_size > program_size,
611 "At consensus version {program_version}: MAX_TRANSACTION_SIZE ({transaction_size}) must be greater than MAX_PROGRAM_SIZE ({program_size})"
612 );
613 }
614 assert!(
616 N::LATEST_MAX_TRANSACTION_SIZE() > N::LATEST_MAX_PROGRAM_SIZE(),
617 "LATEST_MAX_TRANSACTION_SIZE ({}) must be greater than LATEST_MAX_PROGRAM_SIZE ({})",
618 N::LATEST_MAX_TRANSACTION_SIZE(),
619 N::LATEST_MAX_PROGRAM_SIZE()
620 );
621 }
622
623 fn constants_equal_length<N1: Network, N2: Network, N3: Network>() {
625 let _ = [N1::CONSENSUS_VERSION_HEIGHTS, N2::CONSENSUS_VERSION_HEIGHTS, N3::CONSENSUS_VERSION_HEIGHTS];
627 let _ = [N1::MAX_CERTIFICATES, N2::MAX_CERTIFICATES, N3::MAX_CERTIFICATES];
628 let _ = [N1::TRANSACTION_SPEND_LIMIT, N2::TRANSACTION_SPEND_LIMIT, N3::TRANSACTION_SPEND_LIMIT];
629 let _ =
630 [N1::CREDITS_PER_SECOND_OF_RUNTIME, N2::CREDITS_PER_SECOND_OF_RUNTIME, N3::CREDITS_PER_SECOND_OF_RUNTIME];
631 let _ = [N1::MAX_ARRAY_ELEMENTS, N2::MAX_ARRAY_ELEMENTS, N3::MAX_ARRAY_ELEMENTS];
632 let _ = [N1::MAX_MAPPINGS, N2::MAX_MAPPINGS, N3::MAX_MAPPINGS];
633 let _ = [N1::MAX_PROGRAM_SIZE, N2::MAX_PROGRAM_SIZE, N3::MAX_PROGRAM_SIZE];
634 let _ = [N1::MAX_TRANSACTION_SIZE, N2::MAX_TRANSACTION_SIZE, N3::MAX_TRANSACTION_SIZE];
635 let _ = [N1::MAX_WRITES, N2::MAX_WRITES, N3::MAX_WRITES];
636 let _ = [N1::ANCHOR_TIMES, N2::ANCHOR_TIMES, N3::ANCHOR_TIMES];
637 }
638
639 fn latest_max_functions_are_safe<N: Network>() {
642 assert!(N::LATEST_MAX_CERTIFICATES() > 0, "LATEST_MAX_CERTIFICATES must be positive");
644 assert!(N::LATEST_MAX_MAPPINGS() > 0, "LATEST_MAX_MAPPINGS must be positive");
646 assert!(N::LATEST_MAX_PROGRAM_SIZE() > 0, "LATEST_MAX_PROGRAM_SIZE must be positive");
648 assert!(N::LATEST_MAX_TRANSACTION_SIZE() > 0, "LATEST_MAX_TRANSACTION_SIZE must be positive");
650 assert!(N::LATEST_MAX_WRITES() > 0, "LATEST_MAX_WRITES must be positive");
652 }
653
654 #[test]
655 #[allow(clippy::assertions_on_constants)]
656 fn test_consensus_constants() {
657 consensus_constants_at_genesis::<MainnetV0>();
658 consensus_constants_at_genesis::<TestnetV0>();
659 consensus_constants_at_genesis::<CanaryV0>();
660
661 consensus_versions::<MainnetV0>();
662 consensus_versions::<TestnetV0>();
663 consensus_versions::<CanaryV0>();
664
665 consensus_constants_increasing_heights::<MainnetV0>();
666 consensus_constants_increasing_heights::<TestnetV0>();
667 consensus_constants_increasing_heights::<CanaryV0>();
668
669 consensus_constants_valid_heights::<MainnetV0>();
670 consensus_constants_valid_heights::<TestnetV0>();
671 consensus_constants_valid_heights::<CanaryV0>();
672
673 consensus_config_returns_some::<MainnetV0>();
674 consensus_config_returns_some::<TestnetV0>();
675 consensus_config_returns_some::<CanaryV0>();
676
677 max_certificates_increasing::<MainnetV0>(&[]);
678 max_certificates_increasing::<TestnetV0>(&[ConsensusVersion::V22]);
680 max_certificates_increasing::<CanaryV0>(&[]);
681
682 max_array_elements_increasing::<MainnetV0>();
683 max_array_elements_increasing::<TestnetV0>();
684 max_array_elements_increasing::<CanaryV0>();
685
686 max_mappings_increasing::<MainnetV0>();
687 max_mappings_increasing::<TestnetV0>();
688 max_mappings_increasing::<CanaryV0>();
689
690 transaction_size_exceeds_program_size::<MainnetV0>();
691 transaction_size_exceeds_program_size::<TestnetV0>();
692 transaction_size_exceeds_program_size::<CanaryV0>();
693
694 program_and_transaction_size_aligned::<MainnetV0>();
695 program_and_transaction_size_aligned::<TestnetV0>();
696 program_and_transaction_size_aligned::<CanaryV0>();
697
698 latest_max_functions_are_safe::<MainnetV0>();
699 latest_max_functions_are_safe::<TestnetV0>();
700 latest_max_functions_are_safe::<CanaryV0>();
701
702 constants_equal_length::<MainnetV0, TestnetV0, CanaryV0>();
703 }
704
705 #[test]
707 fn test_to_bytes() {
708 let version = ConsensusVersion::V8;
709 let bytes = version.to_bytes_le().unwrap();
710 let result = ConsensusVersion::from_bytes_le(&bytes).unwrap();
711 assert_eq!(result, version);
712
713 let version = ConsensusVersion::latest();
714 let bytes = version.to_bytes_le().unwrap();
715 let result = ConsensusVersion::from_bytes_le(&bytes).unwrap();
716 assert_eq!(result, version);
717
718 let invalid_bytes = u16::MAX.to_bytes_le().unwrap();
719 let result = ConsensusVersion::from_bytes_le(&invalid_bytes);
720 assert!(result.is_err());
721 }
722
723 #[test]
724 fn test_reward_anchor_time() {
725 assert_eq!(MainnetV0::REWARD_ANCHOR_TIME, MainnetV0::ANCHOR_TIMES.first().unwrap().1);
726 assert_eq!(TestnetV0::REWARD_ANCHOR_TIME, TestnetV0::ANCHOR_TIMES.first().unwrap().1);
727 assert_eq!(CanaryV0::REWARD_ANCHOR_TIME, CanaryV0::ANCHOR_TIMES.first().unwrap().1);
728 }
729
730 #[test]
731 fn test_varuna_version_from_consensus() {
732 for consensus_version in enum_iterator::all::<ConsensusVersion>() {
734 let varuna_version = varuna_version_from_consensus(consensus_version);
735 let valid = match varuna_version {
736 VarunaVersion::V1 => consensus_version < ConsensusVersion::V4,
737 VarunaVersion::V2 => (ConsensusVersion::V4..ConsensusVersion::V21).contains(&consensus_version),
738 VarunaVersion::V3 => consensus_version >= ConsensusVersion::V21,
739 };
740 assert!(valid, "{consensus_version:?} incorrectly maps to {varuna_version:?}");
741 }
742
743 assert_eq!(varuna_version_from_consensus(ConsensusVersion::V3), VarunaVersion::V1);
745 assert_eq!(varuna_version_from_consensus(ConsensusVersion::V4), VarunaVersion::V2);
746 assert_eq!(varuna_version_from_consensus(ConsensusVersion::V20), VarunaVersion::V2);
747 assert_eq!(varuna_version_from_consensus(ConsensusVersion::V21), VarunaVersion::V3);
748 assert_eq!(varuna_version_from_consensus(ConsensusVersion::V22), VarunaVersion::V3);
749 }
750
751 #[test]
753 fn test_published_consensus_heights_are_valid() {
754 verify_consensus_heights(&CANARY_V0_CONSENSUS_VERSION_HEIGHTS);
755 verify_consensus_heights(&MAINNET_V0_CONSENSUS_VERSION_HEIGHTS);
756 verify_consensus_heights(&TESTNET_V0_CONSENSUS_VERSION_HEIGHTS);
757 verify_consensus_heights(&TEST_CONSENSUS_VERSION_HEIGHTS);
758 }
759
760 fn test_heights_string(overrides: &[(usize, u32)]) -> String {
762 let mut heights = TEST_CONSENSUS_VERSION_HEIGHTS.map(|(_, height)| height);
763 for (index, height) in overrides {
764 heights[*index] = *height;
765 }
766 heights.iter().map(u32::to_string).collect::<Vec<_>>().join(",")
767 }
768
769 #[test]
771 #[should_panic(expected = "must strictly increase")]
772 fn test_consensus_heights_reject_decreasing() {
773 load_test_consensus_heights_inner(Some(test_heights_string(&[(2, 4)])));
774 }
775
776 #[test]
778 #[should_panic(expected = "must strictly increase")]
779 fn test_consensus_heights_reject_duplicate() {
780 load_test_consensus_heights_inner(Some(test_heights_string(&[(2, 5)])));
781 }
782
783 #[test]
785 #[should_panic(expected = "all later versions must be unscheduled")]
786 fn test_consensus_heights_reject_scheduled_after_unscheduled() {
787 load_test_consensus_heights_inner(Some(test_heights_string(&[(18, u32::MAX)])));
788 }
789
790 #[test]
792 fn test_consensus_heights_accept_trailing_unscheduled() {
793 let heights = load_test_consensus_heights_inner(Some(test_heights_string(&[
794 (18, u32::MAX),
795 (19, u32::MAX),
796 (20, u32::MAX),
797 (21, u32::MAX),
798 ])));
799 assert_eq!(heights[17].1, 21);
800 assert_eq!(heights[18].1, u32::MAX);
801 assert_eq!(heights[19].1, u32::MAX);
802 assert_eq!(heights[20].1, u32::MAX);
803 assert_eq!(heights[21].1, u32::MAX);
804 }
805}