diff --git a/Cargo.lock b/Cargo.lock index 3238a9097d86e1..4c8dfa75cb0fde 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,6 +219,7 @@ name = "agave-validator" version = "2.1.0" dependencies = [ "agave-geyser-plugin-interface", + "assert_cmd", "chrono", "clap 2.33.3", "console", @@ -236,6 +237,7 @@ dependencies = [ "libloading", "log", "num_cpus", + "predicates", "rand 0.8.5", "rayon", "serde", @@ -277,6 +279,7 @@ dependencies = [ "solana-vote-program", "spl-token-2022", "symlink", + "tempfile", "thiserror", "tikv-jemallocator", "tokio", diff --git a/validator/Cargo.toml b/validator/Cargo.toml index 6222435906a31d..39e5c4d1b19d0e 100644 --- a/validator/Cargo.toml +++ b/validator/Cargo.toml @@ -69,10 +69,13 @@ thiserror = { workspace = true } tokio = { workspace = true } [dev-dependencies] +assert_cmd = { workspace = true } +predicates = { workspace = true } solana-account-decoder = { workspace = true } solana-inline-spl = { workspace = true } solana-runtime = { workspace = true, features = ["dev-context-only-utils"] } spl-token-2022 = { workspace = true, features = ["no-entrypoint"] } +tempfile = { workspace = true } [target.'cfg(not(target_env = "msvc"))'.dependencies] jemallocator = { workspace = true } diff --git a/validator/src/main.rs b/validator/src/main.rs index f6cdcdd928eb3a..78903288abcb0c 100644 --- a/validator/src/main.rs +++ b/validator/src/main.rs @@ -1593,6 +1593,23 @@ pub fn main() { } else { &ledger_path }; + let snapshots_dir = fs::canonicalize(snapshots_dir).unwrap_or_else(|err| { + eprintln!( + "Failed to canonicalize snapshots path '{}': {err}", + snapshots_dir.display(), + ); + exit(1); + }); + if account_paths + .iter() + .any(|account_path| account_path == &snapshots_dir) + { + eprintln!( + "Failed: The --accounts and --snapshots paths must be unique since they \ + both create 'snapshots' subdirectories, otherwise there may be collisions", + ); + exit(1); + } let bank_snapshots_dir = snapshots_dir.join("snapshots"); fs::create_dir_all(&bank_snapshots_dir).unwrap_or_else(|err| { @@ -1603,13 +1620,12 @@ pub fn main() { exit(1); }); - let full_snapshot_archives_dir = PathBuf::from( + let full_snapshot_archives_dir = if let Some(full_snapshot_archive_path) = matches.value_of("full_snapshot_archive_path") { - Path::new(full_snapshot_archive_path) + PathBuf::from(full_snapshot_archive_path) } else { - snapshots_dir - }, - ); + snapshots_dir.clone() + }; fs::create_dir_all(&full_snapshot_archives_dir).unwrap_or_else(|err| { eprintln!( "Failed to create full snapshot archives directory '{}': {err}", @@ -1618,15 +1634,13 @@ pub fn main() { exit(1); }); - let incremental_snapshot_archives_dir = PathBuf::from( - if let Some(incremental_snapshot_archive_path) = - matches.value_of("incremental_snapshot_archive_path") - { - Path::new(incremental_snapshot_archive_path) - } else { - snapshots_dir - }, - ); + let incremental_snapshot_archives_dir = if let Some(incremental_snapshot_archive_path) = + matches.value_of("incremental_snapshot_archive_path") + { + PathBuf::from(incremental_snapshot_archive_path) + } else { + snapshots_dir.clone() + }; fs::create_dir_all(&incremental_snapshot_archives_dir).unwrap_or_else(|err| { eprintln!( "Failed to create incremental snapshot archives directory '{}': {err}", diff --git a/validator/tests/cli.rs b/validator/tests/cli.rs new file mode 100644 index 00000000000000..3757df96df1d8d --- /dev/null +++ b/validator/tests/cli.rs @@ -0,0 +1,36 @@ +use { + assert_cmd::prelude::*, + solana_sdk::signer::keypair::{write_keypair_file, Keypair}, + std::process::Command, + tempfile::TempDir, +}; + +#[test] +fn test_use_the_same_path_for_accounts_and_snapshots() { + let temp_dir = TempDir::new().unwrap(); + let temp_dir_path = temp_dir.path(); + + let id_json_path = temp_dir_path.join("id.json"); + let id_json_str = id_json_path.to_str().unwrap(); + + let keypair = Keypair::new(); + write_keypair_file(&keypair, id_json_str).unwrap(); + + let temp_dir_str = temp_dir_path.to_str().unwrap(); + + let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap(); + cmd.args([ + "--identity", + id_json_str, + "--log", + "-", + "--no-voting", + "--accounts", + temp_dir_str, + "--snapshots", + temp_dir_str, + ]); + cmd.assert().failure().stderr(predicates::str::contains( + "The --accounts and --snapshots paths must be unique", + )); +}