* windows: Make solana-test-validator work (#20099)
* windows: Make solana-test-validator work
The important changes to get this going on Windows:
* ledger lock needs to be done on a file instead of the directory
* IPC service needs to use the Windows pipe naming scheme
* always disable the JIT
* file logging not possible yet because we can't redirect stderr,
but this will change once env_logger fixes the pipe output target!
* Integrate review feedback
(cherry picked from commit 567f30aa1a
)
# Conflicts:
# validator/src/bin/solana-test-validator.rs
# validator/src/lib.rs
# validator/src/main.rs
* Fix merge conflicts
Co-authored-by: Jon Cinque <jon.cinque@gmail.com>
This commit is contained in:
@ -108,7 +108,7 @@ fn make_accounts_txs(txes: usize, mint_keypair: &Keypair, hash: Hash) -> Vec<Tra
|
|||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
let mut new = dummy.clone();
|
let mut new = dummy.clone();
|
||||||
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
let sig: Vec<_> = (0..64).map(|_| thread_rng().gen::<u8>()).collect();
|
||||||
new.message.account_keys[0] = pubkey::new_rand();
|
new.message.account_keys[0] = pubkey::new_rand();
|
||||||
new.message.account_keys[1] = pubkey::new_rand();
|
new.message.account_keys[1] = pubkey::new_rand();
|
||||||
new.signatures = vec![Signature::new(&sig[0..64])];
|
new.signatures = vec![Signature::new(&sig[0..64])];
|
||||||
|
@ -362,7 +362,7 @@ fn get_windows_path_var() -> Result<Option<String>, String> {
|
|||||||
Ok(Some(s))
|
Ok(Some(s))
|
||||||
} else {
|
} else {
|
||||||
println!("the registry key HKEY_CURRENT_USER\\Environment\\PATH does not contain valid Unicode. Not modifying the PATH variable");
|
println!("the registry key HKEY_CURRENT_USER\\Environment\\PATH does not contain valid Unicode. Not modifying the PATH variable");
|
||||||
return Ok(None);
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::NotFound => Ok(Some(String::new())),
|
Err(ref e) if e.kind() == io::ErrorKind::NotFound => Ok(Some(String::new())),
|
||||||
@ -391,7 +391,7 @@ fn add_to_path(new_path: &str) -> bool {
|
|||||||
if !old_path.contains(&new_path) {
|
if !old_path.contains(&new_path) {
|
||||||
let mut new_path = new_path.to_string();
|
let mut new_path = new_path.to_string();
|
||||||
if !old_path.is_empty() {
|
if !old_path.is_empty() {
|
||||||
new_path.push_str(";");
|
new_path.push(';');
|
||||||
new_path.push_str(&old_path);
|
new_path.push_str(&old_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,7 +416,7 @@ fn add_to_path(new_path: &str) -> bool {
|
|||||||
SendMessageTimeoutA(
|
SendMessageTimeoutA(
|
||||||
HWND_BROADCAST,
|
HWND_BROADCAST,
|
||||||
WM_SETTINGCHANGE,
|
WM_SETTINGCHANGE,
|
||||||
0 as WPARAM,
|
0_usize,
|
||||||
"Environment\0".as_ptr() as LPARAM,
|
"Environment\0".as_ptr() as LPARAM,
|
||||||
SMTO_ABORTIFHUNG,
|
SMTO_ABORTIFHUNG,
|
||||||
5000,
|
5000,
|
||||||
|
@ -77,6 +77,7 @@ if [[ $CI_OS_NAME = windows ]]; then
|
|||||||
solana-install-init
|
solana-install-init
|
||||||
solana-keygen
|
solana-keygen
|
||||||
solana-stake-accounts
|
solana-stake-accounts
|
||||||
|
solana-test-validator
|
||||||
solana-tokens
|
solana-tokens
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#[cfg(not(target_family = "windows"))]
|
||||||
use clap::{crate_description, crate_name, value_t_or_exit, App, Arg};
|
use clap::{crate_description, crate_name, value_t_or_exit, App, Arg};
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ use {
|
|||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
path::Path,
|
path::{Path, PathBuf},
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
thread::{self, Builder},
|
thread::{self, Builder},
|
||||||
time::{Duration, SystemTime},
|
time::{Duration, SystemTime},
|
||||||
@ -132,7 +132,7 @@ impl AdminRpc for AdminRpcImpl {
|
|||||||
|
|
||||||
// Start the Admin RPC interface
|
// Start the Admin RPC interface
|
||||||
pub fn run(ledger_path: &Path, metadata: AdminRpcRequestMetadata) {
|
pub fn run(ledger_path: &Path, metadata: AdminRpcRequestMetadata) {
|
||||||
let admin_rpc_path = ledger_path.join("admin.rpc");
|
let admin_rpc_path = admin_rpc_path(ledger_path);
|
||||||
|
|
||||||
let event_loop = tokio::runtime::Builder::new_multi_thread()
|
let event_loop = tokio::runtime::Builder::new_multi_thread()
|
||||||
.thread_name("sol-adminrpc-el")
|
.thread_name("sol-adminrpc-el")
|
||||||
@ -173,9 +173,29 @@ pub fn run(ledger_path: &Path, metadata: AdminRpcRequestMetadata) {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn admin_rpc_path(ledger_path: &Path) -> PathBuf {
|
||||||
|
#[cfg(target_family = "windows")]
|
||||||
|
{
|
||||||
|
// More information about the wackiness of pipe names over at
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names
|
||||||
|
if let Some(ledger_filename) = ledger_path.file_name() {
|
||||||
|
PathBuf::from(format!(
|
||||||
|
"\\\\.\\pipe\\{}-admin.rpc",
|
||||||
|
ledger_filename.to_string_lossy()
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
PathBuf::from("\\\\.\\pipe\\admin.rpc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(target_family = "windows"))]
|
||||||
|
{
|
||||||
|
ledger_path.join("admin.rpc")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Connect to the Admin RPC interface
|
// Connect to the Admin RPC interface
|
||||||
pub async fn connect(ledger_path: &Path) -> std::result::Result<gen_client::Client, RpcError> {
|
pub async fn connect(ledger_path: &Path) -> std::result::Result<gen_client::Client, RpcError> {
|
||||||
let admin_rpc_path = ledger_path.join("admin.rpc");
|
let admin_rpc_path = admin_rpc_path(ledger_path);
|
||||||
if !admin_rpc_path.exists() {
|
if !admin_rpc_path.exists() {
|
||||||
Err(RpcError::Client(format!(
|
Err(RpcError::Client(format!(
|
||||||
"{} does not exist",
|
"{} does not exist",
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use {
|
use {
|
||||||
clap::{value_t, value_t_or_exit, App, Arg},
|
clap::{value_t, value_t_or_exit, App, Arg},
|
||||||
fd_lock::FdLock,
|
|
||||||
solana_clap_utils::{
|
solana_clap_utils::{
|
||||||
input_parsers::{pubkey_of, pubkeys_of, value_of},
|
input_parsers::{pubkey_of, pubkeys_of, value_of},
|
||||||
input_validators::{
|
input_validators::{
|
||||||
@ -24,8 +23,8 @@ use {
|
|||||||
},
|
},
|
||||||
solana_streamer::socket::SocketAddrSpace,
|
solana_streamer::socket::SocketAddrSpace,
|
||||||
solana_validator::{
|
solana_validator::{
|
||||||
admin_rpc_service, dashboard::Dashboard, println_name_value, redirect_stderr_to_file,
|
admin_rpc_service, dashboard::Dashboard, ledger_lockfile, lock_ledger, println_name_value,
|
||||||
test_validator::*,
|
redirect_stderr_to_file, test_validator::*,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
@ -168,7 +167,7 @@ fn main() {
|
|||||||
Arg::with_name("no_bpf_jit")
|
Arg::with_name("no_bpf_jit")
|
||||||
.long("no-bpf-jit")
|
.long("no-bpf-jit")
|
||||||
.takes_value(false)
|
.takes_value(false)
|
||||||
.help("Disable the just-in-time compiler and instead use the interpreter for BPF"),
|
.help("Disable the just-in-time compiler and instead use the interpreter for BPF. Windows always disables JIT."),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("slots_per_epoch")
|
Arg::with_name("slots_per_epoch")
|
||||||
@ -304,15 +303,8 @@ fn main() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ledger_fd_lock = FdLock::new(fs::File::open(&ledger_path).unwrap());
|
let mut ledger_lock = ledger_lockfile(&ledger_path);
|
||||||
let _ledger_lock = ledger_fd_lock.try_lock().unwrap_or_else(|_| {
|
let _ledger_write_guard = lock_ledger(&ledger_path, &mut ledger_lock);
|
||||||
println!(
|
|
||||||
"Error: Unable to lock {} directory. Check if another validator is running",
|
|
||||||
ledger_path.display()
|
|
||||||
);
|
|
||||||
exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
if reset_ledger {
|
if reset_ledger {
|
||||||
remove_directory_contents(&ledger_path).unwrap_or_else(|err| {
|
remove_directory_contents(&ledger_path).unwrap_or_else(|err| {
|
||||||
println!("Error: Unable to remove {}: {}", ledger_path.display(), err);
|
println!("Error: Unable to remove {}: {}", ledger_path.display(), err);
|
||||||
@ -396,6 +388,10 @@ fn main() {
|
|||||||
IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
|
IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
|
||||||
faucet_port,
|
faucet_port,
|
||||||
));
|
));
|
||||||
|
// JIT not supported on the BPF VM in Windows currently: https://github.com/solana-labs/rbpf/issues/217
|
||||||
|
#[cfg(target_family = "windows")]
|
||||||
|
let bpf_jit = false;
|
||||||
|
#[cfg(not(target_family = "windows"))]
|
||||||
let bpf_jit = !matches.is_present("no_bpf_jit");
|
let bpf_jit = !matches.is_present("no_bpf_jit");
|
||||||
|
|
||||||
let mut programs = vec![];
|
let mut programs = vec![];
|
||||||
|
@ -3,9 +3,15 @@ pub use solana_core::test_validator;
|
|||||||
pub use solana_gossip::cluster_info::MINIMUM_VALIDATOR_PORT_RANGE_WIDTH;
|
pub use solana_gossip::cluster_info::MINIMUM_VALIDATOR_PORT_RANGE_WIDTH;
|
||||||
use {
|
use {
|
||||||
console::style,
|
console::style,
|
||||||
|
fd_lock::{FdLock, FdLockGuard},
|
||||||
indicatif::{ProgressDrawTarget, ProgressStyle},
|
indicatif::{ProgressDrawTarget, ProgressStyle},
|
||||||
log::*,
|
std::{
|
||||||
std::{env, process::exit, thread::JoinHandle},
|
env,
|
||||||
|
fs::{File, OpenOptions},
|
||||||
|
path::Path,
|
||||||
|
process::exit,
|
||||||
|
thread::JoinHandle,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod admin_rpc_service;
|
pub mod admin_rpc_service;
|
||||||
@ -13,7 +19,7 @@ pub mod dashboard;
|
|||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn redirect_stderr(filename: &str) {
|
fn redirect_stderr(filename: &str) {
|
||||||
use std::{fs::OpenOptions, os::unix::io::AsRawFd};
|
use std::os::unix::io::AsRawFd;
|
||||||
match OpenOptions::new()
|
match OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
@ -36,17 +42,23 @@ pub fn redirect_stderr_to_file(logfile: Option<String>) -> Option<JoinHandle<()>
|
|||||||
env::set_var("RUST_BACKTRACE", "1")
|
env::set_var("RUST_BACKTRACE", "1")
|
||||||
}
|
}
|
||||||
|
|
||||||
let logger_thread = match logfile {
|
let filter = "solana=info";
|
||||||
None => None,
|
match logfile {
|
||||||
|
None => {
|
||||||
|
solana_logger::setup_with_default(filter);
|
||||||
|
None
|
||||||
|
}
|
||||||
Some(logfile) => {
|
Some(logfile) => {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
|
use log::info;
|
||||||
let signals = signal_hook::iterator::Signals::new(&[signal_hook::SIGUSR1])
|
let signals = signal_hook::iterator::Signals::new(&[signal_hook::SIGUSR1])
|
||||||
.unwrap_or_else(|err| {
|
.unwrap_or_else(|err| {
|
||||||
eprintln!("Unable to register SIGUSR1 handler: {:?}", err);
|
eprintln!("Unable to register SIGUSR1 handler: {:?}", err);
|
||||||
exit(1);
|
exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
solana_logger::setup_with_default(filter);
|
||||||
redirect_stderr(&logfile);
|
redirect_stderr(&logfile);
|
||||||
Some(std::thread::spawn(move || {
|
Some(std::thread::spawn(move || {
|
||||||
for signal in signals.forever() {
|
for signal in signals.forever() {
|
||||||
@ -60,14 +72,12 @@ pub fn redirect_stderr_to_file(logfile: Option<String>) -> Option<JoinHandle<()>
|
|||||||
}
|
}
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
{
|
{
|
||||||
println!("logging to a file is not supported on this platform");
|
println!("logging to file is not supported on this platform");
|
||||||
|
solana_logger::setup_with_default(filter);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
solana_logger::setup_with_default("solana=info");
|
|
||||||
logger_thread
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn port_validator(port: String) -> Result<(), String> {
|
pub fn port_validator(port: String) -> Result<(), String> {
|
||||||
@ -133,3 +143,27 @@ impl ProgressBar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ledger_lockfile(ledger_path: &Path) -> FdLock<File> {
|
||||||
|
let lockfile = ledger_path.join("ledger.lock");
|
||||||
|
FdLock::new(
|
||||||
|
OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(&lockfile)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lock_ledger<'path, 'lock>(
|
||||||
|
ledger_path: &'path Path,
|
||||||
|
ledger_lockfile: &'lock mut FdLock<File>,
|
||||||
|
) -> FdLockGuard<'lock, File> {
|
||||||
|
ledger_lockfile.try_lock().unwrap_or_else(|_| {
|
||||||
|
println!(
|
||||||
|
"Error: Unable to lock {} directory. Check if another validator is running",
|
||||||
|
ledger_path.display()
|
||||||
|
);
|
||||||
|
exit(1);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -5,7 +5,6 @@ use {
|
|||||||
AppSettings, Arg, ArgMatches, SubCommand,
|
AppSettings, Arg, ArgMatches, SubCommand,
|
||||||
},
|
},
|
||||||
console::style,
|
console::style,
|
||||||
fd_lock::FdLock,
|
|
||||||
log::*,
|
log::*,
|
||||||
rand::{seq::SliceRandom, thread_rng, Rng},
|
rand::{seq::SliceRandom, thread_rng, Rng},
|
||||||
solana_clap_utils::{
|
solana_clap_utils::{
|
||||||
@ -59,8 +58,8 @@ use {
|
|||||||
},
|
},
|
||||||
solana_streamer::socket::SocketAddrSpace,
|
solana_streamer::socket::SocketAddrSpace,
|
||||||
solana_validator::{
|
solana_validator::{
|
||||||
admin_rpc_service, dashboard::Dashboard, new_spinner_progress_bar, println_name_value,
|
admin_rpc_service, dashboard::Dashboard, ledger_lockfile, lock_ledger,
|
||||||
redirect_stderr_to_file,
|
new_spinner_progress_bar, println_name_value, redirect_stderr_to_file,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
collections::{HashSet, VecDeque},
|
collections::{HashSet, VecDeque},
|
||||||
@ -2517,14 +2516,8 @@ pub fn main() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut ledger_fd_lock = FdLock::new(fs::File::open(&ledger_path).unwrap());
|
let mut ledger_lock = ledger_lockfile(&ledger_path);
|
||||||
let _ledger_lock = ledger_fd_lock.try_lock().unwrap_or_else(|_| {
|
let _ledger_write_guard = lock_ledger(&ledger_path, &mut ledger_lock);
|
||||||
println!(
|
|
||||||
"Error: Unable to lock {} directory. Check if another validator is running",
|
|
||||||
ledger_path.display()
|
|
||||||
);
|
|
||||||
exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
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(
|
||||||
|
Reference in New Issue
Block a user