From 0e12e4e88a5cecd6d5f2be0633215bb37efe5985 Mon Sep 17 00:00:00 2001 From: Howard Wu <9260812+howardwu@users.noreply.github.com> Date: Tue, 26 Sep 2023 21:22:52 -0700 Subject: [PATCH] Clippy --- Cargo.lock | 11 +++++ README.md | 2 +- cli/Cargo.toml | 3 ++ cli/src/commands/start.rs | 2 + cli/src/helpers/mod.rs | 92 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 97942bb683..0a05c582e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3027,6 +3027,7 @@ dependencies = [ "snarkos-node", "snarkos-node-rest", "snarkvm", + "sys-info", "thiserror", "tokio", "tracing-subscriber 0.3.17", @@ -4272,6 +4273,16 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "sys-info" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b3a0d0aba8bf96a0e1ddfdc352fc53b3df7f39318c71854910c3c4b024ae52c" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "tempfile" version = "3.8.0" diff --git a/README.md b/README.md index 7867ece29b..f139e5379d 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ The following are **minimum** requirements to run an Aleo node: - **OS**: 64-bit architectures only, latest up-to-date for security - Clients: Ubuntu 20.04, macOS Ventura or later, Windows 11 or later - Provers: Ubuntu 20.04, macOS Ventura or later - - Validators: Ubuntu 20.04, macOS Ventura or later + - Validators: Ubuntu 20.04 - **CPU**: 64-bit architectures only - Clients: 16-cores - Provers: 32-cores (64-cores preferred) diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 75e7f90595..67c4763435 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -86,6 +86,9 @@ version = "=2.1.7" [dependencies.snarkvm] workspace = true +[dependencies.sys-info] +version = "0.9" + [dependencies.thiserror] version = "1.0" diff --git a/cli/src/commands/start.rs b/cli/src/commands/start.rs index fc6827c2f6..9473d5c546 100644 --- a/cli/src/commands/start.rs +++ b/cli/src/commands/start.rs @@ -378,6 +378,8 @@ impl Start { if node_type.is_validator() { crate::helpers::check_open_files_limit(RECOMMENDED_MIN_NOFILES_LIMIT); } + // Check if the machine meets the minimum requirements for a validator. + crate::helpers::check_validator_machine(node_type, self.dev.is_some()); // Initialize the node. match node_type { diff --git a/cli/src/helpers/mod.rs b/cli/src/helpers/mod.rs index 065108dd14..016186b5ea 100644 --- a/cli/src/helpers/mod.rs +++ b/cli/src/helpers/mod.rs @@ -24,6 +24,8 @@ pub use logger::*; pub mod updater; pub use updater::*; +use snarkos_node::router::messages::NodeType; + #[cfg(target_family = "unix")] use colored::*; #[cfg(target_family = "unix")] @@ -63,3 +65,93 @@ pub fn check_open_files_limit(minimum: u64) { } }; } + +#[cfg(target_family = "unix")] +#[derive(Debug)] +pub(crate) enum DriveType { + SSD, + HDD, + Unknown, +} + +/// Returns the drive type of the given device. +#[cfg(target_family = "unix")] +pub(crate) fn detect_drive_type(device: &str) -> Result { + let path = format!("/sys/block/{}/queue/rotational", device); + match std::fs::read_to_string(&path)?.trim() { + "0" => Ok(DriveType::SSD), + "1" => Ok(DriveType::HDD), + _ => Ok(DriveType::Unknown), + } +} + +/// Returns `true` if the current system is a NVMe system. +#[cfg(target_family = "unix")] +pub(crate) fn is_nvme() -> Result { + let path = "/sys/class/nvme/"; + Ok(std::fs::metadata(path)?.is_dir()) +} + +/// Returns the RAM memory in GiB. +pub(crate) fn detect_ram_memory() -> Result { + let ram_kib = sys_info::mem_info()?.total; + let ram_mib = ram_kib / 1024; + Ok(ram_mib / 1024) +} + +/// Ensures the current system meets the minimum requirements for a validator. +#[rustfmt::skip] +pub(crate) fn check_validator_machine(node_type: NodeType, is_dev: bool) { + // If the node is a validator, ensure it meets the minimum requirements. + if node_type.is_validator() { + // Ensure the system is a Linux-based system. + // Note: While macOS is not officially supported, we allow it for development purposes. + if !cfg!(target_os = "linux") && !cfg!(target_os = "macos") { + let message = "⚠️ The operating system of this machine is not supported for a validator (Ubuntu required)\n".to_string(); + match is_dev { + true => println!("{}", message.yellow().bold()), + false => panic!("{message} in production mode"), + } + } + // Retrieve the number of cores. + let num_cores = num_cpus::get(); + // Enforce the minimum number of cores. + let min_num_cores = 32; + if num_cores < min_num_cores { + let message = format!("⚠️ The number of cores ({num_cores} cores) on this machine is insufficient for a validator (minimum {min_num_cores} cores)\n"); + match is_dev { + true => println!("{}", message.yellow().bold()), + false => panic!("{message} in production mode"), + } + } + // Enforce the minimum amount of RAM. + if let Ok(ram) = crate::helpers::detect_ram_memory() { + let min_ram = 64; + if ram < min_ram { + let message = format!("⚠️ The amount of RAM ({ram} GB) on this machine is insufficient for a validator (minimum {min_ram} GB)\n"); + match is_dev { + true => println!("{}", message.yellow().bold()), + false => panic!("{message} in production mode"), + } + } + } + // Enforce the required drive type. + #[cfg(target_family = "unix")] + if let Ok(crate::helpers::DriveType::HDD) = crate::helpers::detect_drive_type("sda") { + let message = "⚠️ The drive type of this machine is an HDD, and is insufficient for a validator (NVMe SSD required)\n".to_string(); + match is_dev { + true => println!("{}", message.yellow().bold()), + false => panic!("{message} in production mode"), + } + } + // Enforce the drive. + #[cfg(target_family = "unix")] + if let Ok(false) = crate::helpers::is_nvme() { + let message = "⚠️ This machine does not have an NVMe drive, and is insufficient for a validator (NVMe SSD required)\n".to_string(); + match is_dev { + true => println!("{}", message.yellow().bold()), + false => panic!("{message} in production mode"), + } + } + } +}