Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
c375ce1fcd | |||
df813b31c5 | |||
7db92e2951 | |||
6585518f78 | |||
6398e256e4 | |||
b64ebb45e7 | |||
307ac66d9c |
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -4407,6 +4407,7 @@ dependencies = [
|
||||
"bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"generic-array 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1,16 +1,16 @@
|
||||
use crate::keypair::{
|
||||
keypair_from_seed_phrase, keypair_util_from_path, ASK_KEYWORD, SKIP_SEED_PHRASE_VALIDATION_ARG,
|
||||
keypair_from_seed_phrase, signer_from_path, ASK_KEYWORD, SKIP_SEED_PHRASE_VALIDATION_ARG,
|
||||
};
|
||||
use chrono::DateTime;
|
||||
use clap::ArgMatches;
|
||||
use solana_remote_wallet::remote_wallet::DerivationPath;
|
||||
use solana_remote_wallet::remote_wallet::{DerivationPath, RemoteWalletManager};
|
||||
use solana_sdk::{
|
||||
clock::UnixTimestamp,
|
||||
native_token::sol_to_lamports,
|
||||
pubkey::Pubkey,
|
||||
signature::{read_keypair_file, Keypair, Signature, Signer},
|
||||
};
|
||||
use std::str::FromStr;
|
||||
use std::{str::FromStr, sync::Arc};
|
||||
|
||||
// Return parsed values from matches at `name`
|
||||
pub fn values_of<T>(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<T>>
|
||||
@ -96,14 +96,18 @@ pub fn pubkeys_sigs_of(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<(Pubk
|
||||
}
|
||||
|
||||
// Return a signer from matches at `name`
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn signer_of(
|
||||
name: &str,
|
||||
matches: &ArgMatches<'_>,
|
||||
) -> Result<Option<Box<dyn Signer>>, Box<dyn std::error::Error>> {
|
||||
name: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
) -> Result<(Option<Box<dyn Signer>>, Option<Pubkey>), Box<dyn std::error::Error>> {
|
||||
if let Some(location) = matches.value_of(name) {
|
||||
keypair_util_from_path(matches, location, name).map(Some)
|
||||
let signer = signer_from_path(matches, location, name, wallet_manager)?;
|
||||
let signer_pubkey = signer.pubkey();
|
||||
Ok((Some(signer), Some(signer_pubkey)))
|
||||
} else {
|
||||
Ok(None)
|
||||
Ok((None, None))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crate::keypair::{parse_keypair_path, KeypairUrl, ASK_KEYWORD};
|
||||
use chrono::DateTime;
|
||||
use solana_remote_wallet::remote_keypair::generate_remote_keypair;
|
||||
use solana_sdk::{
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
@ -53,9 +52,6 @@ pub fn is_pubkey_or_keypair_or_ask_keyword(string: String) -> Result<(), String>
|
||||
|
||||
pub fn is_valid_signer(string: String) -> Result<(), String> {
|
||||
match parse_keypair_path(&string) {
|
||||
KeypairUrl::Usb(path) => generate_remote_keypair(path, None)
|
||||
.map(|_| ())
|
||||
.map_err(|err| format!("{:?}", err)),
|
||||
KeypairUrl::Filepath(path) => is_keypair(path),
|
||||
_ => Ok(()),
|
||||
}
|
||||
|
@ -6,7 +6,10 @@ use crate::{
|
||||
use bip39::{Language, Mnemonic, Seed};
|
||||
use clap::{values_t, ArgMatches, Error, ErrorKind};
|
||||
use rpassword::prompt_password_stderr;
|
||||
use solana_remote_wallet::remote_keypair::generate_remote_keypair;
|
||||
use solana_remote_wallet::{
|
||||
remote_keypair::generate_remote_keypair,
|
||||
remote_wallet::{RemoteWalletError, RemoteWalletManager},
|
||||
};
|
||||
use solana_sdk::{
|
||||
pubkey::Pubkey,
|
||||
signature::{
|
||||
@ -19,6 +22,7 @@ use std::{
|
||||
io::{stdin, stdout, Write},
|
||||
process::exit,
|
||||
str::FromStr,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
pub enum KeypairUrl {
|
||||
@ -56,10 +60,11 @@ pub fn presigner_from_pubkey_sigs(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn keypair_util_from_path(
|
||||
pub fn signer_from_path(
|
||||
matches: &ArgMatches,
|
||||
path: &str,
|
||||
keypair_name: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
) -> Result<Box<dyn Signer>, Box<dyn error::Error>> {
|
||||
match parse_keypair_path(path) {
|
||||
KeypairUrl::Ask => {
|
||||
@ -75,10 +80,17 @@ pub fn keypair_util_from_path(
|
||||
let mut stdin = std::io::stdin();
|
||||
Ok(Box::new(read_keypair(&mut stdin)?))
|
||||
}
|
||||
KeypairUrl::Usb(path) => Ok(Box::new(generate_remote_keypair(
|
||||
path,
|
||||
derivation_of(matches, "derivation_path"),
|
||||
)?)),
|
||||
KeypairUrl::Usb(path) => {
|
||||
if let Some(wallet_manager) = wallet_manager {
|
||||
Ok(Box::new(generate_remote_keypair(
|
||||
path,
|
||||
derivation_of(matches, "derivation_path"),
|
||||
wallet_manager,
|
||||
)?))
|
||||
} else {
|
||||
Err(RemoteWalletError::NoDeviceFound.into())
|
||||
}
|
||||
}
|
||||
KeypairUrl::Pubkey(pubkey) => {
|
||||
let presigner = pubkeys_sigs_of(matches, SIGNER_ARG.name)
|
||||
.as_ref()
|
||||
|
921
cli/src/cli.rs
921
cli/src/cli.rs
File diff suppressed because it is too large
Load Diff
@ -8,12 +8,13 @@ use crate::{
|
||||
use clap::{value_t, value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
||||
use console::{style, Emoji};
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use solana_clap_utils::{input_parsers::*, input_validators::*};
|
||||
use solana_clap_utils::{input_parsers::*, input_validators::*, keypair::signer_from_path};
|
||||
use solana_client::{
|
||||
pubsub_client::{PubsubClient, SlotInfoMessage},
|
||||
rpc_client::RpcClient,
|
||||
rpc_response::RpcVoteAccountInfo,
|
||||
};
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use solana_sdk::{
|
||||
account_utils::StateMut,
|
||||
clock::{self, Slot},
|
||||
@ -239,11 +240,15 @@ pub fn parse_catchup(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliErro
|
||||
let node_pubkey = pubkey_of(matches, "node_pubkey").unwrap();
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::Catchup { node_pubkey },
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_cluster_ping(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
pub fn parse_cluster_ping(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer_path: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let lamports = value_t_or_exit!(matches, "lamports", u64);
|
||||
let interval = Duration::from_secs(value_t_or_exit!(matches, "interval", u64));
|
||||
let count = if matches.is_present("count") {
|
||||
@ -265,7 +270,12 @@ pub fn parse_cluster_ping(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Cl
|
||||
timeout,
|
||||
commitment_config,
|
||||
},
|
||||
require_keypair: true,
|
||||
signers: vec![signer_from_path(
|
||||
matches,
|
||||
default_signer_path,
|
||||
"keypair",
|
||||
wallet_manager,
|
||||
)?],
|
||||
})
|
||||
}
|
||||
|
||||
@ -273,7 +283,7 @@ pub fn parse_live_slots(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliE
|
||||
let url: String = value_t_or_exit!(matches, "websocket_url", String);
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::LiveSlots { url },
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@ -281,7 +291,7 @@ pub fn parse_get_block_time(matches: &ArgMatches<'_>) -> Result<CliCommandInfo,
|
||||
let slot = value_t_or_exit!(matches, "slot", u64);
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::GetBlockTime { slot },
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@ -293,7 +303,7 @@ pub fn parse_get_epoch_info(matches: &ArgMatches<'_>) -> Result<CliCommandInfo,
|
||||
};
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::GetEpochInfo { commitment_config },
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@ -305,7 +315,7 @@ pub fn parse_get_slot(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliErr
|
||||
};
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::GetSlot { commitment_config },
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@ -317,7 +327,7 @@ pub fn parse_get_transaction_count(matches: &ArgMatches<'_>) -> Result<CliComman
|
||||
};
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::GetTransactionCount { commitment_config },
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@ -330,7 +340,7 @@ pub fn parse_show_stakes(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Cli
|
||||
use_lamports_unit,
|
||||
vote_account_pubkeys,
|
||||
},
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@ -339,7 +349,7 @@ pub fn parse_show_validators(matches: &ArgMatches<'_>) -> Result<CliCommandInfo,
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::ShowValidators { use_lamports_unit },
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@ -531,7 +541,7 @@ pub fn parse_show_block_production(matches: &ArgMatches<'_>) -> Result<CliComman
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::ShowBlockProduction { epoch, slot_limit },
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@ -726,7 +736,7 @@ pub fn process_ping(
|
||||
) -> ProcessResult {
|
||||
let to = Keypair::new().pubkey();
|
||||
|
||||
println_name_value("Source Account:", &config.keypair.pubkey().to_string());
|
||||
println_name_value("Source Account:", &config.signers[0].pubkey().to_string());
|
||||
println_name_value("Destination Account:", &to.to_string());
|
||||
println!();
|
||||
|
||||
@ -745,13 +755,13 @@ pub fn process_ping(
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_new_blockhash(&last_blockhash)?;
|
||||
last_blockhash = recent_blockhash;
|
||||
|
||||
let ix = system_instruction::transfer(&config.keypair.pubkey(), &to, lamports);
|
||||
let ix = system_instruction::transfer(&config.signers[0].pubkey(), &to, lamports);
|
||||
let message = Message::new(vec![ix]);
|
||||
let mut transaction = Transaction::new_unsigned(message);
|
||||
transaction.try_sign(&[config.keypair.as_ref()], recent_blockhash)?;
|
||||
transaction.try_sign(&config.signers, recent_blockhash)?;
|
||||
check_account_for_fee(
|
||||
rpc_client,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&fee_calculator,
|
||||
&transaction.message,
|
||||
)?;
|
||||
@ -1105,28 +1115,38 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::cli::{app, parse_command};
|
||||
use solana_sdk::signature::{write_keypair, Keypair};
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
fn make_tmp_file() -> (String, NamedTempFile) {
|
||||
let tmp_file = NamedTempFile::new().unwrap();
|
||||
(String::from(tmp_file.path().to_str().unwrap()), tmp_file)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_command() {
|
||||
let test_commands = app("test", "desc", "version");
|
||||
let default_keypair = Keypair::new();
|
||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
|
||||
let test_cluster_version = test_commands
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "cluster-version"]);
|
||||
assert_eq!(
|
||||
parse_command(&test_cluster_version).unwrap(),
|
||||
parse_command(&test_cluster_version, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::ClusterVersion,
|
||||
require_keypair: false
|
||||
signers: vec![],
|
||||
}
|
||||
);
|
||||
|
||||
let test_fees = test_commands.clone().get_matches_from(vec!["test", "fees"]);
|
||||
assert_eq!(
|
||||
parse_command(&test_fees).unwrap(),
|
||||
parse_command(&test_fees, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::Fees,
|
||||
require_keypair: false
|
||||
signers: vec![],
|
||||
}
|
||||
);
|
||||
|
||||
@ -1136,10 +1156,10 @@ mod tests {
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "block-time", &slot.to_string()]);
|
||||
assert_eq!(
|
||||
parse_command(&test_get_block_time).unwrap(),
|
||||
parse_command(&test_get_block_time, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::GetBlockTime { slot },
|
||||
require_keypair: false
|
||||
signers: vec![],
|
||||
}
|
||||
);
|
||||
|
||||
@ -1147,12 +1167,12 @@ mod tests {
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "epoch-info"]);
|
||||
assert_eq!(
|
||||
parse_command(&test_get_epoch_info).unwrap(),
|
||||
parse_command(&test_get_epoch_info, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::GetEpochInfo {
|
||||
commitment_config: CommitmentConfig::recent(),
|
||||
},
|
||||
require_keypair: false
|
||||
signers: vec![],
|
||||
}
|
||||
);
|
||||
|
||||
@ -1160,21 +1180,21 @@ mod tests {
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "genesis-hash"]);
|
||||
assert_eq!(
|
||||
parse_command(&test_get_genesis_hash).unwrap(),
|
||||
parse_command(&test_get_genesis_hash, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::GetGenesisHash,
|
||||
require_keypair: false
|
||||
signers: vec![],
|
||||
}
|
||||
);
|
||||
|
||||
let test_get_slot = test_commands.clone().get_matches_from(vec!["test", "slot"]);
|
||||
assert_eq!(
|
||||
parse_command(&test_get_slot).unwrap(),
|
||||
parse_command(&test_get_slot, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::GetSlot {
|
||||
commitment_config: CommitmentConfig::recent(),
|
||||
},
|
||||
require_keypair: false
|
||||
signers: vec![],
|
||||
}
|
||||
);
|
||||
|
||||
@ -1182,12 +1202,12 @@ mod tests {
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "transaction-count"]);
|
||||
assert_eq!(
|
||||
parse_command(&test_transaction_count).unwrap(),
|
||||
parse_command(&test_transaction_count, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::GetTransactionCount {
|
||||
commitment_config: CommitmentConfig::recent(),
|
||||
},
|
||||
require_keypair: false
|
||||
signers: vec![],
|
||||
}
|
||||
);
|
||||
|
||||
@ -1203,7 +1223,7 @@ mod tests {
|
||||
"--confirmed",
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_ping).unwrap(),
|
||||
parse_command(&test_ping, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::Ping {
|
||||
lamports: 1,
|
||||
@ -1212,7 +1232,7 @@ mod tests {
|
||||
timeout: Duration::from_secs(3),
|
||||
commitment_config: CommitmentConfig::default(),
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![default_keypair.into()],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -4,15 +4,15 @@ use console::style;
|
||||
use solana_clap_utils::{
|
||||
input_parsers::derivation_of,
|
||||
input_validators::{is_derivation, is_url},
|
||||
keypair::{keypair_util_from_path, SKIP_SEED_PHRASE_VALIDATION_ARG},
|
||||
keypair::SKIP_SEED_PHRASE_VALIDATION_ARG,
|
||||
};
|
||||
use solana_cli::{
|
||||
cli::{app, parse_command, process_command, CliCommandInfo, CliConfig, CliError},
|
||||
cli::{app, parse_command, process_command, CliCommandInfo, CliConfig, CliSigners},
|
||||
display::{println_name_value, println_name_value_or},
|
||||
};
|
||||
use solana_cli_config::config::{Config, CONFIG_FILE};
|
||||
|
||||
use std::error;
|
||||
use solana_remote_wallet::remote_wallet::{maybe_wallet_manager, RemoteWalletManager};
|
||||
use std::{error, sync::Arc};
|
||||
|
||||
fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error>> {
|
||||
let parse_args = match matches.subcommand() {
|
||||
@ -80,7 +80,10 @@ fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error
|
||||
Ok(parse_args)
|
||||
}
|
||||
|
||||
pub fn parse_args(matches: &ArgMatches<'_>) -> Result<CliConfig, Box<dyn error::Error>> {
|
||||
pub fn parse_args<'a>(
|
||||
matches: &ArgMatches<'_>,
|
||||
wallet_manager: Option<Arc<RemoteWalletManager>>,
|
||||
) -> Result<(CliConfig<'a>, CliSigners), Box<dyn error::Error>> {
|
||||
let config = if let Some(config_file) = matches.value_of("config_file") {
|
||||
Config::load(config_file).unwrap_or_default()
|
||||
} else {
|
||||
@ -95,44 +98,29 @@ pub fn parse_args(matches: &ArgMatches<'_>) -> Result<CliConfig, Box<dyn error::
|
||||
default.json_rpc_url
|
||||
};
|
||||
|
||||
let CliCommandInfo {
|
||||
command,
|
||||
require_keypair,
|
||||
} = parse_command(&matches)?;
|
||||
|
||||
let (keypair, keypair_path) = if require_keypair {
|
||||
let path = if matches.is_present("keypair") {
|
||||
matches.value_of("keypair").unwrap().to_string()
|
||||
} else if config.keypair_path != "" {
|
||||
config.keypair_path
|
||||
} else {
|
||||
let default_keypair_path = CliConfig::default_keypair_path();
|
||||
if !std::path::Path::new(&default_keypair_path).exists() {
|
||||
return Err(CliError::KeypairFileNotFound(format!(
|
||||
"Generate a new keypair at {} with `solana-keygen new`",
|
||||
default_keypair_path
|
||||
))
|
||||
.into());
|
||||
}
|
||||
default_keypair_path
|
||||
};
|
||||
|
||||
let keypair = keypair_util_from_path(matches, &path, "keypair")?;
|
||||
(keypair, Some(path))
|
||||
let default_signer_path = if matches.is_present("keypair") {
|
||||
matches.value_of("keypair").unwrap().to_string()
|
||||
} else if config.keypair_path != "" {
|
||||
config.keypair_path
|
||||
} else {
|
||||
let default = CliConfig::default();
|
||||
(default.keypair, None)
|
||||
CliConfig::default_keypair_path()
|
||||
};
|
||||
|
||||
Ok(CliConfig {
|
||||
command,
|
||||
json_rpc_url,
|
||||
keypair,
|
||||
keypair_path,
|
||||
derivation_path: derivation_of(matches, "derivation_path"),
|
||||
rpc_client: None,
|
||||
verbose: matches.is_present("verbose"),
|
||||
})
|
||||
let CliCommandInfo { command, signers } =
|
||||
parse_command(&matches, &default_signer_path, wallet_manager.as_ref())?;
|
||||
|
||||
Ok((
|
||||
CliConfig {
|
||||
command,
|
||||
json_rpc_url,
|
||||
signers: vec![],
|
||||
keypair_path: default_signer_path,
|
||||
derivation_path: derivation_of(matches, "derivation_path"),
|
||||
rpc_client: None,
|
||||
verbose: matches.is_present("verbose"),
|
||||
},
|
||||
signers,
|
||||
))
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
@ -228,7 +216,10 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
.get_matches();
|
||||
|
||||
if parse_settings(&matches)? {
|
||||
let config = parse_args(&matches)?;
|
||||
let wallet_manager = maybe_wallet_manager()?;
|
||||
|
||||
let (mut config, signers) = parse_args(&matches, wallet_manager)?;
|
||||
config.signers = signers.iter().map(|s| s.as_ref()).collect();
|
||||
let result = process_command(&config)?;
|
||||
println!("{}", result);
|
||||
}
|
||||
|
283
cli/src/nonce.rs
283
cli/src/nonce.rs
@ -1,12 +1,14 @@
|
||||
use crate::cli::{
|
||||
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||
build_balance_message, check_account_for_fee, check_unique_pubkeys, generate_unique_signers,
|
||||
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult,
|
||||
SignerIndex,
|
||||
};
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use solana_clap_utils::{
|
||||
input_parsers::*, input_validators::*, offline::BLOCKHASH_ARG, ArgConstant,
|
||||
};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
account_utils::StateMut,
|
||||
@ -14,7 +16,6 @@ use solana_sdk::{
|
||||
message::Message,
|
||||
nonce_state::{Meta, NonceState},
|
||||
pubkey::Pubkey,
|
||||
signature::Signer,
|
||||
system_instruction::{
|
||||
advance_nonce_account, authorize_nonce_account, create_address_with_seed,
|
||||
create_nonce_account, create_nonce_account_with_seed, withdraw_nonce_account, NonceError,
|
||||
@ -23,6 +24,7 @@ use solana_sdk::{
|
||||
system_program,
|
||||
transaction::Transaction,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum CliNonceError {
|
||||
@ -216,35 +218,61 @@ impl NonceSubCommands for App<'_, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_authorize_nonce_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
pub fn parse_authorize_nonce_account(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer_path: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let nonce_account = pubkey_of(matches, "nonce_account_keypair").unwrap();
|
||||
let new_authority = pubkey_of(matches, "new_authority").unwrap();
|
||||
let nonce_authority = signer_of(NONCE_AUTHORITY_ARG.name, matches)?;
|
||||
let (nonce_authority, nonce_authority_pubkey) =
|
||||
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
||||
|
||||
let payer_provided = None;
|
||||
let signer_info = generate_unique_signers(
|
||||
vec![payer_provided, nonce_authority],
|
||||
matches,
|
||||
default_signer_path,
|
||||
wallet_manager,
|
||||
)?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::AuthorizeNonceAccount {
|
||||
nonce_account,
|
||||
nonce_authority,
|
||||
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
||||
new_authority,
|
||||
},
|
||||
require_keypair: true,
|
||||
signers: signer_info.signers,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_nonce_create_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
let nonce_account = signer_of("nonce_account_keypair", matches)?.unwrap();
|
||||
pub fn parse_nonce_create_account(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer_path: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let (nonce_account, nonce_account_pubkey) =
|
||||
signer_of(matches, "nonce_account_keypair", wallet_manager)?;
|
||||
let seed = matches.value_of("seed").map(|s| s.to_string());
|
||||
let lamports = lamports_of_sol(matches, "amount").unwrap();
|
||||
let nonce_authority = pubkey_of(matches, NONCE_AUTHORITY_ARG.name);
|
||||
|
||||
let payer_provided = None;
|
||||
let signer_info = generate_unique_signers(
|
||||
vec![payer_provided, nonce_account],
|
||||
matches,
|
||||
default_signer_path,
|
||||
wallet_manager,
|
||||
)?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::CreateNonceAccount {
|
||||
nonce_account: nonce_account.into(),
|
||||
nonce_account: signer_info.index_of(nonce_account_pubkey).unwrap(),
|
||||
seed,
|
||||
nonce_authority,
|
||||
lamports,
|
||||
},
|
||||
require_keypair: true,
|
||||
signers: signer_info.signers,
|
||||
})
|
||||
}
|
||||
|
||||
@ -253,20 +281,33 @@ pub fn parse_get_nonce(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliEr
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::GetNonce(nonce_account_pubkey),
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_new_nonce(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
pub fn parse_new_nonce(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer_path: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let nonce_account = pubkey_of(matches, "nonce_account_keypair").unwrap();
|
||||
let nonce_authority = signer_of(NONCE_AUTHORITY_ARG.name, matches)?;
|
||||
let (nonce_authority, nonce_authority_pubkey) =
|
||||
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
||||
|
||||
let payer_provided = None;
|
||||
let signer_info = generate_unique_signers(
|
||||
vec![payer_provided, nonce_authority],
|
||||
matches,
|
||||
default_signer_path,
|
||||
wallet_manager,
|
||||
)?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::NewNonce {
|
||||
nonce_account,
|
||||
nonce_authority,
|
||||
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
||||
},
|
||||
require_keypair: true,
|
||||
signers: signer_info.signers,
|
||||
})
|
||||
}
|
||||
|
||||
@ -279,26 +320,37 @@ pub fn parse_show_nonce_account(matches: &ArgMatches<'_>) -> Result<CliCommandIn
|
||||
nonce_account_pubkey,
|
||||
use_lamports_unit,
|
||||
},
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_withdraw_from_nonce_account(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer_path: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let nonce_account = pubkey_of(matches, "nonce_account_keypair").unwrap();
|
||||
let destination_account_pubkey = pubkey_of(matches, "destination_account_pubkey").unwrap();
|
||||
let lamports = lamports_of_sol(matches, "amount").unwrap();
|
||||
let nonce_authority = signer_of(NONCE_AUTHORITY_ARG.name, matches)?;
|
||||
let (nonce_authority, nonce_authority_pubkey) =
|
||||
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
||||
|
||||
let payer_provided = None;
|
||||
let signer_info = generate_unique_signers(
|
||||
vec![payer_provided, nonce_authority],
|
||||
matches,
|
||||
default_signer_path,
|
||||
wallet_manager,
|
||||
)?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::WithdrawFromNonceAccount {
|
||||
nonce_account,
|
||||
nonce_authority,
|
||||
nonce_authority: signer_info.index_of(nonce_authority_pubkey).unwrap(),
|
||||
destination_account_pubkey,
|
||||
lamports,
|
||||
},
|
||||
require_keypair: true,
|
||||
signers: signer_info.signers,
|
||||
})
|
||||
}
|
||||
|
||||
@ -334,40 +386,36 @@ pub fn process_authorize_nonce_account(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
nonce_account: &Pubkey,
|
||||
nonce_authority: Option<&dyn Signer>,
|
||||
nonce_authority: SignerIndex,
|
||||
new_authority: &Pubkey,
|
||||
) -> ProcessResult {
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
|
||||
let nonce_authority = nonce_authority.unwrap_or_else(|| config.keypair.as_ref());
|
||||
let nonce_authority = config.signers[nonce_authority];
|
||||
let ix = authorize_nonce_account(nonce_account, &nonce_authority.pubkey(), new_authority);
|
||||
let message = Message::new_with_payer(vec![ix], Some(&config.keypair.pubkey()));
|
||||
let message = Message::new_with_payer(vec![ix], Some(&config.signers[0].pubkey()));
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(
|
||||
&[config.keypair.as_ref(), nonce_authority],
|
||||
recent_blockhash,
|
||||
)?;
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
|
||||
check_account_for_fee(
|
||||
rpc_client,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client
|
||||
.send_and_confirm_transaction(&mut tx, &[config.keypair.as_ref(), nonce_authority]);
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.signers);
|
||||
log_instruction_custom_error::<NonceError>(result)
|
||||
}
|
||||
|
||||
pub fn process_create_nonce_account(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
nonce_account: &dyn Signer,
|
||||
nonce_account: SignerIndex,
|
||||
seed: Option<String>,
|
||||
nonce_authority: Option<Pubkey>,
|
||||
lamports: u64,
|
||||
) -> ProcessResult {
|
||||
let nonce_account_pubkey = nonce_account.pubkey();
|
||||
let nonce_account_pubkey = config.signers[nonce_account].pubkey();
|
||||
let nonce_account_address = if let Some(seed) = seed.clone() {
|
||||
create_address_with_seed(&nonce_account_pubkey, &seed, &system_program::id())?
|
||||
} else {
|
||||
@ -375,7 +423,7 @@ pub fn process_create_nonce_account(
|
||||
};
|
||||
|
||||
check_unique_pubkeys(
|
||||
(&config.keypair.pubkey(), "cli keypair".to_string()),
|
||||
(&config.signers[0].pubkey(), "cli keypair".to_string()),
|
||||
(&nonce_account_address, "nonce_account".to_string()),
|
||||
)?;
|
||||
|
||||
@ -402,20 +450,20 @@ pub fn process_create_nonce_account(
|
||||
.into());
|
||||
}
|
||||
|
||||
let nonce_authority = nonce_authority.unwrap_or_else(|| config.keypair.pubkey());
|
||||
let nonce_authority = nonce_authority.unwrap_or_else(|| config.signers[0].pubkey());
|
||||
|
||||
let ixs = if let Some(seed) = seed {
|
||||
create_nonce_account_with_seed(
|
||||
&config.keypair.pubkey(), // from
|
||||
&nonce_account_address, // to
|
||||
&nonce_account_pubkey, // base
|
||||
&seed, // seed
|
||||
&config.signers[0].pubkey(), // from
|
||||
&nonce_account_address, // to
|
||||
&nonce_account_pubkey, // base
|
||||
&seed, // seed
|
||||
&nonce_authority,
|
||||
lamports,
|
||||
)
|
||||
} else {
|
||||
create_nonce_account(
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&nonce_account_pubkey,
|
||||
&nonce_authority,
|
||||
lamports,
|
||||
@ -424,23 +472,17 @@ pub fn process_create_nonce_account(
|
||||
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
|
||||
let signers = if nonce_account_pubkey != config.keypair.pubkey() {
|
||||
vec![config.keypair.as_ref(), nonce_account] // both must sign if `from` and `to` differ
|
||||
} else {
|
||||
vec![config.keypair.as_ref()] // when stake_account == config.keypair and there's a seed, we only need one signature
|
||||
};
|
||||
|
||||
let message = Message::new_with_payer(ixs, Some(&config.keypair.pubkey()));
|
||||
let message = Message::new_with_payer(ixs, Some(&config.signers[0].pubkey()));
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(&signers, recent_blockhash)?;
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
|
||||
check_account_for_fee(
|
||||
rpc_client,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &signers);
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.signers);
|
||||
log_instruction_custom_error::<SystemError>(result)
|
||||
}
|
||||
|
||||
@ -468,10 +510,10 @@ pub fn process_new_nonce(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
nonce_account: &Pubkey,
|
||||
nonce_authority: Option<&dyn Signer>,
|
||||
nonce_authority: SignerIndex,
|
||||
) -> ProcessResult {
|
||||
check_unique_pubkeys(
|
||||
(&config.keypair.pubkey(), "cli keypair".to_string()),
|
||||
(&config.signers[0].pubkey(), "cli keypair".to_string()),
|
||||
(&nonce_account, "nonce_account_pubkey".to_string()),
|
||||
)?;
|
||||
|
||||
@ -482,23 +524,20 @@ pub fn process_new_nonce(
|
||||
.into());
|
||||
}
|
||||
|
||||
let nonce_authority = nonce_authority.unwrap_or_else(|| config.keypair.as_ref());
|
||||
let nonce_authority = config.signers[nonce_authority];
|
||||
let ix = advance_nonce_account(&nonce_account, &nonce_authority.pubkey());
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let message = Message::new_with_payer(vec![ix], Some(&config.keypair.pubkey()));
|
||||
let message = Message::new_with_payer(vec![ix], Some(&config.signers[0].pubkey()));
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(
|
||||
&[config.keypair.as_ref(), nonce_authority],
|
||||
recent_blockhash,
|
||||
)?;
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
check_account_for_fee(
|
||||
rpc_client,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client
|
||||
.send_and_confirm_transaction(&mut tx, &[config.keypair.as_ref(), nonce_authority]);
|
||||
let result =
|
||||
rpc_client.send_and_confirm_transaction(&mut tx, &[config.signers[0], nonce_authority]);
|
||||
log_instruction_custom_error::<SystemError>(result)
|
||||
}
|
||||
|
||||
@ -555,33 +594,29 @@ pub fn process_withdraw_from_nonce_account(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
nonce_account: &Pubkey,
|
||||
nonce_authority: Option<&dyn Signer>,
|
||||
nonce_authority: SignerIndex,
|
||||
destination_account_pubkey: &Pubkey,
|
||||
lamports: u64,
|
||||
) -> ProcessResult {
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
|
||||
let nonce_authority = nonce_authority.unwrap_or_else(|| config.keypair.as_ref());
|
||||
let nonce_authority = config.signers[nonce_authority];
|
||||
let ix = withdraw_nonce_account(
|
||||
nonce_account,
|
||||
&nonce_authority.pubkey(),
|
||||
destination_account_pubkey,
|
||||
lamports,
|
||||
);
|
||||
let message = Message::new_with_payer(vec![ix], Some(&config.keypair.pubkey()));
|
||||
let message = Message::new_with_payer(vec![ix], Some(&config.signers[0].pubkey()));
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(
|
||||
&[config.keypair.as_ref(), nonce_authority],
|
||||
recent_blockhash,
|
||||
)?;
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
check_account_for_fee(
|
||||
rpc_client,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client
|
||||
.send_and_confirm_transaction(&mut tx, &[config.keypair.as_ref(), nonce_authority]);
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.signers);
|
||||
log_instruction_custom_error::<NonceError>(result)
|
||||
}
|
||||
|
||||
@ -593,10 +628,9 @@ mod tests {
|
||||
account::Account,
|
||||
hash::hash,
|
||||
nonce_state::{Meta as NonceMeta, NonceState},
|
||||
signature::{read_keypair_file, write_keypair, Keypair},
|
||||
signature::{read_keypair_file, write_keypair, Keypair, Signer},
|
||||
system_program,
|
||||
};
|
||||
use std::rc::Rc;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
fn make_tmp_file() -> (String, NamedTempFile) {
|
||||
@ -607,6 +641,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_parse_command() {
|
||||
let test_commands = app("test", "desc", "version");
|
||||
let default_keypair = Keypair::new();
|
||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
let (keypair_file, mut tmp_file) = make_tmp_file();
|
||||
let nonce_account_keypair = Keypair::new();
|
||||
write_keypair(&nonce_account_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
@ -625,14 +662,14 @@ mod tests {
|
||||
&Pubkey::default().to_string(),
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_authorize_nonce_account).unwrap(),
|
||||
parse_command(&test_authorize_nonce_account, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::AuthorizeNonceAccount {
|
||||
nonce_account: nonce_account_pubkey,
|
||||
nonce_authority: None,
|
||||
nonce_authority: 0,
|
||||
new_authority: Pubkey::default(),
|
||||
},
|
||||
require_keypair: true,
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||
}
|
||||
);
|
||||
|
||||
@ -646,16 +683,17 @@ mod tests {
|
||||
&authority_keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_authorize_nonce_account).unwrap(),
|
||||
parse_command(&test_authorize_nonce_account, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::AuthorizeNonceAccount {
|
||||
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
||||
nonce_authority: Some(
|
||||
read_keypair_file(&authority_keypair_file).unwrap().into()
|
||||
),
|
||||
nonce_authority: 1,
|
||||
new_authority: Pubkey::default(),
|
||||
},
|
||||
require_keypair: true,
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
read_keypair_file(&authority_keypair_file).unwrap().into()
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
@ -667,15 +705,18 @@ mod tests {
|
||||
"50",
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_create_nonce_account).unwrap(),
|
||||
parse_command(&test_create_nonce_account, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::CreateNonceAccount {
|
||||
nonce_account: Rc::new(read_keypair_file(&keypair_file).unwrap().into()),
|
||||
nonce_account: 1,
|
||||
seed: None,
|
||||
nonce_authority: None,
|
||||
lamports: 50_000_000_000,
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
read_keypair_file(&keypair_file).unwrap().into()
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
@ -689,17 +730,18 @@ mod tests {
|
||||
&authority_keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_create_nonce_account).unwrap(),
|
||||
parse_command(&test_create_nonce_account, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::CreateNonceAccount {
|
||||
nonce_account: Rc::new(read_keypair_file(&keypair_file).unwrap().into()),
|
||||
nonce_account: 1,
|
||||
seed: None,
|
||||
nonce_authority: Some(
|
||||
read_keypair_file(&authority_keypair_file).unwrap().pubkey()
|
||||
),
|
||||
nonce_authority: Some(nonce_authority_keypair.pubkey()),
|
||||
lamports: 50_000_000_000,
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
read_keypair_file(&keypair_file).unwrap().into()
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
@ -710,10 +752,10 @@ mod tests {
|
||||
&nonce_account_string,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_get_nonce).unwrap(),
|
||||
parse_command(&test_get_nonce, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::GetNonce(nonce_account_keypair.pubkey(),),
|
||||
require_keypair: false
|
||||
command: CliCommand::GetNonce(nonce_account_keypair.pubkey()),
|
||||
signers: vec![],
|
||||
}
|
||||
);
|
||||
|
||||
@ -724,13 +766,13 @@ mod tests {
|
||||
.get_matches_from(vec!["test", "new-nonce", &keypair_file]);
|
||||
let nonce_account = read_keypair_file(&keypair_file).unwrap();
|
||||
assert_eq!(
|
||||
parse_command(&test_new_nonce).unwrap(),
|
||||
parse_command(&test_new_nonce, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::NewNonce {
|
||||
nonce_account: nonce_account.pubkey(),
|
||||
nonce_authority: None,
|
||||
nonce_authority: 0,
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||
}
|
||||
);
|
||||
|
||||
@ -744,15 +786,16 @@ mod tests {
|
||||
]);
|
||||
let nonce_account = read_keypair_file(&keypair_file).unwrap();
|
||||
assert_eq!(
|
||||
parse_command(&test_new_nonce).unwrap(),
|
||||
parse_command(&test_new_nonce, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::NewNonce {
|
||||
nonce_account: nonce_account.pubkey(),
|
||||
nonce_authority: Some(
|
||||
read_keypair_file(&authority_keypair_file).unwrap().into()
|
||||
),
|
||||
nonce_authority: 1,
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
read_keypair_file(&authority_keypair_file).unwrap().into()
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
@ -763,13 +806,13 @@ mod tests {
|
||||
&nonce_account_string,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_show_nonce_account).unwrap(),
|
||||
parse_command(&test_show_nonce_account, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::ShowNonceAccount {
|
||||
nonce_account_pubkey: nonce_account_keypair.pubkey(),
|
||||
use_lamports_unit: false,
|
||||
},
|
||||
require_keypair: false
|
||||
signers: vec![],
|
||||
}
|
||||
);
|
||||
|
||||
@ -782,15 +825,20 @@ mod tests {
|
||||
"42",
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_withdraw_from_nonce_account).unwrap(),
|
||||
parse_command(
|
||||
&test_withdraw_from_nonce_account,
|
||||
&default_keypair_file,
|
||||
None
|
||||
)
|
||||
.unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::WithdrawFromNonceAccount {
|
||||
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
||||
nonce_authority: None,
|
||||
nonce_authority: 0,
|
||||
destination_account_pubkey: nonce_account_pubkey,
|
||||
lamports: 42_000_000_000
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||
}
|
||||
);
|
||||
|
||||
@ -802,15 +850,20 @@ mod tests {
|
||||
"42",
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_withdraw_from_nonce_account).unwrap(),
|
||||
parse_command(
|
||||
&test_withdraw_from_nonce_account,
|
||||
&default_keypair_file,
|
||||
None
|
||||
)
|
||||
.unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::WithdrawFromNonceAccount {
|
||||
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
||||
nonce_authority: None,
|
||||
nonce_authority: 0,
|
||||
destination_account_pubkey: nonce_account_pubkey,
|
||||
lamports: 42000000000
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||
}
|
||||
);
|
||||
|
||||
@ -825,17 +878,23 @@ mod tests {
|
||||
&authority_keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_withdraw_from_nonce_account).unwrap(),
|
||||
parse_command(
|
||||
&test_withdraw_from_nonce_account,
|
||||
&default_keypair_file,
|
||||
None
|
||||
)
|
||||
.unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::WithdrawFromNonceAccount {
|
||||
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
||||
nonce_authority: Some(
|
||||
read_keypair_file(&authority_keypair_file).unwrap().into()
|
||||
),
|
||||
nonce_authority: 1,
|
||||
destination_account_pubkey: nonce_account_pubkey,
|
||||
lamports: 42_000_000_000
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
read_keypair_file(&authority_keypair_file).unwrap().into()
|
||||
],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
959
cli/src/stake.rs
959
cli/src/stake.rs
File diff suppressed because it is too large
Load Diff
@ -1,16 +1,17 @@
|
||||
use crate::cli::{
|
||||
check_account_for_fee, check_unique_pubkeys, log_instruction_custom_error, CliCommand,
|
||||
CliCommandInfo, CliConfig, CliError, ProcessResult,
|
||||
CliCommandInfo, CliConfig, CliError, ProcessResult, SignerIndex,
|
||||
};
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use solana_clap_utils::{input_parsers::*, input_validators::*};
|
||||
use solana_clap_utils::{input_parsers::*, input_validators::*, keypair::signer_from_path};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_sdk::signature::Keypair;
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use solana_sdk::{
|
||||
account_utils::StateMut, message::Message, pubkey::Pubkey, signature::Signer,
|
||||
system_instruction::SystemError, transaction::Transaction,
|
||||
account_utils::StateMut, message::Message, pubkey::Pubkey, system_instruction::SystemError,
|
||||
transaction::Transaction,
|
||||
};
|
||||
use solana_storage_program::storage_instruction::{self, StorageAccountType};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait StorageSubCommands {
|
||||
fn storage_subcommands(self) -> Self;
|
||||
@ -99,35 +100,49 @@ impl StorageSubCommands for App<'_, '_> {
|
||||
|
||||
pub fn parse_storage_create_archiver_account(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer_path: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
|
||||
let storage_account = keypair_of(matches, "storage_account").unwrap();
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::CreateStorageAccount {
|
||||
account_owner,
|
||||
storage_account: storage_account.into(),
|
||||
storage_account: 1,
|
||||
account_type: StorageAccountType::Archiver,
|
||||
},
|
||||
require_keypair: true,
|
||||
signers: vec![
|
||||
signer_from_path(matches, default_signer_path, "keypair", wallet_manager)?,
|
||||
storage_account.into(),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_storage_create_validator_account(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer_path: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
|
||||
let storage_account = keypair_of(matches, "storage_account").unwrap();
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::CreateStorageAccount {
|
||||
account_owner,
|
||||
storage_account: storage_account.into(),
|
||||
storage_account: 1,
|
||||
account_type: StorageAccountType::Validator,
|
||||
},
|
||||
require_keypair: true,
|
||||
signers: vec![
|
||||
signer_from_path(matches, default_signer_path, "keypair", wallet_manager)?,
|
||||
storage_account.into(),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_storage_claim_reward(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
pub fn parse_storage_claim_reward(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer_path: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let node_account_pubkey = pubkey_of(matches, "node_account_pubkey").unwrap();
|
||||
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
||||
Ok(CliCommandInfo {
|
||||
@ -135,7 +150,12 @@ pub fn parse_storage_claim_reward(matches: &ArgMatches<'_>) -> Result<CliCommand
|
||||
node_account_pubkey,
|
||||
storage_account_pubkey,
|
||||
},
|
||||
require_keypair: true,
|
||||
signers: vec![signer_from_path(
|
||||
matches,
|
||||
default_signer_path,
|
||||
"keypair",
|
||||
wallet_manager,
|
||||
)?],
|
||||
})
|
||||
}
|
||||
|
||||
@ -145,20 +165,21 @@ pub fn parse_storage_get_account_command(
|
||||
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::ShowStorageAccount(storage_account_pubkey),
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process_create_storage_account(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
storage_account: SignerIndex,
|
||||
account_owner: &Pubkey,
|
||||
storage_account: &Keypair,
|
||||
account_type: StorageAccountType,
|
||||
) -> ProcessResult {
|
||||
let storage_account = config.signers[storage_account];
|
||||
let storage_account_pubkey = storage_account.pubkey();
|
||||
check_unique_pubkeys(
|
||||
(&config.keypair.pubkey(), "cli keypair".to_string()),
|
||||
(&config.signers[0].pubkey(), "cli keypair".to_string()),
|
||||
(
|
||||
&storage_account_pubkey,
|
||||
"storage_account_pubkey".to_string(),
|
||||
@ -183,7 +204,7 @@ pub fn process_create_storage_account(
|
||||
.max(1);
|
||||
|
||||
let ixs = storage_instruction::create_storage_account(
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&account_owner,
|
||||
&storage_account_pubkey,
|
||||
required_balance,
|
||||
@ -193,18 +214,14 @@ pub fn process_create_storage_account(
|
||||
|
||||
let message = Message::new(ixs);
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(
|
||||
&[config.keypair.as_ref(), storage_account],
|
||||
recent_blockhash,
|
||||
)?;
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
check_account_for_fee(
|
||||
rpc_client,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client
|
||||
.send_and_confirm_transaction(&mut tx, &[config.keypair.as_ref(), storage_account]);
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.signers);
|
||||
log_instruction_custom_error::<SystemError>(result)
|
||||
}
|
||||
|
||||
@ -218,13 +235,13 @@ pub fn process_claim_storage_reward(
|
||||
|
||||
let instruction =
|
||||
storage_instruction::claim_reward(node_account_pubkey, storage_account_pubkey);
|
||||
let signers = [config.keypair.as_ref()];
|
||||
let signers = [config.signers[0]];
|
||||
let message = Message::new_with_payer(vec![instruction], Some(&signers[0].pubkey()));
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(&signers, recent_blockhash)?;
|
||||
check_account_for_fee(
|
||||
rpc_client,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
@ -260,7 +277,7 @@ pub fn process_show_storage_account(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::cli::{app, parse_command};
|
||||
use solana_sdk::signature::write_keypair;
|
||||
use solana_sdk::signature::{read_keypair_file, write_keypair, Keypair, Signer};
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
fn make_tmp_file() -> (String, NamedTempFile) {
|
||||
@ -274,6 +291,10 @@ mod tests {
|
||||
let pubkey = Pubkey::new_rand();
|
||||
let pubkey_string = pubkey.to_string();
|
||||
|
||||
let default_keypair = Keypair::new();
|
||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
|
||||
let (keypair_file, mut tmp_file) = make_tmp_file();
|
||||
let storage_account_keypair = Keypair::new();
|
||||
write_keypair(&storage_account_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
@ -285,14 +306,22 @@ mod tests {
|
||||
&keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_create_archiver_storage_account).unwrap(),
|
||||
parse_command(
|
||||
&test_create_archiver_storage_account,
|
||||
&default_keypair_file,
|
||||
None
|
||||
)
|
||||
.unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::CreateStorageAccount {
|
||||
account_owner: pubkey,
|
||||
storage_account: storage_account_keypair.into(),
|
||||
storage_account: 1,
|
||||
account_type: StorageAccountType::Archiver,
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
storage_account_keypair.into()
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
@ -309,14 +338,22 @@ mod tests {
|
||||
&keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_create_validator_storage_account).unwrap(),
|
||||
parse_command(
|
||||
&test_create_validator_storage_account,
|
||||
&default_keypair_file,
|
||||
None
|
||||
)
|
||||
.unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::CreateStorageAccount {
|
||||
account_owner: pubkey,
|
||||
storage_account: storage_account_keypair.into(),
|
||||
storage_account: 1,
|
||||
account_type: StorageAccountType::Validator,
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
storage_account_keypair.into()
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
@ -327,13 +364,13 @@ mod tests {
|
||||
&storage_account_string,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_claim_storage_reward).unwrap(),
|
||||
parse_command(&test_claim_storage_reward, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::ClaimStorageReward {
|
||||
node_account_pubkey: pubkey,
|
||||
storage_account_pubkey,
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -11,9 +11,11 @@ use serde_json::{Map, Value};
|
||||
use solana_clap_utils::{
|
||||
input_parsers::pubkey_of,
|
||||
input_validators::{is_pubkey, is_url},
|
||||
keypair::signer_from_path,
|
||||
};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_config_program::{config_instruction, get_config_data, ConfigKeys, ConfigState};
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
commitment_config::CommitmentConfig,
|
||||
@ -22,7 +24,7 @@ use solana_sdk::{
|
||||
signature::{Keypair, Signer},
|
||||
transaction::Transaction,
|
||||
};
|
||||
use std::error;
|
||||
use std::{error, sync::Arc};
|
||||
use titlecase::titlecase;
|
||||
|
||||
pub const MAX_SHORT_FIELD_LENGTH: usize = 70;
|
||||
@ -224,17 +226,26 @@ impl ValidatorInfoSubCommands for App<'_, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_validator_info_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
pub fn parse_validator_info_command(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer_path: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let info_pubkey = pubkey_of(matches, "info_pubkey");
|
||||
// Prepare validator info
|
||||
let validator_info = parse_args(&matches);
|
||||
let validator_info = parse_args(matches);
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::SetValidatorInfo {
|
||||
validator_info,
|
||||
force_keybase: matches.is_present("force"),
|
||||
info_pubkey,
|
||||
},
|
||||
require_keypair: true,
|
||||
signers: vec![signer_from_path(
|
||||
matches,
|
||||
default_signer_path,
|
||||
"keypair",
|
||||
wallet_manager,
|
||||
)?],
|
||||
})
|
||||
}
|
||||
|
||||
@ -244,7 +255,7 @@ pub fn parse_get_validator_info_command(
|
||||
let info_pubkey = pubkey_of(matches, "info_pubkey");
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::GetValidatorInfo(info_pubkey),
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
@ -257,7 +268,7 @@ pub fn process_set_validator_info(
|
||||
) -> ProcessResult {
|
||||
// Validate keybase username
|
||||
if let Some(string) = validator_info.get("keybaseUsername") {
|
||||
let result = verify_keybase(&config.keypair.pubkey(), &string);
|
||||
let result = verify_keybase(&config.signers[0].pubkey(), &string);
|
||||
if result.is_err() {
|
||||
if force_keybase {
|
||||
println!("--force supplied, ignoring: {:?}", result);
|
||||
@ -282,7 +293,7 @@ pub fn process_set_validator_info(
|
||||
})
|
||||
.find(|(pubkey, account)| {
|
||||
let (validator_pubkey, _) = parse_validator_info(&pubkey, &account).unwrap();
|
||||
validator_pubkey == config.keypair.pubkey()
|
||||
validator_pubkey == config.signers[0].pubkey()
|
||||
});
|
||||
|
||||
// Create validator-info keypair to use if info_pubkey not provided or does not exist
|
||||
@ -300,7 +311,7 @@ pub fn process_set_validator_info(
|
||||
.poll_get_balance_with_commitment(&info_pubkey, CommitmentConfig::default())
|
||||
.unwrap_or(0);
|
||||
|
||||
let keys = vec![(id(), false), (config.keypair.pubkey(), true)];
|
||||
let keys = vec![(id(), false), (config.signers[0].pubkey(), true)];
|
||||
let (message, signers): (Message, Vec<&dyn Signer>) = if balance == 0 {
|
||||
if info_pubkey != info_keypair.pubkey() {
|
||||
println!(
|
||||
@ -311,12 +322,12 @@ pub fn process_set_validator_info(
|
||||
}
|
||||
println!(
|
||||
"Publishing info for Validator {:?}",
|
||||
config.keypair.pubkey()
|
||||
config.signers[0].pubkey()
|
||||
);
|
||||
let lamports = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(ValidatorInfo::max_space() as usize)?;
|
||||
let mut instructions = config_instruction::create_account::<ValidatorInfo>(
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&info_keypair.pubkey(),
|
||||
lamports,
|
||||
keys.clone(),
|
||||
@ -327,13 +338,13 @@ pub fn process_set_validator_info(
|
||||
keys,
|
||||
&validator_info,
|
||||
)]);
|
||||
let signers = vec![config.keypair.as_ref(), &info_keypair];
|
||||
let signers = vec![config.signers[0], &info_keypair];
|
||||
let message = Message::new(instructions);
|
||||
(message, signers)
|
||||
} else {
|
||||
println!(
|
||||
"Updating Validator {:?} info at: {:?}",
|
||||
config.keypair.pubkey(),
|
||||
config.signers[0].pubkey(),
|
||||
info_pubkey
|
||||
);
|
||||
let instructions = vec![config_instruction::store(
|
||||
@ -342,8 +353,8 @@ pub fn process_set_validator_info(
|
||||
keys,
|
||||
&validator_info,
|
||||
)];
|
||||
let message = Message::new_with_payer(instructions, Some(&config.keypair.pubkey()));
|
||||
let signers = vec![config.keypair.as_ref()];
|
||||
let message = Message::new_with_payer(instructions, Some(&config.signers[0].pubkey()));
|
||||
let signers = vec![config.signers[0]];
|
||||
(message, signers)
|
||||
};
|
||||
|
||||
@ -353,7 +364,7 @@ pub fn process_set_validator_info(
|
||||
tx.try_sign(&signers, recent_blockhash)?;
|
||||
check_account_for_fee(
|
||||
rpc_client,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
|
168
cli/src/vote.rs
168
cli/src/vote.rs
@ -1,16 +1,16 @@
|
||||
use crate::cli::{
|
||||
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult,
|
||||
build_balance_message, check_account_for_fee, check_unique_pubkeys, generate_unique_signers,
|
||||
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError, CliSignerInfo,
|
||||
ProcessResult,
|
||||
};
|
||||
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
||||
use solana_clap_utils::{input_parsers::*, input_validators::*};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
signature::Keypair,
|
||||
signature::Signer,
|
||||
system_instruction::{create_address_with_seed, SystemError},
|
||||
transaction::Transaction,
|
||||
};
|
||||
@ -18,6 +18,7 @@ use solana_vote_program::{
|
||||
vote_instruction::{self, VoteError},
|
||||
vote_state::{VoteAuthorize, VoteInit, VoteState},
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait VoteSubCommands {
|
||||
fn vote_subcommands(self) -> Self;
|
||||
@ -176,56 +177,88 @@ impl VoteSubCommands for App<'_, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_vote_create_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
let vote_account = keypair_of(matches, "vote_account").unwrap();
|
||||
pub fn parse_vote_create_account(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer_path: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let (vote_account, _) = signer_of(matches, "vote_account", wallet_manager)?;
|
||||
let seed = matches.value_of("seed").map(|s| s.to_string());
|
||||
let identity_pubkey = pubkey_of(matches, "identity_pubkey").unwrap();
|
||||
let commission = value_t_or_exit!(matches, "commission", u8);
|
||||
let authorized_voter = pubkey_of(matches, "authorized_voter");
|
||||
let authorized_withdrawer = pubkey_of(matches, "authorized_withdrawer");
|
||||
|
||||
let payer_provided = None;
|
||||
let CliSignerInfo { signers } = generate_unique_signers(
|
||||
vec![payer_provided, vote_account],
|
||||
matches,
|
||||
default_signer_path,
|
||||
wallet_manager,
|
||||
)?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::CreateVoteAccount {
|
||||
vote_account: vote_account.into(),
|
||||
seed,
|
||||
node_pubkey: identity_pubkey,
|
||||
authorized_voter,
|
||||
authorized_withdrawer,
|
||||
commission,
|
||||
},
|
||||
require_keypair: true,
|
||||
signers,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_vote_authorize(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer_path: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
vote_authorize: VoteAuthorize,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||
let new_authorized_pubkey = pubkey_of(matches, "new_authorized_pubkey").unwrap();
|
||||
|
||||
let authorized_voter_provided = None;
|
||||
let CliSignerInfo { signers } = generate_unique_signers(
|
||||
vec![authorized_voter_provided],
|
||||
matches,
|
||||
default_signer_path,
|
||||
wallet_manager,
|
||||
)?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::VoteAuthorize {
|
||||
vote_account_pubkey,
|
||||
new_authorized_pubkey,
|
||||
vote_authorize,
|
||||
},
|
||||
require_keypair: true,
|
||||
signers,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_vote_update_validator(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
pub fn parse_vote_update_validator(
|
||||
matches: &ArgMatches<'_>,
|
||||
default_signer_path: &str,
|
||||
wallet_manager: Option<&Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||
let new_identity_pubkey = pubkey_of(matches, "new_identity_pubkey").unwrap();
|
||||
let authorized_voter = keypair_of(matches, "authorized_voter").unwrap();
|
||||
let (authorized_voter, _) = signer_of(matches, "authorized_voter", wallet_manager)?;
|
||||
|
||||
let payer_provided = None;
|
||||
let CliSignerInfo { signers } = generate_unique_signers(
|
||||
vec![payer_provided, authorized_voter],
|
||||
matches,
|
||||
default_signer_path,
|
||||
wallet_manager,
|
||||
)?;
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::VoteUpdateValidator {
|
||||
vote_account_pubkey,
|
||||
new_identity_pubkey,
|
||||
authorized_voter: authorized_voter.into(),
|
||||
},
|
||||
require_keypair: true,
|
||||
signers,
|
||||
})
|
||||
}
|
||||
|
||||
@ -239,20 +272,20 @@ pub fn parse_vote_get_account_command(
|
||||
pubkey: vote_account_pubkey,
|
||||
use_lamports_unit,
|
||||
},
|
||||
require_keypair: false,
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process_create_vote_account(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
vote_account: &Keypair,
|
||||
seed: &Option<String>,
|
||||
identity_pubkey: &Pubkey,
|
||||
authorized_voter: &Option<Pubkey>,
|
||||
authorized_withdrawer: &Option<Pubkey>,
|
||||
commission: u8,
|
||||
) -> ProcessResult {
|
||||
let vote_account = config.signers[1];
|
||||
let vote_account_pubkey = vote_account.pubkey();
|
||||
let vote_account_address = if let Some(seed) = seed {
|
||||
create_address_with_seed(&vote_account_pubkey, &seed, &solana_vote_program::id())?
|
||||
@ -260,7 +293,7 @@ pub fn process_create_vote_account(
|
||||
vote_account_pubkey
|
||||
};
|
||||
check_unique_pubkeys(
|
||||
(&config.keypair.pubkey(), "cli keypair".to_string()),
|
||||
(&config.signers[0].pubkey(), "cli keypair".to_string()),
|
||||
(&vote_account_address, "vote_account".to_string()),
|
||||
)?;
|
||||
|
||||
@ -294,16 +327,16 @@ pub fn process_create_vote_account(
|
||||
|
||||
let ixs = if let Some(seed) = seed {
|
||||
vote_instruction::create_account_with_seed(
|
||||
&config.keypair.pubkey(), // from
|
||||
&vote_account_address, // to
|
||||
&vote_account_pubkey, // base
|
||||
seed, // seed
|
||||
&config.signers[0].pubkey(), // from
|
||||
&vote_account_address, // to
|
||||
&vote_account_pubkey, // base
|
||||
seed, // seed
|
||||
&vote_init,
|
||||
required_balance,
|
||||
)
|
||||
} else {
|
||||
vote_instruction::create_account(
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&vote_account_pubkey,
|
||||
&vote_init,
|
||||
required_balance,
|
||||
@ -311,22 +344,16 @@ pub fn process_create_vote_account(
|
||||
};
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
|
||||
let signers = if vote_account_pubkey != config.keypair.pubkey() {
|
||||
vec![config.keypair.as_ref(), vote_account] // both must sign if `from` and `to` differ
|
||||
} else {
|
||||
vec![config.keypair.as_ref()] // when stake_account == config.keypair and there's a seed, we only need one signature
|
||||
};
|
||||
|
||||
let message = Message::new(ixs);
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(&signers, recent_blockhash)?;
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
check_account_for_fee(
|
||||
rpc_client,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &signers);
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.signers);
|
||||
log_instruction_custom_error::<SystemError>(result)
|
||||
}
|
||||
|
||||
@ -343,22 +370,22 @@ pub fn process_vote_authorize(
|
||||
)?;
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let ixs = vec![vote_instruction::authorize(
|
||||
vote_account_pubkey, // vote account to update
|
||||
&config.keypair.pubkey(), // current authorized voter
|
||||
new_authorized_pubkey, // new vote signer/withdrawer
|
||||
vote_authorize, // vote or withdraw
|
||||
vote_account_pubkey, // vote account to update
|
||||
&config.signers[0].pubkey(), // current authorized voter
|
||||
new_authorized_pubkey, // new vote signer/withdrawer
|
||||
vote_authorize, // vote or withdraw
|
||||
)];
|
||||
|
||||
let message = Message::new_with_payer(ixs, Some(&config.keypair.pubkey()));
|
||||
let message = Message::new_with_payer(ixs, Some(&config.signers[0].pubkey()));
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(&[config.keypair.as_ref()], recent_blockhash)?;
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
check_account_for_fee(
|
||||
rpc_client,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[config.keypair.as_ref()]);
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[config.signers[0]]);
|
||||
log_instruction_custom_error::<VoteError>(result)
|
||||
}
|
||||
|
||||
@ -367,8 +394,8 @@ pub fn process_vote_update_validator(
|
||||
config: &CliConfig,
|
||||
vote_account_pubkey: &Pubkey,
|
||||
new_identity_pubkey: &Pubkey,
|
||||
authorized_voter: &Keypair,
|
||||
) -> ProcessResult {
|
||||
let authorized_voter = config.signers[1];
|
||||
check_unique_pubkeys(
|
||||
(vote_account_pubkey, "vote_account_pubkey".to_string()),
|
||||
(new_identity_pubkey, "new_identity_pubkey".to_string()),
|
||||
@ -380,19 +407,16 @@ pub fn process_vote_update_validator(
|
||||
new_identity_pubkey,
|
||||
)];
|
||||
|
||||
let message = Message::new_with_payer(ixs, Some(&config.keypair.pubkey()));
|
||||
let message = Message::new_with_payer(ixs, Some(&config.signers[0].pubkey()));
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(
|
||||
&[config.keypair.as_ref(), authorized_voter],
|
||||
recent_blockhash,
|
||||
)?;
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
check_account_for_fee(
|
||||
rpc_client,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
&fee_calculator,
|
||||
&tx.message,
|
||||
)?;
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &[config.keypair.as_ref()]);
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.signers);
|
||||
log_instruction_custom_error::<VoteError>(result)
|
||||
}
|
||||
|
||||
@ -474,7 +498,7 @@ pub fn process_show_vote_account(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::cli::{app, parse_command};
|
||||
use solana_sdk::signature::write_keypair;
|
||||
use solana_sdk::signature::{read_keypair_file, write_keypair, Keypair, Signer};
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
fn make_tmp_file() -> (String, NamedTempFile) {
|
||||
@ -492,6 +516,10 @@ mod tests {
|
||||
let pubkey2 = keypair2.pubkey();
|
||||
let pubkey2_string = pubkey2.to_string();
|
||||
|
||||
let default_keypair = Keypair::new();
|
||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
|
||||
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"vote-authorize-voter",
|
||||
@ -499,14 +527,14 @@ mod tests {
|
||||
&pubkey2_string,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_authorize_voter).unwrap(),
|
||||
parse_command(&test_authorize_voter, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::VoteAuthorize {
|
||||
vote_account_pubkey: pubkey,
|
||||
new_authorized_pubkey: pubkey2,
|
||||
vote_authorize: VoteAuthorize::Voter
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||
}
|
||||
);
|
||||
|
||||
@ -525,17 +553,19 @@ mod tests {
|
||||
"10",
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_create_vote_account).unwrap(),
|
||||
parse_command(&test_create_vote_account, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::CreateVoteAccount {
|
||||
vote_account: keypair.into(),
|
||||
seed: None,
|
||||
node_pubkey,
|
||||
authorized_voter: None,
|
||||
authorized_withdrawer: None,
|
||||
commission: 10,
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
Box::new(keypair)
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
@ -550,17 +580,19 @@ mod tests {
|
||||
&node_pubkey_string,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_create_vote_account2).unwrap(),
|
||||
parse_command(&test_create_vote_account2, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::CreateVoteAccount {
|
||||
vote_account: keypair.into(),
|
||||
seed: None,
|
||||
node_pubkey,
|
||||
authorized_voter: None,
|
||||
authorized_withdrawer: None,
|
||||
commission: 100,
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
Box::new(keypair)
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
@ -579,17 +611,19 @@ mod tests {
|
||||
&authed.to_string(),
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_create_vote_account3).unwrap(),
|
||||
parse_command(&test_create_vote_account3, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::CreateVoteAccount {
|
||||
vote_account: keypair.into(),
|
||||
seed: None,
|
||||
node_pubkey,
|
||||
authorized_voter: Some(authed),
|
||||
authorized_withdrawer: None,
|
||||
commission: 100
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
Box::new(keypair)
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
@ -606,17 +640,19 @@ mod tests {
|
||||
&authed.to_string(),
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_create_vote_account4).unwrap(),
|
||||
parse_command(&test_create_vote_account4, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::CreateVoteAccount {
|
||||
vote_account: keypair.into(),
|
||||
seed: None,
|
||||
node_pubkey,
|
||||
authorized_voter: None,
|
||||
authorized_withdrawer: Some(authed),
|
||||
commission: 100
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
Box::new(keypair)
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
@ -628,16 +664,16 @@ mod tests {
|
||||
&keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_update_validator).unwrap(),
|
||||
parse_command(&test_update_validator, &default_keypair_file, None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::VoteUpdateValidator {
|
||||
vote_account_pubkey: pubkey,
|
||||
new_identity_pubkey: pubkey2,
|
||||
authorized_voter: solana_sdk::signature::read_keypair_file(&keypair_file)
|
||||
.unwrap()
|
||||
.into(),
|
||||
},
|
||||
require_keypair: true
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
Box::new(read_keypair_file(&keypair_file).unwrap())
|
||||
],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use solana_cli::cli::{process_command, CliCommand, CliConfig};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_core::validator::new_validator_for_tests;
|
||||
use solana_faucet::faucet::run_local_faucet;
|
||||
use solana_sdk::{bpf_loader, pubkey::Pubkey};
|
||||
use solana_sdk::{bpf_loader, pubkey::Pubkey, signature::Keypair};
|
||||
use std::{
|
||||
fs::{remove_dir_all, File},
|
||||
io::Read,
|
||||
@ -38,6 +38,7 @@ fn test_cli_deploy_program() {
|
||||
.unwrap();
|
||||
|
||||
let mut config = CliConfig::default();
|
||||
let keypair = Keypair::new();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.command = CliCommand::Airdrop {
|
||||
faucet_host: None,
|
||||
@ -45,6 +46,7 @@ fn test_cli_deploy_program() {
|
||||
pubkey: None,
|
||||
lamports: minimum_balance_for_rent_exemption + 1, // min balance for rent exemption + leftover for tx processing
|
||||
};
|
||||
config.signers = vec![&keypair];
|
||||
process_command(&config).unwrap();
|
||||
|
||||
config.command = CliCommand::Deploy(pathbuf.to_str().unwrap().to_string());
|
||||
|
@ -4,25 +4,14 @@ use solana_faucet::faucet::run_local_faucet;
|
||||
use solana_sdk::{
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
signature::{keypair_from_seed, read_keypair_file, write_keypair, Keypair, Signer},
|
||||
signature::{keypair_from_seed, Keypair, Signer},
|
||||
system_instruction::create_address_with_seed,
|
||||
system_program,
|
||||
};
|
||||
use std::fs::remove_dir_all;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::{fs::remove_dir_all, sync::mpsc::channel, thread::sleep, time::Duration};
|
||||
|
||||
#[cfg(test)]
|
||||
use solana_core::validator::new_validator_for_tests;
|
||||
use std::rc::Rc;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
fn make_tmp_file() -> (String, NamedTempFile) {
|
||||
let tmp_file = NamedTempFile::new().unwrap();
|
||||
(String::from(tmp_file.path().to_str().unwrap()), tmp_file)
|
||||
}
|
||||
|
||||
fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
|
||||
(0..5).for_each(|tries| {
|
||||
@ -45,28 +34,9 @@ fn test_nonce() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
let keypair = keypair_from_seed(&[0u8; 32]).unwrap();
|
||||
let (keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
|
||||
let mut config_nonce = CliConfig::default();
|
||||
config_nonce.keypair = keypair.into();
|
||||
config_nonce.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
full_battery_tests(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&mut config_payer,
|
||||
&mut config_nonce,
|
||||
&keypair_file,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
full_battery_tests(&rpc_client, &faucet_addr, json_rpc_url, None, false);
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
@ -80,27 +50,14 @@ fn test_nonce_with_seed() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
let keypair = keypair_from_seed(&[0u8; 32]).unwrap();
|
||||
let (keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
|
||||
let mut config_nonce = CliConfig::default();
|
||||
config_nonce.keypair = keypair.into();
|
||||
config_nonce.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
let json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
full_battery_tests(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&mut config_payer,
|
||||
&mut config_nonce,
|
||||
&keypair_file,
|
||||
json_rpc_url,
|
||||
Some(String::from("seed")),
|
||||
None,
|
||||
false,
|
||||
);
|
||||
|
||||
server.close().unwrap();
|
||||
@ -115,78 +72,73 @@ fn test_nonce_with_authority() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
let nonce_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
|
||||
let (nonce_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&nonce_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
let mut config_nonce = CliConfig::default();
|
||||
config_nonce.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
|
||||
let nonce_authority = Keypair::new();
|
||||
let (authority_keypair_file, mut tmp_file2) = make_tmp_file();
|
||||
write_keypair(&nonce_authority, tmp_file2.as_file_mut()).unwrap();
|
||||
|
||||
full_battery_tests(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&mut config_payer,
|
||||
&mut config_nonce,
|
||||
&nonce_keypair_file,
|
||||
None,
|
||||
Some(&authority_keypair_file),
|
||||
);
|
||||
full_battery_tests(&rpc_client, &faucet_addr, json_rpc_url, None, true);
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
}
|
||||
|
||||
fn read_keypair_from_option(keypair_file: &Option<&str>) -> Option<Box<dyn Signer>> {
|
||||
keypair_file.map(|akf| read_keypair_file(&akf).unwrap().into())
|
||||
}
|
||||
|
||||
fn full_battery_tests(
|
||||
rpc_client: &RpcClient,
|
||||
faucet_addr: &std::net::SocketAddr,
|
||||
config_payer: &mut CliConfig,
|
||||
config_nonce: &mut CliConfig,
|
||||
nonce_keypair_file: &str,
|
||||
json_rpc_url: String,
|
||||
seed: Option<String>,
|
||||
authority_keypair_file: Option<&str>,
|
||||
use_nonce_authority: bool,
|
||||
) {
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url = json_rpc_url.clone();
|
||||
let payer = Keypair::new();
|
||||
config_payer.signers = vec![&payer];
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_payer.keypair.pubkey(),
|
||||
&config_payer.signers[0].pubkey(),
|
||||
2000,
|
||||
)
|
||||
.unwrap();
|
||||
check_balance(2000, &rpc_client, &config_payer.keypair.pubkey());
|
||||
check_balance(2000, &rpc_client, &config_payer.signers[0].pubkey());
|
||||
|
||||
let mut config_nonce = CliConfig::default();
|
||||
config_nonce.json_rpc_url = json_rpc_url;
|
||||
let nonce_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
|
||||
config_nonce.signers = vec![&nonce_keypair];
|
||||
|
||||
let nonce_account = if let Some(seed) = seed.as_ref() {
|
||||
create_address_with_seed(&config_nonce.keypair.pubkey(), seed, &system_program::id())
|
||||
.unwrap()
|
||||
create_address_with_seed(
|
||||
&config_nonce.signers[0].pubkey(),
|
||||
seed,
|
||||
&system_program::id(),
|
||||
)
|
||||
.unwrap()
|
||||
} else {
|
||||
read_keypair_file(&nonce_keypair_file).unwrap().pubkey()
|
||||
nonce_keypair.pubkey()
|
||||
};
|
||||
|
||||
let nonce_authority = Keypair::new();
|
||||
let optional_authority = if use_nonce_authority {
|
||||
Some(nonce_authority.pubkey())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Create nonce account
|
||||
config_payer.signers.push(&nonce_keypair);
|
||||
config_payer.command = CliCommand::CreateNonceAccount {
|
||||
nonce_account: Rc::new(read_keypair_file(&nonce_keypair_file).unwrap().into()),
|
||||
nonce_account: 1,
|
||||
seed,
|
||||
nonce_authority: read_keypair_from_option(&authority_keypair_file).map(|k| k.pubkey()),
|
||||
nonce_authority: optional_authority,
|
||||
lamports: 1000,
|
||||
};
|
||||
|
||||
process_command(&config_payer).unwrap();
|
||||
check_balance(1000, &rpc_client, &config_payer.keypair.pubkey());
|
||||
check_balance(1000, &rpc_client, &config_payer.signers[0].pubkey());
|
||||
check_balance(1000, &rpc_client, &nonce_account);
|
||||
|
||||
// Get nonce
|
||||
config_payer.signers.pop();
|
||||
config_payer.command = CliCommand::GetNonce(nonce_account);
|
||||
let first_nonce_string = process_command(&config_payer).unwrap();
|
||||
let first_nonce = first_nonce_string.parse::<Hash>().unwrap();
|
||||
@ -198,14 +150,24 @@ fn full_battery_tests(
|
||||
|
||||
assert_eq!(first_nonce, second_nonce);
|
||||
|
||||
let mut authorized_signers: Vec<&dyn Signer> = vec![&payer];
|
||||
let index = if use_nonce_authority {
|
||||
authorized_signers.push(&nonce_authority);
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
// New nonce
|
||||
config_payer.signers = authorized_signers.clone();
|
||||
config_payer.command = CliCommand::NewNonce {
|
||||
nonce_account,
|
||||
nonce_authority: read_keypair_from_option(&authority_keypair_file),
|
||||
nonce_authority: index,
|
||||
};
|
||||
process_command(&config_payer).unwrap();
|
||||
|
||||
// Get nonce
|
||||
config_payer.signers = vec![&payer];
|
||||
config_payer.command = CliCommand::GetNonce(nonce_account);
|
||||
let third_nonce_string = process_command(&config_payer).unwrap();
|
||||
let third_nonce = third_nonce_string.parse::<Hash>().unwrap();
|
||||
@ -214,14 +176,15 @@ fn full_battery_tests(
|
||||
|
||||
// Withdraw from nonce account
|
||||
let payee_pubkey = Pubkey::new_rand();
|
||||
config_payer.signers = authorized_signers;
|
||||
config_payer.command = CliCommand::WithdrawFromNonceAccount {
|
||||
nonce_account,
|
||||
nonce_authority: read_keypair_from_option(&authority_keypair_file),
|
||||
nonce_authority: index,
|
||||
destination_account_pubkey: payee_pubkey,
|
||||
lamports: 100,
|
||||
};
|
||||
process_command(&config_payer).unwrap();
|
||||
check_balance(1000, &rpc_client, &config_payer.keypair.pubkey());
|
||||
check_balance(1000, &rpc_client, &config_payer.signers[0].pubkey());
|
||||
check_balance(900, &rpc_client, &nonce_account);
|
||||
check_balance(100, &rpc_client, &payee_pubkey);
|
||||
|
||||
@ -234,48 +197,37 @@ fn full_battery_tests(
|
||||
|
||||
// Set new authority
|
||||
let new_authority = Keypair::new();
|
||||
let (new_authority_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&new_authority, tmp_file.as_file_mut()).unwrap();
|
||||
config_payer.command = CliCommand::AuthorizeNonceAccount {
|
||||
nonce_account,
|
||||
nonce_authority: read_keypair_from_option(&authority_keypair_file),
|
||||
new_authority: read_keypair_file(&new_authority_keypair_file)
|
||||
.unwrap()
|
||||
.pubkey(),
|
||||
nonce_authority: index,
|
||||
new_authority: new_authority.pubkey(),
|
||||
};
|
||||
process_command(&config_payer).unwrap();
|
||||
|
||||
// Old authority fails now
|
||||
config_payer.command = CliCommand::NewNonce {
|
||||
nonce_account,
|
||||
nonce_authority: read_keypair_from_option(&authority_keypair_file),
|
||||
nonce_authority: index,
|
||||
};
|
||||
process_command(&config_payer).unwrap_err();
|
||||
|
||||
// New authority can advance nonce
|
||||
config_payer.signers = vec![&payer, &new_authority];
|
||||
config_payer.command = CliCommand::NewNonce {
|
||||
nonce_account,
|
||||
nonce_authority: Some(
|
||||
read_keypair_file(&new_authority_keypair_file)
|
||||
.unwrap()
|
||||
.into(),
|
||||
),
|
||||
nonce_authority: 1,
|
||||
};
|
||||
process_command(&config_payer).unwrap();
|
||||
|
||||
// New authority can withdraw from nonce account
|
||||
config_payer.command = CliCommand::WithdrawFromNonceAccount {
|
||||
nonce_account,
|
||||
nonce_authority: Some(
|
||||
read_keypair_file(&new_authority_keypair_file)
|
||||
.unwrap()
|
||||
.into(),
|
||||
),
|
||||
nonce_authority: 1,
|
||||
destination_account_pubkey: payee_pubkey,
|
||||
lamports: 100,
|
||||
};
|
||||
process_command(&config_payer).unwrap();
|
||||
check_balance(1000, &rpc_client, &config_payer.keypair.pubkey());
|
||||
check_balance(1000, &rpc_client, &config_payer.signers[0].pubkey());
|
||||
check_balance(800, &rpc_client, &nonce_account);
|
||||
check_balance(200, &rpc_client, &payee_pubkey);
|
||||
}
|
||||
|
114
cli/tests/pay.rs
114
cli/tests/pay.rs
@ -12,22 +12,12 @@ use solana_sdk::{
|
||||
fee_calculator::FeeCalculator,
|
||||
nonce_state::NonceState,
|
||||
pubkey::Pubkey,
|
||||
signature::{read_keypair_file, write_keypair, Keypair, Signer},
|
||||
signature::{Keypair, Signer},
|
||||
};
|
||||
use std::fs::remove_dir_all;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::{fs::remove_dir_all, sync::mpsc::channel, thread::sleep, time::Duration};
|
||||
|
||||
#[cfg(test)]
|
||||
use solana_core::validator::new_validator_for_tests;
|
||||
use std::rc::Rc;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
fn make_tmp_file() -> (String, NamedTempFile) {
|
||||
let tmp_file = NamedTempFile::new().unwrap();
|
||||
(String::from(tmp_file.path().to_str().unwrap()), tmp_file)
|
||||
}
|
||||
|
||||
fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
|
||||
(0..5).for_each(|tries| {
|
||||
@ -52,32 +42,36 @@ fn test_cli_timestamp_tx() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer0 = Keypair::new();
|
||||
let default_signer1 = Keypair::new();
|
||||
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_payer.signers = vec![&default_signer0];
|
||||
|
||||
let mut config_witness = CliConfig::default();
|
||||
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
|
||||
config_witness.signers = vec![&default_signer1];
|
||||
|
||||
assert_ne!(
|
||||
config_payer.keypair.pubkey(),
|
||||
config_witness.keypair.pubkey()
|
||||
config_payer.signers[0].pubkey(),
|
||||
config_witness.signers[0].pubkey()
|
||||
);
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_payer.keypair.pubkey(),
|
||||
&config_payer.signers[0].pubkey(),
|
||||
50,
|
||||
)
|
||||
.unwrap();
|
||||
check_balance(50, &rpc_client, &config_payer.keypair.pubkey());
|
||||
check_balance(50, &rpc_client, &config_payer.signers[0].pubkey());
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_witness.keypair.pubkey(),
|
||||
&config_witness.signers[0].pubkey(),
|
||||
1,
|
||||
)
|
||||
.unwrap();
|
||||
@ -89,7 +83,7 @@ fn test_cli_timestamp_tx() {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
timestamp: Some(dt),
|
||||
timestamp_pubkey: Some(config_witness.keypair.pubkey()),
|
||||
timestamp_pubkey: Some(config_witness.signers[0].pubkey()),
|
||||
..PayCommand::default()
|
||||
});
|
||||
let sig_response = process_command(&config_payer);
|
||||
@ -101,7 +95,7 @@ fn test_cli_timestamp_tx() {
|
||||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
|
||||
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_balance(10, &rpc_client, &process_id); // contract balance
|
||||
check_balance(0, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
@ -109,7 +103,7 @@ fn test_cli_timestamp_tx() {
|
||||
config_witness.command = CliCommand::TimeElapsed(bob_pubkey, process_id, dt);
|
||||
process_command(&config_witness).unwrap();
|
||||
|
||||
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
|
||||
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_balance(0, &rpc_client, &process_id); // contract balance
|
||||
check_balance(10, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
@ -127,30 +121,34 @@ fn test_cli_witness_tx() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer0 = Keypair::new();
|
||||
let default_signer1 = Keypair::new();
|
||||
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_payer.signers = vec![&default_signer0];
|
||||
|
||||
let mut config_witness = CliConfig::default();
|
||||
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
|
||||
config_witness.signers = vec![&default_signer1];
|
||||
|
||||
assert_ne!(
|
||||
config_payer.keypair.pubkey(),
|
||||
config_witness.keypair.pubkey()
|
||||
config_payer.signers[0].pubkey(),
|
||||
config_witness.signers[0].pubkey()
|
||||
);
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_payer.keypair.pubkey(),
|
||||
&config_payer.signers[0].pubkey(),
|
||||
50,
|
||||
)
|
||||
.unwrap();
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_witness.keypair.pubkey(),
|
||||
&config_witness.signers[0].pubkey(),
|
||||
1,
|
||||
)
|
||||
.unwrap();
|
||||
@ -159,7 +157,7 @@ fn test_cli_witness_tx() {
|
||||
config_payer.command = CliCommand::Pay(PayCommand {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
witnesses: Some(vec![config_witness.keypair.pubkey()]),
|
||||
witnesses: Some(vec![config_witness.signers[0].pubkey()]),
|
||||
..PayCommand::default()
|
||||
});
|
||||
let sig_response = process_command(&config_payer);
|
||||
@ -171,7 +169,7 @@ fn test_cli_witness_tx() {
|
||||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
|
||||
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_balance(10, &rpc_client, &process_id); // contract balance
|
||||
check_balance(0, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
@ -179,7 +177,7 @@ fn test_cli_witness_tx() {
|
||||
config_witness.command = CliCommand::Witness(bob_pubkey, process_id);
|
||||
process_command(&config_witness).unwrap();
|
||||
|
||||
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
|
||||
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_balance(0, &rpc_client, &process_id); // contract balance
|
||||
check_balance(10, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
@ -197,23 +195,27 @@ fn test_cli_cancel_tx() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer0 = Keypair::new();
|
||||
let default_signer1 = Keypair::new();
|
||||
|
||||
let mut config_payer = CliConfig::default();
|
||||
config_payer.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_payer.signers = vec![&default_signer0];
|
||||
|
||||
let mut config_witness = CliConfig::default();
|
||||
config_witness.json_rpc_url = config_payer.json_rpc_url.clone();
|
||||
config_witness.signers = vec![&default_signer1];
|
||||
|
||||
assert_ne!(
|
||||
config_payer.keypair.pubkey(),
|
||||
config_witness.keypair.pubkey()
|
||||
config_payer.signers[0].pubkey(),
|
||||
config_witness.signers[0].pubkey()
|
||||
);
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_payer.keypair.pubkey(),
|
||||
&config_payer.signers[0].pubkey(),
|
||||
50,
|
||||
)
|
||||
.unwrap();
|
||||
@ -222,7 +224,7 @@ fn test_cli_cancel_tx() {
|
||||
config_payer.command = CliCommand::Pay(PayCommand {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
witnesses: Some(vec![config_witness.keypair.pubkey()]),
|
||||
witnesses: Some(vec![config_witness.signers[0].pubkey()]),
|
||||
cancelable: true,
|
||||
..PayCommand::default()
|
||||
});
|
||||
@ -235,7 +237,7 @@ fn test_cli_cancel_tx() {
|
||||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
check_balance(40, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
|
||||
check_balance(40, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_balance(10, &rpc_client, &process_id); // contract balance
|
||||
check_balance(0, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
@ -243,7 +245,7 @@ fn test_cli_cancel_tx() {
|
||||
config_payer.command = CliCommand::Cancel(process_id);
|
||||
process_command(&config_payer).unwrap();
|
||||
|
||||
check_balance(50, &rpc_client, &config_payer.keypair.pubkey()); // config_payer balance
|
||||
check_balance(50, &rpc_client, &config_payer.signers[0].pubkey()); // config_payer balance
|
||||
check_balance(0, &rpc_client, &process_id); // contract balance
|
||||
check_balance(0, &rpc_client, &bob_pubkey); // recipient balance
|
||||
|
||||
@ -261,22 +263,26 @@ fn test_offline_pay_tx() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer = Keypair::new();
|
||||
let default_offline_signer = Keypair::new();
|
||||
|
||||
let mut config_offline = CliConfig::default();
|
||||
config_offline.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_offline.signers = vec![&default_offline_signer];
|
||||
let mut config_online = CliConfig::default();
|
||||
config_online.json_rpc_url =
|
||||
format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config_online.signers = vec![&default_signer];
|
||||
assert_ne!(
|
||||
config_offline.keypair.pubkey(),
|
||||
config_online.keypair.pubkey()
|
||||
config_offline.signers[0].pubkey(),
|
||||
config_online.signers[0].pubkey()
|
||||
);
|
||||
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_offline.keypair.pubkey(),
|
||||
&config_offline.signers[0].pubkey(),
|
||||
50,
|
||||
)
|
||||
.unwrap();
|
||||
@ -284,12 +290,12 @@ fn test_offline_pay_tx() {
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config_online.keypair.pubkey(),
|
||||
&config_online.signers[0].pubkey(),
|
||||
50,
|
||||
)
|
||||
.unwrap();
|
||||
check_balance(50, &rpc_client, &config_offline.keypair.pubkey());
|
||||
check_balance(50, &rpc_client, &config_online.keypair.pubkey());
|
||||
check_balance(50, &rpc_client, &config_offline.signers[0].pubkey());
|
||||
check_balance(50, &rpc_client, &config_online.signers[0].pubkey());
|
||||
|
||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||
config_offline.command = CliCommand::Pay(PayCommand {
|
||||
@ -301,15 +307,15 @@ fn test_offline_pay_tx() {
|
||||
});
|
||||
let sig_response = process_command(&config_offline).unwrap();
|
||||
|
||||
check_balance(50, &rpc_client, &config_offline.keypair.pubkey());
|
||||
check_balance(50, &rpc_client, &config_online.keypair.pubkey());
|
||||
check_balance(50, &rpc_client, &config_offline.signers[0].pubkey());
|
||||
check_balance(50, &rpc_client, &config_online.signers[0].pubkey());
|
||||
check_balance(0, &rpc_client, &bob_pubkey);
|
||||
|
||||
let (blockhash, signers) = parse_sign_only_reply_string(&sig_response);
|
||||
let offline_presigner =
|
||||
presigner_from_pubkey_sigs(&config_offline.keypair.pubkey(), &signers).unwrap();
|
||||
let online_pubkey = config_online.keypair.pubkey();
|
||||
config_online.keypair = offline_presigner.into();
|
||||
presigner_from_pubkey_sigs(&config_offline.signers[0].pubkey(), &signers).unwrap();
|
||||
let online_pubkey = config_online.signers[0].pubkey();
|
||||
config_online.signers = vec![&offline_presigner];
|
||||
config_online.command = CliCommand::Pay(PayCommand {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
@ -318,7 +324,7 @@ fn test_offline_pay_tx() {
|
||||
});
|
||||
process_command(&config_online).unwrap();
|
||||
|
||||
check_balance(40, &rpc_client, &config_offline.keypair.pubkey());
|
||||
check_balance(40, &rpc_client, &config_offline.signers[0].pubkey());
|
||||
check_balance(50, &rpc_client, &online_pubkey);
|
||||
check_balance(10, &rpc_client, &bob_pubkey);
|
||||
|
||||
@ -336,9 +342,11 @@ fn test_nonced_pay_tx() {
|
||||
let faucet_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
let default_signer = Keypair::new();
|
||||
|
||||
let mut config = CliConfig::default();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.signers = vec![&default_signer];
|
||||
|
||||
let minimum_nonce_balance = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(NonceState::size())
|
||||
@ -347,29 +355,28 @@ fn test_nonced_pay_tx() {
|
||||
request_and_confirm_airdrop(
|
||||
&rpc_client,
|
||||
&faucet_addr,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
50 + minimum_nonce_balance,
|
||||
)
|
||||
.unwrap();
|
||||
check_balance(
|
||||
50 + minimum_nonce_balance,
|
||||
&rpc_client,
|
||||
&config.keypair.pubkey(),
|
||||
&config.signers[0].pubkey(),
|
||||
);
|
||||
|
||||
// Create nonce account
|
||||
let nonce_account = Keypair::new();
|
||||
let (nonce_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&nonce_account, tmp_file.as_file_mut()).unwrap();
|
||||
config.command = CliCommand::CreateNonceAccount {
|
||||
nonce_account: Rc::new(read_keypair_file(&nonce_keypair_file).unwrap().into()),
|
||||
nonce_account: 1,
|
||||
seed: None,
|
||||
nonce_authority: Some(config.keypair.pubkey()),
|
||||
nonce_authority: Some(config.signers[0].pubkey()),
|
||||
lamports: minimum_nonce_balance,
|
||||
};
|
||||
config.signers.push(&nonce_account);
|
||||
process_command(&config).unwrap();
|
||||
|
||||
check_balance(50, &rpc_client, &config.keypair.pubkey());
|
||||
check_balance(50, &rpc_client, &config.signers[0].pubkey());
|
||||
check_balance(minimum_nonce_balance, &rpc_client, &nonce_account.pubkey());
|
||||
|
||||
// Fetch nonce hash
|
||||
@ -381,6 +388,7 @@ fn test_nonced_pay_tx() {
|
||||
};
|
||||
|
||||
let bob_pubkey = Pubkey::new_rand();
|
||||
config.signers = vec![&default_signer];
|
||||
config.command = CliCommand::Pay(PayCommand {
|
||||
lamports: 10,
|
||||
to: bob_pubkey,
|
||||
@ -390,7 +398,7 @@ fn test_nonced_pay_tx() {
|
||||
});
|
||||
process_command(&config).expect("failed to process pay command");
|
||||
|
||||
check_balance(40, &rpc_client, &config.keypair.pubkey());
|
||||
check_balance(40, &rpc_client, &config.signers[0].pubkey());
|
||||
check_balance(10, &rpc_client, &bob_pubkey);
|
||||
|
||||
// Verify that nonce has been used
|
||||
|
@ -2,8 +2,8 @@ use solana_cli::cli::{process_command, CliCommand, CliConfig};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_core::validator::new_validator_for_tests;
|
||||
use solana_faucet::faucet::run_local_faucet;
|
||||
use std::fs::remove_dir_all;
|
||||
use std::sync::mpsc::channel;
|
||||
use solana_sdk::signature::Keypair;
|
||||
use std::{fs::remove_dir_all, sync::mpsc::channel};
|
||||
|
||||
#[test]
|
||||
fn test_cli_request_airdrop() {
|
||||
@ -20,6 +20,8 @@ fn test_cli_request_airdrop() {
|
||||
pubkey: None,
|
||||
lamports: 50,
|
||||
};
|
||||
let keypair = Keypair::new();
|
||||
bob_config.signers = vec![&keypair];
|
||||
|
||||
let sig_response = process_command(&bob_config);
|
||||
sig_response.unwrap();
|
||||
@ -27,7 +29,7 @@ fn test_cli_request_airdrop() {
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let balance = rpc_client
|
||||
.retry_get_balance(&bob_config.keypair.pubkey(), 1)
|
||||
.retry_get_balance(&bob_config.signers[0].pubkey(), 1)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(balance, 50);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,22 +10,12 @@ use solana_sdk::{
|
||||
fee_calculator::FeeCalculator,
|
||||
nonce_state::NonceState,
|
||||
pubkey::Pubkey,
|
||||
signature::{keypair_from_seed, read_keypair_file, write_keypair, Signer},
|
||||
signature::{keypair_from_seed, Keypair, Signer},
|
||||
};
|
||||
use std::fs::remove_dir_all;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::{fs::remove_dir_all, sync::mpsc::channel, thread::sleep, time::Duration};
|
||||
|
||||
#[cfg(test)]
|
||||
use solana_core::validator::new_validator_for_tests_ex;
|
||||
use std::rc::Rc;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
fn make_tmp_file() -> (String, NamedTempFile) {
|
||||
let tmp_file = NamedTempFile::new().unwrap();
|
||||
(String::from(tmp_file.path().to_str().unwrap()), tmp_file)
|
||||
}
|
||||
|
||||
fn check_balance(expected_balance: u64, client: &RpcClient, pubkey: &Pubkey) {
|
||||
(0..5).for_each(|tries| {
|
||||
@ -50,13 +40,15 @@ fn test_transfer() {
|
||||
|
||||
let rpc_client = RpcClient::new_socket(leader_data.rpc);
|
||||
|
||||
let default_signer = Keypair::new();
|
||||
let default_offline_signer = Keypair::new();
|
||||
|
||||
let mut config = CliConfig::default();
|
||||
config.json_rpc_url = format!("http://{}:{}", leader_data.rpc.ip(), leader_data.rpc.port());
|
||||
config.signers = vec![&default_signer];
|
||||
|
||||
let sender_pubkey = config.keypair.pubkey();
|
||||
let sender_pubkey = config.signers[0].pubkey();
|
||||
let recipient_pubkey = Pubkey::new(&[1u8; 32]);
|
||||
println!("sender: {:?}", sender_pubkey);
|
||||
println!("recipient: {:?}", recipient_pubkey);
|
||||
|
||||
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &sender_pubkey, 50_000).unwrap();
|
||||
check_balance(50_000, &rpc_client, &sender_pubkey);
|
||||
@ -66,12 +58,12 @@ fn test_transfer() {
|
||||
config.command = CliCommand::Transfer {
|
||||
lamports: 10,
|
||||
to: recipient_pubkey,
|
||||
from: None,
|
||||
from: 0,
|
||||
sign_only: false,
|
||||
blockhash_query: BlockhashQuery::All,
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
fee_payer: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
check_balance(49_989, &rpc_client, &sender_pubkey);
|
||||
@ -79,12 +71,12 @@ fn test_transfer() {
|
||||
|
||||
let mut offline = CliConfig::default();
|
||||
offline.json_rpc_url = String::default();
|
||||
offline.signers = vec![&default_offline_signer];
|
||||
// Verify we cannot contact the cluster
|
||||
offline.command = CliCommand::ClusterVersion;
|
||||
process_command(&offline).unwrap_err();
|
||||
|
||||
let offline_pubkey = offline.keypair.pubkey();
|
||||
println!("offline: {:?}", offline_pubkey);
|
||||
let offline_pubkey = offline.signers[0].pubkey();
|
||||
request_and_confirm_airdrop(&rpc_client, &faucet_addr, &offline_pubkey, 50).unwrap();
|
||||
check_balance(50, &rpc_client, &offline_pubkey);
|
||||
|
||||
@ -93,25 +85,26 @@ fn test_transfer() {
|
||||
offline.command = CliCommand::Transfer {
|
||||
lamports: 10,
|
||||
to: recipient_pubkey,
|
||||
from: None,
|
||||
from: 0,
|
||||
sign_only: true,
|
||||
blockhash_query: BlockhashQuery::None(blockhash, FeeCalculator::default()),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
fee_payer: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
};
|
||||
let sign_only_reply = process_command(&offline).unwrap();
|
||||
let (blockhash, signers) = parse_sign_only_reply_string(&sign_only_reply);
|
||||
let offline_presigner = presigner_from_pubkey_sigs(&offline_pubkey, &signers).unwrap();
|
||||
config.signers = vec![&offline_presigner];
|
||||
config.command = CliCommand::Transfer {
|
||||
lamports: 10,
|
||||
to: recipient_pubkey,
|
||||
from: Some(offline_presigner.clone().into()),
|
||||
from: 0,
|
||||
sign_only: false,
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: None,
|
||||
nonce_authority: None,
|
||||
fee_payer: Some(offline_presigner.clone().into()),
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
check_balance(39, &rpc_client, &offline_pubkey);
|
||||
@ -119,13 +112,12 @@ fn test_transfer() {
|
||||
|
||||
// Create nonce account
|
||||
let nonce_account = keypair_from_seed(&[3u8; 32]).unwrap();
|
||||
let (nonce_account_file, mut tmp_file) = make_tmp_file();
|
||||
write_keypair(&nonce_account, tmp_file.as_file_mut()).unwrap();
|
||||
let minimum_nonce_balance = rpc_client
|
||||
.get_minimum_balance_for_rent_exemption(NonceState::size())
|
||||
.unwrap();
|
||||
config.signers = vec![&default_signer, &nonce_account];
|
||||
config.command = CliCommand::CreateNonceAccount {
|
||||
nonce_account: Rc::new(read_keypair_file(&nonce_account_file).unwrap().into()),
|
||||
nonce_account: 1,
|
||||
seed: None,
|
||||
nonce_authority: None,
|
||||
lamports: minimum_nonce_balance,
|
||||
@ -142,15 +134,16 @@ fn test_transfer() {
|
||||
};
|
||||
|
||||
// Nonced transfer
|
||||
config.signers = vec![&default_signer];
|
||||
config.command = CliCommand::Transfer {
|
||||
lamports: 10,
|
||||
to: recipient_pubkey,
|
||||
from: None,
|
||||
from: 0,
|
||||
sign_only: false,
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(nonce_hash),
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
nonce_authority: None,
|
||||
fee_payer: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
check_balance(49_976 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
|
||||
@ -164,9 +157,10 @@ fn test_transfer() {
|
||||
assert_ne!(nonce_hash, new_nonce_hash);
|
||||
|
||||
// Assign nonce authority to offline
|
||||
config.signers = vec![&default_signer];
|
||||
config.command = CliCommand::AuthorizeNonceAccount {
|
||||
nonce_account: nonce_account.pubkey(),
|
||||
nonce_authority: None,
|
||||
nonce_authority: 0,
|
||||
new_authority: offline_pubkey,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
@ -181,28 +175,30 @@ fn test_transfer() {
|
||||
};
|
||||
|
||||
// Offline, nonced transfer
|
||||
offline.signers = vec![&default_offline_signer];
|
||||
offline.command = CliCommand::Transfer {
|
||||
lamports: 10,
|
||||
to: recipient_pubkey,
|
||||
from: None,
|
||||
from: 0,
|
||||
sign_only: true,
|
||||
blockhash_query: BlockhashQuery::None(nonce_hash, FeeCalculator::default()),
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
nonce_authority: None,
|
||||
fee_payer: None,
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
};
|
||||
let sign_only_reply = process_command(&offline).unwrap();
|
||||
let (blockhash, signers) = parse_sign_only_reply_string(&sign_only_reply);
|
||||
let offline_presigner = presigner_from_pubkey_sigs(&offline_pubkey, &signers).unwrap();
|
||||
config.signers = vec![&offline_presigner];
|
||||
config.command = CliCommand::Transfer {
|
||||
lamports: 10,
|
||||
to: recipient_pubkey,
|
||||
from: Some(offline_presigner.clone().into()),
|
||||
from: 0,
|
||||
sign_only: false,
|
||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash),
|
||||
nonce_account: Some(nonce_account.pubkey()),
|
||||
nonce_authority: Some(offline_presigner.clone().into()),
|
||||
fee_payer: Some(offline_presigner.clone().into()),
|
||||
nonce_authority: 0,
|
||||
fee_payer: 0,
|
||||
};
|
||||
process_command(&config).unwrap();
|
||||
check_balance(28, &rpc_client, &offline_pubkey);
|
||||
|
@ -30,7 +30,6 @@ use solana_ledger::{
|
||||
create_new_tmp_ledger,
|
||||
leader_schedule::FixedSchedule,
|
||||
leader_schedule_cache::LeaderScheduleCache,
|
||||
shred_version::compute_shred_version,
|
||||
};
|
||||
use solana_metrics::datapoint_info;
|
||||
use solana_runtime::bank::Bank;
|
||||
@ -39,6 +38,7 @@ use solana_sdk::{
|
||||
genesis_config::GenesisConfig,
|
||||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
shred_version::compute_shred_version,
|
||||
signature::{Keypair, Signer},
|
||||
timing::timestamp,
|
||||
};
|
||||
|
@ -1,23 +1,18 @@
|
||||
//! A command-line executable for generating the chain's genesis config.
|
||||
|
||||
use chrono::{TimeZone, Utc};
|
||||
use clap::{crate_description, crate_name, value_t, value_t_or_exit, App, Arg, ArgMatches};
|
||||
use solana_clap_utils::{
|
||||
input_parsers::{pubkey_of, unix_timestamp_from_rfc3339_datetime},
|
||||
input_validators::{is_rfc3339_datetime, is_valid_percentage},
|
||||
};
|
||||
use solana_genesis::{genesis_accounts::add_genesis_accounts, Base64Account};
|
||||
use solana_ledger::{
|
||||
blockstore::create_new_ledger, poh::compute_hashes_per_tick,
|
||||
shred_version::compute_shred_version,
|
||||
};
|
||||
use solana_ledger::{blockstore::create_new_ledger, poh::compute_hashes_per_tick};
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
clock,
|
||||
epoch_schedule::EpochSchedule,
|
||||
fee_calculator::FeeCalculator,
|
||||
genesis_config::{GenesisConfig, OperatingMode},
|
||||
native_token::lamports_to_sol,
|
||||
native_token::sol_to_lamports,
|
||||
poh_config::PohConfig,
|
||||
pubkey::Pubkey,
|
||||
@ -557,47 +552,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
|
||||
create_new_ledger(&ledger_path, &genesis_config)?;
|
||||
|
||||
println!(
|
||||
"\
|
||||
Creation time: {}\n\
|
||||
Operating mode: {:?}\n\
|
||||
Genesis hash: {}\n\
|
||||
Shred version: {}\n\
|
||||
Hashes per tick: {:?}\n\
|
||||
Slots per epoch: {}\n\
|
||||
Warmup epochs: {}abled\n\
|
||||
{:?}\n\
|
||||
{:?}\n\
|
||||
Capitalization: {} SOL in {} accounts\n\
|
||||
",
|
||||
Utc.timestamp(genesis_config.creation_time, 0).to_rfc3339(),
|
||||
genesis_config.operating_mode,
|
||||
genesis_config.hash(),
|
||||
compute_shred_version(&genesis_config.hash(), None),
|
||||
genesis_config.poh_config.hashes_per_tick,
|
||||
genesis_config.epoch_schedule.slots_per_epoch,
|
||||
if genesis_config.epoch_schedule.warmup {
|
||||
"en"
|
||||
} else {
|
||||
"dis"
|
||||
},
|
||||
genesis_config.rent,
|
||||
genesis_config.fee_calculator,
|
||||
lamports_to_sol(
|
||||
genesis_config
|
||||
.accounts
|
||||
.iter()
|
||||
.map(|(pubkey, account)| {
|
||||
if account.lamports == 0 {
|
||||
panic!("{:?}", (pubkey, account));
|
||||
}
|
||||
account.lamports
|
||||
})
|
||||
.sum::<u64>()
|
||||
),
|
||||
genesis_config.accounts.len(),
|
||||
);
|
||||
|
||||
println!("{}", genesis_config);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -8,11 +8,12 @@ use num_cpus;
|
||||
use solana_clap_utils::{
|
||||
input_validators::is_derivation,
|
||||
keypair::{
|
||||
keypair_from_seed_phrase, keypair_util_from_path, prompt_passphrase,
|
||||
keypair_from_seed_phrase, prompt_passphrase, signer_from_path,
|
||||
SKIP_SEED_PHRASE_VALIDATION_ARG,
|
||||
},
|
||||
};
|
||||
use solana_cli_config::config::{Config, CONFIG_FILE};
|
||||
use solana_remote_wallet::remote_wallet::{maybe_wallet_manager, RemoteWalletManager};
|
||||
use solana_sdk::{
|
||||
pubkey::write_pubkey_file,
|
||||
signature::{keypair_from_seed, write_keypair, write_keypair_file, Keypair, Signer},
|
||||
@ -49,6 +50,7 @@ fn check_for_overwrite(outfile: &str, matches: &ArgMatches) {
|
||||
fn get_keypair_from_matches(
|
||||
matches: &ArgMatches,
|
||||
config: Config,
|
||||
wallet_manager: Option<Arc<RemoteWalletManager>>,
|
||||
) -> Result<Box<dyn Signer>, Box<dyn error::Error>> {
|
||||
let mut path = dirs::home_dir().expect("home directory");
|
||||
let path = if matches.is_present("keypair") {
|
||||
@ -59,7 +61,7 @@ fn get_keypair_from_matches(
|
||||
path.extend(&[".config", "solana", "id.json"]);
|
||||
path.to_str().unwrap()
|
||||
};
|
||||
keypair_util_from_path(matches, path, "pubkey recovery")
|
||||
signer_from_path(matches, path, "pubkey recovery", wallet_manager.as_ref())
|
||||
}
|
||||
|
||||
fn output_keypair(
|
||||
@ -380,9 +382,11 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
Config::default()
|
||||
};
|
||||
|
||||
let wallet_manager = maybe_wallet_manager()?;
|
||||
|
||||
match matches.subcommand() {
|
||||
("pubkey", Some(matches)) => {
|
||||
let pubkey = get_keypair_from_matches(matches, config)?.try_pubkey()?;
|
||||
let pubkey = get_keypair_from_matches(matches, config, wallet_manager)?.try_pubkey()?;
|
||||
|
||||
if matches.is_present("outfile") {
|
||||
let outfile = matches.value_of("outfile").unwrap();
|
||||
@ -559,7 +563,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
||||
}
|
||||
}
|
||||
("verify", Some(matches)) => {
|
||||
let keypair = get_keypair_from_matches(matches, config)?;
|
||||
let keypair = get_keypair_from_matches(matches, config, wallet_manager)?;
|
||||
let test_data = b"test";
|
||||
let signature = keypair.try_sign_message(test_data)?;
|
||||
let pubkey_bs58 = matches.value_of("pubkey").unwrap();
|
||||
|
@ -11,12 +11,11 @@ use solana_ledger::{
|
||||
blockstore_db::{self, Column, Database},
|
||||
blockstore_processor::{BankForksInfo, ProcessOptions},
|
||||
rooted_slot_iterator::RootedSlotIterator,
|
||||
shred_version::compute_shred_version,
|
||||
snapshot_utils,
|
||||
};
|
||||
use solana_sdk::{
|
||||
clock::Slot, genesis_config::GenesisConfig, native_token::lamports_to_sol,
|
||||
program_utils::limited_deserialize, pubkey::Pubkey,
|
||||
program_utils::limited_deserialize, pubkey::Pubkey, shred_version::compute_shred_version,
|
||||
};
|
||||
use solana_vote_program::vote_state::VoteState;
|
||||
use std::{
|
||||
@ -605,7 +604,7 @@ fn main() {
|
||||
.arg(&starting_slot_arg)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("print-slot")
|
||||
SubCommand::with_name("slot")
|
||||
.about("Print the contents of one or more slots")
|
||||
.arg(
|
||||
Arg::with_name("slots")
|
||||
@ -617,6 +616,10 @@ fn main() {
|
||||
.help("List of slots to print"),
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("genesis")
|
||||
.about("Prints the ledger's genesis config")
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("genesis-hash")
|
||||
.about("Prints the ledger's genesis hash")
|
||||
@ -694,7 +697,7 @@ fn main() {
|
||||
.help("Output directory for the snapshot"),
|
||||
)
|
||||
).subcommand(
|
||||
SubCommand::with_name("print-accounts")
|
||||
SubCommand::with_name("accounts")
|
||||
.about("Print account contents after processing in the ledger")
|
||||
.arg(&no_snapshot_arg)
|
||||
.arg(&account_paths_arg)
|
||||
@ -764,6 +767,9 @@ fn main() {
|
||||
LedgerOutputMethod::Print,
|
||||
);
|
||||
}
|
||||
("genesis", Some(_arg_matches)) => {
|
||||
println!("{}", open_genesis_config(&ledger_path));
|
||||
}
|
||||
("genesis-hash", Some(_arg_matches)) => {
|
||||
println!("{}", open_genesis_config(&ledger_path).hash());
|
||||
}
|
||||
@ -794,7 +800,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
("print-slot", Some(arg_matches)) => {
|
||||
("slot", Some(arg_matches)) => {
|
||||
let slots = values_t_or_exit!(arg_matches, "slots", Slot);
|
||||
for slot in slots {
|
||||
println!("Slot {}", slot);
|
||||
@ -943,7 +949,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
("print-accounts", Some(arg_matches)) => {
|
||||
("accounts", Some(arg_matches)) => {
|
||||
let dev_halt_at_slot = value_t!(arg_matches, "halt_at_slot", Slot).ok();
|
||||
let process_options = ProcessOptions {
|
||||
dev_halt_at_slot,
|
||||
|
@ -2264,7 +2264,7 @@ pub fn create_new_ledger(ledger_path: &Path, genesis_config: &GenesisConfig) ->
|
||||
let hashes_per_tick = genesis_config.poh_config.hashes_per_tick.unwrap_or(0);
|
||||
let entries = create_ticks(ticks_per_slot, hashes_per_tick, genesis_config.hash());
|
||||
let last_hash = entries.last().unwrap().hash;
|
||||
let version = Shred::version_from_hash(&last_hash);
|
||||
let version = solana_sdk::shred_version::version_from_hash(&last_hash);
|
||||
|
||||
let shredder = Shredder::new(0, 0, 0.0, Arc::new(Keypair::new()), 0, version)
|
||||
.expect("Failed to create entry shredder");
|
||||
|
@ -15,7 +15,6 @@ pub mod leader_schedule_utils;
|
||||
pub mod poh;
|
||||
pub mod rooted_slot_iterator;
|
||||
pub mod shred;
|
||||
pub mod shred_version;
|
||||
pub mod sigverify_shreds;
|
||||
pub mod snapshot_package;
|
||||
pub mod snapshot_utils;
|
||||
|
@ -392,22 +392,6 @@ impl Shred {
|
||||
self.signature()
|
||||
.verify(pubkey.as_ref(), &self.payload[SIZE_OF_SIGNATURE..])
|
||||
}
|
||||
|
||||
pub fn version_from_hash(hash: &Hash) -> u16 {
|
||||
let hash = hash.as_ref();
|
||||
let mut accum = [0u8; 2];
|
||||
hash.chunks(2).for_each(|seed| {
|
||||
accum
|
||||
.iter_mut()
|
||||
.zip(seed)
|
||||
.for_each(|(accum, seed)| *accum ^= *seed)
|
||||
});
|
||||
// convert accum into a u16
|
||||
let version = ((accum[0] as u16) << 8) | accum[1] as u16;
|
||||
|
||||
// ensure version is never zero, to avoid looking like an uninitialized version
|
||||
version.saturating_add(1)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -919,8 +903,7 @@ pub mod tests {
|
||||
use super::*;
|
||||
use bincode::serialized_size;
|
||||
use matches::assert_matches;
|
||||
use solana_sdk::hash::hash;
|
||||
use solana_sdk::system_transaction;
|
||||
use solana_sdk::{hash::hash, shred_version, system_transaction};
|
||||
use std::collections::HashSet;
|
||||
use std::convert::TryInto;
|
||||
|
||||
@ -1451,7 +1434,7 @@ pub mod tests {
|
||||
fn test_shred_version() {
|
||||
let keypair = Arc::new(Keypair::new());
|
||||
let hash = hash(Hash::default().as_ref());
|
||||
let version = Shred::version_from_hash(&hash);
|
||||
let version = shred_version::version_from_hash(&hash);
|
||||
assert_ne!(version, 0);
|
||||
let shredder =
|
||||
Shredder::new(0, 0, 1.0, keypair, 0, version).expect("Failed in creating shredder");
|
||||
@ -1481,19 +1464,19 @@ pub mod tests {
|
||||
0x5a, 0x5a, 0xa5, 0xa5, 0x5a, 0x5a, 0xa5, 0xa5, 0x5a, 0x5a, 0xa5, 0xa5, 0x5a, 0x5a,
|
||||
0xa5, 0xa5, 0x5a, 0x5a,
|
||||
];
|
||||
let version = Shred::version_from_hash(&Hash::new(&hash));
|
||||
let version = shred_version::version_from_hash(&Hash::new(&hash));
|
||||
assert_eq!(version, 1);
|
||||
let hash = [
|
||||
0xa5u8, 0xa5, 0x5a, 0x5a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
let version = Shred::version_from_hash(&Hash::new(&hash));
|
||||
let version = shred_version::version_from_hash(&Hash::new(&hash));
|
||||
assert_eq!(version, 0xffff);
|
||||
let hash = [
|
||||
0xa5u8, 0xa5, 0x5a, 0x5a, 0xa5, 0xa5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
let version = Shred::version_from_hash(&Hash::new(&hash));
|
||||
let version = shred_version::version_from_hash(&Hash::new(&hash));
|
||||
assert_eq!(version, 0x5a5b);
|
||||
}
|
||||
|
||||
@ -1501,7 +1484,7 @@ pub mod tests {
|
||||
fn test_shred_fec_set_index() {
|
||||
let keypair = Arc::new(Keypair::new());
|
||||
let hash = hash(Hash::default().as_ref());
|
||||
let version = Shred::version_from_hash(&hash);
|
||||
let version = shred_version::version_from_hash(&hash);
|
||||
assert_ne!(version, 0);
|
||||
let shredder =
|
||||
Shredder::new(0, 0, 0.5, keypair, 0, version).expect("Failed in creating shredder");
|
||||
@ -1539,7 +1522,7 @@ pub mod tests {
|
||||
fn test_max_coding_shreds() {
|
||||
let keypair = Arc::new(Keypair::new());
|
||||
let hash = hash(Hash::default().as_ref());
|
||||
let version = Shred::version_from_hash(&hash);
|
||||
let version = shred_version::version_from_hash(&hash);
|
||||
assert_ne!(version, 0);
|
||||
let shredder =
|
||||
Shredder::new(0, 0, 1.0, keypair, 0, version).expect("Failed in creating shredder");
|
||||
|
@ -519,7 +519,7 @@ pub fn untar_snapshot_in<P: AsRef<Path>, Q: AsRef<Path>>(
|
||||
archive.unpack(&unpack_dir)?;
|
||||
} else if let Err(e) = archive.unpack(&unpack_dir) {
|
||||
warn!(
|
||||
"Trying to unpack as uncompressed tar because an error occured: {:?}",
|
||||
"Trying to unpack as uncompressed tar because an error occurred: {:?}",
|
||||
e
|
||||
);
|
||||
let tar_bz2 = File::open(snapshot_tar)?;
|
||||
|
199
programs/bpf/Cargo.lock
generated
199
programs/bpf/Cargo.lock
generated
@ -1936,175 +1936,178 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-loader-program"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-logger 0.24.0",
|
||||
"solana-sdk 0.24.0",
|
||||
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-logger 1.1.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana_rbpf 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-programs"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"elf 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-bpf-loader-program 0.24.0",
|
||||
"solana-logger 0.24.0",
|
||||
"solana-runtime 0.24.0",
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-bpf-loader-program 1.1.0",
|
||||
"solana-logger 1.1.0",
|
||||
"solana-runtime 1.1.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana_rbpf 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-128bit"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"solana-bpf-rust-128bit-dep 0.24.0",
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-bpf-rust-128bit-dep 1.1.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-128bit-dep"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-alloc"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-dep-crate"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-dup-accounts"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-error-handling"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
"thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-external-spend"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-iter"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-many-args"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"solana-bpf-rust-many-args-dep 0.24.0",
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-bpf-rust-many-args-dep 1.1.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-many-args-dep"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-noop"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-panic"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-param-passing"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"solana-bpf-rust-param-passing-dep 0.24.0",
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-bpf-rust-param-passing-dep 1.1.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-param-passing-dep"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-sysval"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk-bpf-test 0.24.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-sdk-bpf-test 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-config-program"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-logger 0.24.0",
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-logger 1.1.0",
|
||||
"solana-sdk 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-crate-features"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2127,7 +2130,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solana-logger"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2136,30 +2139,30 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solana-measure"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-metrics 0.24.0",
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-metrics 1.1.0",
|
||||
"solana-sdk 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-metrics"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"reqwest 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"sys-info 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-rayon-threadlimit"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sys-info 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2167,7 +2170,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solana-runtime"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2179,32 +2182,36 @@ dependencies = [
|
||||
"libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-bpf-loader-program 0.24.0",
|
||||
"solana-logger 0.24.0",
|
||||
"solana-measure 0.24.0",
|
||||
"solana-metrics 0.24.0",
|
||||
"solana-rayon-threadlimit 0.24.0",
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-stake-program 0.24.0",
|
||||
"solana-storage-program 0.24.0",
|
||||
"solana-vote-program 0.24.0",
|
||||
"solana-bpf-loader-program 1.1.0",
|
||||
"solana-logger 1.1.0",
|
||||
"solana-measure 1.1.0",
|
||||
"solana-metrics 1.1.0",
|
||||
"solana-rayon-threadlimit 1.1.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-stake-program 1.1.0",
|
||||
"solana-storage-program 1.1.0",
|
||||
"solana-vote-program 1.1.0",
|
||||
"sys-info 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-sdk"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ed25519-dalek 1.0.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"generic-array 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2222,19 +2229,19 @@ dependencies = [
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-crate-features 0.24.0",
|
||||
"solana-logger 0.24.0",
|
||||
"solana-sdk-macro 0.24.0",
|
||||
"solana-crate-features 1.1.0",
|
||||
"solana-logger 1.1.0",
|
||||
"solana-sdk-macro 1.1.0",
|
||||
"thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-sdk-bpf-test"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "solana-sdk-macro"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2244,7 +2251,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solana-stake-program"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2252,17 +2259,17 @@ dependencies = [
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-config-program 0.24.0",
|
||||
"solana-logger 0.24.0",
|
||||
"solana-metrics 0.24.0",
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-vote-program 0.24.0",
|
||||
"solana-config-program 1.1.0",
|
||||
"solana-logger 1.1.0",
|
||||
"solana-metrics 1.1.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"solana-vote-program 1.1.0",
|
||||
"thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-storage-program"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2271,13 +2278,13 @@ dependencies = [
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-logger 0.24.0",
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-logger 1.1.0",
|
||||
"solana-sdk 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-vote-program"
|
||||
version = "0.24.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2285,9 +2292,9 @@ dependencies = [
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-logger 0.24.0",
|
||||
"solana-metrics 0.24.0",
|
||||
"solana-sdk 0.24.0",
|
||||
"solana-logger 1.1.0",
|
||||
"solana-metrics 1.1.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::remote_wallet::{
|
||||
initialize_wallet_manager, DerivationPath, RemoteWallet, RemoteWalletError, RemoteWalletInfo,
|
||||
DerivationPath, RemoteWallet, RemoteWalletError, RemoteWalletInfo, RemoteWalletManager,
|
||||
};
|
||||
use dialoguer::{theme::ColorfulTheme, Select};
|
||||
use log::*;
|
||||
@ -378,9 +378,8 @@ fn extend_and_serialize(derivation_path: &DerivationPath) -> Vec<u8> {
|
||||
/// Choose a Ledger wallet based on matching info fields
|
||||
pub fn get_ledger_from_info(
|
||||
info: RemoteWalletInfo,
|
||||
wallet_manager: &RemoteWalletManager,
|
||||
) -> Result<Arc<LedgerWallet>, RemoteWalletError> {
|
||||
let wallet_manager = initialize_wallet_manager()?;
|
||||
let _device_count = wallet_manager.update_devices()?;
|
||||
let devices = wallet_manager.list_devices();
|
||||
let (pubkeys, device_paths): (Vec<Pubkey>, Vec<String>) = devices
|
||||
.iter()
|
||||
|
@ -1,7 +1,8 @@
|
||||
use crate::{
|
||||
ledger::get_ledger_from_info,
|
||||
remote_wallet::{
|
||||
DerivationPath, RemoteWallet, RemoteWalletError, RemoteWalletInfo, RemoteWalletType,
|
||||
DerivationPath, RemoteWallet, RemoteWalletError, RemoteWalletInfo, RemoteWalletManager,
|
||||
RemoteWalletType,
|
||||
},
|
||||
};
|
||||
use solana_sdk::{
|
||||
@ -12,24 +13,29 @@ use solana_sdk::{
|
||||
pub struct RemoteKeypair {
|
||||
pub wallet_type: RemoteWalletType,
|
||||
pub derivation_path: DerivationPath,
|
||||
pub pubkey: Pubkey,
|
||||
}
|
||||
|
||||
impl RemoteKeypair {
|
||||
pub fn new(wallet_type: RemoteWalletType, derivation_path: DerivationPath) -> Self {
|
||||
Self {
|
||||
pub fn new(
|
||||
wallet_type: RemoteWalletType,
|
||||
derivation_path: DerivationPath,
|
||||
) -> Result<Self, RemoteWalletError> {
|
||||
let pubkey = match &wallet_type {
|
||||
RemoteWalletType::Ledger(wallet) => wallet.get_pubkey(&derivation_path)?,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
wallet_type,
|
||||
derivation_path,
|
||||
}
|
||||
pubkey,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Signer for RemoteKeypair {
|
||||
fn try_pubkey(&self) -> Result<Pubkey, SignerError> {
|
||||
match &self.wallet_type {
|
||||
RemoteWalletType::Ledger(wallet) => wallet
|
||||
.get_pubkey(&self.derivation_path)
|
||||
.map_err(|e| e.into()),
|
||||
}
|
||||
Ok(self.pubkey)
|
||||
}
|
||||
|
||||
fn try_sign_message(&self, message: &[u8]) -> Result<Signature, SignerError> {
|
||||
@ -44,17 +50,18 @@ impl Signer for RemoteKeypair {
|
||||
pub fn generate_remote_keypair(
|
||||
path: String,
|
||||
explicit_derivation_path: Option<DerivationPath>,
|
||||
wallet_manager: &RemoteWalletManager,
|
||||
) -> Result<RemoteKeypair, RemoteWalletError> {
|
||||
let (remote_wallet_info, mut derivation_path) = RemoteWalletInfo::parse_path(path)?;
|
||||
if let Some(derivation) = explicit_derivation_path {
|
||||
derivation_path = derivation;
|
||||
}
|
||||
if remote_wallet_info.manufacturer == "ledger" {
|
||||
let ledger = get_ledger_from_info(remote_wallet_info)?;
|
||||
Ok(RemoteKeypair {
|
||||
wallet_type: RemoteWalletType::Ledger(ledger),
|
||||
let ledger = get_ledger_from_info(remote_wallet_info, wallet_manager)?;
|
||||
Ok(RemoteKeypair::new(
|
||||
RemoteWalletType::Ledger(ledger),
|
||||
derivation_path,
|
||||
})
|
||||
)?)
|
||||
} else {
|
||||
Err(RemoteWalletError::DeviceTypeMismatch)
|
||||
}
|
||||
|
@ -299,6 +299,17 @@ pub fn initialize_wallet_manager() -> Result<Arc<RemoteWalletManager>, RemoteWal
|
||||
Ok(RemoteWalletManager::new(hidapi))
|
||||
}
|
||||
|
||||
pub fn maybe_wallet_manager() -> Result<Option<Arc<RemoteWalletManager>>, RemoteWalletError> {
|
||||
let wallet_manager = initialize_wallet_manager()?;
|
||||
let device_count = wallet_manager.update_devices()?;
|
||||
if device_count > 0 {
|
||||
Ok(Some(wallet_manager))
|
||||
} else {
|
||||
drop(wallet_manager);
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -8,7 +8,6 @@ use crate::{
|
||||
AccountsDBSerialize, AppendVecId, ErrorCounters, SnapshotStorage, SnapshotStorages,
|
||||
},
|
||||
blockhash_queue::BlockhashQueue,
|
||||
hard_forks::HardForks,
|
||||
message_processor::{MessageProcessor, ProcessInstruction},
|
||||
nonce_utils,
|
||||
rent_collector::RentCollector,
|
||||
@ -38,6 +37,7 @@ use solana_sdk::{
|
||||
epoch_schedule::EpochSchedule,
|
||||
fee_calculator::FeeCalculator,
|
||||
genesis_config::GenesisConfig,
|
||||
hard_forks::HardForks,
|
||||
hash::{extend_and_hash, hashv, Hash},
|
||||
inflation::Inflation,
|
||||
native_loader,
|
||||
|
@ -7,7 +7,6 @@ pub mod bank_client;
|
||||
mod blockhash_queue;
|
||||
pub mod bloom;
|
||||
pub mod genesis_utils;
|
||||
pub mod hard_forks;
|
||||
pub mod loader_utils;
|
||||
pub mod message_processor;
|
||||
mod native_loader;
|
||||
|
@ -15,6 +15,7 @@ program = []
|
||||
default = [
|
||||
"assert_matches",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"memmap",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
@ -30,6 +31,7 @@ bincode = "1.2.1"
|
||||
bs58 = "0.3.0"
|
||||
bv = { version = "0.11.0", features = ["serde"] }
|
||||
byteorder = { version = "1.3.2", optional = true }
|
||||
chrono = { version = "0.4", optional = true }
|
||||
generic-array = { version = "0.13.2", default-features = false, features = ["serde", "more_lengths"] }
|
||||
hex = "0.4.0"
|
||||
hmac = "0.7.0"
|
||||
|
@ -7,16 +7,20 @@ use crate::{
|
||||
fee_calculator::FeeCalculator,
|
||||
hash::{hash, Hash},
|
||||
inflation::Inflation,
|
||||
native_token::lamports_to_sol,
|
||||
poh_config::PohConfig,
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
shred_version::compute_shred_version,
|
||||
signature::{Keypair, Signer},
|
||||
system_program::{self, solana_system_program},
|
||||
};
|
||||
use bincode::{deserialize, serialize};
|
||||
use chrono::{TimeZone, Utc};
|
||||
use memmap::Mmap;
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
fmt,
|
||||
fs::{File, OpenOptions},
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
@ -173,6 +177,51 @@ impl GenesisConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for GenesisConfig {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"\
|
||||
Creation time: {}\n\
|
||||
Operating mode: {:?}\n\
|
||||
Genesis hash: {}\n\
|
||||
Shred version: {}\n\
|
||||
Hashes per tick: {:?}\n\
|
||||
Slots per epoch: {}\n\
|
||||
Warmup epochs: {}abled\n\
|
||||
{:?}\n\
|
||||
{:?}\n\
|
||||
Capitalization: {} SOL in {} accounts\n\
|
||||
",
|
||||
Utc.timestamp(self.creation_time, 0).to_rfc3339(),
|
||||
self.operating_mode,
|
||||
self.hash(),
|
||||
compute_shred_version(&self.hash(), None),
|
||||
self.poh_config.hashes_per_tick,
|
||||
self.epoch_schedule.slots_per_epoch,
|
||||
if self.epoch_schedule.warmup {
|
||||
"en"
|
||||
} else {
|
||||
"dis"
|
||||
},
|
||||
self.rent,
|
||||
self.fee_calculator,
|
||||
lamports_to_sol(
|
||||
self.accounts
|
||||
.iter()
|
||||
.map(|(pubkey, account)| {
|
||||
if account.lamports == 0 {
|
||||
panic!("{:?}", (pubkey, account));
|
||||
}
|
||||
account.lamports
|
||||
})
|
||||
.sum::<u64>()
|
||||
),
|
||||
self.accounts.len(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -70,6 +70,10 @@ pub mod client;
|
||||
#[cfg(not(feature = "program"))]
|
||||
pub mod genesis_config;
|
||||
#[cfg(not(feature = "program"))]
|
||||
pub mod hard_forks;
|
||||
#[cfg(not(feature = "program"))]
|
||||
pub mod shred_version;
|
||||
#[cfg(not(feature = "program"))]
|
||||
pub mod signature;
|
||||
#[cfg(not(feature = "program"))]
|
||||
pub mod signers;
|
||||
|
@ -1,6 +1,23 @@
|
||||
use crate::shred::Shred;
|
||||
use solana_runtime::hard_forks::HardForks;
|
||||
use solana_sdk::hash::{extend_and_hash, Hash};
|
||||
use solana_sdk::{
|
||||
hard_forks::HardForks,
|
||||
hash::{extend_and_hash, Hash},
|
||||
};
|
||||
|
||||
pub fn version_from_hash(hash: &Hash) -> u16 {
|
||||
let hash = hash.as_ref();
|
||||
let mut accum = [0u8; 2];
|
||||
hash.chunks(2).for_each(|seed| {
|
||||
accum
|
||||
.iter_mut()
|
||||
.zip(seed)
|
||||
.for_each(|(accum, seed)| *accum ^= *seed)
|
||||
});
|
||||
// convert accum into a u16
|
||||
let version = ((accum[0] as u16) << 8) | accum[1] as u16;
|
||||
|
||||
// ensure version is never zero, to avoid looking like an uninitialized version
|
||||
version.saturating_add(1)
|
||||
}
|
||||
|
||||
pub fn compute_shred_version(genesis_hash: &Hash, hard_forks: Option<&HardForks>) -> u16 {
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
@ -15,7 +32,7 @@ pub fn compute_shred_version(genesis_hash: &Hash, hard_forks: Option<&HardForks>
|
||||
}
|
||||
}
|
||||
|
||||
Shred::version_from_hash(&hash)
|
||||
version_from_hash(&hash)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
@ -183,8 +183,8 @@ impl<T> From<T> for Box<dyn Signer>
|
||||
where
|
||||
T: Signer + 'static,
|
||||
{
|
||||
fn from(keypair_util: T) -> Self {
|
||||
Box::new(keypair_util)
|
||||
fn from(signer: T) -> Self {
|
||||
Box::new(signer)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,14 +197,65 @@ fn download_tar_bz2(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_rpc_addr(
|
||||
fn get_shred_rpc_peers(
|
||||
cluster_info: &Arc<RwLock<ClusterInfo>>,
|
||||
expected_shred_version: Option<u16>,
|
||||
) -> Vec<ContactInfo> {
|
||||
let rpc_peers = cluster_info.read().unwrap().all_rpc_peers();
|
||||
match expected_shred_version {
|
||||
Some(expected_shred_version) => {
|
||||
// Filter out rpc peers that don't match the expected shred version
|
||||
rpc_peers
|
||||
.into_iter()
|
||||
.filter(|contact_info| contact_info.shred_version == expected_shred_version)
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
None => {
|
||||
if !rpc_peers
|
||||
.iter()
|
||||
.all(|contact_info| contact_info.shred_version == rpc_peers[0].shred_version)
|
||||
{
|
||||
eprintln!(
|
||||
"Multiple shred versions observed in gossip. Restart with --expected-shred-version"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
rpc_peers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_trusted_snapshot_hashes(
|
||||
cluster_info: &Arc<RwLock<ClusterInfo>>,
|
||||
trusted_validators: Option<&HashSet<Pubkey>>,
|
||||
) -> Option<HashSet<(Slot, Hash)>> {
|
||||
if let Some(trusted_validators) = trusted_validators {
|
||||
let mut trusted_snapshot_hashes = HashSet::new();
|
||||
for trusted_validator in trusted_validators {
|
||||
if let Some(snapshot_hashes) = cluster_info
|
||||
.read()
|
||||
.unwrap()
|
||||
.get_snapshot_hash_for_node(trusted_validator)
|
||||
{
|
||||
for snapshot_hash in snapshot_hashes {
|
||||
trusted_snapshot_hashes.insert(*snapshot_hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(trusted_snapshot_hashes)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_rpc_node(
|
||||
node: &Node,
|
||||
identity_keypair: &Arc<Keypair>,
|
||||
entrypoint_gossip: &SocketAddr,
|
||||
expected_shred_version: Option<u16>,
|
||||
trusted_validators: Option<&HashSet<Pubkey>>,
|
||||
snapshot_not_required: bool,
|
||||
) -> (RpcClient, SocketAddr) {
|
||||
) -> (ContactInfo, RpcClient, Option<(Slot, Hash)>) {
|
||||
let mut cluster_info = ClusterInfo::new(
|
||||
ClusterInfo::spy_contact_info(&identity_keypair.pubkey()),
|
||||
identity_keypair.clone(),
|
||||
@ -220,136 +271,109 @@ fn get_rpc_addr(
|
||||
&gossip_exit_flag,
|
||||
);
|
||||
|
||||
let (rpc_client, rpc_addr) = loop {
|
||||
let (rpc_contact_info, rpc_client, selected_snapshot_hash) = loop {
|
||||
info!(
|
||||
"Searching for an RPC service, shred version={:?}...\n{}",
|
||||
expected_shred_version,
|
||||
cluster_info.read().unwrap().contact_info_trace()
|
||||
"Searching for an RPC service, shred version={:?}...",
|
||||
expected_shred_version
|
||||
);
|
||||
sleep(Duration::from_secs(1));
|
||||
info!("\n{}", cluster_info.read().unwrap().contact_info_trace());
|
||||
|
||||
let mut rpc_peers = cluster_info.read().unwrap().all_rpc_peers();
|
||||
match expected_shred_version {
|
||||
Some(expected_shred_version) => {
|
||||
// Filter out rpc peers that don't match the expected shred version
|
||||
rpc_peers = rpc_peers
|
||||
.into_iter()
|
||||
.filter(|contact_info| contact_info.shred_version == expected_shred_version)
|
||||
.collect::<Vec<_>>();
|
||||
}
|
||||
None => {
|
||||
if !rpc_peers
|
||||
.iter()
|
||||
.all(|contact_info| contact_info.shred_version == rpc_peers[0].shred_version)
|
||||
{
|
||||
eprintln!(
|
||||
"Multiple shred versions observed in gossip. Restart with --expected-shred-version"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
let rpc_peers = get_shred_rpc_peers(&cluster_info, expected_shred_version);
|
||||
if rpc_peers.is_empty() {
|
||||
info!("No RPC services found");
|
||||
continue;
|
||||
}
|
||||
|
||||
let trusted_slots = if let Some(trusted_validators) = trusted_validators {
|
||||
let trusted_slots = HashSet::new();
|
||||
for trusted_validator in trusted_validators {
|
||||
if let Some(slot_hash) = cluster_info
|
||||
let mut highest_snapshot_hash: Option<(Slot, Hash)> = None;
|
||||
let eligible_rpc_peers = if snapshot_not_required {
|
||||
rpc_peers
|
||||
} else {
|
||||
let trusted_snapshot_hashes =
|
||||
get_trusted_snapshot_hashes(&cluster_info, trusted_validators);
|
||||
|
||||
let mut eligible_rpc_peers = vec![];
|
||||
|
||||
for rpc_peer in rpc_peers.iter() {
|
||||
if let Some(snapshot_hashes) = cluster_info
|
||||
.read()
|
||||
.unwrap()
|
||||
.get_snapshot_hash_for_node(trusted_validator)
|
||||
.get_snapshot_hash_for_node(&rpc_peer.id)
|
||||
{
|
||||
trusted_slots.union(&slot_hash.iter().collect());
|
||||
}
|
||||
}
|
||||
Some(trusted_slots)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if rpc_peers.is_empty() {
|
||||
info!("No RPC services found ");
|
||||
} else {
|
||||
let eligible_rpc_peers = if snapshot_not_required {
|
||||
rpc_peers
|
||||
} else {
|
||||
let mut eligible_rpc_peers = vec![];
|
||||
let mut highest_snapshot_slot = 0;
|
||||
|
||||
for rpc_peer in rpc_peers.iter() {
|
||||
if let Some(snapshot_hash) = cluster_info
|
||||
.read()
|
||||
.unwrap()
|
||||
.get_snapshot_hash_for_node(&rpc_peer.id)
|
||||
{
|
||||
let highest_snapshot_slot_for_node =
|
||||
snapshot_hash.iter().fold(0, |highest_slot, snapshot_hash| {
|
||||
if let Some(ref trusted_slots) = trusted_slots {
|
||||
if !trusted_slots.contains(snapshot_hash) {
|
||||
// Ignore all untrusted slots
|
||||
return highest_slot;
|
||||
}
|
||||
}
|
||||
highest_slot.max(snapshot_hash.0)
|
||||
});
|
||||
|
||||
if highest_snapshot_slot_for_node > highest_snapshot_slot {
|
||||
// Found a higher snapshot, remove all rpc peers with a lower snapshot
|
||||
eligible_rpc_peers.clear();
|
||||
highest_snapshot_slot = highest_snapshot_slot_for_node;
|
||||
for snapshot_hash in snapshot_hashes {
|
||||
if let Some(ref trusted_snapshot_hashes) = trusted_snapshot_hashes {
|
||||
if !trusted_snapshot_hashes.contains(snapshot_hash) {
|
||||
// Ignore all untrusted snapshot hashes
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if highest_snapshot_slot_for_node == highest_snapshot_slot {
|
||||
if highest_snapshot_hash.is_none()
|
||||
|| snapshot_hash.0 > highest_snapshot_hash.unwrap().0
|
||||
{
|
||||
// Found a higher snapshot, remove all nodes with a lower snapshot
|
||||
eligible_rpc_peers.clear();
|
||||
highest_snapshot_hash = Some(*snapshot_hash)
|
||||
}
|
||||
|
||||
if Some(*snapshot_hash) == highest_snapshot_hash {
|
||||
eligible_rpc_peers.push(rpc_peer.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if highest_snapshot_slot == 0 {
|
||||
match highest_snapshot_hash {
|
||||
None => {
|
||||
assert!(eligible_rpc_peers.is_empty());
|
||||
info!("No snapshot available");
|
||||
} else {
|
||||
info!("No snapshots available");
|
||||
}
|
||||
Some(highest_snapshot_hash) => {
|
||||
info!(
|
||||
"Highest available snapshot slot is {}",
|
||||
highest_snapshot_slot
|
||||
"Highest available snapshot slot is {}, available from {:?}",
|
||||
highest_snapshot_hash.0,
|
||||
eligible_rpc_peers
|
||||
.iter()
|
||||
.map(|contact_info| contact_info.id)
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
eligible_rpc_peers
|
||||
}
|
||||
eligible_rpc_peers
|
||||
};
|
||||
|
||||
if !eligible_rpc_peers.is_empty() {
|
||||
// Prefer the entrypoint's RPC service if present, otherwise pick one at random
|
||||
let contact_info = if let Some(contact_info) = eligible_rpc_peers
|
||||
.iter()
|
||||
.find(|contact_info| contact_info.gossip == *entrypoint_gossip)
|
||||
{
|
||||
contact_info
|
||||
} else {
|
||||
&eligible_rpc_peers[thread_rng().gen_range(0, eligible_rpc_peers.len())]
|
||||
};
|
||||
|
||||
if !eligible_rpc_peers.is_empty() {
|
||||
// Prefer the entrypoint's RPC service if present, otherwise pick one at random
|
||||
let contact_info = if let Some(contact_info) = eligible_rpc_peers
|
||||
.iter()
|
||||
.find(|contact_info| contact_info.gossip == *entrypoint_gossip)
|
||||
{
|
||||
contact_info
|
||||
} else {
|
||||
&eligible_rpc_peers[thread_rng().gen_range(0, eligible_rpc_peers.len())]
|
||||
};
|
||||
|
||||
info!(
|
||||
"Trying RPC service from node {}: {:?}",
|
||||
contact_info.id, contact_info.rpc
|
||||
);
|
||||
let rpc_client = RpcClient::new_socket(contact_info.rpc);
|
||||
match rpc_client.get_version() {
|
||||
Ok(rpc_version) => {
|
||||
info!("RPC node version: {}", rpc_version.solana_core);
|
||||
break (rpc_client, contact_info.rpc);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("Failed to get RPC node's version: {}", err);
|
||||
}
|
||||
info!(
|
||||
"Trying RPC service from node {}: {:?}",
|
||||
contact_info.id, contact_info.rpc
|
||||
);
|
||||
let rpc_client = RpcClient::new_socket(contact_info.rpc);
|
||||
match rpc_client.get_version() {
|
||||
Ok(rpc_version) => {
|
||||
info!("RPC node version: {}", rpc_version.solana_core);
|
||||
break (contact_info.clone(), rpc_client, highest_snapshot_hash);
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("Failed to get RPC node's version: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sleep(Duration::from_secs(1));
|
||||
};
|
||||
|
||||
gossip_exit_flag.store(true, Ordering::Relaxed);
|
||||
gossip_service.join().unwrap();
|
||||
|
||||
(rpc_client, rpc_addr)
|
||||
(rpc_contact_info, rpc_client, selected_snapshot_hash)
|
||||
}
|
||||
|
||||
fn check_vote_account(
|
||||
@ -405,11 +429,11 @@ fn check_vote_account(
|
||||
fn download_ledger(
|
||||
rpc_addr: &SocketAddr,
|
||||
ledger_path: &Path,
|
||||
no_snapshot_fetch: bool,
|
||||
snapshot_hash: Option<(Slot, Hash)>,
|
||||
) -> Result<(), String> {
|
||||
download_tar_bz2(rpc_addr, "genesis.tar.bz2", ledger_path, false)?;
|
||||
|
||||
if !no_snapshot_fetch {
|
||||
if snapshot_hash.is_some() {
|
||||
let snapshot_package =
|
||||
solana_ledger::snapshot_utils::get_snapshot_archive_path(ledger_path);
|
||||
if snapshot_package.exists() {
|
||||
@ -994,7 +1018,7 @@ pub fn main() {
|
||||
);
|
||||
|
||||
if !no_genesis_fetch {
|
||||
let (rpc_client, rpc_addr) = get_rpc_addr(
|
||||
let (rpc_contact_info, rpc_client, snapshot_hash) = get_rpc_node(
|
||||
&node,
|
||||
&identity_keypair,
|
||||
&cluster_entrypoint.gossip,
|
||||
@ -1008,11 +1032,6 @@ pub fn main() {
|
||||
no_snapshot_fetch,
|
||||
);
|
||||
|
||||
download_ledger(&rpc_addr, &ledger_path, no_snapshot_fetch).unwrap_or_else(|err| {
|
||||
error!("Failed to initialize ledger: {}", err);
|
||||
exit(1);
|
||||
});
|
||||
|
||||
let genesis_hash = rpc_client.get_genesis_hash().unwrap_or_else(|err| {
|
||||
error!("Failed to get genesis hash: {}", err);
|
||||
exit(1);
|
||||
@ -1041,6 +1060,13 @@ pub fn main() {
|
||||
exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
download_ledger(&rpc_contact_info.rpc, &ledger_path, snapshot_hash).unwrap_or_else(
|
||||
|err| {
|
||||
error!("Failed to initialize ledger: {}", err);
|
||||
exit(1);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user