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,
77 V2 = 2,
78 V3 = 3,
79 V4 = 4,
80}
81
82pub trait Network:
83 'static
84 + Environment
85 + Copy
86 + Clone
87 + Debug
88 + Eq
89 + PartialEq
90 + core::hash::Hash
91 + Serialize
92 + DeserializeOwned
93 + for<'a> Deserialize<'a>
94 + Send
95 + Sync
96{
97 const ID: u16;
99 const NAME: &'static str;
101 const EDITION: u16;
103
104 const INCLUSION_FUNCTION_NAME: &'static str;
106
107 const GENESIS_TIMESTAMP: i64;
109 const GENESIS_COINBASE_TARGET: u64;
111 const GENESIS_PROOF_TARGET: u64;
113 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;
124 const EXECUTION_STORAGE_PENALTY_THRESHOLD: u64 = 5000;
126 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;
134 const TRANSACTION_SPEND_LIMIT: u64 = 100_000_000;
136
137 const ANCHOR_HEIGHT: u32 = Self::ANCHOR_TIME as u32 / Self::BLOCK_TIME as u32;
139 const ANCHOR_TIME: u16 = 25;
141 const BLOCK_TIME: u16 = 10;
143 const NUM_BLOCKS_PER_EPOCH: u32 = 3600 / Self::BLOCK_TIME as u32; const MAX_DATA_ENTRIES: usize = 32;
148 const MAX_DATA_DEPTH: usize = 32;
151 #[allow(clippy::cast_possible_truncation)]
153 const MAX_DATA_SIZE_IN_FIELDS: u32 = ((128 * 1024 * 8) / Field::<Self>::SIZE_IN_DATA_BITS) as u32;
154
155 const MIN_STRUCT_ENTRIES: usize = 1; const MAX_STRUCT_ENTRIES: usize = Self::MAX_DATA_ENTRIES;
159
160 const MIN_ARRAY_ELEMENTS: usize = 1; const MAX_ARRAY_ELEMENTS: usize = Self::MAX_DATA_ENTRIES;
164
165 const MIN_RECORD_ENTRIES: usize = 1; const MAX_RECORD_ENTRIES: usize = Self::MIN_RECORD_ENTRIES.saturating_add(Self::MAX_DATA_ENTRIES);
169
170 const MAX_PROGRAM_SIZE: usize = 100_000; const MAX_MAPPINGS: usize = 31;
175 const MAX_FUNCTIONS: usize = 31;
177 const MAX_STRUCTS: usize = 10 * Self::MAX_FUNCTIONS;
179 const MAX_RECORDS: usize = 10 * Self::MAX_FUNCTIONS;
181 const MAX_CLOSURES: usize = 2 * Self::MAX_FUNCTIONS;
183 const MAX_OPERANDS: usize = Self::MAX_INPUTS;
185 const MAX_INSTRUCTIONS: usize = u16::MAX as usize;
187 const MAX_COMMANDS: usize = u16::MAX as usize;
189 const MAX_WRITES: u16 = 16;
191
192 const MAX_INPUTS: usize = 16;
194 const MAX_OUTPUTS: usize = 16;
196
197 const MAX_PROGRAM_DEPTH: usize = 64;
199 const MAX_IMPORTS: usize = 64;
201
202 const MAX_TRANSACTION_SIZE: usize = 128_000; type StateRoot: Bech32ID<Field<Self>>;
208 type BlockHash: Bech32ID<Field<Self>>;
210 type RatificationID: Bech32ID<Field<Self>>;
212 type TransactionID: Bech32ID<Field<Self>>;
214 type TransitionID: Bech32ID<Field<Self>>;
216 type TransmissionChecksum: IntegerType;
218
219 const CONSENSUS_VERSION_HEIGHTS: [(ConsensusVersion, u32); 4];
222 const MAX_CERTIFICATES: [(ConsensusVersion, u16); 2];
228
229 #[allow(non_snake_case)]
237 fn CONSENSUS_VERSION(seek_height: u32) -> anyhow::Result<ConsensusVersion> {
238 match Self::CONSENSUS_VERSION_HEIGHTS.binary_search_by(|(_, height)| height.cmp(&seek_height)) {
239 Ok(index) => Ok(Self::CONSENSUS_VERSION_HEIGHTS[index].0),
241 Err(index) => {
243 if index == 0 {
244 Err(anyhow!("Expected consensus version 1 to exist at height 0."))
245 } else {
246 Ok(Self::CONSENSUS_VERSION_HEIGHTS[index - 1].0)
248 }
249 }
250 }
251 }
252 #[allow(non_snake_case)]
254 fn CONSENSUS_HEIGHT(version: ConsensusVersion) -> Result<u32> {
255 Ok(Self::CONSENSUS_VERSION_HEIGHTS.get(version as usize - 1).ok_or(anyhow!("Invalid consensus version"))?.1)
256 }
257 #[allow(non_snake_case)]
259 fn LATEST_MAX_CERTIFICATES() -> Result<u16> {
260 Self::MAX_CERTIFICATES.last().map_or(Err(anyhow!("No MAX_CERTIFICATES defined.")), |(_, value)| Ok(*value))
261 }
262
263 fn genesis_bytes() -> &'static [u8];
265
266 fn restrictions_list_as_str() -> &'static str;
268
269 fn get_credits_proving_key(function_name: String) -> Result<&'static Arc<VarunaProvingKey<Self>>>;
271
272 fn get_credits_verifying_key(function_name: String) -> Result<&'static Arc<VarunaVerifyingKey<Self>>>;
274
275 fn inclusion_proving_key() -> &'static Arc<VarunaProvingKey<Self>>;
277
278 fn inclusion_verifying_key() -> &'static Arc<VarunaVerifyingKey<Self>>;
280
281 fn g_powers() -> &'static Vec<Group<Self>>;
283
284 fn g_scalar_multiply(scalar: &Scalar<Self>) -> Group<Self>;
286
287 fn varuna_universal_prover() -> &'static UniversalProver<Self::PairingCurve>;
289
290 fn varuna_universal_verifier() -> &'static UniversalVerifier<Self::PairingCurve>;
292
293 fn varuna_fs_parameters() -> &'static FiatShamirParameters<Self>;
295
296 fn encryption_domain() -> Field<Self>;
298
299 fn graph_key_domain() -> Field<Self>;
301
302 fn serial_number_domain() -> Field<Self>;
304
305 fn commit_bhp256(input: &[bool], randomizer: &Scalar<Self>) -> Result<Field<Self>>;
307
308 fn commit_bhp512(input: &[bool], randomizer: &Scalar<Self>) -> Result<Field<Self>>;
310
311 fn commit_bhp768(input: &[bool], randomizer: &Scalar<Self>) -> Result<Field<Self>>;
313
314 fn commit_bhp1024(input: &[bool], randomizer: &Scalar<Self>) -> Result<Field<Self>>;
316
317 fn commit_ped64(input: &[bool], randomizer: &Scalar<Self>) -> Result<Field<Self>>;
319
320 fn commit_ped128(input: &[bool], randomizer: &Scalar<Self>) -> Result<Field<Self>>;
322
323 fn commit_to_group_bhp256(input: &[bool], randomizer: &Scalar<Self>) -> Result<Group<Self>>;
325
326 fn commit_to_group_bhp512(input: &[bool], randomizer: &Scalar<Self>) -> Result<Group<Self>>;
328
329 fn commit_to_group_bhp768(input: &[bool], randomizer: &Scalar<Self>) -> Result<Group<Self>>;
331
332 fn commit_to_group_bhp1024(input: &[bool], randomizer: &Scalar<Self>) -> Result<Group<Self>>;
334
335 fn commit_to_group_ped64(input: &[bool], randomizer: &Scalar<Self>) -> Result<Group<Self>>;
337
338 fn commit_to_group_ped128(input: &[bool], randomizer: &Scalar<Self>) -> Result<Group<Self>>;
340
341 fn hash_bhp256(input: &[bool]) -> Result<Field<Self>>;
343
344 fn hash_bhp512(input: &[bool]) -> Result<Field<Self>>;
346
347 fn hash_bhp768(input: &[bool]) -> Result<Field<Self>>;
349
350 fn hash_bhp1024(input: &[bool]) -> Result<Field<Self>>;
352
353 fn hash_keccak256(input: &[bool]) -> Result<Vec<bool>>;
355
356 fn hash_keccak384(input: &[bool]) -> Result<Vec<bool>>;
358
359 fn hash_keccak512(input: &[bool]) -> Result<Vec<bool>>;
361
362 fn hash_ped64(input: &[bool]) -> Result<Field<Self>>;
364
365 fn hash_ped128(input: &[bool]) -> Result<Field<Self>>;
367
368 fn hash_psd2(input: &[Field<Self>]) -> Result<Field<Self>>;
370
371 fn hash_psd4(input: &[Field<Self>]) -> Result<Field<Self>>;
373
374 fn hash_psd8(input: &[Field<Self>]) -> Result<Field<Self>>;
376
377 fn hash_sha3_256(input: &[bool]) -> Result<Vec<bool>>;
379
380 fn hash_sha3_384(input: &[bool]) -> Result<Vec<bool>>;
382
383 fn hash_sha3_512(input: &[bool]) -> Result<Vec<bool>>;
385
386 fn hash_many_psd2(input: &[Field<Self>], num_outputs: u16) -> Vec<Field<Self>>;
388
389 fn hash_many_psd4(input: &[Field<Self>], num_outputs: u16) -> Vec<Field<Self>>;
391
392 fn hash_many_psd8(input: &[Field<Self>], num_outputs: u16) -> Vec<Field<Self>>;
394
395 fn hash_to_group_bhp256(input: &[bool]) -> Result<Group<Self>>;
397
398 fn hash_to_group_bhp512(input: &[bool]) -> Result<Group<Self>>;
400
401 fn hash_to_group_bhp768(input: &[bool]) -> Result<Group<Self>>;
403
404 fn hash_to_group_bhp1024(input: &[bool]) -> Result<Group<Self>>;
406
407 fn hash_to_group_ped64(input: &[bool]) -> Result<Group<Self>>;
409
410 fn hash_to_group_ped128(input: &[bool]) -> Result<Group<Self>>;
412
413 fn hash_to_group_psd2(input: &[Field<Self>]) -> Result<Group<Self>>;
415
416 fn hash_to_group_psd4(input: &[Field<Self>]) -> Result<Group<Self>>;
418
419 fn hash_to_group_psd8(input: &[Field<Self>]) -> Result<Group<Self>>;
421
422 fn hash_to_scalar_psd2(input: &[Field<Self>]) -> Result<Scalar<Self>>;
424
425 fn hash_to_scalar_psd4(input: &[Field<Self>]) -> Result<Scalar<Self>>;
427
428 fn hash_to_scalar_psd8(input: &[Field<Self>]) -> Result<Scalar<Self>>;
430
431 fn merkle_tree_bhp<const DEPTH: u8>(leaves: &[Vec<bool>]) -> Result<BHPMerkleTree<Self, DEPTH>>;
433
434 fn merkle_tree_psd<const DEPTH: u8>(leaves: &[Vec<Field<Self>>]) -> Result<PoseidonMerkleTree<Self, DEPTH>>;
436
437 #[allow(clippy::ptr_arg)]
439 fn verify_merkle_path_bhp<const DEPTH: u8>(
440 path: &MerklePath<Self, DEPTH>,
441 root: &Field<Self>,
442 leaf: &Vec<bool>,
443 ) -> bool;
444
445 #[allow(clippy::ptr_arg)]
447 fn verify_merkle_path_psd<const DEPTH: u8>(
448 path: &MerklePath<Self, DEPTH>,
449 root: &Field<Self>,
450 leaf: &Vec<Field<Self>>,
451 ) -> bool;
452}
453
454#[macro_export]
461macro_rules! consensus_config_value {
462 ($network:ident, $constant:ident, $seek_height:expr) => {
463 $network::CONSENSUS_VERSION($seek_height).map_or(None, |seek_version| {
465 match $network::$constant.binary_search_by(|(version, _)| version.cmp(&seek_version)) {
467 Ok(index) => Some($network::$constant[index].1),
469 Err(index) => {
471 if index == 0 {
473 None
474 } else {
476 Some($network::$constant[index - 1].1)
477 }
478 }
479 }
480 })
481 };
482}
483
484#[cfg(test)]
485mod tests {
486 use super::*;
487
488 fn consensus_constants_at_genesis<N: Network>() {
491 let height = N::CONSENSUS_VERSION_HEIGHTS.first().unwrap().1;
492 assert_eq!(height, 0);
493 let consensus_version = N::CONSENSUS_VERSION_HEIGHTS.first().unwrap().0;
494 assert_eq!(consensus_version, ConsensusVersion::V1);
495 assert_eq!(consensus_version as usize, 1);
496 }
497
498 fn consensus_versions<N: Network>() {
500 let mut previous_version = N::CONSENSUS_VERSION_HEIGHTS.first().unwrap().0;
501 assert_eq!(previous_version as usize, 1);
503 for (version, _) in N::CONSENSUS_VERSION_HEIGHTS.iter().skip(1) {
505 assert_eq!(*version as usize, previous_version as usize + 1);
506 previous_version = *version;
507 }
508 let mut previous_version = N::MAX_CERTIFICATES.first().unwrap().0;
510 for (version, _) in N::MAX_CERTIFICATES.iter().skip(1) {
511 assert!(*version > previous_version);
512 previous_version = *version;
513 }
514 }
515
516 fn consensus_constants_increasing_heights<N: Network>() {
518 let mut previous_height = N::CONSENSUS_VERSION_HEIGHTS.first().unwrap().1;
519 for (version, height) in N::CONSENSUS_VERSION_HEIGHTS.iter().skip(1) {
520 assert!(*height > previous_height);
521 previous_height = *height;
522 assert_eq!(N::CONSENSUS_VERSION(*height).unwrap(), *version);
524 assert_eq!(N::CONSENSUS_HEIGHT(*version).unwrap(), *height);
526 }
527 }
528
529 fn consensus_constants_valid_heights<N: Network>() {
531 for (version, value) in N::MAX_CERTIFICATES.iter() {
532 let height = N::CONSENSUS_VERSION_HEIGHTS.iter().find(|(c_version, _)| *c_version == *version).unwrap().1;
534 assert_eq!(consensus_config_value!(N, MAX_CERTIFICATES, height).unwrap(), *value);
536 }
537 }
538
539 fn max_certificates_increasing<N: Network>() {
542 let mut previous_value = N::MAX_CERTIFICATES.first().unwrap().1;
543 for (_, value) in N::MAX_CERTIFICATES.iter().skip(1) {
544 assert!(*value >= previous_value);
545 previous_value = *value;
546 }
547 }
548
549 fn constants_equal_length<N1: Network, N2: Network, N3: Network>() {
551 let _ = [N1::CONSENSUS_VERSION_HEIGHTS, N2::CONSENSUS_VERSION_HEIGHTS, N3::CONSENSUS_VERSION_HEIGHTS];
553 let _ = [N1::MAX_CERTIFICATES, N2::MAX_CERTIFICATES, N3::MAX_CERTIFICATES];
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 max_certificates_increasing::<MainnetV0>();
576 max_certificates_increasing::<TestnetV0>();
577 max_certificates_increasing::<CanaryV0>();
578
579 constants_equal_length::<MainnetV0, TestnetV0, CanaryV0>();
580 }
581}