Skip to main content

snarkvm_console_network/
consensus_heights.rs

1// Copyright (c) 2019-2026 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::{FromBytes, ToBytes, io_error};
17
18use enum_iterator::{Sequence, last};
19use std::io;
20
21/// The different consensus versions.
22/// If you need the version active for a specific height, see: `N::CONSENSUS_VERSION`.
23#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Sequence)]
24#[repr(u16)]
25pub enum ConsensusVersion {
26    /// V1: The initial genesis consensus version.
27    V1 = 1,
28    /// V2: Update to the block reward and execution cost algorithms.
29    V2 = 2,
30    /// V3: Update to the number of validators and finalize scope RNG seed.
31    V3 = 3,
32    /// V4: Update to the Varuna version.
33    V4 = 4,
34    /// V5: Update to the number of validators and enable batch proposal spend limits.
35    V5 = 5,
36    /// V6: Update to the number of validators.
37    V6 = 6,
38    /// V7: Update to program rules.
39    V7 = 7,
40    /// V8: Update to inclusion version, record commitment version, and introduces sender ciphertexts.
41    V8 = 8,
42    /// V9: Support for program upgradability.
43    V9 = 9,
44    /// V10: Lower fees, appropriate record output type checking.
45    V10 = 10,
46    /// V11: Expand array size limit to 512 and introduce ECDSA signature verification opcodes.
47    V11 = 11,
48    /// V12: Prevent connection to forked nodes, disable StringType, enable block timestamp.
49    V12 = 12,
50    /// V13: Introduces external structs.
51    V13 = 13,
52    /// V14: Increase the program size limit to 512 kB, the transaction size limit to 540 kB,
53    ///      the array size limit to 2048, and the `Future` argument bit size to 32 bits.
54    ///      Introduces `aleo::GENERATOR`, `aleo::GENERATOR_POWERS`, `snark.verify` opcodes,
55    ///      and dynamic dispatch, and identifier literal types.
56    V14 = 14,
57}
58
59impl ToBytes for ConsensusVersion {
60    fn write_le<W: io::Write>(&self, writer: W) -> io::Result<()> {
61        (*self as u16).write_le(writer)
62    }
63}
64
65impl FromBytes for ConsensusVersion {
66    fn read_le<R: io::Read>(reader: R) -> io::Result<Self> {
67        match u16::read_le(reader)? {
68            0 => Err(io_error("Zero is not a valid consensus version")),
69            1 => Ok(Self::V1),
70            2 => Ok(Self::V2),
71            3 => Ok(Self::V3),
72            4 => Ok(Self::V4),
73            5 => Ok(Self::V5),
74            6 => Ok(Self::V6),
75            7 => Ok(Self::V7),
76            8 => Ok(Self::V8),
77            9 => Ok(Self::V9),
78            10 => Ok(Self::V10),
79            11 => Ok(Self::V11),
80            12 => Ok(Self::V12),
81            13 => Ok(Self::V13),
82            14 => Ok(Self::V14),
83            _ => Err(io_error("Invalid consensus version")),
84        }
85    }
86}
87
88impl ConsensusVersion {
89    pub fn latest() -> Self {
90        last::<ConsensusVersion>().expect("At least one ConsensusVersion should be defined.")
91    }
92}
93
94impl std::fmt::Display for ConsensusVersion {
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        // Use Debug formatting for Display.
97        write!(f, "{self:?}")
98    }
99}
100
101/// The number of consensus versions.
102pub(crate) const NUM_CONSENSUS_VERSIONS: usize = enum_iterator::cardinality::<ConsensusVersion>();
103
104/// The consensus version height for `CanaryV0`.
105pub const CANARY_V0_CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] = [
106    (ConsensusVersion::V1, 0),
107    (ConsensusVersion::V2, 2_900_000),
108    (ConsensusVersion::V3, 4_560_000),
109    (ConsensusVersion::V4, 5_730_000),
110    (ConsensusVersion::V5, 5_780_000),
111    (ConsensusVersion::V6, 6_240_000),
112    (ConsensusVersion::V7, 6_880_000),
113    (ConsensusVersion::V8, 7_565_000),
114    (ConsensusVersion::V9, 8_028_000),
115    (ConsensusVersion::V10, 8_600_000),
116    (ConsensusVersion::V11, 9_510_000),
117    (ConsensusVersion::V12, 10_030_000),
118    (ConsensusVersion::V13, 10_881_000),
119    (ConsensusVersion::V14, 11_960_000),
120];
121
122/// The consensus version height for `MainnetV0`.
123pub const MAINNET_V0_CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] = [
124    (ConsensusVersion::V1, 0),
125    (ConsensusVersion::V2, 2_800_000),
126    (ConsensusVersion::V3, 4_900_000),
127    (ConsensusVersion::V4, 6_135_000),
128    (ConsensusVersion::V5, 7_060_000),
129    (ConsensusVersion::V6, 7_560_000),
130    (ConsensusVersion::V7, 7_570_000),
131    (ConsensusVersion::V8, 9_430_000),
132    (ConsensusVersion::V9, 10_272_000),
133    (ConsensusVersion::V10, 11_205_000),
134    (ConsensusVersion::V11, 12_870_000),
135    (ConsensusVersion::V12, 13_815_000),
136    (ConsensusVersion::V13, 16_850_000),
137    (ConsensusVersion::V14, 17_700_000),
138];
139
140/// The consensus version heights for `TestnetV0`.
141pub const TESTNET_V0_CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] = [
142    (ConsensusVersion::V1, 0),
143    (ConsensusVersion::V2, 2_950_000),
144    (ConsensusVersion::V3, 4_800_000),
145    (ConsensusVersion::V4, 6_625_000),
146    (ConsensusVersion::V5, 6_765_000),
147    (ConsensusVersion::V6, 7_600_000),
148    (ConsensusVersion::V7, 8_365_000),
149    (ConsensusVersion::V8, 9_173_000),
150    (ConsensusVersion::V9, 9_800_000),
151    (ConsensusVersion::V10, 10_525_000),
152    (ConsensusVersion::V11, 11_952_000),
153    (ConsensusVersion::V12, 12_669_000),
154    (ConsensusVersion::V13, 14_906_000),
155    (ConsensusVersion::V14, 15_370_000),
156];
157
158/// The consensus version heights when the `test_consensus_heights` feature is enabled.
159pub const TEST_CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] = [
160    (ConsensusVersion::V1, 0),
161    (ConsensusVersion::V2, 5),
162    (ConsensusVersion::V3, 6),
163    (ConsensusVersion::V4, 7),
164    (ConsensusVersion::V5, 8),
165    (ConsensusVersion::V6, 9),
166    (ConsensusVersion::V7, 10),
167    (ConsensusVersion::V8, 11),
168    (ConsensusVersion::V9, 12),
169    (ConsensusVersion::V10, 13),
170    (ConsensusVersion::V11, 14),
171    (ConsensusVersion::V12, 15),
172    (ConsensusVersion::V13, 16),
173    (ConsensusVersion::V14, 17),
174];
175
176#[cfg(any(test, feature = "test", feature = "test_consensus_heights"))]
177pub fn load_test_consensus_heights() -> [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] {
178    // Attempt to read the test consensus heights from the environment variable.
179    load_test_consensus_heights_inner(std::env::var("CONSENSUS_VERSION_HEIGHTS").ok())
180}
181
182#[cfg(any(test, feature = "test", feature = "test_consensus_heights", feature = "wasm"))]
183pub(crate) fn load_test_consensus_heights_inner(
184    consensus_version_heights: Option<String>,
185) -> [(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS] {
186    // Define a closure to verify the consensus heights.
187    let verify_consensus_heights = |heights: &[(ConsensusVersion, u32); NUM_CONSENSUS_VERSIONS]| {
188        // Assert that the genesis height is 0.
189        assert_eq!(heights[0].1, 0, "Genesis height must be 0.");
190        // Assert that the consensus heights are strictly increasing.
191        for window in heights.windows(2) {
192            if window[0] >= window[1] {
193                panic!("Heights must be strictly increasing, but found: {window:?}");
194            }
195        }
196    };
197
198    // Define consensus version heights container used for testing.
199    let mut test_consensus_heights = TEST_CONSENSUS_VERSION_HEIGHTS;
200
201    // If version heights have been specified, verify and return them.
202    match consensus_version_heights {
203        Some(height_string) => {
204            let parsing_error = format!("Expected exactly {NUM_CONSENSUS_VERSIONS} ConsensusVersion heights.");
205            // Parse the heights from the environment variable.
206            let parsed_test_consensus_heights: [u32; NUM_CONSENSUS_VERSIONS] = height_string
207                .replace(" ", "")
208                .split(",")
209                .map(|height| height.parse::<u32>().expect("Heights should be valid u32 values."))
210                .collect::<Vec<u32>>()
211                .try_into()
212                .expect(&parsing_error);
213            // Set the parsed heights in the test consensus heights.
214            for (i, height) in parsed_test_consensus_heights.into_iter().enumerate() {
215                test_consensus_heights[i] = (TEST_CONSENSUS_VERSION_HEIGHTS[i].0, height);
216            }
217            // Verify and return the parsed test consensus heights.
218            verify_consensus_heights(&test_consensus_heights);
219            test_consensus_heights
220        }
221        None => {
222            // Verify and return the default test consensus heights.
223            verify_consensus_heights(&test_consensus_heights);
224            test_consensus_heights
225        }
226    }
227}
228
229/// Returns the consensus configuration value for the specified height.
230///
231/// Arguments:
232/// - `$network`: The network to use the constant of.
233/// - `$constant`: The constant to search a value of.
234/// - `$seek_height`: The block height to search the value for.
235#[macro_export]
236macro_rules! consensus_config_value {
237    ($network:ident, $constant:ident, $seek_height:expr) => {
238        // Search the consensus version enacted at the specified height.
239        $network::CONSENSUS_VERSION($seek_height).map_or(None, |seek_version| {
240            // Search the consensus value for the specified version.
241            // NOTE: calling `consensus_config_value_by_version!` here would require callers to import both macros.
242            match $network::$constant.binary_search_by(|(version, _)| version.cmp(&seek_version)) {
243                // If a value was found for this consensus version, return it.
244                Ok(index) => Some($network::$constant[index].1),
245                // If the specified version was not found exactly, determine whether to return an appropriate value anyway.
246                Err(index) => {
247                    // This constant is not yet in effect at this consensus version.
248                    if index == 0 {
249                        None
250                    // Return the appropriate value belonging to the consensus version *lower* than the sought version.
251                    } else {
252                        Some($network::$constant[index - 1].1)
253                    }
254                }
255            }
256        })
257    };
258}
259
260/// Returns the consensus configuration value for the specified ConsensusVersion.
261///
262/// Arguments:
263/// - `$network`: The network to use the constant of.
264/// - `$constant`: The constant to search a value of.
265/// - `$seek_version`: The ConsensusVersion to search the value for.
266#[macro_export]
267macro_rules! consensus_config_value_by_version {
268    ($network:ident, $constant:ident, $seek_version:expr) => {
269        // Search the consensus value for the specified version.
270        match $network::$constant.binary_search_by(|(version, _)| version.cmp(&$seek_version)) {
271            // If a value was found for this consensus version, return it.
272            Ok(index) => Some($network::$constant[index].1),
273            // If the specified version was not found exactly, determine whether to return an appropriate value anyway.
274            Err(index) => {
275                // This constant is not yet in effect at this consensus version.
276                if index == 0 {
277                    None
278                // Return the appropriate value belonging to the consensus version *lower* than the sought version.
279                } else {
280                    Some($network::$constant[index - 1].1)
281                }
282            }
283        }
284    };
285}
286
287#[cfg(test)]
288mod tests {
289    use super::*;
290    use crate::{CanaryV0, MainnetV0, Network, TestnetV0};
291
292    /// Ensure that the consensus constants are defined and correct at genesis.
293    /// It is possible this invariant no longer holds in the future, e.g. due to pruning or novel types of constants.
294    fn consensus_constants_at_genesis<N: Network>() {
295        let height = N::_CONSENSUS_VERSION_HEIGHTS.first().unwrap().1;
296        assert_eq!(height, 0);
297        let consensus_version = N::_CONSENSUS_VERSION_HEIGHTS.first().unwrap().0;
298        assert_eq!(consensus_version, ConsensusVersion::V1);
299        assert_eq!(consensus_version as usize, 1);
300    }
301
302    /// Ensure that the consensus *versions* are unique, incrementing and start with 1.
303    fn consensus_versions<N: Network>() {
304        let mut previous_version = N::_CONSENSUS_VERSION_HEIGHTS.first().unwrap().0;
305        // Ensure that the consensus versions start with 1.
306        assert_eq!(previous_version as usize, 1);
307        // Ensure that the consensus versions are unique and incrementing by 1.
308        for (version, _) in N::_CONSENSUS_VERSION_HEIGHTS.iter().skip(1) {
309            assert_eq!(*version as usize, previous_version as usize + 1);
310            previous_version = *version;
311        }
312        // Ensure that the consensus versions are unique and incrementing.
313        let mut previous_version = N::MAX_CERTIFICATES.first().unwrap().0;
314        for (version, _) in N::MAX_CERTIFICATES.iter().skip(1) {
315            assert!(*version > previous_version);
316            previous_version = *version;
317        }
318        let mut previous_version = N::TRANSACTION_SPEND_LIMIT.first().unwrap().0;
319        for (version, _) in N::TRANSACTION_SPEND_LIMIT.iter().skip(1) {
320            assert!(*version > previous_version);
321            previous_version = *version;
322        }
323        let mut previous_version = N::MAX_ARRAY_ELEMENTS.first().unwrap().0;
324        for (version, _) in N::MAX_ARRAY_ELEMENTS.iter().skip(1) {
325            assert!(*version > previous_version);
326            previous_version = *version;
327        }
328        let mut previous_version = N::MAX_PROGRAM_SIZE.first().unwrap().0;
329        for (version, _) in N::MAX_PROGRAM_SIZE.iter().skip(1) {
330            assert!(*version > previous_version);
331            previous_version = *version;
332        }
333        let mut previous_version = N::MAX_TRANSACTION_SIZE.first().unwrap().0;
334        for (version, _) in N::MAX_TRANSACTION_SIZE.iter().skip(1) {
335            assert!(*version > previous_version);
336            previous_version = *version;
337        }
338        let mut previous_version = N::MAX_WRITES.first().unwrap().0;
339        for (version, _) in N::MAX_WRITES.iter().skip(1) {
340            assert!(*version > previous_version);
341            previous_version = *version;
342        }
343    }
344
345    /// Ensure that consensus *heights* are unique and incrementing.
346    fn consensus_constants_increasing_heights<N: Network>() {
347        let mut previous_height = N::CONSENSUS_VERSION_HEIGHTS().first().unwrap().1;
348        for (version, height) in N::CONSENSUS_VERSION_HEIGHTS().iter().skip(1) {
349            assert!(*height > previous_height);
350            previous_height = *height;
351            // Ensure that N::CONSENSUS_VERSION returns the expected value.
352            assert_eq!(N::CONSENSUS_VERSION(*height).unwrap(), *version);
353            // Ensure that N::CONSENSUS_HEIGHT returns the expected value.
354            assert_eq!(N::CONSENSUS_HEIGHT(*version).unwrap(), *height);
355        }
356    }
357
358    /// Ensure that version of all consensus-relevant constants are present in the consensus version heights.
359    fn consensus_constants_valid_heights<N: Network>() {
360        for (version, value) in N::MAX_CERTIFICATES.iter() {
361            // Ensure that the height at which an update occurs are present in CONSENSUS_VERSION_HEIGHTS.
362            let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
363            // Double-check that consensus_config_value returns the correct value.
364            assert_eq!(consensus_config_value!(N, MAX_CERTIFICATES, height).unwrap(), *value);
365        }
366        for (version, value) in N::TRANSACTION_SPEND_LIMIT.iter() {
367            // Ensure that the height at which an update occurs are present in CONSENSUS_VERSION_HEIGHTS.
368            let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
369            // Double-check that consensus_config_value returns the correct value.
370            assert_eq!(consensus_config_value!(N, TRANSACTION_SPEND_LIMIT, height).unwrap(), *value);
371        }
372        for (version, value) in N::MAX_ARRAY_ELEMENTS.iter() {
373            // Ensure that the height at which an update occurs are present in CONSENSUS_VERSION_HEIGHTS.
374            let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
375            // Double-check that consensus_config_value returns the correct value.
376            assert_eq!(consensus_config_value!(N, MAX_ARRAY_ELEMENTS, height).unwrap(), *value);
377        }
378        for (version, value) in N::MAX_PROGRAM_SIZE.iter() {
379            // Ensure that the height at which an update occurs are present in CONSENSUS_VERSION_HEIGHTS.
380            let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
381            // Double-check that consensus_config_value returns the correct value.
382            assert_eq!(consensus_config_value!(N, MAX_PROGRAM_SIZE, height).unwrap(), *value);
383        }
384        for (version, value) in N::MAX_TRANSACTION_SIZE.iter() {
385            // Ensure that the height at which an update occurs are present in CONSENSUS_VERSION_HEIGHTS.
386            let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
387            // Double-check that consensus_config_value returns the correct value.
388            assert_eq!(consensus_config_value!(N, MAX_TRANSACTION_SIZE, height).unwrap(), *value);
389        }
390        for (version, value) in N::MAX_WRITES.iter() {
391            // Ensure that the height at which an update occurs are present in CONSENSUS_VERSION_HEIGHTS.
392            let height = N::CONSENSUS_VERSION_HEIGHTS().iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
393            // Double-check that consensus_config_value returns the correct value.
394            assert_eq!(consensus_config_value!(N, MAX_WRITES, height).unwrap(), *value);
395        }
396    }
397
398    /// Ensure that consensus_config_value returns a valid value for all consensus versions.
399    fn consensus_config_returns_some<N: Network>() {
400        for (_, height) in N::CONSENSUS_VERSION_HEIGHTS().iter() {
401            assert!(consensus_config_value!(N, MAX_CERTIFICATES, *height).is_some());
402            assert!(consensus_config_value!(N, TRANSACTION_SPEND_LIMIT, *height).is_some());
403            assert!(consensus_config_value!(N, MAX_ARRAY_ELEMENTS, *height).is_some());
404            assert!(consensus_config_value!(N, MAX_PROGRAM_SIZE, *height).is_some());
405            assert!(consensus_config_value!(N, MAX_TRANSACTION_SIZE, *height).is_some());
406            assert!(consensus_config_value!(N, MAX_WRITES, *height).is_some());
407        }
408    }
409
410    /// Ensure that `MAX_CERTIFICATES` increases and is correctly defined.
411    /// See the constant declaration for an explanation why.
412    fn max_certificates_increasing<N: Network>() {
413        let mut previous_value = N::MAX_CERTIFICATES.first().unwrap().1;
414        for (_, value) in N::MAX_CERTIFICATES.iter().skip(1) {
415            assert!(*value >= previous_value);
416            previous_value = *value;
417        }
418    }
419
420    /// Ensure that `MAX_ARRAY_ELEMENTS` increases and is correctly defined.
421    /// See the constant declaration for an explanation why.
422    fn max_array_elements_increasing<N: Network>() {
423        let mut previous_value = N::MAX_ARRAY_ELEMENTS.first().unwrap().1;
424        for (_, value) in N::MAX_ARRAY_ELEMENTS.iter().skip(1) {
425            assert!(*value >= previous_value);
426            previous_value = *value;
427        }
428    }
429
430    /// Ensure that `MAX_TRANSACTION_SIZE` is at least 28KB greater than `MAX_PROGRAM_SIZE` for all consensus versions.
431    /// This overhead accounts for proofs, signatures, and other transaction metadata.
432    fn transaction_size_exceeds_program_size<N: Network>() {
433        const MIN_OVERHEAD: usize = 28_000; // 28 kB minimum overhead
434
435        for (_, height) in N::CONSENSUS_VERSION_HEIGHTS().iter() {
436            let max_program_size = consensus_config_value!(N, MAX_PROGRAM_SIZE, *height).unwrap();
437            let max_transaction_size = consensus_config_value!(N, MAX_TRANSACTION_SIZE, *height).unwrap();
438
439            assert!(
440                max_transaction_size >= max_program_size + MIN_OVERHEAD,
441                "At height {height}: MAX_TRANSACTION_SIZE ({max_transaction_size}) must be at least {MIN_OVERHEAD} bytes greater than MAX_PROGRAM_SIZE ({max_program_size})"
442            );
443        }
444    }
445
446    /// Ensure that the number of constant definitions is the same across networks.
447    fn constants_equal_length<N1: Network, N2: Network, N3: Network>() {
448        // If we can construct an array, that means the underlying types must be the same.
449        let _ = [N1::CONSENSUS_VERSION_HEIGHTS, N2::CONSENSUS_VERSION_HEIGHTS, N3::CONSENSUS_VERSION_HEIGHTS];
450        let _ = [N1::MAX_CERTIFICATES, N2::MAX_CERTIFICATES, N3::MAX_CERTIFICATES];
451        let _ = [N1::TRANSACTION_SPEND_LIMIT, N2::TRANSACTION_SPEND_LIMIT, N3::TRANSACTION_SPEND_LIMIT];
452        let _ = [N1::MAX_ARRAY_ELEMENTS, N2::MAX_ARRAY_ELEMENTS, N3::MAX_ARRAY_ELEMENTS];
453        let _ = [N1::MAX_PROGRAM_SIZE, N2::MAX_PROGRAM_SIZE, N3::MAX_PROGRAM_SIZE];
454        let _ = [N1::MAX_TRANSACTION_SIZE, N2::MAX_TRANSACTION_SIZE, N3::MAX_TRANSACTION_SIZE];
455        let _ = [N1::MAX_WRITES, N2::MAX_WRITES, N3::MAX_WRITES];
456    }
457
458    /// Ensure that `LATEST_MAX_*` functions return valid values without panicking.
459    /// These functions use `.expect()` internally, so this test verifies the arrays are non-empty.
460    fn latest_max_functions_are_safe<N: Network>() {
461        // Verify LATEST_MAX_CERTIFICATES returns a positive value.
462        assert!(N::LATEST_MAX_CERTIFICATES() > 0, "LATEST_MAX_CERTIFICATES must be positive");
463        // Verify LATEST_MAX_PROGRAM_SIZE returns a positive value.
464        assert!(N::LATEST_MAX_PROGRAM_SIZE() > 0, "LATEST_MAX_PROGRAM_SIZE must be positive");
465        // Verify LATEST_MAX_TRANSACTION_SIZE returns a positive value.
466        assert!(N::LATEST_MAX_TRANSACTION_SIZE() > 0, "LATEST_MAX_TRANSACTION_SIZE must be positive");
467        // Verify LATEST_MAX_WRITES returns a positive value.
468        assert!(N::LATEST_MAX_WRITES() > 0, "LATEST_MAX_WRITES must be positive");
469    }
470
471    #[test]
472    #[allow(clippy::assertions_on_constants)]
473    fn test_consensus_constants() {
474        consensus_constants_at_genesis::<MainnetV0>();
475        consensus_constants_at_genesis::<TestnetV0>();
476        consensus_constants_at_genesis::<CanaryV0>();
477
478        consensus_versions::<MainnetV0>();
479        consensus_versions::<TestnetV0>();
480        consensus_versions::<CanaryV0>();
481
482        consensus_constants_increasing_heights::<MainnetV0>();
483        consensus_constants_increasing_heights::<TestnetV0>();
484        consensus_constants_increasing_heights::<CanaryV0>();
485
486        consensus_constants_valid_heights::<MainnetV0>();
487        consensus_constants_valid_heights::<TestnetV0>();
488        consensus_constants_valid_heights::<CanaryV0>();
489
490        consensus_config_returns_some::<MainnetV0>();
491        consensus_config_returns_some::<TestnetV0>();
492        consensus_config_returns_some::<CanaryV0>();
493
494        max_certificates_increasing::<MainnetV0>();
495        max_certificates_increasing::<TestnetV0>();
496        max_certificates_increasing::<CanaryV0>();
497
498        max_array_elements_increasing::<MainnetV0>();
499        max_array_elements_increasing::<TestnetV0>();
500        max_array_elements_increasing::<CanaryV0>();
501
502        transaction_size_exceeds_program_size::<MainnetV0>();
503        transaction_size_exceeds_program_size::<TestnetV0>();
504        transaction_size_exceeds_program_size::<CanaryV0>();
505
506        latest_max_functions_are_safe::<MainnetV0>();
507        latest_max_functions_are_safe::<TestnetV0>();
508        latest_max_functions_are_safe::<CanaryV0>();
509
510        constants_equal_length::<MainnetV0, TestnetV0, CanaryV0>();
511    }
512
513    /// Ensure (de-)serialization works correctly.
514    #[test]
515    fn test_to_bytes() {
516        let version = ConsensusVersion::V8;
517        let bytes = version.to_bytes_le().unwrap();
518        let result = ConsensusVersion::from_bytes_le(&bytes).unwrap();
519        assert_eq!(result, version);
520
521        let version = ConsensusVersion::latest();
522        let bytes = version.to_bytes_le().unwrap();
523        let result = ConsensusVersion::from_bytes_le(&bytes).unwrap();
524        assert_eq!(result, version);
525
526        let invalid_bytes = u16::MAX.to_bytes_le().unwrap();
527        let result = ConsensusVersion::from_bytes_le(&invalid_bytes);
528        assert!(result.is_err());
529    }
530}