diff --git a/.integration/src/lib.rs b/.integration/src/lib.rs index 63331370b1..9a88e3a490 100644 --- a/.integration/src/lib.rs +++ b/.integration/src/lib.rs @@ -42,7 +42,8 @@ mod tests { // Perform the sync. let rt = tokio::runtime::Runtime::new().unwrap(); rt.block_on(async { - let completed_height = sync_ledger_with_cdn(TEST_BASE_URL, ledger.clone()).await.unwrap(); + let completed_height = + sync_ledger_with_cdn(TEST_BASE_URL, ledger.clone(), Default::default()).await.unwrap(); assert_eq!(completed_height, ledger.latest_height()); }); } diff --git a/Cargo.lock b/Cargo.lock index 3df02cd144..3432296c86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,9 +219,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355" [[package]] name = "arrayref" @@ -270,9 +270,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" dependencies = [ "proc-macro2", "quote 1.0.33", @@ -1194,9 +1194,9 @@ checksum = "c1fd087255f739f4f1aeea69f11b72f8080e9c2e7645cd06955dad4a178a49e3" [[package]] name = "futures" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -1209,9 +1209,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -1219,15 +1219,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -1237,15 +1237,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote 1.0.33", @@ -1254,15 +1254,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" @@ -1272,9 +1272,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -2066,9 +2066,9 @@ dependencies = [ [[package]] name = "mockall" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a978c8292954bcb9347a4e28772c0a0621166a1598fc1be28ac0076a4bb810e" +checksum = "43766c2b5203b10de348ffe19f7e54564b64f3d6018ff7648d1e2d6d3a0f0a48" dependencies = [ "cfg-if", "downcast", @@ -2081,9 +2081,9 @@ dependencies = [ [[package]] name = "mockall_derive" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad2765371d0978ba4ace4ebef047baa62fc068b431e468444b5610dd441c639b" +checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" dependencies = [ "cfg-if", "proc-macro2", @@ -4668,18 +4668,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.51" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" +checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.51" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" +checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3" dependencies = [ "proc-macro2", "quote 1.0.33", diff --git a/Cargo.toml b/Cargo.toml index e7b0dadbb7..9660ed1550 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ jemalloc = [ "tikv-jemallocator" ] metrics = [ "snarkos-node-metrics", "snarkos-node/metrics" ] [dependencies.anyhow] -version = "1.0.75" +version = "1.0.76" [dependencies.clap] version = "4.4" diff --git a/README.md b/README.md index 301c069d6d..62eea7c704 100644 --- a/README.md +++ b/README.md @@ -66,13 +66,13 @@ The following are **minimum** requirements to run an Aleo node: - Provers: CUDA-enabled GPU (optional) - Validators: Not required at this time -Please note to run an Aleo Prover that is **competitive**, the machine will require more than these requirements. +Please note that in order to run an Aleo Prover that is **competitive**, the machine will need more than these requirements. ### 2.2 Installation Before beginning, please ensure your machine has `Rust v1.66+` installed. Instructions to [install Rust can be found here.](https://www.rust-lang.org/tools/install) -Start by cloning this Github repository: +Start by cloning this GitHub repository: ``` git clone https://github.com/AleoHQ/snarkOS.git --depth 1 ``` @@ -150,11 +150,11 @@ APrivateKey1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ### 3. I can't generate a new address ### - Before running the command above (`snarkos account new`) try `source ~/.bashrc` -- Also double-check the spelling of `snarkos`. Note the directory is `/snarkOS`, the command is `snarkos` +- Also double-check the spelling of `snarkos`. Note the directory is `/snarkOS`, and the command is `snarkos` ## 5. Command Line Interface -To run a node with custom settings, refer to the full list of options and flags available in the `snarkOS` CLI. +To run a node with custom settings, refer to the options and flags available in the `snarkOS` CLI. The full list of CLI flags and options can be viewed with `snarkos --help`: ``` @@ -225,7 +225,7 @@ In the fourth terminal, start the fourth validator by running: cargo run --release -- start --nodisplay --dev 3 --validator ``` -From here, this procedure can be used to further start up provers and clients. +From here, this procedure can be used to further start-up provers and clients. ### 6.2 Operations @@ -434,7 +434,7 @@ Thank you for helping make snarkOS better! -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome! ## 8. License diff --git a/account/Cargo.toml b/account/Cargo.toml index 01346141ad..966c0450bb 100644 --- a/account/Cargo.toml +++ b/account/Cargo.toml @@ -17,7 +17,7 @@ license = "Apache-2.0" edition = "2021" [dependencies.anyhow] -version = "1.0.75" +version = "1.0.76" [dependencies.colored] version = "2" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index eb62cc3ca7..25cea5fa09 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -27,7 +27,7 @@ default-features = false version = "1" [dependencies.anyhow] -version = "1.0.75" +version = "1.0.76" [dependencies.bincode] version = "1.0" diff --git a/cli/src/commands/developer/scan.rs b/cli/src/commands/developer/scan.rs index 38aa1e322f..d56c9cdbab 100644 --- a/cli/src/commands/developer/scan.rs +++ b/cli/src/commands/developer/scan.rs @@ -252,25 +252,41 @@ impl Scan { // Construct the runtime. let rt = tokio::runtime::Runtime::new()?; + // Create a placeholder shutdown flag. + let _shutdown = Default::default(); + // Scan the blocks via the CDN. rt.block_on(async move { - let _ = snarkos_node_cdn::load_blocks(&cdn, cdn_request_start, Some(cdn_request_end), move |block| { - // Check if the block is within the requested range. - if block.height() < start_height || block.height() > end_height { - return Ok(()); - } - - // Log the progress. - let percentage_complete = - block.height().saturating_sub(start_height) as f64 * 100.0 / total_blocks as f64; - print!("\rScanning {total_blocks} blocks for records ({percentage_complete:.2}% complete)..."); - stdout().flush()?; - - // Scan the block for records. - Self::scan_block(&block, &endpoint, private_key, &view_key, &address_x_coordinate, records.clone())?; - - Ok(()) - }) + let _ = snarkos_node_cdn::load_blocks( + &cdn, + cdn_request_start, + Some(cdn_request_end), + _shutdown, + move |block| { + // Check if the block is within the requested range. + if block.height() < start_height || block.height() > end_height { + return Ok(()); + } + + // Log the progress. + let percentage_complete = + block.height().saturating_sub(start_height) as f64 * 100.0 / total_blocks as f64; + print!("\rScanning {total_blocks} blocks for records ({percentage_complete:.2}% complete)..."); + stdout().flush()?; + + // Scan the block for records. + Self::scan_block( + &block, + &endpoint, + private_key, + &view_key, + &address_x_coordinate, + records.clone(), + )?; + + Ok(()) + }, + ) .await; }); diff --git a/display/Cargo.toml b/display/Cargo.toml index 8498da34b4..1fe8ea248a 100644 --- a/display/Cargo.toml +++ b/display/Cargo.toml @@ -17,7 +17,7 @@ license = "Apache-2.0" edition = "2021" [dependencies.anyhow] -version = "1.0.75" +version = "1.0.76" [dependencies.crossterm] version = "0.27" diff --git a/node/Cargo.toml b/node/Cargo.toml index 1fbec3d44a..b69de2db5e 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -33,7 +33,7 @@ version = "0.1.18" default-features = false [dependencies.anyhow] -version = "1.0.75" +version = "1.0.76" [dependencies.async-trait] version = "0.1" diff --git a/node/bft/Cargo.toml b/node/bft/Cargo.toml index ddf88bccb4..79fe9736df 100644 --- a/node/bft/Cargo.toml +++ b/node/bft/Cargo.toml @@ -21,7 +21,7 @@ default = [ ] metrics = [ "dep:metrics", "snarkos-node-bft-events/metrics" ] [dependencies.anyhow] -version = "1.0.70" +version = "1.0.76" [dependencies.async-recursion] version = "1.0" @@ -36,7 +36,7 @@ version = "1" version = "2" [dependencies.futures] -version = "0.3.29" +version = "0.3.30" features = [ "thread-pool" ] [dependencies.indexmap] @@ -177,4 +177,4 @@ features = [ "env-filter" ] version = "0.1" [dev-dependencies.mockall] -version = "0.12.0" +version = "0.12.1" diff --git a/node/bft/ledger-service/src/ledger.rs b/node/bft/ledger-service/src/ledger.rs index 658f10b49d..a34a7f2a08 100644 --- a/node/bft/ledger-service/src/ledger.rs +++ b/node/bft/ledger-service/src/ledger.rs @@ -26,19 +26,27 @@ use snarkvm::{ }; use indexmap::IndexMap; -use std::{fmt, ops::Range, sync::Arc}; +use std::{ + fmt, + ops::Range, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, +}; /// A core ledger service. pub struct CoreLedgerService> { ledger: Ledger, coinbase_verifying_key: Arc>, + shutdown: Arc, } impl> CoreLedgerService { /// Initializes a new core ledger service. - pub fn new(ledger: Ledger) -> Self { + pub fn new(ledger: Ledger, shutdown: Arc) -> Self { let coinbase_verifying_key = Arc::new(ledger.coinbase_puzzle().coinbase_verifying_key().clone()); - Self { ledger, coinbase_verifying_key } + Self { ledger, coinbase_verifying_key, shutdown } } } @@ -283,6 +291,11 @@ impl> LedgerService for CoreLedgerService< /// Adds the given block as the next block in the ledger. #[cfg(feature = "ledger-write")] fn advance_to_next_block(&self, block: &Block) -> Result<()> { + // If the Ctrl-C handler registered the signal, then skip advancing to the next block. + if self.shutdown.load(Ordering::Relaxed) { + bail!("Skipping advancing to block {} - The node is shutting down", block.height()); + } + // Advance to the next block. self.ledger.advance_to_next_block(block)?; tracing::info!("\n\nAdvanced to block {} at round {} - {}\n", block.height(), block.round(), block.hash()); Ok(()) diff --git a/node/bft/ledger-service/src/translucent.rs b/node/bft/ledger-service/src/translucent.rs index a86267ebbe..cf327a173f 100644 --- a/node/bft/ledger-service/src/translucent.rs +++ b/node/bft/ledger-service/src/translucent.rs @@ -26,7 +26,11 @@ use snarkvm::{ }, prelude::{narwhal::BatchCertificate, Field, Network, Result}, }; -use std::{fmt, ops::Range}; +use std::{ + fmt, + ops::Range, + sync::{atomic::AtomicBool, Arc}, +}; pub struct TranslucentLedgerService> { inner: CoreLedgerService, @@ -41,8 +45,8 @@ impl> fmt::Debug for TranslucentLedgerService impl> TranslucentLedgerService { /// Initializes a new ledger service wrapper. - pub fn new(ledger: Ledger) -> Self { - Self { inner: CoreLedgerService::new(ledger) } + pub fn new(ledger: Ledger, shutdown: Arc) -> Self { + Self { inner: CoreLedgerService::new(ledger, shutdown) } } } diff --git a/node/bft/src/gateway.rs b/node/bft/src/gateway.rs index 1733683f3c..d6b8c000d4 100644 --- a/node/bft/src/gateway.rs +++ b/node/bft/src/gateway.rs @@ -205,7 +205,7 @@ impl Gateway { .map_or_else(|_e| Committee::::MAX_COMMITTEE_SIZE as usize, |committee| committee.num_members()) } - /// The maxixmum number of events to cache. + /// The maximum number of events to cache. fn max_cache_events(&self) -> usize { self.max_cache_transmissions() } diff --git a/node/bft/tests/common/primary.rs b/node/bft/tests/common/primary.rs index 2d81fd45a8..421ef9390e 100644 --- a/node/bft/tests/common/primary.rs +++ b/node/bft/tests/common/primary.rs @@ -151,7 +151,7 @@ impl TestNetwork { for (id, account) in accounts.into_iter().enumerate() { let mut rng = TestRng::fixed(id as u64); let gen_ledger = genesis_ledger(gen_key, committee.clone(), balances.clone(), &mut rng); - let ledger = Arc::new(TranslucentLedgerService::new(gen_ledger)); + let ledger = Arc::new(TranslucentLedgerService::new(gen_ledger, Default::default())); let storage = Storage::new(ledger.clone(), Arc::new(BFTMemoryService::new()), MAX_GC_ROUNDS); let (primary, bft) = if config.bft { diff --git a/node/cdn/Cargo.toml b/node/cdn/Cargo.toml index 8b694478a2..cdd4ecad73 100644 --- a/node/cdn/Cargo.toml +++ b/node/cdn/Cargo.toml @@ -21,7 +21,7 @@ default = [ "parallel" ] parallel = [ "rayon" ] [dependencies.anyhow] -version = "1.0.75" +version = "1.0.76" [dependencies.backoff] version = "0.4" diff --git a/node/cdn/src/blocks.rs b/node/cdn/src/blocks.rs index 5ca83e6ca1..6477ee658e 100644 --- a/node/cdn/src/blocks.rs +++ b/node/cdn/src/blocks.rs @@ -29,7 +29,10 @@ use futures::{Future, StreamExt}; use parking_lot::RwLock; use reqwest::Client; use std::{ - sync::Arc, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, time::{Duration, Instant}, }; @@ -45,14 +48,16 @@ const NETWORK_ID: u16 = 3; pub async fn sync_ledger_with_cdn>( base_url: &str, ledger: Ledger, + shutdown: Arc, ) -> Result { // Fetch the node height. let start_height = ledger.latest_height() + 1; // Load the blocks from the CDN into the ledger. let ledger_clone = ledger.clone(); - let result = - load_blocks(base_url, start_height, None, move |block: Block| ledger_clone.advance_to_next_block(&block)) - .await; + let result = load_blocks(base_url, start_height, None, shutdown, move |block: Block| { + ledger_clone.advance_to_next_block(&block) + }) + .await; // TODO (howardwu): Find a way to resolve integrity failures. // If the sync failed, check the integrity of the ledger. @@ -90,6 +95,7 @@ pub async fn load_blocks( base_url: &str, start_height: u32, end_height: Option, + shutdown: Arc, process: impl FnMut(Block) -> Result<()> + Clone + Send + Sync + 'static, ) -> Result { // If the network is not supported, return. @@ -148,6 +154,15 @@ pub async fn load_blocks( futures::stream::iter(cdn_range.clone().step_by(BLOCKS_PER_FILE as usize)) .map(|start| { + // If the Ctrl-C handler registered the signal, then stop the sync. + if shutdown.load(Ordering::Relaxed) { + info!("Skipping block sync (at {start}) - The node is shutting down"); + // Note: Calling 'exit' from here is not ideal, but the CDN sync happens before + // the node is even initialized, so it doesn't result in any other + // functionalities being shut down abruptly. + std::process::exit(0); + } + // Prepare the end height. let end = start + BLOCKS_PER_FILE; @@ -416,7 +431,7 @@ mod tests { let rt = tokio::runtime::Runtime::new().unwrap(); rt.block_on(async { - let completed_height = load_blocks(TEST_BASE_URL, start, end, process).await.unwrap(); + let completed_height = load_blocks(TEST_BASE_URL, start, end, Default::default(), process).await.unwrap(); assert_eq!(blocks.read().len(), expected); if expected > 0 { assert_eq!(blocks.read().last().unwrap().height(), completed_height); diff --git a/node/consensus/Cargo.toml b/node/consensus/Cargo.toml index baeea6a5e3..b8091ffa6b 100644 --- a/node/consensus/Cargo.toml +++ b/node/consensus/Cargo.toml @@ -21,7 +21,7 @@ default = [ ] metrics = [ "dep:metrics" ] [dependencies.anyhow] -version = "1.0.75" +version = "1.0.76" [dependencies.colored] version = "2" diff --git a/node/rest/Cargo.toml b/node/rest/Cargo.toml index 1514567ef3..db62ef4e2b 100644 --- a/node/rest/Cargo.toml +++ b/node/rest/Cargo.toml @@ -21,7 +21,7 @@ default = [ "parallel" ] parallel = [ "rayon" ] [dependencies.anyhow] -version = "1.0.75" +version = "1.0.76" [dependencies.axum] version = "0.7" diff --git a/node/router/Cargo.toml b/node/router/Cargo.toml index 95aa976fea..2f10df5347 100644 --- a/node/router/Cargo.toml +++ b/node/router/Cargo.toml @@ -21,7 +21,7 @@ test = [ ] metrics = [ "dep:metrics" ] [dependencies.anyhow] -version = "1.0.75" +version = "1.0.76" [dependencies.async-trait] version = "0.1" @@ -36,7 +36,7 @@ version = "1" version = "2" [dependencies.futures] -version = "0.3.29" +version = "0.3.30" features = [ "thread-pool" ] [dependencies.indexmap] diff --git a/node/src/client/mod.rs b/node/src/client/mod.rs index dcbef9cb97..1878deaeaa 100644 --- a/node/src/client/mod.rs +++ b/node/src/client/mod.rs @@ -83,8 +83,11 @@ impl> Client { cdn: Option, dev: Option, ) -> Result { + // Prepare the shutdown flag. + let shutdown: Arc = Default::default(); + // Initialize the signal handler. - let signal_node = Self::handle_signals(); + let signal_node = Self::handle_signals(shutdown.clone()); // Initialize the ledger. let ledger = Ledger::::load(genesis.clone(), dev)?; @@ -93,14 +96,16 @@ impl> Client { // Initialize the CDN. if let Some(base_url) = cdn { // Sync the ledger with the CDN. - if let Err((_, error)) = snarkos_node_cdn::sync_ledger_with_cdn(&base_url, ledger.clone()).await { + if let Err((_, error)) = + snarkos_node_cdn::sync_ledger_with_cdn(&base_url, ledger.clone(), shutdown.clone()).await + { crate::log_clean_error(dev); return Err(error); } } // Initialize the ledger service. - let ledger_service = Arc::new(CoreLedgerService::::new(ledger.clone())); + let ledger_service = Arc::new(CoreLedgerService::::new(ledger.clone(), shutdown.clone())); // Initialize the sync module. let sync = BlockSync::new(BlockSyncMode::Router, ledger_service.clone()); @@ -125,7 +130,7 @@ impl> Client { genesis, coinbase_puzzle, handles: Default::default(), - shutdown: Default::default(), + shutdown, }; // Initialize the REST server. diff --git a/node/src/prover/mod.rs b/node/src/prover/mod.rs index f7dd2bc2db..4d542b62d0 100644 --- a/node/src/prover/mod.rs +++ b/node/src/prover/mod.rs @@ -90,8 +90,11 @@ impl> Prover { genesis: Block, dev: Option, ) -> Result { + // Prepare the shutdown flag. + let shutdown: Arc = Default::default(); + // Initialize the signal handler. - let signal_node = Self::handle_signals(); + let signal_node = Self::handle_signals(shutdown.clone()); // Initialize the ledger service. let ledger_service = Arc::new(ProverLedgerService::new()); @@ -123,7 +126,7 @@ impl> Prover { puzzle_instances: Default::default(), max_puzzle_instances: u8::try_from(max_puzzle_instances)?, handles: Default::default(), - shutdown: Default::default(), + shutdown, _phantom: Default::default(), }; // Initialize the routing. diff --git a/node/src/traits.rs b/node/src/traits.rs index a8960ffeb9..12947ca3f2 100644 --- a/node/src/traits.rs +++ b/node/src/traits.rs @@ -16,7 +16,13 @@ use snarkos_node_router::{messages::NodeType, Routing}; use snarkvm::prelude::{Address, Network, PrivateKey, ViewKey}; use once_cell::sync::OnceCell; -use std::sync::Arc; +use std::{ + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, + time::Duration, +}; #[async_trait] pub trait NodeInterface: Routing { @@ -46,8 +52,9 @@ pub trait NodeInterface: Routing { } /// Handles OS signals for the node to intercept and perform a clean shutdown. + /// The optional `shutdown_flag` flag can be used to cleanly terminate the syncing process. /// Note: Only Ctrl-C is supported; it should work on both Unix-family systems and Windows. - fn handle_signals() -> Arc> { + fn handle_signals(shutdown_flag: Arc) -> Arc> { // In order for the signal handler to be started as early as possible, a reference to the node needs // to be passed to it at a later time. let node: Arc> = Default::default(); @@ -56,9 +63,17 @@ pub trait NodeInterface: Routing { tokio::task::spawn(async move { match tokio::signal::ctrl_c().await { Ok(()) => { - if let Some(node) = node_clone.get() { - node.shut_down().await; + match node_clone.get() { + // If the node is already initialized, then shut it down. + Some(node) => node.shut_down().await, + // Otherwise, if the node is not yet initialized, then set the shutdown flag directly. + None => shutdown_flag.store(true, Ordering::Relaxed), } + + // A best-effort attempt to let any ongoing activity conclude. + tokio::time::sleep(Duration::from_secs(3)).await; + + // Terminate the process. std::process::exit(0); } Err(error) => error!("tokio::signal::ctrl_c encountered an error: {}", error), diff --git a/node/src/validator/mod.rs b/node/src/validator/mod.rs index de3eb2d4a3..ee1ab20c3e 100644 --- a/node/src/validator/mod.rs +++ b/node/src/validator/mod.rs @@ -83,8 +83,11 @@ impl> Validator { cdn: Option, dev: Option, ) -> Result { + // Prepare the shutdown flag. + let shutdown: Arc = Default::default(); + // Initialize the signal handler. - let signal_node = Self::handle_signals(); + let signal_node = Self::handle_signals(shutdown.clone()); // Initialize the ledger. let ledger = Ledger::load(genesis, dev)?; @@ -93,14 +96,16 @@ impl> Validator { // Initialize the CDN. if let Some(base_url) = cdn { // Sync the ledger with the CDN. - if let Err((_, error)) = snarkos_node_cdn::sync_ledger_with_cdn(&base_url, ledger.clone()).await { + if let Err((_, error)) = + snarkos_node_cdn::sync_ledger_with_cdn(&base_url, ledger.clone(), shutdown.clone()).await + { crate::log_clean_error(dev); return Err(error); } } // Initialize the ledger service. - let ledger_service = Arc::new(CoreLedgerService::new(ledger.clone())); + let ledger_service = Arc::new(CoreLedgerService::new(ledger.clone(), shutdown.clone())); // Initialize the sync module. let sync = BlockSync::new(BlockSyncMode::Gateway, ledger_service.clone()); @@ -130,7 +135,7 @@ impl> Validator { rest: None, sync, handles: Default::default(), - shutdown: Default::default(), + shutdown, }; // Initialize the transaction pool. node.initialize_transaction_pool(dev)?;