* Improve check for Apple M1 silicon under Rosetta (cherry picked from commit59641623d1
) # Conflicts: # core/src/validator.rs * test-validator: start logging asap (cherry picked from commitee65ffb3c8
) * test-validator: move feature check earlier in startup (cherry picked from commite641f257ef
) * validator: add avx2 runtime check (cherry picked from commitc435f7b3e3
) * validator: start logging asap (cherry picked from commited8285c096
) * validator: check target CPU features earlier (cherry picked from commit8ed0cd0fff
) * validator: remove disused cuda config argument (cherry picked from commit71f6d839f9
) Co-authored-by: Trent Nelson <trent@solana.com>
This commit is contained in:
@ -120,7 +120,6 @@ pub struct ValidatorConfig {
|
|||||||
pub max_genesis_archive_unpacked_size: u64,
|
pub max_genesis_archive_unpacked_size: u64,
|
||||||
pub wal_recovery_mode: Option<BlockstoreRecoveryMode>,
|
pub wal_recovery_mode: Option<BlockstoreRecoveryMode>,
|
||||||
pub poh_verify: bool, // Perform PoH verification during blockstore processing at boo
|
pub poh_verify: bool, // Perform PoH verification during blockstore processing at boo
|
||||||
pub cuda: bool,
|
|
||||||
pub require_tower: bool,
|
pub require_tower: bool,
|
||||||
pub tower_path: Option<PathBuf>,
|
pub tower_path: Option<PathBuf>,
|
||||||
pub debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
pub debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
||||||
@ -177,7 +176,6 @@ impl Default for ValidatorConfig {
|
|||||||
max_genesis_archive_unpacked_size: MAX_GENESIS_ARCHIVE_UNPACKED_SIZE,
|
max_genesis_archive_unpacked_size: MAX_GENESIS_ARCHIVE_UNPACKED_SIZE,
|
||||||
wal_recovery_mode: None,
|
wal_recovery_mode: None,
|
||||||
poh_verify: true,
|
poh_verify: true,
|
||||||
cuda: false,
|
|
||||||
require_tower: false,
|
require_tower: false,
|
||||||
tower_path: None,
|
tower_path: None,
|
||||||
debug_keys: None,
|
debug_keys: None,
|
||||||
@ -302,8 +300,6 @@ impl Validator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
report_target_features();
|
|
||||||
|
|
||||||
for cluster_entrypoint in &cluster_entrypoints {
|
for cluster_entrypoint in &cluster_entrypoints {
|
||||||
info!("entrypoint: {:?}", cluster_entrypoint);
|
info!("entrypoint: {:?}", cluster_entrypoint);
|
||||||
}
|
}
|
||||||
@ -1419,7 +1415,26 @@ fn wait_for_supermajority(
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_target_features() {
|
fn is_rosetta_emulated() -> bool {
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
use std::str::FromStr;
|
||||||
|
std::process::Command::new("sysctl")
|
||||||
|
.args(&["-in", "sysctl.proc_translated"])
|
||||||
|
.output()
|
||||||
|
.map_err(|_| ())
|
||||||
|
.and_then(|output| String::from_utf8(output.stdout).map_err(|_| ()))
|
||||||
|
.and_then(|stdout| u8::from_str(stdout.trim()).map_err(|_| ()))
|
||||||
|
.map(|enabled| enabled == 1)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
{
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report_target_features() {
|
||||||
warn!(
|
warn!(
|
||||||
"CUDA is {}abled",
|
"CUDA is {}abled",
|
||||||
if solana_perf::perf_libs::api().is_some() {
|
if solana_perf::perf_libs::api().is_some() {
|
||||||
@ -1429,40 +1444,47 @@ fn report_target_features() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// We exclude Mac OS here to be compatible with computers that have Mac M1 chips.
|
if !is_rosetta_emulated() {
|
||||||
// For these computers, one must install rust/cargo/brew etc. using Rosetta 2,
|
|
||||||
// which allows them to run software targeted for x86_64 on an aarch64.
|
|
||||||
// Hence the code below will run on these machines (target_arch="x86_64")
|
|
||||||
// if we don't exclude with target_os="macos".
|
|
||||||
//
|
|
||||||
// It's going to require more more work to get Solana building
|
|
||||||
// on Mac M1's without Rosetta,
|
|
||||||
// and when that happens we should remove this
|
|
||||||
// (the feature flag for code targeting that is target_arch="aarch64")
|
|
||||||
#[cfg(all(
|
|
||||||
any(target_arch = "x86", target_arch = "x86_64"),
|
|
||||||
not(target_os = "macos")
|
|
||||||
))]
|
|
||||||
{
|
|
||||||
unsafe { check_avx() };
|
unsafe { check_avx() };
|
||||||
|
unsafe { check_avx2() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validator binaries built on a machine with AVX support will generate invalid opcodes
|
// Validator binaries built on a machine with AVX support will generate invalid opcodes
|
||||||
// when run on machines without AVX causing a non-obvious process abort. Instead detect
|
// when run on machines without AVX causing a non-obvious process abort. Instead detect
|
||||||
// the mismatch and error cleanly.
|
// the mismatch and error cleanly.
|
||||||
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
#[target_feature(enable = "avx")]
|
#[target_feature(enable = "avx")]
|
||||||
unsafe fn check_avx() {
|
unsafe fn check_avx() {
|
||||||
if is_x86_feature_detected!("avx") {
|
if is_x86_feature_detected!("avx") {
|
||||||
info!("AVX detected");
|
info!("AVX detected");
|
||||||
} else {
|
} else {
|
||||||
error!(
|
error!(
|
||||||
"Your machine does not have AVX support, please rebuild from source on your machine"
|
"Incompatible CPU detected: missing AVX support. Please build from source on the target"
|
||||||
);
|
);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||||
|
unsafe fn check_avx() {}
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
|
#[target_feature(enable = "avx2")]
|
||||||
|
unsafe fn check_avx2() {
|
||||||
|
if is_x86_feature_detected!("avx2") {
|
||||||
|
info!("AVX2 detected");
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
"Incompatible CPU detected: missing AVX2 support. Please build from source on the target"
|
||||||
|
);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||||
|
unsafe fn check_avx2() {}
|
||||||
|
|
||||||
// Get the activated stake percentage (based on the provided bank) that is visible in gossip
|
// Get the activated stake percentage (based on the provided bank) that is visible in gossip
|
||||||
fn get_stake_percent_in_gossip(bank: &Bank, cluster_info: &ClusterInfo, log: bool) -> u64 {
|
fn get_stake_percent_in_gossip(bank: &Bank, cluster_info: &ClusterInfo, log: bool) -> u64 {
|
||||||
let mut online_stake = 0;
|
let mut online_stake = 0;
|
||||||
|
@ -36,7 +36,6 @@ pub fn safe_clone_config(config: &ValidatorConfig) -> ValidatorConfig {
|
|||||||
max_genesis_archive_unpacked_size: config.max_genesis_archive_unpacked_size,
|
max_genesis_archive_unpacked_size: config.max_genesis_archive_unpacked_size,
|
||||||
wal_recovery_mode: config.wal_recovery_mode.clone(),
|
wal_recovery_mode: config.wal_recovery_mode.clone(),
|
||||||
poh_verify: config.poh_verify,
|
poh_verify: config.poh_verify,
|
||||||
cuda: config.cuda,
|
|
||||||
require_tower: config.require_tower,
|
require_tower: config.require_tower,
|
||||||
tower_path: config.tower_path.clone(),
|
tower_path: config.tower_path.clone(),
|
||||||
debug_keys: config.debug_keys.clone(),
|
debug_keys: config.debug_keys.clone(),
|
||||||
|
@ -282,6 +282,112 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
|
let ledger_path = value_t_or_exit!(matches, "ledger_path", PathBuf);
|
||||||
|
let reset_ledger = matches.is_present("reset");
|
||||||
|
let output = if matches.is_present("quiet") {
|
||||||
|
Output::None
|
||||||
|
} else if matches.is_present("log") {
|
||||||
|
Output::Log
|
||||||
|
} else {
|
||||||
|
Output::Dashboard
|
||||||
|
};
|
||||||
|
let mut ledger_fd_lock = FdLock::new(fs::File::open(&ledger_path).unwrap());
|
||||||
|
let _ledger_lock = ledger_fd_lock.try_lock().unwrap_or_else(|_| {
|
||||||
|
println!(
|
||||||
|
"Error: Unable to lock {} directory. Check if another validator is running",
|
||||||
|
ledger_path.display()
|
||||||
|
);
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
if reset_ledger {
|
||||||
|
remove_directory_contents(&ledger_path).unwrap_or_else(|err| {
|
||||||
|
println!("Error: Unable to remove {}: {}", ledger_path.display(), err);
|
||||||
|
exit(1);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
solana_runtime::snapshot_utils::remove_tmp_snapshot_archives(&ledger_path);
|
||||||
|
|
||||||
|
let validator_log_symlink = ledger_path.join("validator.log");
|
||||||
|
let logfile = if output != Output::Log {
|
||||||
|
let validator_log_with_timestamp = format!(
|
||||||
|
"validator-{}.log",
|
||||||
|
SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_millis()
|
||||||
|
);
|
||||||
|
|
||||||
|
let _ = fs::remove_file(&validator_log_symlink);
|
||||||
|
symlink::symlink_file(&validator_log_with_timestamp, &validator_log_symlink).unwrap();
|
||||||
|
|
||||||
|
Some(
|
||||||
|
ledger_path
|
||||||
|
.join(validator_log_with_timestamp)
|
||||||
|
.into_os_string()
|
||||||
|
.into_string()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let _logger_thread = redirect_stderr_to_file(logfile);
|
||||||
|
|
||||||
|
if !ledger_path.exists() {
|
||||||
|
fs::create_dir(&ledger_path).unwrap_or_else(|err| {
|
||||||
|
println!(
|
||||||
|
"Error: Unable to create directory {}: {}",
|
||||||
|
ledger_path.display(),
|
||||||
|
err
|
||||||
|
);
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ledger_fd_lock = FdLock::new(fs::File::open(&ledger_path).unwrap());
|
||||||
|
let _ledger_lock = ledger_fd_lock.try_lock().unwrap_or_else(|_| {
|
||||||
|
println!(
|
||||||
|
"Error: Unable to lock {} directory. Check if another validator is running",
|
||||||
|
ledger_path.display()
|
||||||
|
);
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
if reset_ledger {
|
||||||
|
remove_directory_contents(&ledger_path).unwrap_or_else(|err| {
|
||||||
|
println!("Error: Unable to remove {}: {}", ledger_path.display(), err);
|
||||||
|
exit(1);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
solana_runtime::snapshot_utils::remove_tmp_snapshot_archives(&ledger_path);
|
||||||
|
|
||||||
|
let validator_log_symlink = ledger_path.join("validator.log");
|
||||||
|
let logfile = if output != Output::Log {
|
||||||
|
let validator_log_with_timestamp = format!(
|
||||||
|
"validator-{}.log",
|
||||||
|
SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_millis()
|
||||||
|
);
|
||||||
|
|
||||||
|
let _ = fs::remove_file(&validator_log_symlink);
|
||||||
|
symlink::symlink_file(&validator_log_with_timestamp, &validator_log_symlink).unwrap();
|
||||||
|
|
||||||
|
Some(
|
||||||
|
ledger_path
|
||||||
|
.join(validator_log_with_timestamp)
|
||||||
|
.into_os_string()
|
||||||
|
.into_string()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let _logger_thread = redirect_stderr_to_file(logfile);
|
||||||
|
|
||||||
|
solana_core::validator::report_target_features();
|
||||||
|
|
||||||
// TODO: Ideally test-validator should *only* allow private addresses.
|
// TODO: Ideally test-validator should *only* allow private addresses.
|
||||||
let socket_addr_space = SocketAddrSpace::new(/*allow_private_addr=*/ true);
|
let socket_addr_space = SocketAddrSpace::new(/*allow_private_addr=*/ true);
|
||||||
let cli_config = if let Some(config_file) = matches.value_of("config_file") {
|
let cli_config = if let Some(config_file) = matches.value_of("config_file") {
|
||||||
@ -302,15 +408,6 @@ fn main() {
|
|||||||
.unwrap_or_else(|_| (Keypair::new().pubkey(), true))
|
.unwrap_or_else(|_| (Keypair::new().pubkey(), true))
|
||||||
});
|
});
|
||||||
|
|
||||||
let ledger_path = value_t_or_exit!(matches, "ledger_path", PathBuf);
|
|
||||||
let reset_ledger = matches.is_present("reset");
|
|
||||||
let output = if matches.is_present("quiet") {
|
|
||||||
Output::None
|
|
||||||
} else if matches.is_present("log") {
|
|
||||||
Output::Log
|
|
||||||
} else {
|
|
||||||
Output::Dashboard
|
|
||||||
};
|
|
||||||
let rpc_port = value_t_or_exit!(matches, "rpc_port", u16);
|
let rpc_port = value_t_or_exit!(matches, "rpc_port", u16);
|
||||||
let faucet_port = value_t_or_exit!(matches, "faucet_port", u16);
|
let faucet_port = value_t_or_exit!(matches, "faucet_port", u16);
|
||||||
let slots_per_epoch = value_t!(matches, "slots_per_epoch", Slot).ok();
|
let slots_per_epoch = value_t!(matches, "slots_per_epoch", Slot).ok();
|
||||||
@ -394,59 +491,6 @@ fn main() {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if !ledger_path.exists() {
|
|
||||||
fs::create_dir(&ledger_path).unwrap_or_else(|err| {
|
|
||||||
println!(
|
|
||||||
"Error: Unable to create directory {}: {}",
|
|
||||||
ledger_path.display(),
|
|
||||||
err
|
|
||||||
);
|
|
||||||
exit(1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut ledger_fd_lock = FdLock::new(fs::File::open(&ledger_path).unwrap());
|
|
||||||
let _ledger_lock = ledger_fd_lock.try_lock().unwrap_or_else(|_| {
|
|
||||||
println!(
|
|
||||||
"Error: Unable to lock {} directory. Check if another validator is running",
|
|
||||||
ledger_path.display()
|
|
||||||
);
|
|
||||||
exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
if reset_ledger {
|
|
||||||
remove_directory_contents(&ledger_path).unwrap_or_else(|err| {
|
|
||||||
println!("Error: Unable to remove {}: {}", ledger_path.display(), err);
|
|
||||||
exit(1);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
solana_runtime::snapshot_utils::remove_tmp_snapshot_archives(&ledger_path);
|
|
||||||
|
|
||||||
let validator_log_symlink = ledger_path.join("validator.log");
|
|
||||||
let logfile = if output != Output::Log {
|
|
||||||
let validator_log_with_timestamp = format!(
|
|
||||||
"validator-{}.log",
|
|
||||||
SystemTime::now()
|
|
||||||
.duration_since(UNIX_EPOCH)
|
|
||||||
.unwrap()
|
|
||||||
.as_millis()
|
|
||||||
);
|
|
||||||
|
|
||||||
let _ = fs::remove_file(&validator_log_symlink);
|
|
||||||
symlink::symlink_file(&validator_log_with_timestamp, &validator_log_symlink).unwrap();
|
|
||||||
|
|
||||||
Some(
|
|
||||||
ledger_path
|
|
||||||
.join(validator_log_with_timestamp)
|
|
||||||
.into_os_string()
|
|
||||||
.into_string()
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let _logger_thread = redirect_stderr_to_file(logfile);
|
|
||||||
|
|
||||||
let faucet_lamports = sol_to_lamports(value_of(&matches, "faucet_sol").unwrap());
|
let faucet_lamports = sol_to_lamports(value_of(&matches, "faucet_sol").unwrap());
|
||||||
let faucet_keypair_file = ledger_path.join("faucet-keypair.json");
|
let faucet_keypair_file = ledger_path.join("faucet-keypair.json");
|
||||||
if !faucet_keypair_file.exists() {
|
if !faucet_keypair_file.exists() {
|
||||||
|
@ -2076,6 +2076,33 @@ pub fn main() {
|
|||||||
.exit();
|
.exit();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
let logfile = {
|
||||||
|
let logfile = matches
|
||||||
|
.value_of("logfile")
|
||||||
|
.map(|s| s.into())
|
||||||
|
.unwrap_or_else(|| format!("solana-validator-{}.log", identity_keypair.pubkey()));
|
||||||
|
|
||||||
|
if logfile == "-" {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
println!("log file: {}", logfile);
|
||||||
|
Some(logfile)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let use_progress_bar = logfile.is_none();
|
||||||
|
let _logger_thread = redirect_stderr_to_file(logfile);
|
||||||
|
|
||||||
|
info!("{} {}", crate_name!(), solana_version::version!());
|
||||||
|
info!("Starting validator with: {:#?}", std::env::args_os());
|
||||||
|
|
||||||
|
let cuda = matches.is_present("cuda");
|
||||||
|
if cuda {
|
||||||
|
solana_perf::perf_libs::init_cuda();
|
||||||
|
enable_recycler_warming();
|
||||||
|
}
|
||||||
|
|
||||||
|
solana_core::validator::report_target_features();
|
||||||
|
|
||||||
let authorized_voter_keypairs = keypairs_of(&matches, "authorized_voter_keypairs")
|
let authorized_voter_keypairs = keypairs_of(&matches, "authorized_voter_keypairs")
|
||||||
.map(|keypairs| keypairs.into_iter().map(Arc::new).collect())
|
.map(|keypairs| keypairs.into_iter().map(Arc::new).collect())
|
||||||
.unwrap_or_else(|| vec![identity_keypair.clone()]);
|
.unwrap_or_else(|| vec![identity_keypair.clone()]);
|
||||||
@ -2197,7 +2224,6 @@ pub fn main() {
|
|||||||
require_tower: matches.is_present("require_tower"),
|
require_tower: matches.is_present("require_tower"),
|
||||||
tower_path: value_t!(matches, "tower", PathBuf).ok(),
|
tower_path: value_t!(matches, "tower", PathBuf).ok(),
|
||||||
dev_halt_at_slot: value_t!(matches, "dev_halt_at_slot", Slot).ok(),
|
dev_halt_at_slot: value_t!(matches, "dev_halt_at_slot", Slot).ok(),
|
||||||
cuda: matches.is_present("cuda"),
|
|
||||||
expected_genesis_hash: matches
|
expected_genesis_hash: matches
|
||||||
.value_of("expected_genesis_hash")
|
.value_of("expected_genesis_hash")
|
||||||
.map(|s| Hash::from_str(s).unwrap()),
|
.map(|s| Hash::from_str(s).unwrap()),
|
||||||
@ -2471,25 +2497,6 @@ pub fn main() {
|
|||||||
exit(1);
|
exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
let logfile = {
|
|
||||||
let logfile = matches
|
|
||||||
.value_of("logfile")
|
|
||||||
.map(|s| s.into())
|
|
||||||
.unwrap_or_else(|| format!("solana-validator-{}.log", identity_keypair.pubkey()));
|
|
||||||
|
|
||||||
if logfile == "-" {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
println!("log file: {}", logfile);
|
|
||||||
Some(logfile)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let use_progress_bar = logfile.is_none();
|
|
||||||
let _logger_thread = redirect_stderr_to_file(logfile);
|
|
||||||
|
|
||||||
info!("{} {}", crate_name!(), solana_version::version!());
|
|
||||||
info!("Starting validator with: {:#?}", std::env::args_os());
|
|
||||||
|
|
||||||
let start_progress = Arc::new(RwLock::new(ValidatorStartProgress::default()));
|
let start_progress = Arc::new(RwLock::new(ValidatorStartProgress::default()));
|
||||||
admin_rpc_service::run(
|
admin_rpc_service::run(
|
||||||
&ledger_path,
|
&ledger_path,
|
||||||
@ -2594,10 +2601,6 @@ pub fn main() {
|
|||||||
solana_metrics::set_host_id(identity_keypair.pubkey().to_string());
|
solana_metrics::set_host_id(identity_keypair.pubkey().to_string());
|
||||||
solana_metrics::set_panic_hook("validator");
|
solana_metrics::set_panic_hook("validator");
|
||||||
|
|
||||||
if validator_config.cuda {
|
|
||||||
solana_perf::perf_libs::init_cuda();
|
|
||||||
enable_recycler_warming();
|
|
||||||
}
|
|
||||||
solana_ledger::entry::init_poh();
|
solana_ledger::entry::init_poh();
|
||||||
solana_runtime::snapshot_utils::remove_tmp_snapshot_archives(&snapshot_output_dir);
|
solana_runtime::snapshot_utils::remove_tmp_snapshot_archives(&snapshot_output_dir);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user