1use crate::{FromBytes, ToBytes, io_error};
17
18use enum_iterator::{Sequence, last};
19use std::io;
20
21#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Sequence)]
24#[repr(u16)]
25pub enum ConsensusVersion {
26 V1 = 1,
28 V2 = 2,
30 V3 = 3,
32 V4 = 4,
34 V5 = 5,
36 V6 = 6,
38 V7 = 7,
40 V8 = 8,
42 V9 = 9,
44 V10 = 10,
46 V11 = 11,
48 V12 = 12,
50 V13 = 13,
52 V14 = 14,
57 V15 = 15,
60 V16 = 16,
65 V17 = 17,
68}
69
70impl ToBytes for ConsensusVersion {
71 fn write_le<W: io::Write>(&self, writer: W) -> io::Result<()> {
72 (*self as u16).write_le(writer)
73 }
74}
75
76impl FromBytes for ConsensusVersion {
77 fn read_le<R: io::Read>(reader: R) -> io::Result<Self> {
78 match u16::read_le(reader)? {
79 0 => Err(io_error("Zero is not a valid consensus version")),
80 1 => Ok(Self::V1),
81 2 => Ok(Self::V2),
82 3 => Ok(Self::V3),
83 4 => Ok(Self::V4),
84 5 => Ok(Self::V5),
85 6 => Ok(Self::V6),
86 7 => Ok(Self::V7),
87 8 => Ok(Self::V8),
88 9 => Ok(Self::V9),
89 10 => Ok(Self::V10),
90 11 => Ok(Self::V11),
91 12 => Ok(Self::V12),
92 13 => Ok(Self::V13),
93 14 => Ok(Self::V14),
94 15 => Ok(Self::V15),
95 16 => Ok(Self::V16),
96 17 => Ok(Self::V17),
97 _ => Err(io_error("Invalid consensus version")),
98 }
99 }
100}
101
102impl ConsensusVersion {
103 pub fn latest() -> Self {
104 last::<ConsensusVersion>().expect("At least one ConsensusVersion should be defined.")
105 }
106}
107
108impl std::fmt::Display for ConsensusVersion {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 write!(f, "{self:?}")
112 }
113}
114
115pub(crate) const NUM_CONSENSUS_VERSIONS: usize = enum_iterator::cardinality::<ConsensusVersion>();
117
118pub const CANARY_V0_CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] = [
120 (ConsensusVersion::V1, 0),
121 (ConsensusVersion::V2, 2_900_000),
122 (ConsensusVersion::V3, 4_560_000),
123 (ConsensusVersion::V4, 5_730_000),
124 (ConsensusVersion::V5, 5_780_000),
125 (ConsensusVersion::V6, 6_240_000),
126 (ConsensusVersion::V7, 6_880_000),
127 (ConsensusVersion::V8, 7_565_000),
128 (ConsensusVersion::V9, 8_028_000),
129 (ConsensusVersion::V10, 8_600_000),
130 (ConsensusVersion::V11, 9_510_000),
131 (ConsensusVersion::V12, 10_030_000),
132 (ConsensusVersion::V13, 10_881_000),
133 (ConsensusVersion::V14, 11_960_000),
134 (ConsensusVersion::V15, u32::MAX),
135 (ConsensusVersion::V16, u32::MAX),
136 (ConsensusVersion::V17, u32::MAX),
137];
138
139pub const MAINNET_V0_CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] = [
141 (ConsensusVersion::V1, 0),
142 (ConsensusVersion::V2, 2_800_000),
143 (ConsensusVersion::V3, 4_900_000),
144 (ConsensusVersion::V4, 6_135_000),
145 (ConsensusVersion::V5, 7_060_000),
146 (ConsensusVersion::V6, 7_560_000),
147 (ConsensusVersion::V7, 7_570_000),
148 (ConsensusVersion::V8, 9_430_000),
149 (ConsensusVersion::V9, 10_272_000),
150 (ConsensusVersion::V10, 11_205_000),
151 (ConsensusVersion::V11, 12_870_000),
152 (ConsensusVersion::V12, 13_815_000),
153 (ConsensusVersion::V13, 16_850_000),
154 (ConsensusVersion::V14, 17_700_000),
155 (ConsensusVersion::V15, 19_264_000),
156 (ConsensusVersion::V16, 19_860_000),
157 (ConsensusVersion::V17, 19_860_001),
158];
159
160pub const TESTNET_V0_CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] = [
162 (ConsensusVersion::V1, 0),
163 (ConsensusVersion::V2, 2_950_000),
164 (ConsensusVersion::V3, 4_800_000),
165 (ConsensusVersion::V4, 6_625_000),
166 (ConsensusVersion::V5, 6_765_000),
167 (ConsensusVersion::V6, 7_600_000),
168 (ConsensusVersion::V7, 8_365_000),
169 (ConsensusVersion::V8, 9_173_000),
170 (ConsensusVersion::V9, 9_800_000),
171 (ConsensusVersion::V10, 10_525_000),
172 (ConsensusVersion::V11, 11_952_000),
173 (ConsensusVersion::V12, 12_669_000),
174 (ConsensusVersion::V13, 14_906_000),
175 (ConsensusVersion::V14, 15_370_000),
176 (ConsensusVersion::V15, 16_886_000),
177 (ConsensusVersion::V16, 17_319_000),
178 (ConsensusVersion::V17, u32::MAX),
179];
180
181pub const TEST_CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] = [
183 (ConsensusVersion::V1, 0),
184 (ConsensusVersion::V2, 5),
185 (ConsensusVersion::V3, 6),
186 (ConsensusVersion::V4, 7),
187 (ConsensusVersion::V5, 8),
188 (ConsensusVersion::V6, 9),
189 (ConsensusVersion::V7, 10),
190 (ConsensusVersion::V8, 11),
191 (ConsensusVersion::V9, 12),
192 (ConsensusVersion::V10, 13),
193 (ConsensusVersion::V11, 14),
194 (ConsensusVersion::V12, 15),
195 (ConsensusVersion::V13, 16),
196 (ConsensusVersion::V14, 17),
197 (ConsensusVersion::V15, 18),
198 (ConsensusVersion::V16, 19),
199 (ConsensusVersion::V17, 20),
200];
201
202#[cfg(any(test, feature = "test", feature = "test_consensus_heights"))]
203pub fn load_test_consensus_heights() -> [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] {
204 load_test_consensus_heights_inner(std::env::var("CONSENSUS_VERSION_HEIGHTS").ok())
206}
207
208#[cfg(any(test, feature = "test", feature = "test_consensus_heights", feature = "wasm"))]
209pub(crate) fn load_test_consensus_heights_inner(
210 consensus_version_heights: Option<String>,
211) -> [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] {
212 let verify_consensus_heights = |heights: &[(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS]| {
214 assert_eq!(heights[0].1, 0, "Genesis height must be 0.");
216 for window in heights.windows(2) {
218 if window[0] >= window[1] {
219 panic!("Heights must be strictly increasing, but found: {window:?}");
220 }
221 }
222 };
223
224 let mut test_consensus_heights = TEST_CONSENSUS_VERSION_HEIGHTS;
226
227 match consensus_version_heights {
229 Some(height_string) => {
230 let parsing_error = format!("Expected exactly {NUM_CONSENSUS_VERSIONS} ConsensusVersion heights.");
231 let parsed_test_consensus_heights: [u32; NUM_CONSENSUS_VERSIONS] = height_string
233 .replace(" ", "")
234 .split(",")
235 .map(|height| height.parse::<u32>().expect("Heights should be valid u32 values."))
236 .collect::<Vec<u32>>()
237 .try_into()
238 .expect(&parsing_error);
239 for (i, height) in parsed_test_consensus_heights.into_iter().enumerate() {
241 test_consensus_heights[i] = (TEST_CONSENSUS_VERSION_HEIGHTS[i].0, height);
242 }
243 verify_consensus_heights(&test_consensus_heights);
245 test_consensus_heights
246 }
247 None => {
248 verify_consensus_heights(&test_consensus_heights);
250 test_consensus_heights
251 }
252 }
253}
254
255#[macro_export]
262macro_rules! consensus_config_value {
263 ($network:ident, $constant:ident, $seek_height:expr) => {
264 $network::CONSENSUS_VERSION($seek_height).map_or(None, |seek_version| {
266 match $network::$constant.binary_search_by(|(version, _)| version.cmp(&seek_version)) {
269 Ok(index) => Some($network::$constant[index].1),
271 Err(index) => {
273 if index == 0 {
275 None
276 } else {
278 Some($network::$constant[index - 1].1)
279 }
280 }
281 }
282 })
283 };
284}
285
286#[macro_export]
293macro_rules! consensus_config_value_by_version {
294 ($network:ident, $constant:ident, $seek_version:expr) => {
295 match $network::$constant.binary_search_by(|(version, _)| version.cmp(&$seek_version)) {
297 Ok(index) => Some($network::$constant[index].1),
299 Err(index) => {
301 if index == 0 {
303 None
304 } else {
306 Some($network::$constant[index - 1].1)
307 }
308 }
309 }
310 };
311}
312
313#[cfg(test)]
314mod tests {
315 use super::*;
316 use crate::{CanaryV0, MainnetV0, Network, TestnetV0};
317
318 fn consensus_constants_at_genesis<N: Network>() {
321 let height = N::_CONSENSUS_VERSION_HEIGHTS.first().unwrap().1;
322 assert_eq!(height, 0);
323 let consensus_version = N::_CONSENSUS_VERSION_HEIGHTS.first().unwrap().0;
324 assert_eq!(consensus_version, ConsensusVersion::V1);
325 assert_eq!(consensus_version as usize, 1);
326 }
327
328 fn consensus_versions<N: Network>() {
330 let mut previous_version = N::_CONSENSUS_VERSION_HEIGHTS.first().unwrap().0;
331 assert_eq!(previous_version as usize, 1);
333 for (version, _) in N::_CONSENSUS_VERSION_HEIGHTS.iter().skip(1) {
335 assert_eq!(*version as usize, previous_version as usize + 1);
336 previous_version = *version;
337 }
338 let mut previous_version = N::MAX_CERTIFICATES.first().unwrap().0;
340 for (version, _) in N::MAX_CERTIFICATES.iter().skip(1) {
341 assert!(*version > previous_version);
342 previous_version = *version;
343 }
344 let mut previous_version = N::TRANSACTION_SPEND_LIMIT.first().unwrap().0;
345 for (version, _) in N::TRANSACTION_SPEND_LIMIT.iter().skip(1) {
346 assert!(*version > previous_version);
347 previous_version = *version;
348 }
349 let mut previous_version = N::CREDITS_PER_SECOND_OF_RUNTIME.first().unwrap().0;
350 for (version, _) in N::CREDITS_PER_SECOND_OF_RUNTIME.iter().skip(1) {
351 assert!(*version > previous_version);
352 previous_version = *version;
353 }
354 let mut previous_version = N::MAX_ARRAY_ELEMENTS.first().unwrap().0;
355 for (version, _) in N::MAX_ARRAY_ELEMENTS.iter().skip(1) {
356 assert!(*version > previous_version);
357 previous_version = *version;
358 }
359 let mut previous_version = N::MAX_PROGRAM_SIZE.first().unwrap().0;
360 for (version, _) in N::MAX_PROGRAM_SIZE.iter().skip(1) {
361 assert!(*version > previous_version);
362 previous_version = *version;
363 }
364 let mut previous_version = N::MAX_TRANSACTION_SIZE.first().unwrap().0;
365 for (version, _) in N::MAX_TRANSACTION_SIZE.iter().skip(1) {
366 assert!(*version > previous_version);
367 previous_version = *version;
368 }
369 let mut previous_version = N::MAX_WRITES.first().unwrap().0;
370 for (version, _) in N::MAX_WRITES.iter().skip(1) {
371 assert!(*version > previous_version);
372 previous_version = *version;
373 }
374 let mut previous_version = N::ANCHOR_TIMES.first().unwrap().0;
375 for (version, _) in N::ANCHOR_TIMES.iter().skip(1) {
376 assert!(*version > previous_version);
377 previous_version = *version;
378 }
379 }
380
381 fn consensus_constants_increasing_heights<N: Network>() {
383 let mut previous_height = N::CONSENSUS_VERSION_HEIGHTS().first().unwrap().1;
384 for (version, height) in N::CONSENSUS_VERSION_HEIGHTS().iter().skip(1) {
385 assert!(*height > previous_height);
386 previous_height = *height;
387 assert_eq!(N::CONSENSUS_VERSION(*height).unwrap(), *version);
389 assert_eq!(N::CONSENSUS_HEIGHT(*version).unwrap(), *height);
391 }
392 }
393
394 fn consensus_constants_valid_heights<N: Network>() {
396 for (version, value) in N::MAX_CERTIFICATES.iter() {
397 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
399 assert_eq!(consensus_config_value!(N, MAX_CERTIFICATES, height).unwrap(), *value);
401 }
402 for (version, value) in N::TRANSACTION_SPEND_LIMIT.iter() {
403 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
405 assert_eq!(consensus_config_value!(N, TRANSACTION_SPEND_LIMIT, height).unwrap(), *value);
407 }
408 for (version, value) in N::CREDITS_PER_SECOND_OF_RUNTIME.iter() {
409 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
411 assert_eq!(consensus_config_value!(N, CREDITS_PER_SECOND_OF_RUNTIME, height).unwrap(), *value);
413 }
414 for (version, value) in N::MAX_ARRAY_ELEMENTS.iter() {
415 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
417 assert_eq!(consensus_config_value!(N, MAX_ARRAY_ELEMENTS, height).unwrap(), *value);
419 }
420 for (version, value) in N::MAX_PROGRAM_SIZE.iter() {
421 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
423 assert_eq!(consensus_config_value!(N, MAX_PROGRAM_SIZE, height).unwrap(), *value);
425 }
426 for (version, value) in N::MAX_TRANSACTION_SIZE.iter() {
427 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
429 assert_eq!(consensus_config_value!(N, MAX_TRANSACTION_SIZE, height).unwrap(), *value);
431 }
432 for (version, value) in N::MAX_WRITES.iter() {
433 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
435 assert_eq!(consensus_config_value!(N, MAX_WRITES, height).unwrap(), *value);
437 }
438 for (version, value) in N::ANCHOR_TIMES.iter() {
439 let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| c_version == version).unwrap().1;
440 assert_eq!(consensus_config_value!(N, ANCHOR_TIMES, height).unwrap(), *value);
441 }
442 }
443
444 fn consensus_config_returns_some<N: Network>() {
446 for (_, height) in N::CONSENSUS_VERSION_HEIGHTS().iter() {
447 assert!(consensus_config_value!(N, MAX_CERTIFICATES, *height).is_some());
448 assert!(consensus_config_value!(N, TRANSACTION_SPEND_LIMIT, *height).is_some());
449 assert!(consensus_config_value!(N, CREDITS_PER_SECOND_OF_RUNTIME, *height).is_some());
450 assert!(consensus_config_value!(N, MAX_ARRAY_ELEMENTS, *height).is_some());
451 assert!(consensus_config_value!(N, MAX_PROGRAM_SIZE, *height).is_some());
452 assert!(consensus_config_value!(N, MAX_TRANSACTION_SIZE, *height).is_some());
453 assert!(consensus_config_value!(N, MAX_WRITES, *height).is_some());
454 assert!(consensus_config_value!(N, ANCHOR_TIMES, *height).is_some());
455 }
456 }
457
458 fn max_certificates_increasing<N: Network>() {
461 let mut previous_value = N::MAX_CERTIFICATES.first().unwrap().1;
462 for (_, value) in N::MAX_CERTIFICATES.iter().skip(1) {
463 assert!(*value >= previous_value);
464 previous_value = *value;
465 }
466 }
467
468 fn max_array_elements_increasing<N: Network>() {
471 let mut previous_value = N::MAX_ARRAY_ELEMENTS.first().unwrap().1;
472 for (_, value) in N::MAX_ARRAY_ELEMENTS.iter().skip(1) {
473 assert!(*value >= previous_value);
474 previous_value = *value;
475 }
476 }
477
478 fn transaction_size_exceeds_program_size<N: Network>() {
481 const MIN_OVERHEAD: usize = 28_000; for (_, height) in N::CONSENSUS_VERSION_HEIGHTS().iter() {
484 let max_program_size = consensus_config_value!(N, MAX_PROGRAM_SIZE, *height).unwrap();
485 let max_transaction_size = consensus_config_value!(N, MAX_TRANSACTION_SIZE, *height).unwrap();
486
487 assert!(
488 max_transaction_size >= max_program_size + MIN_OVERHEAD,
489 "At height {height}: MAX_TRANSACTION_SIZE ({max_transaction_size}) must be at least {MIN_OVERHEAD} bytes greater than MAX_PROGRAM_SIZE ({max_program_size})"
490 );
491 }
492 }
493
494 fn program_and_transaction_size_aligned<N: Network>() {
500 assert_eq!(
502 N::MAX_PROGRAM_SIZE.len(),
503 N::MAX_TRANSACTION_SIZE.len(),
504 "MAX_PROGRAM_SIZE and MAX_TRANSACTION_SIZE must define the same number of entries"
505 );
506 for (index, (program_version, program_size)) in N::MAX_PROGRAM_SIZE.iter().enumerate() {
509 let (transaction_version, transaction_size) = &N::MAX_TRANSACTION_SIZE[index];
510 assert_eq!(
511 program_version, transaction_version,
512 "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}"
513 );
514 assert!(
515 transaction_size > program_size,
516 "At consensus version {program_version}: MAX_TRANSACTION_SIZE ({transaction_size}) must be greater than MAX_PROGRAM_SIZE ({program_size})"
517 );
518 }
519 assert!(
521 N::LATEST_MAX_TRANSACTION_SIZE() > N::LATEST_MAX_PROGRAM_SIZE(),
522 "LATEST_MAX_TRANSACTION_SIZE ({}) must be greater than LATEST_MAX_PROGRAM_SIZE ({})",
523 N::LATEST_MAX_TRANSACTION_SIZE(),
524 N::LATEST_MAX_PROGRAM_SIZE()
525 );
526 }
527
528 fn constants_equal_length<N1: Network, N2: Network, N3: Network>() {
530 let _ = [N1::CONSENSUS_VERSION_HEIGHTS, N2::CONSENSUS_VERSION_HEIGHTS, N3::CONSENSUS_VERSION_HEIGHTS];
532 let _ = [N1::MAX_CERTIFICATES, N2::MAX_CERTIFICATES, N3::MAX_CERTIFICATES];
533 let _ = [N1::TRANSACTION_SPEND_LIMIT, N2::TRANSACTION_SPEND_LIMIT, N3::TRANSACTION_SPEND_LIMIT];
534 let _ =
535 [N1::CREDITS_PER_SECOND_OF_RUNTIME, N2::CREDITS_PER_SECOND_OF_RUNTIME, N3::CREDITS_PER_SECOND_OF_RUNTIME];
536 let _ = [N1::MAX_ARRAY_ELEMENTS, N2::MAX_ARRAY_ELEMENTS, N3::MAX_ARRAY_ELEMENTS];
537 let _ = [N1::MAX_PROGRAM_SIZE, N2::MAX_PROGRAM_SIZE, N3::MAX_PROGRAM_SIZE];
538 let _ = [N1::MAX_TRANSACTION_SIZE, N2::MAX_TRANSACTION_SIZE, N3::MAX_TRANSACTION_SIZE];
539 let _ = [N1::MAX_WRITES, N2::MAX_WRITES, N3::MAX_WRITES];
540 let _ = [N1::ANCHOR_TIMES, N2::ANCHOR_TIMES, N3::ANCHOR_TIMES];
541 }
542
543 fn latest_max_functions_are_safe<N: Network>() {
546 assert!(N::LATEST_MAX_CERTIFICATES() > 0, "LATEST_MAX_CERTIFICATES must be positive");
548 assert!(N::LATEST_MAX_PROGRAM_SIZE() > 0, "LATEST_MAX_PROGRAM_SIZE must be positive");
550 assert!(N::LATEST_MAX_TRANSACTION_SIZE() > 0, "LATEST_MAX_TRANSACTION_SIZE must be positive");
552 assert!(N::LATEST_MAX_WRITES() > 0, "LATEST_MAX_WRITES must be positive");
554 }
555
556 #[test]
557 #[allow(clippy::assertions_on_constants)]
558 fn test_consensus_constants() {
559 consensus_constants_at_genesis::<MainnetV0>();
560 consensus_constants_at_genesis::<TestnetV0>();
561 consensus_constants_at_genesis::<CanaryV0>();
562
563 consensus_versions::<MainnetV0>();
564 consensus_versions::<TestnetV0>();
565 consensus_versions::<CanaryV0>();
566
567 consensus_constants_increasing_heights::<MainnetV0>();
568 consensus_constants_increasing_heights::<TestnetV0>();
569 consensus_constants_increasing_heights::<CanaryV0>();
570
571 consensus_constants_valid_heights::<MainnetV0>();
572 consensus_constants_valid_heights::<TestnetV0>();
573 consensus_constants_valid_heights::<CanaryV0>();
574
575 consensus_config_returns_some::<MainnetV0>();
576 consensus_config_returns_some::<TestnetV0>();
577 consensus_config_returns_some::<CanaryV0>();
578
579 max_certificates_increasing::<MainnetV0>();
580 max_certificates_increasing::<TestnetV0>();
581 max_certificates_increasing::<CanaryV0>();
582
583 max_array_elements_increasing::<MainnetV0>();
584 max_array_elements_increasing::<TestnetV0>();
585 max_array_elements_increasing::<CanaryV0>();
586
587 transaction_size_exceeds_program_size::<MainnetV0>();
588 transaction_size_exceeds_program_size::<TestnetV0>();
589 transaction_size_exceeds_program_size::<CanaryV0>();
590
591 program_and_transaction_size_aligned::<MainnetV0>();
592 program_and_transaction_size_aligned::<TestnetV0>();
593 program_and_transaction_size_aligned::<CanaryV0>();
594
595 latest_max_functions_are_safe::<MainnetV0>();
596 latest_max_functions_are_safe::<TestnetV0>();
597 latest_max_functions_are_safe::<CanaryV0>();
598
599 constants_equal_length::<MainnetV0, TestnetV0, CanaryV0>();
600 }
601
602 #[test]
604 fn test_to_bytes() {
605 let version = ConsensusVersion::V8;
606 let bytes = version.to_bytes_le().unwrap();
607 let result = ConsensusVersion::from_bytes_le(&bytes).unwrap();
608 assert_eq!(result, version);
609
610 let version = ConsensusVersion::latest();
611 let bytes = version.to_bytes_le().unwrap();
612 let result = ConsensusVersion::from_bytes_le(&bytes).unwrap();
613 assert_eq!(result, version);
614
615 let invalid_bytes = u16::MAX.to_bytes_le().unwrap();
616 let result = ConsensusVersion::from_bytes_le(&invalid_bytes);
617 assert!(result.is_err());
618 }
619
620 #[test]
621 fn test_reward_anchor_time() {
622 assert_eq!(MainnetV0::REWARD_ANCHOR_TIME, MainnetV0::ANCHOR_TIMES.first().unwrap().1);
623 assert_eq!(TestnetV0::REWARD_ANCHOR_TIME, TestnetV0::ANCHOR_TIMES.first().unwrap().1);
624 assert_eq!(CanaryV0::REWARD_ANCHOR_TIME, CanaryV0::ANCHOR_TIMES.first().unwrap().1);
625 }
626}