1#![forbid(unsafe_code)]
17#![allow(clippy::too_many_arguments)]
18#![warn(clippy::cast_possible_truncation)]
19
20#[macro_use]
21extern crate lazy_static;
22
23pub use snarkvm_console_network_environment as environment;
24pub use snarkvm_console_network_environment::*;
25
26mod helpers;
27pub use helpers::*;
28
29mod canary_v0;
30pub use canary_v0::*;
31
32mod mainnet_v0;
33pub use mainnet_v0::*;
34
35mod testnet_v0;
36pub use testnet_v0::*;
37
38pub mod prelude {
39 pub use crate::{ConsensusVersion, Network, consensus_config_value, environment::prelude::*};
40}
41
42use crate::environment::prelude::*;
43use snarkvm_algorithms::{
44 AlgebraicSponge,
45 crypto_hash::PoseidonSponge,
46 snark::varuna::{CircuitProvingKey, CircuitVerifyingKey, VarunaHidingMode},
47 srs::{UniversalProver, UniversalVerifier},
48};
49use snarkvm_console_algorithms::{BHP512, BHP1024, Poseidon2, Poseidon4};
50use snarkvm_console_collections::merkle_tree::{MerklePath, MerkleTree};
51use snarkvm_console_types::{Field, Group, Scalar};
52use snarkvm_curves::PairingEngine;
53
54use indexmap::IndexMap;
55use once_cell::sync::OnceCell;
56use std::sync::Arc;
57
58pub type BHPMerkleTree<N, const DEPTH: u8> = MerkleTree<N, BHP1024<N>, BHP512<N>, DEPTH>;
60pub type PoseidonMerkleTree<N, const DEPTH: u8> = MerkleTree<N, Poseidon4<N>, Poseidon2<N>, DEPTH>;
62
63type Fq<N> = <<N as Environment>::PairingCurve as PairingEngine>::Fq;
65pub type FiatShamir<N> = PoseidonSponge<Fq<N>, 2, 1>;
66pub type FiatShamirParameters<N> = <FiatShamir<N> as AlgebraicSponge<Fq<N>, 2>>::Parameters;
67
68pub(crate) type VarunaProvingKey<N> = CircuitProvingKey<<N as Environment>::PairingCurve, VarunaHidingMode>;
70pub(crate) type VarunaVerifyingKey<N> = CircuitVerifyingKey<<N as Environment>::PairingCurve>;
71
72#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd)]
75pub enum ConsensusVersion {
76 V1 = 1,
78 V2 = 2,
80 V3 = 3,
82 V4 = 4,
84 V5 = 5,
86 V6 = 6,
88 V7 = 7,
90}
91
92pub trait Network:
93 'static
94 + Environment
95 + Copy
96 + Clone
97 + Debug
98 + Eq
99 + PartialEq
100 + core::hash::Hash
101 + Serialize
102 + DeserializeOwned
103 + for<'a> Deserialize<'a>
104 + Send
105 + Sync
106{
107 const ID: u16;
109 const NAME: &'static str;
111 const EDITION: u16;
113
114 const INCLUSION_FUNCTION_NAME: &'static str;
116
117 const GENESIS_TIMESTAMP: i64;
119 const GENESIS_COINBASE_TARGET: u64;
121 const GENESIS_PROOF_TARGET: u64;
123 const MAX_SOLUTIONS_AS_POWER_OF_TWO: u8 = 2; const MAX_SOLUTIONS: usize = 1 << Self::MAX_SOLUTIONS_AS_POWER_OF_TWO; const STARTING_SUPPLY: u64 = 1_500_000_000_000_000; const DEPLOYMENT_FEE_MULTIPLIER: u64 = 1_000; const EXECUTION_STORAGE_FEE_SCALING_FACTOR: u64 = 5000;
134 const EXECUTION_STORAGE_PENALTY_THRESHOLD: u64 = 5000;
136 const SYNTHESIS_FEE_MULTIPLIER: u64 = 25; const MAX_DEPLOYMENT_VARIABLES: u64 = 1 << 20; const MAX_DEPLOYMENT_CONSTRAINTS: u64 = 1 << 20; const MAX_FEE: u64 = 1_000_000_000_000_000;
144 const TRANSACTION_SPEND_LIMIT: u64 = 100_000_000;
146
147 const ANCHOR_HEIGHT: u32 = Self::ANCHOR_TIME as u32 / Self::BLOCK_TIME as u32;
149 const ANCHOR_TIME: u16 = 25;
151 const BLOCK_TIME: u16 = 10;
153 const NUM_BLOCKS_PER_EPOCH: u32 = 3600 / Self::BLOCK_TIME as u32; const MAX_DATA_ENTRIES: usize = 32;
158 const MAX_DATA_DEPTH: usize = 32;
161 #[allow(clippy::cast_possible_truncation)]
163 const MAX_DATA_SIZE_IN_FIELDS: u32 = ((128 * 1024 * 8) / Field::<Self>::SIZE_IN_DATA_BITS) as u32;
164
165 const MIN_STRUCT_ENTRIES: usize = 1; const MAX_STRUCT_ENTRIES: usize = Self::MAX_DATA_ENTRIES;
169
170 const MIN_ARRAY_ELEMENTS: usize = 1; const MAX_ARRAY_ELEMENTS: usize = Self::MAX_DATA_ENTRIES;
174
175 const MIN_RECORD_ENTRIES: usize = 1; const MAX_RECORD_ENTRIES: usize = Self::MIN_RECORD_ENTRIES.saturating_add(Self::MAX_DATA_ENTRIES);
179
180 const MAX_PROGRAM_SIZE: usize = 100_000; const MAX_MAPPINGS: usize = 31;
185 const MAX_FUNCTIONS: usize = 31;
187 const MAX_STRUCTS: usize = 10 * Self::MAX_FUNCTIONS;
189 const MAX_RECORDS: usize = 10 * Self::MAX_FUNCTIONS;
191 const MAX_CLOSURES: usize = 2 * Self::MAX_FUNCTIONS;
193 const MAX_OPERANDS: usize = Self::MAX_INPUTS;
195 const MAX_INSTRUCTIONS: usize = u16::MAX as usize;
197 const MAX_COMMANDS: usize = u16::MAX as usize;
199 const MAX_WRITES: u16 = 16;
201
202 const MAX_INPUTS: usize = 16;
204 const MAX_OUTPUTS: usize = 16;
206
207 const MAX_IMPORTS: usize = 64;
209
210 const MAX_TRANSACTION_SIZE: usize = 128_000; type StateRoot: Bech32ID<Field<Self>>;
216 type BlockHash: Bech32ID<Field<Self>>;
218 type RatificationID: Bech32ID<Field<Self>>;
220 type TransactionID: Bech32ID<Field<Self>>;
222 type TransitionID: Bech32ID<Field<Self>>;
224 type TransmissionChecksum: IntegerType;
226
227 const CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); 7];
230 const MAX_CERTIFICATES: [(ConsensusVersion, u16); 4];
236
237 #[allow(non_snake_case)]
239 fn CONSENSUS_VERSION(seek_height: u32) -> anyhow::Result<ConsensusVersion> {
240 match Self::CONSENSUS_VERSION_HEIGHTS.binary_search_by(|(_, height)| height.cmp(&seek_height)) {
241 Ok(index) => Ok(Self::CONSENSUS_VERSION_HEIGHTS[index].0),
243 Err(index) => {
245 if index == 0 {
246 Err(anyhow!("Expected consensus version 1 to exist at height 0."))
247 } else {
248 Ok(Self::CONSENSUS_VERSION_HEIGHTS[index - 1].0)
250 }
251 }
252 }
253 }
254 #[allow(non_snake_case)]
256 fn CONSENSUS_HEIGHT(version: ConsensusVersion) -> Result<u32> {
257 Ok(Self::CONSENSUS_VERSION_HEIGHTS.get(version as usize - 1).ok_or(anyhow!("Invalid consensus version"))?.1)
258 }
259 #[allow(non_snake_case)]
261 fn LATEST_MAX_CERTIFICATES() -> Result<u16> {
262 Self::MAX_CERTIFICATES.last().map_or(Err(anyhow!("No MAX_CERTIFICATES defined.")), |(_, value)| Ok(*value))
263 }
264
265 fn genesis_bytes() -> &'static [u8];
267
268 fn restrictions_list_as_str() -> &'static str;
270
271 fn get_credits_proving_key(function_name: String) -> Result<&'static Arc<VarunaProvingKey<Self>>>;
273
274 fn get_credits_verifying_key(function_name: String) -> Result<&'static Arc<VarunaVerifyingKey<Self>>>;
276
277 fn inclusion_proving_key() -> &'static Arc<VarunaProvingKey<Self>>;
279
280 fn inclusion_verifying_key() -> &'static Arc<VarunaVerifyingKey<Self>>;
282
283 fn g_powers() -> &'static Vec<Group<Self>>;
285
286 fn g_scalar_multiply(scalar: &Scalar<Self>) -> Group<Self>;
288
289 fn varuna_universal_prover() -> &'static UniversalProver<Self::PairingCurve>;
291
292 fn varuna_universal_verifier() -> &'static UniversalVerifier<Self::PairingCurve>;
294
295 fn varuna_fs_parameters() -> &'static FiatShamirParameters<Self>;
297
298 fn encryption_domain() -> Field<Self>;
300
301 fn graph_key_domain() -> Field<Self>;
303
304 fn serial_number_domain() -> Field<Self>;
306
307 fn commit_bhp256(input: &[bool], randomizer: &Scalar<Self>) -> Result<Field<Self>>;
309
310 fn commit_bhp512(input: &[bool], randomizer: &Scalar<Self>) -> Result<Field<Self>>;
312
313 fn commit_bhp768(input: &[bool], randomizer: &Scalar<Self>) -> Result<Field<Self>>;
315
316 fn commit_bhp1024(input: &[bool], randomizer: &Scalar<Self>) -> Result<Field<Self>>;
318
319 fn commit_ped64(input: &[bool], randomizer: &Scalar<Self>) -> Result<Field<Self>>;
321
322 fn commit_ped128(input: &[bool], randomizer: &Scalar<Self>) -> Result<Field<Self>>;
324
325 fn commit_to_group_bhp256(input: &[bool], randomizer: &Scalar<Self>) -> Result<Group<Self>>;
327
328 fn commit_to_group_bhp512(input: &[bool], randomizer: &Scalar<Self>) -> Result<Group<Self>>;
330
331 fn commit_to_group_bhp768(input: &[bool], randomizer: &Scalar<Self>) -> Result<Group<Self>>;
333
334 fn commit_to_group_bhp1024(input: &[bool], randomizer: &Scalar<Self>) -> Result<Group<Self>>;
336
337 fn commit_to_group_ped64(input: &[bool], randomizer: &Scalar<Self>) -> Result<Group<Self>>;
339
340 fn commit_to_group_ped128(input: &[bool], randomizer: &Scalar<Self>) -> Result<Group<Self>>;
342
343 fn hash_bhp256(input: &[bool]) -> Result<Field<Self>>;
345
346 fn hash_bhp512(input: &[bool]) -> Result<Field<Self>>;
348
349 fn hash_bhp768(input: &[bool]) -> Result<Field<Self>>;
351
352 fn hash_bhp1024(input: &[bool]) -> Result<Field<Self>>;
354
355 fn hash_keccak256(input: &[bool]) -> Result<Vec<bool>>;
357
358 fn hash_keccak384(input: &[bool]) -> Result<Vec<bool>>;
360
361 fn hash_keccak512(input: &[bool]) -> Result<Vec<bool>>;
363
364 fn hash_ped64(input: &[bool]) -> Result<Field<Self>>;
366
367 fn hash_ped128(input: &[bool]) -> Result<Field<Self>>;
369
370 fn hash_psd2(input: &[Field<Self>]) -> Result<Field<Self>>;
372
373 fn hash_psd4(input: &[Field<Self>]) -> Result<Field<Self>>;
375
376 fn hash_psd8(input: &[Field<Self>]) -> Result<Field<Self>>;
378
379 fn hash_sha3_256(input: &[bool]) -> Result<Vec<bool>>;
381
382 fn hash_sha3_384(input: &[bool]) -> Result<Vec<bool>>;
384
385 fn hash_sha3_512(input: &[bool]) -> Result<Vec<bool>>;
387
388 fn hash_many_psd2(input: &[Field<Self>], num_outputs: u16) -> Vec<Field<Self>>;
390
391 fn hash_many_psd4(input: &[Field<Self>], num_outputs: u16) -> Vec<Field<Self>>;
393
394 fn hash_many_psd8(input: &[Field<Self>], num_outputs: u16) -> Vec<Field<Self>>;
396
397 fn hash_to_group_bhp256(input: &[bool]) -> Result<Group<Self>>;
399
400 fn hash_to_group_bhp512(input: &[bool]) -> Result<Group<Self>>;
402
403 fn hash_to_group_bhp768(input: &[bool]) -> Result<Group<Self>>;
405
406 fn hash_to_group_bhp1024(input: &[bool]) -> Result<Group<Self>>;
408
409 fn hash_to_group_ped64(input: &[bool]) -> Result<Group<Self>>;
411
412 fn hash_to_group_ped128(input: &[bool]) -> Result<Group<Self>>;
414
415 fn hash_to_group_psd2(input: &[Field<Self>]) -> Result<Group<Self>>;
417
418 fn hash_to_group_psd4(input: &[Field<Self>]) -> Result<Group<Self>>;
420
421 fn hash_to_group_psd8(input: &[Field<Self>]) -> Result<Group<Self>>;
423
424 fn hash_to_scalar_psd2(input: &[Field<Self>]) -> Result<Scalar<Self>>;
426
427 fn hash_to_scalar_psd4(input: &[Field<Self>]) -> Result<Scalar<Self>>;
429
430 fn hash_to_scalar_psd8(input: &[Field<Self>]) -> Result<Scalar<Self>>;
432
433 fn merkle_tree_bhp<const DEPTH: u8>(leaves: &[Vec<bool>]) -> Result<BHPMerkleTree<Self, DEPTH>>;
435
436 fn merkle_tree_psd<const DEPTH: u8>(leaves: &[Vec<Field<Self>>]) -> Result<PoseidonMerkleTree<Self, DEPTH>>;
438
439 #[allow(clippy::ptr_arg)]
441 fn verify_merkle_path_bhp<const DEPTH: u8>(
442 path: &MerklePath<Self, DEPTH>,
443 root: &Field<Self>,
444 leaf: &Vec<bool>,
445 ) -> bool;
446
447 #[allow(clippy::ptr_arg)]
449 fn verify_merkle_path_psd<const DEPTH: u8>(
450 path: &MerklePath<Self, DEPTH>,
451 root: &Field<Self>,
452 leaf: &Vec<Field<Self>>,
453 ) -> bool;
454}
455
456#[macro_export]
463macro_rules! consensus_config_value {
464 ($network:ident, $constant:ident, $seek_height:expr) => {
465 $network::CONSENSUS_VERSION($seek_height).map_or(None, |seek_version| {
467 match $network::$constant.binary_search_by(|(version, _)| version.cmp(&seek_version)) {
469 Ok(index) => Some($network::$constant[index].1),
471 Err(index) => {
473 if index == 0 {
475 None
476 } else {
478 Some($network::$constant[index - 1].1)
479 }
480 }
481 }
482 })
483 };
484}
485
486#[cfg(test)]
487mod tests {
488 use super::*;
489
490 fn consensus_constants_at_genesis<N: Network>() {
493 let height = N::CONSENSUS_VERSION_HEIGHTS.first().unwrap().1;
494 assert_eq!(height, 0);
495 let consensus_version = N::CONSENSUS_VERSION_HEIGHTS.first().unwrap().0;
496 assert_eq!(consensus_version, ConsensusVersion::V1);
497 assert_eq!(consensus_version as usize, 1);
498 }
499
500 fn consensus_versions<N: Network>() {
502 let mut previous_version = N::CONSENSUS_VERSION_HEIGHTS.first().unwrap().0;
503 assert_eq!(previous_version as usize, 1);
505 for (version, _) in N::CONSENSUS_VERSION_HEIGHTS.iter().skip(1) {
507 assert_eq!(*version as usize, previous_version as usize + 1);
508 previous_version = *version;
509 }
510 let mut previous_version = N::MAX_CERTIFICATES.first().unwrap().0;
512 for (version, _) in N::MAX_CERTIFICATES.iter().skip(1) {
513 assert!(*version > previous_version);
514 previous_version = *version;
515 }
516 }
517
518 fn consensus_constants_increasing_heights<N: Network>() {
520 let mut previous_height = N::CONSENSUS_VERSION_HEIGHTS.first().unwrap().1;
521 for (version, height) in N::CONSENSUS_VERSION_HEIGHTS.iter().skip(1) {
522 assert!(*height > previous_height);
523 previous_height = *height;
524 assert_eq!(N::CONSENSUS_VERSION(*height).unwrap(), *version);
526 assert_eq!(N::CONSENSUS_HEIGHT(*version).unwrap(), *height);
528 }
529 }
530
531 fn consensus_constants_valid_heights<N: Network>() {
533 for (version, value) in N::MAX_CERTIFICATES.iter() {
534 let height = N::CONSENSUS_VERSION_HEIGHTS.iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
536 assert_eq!(consensus_config_value!(N, MAX_CERTIFICATES, height).unwrap(), *value);
538 }
539 }
540
541 fn max_certificates_increasing<N: Network>() {
544 let mut previous_value = N::MAX_CERTIFICATES.first().unwrap().1;
545 for (_, value) in N::MAX_CERTIFICATES.iter().skip(1) {
546 assert!(*value >= previous_value);
547 previous_value = *value;
548 }
549 }
550
551 fn constants_equal_length<N1: Network, N2: Network, N3: Network>() {
553 let _ = [N1::CONSENSUS_VERSION_HEIGHTS, N2::CONSENSUS_VERSION_HEIGHTS, N3::CONSENSUS_VERSION_HEIGHTS];
555 let _ = [N1::MAX_CERTIFICATES, N2::MAX_CERTIFICATES, N3::MAX_CERTIFICATES];
556 }
557
558 #[test]
559 #[allow(clippy::assertions_on_constants)]
560 fn test_consensus_constants() {
561 consensus_constants_at_genesis::<MainnetV0>();
562 consensus_constants_at_genesis::<TestnetV0>();
563 consensus_constants_at_genesis::<CanaryV0>();
564
565 consensus_versions::<MainnetV0>();
566 consensus_versions::<TestnetV0>();
567 consensus_versions::<CanaryV0>();
568
569 consensus_constants_increasing_heights::<MainnetV0>();
570 consensus_constants_increasing_heights::<TestnetV0>();
571 consensus_constants_increasing_heights::<CanaryV0>();
572
573 consensus_constants_valid_heights::<MainnetV0>();
574 consensus_constants_valid_heights::<TestnetV0>();
575 consensus_constants_valid_heights::<CanaryV0>();
576
577 max_certificates_increasing::<MainnetV0>();
578 max_certificates_increasing::<TestnetV0>();
579 max_certificates_increasing::<CanaryV0>();
580
581 constants_equal_length::<MainnetV0, TestnetV0, CanaryV0>();
582 }
583}