1use snarkos_account::Account;
17use snarkos_display::Display;
18use snarkos_node::{Node, bft::MEMORY_POOL_PORT, router::messages::NodeType};
19use snarkvm::{
20 console::{
21 account::{Address, PrivateKey},
22 algorithms::Hash,
23 network::{CanaryV0, MainnetV0, Network, TestnetV0},
24 },
25 ledger::{
26 block::Block,
27 committee::{Committee, MIN_DELEGATOR_STAKE, MIN_VALIDATOR_STAKE},
28 store::{ConsensusStore, helpers::memory::ConsensusMemory},
29 },
30 prelude::{FromBytes, ToBits, ToBytes},
31 synthesizer::VM,
32 utilities::to_bytes_le,
33};
34
35use aleo_std::StorageMode;
36use anyhow::{Context, Result, bail, ensure};
37use clap::Parser;
38use colored::Colorize;
39use core::str::FromStr;
40use indexmap::IndexMap;
41use rand::{Rng, SeedableRng};
42use rand_chacha::ChaChaRng;
43use serde::{Deserialize, Serialize};
44use std::{
45 net::SocketAddr,
46 path::PathBuf,
47 sync::{Arc, atomic::AtomicBool},
48};
49use tokio::runtime::{self, Runtime};
50
51#[cfg(target_family = "unix")]
54const RECOMMENDED_MIN_NOFILES_LIMIT: u64 = 2048;
55
56const DEVELOPMENT_MODE_RNG_SEED: u64 = 1234567890u64;
58
59const DEVELOPMENT_MODE_NUM_GENESIS_COMMITTEE_MEMBERS: u16 = 4;
61
62pub(crate) const CDN_BASE_URL: &str = "https://cdn.provable.com";
64
65#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
67pub struct BondedBalances(IndexMap<String, (String, String, u64)>);
68
69impl FromStr for BondedBalances {
70 type Err = serde_json::Error;
71
72 fn from_str(s: &str) -> Result<Self, Self::Err> {
73 serde_json::from_str(s)
74 }
75}
76
77#[derive(Clone, Debug, Parser)]
79#[command(group(
80 clap::ArgGroup::new("node_type").required(false).multiple(false)
82))]
83pub struct Start {
84 #[clap(default_value_t=MainnetV0::ID, long = "network", value_parser = clap::value_parser!(u16).range((MainnetV0::ID as i64)..=(CanaryV0::ID as i64)))]
86 pub network: u16,
87
88 #[clap(long = "validator", group = "node_type")]
90 pub validator: bool,
91 #[clap(long = "prover", group = "node_type")]
93 pub prover: bool,
94 #[clap(long = "client", group = "node_type")]
96 pub client: bool,
97
98 #[clap(long = "private-key")]
100 pub private_key: Option<String>,
101 #[clap(long = "private-key-file")]
103 pub private_key_file: Option<PathBuf>,
104
105 #[clap(long = "node")]
107 pub node: Option<SocketAddr>,
108 #[clap(long = "bft")]
110 pub bft: Option<SocketAddr>,
111 #[clap(default_value = "", long = "peers")]
113 pub peers: String,
114 #[clap(default_value = "", long = "validators")]
116 pub validators: String,
117 #[clap(long = "allow-external-peers")]
121 pub allow_external_peers: bool,
122 #[clap(long = "rotate-external-peers")]
124 pub rotate_external_peers: bool,
125
126 #[clap(long = "rest")]
128 pub rest: Option<SocketAddr>,
129 #[clap(default_value = "10", long = "rest-rps")]
131 pub rest_rps: u32,
132 #[clap(long)]
134 pub norest: bool,
135
136 #[clap(long)]
138 pub nodisplay: bool,
139 #[clap(default_value = "1", long = "verbosity")]
141 pub verbosity: u8,
142 #[clap(default_value_os_t = std::env::temp_dir().join("snarkos.log"), long = "logfile")]
144 pub logfile: PathBuf,
145
146 #[cfg(feature = "metrics")]
148 #[clap(default_value = "false", long = "metrics")]
149 pub metrics: bool,
150 #[cfg(feature = "metrics")]
152 #[clap(long = "metrics-ip")]
153 pub metrics_ip: Option<SocketAddr>,
154
155 #[clap(long = "storage")]
158 pub storage: Option<PathBuf>,
159 #[clap(long = "cdn")]
161 pub cdn: Option<String>,
162 #[clap(long)]
164 pub nocdn: bool,
165
166 #[clap(long)]
168 pub dev: Option<u16>,
169 #[clap(long)]
171 pub dev_num_validators: Option<u16>,
172 #[clap(default_value = "false", long = "no-dev-txs")]
174 pub no_dev_txs: bool,
175 #[clap(long)]
177 pub dev_bonded_balances: Option<BondedBalances>,
178}
179
180impl Start {
181 pub fn parse(self) -> Result<String> {
183 let shutdown: Arc<AtomicBool> = Default::default();
185
186 let log_receiver =
188 crate::helpers::initialize_logger(self.verbosity, self.nodisplay, self.logfile.clone(), shutdown.clone());
189 Self::runtime().block_on(async move {
191 let node_parse_error = || "Failed to parse node arguments";
193 let display_start_error = || "Failed to initialize the display";
194
195 let mut cli = self.clone();
197 match cli.network {
199 MainnetV0::ID => {
200 let node = cli.parse_node::<MainnetV0>(shutdown.clone()).await.with_context(node_parse_error)?;
202 if !cli.nodisplay {
204 Display::start(node, log_receiver).with_context(display_start_error)?;
206 }
207 }
208 TestnetV0::ID => {
209 let node = cli.parse_node::<TestnetV0>(shutdown.clone()).await.with_context(node_parse_error)?;
211 if !cli.nodisplay {
213 Display::start(node, log_receiver).with_context(display_start_error)?;
215 }
216 }
217 CanaryV0::ID => {
218 let node = cli.parse_node::<CanaryV0>(shutdown.clone()).await.with_context(node_parse_error)?;
220 if !cli.nodisplay {
222 Display::start(node, log_receiver).with_context(display_start_error)?;
224 }
225 }
226 _ => panic!("Invalid network ID specified"),
227 };
228 std::future::pending::<()>().await;
231 Ok(String::new())
232 })
233 }
234}
235
236impl Start {
237 fn parse_trusted_peers(&self) -> Result<Vec<SocketAddr>> {
239 match self.peers.is_empty() {
240 true => Ok(vec![]),
241 false => Ok(self
242 .peers
243 .split(',')
244 .flat_map(|ip| match ip.parse::<SocketAddr>() {
245 Ok(ip) => Some(ip),
246 Err(e) => {
247 eprintln!("The IP supplied to --peers ('{ip}') is malformed: {e}");
248 None
249 }
250 })
251 .collect()),
252 }
253 }
254
255 fn parse_trusted_validators(&self) -> Result<Vec<SocketAddr>> {
257 match self.validators.is_empty() {
258 true => Ok(vec![]),
259 false => Ok(self
260 .validators
261 .split(',')
262 .flat_map(|ip| match ip.parse::<SocketAddr>() {
263 Ok(ip) => Some(ip),
264 Err(e) => {
265 eprintln!("The IP supplied to --validators ('{ip}') is malformed: {e}");
266 None
267 }
268 })
269 .collect()),
270 }
271 }
272
273 fn parse_cdn<N: Network>(&self) -> Option<String> {
275 let is_no_node_type = !(self.validator || self.prover || self.client);
277
278 if self.dev.is_some() || self.nocdn || self.prover || is_no_node_type {
284 None
285 }
286 else {
288 match &self.cdn {
290 Some(cdn) => match cdn.is_empty() {
292 true => None,
293 false => Some(cdn.clone()),
294 },
295 None => match N::ID {
297 MainnetV0::ID => Some(format!("{CDN_BASE_URL}/v0/blocks/mainnet")),
298 TestnetV0::ID => Some(format!("{CDN_BASE_URL}/v0/blocks/testnet")),
299 CanaryV0::ID => Some(format!("{CDN_BASE_URL}/v0/blocks/canary")),
300 _ => None,
301 },
302 }
303 }
304 }
305
306 fn parse_private_key<N: Network>(&self) -> Result<Account<N>> {
309 match self.dev {
310 None => match (&self.private_key, &self.private_key_file) {
311 (Some(private_key), None) => Account::from_str(private_key.trim()),
313 (None, Some(path)) => {
315 check_permissions(path)?;
316 Account::from_str(std::fs::read_to_string(path)?.trim())
317 }
318 (None, None) => match self.client {
320 true => Account::new(&mut rand::thread_rng()),
321 false => bail!("Missing the '--private-key' or '--private-key-file' argument"),
322 },
323 (Some(_), Some(_)) => {
325 bail!("Cannot use '--private-key' and '--private-key-file' simultaneously, please use only one")
326 }
327 },
328 Some(dev) => {
329 Account::try_from({
331 let mut rng = ChaChaRng::seed_from_u64(DEVELOPMENT_MODE_RNG_SEED);
333 for _ in 0..dev {
335 let _ = PrivateKey::<N>::new(&mut rng)?;
336 }
337 let private_key = PrivateKey::<N>::new(&mut rng)?;
338 println!("🔑 Your development private key for node {dev} is {}.\n", private_key.to_string().bold());
339 private_key
340 })
341 }
342 }
343 }
344
345 fn parse_development(
347 &mut self,
348 trusted_peers: &mut Vec<SocketAddr>,
349 trusted_validators: &mut Vec<SocketAddr>,
350 ) -> Result<()> {
351 if let Some(dev) = self.dev {
355 if trusted_peers.is_empty() {
357 for i in 0..dev {
358 trusted_peers.push(SocketAddr::from_str(&format!("127.0.0.1:{}", 4130 + i))?);
359 }
360 }
361 if trusted_validators.is_empty() {
363 for i in 0..2 {
365 if i != dev {
366 trusted_validators.push(SocketAddr::from_str(&format!("127.0.0.1:{}", MEMORY_POOL_PORT + i))?);
367 }
368 }
369 }
370 if self.node.is_none() {
374 self.node = Some(SocketAddr::from_str(&format!("0.0.0.0:{}", 4130 + dev))?);
375 }
376
377 if !self.norest && self.rest.is_none() {
379 self.rest = Some(SocketAddr::from_str(&format!("0.0.0.0:{}", 3030 + dev)).unwrap());
380 }
381 }
382 Ok(())
383 }
384
385 fn parse_genesis<N: Network>(&self) -> Result<Block<N>> {
388 if self.dev.is_some() {
389 let num_committee_members = match self.dev_num_validators {
391 Some(num_committee_members) => num_committee_members,
392 None => DEVELOPMENT_MODE_NUM_GENESIS_COMMITTEE_MEMBERS,
393 };
394 ensure!(
395 num_committee_members >= DEVELOPMENT_MODE_NUM_GENESIS_COMMITTEE_MEMBERS,
396 "Number of genesis committee members is too low"
397 );
398
399 let mut rng = ChaChaRng::seed_from_u64(DEVELOPMENT_MODE_RNG_SEED);
401 let dev_keys =
403 (0..num_committee_members).map(|_| PrivateKey::<N>::new(&mut rng)).collect::<Result<Vec<_>>>()?;
404 let development_addresses = dev_keys.iter().map(Address::<N>::try_from).collect::<Result<Vec<_>>>()?;
406
407 let (committee, bonded_balances) = match &self.dev_bonded_balances {
409 Some(bonded_balances) => {
410 let bonded_balances = bonded_balances
412 .0
413 .iter()
414 .map(|(staker_address, (validator_address, withdrawal_address, amount))| {
415 let staker_addr = Address::<N>::from_str(staker_address)?;
416 let validator_addr = Address::<N>::from_str(validator_address)?;
417 let withdrawal_addr = Address::<N>::from_str(withdrawal_address)?;
418 Ok((staker_addr, (validator_addr, withdrawal_addr, *amount)))
419 })
420 .collect::<Result<IndexMap<_, _>>>()?;
421
422 let mut members = IndexMap::new();
424 for (staker_address, (validator_address, _, amount)) in bonded_balances.iter() {
425 match staker_address == validator_address {
427 true => ensure!(amount >= &MIN_VALIDATOR_STAKE, "Validator stake is too low"),
428 false => ensure!(amount >= &MIN_DELEGATOR_STAKE, "Delegator stake is too low"),
429 }
430
431 ensure!(
433 development_addresses.contains(validator_address),
434 "Validator address {validator_address} is not included in the list of development addresses"
435 );
436
437 members.entry(*validator_address).and_modify(|(stake, _, _)| *stake += amount).or_insert((
439 *amount,
440 true,
441 rng.gen_range(0..100),
442 ));
443 }
444 let committee = Committee::<N>::new(0u64, members)?;
446 (committee, bonded_balances)
447 }
448 None => {
449 let stake_per_member =
451 N::STARTING_SUPPLY.saturating_div(2).saturating_div(num_committee_members as u64);
452 ensure!(stake_per_member >= MIN_VALIDATOR_STAKE, "Committee stake per member is too low");
453
454 let members = development_addresses
456 .iter()
457 .map(|address| (*address, (stake_per_member, true, rng.gen_range(0..100))))
458 .collect::<IndexMap<_, _>>();
459
460 let bonded_balances = members
463 .iter()
464 .map(|(address, (stake, _, _))| (*address, (*address, *address, *stake)))
465 .collect::<IndexMap<_, _>>();
466 let committee = Committee::<N>::new(0u64, members)?;
468
469 (committee, bonded_balances)
470 }
471 };
472
473 ensure!(
475 committee.members().len() == num_committee_members as usize,
476 "Number of committee members {} does not match the expected number of members {num_committee_members}",
477 committee.members().len()
478 );
479
480 let remaining_balance = N::STARTING_SUPPLY.saturating_sub(committee.total_stake());
482 let public_balance_per_validator = remaining_balance.saturating_div(num_committee_members as u64);
483
484 let mut public_balances = dev_keys
486 .iter()
487 .map(|private_key| Ok((Address::try_from(private_key)?, public_balance_per_validator)))
488 .collect::<Result<indexmap::IndexMap<_, _>>>()?;
489
490 let leftover =
492 remaining_balance.saturating_sub(public_balance_per_validator * num_committee_members as u64);
493 if leftover > 0 {
494 let (_, balance) = public_balances.get_index_mut(0).unwrap();
495 *balance += leftover;
496 }
497
498 let public_balances_sum: u64 = public_balances.values().copied().sum();
500 if committee.total_stake() + public_balances_sum != N::STARTING_SUPPLY {
501 bail!("Sum of committee stakes and public balances does not equal total starting supply.");
502 }
503
504 load_or_compute_genesis(dev_keys[0], committee, public_balances, bonded_balances, &mut rng)
506 } else {
507 if self.dev_num_validators.is_some() {
509 eprintln!("The '--dev-num-validators' flag is ignored because '--dev' is not set");
510 }
511
512 Block::from_bytes_le(N::genesis_bytes())
513 }
514 }
515
516 const fn parse_node_type(&self) -> NodeType {
519 if self.validator {
520 NodeType::Validator
521 } else if self.prover {
522 NodeType::Prover
523 } else {
524 NodeType::Client
525 }
526 }
527
528 #[rustfmt::skip]
530 async fn parse_node<N: Network>(&mut self, shutdown: Arc<AtomicBool>) -> Result<Node<N>> {
531 println!("{}", crate::helpers::welcome_message());
533
534 if cfg!(feature = "test_network") && self.dev.is_none() {
537 bail!("The 'test_network' feature is enabled, but the '--dev' flag is not set");
538 }
539 if cfg!(feature = "test_network") && N::ID == MainnetV0::ID {
540 bail!("The 'test_network' feature is enabled, but you are trying to use mainnet. This is not supported.");
541 }
542
543 let mut trusted_peers = self.parse_trusted_peers()?;
545 let mut trusted_validators = self.parse_trusted_validators()?;
547 self.parse_development(&mut trusted_peers, &mut trusted_validators)?;
549
550 let cdn = self.parse_cdn::<N>();
552
553 let genesis = self.parse_genesis::<N>()?;
555 let account = self.parse_private_key::<N>()?;
557 let node_type = self.parse_node_type();
559
560 let node_ip = match self.node {
562 Some(node_ip) => node_ip,
563 None => SocketAddr::from_str("0.0.0.0:4130").unwrap(),
564 };
565
566 let rest_ip = match self.norest {
568 true => None,
569 false => self.rest.or_else(|| Some("0.0.0.0:3030".parse().unwrap())),
570 };
571
572 if self.nodisplay {
574 println!("👛 Your Aleo address is {}.\n", account.address().to_string().bold());
576 println!(
578 "🧭 Starting {} on {} at {}.\n",
579 node_type.description().bold(),
580 N::NAME.bold(),
581 node_ip.to_string().bold()
582 );
583
584 if node_type.is_validator() {
586 if let Some(rest_ip) = rest_ip {
587 println!("🌐 Starting the REST server at {}.\n", rest_ip.to_string().bold());
588
589 if let Ok(jwt_token) = snarkos_node_rest::Claims::new(account.address()).to_jwt_string() {
590 println!("🔑 Your one-time JWT token is {}\n", jwt_token.dimmed());
591 }
592 }
593 }
594 }
595
596 #[cfg(target_family = "unix")]
598 if node_type.is_validator() {
599 crate::helpers::check_open_files_limit(RECOMMENDED_MIN_NOFILES_LIMIT);
600 }
601 crate::helpers::check_validator_machine(node_type);
603
604 #[cfg(feature = "metrics")]
606 if self.metrics {
607 metrics::initialize_metrics(self.metrics_ip);
608 }
609
610 let storage_mode = match &self.storage {
612 Some(path) => StorageMode::Custom(path.clone()),
613 None => match self.dev {
614 Some(id) => StorageMode::Development(id),
615 None => StorageMode::Production,
616 },
617 };
618
619 let dev_txs = match self.dev {
621 Some(_) => !self.no_dev_txs,
622 None => {
623 if self.no_dev_txs {
625 eprintln!("The '--no-dev-txs' flag is ignored because '--dev' is not set");
626 }
627 false
628 }
629 };
630
631 match node_type {
633 NodeType::Validator => Node::new_validator(node_ip, self.bft, rest_ip, self.rest_rps, account, &trusted_peers, &trusted_validators, genesis, cdn, storage_mode, self.allow_external_peers, dev_txs, shutdown.clone()).await,
634 NodeType::Prover => Node::new_prover(node_ip, account, &trusted_peers, genesis, storage_mode, shutdown.clone()).await,
635 NodeType::Client => Node::new_client(node_ip, rest_ip, self.rest_rps, account, &trusted_peers, genesis, cdn, storage_mode, self.rotate_external_peers, shutdown).await,
636 }
637 }
638
639 fn runtime() -> Runtime {
641 let num_cores = num_cpus::get();
643
644 let (num_tokio_worker_threads, max_tokio_blocking_threads, num_rayon_cores_global) =
648 (2 * num_cores, 512, num_cores);
649
650 rayon::ThreadPoolBuilder::new()
652 .stack_size(8 * 1024 * 1024)
653 .num_threads(num_rayon_cores_global)
654 .build_global()
655 .unwrap();
656
657 runtime::Builder::new_multi_thread()
659 .enable_all()
660 .thread_stack_size(8 * 1024 * 1024)
661 .worker_threads(num_tokio_worker_threads)
662 .max_blocking_threads(max_tokio_blocking_threads)
663 .build()
664 .expect("Failed to initialize a runtime for the router")
665 }
666}
667
668fn check_permissions(path: &PathBuf) -> Result<(), snarkvm::prelude::Error> {
669 #[cfg(target_family = "unix")]
670 {
671 use std::os::unix::fs::PermissionsExt;
672 ensure!(path.exists(), "The file '{:?}' does not exist", path);
673 crate::check_parent_permissions(path)?;
674 let permissions = path.metadata()?.permissions().mode();
675 ensure!(permissions & 0o777 == 0o600, "The file {:?} must be readable only by the owner (0600)", path);
676 }
677 Ok(())
678}
679
680fn load_or_compute_genesis<N: Network>(
682 genesis_private_key: PrivateKey<N>,
683 committee: Committee<N>,
684 public_balances: indexmap::IndexMap<Address<N>, u64>,
685 bonded_balances: indexmap::IndexMap<Address<N>, (Address<N>, Address<N>, u64)>,
686 rng: &mut ChaChaRng,
687) -> Result<Block<N>> {
688 let mut preimage = Vec::new();
690
691 preimage.extend(&N::ID.to_le_bytes());
693 preimage.extend(&to_bytes_le![N::GENESIS_COINBASE_TARGET]?);
695 preimage.extend(&to_bytes_le![N::GENESIS_PROOF_TARGET]?);
697
698 preimage.extend(genesis_private_key.to_bytes_le()?);
700 preimage.extend(committee.to_bytes_le()?);
701 preimage.extend(&to_bytes_le![public_balances.iter().collect::<Vec<(_, _)>>()]?);
702 preimage.extend(&to_bytes_le![
703 bonded_balances
704 .iter()
705 .flat_map(|(staker, (validator, withdrawal, amount))| to_bytes_le![staker, validator, withdrawal, amount])
706 .collect::<Vec<_>>()
707 ]?);
708
709 match N::ID {
711 snarkvm::console::network::MainnetV0::ID => {
712 preimage.extend(snarkvm::parameters::mainnet::BondValidatorVerifier::METADATA.as_bytes());
713 preimage.extend(snarkvm::parameters::mainnet::BondPublicVerifier::METADATA.as_bytes());
714 preimage.extend(snarkvm::parameters::mainnet::UnbondPublicVerifier::METADATA.as_bytes());
715 preimage.extend(snarkvm::parameters::mainnet::ClaimUnbondPublicVerifier::METADATA.as_bytes());
716 preimage.extend(snarkvm::parameters::mainnet::SetValidatorStateVerifier::METADATA.as_bytes());
717 preimage.extend(snarkvm::parameters::mainnet::TransferPrivateVerifier::METADATA.as_bytes());
718 preimage.extend(snarkvm::parameters::mainnet::TransferPublicVerifier::METADATA.as_bytes());
719 preimage.extend(snarkvm::parameters::mainnet::TransferPrivateToPublicVerifier::METADATA.as_bytes());
720 preimage.extend(snarkvm::parameters::mainnet::TransferPublicToPrivateVerifier::METADATA.as_bytes());
721 preimage.extend(snarkvm::parameters::mainnet::FeePrivateVerifier::METADATA.as_bytes());
722 preimage.extend(snarkvm::parameters::mainnet::FeePublicVerifier::METADATA.as_bytes());
723 preimage.extend(snarkvm::parameters::mainnet::InclusionVerifier::METADATA.as_bytes());
724 }
725 snarkvm::console::network::TestnetV0::ID => {
726 preimage.extend(snarkvm::parameters::testnet::BondValidatorVerifier::METADATA.as_bytes());
727 preimage.extend(snarkvm::parameters::testnet::BondPublicVerifier::METADATA.as_bytes());
728 preimage.extend(snarkvm::parameters::testnet::UnbondPublicVerifier::METADATA.as_bytes());
729 preimage.extend(snarkvm::parameters::testnet::ClaimUnbondPublicVerifier::METADATA.as_bytes());
730 preimage.extend(snarkvm::parameters::testnet::SetValidatorStateVerifier::METADATA.as_bytes());
731 preimage.extend(snarkvm::parameters::testnet::TransferPrivateVerifier::METADATA.as_bytes());
732 preimage.extend(snarkvm::parameters::testnet::TransferPublicVerifier::METADATA.as_bytes());
733 preimage.extend(snarkvm::parameters::testnet::TransferPrivateToPublicVerifier::METADATA.as_bytes());
734 preimage.extend(snarkvm::parameters::testnet::TransferPublicToPrivateVerifier::METADATA.as_bytes());
735 preimage.extend(snarkvm::parameters::testnet::FeePrivateVerifier::METADATA.as_bytes());
736 preimage.extend(snarkvm::parameters::testnet::FeePublicVerifier::METADATA.as_bytes());
737 preimage.extend(snarkvm::parameters::testnet::InclusionVerifier::METADATA.as_bytes());
738 }
739 snarkvm::console::network::CanaryV0::ID => {
740 preimage.extend(snarkvm::parameters::canary::BondValidatorVerifier::METADATA.as_bytes());
741 preimage.extend(snarkvm::parameters::canary::BondPublicVerifier::METADATA.as_bytes());
742 preimage.extend(snarkvm::parameters::canary::UnbondPublicVerifier::METADATA.as_bytes());
743 preimage.extend(snarkvm::parameters::canary::ClaimUnbondPublicVerifier::METADATA.as_bytes());
744 preimage.extend(snarkvm::parameters::canary::SetValidatorStateVerifier::METADATA.as_bytes());
745 preimage.extend(snarkvm::parameters::canary::TransferPrivateVerifier::METADATA.as_bytes());
746 preimage.extend(snarkvm::parameters::canary::TransferPublicVerifier::METADATA.as_bytes());
747 preimage.extend(snarkvm::parameters::canary::TransferPrivateToPublicVerifier::METADATA.as_bytes());
748 preimage.extend(snarkvm::parameters::canary::TransferPublicToPrivateVerifier::METADATA.as_bytes());
749 preimage.extend(snarkvm::parameters::canary::FeePrivateVerifier::METADATA.as_bytes());
750 preimage.extend(snarkvm::parameters::canary::FeePublicVerifier::METADATA.as_bytes());
751 preimage.extend(snarkvm::parameters::canary::InclusionVerifier::METADATA.as_bytes());
752 }
753 _ => {
754 bail!("Unrecognized Network ID: {}", N::ID);
756 }
757 }
758
759 let hasher = snarkvm::console::algorithms::BHP256::<N>::setup("aleo.dev.block")?;
761 let hash = hasher.hash(&preimage.to_bits_le())?.to_string();
765
766 let load_block = |file_path| -> Result<Block<N>> {
768 let buffer = std::fs::read(file_path)?;
770 Block::from_bytes_le(&buffer)
772 };
773
774 let file_path = std::env::temp_dir().join(hash);
776 if file_path.exists() {
778 if let Ok(block) = load_block(&file_path) {
780 return Ok(block);
781 }
782 }
783
784 let vm = VM::from(ConsensusStore::<N, ConsensusMemory<N>>::open(StorageMode::new_test(None))?)?;
788 let block = vm.genesis_quorum(&genesis_private_key, committee, public_balances, bonded_balances, rng)?;
790 std::fs::write(&file_path, block.to_bytes_le()?)?;
792 Ok(block)
794}
795
796#[cfg(test)]
797mod tests {
798 use super::*;
799 use crate::commands::{CLI, Command};
800 use snarkvm::prelude::MainnetV0;
801
802 type CurrentNetwork = MainnetV0;
803
804 #[test]
805 fn test_parse_trusted_peers() {
806 let config = Start::try_parse_from(["snarkos", "--peers", ""].iter()).unwrap();
807 assert!(config.parse_trusted_peers().is_ok());
808 assert!(config.parse_trusted_peers().unwrap().is_empty());
809
810 let config = Start::try_parse_from(["snarkos", "--peers", "1.2.3.4:5"].iter()).unwrap();
811 assert!(config.parse_trusted_peers().is_ok());
812 assert_eq!(config.parse_trusted_peers().unwrap(), vec![SocketAddr::from_str("1.2.3.4:5").unwrap()]);
813
814 let config = Start::try_parse_from(["snarkos", "--peers", "1.2.3.4:5,6.7.8.9:0"].iter()).unwrap();
815 assert!(config.parse_trusted_peers().is_ok());
816 assert_eq!(config.parse_trusted_peers().unwrap(), vec![
817 SocketAddr::from_str("1.2.3.4:5").unwrap(),
818 SocketAddr::from_str("6.7.8.9:0").unwrap()
819 ]);
820 }
821
822 #[test]
823 fn test_parse_trusted_validators() {
824 let config = Start::try_parse_from(["snarkos", "--validators", ""].iter()).unwrap();
825 assert!(config.parse_trusted_validators().is_ok());
826 assert!(config.parse_trusted_validators().unwrap().is_empty());
827
828 let config = Start::try_parse_from(["snarkos", "--validators", "1.2.3.4:5"].iter()).unwrap();
829 assert!(config.parse_trusted_validators().is_ok());
830 assert_eq!(config.parse_trusted_validators().unwrap(), vec![SocketAddr::from_str("1.2.3.4:5").unwrap()]);
831
832 let config = Start::try_parse_from(["snarkos", "--validators", "1.2.3.4:5,6.7.8.9:0"].iter()).unwrap();
833 assert!(config.parse_trusted_validators().is_ok());
834 assert_eq!(config.parse_trusted_validators().unwrap(), vec![
835 SocketAddr::from_str("1.2.3.4:5").unwrap(),
836 SocketAddr::from_str("6.7.8.9:0").unwrap()
837 ]);
838 }
839
840 #[test]
841 fn test_parse_cdn() {
842 let config = Start::try_parse_from(["snarkos", "--validator", "--private-key", "aleo1xx"].iter()).unwrap();
844 assert!(config.parse_cdn::<CurrentNetwork>().is_some());
845 let config =
846 Start::try_parse_from(["snarkos", "--validator", "--private-key", "aleo1xx", "--cdn", "url"].iter())
847 .unwrap();
848 assert!(config.parse_cdn::<CurrentNetwork>().is_some());
849 let config =
850 Start::try_parse_from(["snarkos", "--validator", "--private-key", "aleo1xx", "--cdn", ""].iter()).unwrap();
851 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
852
853 let config =
855 Start::try_parse_from(["snarkos", "--dev", "0", "--validator", "--private-key", "aleo1xx"].iter()).unwrap();
856 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
857 let config = Start::try_parse_from(
858 ["snarkos", "--dev", "0", "--validator", "--private-key", "aleo1xx", "--cdn", "url"].iter(),
859 )
860 .unwrap();
861 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
862 let config = Start::try_parse_from(
863 ["snarkos", "--dev", "0", "--validator", "--private-key", "aleo1xx", "--cdn", ""].iter(),
864 )
865 .unwrap();
866 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
867
868 let config = Start::try_parse_from(["snarkos", "--prover", "--private-key", "aleo1xx"].iter()).unwrap();
870 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
871 let config =
872 Start::try_parse_from(["snarkos", "--prover", "--private-key", "aleo1xx", "--cdn", "url"].iter()).unwrap();
873 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
874 let config =
875 Start::try_parse_from(["snarkos", "--prover", "--private-key", "aleo1xx", "--cdn", ""].iter()).unwrap();
876 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
877
878 let config =
880 Start::try_parse_from(["snarkos", "--dev", "0", "--prover", "--private-key", "aleo1xx"].iter()).unwrap();
881 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
882 let config = Start::try_parse_from(
883 ["snarkos", "--dev", "0", "--prover", "--private-key", "aleo1xx", "--cdn", "url"].iter(),
884 )
885 .unwrap();
886 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
887 let config = Start::try_parse_from(
888 ["snarkos", "--dev", "0", "--prover", "--private-key", "aleo1xx", "--cdn", ""].iter(),
889 )
890 .unwrap();
891 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
892
893 let config = Start::try_parse_from(["snarkos", "--client", "--private-key", "aleo1xx"].iter()).unwrap();
895 assert!(config.parse_cdn::<CurrentNetwork>().is_some());
896 let config =
897 Start::try_parse_from(["snarkos", "--client", "--private-key", "aleo1xx", "--cdn", "url"].iter()).unwrap();
898 assert!(config.parse_cdn::<CurrentNetwork>().is_some());
899 let config =
900 Start::try_parse_from(["snarkos", "--client", "--private-key", "aleo1xx", "--cdn", ""].iter()).unwrap();
901 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
902
903 let config =
905 Start::try_parse_from(["snarkos", "--dev", "0", "--client", "--private-key", "aleo1xx"].iter()).unwrap();
906 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
907 let config = Start::try_parse_from(
908 ["snarkos", "--dev", "0", "--client", "--private-key", "aleo1xx", "--cdn", "url"].iter(),
909 )
910 .unwrap();
911 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
912 let config = Start::try_parse_from(
913 ["snarkos", "--dev", "0", "--client", "--private-key", "aleo1xx", "--cdn", ""].iter(),
914 )
915 .unwrap();
916 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
917
918 let config = Start::try_parse_from(["snarkos"].iter()).unwrap();
920 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
921 let config = Start::try_parse_from(["snarkos", "--cdn", "url"].iter()).unwrap();
922 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
923 let config = Start::try_parse_from(["snarkos", "--cdn", ""].iter()).unwrap();
924 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
925
926 let config = Start::try_parse_from(["snarkos", "--dev", "0"].iter()).unwrap();
928 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
929 let config = Start::try_parse_from(["snarkos", "--dev", "0", "--cdn", "url"].iter()).unwrap();
930 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
931 let config = Start::try_parse_from(["snarkos", "--dev", "0", "--cdn", ""].iter()).unwrap();
932 assert!(config.parse_cdn::<CurrentNetwork>().is_none());
933 }
934
935 #[test]
936 fn test_parse_development_and_genesis() {
937 let prod_genesis = Block::from_bytes_le(CurrentNetwork::genesis_bytes()).unwrap();
938
939 let mut trusted_peers = vec![];
940 let mut trusted_validators = vec![];
941 let mut config = Start::try_parse_from(["snarkos"].iter()).unwrap();
942 config.parse_development(&mut trusted_peers, &mut trusted_validators).unwrap();
943 let candidate_genesis = config.parse_genesis::<CurrentNetwork>().unwrap();
944 assert_eq!(trusted_peers.len(), 0);
945 assert_eq!(trusted_validators.len(), 0);
946 assert_eq!(candidate_genesis, prod_genesis);
947
948 let _config = Start::try_parse_from(["snarkos", "--dev", ""].iter()).unwrap_err();
949
950 let mut trusted_peers = vec![];
951 let mut trusted_validators = vec![];
952 let mut config = Start::try_parse_from(["snarkos", "--dev", "1"].iter()).unwrap();
953 config.parse_development(&mut trusted_peers, &mut trusted_validators).unwrap();
954 assert_eq!(config.rest, Some(SocketAddr::from_str("0.0.0.0:3031").unwrap()));
955
956 let mut trusted_peers = vec![];
957 let mut trusted_validators = vec![];
958 let mut config = Start::try_parse_from(["snarkos", "--dev", "1", "--rest", "127.0.0.1:8080"].iter()).unwrap();
959 config.parse_development(&mut trusted_peers, &mut trusted_validators).unwrap();
960 assert_eq!(config.rest, Some(SocketAddr::from_str("127.0.0.1:8080").unwrap()));
961
962 let mut trusted_peers = vec![];
963 let mut trusted_validators = vec![];
964 let mut config = Start::try_parse_from(["snarkos", "--dev", "1", "--norest"].iter()).unwrap();
965 config.parse_development(&mut trusted_peers, &mut trusted_validators).unwrap();
966 assert!(config.rest.is_none());
967
968 let mut trusted_peers = vec![];
969 let mut trusted_validators = vec![];
970 let mut config = Start::try_parse_from(["snarkos", "--dev", "0"].iter()).unwrap();
971 config.parse_development(&mut trusted_peers, &mut trusted_validators).unwrap();
972 let expected_genesis = config.parse_genesis::<CurrentNetwork>().unwrap();
973 assert_eq!(config.node, Some(SocketAddr::from_str("0.0.0.0:4130").unwrap()));
974 assert_eq!(config.rest, Some(SocketAddr::from_str("0.0.0.0:3030").unwrap()));
975 assert_eq!(trusted_peers.len(), 0);
976 assert_eq!(trusted_validators.len(), 1);
977 assert!(!config.validator);
978 assert!(!config.prover);
979 assert!(!config.client);
980 assert_ne!(expected_genesis, prod_genesis);
981
982 let mut trusted_peers = vec![];
983 let mut trusted_validators = vec![];
984 let mut config =
985 Start::try_parse_from(["snarkos", "--dev", "1", "--validator", "--private-key", ""].iter()).unwrap();
986 config.parse_development(&mut trusted_peers, &mut trusted_validators).unwrap();
987 let genesis = config.parse_genesis::<CurrentNetwork>().unwrap();
988 assert_eq!(config.node, Some(SocketAddr::from_str("0.0.0.0:4131").unwrap()));
989 assert_eq!(config.rest, Some(SocketAddr::from_str("0.0.0.0:3031").unwrap()));
990 assert_eq!(trusted_peers.len(), 1);
991 assert_eq!(trusted_validators.len(), 1);
992 assert!(config.validator);
993 assert!(!config.prover);
994 assert!(!config.client);
995 assert_eq!(genesis, expected_genesis);
996
997 let mut trusted_peers = vec![];
998 let mut trusted_validators = vec![];
999 let mut config =
1000 Start::try_parse_from(["snarkos", "--dev", "2", "--prover", "--private-key", ""].iter()).unwrap();
1001 config.parse_development(&mut trusted_peers, &mut trusted_validators).unwrap();
1002 let genesis = config.parse_genesis::<CurrentNetwork>().unwrap();
1003 assert_eq!(config.node, Some(SocketAddr::from_str("0.0.0.0:4132").unwrap()));
1004 assert_eq!(config.rest, Some(SocketAddr::from_str("0.0.0.0:3032").unwrap()));
1005 assert_eq!(trusted_peers.len(), 2);
1006 assert_eq!(trusted_validators.len(), 2);
1007 assert!(!config.validator);
1008 assert!(config.prover);
1009 assert!(!config.client);
1010 assert_eq!(genesis, expected_genesis);
1011
1012 let mut trusted_peers = vec![];
1013 let mut trusted_validators = vec![];
1014 let mut config =
1015 Start::try_parse_from(["snarkos", "--dev", "3", "--client", "--private-key", ""].iter()).unwrap();
1016 config.parse_development(&mut trusted_peers, &mut trusted_validators).unwrap();
1017 let genesis = config.parse_genesis::<CurrentNetwork>().unwrap();
1018 assert_eq!(config.node, Some(SocketAddr::from_str("0.0.0.0:4133").unwrap()));
1019 assert_eq!(config.rest, Some(SocketAddr::from_str("0.0.0.0:3033").unwrap()));
1020 assert_eq!(trusted_peers.len(), 3);
1021 assert_eq!(trusted_validators.len(), 2);
1022 assert!(!config.validator);
1023 assert!(!config.prover);
1024 assert!(config.client);
1025 assert_eq!(genesis, expected_genesis);
1026 }
1027
1028 #[test]
1029 fn clap_snarkos_start() {
1030 let arg_vec = vec![
1031 "snarkos",
1032 "start",
1033 "--nodisplay",
1034 "--dev",
1035 "2",
1036 "--validator",
1037 "--private-key",
1038 "PRIVATE_KEY",
1039 "--cdn",
1040 "CDN",
1041 "--peers",
1042 "IP1,IP2,IP3",
1043 "--validators",
1044 "IP1,IP2,IP3",
1045 "--rest",
1046 "127.0.0.1:3030",
1047 ];
1048 let cli = CLI::parse_from(arg_vec);
1049
1050 if let Command::Start(start) = cli.command {
1051 assert!(start.nodisplay);
1052 assert_eq!(start.dev, Some(2));
1053 assert!(start.validator);
1054 assert_eq!(start.private_key.as_deref(), Some("PRIVATE_KEY"));
1055 assert_eq!(start.cdn, Some("CDN".to_string()));
1056 assert_eq!(start.rest, Some("127.0.0.1:3030".parse().unwrap()));
1057 assert_eq!(start.network, 0);
1058 assert_eq!(start.peers, "IP1,IP2,IP3");
1059 assert_eq!(start.validators, "IP1,IP2,IP3");
1060 } else {
1061 panic!("Unexpected result of clap parsing!");
1062 }
1063 }
1064}