CLI: Factor out offline helpers (bp #12382)

This commit is contained in:
Trent Nelson
2020-09-21 13:26:06 -06:00
committed by mergify[bot]
parent c0e44b624e
commit 838aaee144
38 changed files with 1008 additions and 978 deletions

28
Cargo.lock generated
View File

@ -3539,6 +3539,7 @@ dependencies = [
"solana-budget-program",
"solana-clap-utils",
"solana-cli-config",
"solana-cli-output",
"solana-client",
"solana-config-program",
"solana-core",
@ -3569,6 +3570,26 @@ dependencies = [
"url 2.1.1",
]
[[package]]
name = "solana-cli-output"
version = "1.3.13"
dependencies = [
"Inflector",
"chrono",
"console",
"humantime 2.0.1",
"indicatif",
"serde",
"serde_derive",
"serde_json",
"solana-clap-utils",
"solana-client",
"solana-sdk 1.3.13",
"solana-stake-program",
"solana-transaction-status",
"solana-vote-program",
]
[[package]]
name = "solana-client"
version = "1.3.13"
@ -3576,6 +3597,7 @@ dependencies = [
"assert_matches",
"bincode",
"bs58",
"clap",
"indicatif",
"jsonrpc-core",
"jsonrpc-http-server",
@ -3586,6 +3608,7 @@ dependencies = [
"serde_derive",
"serde_json",
"solana-account-decoder",
"solana-clap-utils",
"solana-logger 1.3.13",
"solana-net-utils",
"solana-sdk 1.3.13",
@ -3976,7 +3999,7 @@ dependencies = [
"serde_yaml",
"signal-hook",
"solana-clap-utils",
"solana-cli",
"solana-cli-output",
"solana-ledger",
"solana-logger 1.3.13",
"solana-measure",
@ -4483,6 +4506,7 @@ dependencies = [
"solana-clap-utils",
"solana-cli",
"solana-cli-config",
"solana-cli-output",
"solana-client",
"solana-logger 1.3.13",
"solana-metrics",
@ -4723,8 +4747,8 @@ dependencies = [
"humantime 2.0.1",
"log 0.4.8",
"solana-clap-utils",
"solana-cli",
"solana-cli-config",
"solana-cli-output",
"solana-client",
"solana-logger 1.3.13",
"solana-metrics",

View File

@ -10,6 +10,7 @@ members = [
"banks-server",
"clap-utils",
"cli-config",
"cli-output",
"client",
"core",
"dos",

View File

@ -0,0 +1,19 @@
use crate::{input_validators, ArgConstant};
use clap::Arg;
pub const FEE_PAYER_ARG: ArgConstant<'static> = ArgConstant {
name: "fee_payer",
long: "fee-payer",
help: "Specify the fee-payer account. This may be a keypair file, the ASK keyword \n\
or the pubkey of an offline signer, provided an appropriate --signer argument \n\
is also passed. Defaults to the client keypair.",
};
pub fn fee_payer_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(FEE_PAYER_ARG.name)
.long(FEE_PAYER_ARG.long)
.takes_value(true)
.value_name("KEYPAIR")
.validator(input_validators::is_valid_signer)
.help(FEE_PAYER_ARG.help)
}

View File

@ -11,6 +11,7 @@ use solana_remote_wallet::{
remote_wallet::{maybe_wallet_manager, RemoteWalletError, RemoteWalletManager},
};
use solana_sdk::{
hash::Hash,
pubkey::Pubkey,
signature::{
keypair_from_seed, keypair_from_seed_phrase_and_passphrase, read_keypair,
@ -25,6 +26,81 @@ use std::{
sync::Arc,
};
pub struct SignOnly {
pub blockhash: Hash,
pub present_signers: Vec<(Pubkey, Signature)>,
pub absent_signers: Vec<Pubkey>,
pub bad_signers: Vec<Pubkey>,
}
impl SignOnly {
pub fn has_all_signers(&self) -> bool {
self.absent_signers.is_empty() && self.bad_signers.is_empty()
}
pub fn presigner_of(&self, pubkey: &Pubkey) -> Option<Presigner> {
presigner_from_pubkey_sigs(pubkey, &self.present_signers)
}
}
pub type CliSigners = Vec<Box<dyn Signer>>;
pub type SignerIndex = usize;
pub struct CliSignerInfo {
pub signers: CliSigners,
}
impl CliSignerInfo {
pub fn index_of(&self, pubkey: Option<Pubkey>) -> Option<usize> {
if let Some(pubkey) = pubkey {
self.signers
.iter()
.position(|signer| signer.pubkey() == pubkey)
} else {
Some(0)
}
}
}
pub struct DefaultSigner {
pub arg_name: String,
pub path: String,
}
impl DefaultSigner {
pub fn generate_unique_signers(
&self,
bulk_signers: Vec<Option<Box<dyn Signer>>>,
matches: &ArgMatches<'_>,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliSignerInfo, Box<dyn error::Error>> {
let mut unique_signers = vec![];
// Determine if the default signer is needed
if bulk_signers.iter().any(|signer| signer.is_none()) {
let default_signer = self.signer_from_path(matches, wallet_manager)?;
unique_signers.push(default_signer);
}
for signer in bulk_signers.into_iter() {
if let Some(signer) = signer {
if !unique_signers.iter().any(|s| s == &signer) {
unique_signers.push(signer);
}
}
}
Ok(CliSignerInfo {
signers: unique_signers,
})
}
pub fn signer_from_path(
&self,
matches: &ArgMatches,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<Box<dyn Signer>, Box<dyn std::error::Error>> {
signer_from_path(matches, &self.path, &self.arg_name, wallet_manager)
}
}
pub enum KeypairUrl {
Ask,
Filepath(String),

View File

@ -24,7 +24,9 @@ impl std::fmt::Debug for DisplayError {
}
pub mod commitment;
pub mod fee_payer;
pub mod input_parsers;
pub mod input_validators;
pub mod keypair;
pub mod nonce;
pub mod offline;

47
clap-utils/src/nonce.rs Normal file
View File

@ -0,0 +1,47 @@
use crate::{input_validators::*, offline::BLOCKHASH_ARG, ArgConstant};
use clap::{App, Arg};
pub const NONCE_ARG: ArgConstant<'static> = ArgConstant {
name: "nonce",
long: "nonce",
help: "Provide the nonce account to use when creating a nonced \n\
transaction. Nonced transactions are useful when a transaction \n\
requires a lengthy signing process. Learn more about nonced \n\
transactions at https://docs.solana.com/offline-signing/durable-nonce",
};
pub const NONCE_AUTHORITY_ARG: ArgConstant<'static> = ArgConstant {
name: "nonce_authority",
long: "nonce-authority",
help: "Provide the nonce authority keypair to use when signing a nonced transaction",
};
fn nonce_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(NONCE_ARG.name)
.long(NONCE_ARG.long)
.takes_value(true)
.value_name("PUBKEY")
.requires(BLOCKHASH_ARG.name)
.validator(is_valid_pubkey)
.help(NONCE_ARG.help)
}
pub fn nonce_authority_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(NONCE_AUTHORITY_ARG.name)
.long(NONCE_AUTHORITY_ARG.long)
.takes_value(true)
.value_name("KEYPAIR")
.validator(is_valid_signer)
.help(NONCE_AUTHORITY_ARG.help)
}
pub trait NonceArgs {
fn nonce_args(self) -> Self;
}
impl NonceArgs for App<'_, '_> {
fn nonce_args(self) -> Self {
self.arg(nonce_arg())
.arg(nonce_authority_arg().requires(NONCE_ARG.name))
}
}

View File

@ -1,4 +1,5 @@
use crate::ArgConstant;
use crate::{input_validators::*, ArgConstant};
use clap::{App, Arg};
pub const BLOCKHASH_ARG: ArgConstant<'static> = ArgConstant {
name: "blockhash",
@ -17,3 +18,43 @@ pub const SIGNER_ARG: ArgConstant<'static> = ArgConstant {
long: "signer",
help: "Provide a public-key/signature pair for the transaction",
};
pub fn blockhash_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(BLOCKHASH_ARG.name)
.long(BLOCKHASH_ARG.long)
.takes_value(true)
.value_name("BLOCKHASH")
.validator(is_hash)
.help(BLOCKHASH_ARG.help)
}
pub fn sign_only_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(SIGN_ONLY_ARG.name)
.long(SIGN_ONLY_ARG.long)
.takes_value(false)
.requires(BLOCKHASH_ARG.name)
.help(SIGN_ONLY_ARG.help)
}
fn signer_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(SIGNER_ARG.name)
.long(SIGNER_ARG.long)
.takes_value(true)
.value_name("PUBKEY=SIGNATURE")
.validator(is_pubkey_sig)
.requires(BLOCKHASH_ARG.name)
.multiple(true)
.help(SIGNER_ARG.help)
}
pub trait OfflineArgs {
fn offline_args(self) -> Self;
}
impl OfflineArgs for App<'_, '_> {
fn offline_args(self) -> Self {
self.arg(blockhash_arg())
.arg(sign_only_arg())
.arg(signer_arg())
}
}

28
cli-output/Cargo.toml Normal file
View File

@ -0,0 +1,28 @@
[package]
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
edition = "2018"
name = "solana-cli-output"
description = "Blockchain, Rebuilt for Scale"
version = "1.3.13"
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
chrono = { version = "0.4.11", features = ["serde"] }
console = "0.11.3"
humantime = "2.0.1"
Inflector = "0.11.4"
indicatif = "0.15.0"
serde = "1.0.112"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-clap-utils = { path = "../clap-utils", version = "1.3.13" }
solana-client = { path = "../client", version = "1.3.13" }
solana-sdk = { path = "../sdk", version = "1.3.13" }
solana-stake-program = { path = "../programs/stake", version = "1.3.13" }
solana-transaction-status = { path = "../transaction-status", version = "1.3.13" }
solana-vote-program = { path = "../programs/vote", version = "1.3.13" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -1,20 +1,22 @@
use crate::{
cli::build_balance_message,
display::{format_labeled_address, writeln_name_value},
};
use crate::display::{build_balance_message, format_labeled_address, writeln_name_value};
use chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc};
use console::{style, Emoji};
use inflector::cases::titlecase::to_title_case;
use serde::Serialize;
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use solana_clap_utils::keypair::SignOnly;
use solana_client::rpc_response::{
RpcAccountBalance, RpcKeyedAccount, RpcSupply, RpcVoteAccountInfo,
};
use solana_sdk::{
clock::{self, Epoch, Slot, UnixTimestamp},
epoch_info::EpochInfo,
hash::Hash,
native_token::lamports_to_sol,
pubkey::Pubkey,
signature::Signature,
stake_history::StakeHistoryEntry,
transaction::Transaction,
};
use solana_stake_program::stake_state::{Authorized, Lockup};
use solana_vote_program::{
@ -24,6 +26,7 @@ use solana_vote_program::{
use std::{
collections::{BTreeMap, HashMap},
fmt,
str::FromStr,
time::Duration,
};
@ -1145,3 +1148,149 @@ impl fmt::Display for CliFees {
Ok(())
}
}
pub fn return_signers(
tx: &Transaction,
output_format: &OutputFormat,
) -> Result<String, Box<dyn std::error::Error>> {
let verify_results = tx.verify_with_results();
let mut signers = Vec::new();
let mut absent = Vec::new();
let mut bad_sig = Vec::new();
tx.signatures
.iter()
.zip(tx.message.account_keys.iter())
.zip(verify_results.into_iter())
.for_each(|((sig, key), res)| {
if res {
signers.push(format!("{}={}", key, sig))
} else if *sig == Signature::default() {
absent.push(key.to_string());
} else {
bad_sig.push(key.to_string());
}
});
let cli_command = CliSignOnlyData {
blockhash: tx.message.recent_blockhash.to_string(),
signers,
absent,
bad_sig,
};
Ok(output_format.formatted_string(&cli_command))
}
pub fn parse_sign_only_reply_string(reply: &str) -> SignOnly {
let object: Value = serde_json::from_str(&reply).unwrap();
let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap();
let blockhash = blockhash_str.parse::<Hash>().unwrap();
let mut present_signers: Vec<(Pubkey, Signature)> = Vec::new();
let signer_strings = object.get("signers");
if let Some(sig_strings) = signer_strings {
present_signers = sig_strings
.as_array()
.unwrap()
.iter()
.map(|signer_string| {
let mut signer = signer_string.as_str().unwrap().split('=');
let key = Pubkey::from_str(signer.next().unwrap()).unwrap();
let sig = Signature::from_str(signer.next().unwrap()).unwrap();
(key, sig)
})
.collect();
}
let mut absent_signers: Vec<Pubkey> = Vec::new();
let signer_strings = object.get("absent");
if let Some(sig_strings) = signer_strings {
absent_signers = sig_strings
.as_array()
.unwrap()
.iter()
.map(|val| {
let s = val.as_str().unwrap();
Pubkey::from_str(s).unwrap()
})
.collect();
}
let mut bad_signers: Vec<Pubkey> = Vec::new();
let signer_strings = object.get("badSig");
if let Some(sig_strings) = signer_strings {
bad_signers = sig_strings
.as_array()
.unwrap()
.iter()
.map(|val| {
let s = val.as_str().unwrap();
Pubkey::from_str(s).unwrap()
})
.collect();
}
SignOnly {
blockhash,
present_signers,
absent_signers,
bad_signers,
}
}
#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::{
message::Message,
pubkey::Pubkey,
signature::{keypair_from_seed, NullSigner, Signature, Signer, SignerError},
system_instruction,
transaction::Transaction,
};
#[test]
fn test_return_signers() {
struct BadSigner {
pubkey: Pubkey,
}
impl BadSigner {
pub fn new(pubkey: Pubkey) -> Self {
Self { pubkey }
}
}
impl Signer for BadSigner {
fn try_pubkey(&self) -> Result<Pubkey, SignerError> {
Ok(self.pubkey)
}
fn try_sign_message(&self, _message: &[u8]) -> Result<Signature, SignerError> {
Ok(Signature::new(&[1u8; 64]))
}
}
let present: Box<dyn Signer> = Box::new(keypair_from_seed(&[2u8; 32]).unwrap());
let absent: Box<dyn Signer> = Box::new(NullSigner::new(&Pubkey::new(&[3u8; 32])));
let bad: Box<dyn Signer> = Box::new(BadSigner::new(Pubkey::new(&[4u8; 32])));
let to = Pubkey::new(&[5u8; 32]);
let nonce = Pubkey::new(&[6u8; 32]);
let from = present.pubkey();
let fee_payer = absent.pubkey();
let nonce_auth = bad.pubkey();
let mut tx = Transaction::new_unsigned(Message::new_with_nonce(
vec![system_instruction::transfer(&from, &to, 42)],
Some(&fee_payer),
&nonce,
&nonce_auth,
));
let signers = vec![present.as_ref(), absent.as_ref(), bad.as_ref()];
let blockhash = Hash::new(&[7u8; 32]);
tx.try_partial_sign(&signers, blockhash).unwrap();
let res = return_signers(&tx, &OutputFormat::JsonCompact).unwrap();
let sign_only = parse_sign_only_reply_string(&res);
assert_eq!(sign_only.blockhash, blockhash);
assert_eq!(sign_only.present_signers[0].0, present.pubkey());
assert_eq!(sign_only.absent_signers[0], absent.pubkey());
assert_eq!(sign_only.bad_signers[0], bad.pubkey());
}
}

View File

@ -1,4 +1,3 @@
use crate::cli::SettingType;
use console::style;
use indicatif::{ProgressBar, ProgressStyle};
use solana_sdk::{
@ -8,6 +7,24 @@ use solana_sdk::{
use solana_transaction_status::UiTransactionStatusMeta;
use std::{collections::HashMap, fmt, io};
pub fn build_balance_message(lamports: u64, use_lamports_unit: bool, show_unit: bool) -> String {
if use_lamports_unit {
let ess = if lamports == 1 { "" } else { "s" };
let unit = if show_unit {
format!(" lamport{}", ess)
} else {
"".to_string()
};
format!("{:?}{}", lamports, unit)
} else {
let sol = lamports_to_sol(lamports);
let sol_str = format!("{:.9}", sol);
let pretty_sol = sol_str.trim_end_matches('0').trim_end_matches('.');
let unit = if show_unit { " SOL" } else { "" };
format!("{}{}", pretty_sol, unit)
}
}
// Pretty print a "name value"
pub fn println_name_value(name: &str, value: &str) {
let styled_value = if value == "" {
@ -40,21 +57,6 @@ pub fn format_labeled_address(pubkey: &str, address_labels: &HashMap<String, Str
}
}
pub fn println_name_value_or(name: &str, value: &str, setting_type: SettingType) {
let description = match setting_type {
SettingType::Explicit => "",
SettingType::Computed => "(computed)",
SettingType::SystemDefault => "(default)",
};
println!(
"{} {} {}",
style(name).bold(),
style(value),
style(description).italic(),
);
}
pub fn println_signers(
blockhash: &Hash,
signers: &[String],

3
cli-output/src/lib.rs Normal file
View File

@ -0,0 +1,3 @@
mod cli_output;
pub mod display;
pub use cli_output::*;

View File

@ -31,6 +31,7 @@ solana-account-decoder = { path = "../account-decoder", version = "1.3.13" }
solana-budget-program = { path = "../programs/budget", version = "1.3.13" }
solana-clap-utils = { path = "../clap-utils", version = "1.3.13" }
solana-cli-config = { path = "../cli-config", version = "1.3.13" }
solana-cli-output = { path = "../cli-output", version = "1.3.13" }
solana-client = { path = "../client", version = "1.3.13" }
solana-config-program = { path = "../programs/config", version = "1.3.13" }
solana-faucet = { path = "../faucet", version = "1.3.13" }

View File

@ -1,14 +1,5 @@
use crate::{
checks::*,
cli_output::{CliAccount, CliSignOnlyData, CliSignature, OutputFormat},
cluster_query::*,
display::{new_spinner_progress_bar, println_name_value, println_transaction},
nonce::{self, *},
offline::{blockhash_query::BlockhashQuery, *},
spend_utils::*,
stake::*,
validator_info::*,
vote::*,
checks::*, cluster_query::*, nonce::*, spend_utils::*, stake::*, validator_info::*, vote::*,
};
use chrono::prelude::*;
use clap::{value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
@ -18,11 +9,25 @@ use serde_json::{self, json, Value};
use solana_account_decoder::{UiAccount, UiAccountEncoding};
use solana_budget_program::budget_instruction::{self, BudgetError};
use solana_clap_utils::{
commitment::commitment_arg_with_default, input_parsers::*, input_validators::*,
keypair::signer_from_path, offline::SIGN_ONLY_ARG, ArgConstant,
self,
commitment::commitment_arg_with_default,
fee_payer::{fee_payer_arg, FEE_PAYER_ARG},
input_parsers::*,
input_validators::*,
keypair::*,
nonce::*,
offline::*,
};
use solana_cli_output::{
display::{
build_balance_message, new_spinner_progress_bar, println_name_value, println_transaction,
},
return_signers, CliAccount, CliSignature, OutputFormat,
};
use solana_client::{
blockhash_query::BlockhashQuery,
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
nonce_utils,
rpc_client::RpcClient,
rpc_config::{RpcLargestAccountsFilter, RpcSendTransactionConfig},
rpc_response::{Response, RpcKeyedAccount},
@ -37,12 +42,10 @@ use solana_sdk::{
clock::{Epoch, Slot, DEFAULT_TICKS_PER_SECOND},
commitment_config::CommitmentConfig,
decode_error::DecodeError,
fee_calculator::FeeCalculator,
hash::Hash,
instruction::InstructionError,
loader_instruction,
message::Message,
native_token::lamports_to_sol,
pubkey::{Pubkey, MAX_SEED_LEN},
signature::{Keypair, Signature, Signer, SignerError},
signers::Signers,
@ -71,97 +74,9 @@ use std::{
use thiserror::Error;
use url::Url;
pub type CliSigners = Vec<Box<dyn Signer>>;
pub type SignerIndex = usize;
pub(crate) struct CliSignerInfo {
pub signers: CliSigners,
}
impl CliSignerInfo {
pub(crate) fn index_of(&self, pubkey: Option<Pubkey>) -> Option<usize> {
if let Some(pubkey) = pubkey {
self.signers
.iter()
.position(|signer| signer.pubkey() == pubkey)
} else {
Some(0)
}
}
}
pub(crate) fn generate_unique_signers(
bulk_signers: Vec<Option<Box<dyn Signer>>>,
matches: &ArgMatches<'_>,
default_signer_path: &str,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliSignerInfo, Box<dyn error::Error>> {
let mut unique_signers = vec![];
// Determine if the default signer is needed
if bulk_signers.iter().any(|signer| signer.is_none()) {
let default_signer =
signer_from_path(matches, default_signer_path, "keypair", wallet_manager)?;
unique_signers.push(default_signer);
}
for signer in bulk_signers.into_iter() {
if let Some(signer) = signer {
if !unique_signers.iter().any(|s| s == &signer) {
unique_signers.push(signer);
}
}
}
Ok(CliSignerInfo {
signers: unique_signers,
})
}
const DATA_CHUNK_SIZE: usize = 229; // Keep program chunks under PACKET_DATA_SIZE
pub const DEFAULT_RPC_TIMEOUT_SECONDS: &str = "30";
pub const FEE_PAYER_ARG: ArgConstant<'static> = ArgConstant {
name: "fee_payer",
long: "fee-payer",
help: "Specify the fee-payer account. This may be a keypair file, the ASK keyword \n\
or the pubkey of an offline signer, provided an appropriate --signer argument \n\
is also passed. Defaults to the client keypair.",
};
pub fn fee_payer_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(FEE_PAYER_ARG.name)
.long(FEE_PAYER_ARG.long)
.takes_value(true)
.value_name("KEYPAIR")
.validator(is_valid_signer)
.help(FEE_PAYER_ARG.help)
}
#[derive(Debug)]
pub struct KeypairEq(Keypair);
impl From<Keypair> for KeypairEq {
fn from(keypair: Keypair) -> Self {
Self(keypair)
}
}
impl PartialEq for KeypairEq {
fn eq(&self, other: &Self) -> bool {
self.pubkey() == other.pubkey()
}
}
impl std::ops::Deref for KeypairEq {
type Target = Keypair;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub fn nonce_authority_arg<'a, 'b>() -> Arg<'a, 'b> {
nonce::nonce_authority_arg().requires(NONCE_ARG.name)
}
#[derive(Default, Debug, PartialEq)]
pub struct PayCommand {
pub amount: SpendAmount,
@ -467,7 +382,7 @@ pub enum CliError {
#[error("insufficient funds for spend ({0} SOL) and fee ({1} SOL)")]
InsufficientFundsForSpendAndFee(f64, f64),
#[error(transparent)]
InvalidNonce(CliNonceError),
InvalidNonce(nonce_utils::Error),
#[error("dynamic program error: {0}")]
DynamicProgramError(String),
#[error("rpc request error: {0}")]
@ -482,10 +397,10 @@ impl From<Box<dyn error::Error>> for CliError {
}
}
impl From<CliNonceError> for CliError {
fn from(error: CliNonceError) -> Self {
impl From<nonce_utils::Error> for CliError {
fn from(error: nonce_utils::Error) -> Self {
match error {
CliNonceError::Client(client_error) => Self::RpcRequestError(client_error),
nonce_utils::Error::Client(client_error) => Self::RpcRequestError(client_error),
_ => Self::InvalidNonce(error),
}
}
@ -622,7 +537,7 @@ impl Default for CliConfig<'_> {
pub fn parse_command(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, Box<dyn error::Error>> {
let response = match matches.subcommand() {
@ -637,7 +552,7 @@ pub fn parse_command(
signers: vec![],
}),
("create-address-with-seed", Some(matches)) => {
parse_create_address_with_seed(matches, default_signer_path, wallet_manager)
parse_create_address_with_seed(matches, default_signer, wallet_manager)
}
("fees", Some(_matches)) => Ok(CliCommandInfo {
command: CliCommand::Fees,
@ -665,7 +580,7 @@ pub fn parse_command(
command: CliCommand::LeaderSchedule,
signers: vec![],
}),
("ping", Some(matches)) => parse_cluster_ping(matches, default_signer_path, wallet_manager),
("ping", Some(matches)) => parse_cluster_ping(matches, default_signer, wallet_manager),
("live-slots", Some(_matches)) => Ok(CliCommandInfo {
command: CliCommand::LiveSlots,
signers: vec![],
@ -682,28 +597,21 @@ pub fn parse_command(
}
// Nonce Commands
("authorize-nonce-account", Some(matches)) => {
parse_authorize_nonce_account(matches, default_signer_path, wallet_manager)
parse_authorize_nonce_account(matches, default_signer, wallet_manager)
}
("create-nonce-account", Some(matches)) => {
parse_nonce_create_account(matches, default_signer_path, wallet_manager)
parse_nonce_create_account(matches, default_signer, wallet_manager)
}
("nonce", Some(matches)) => parse_get_nonce(matches, wallet_manager),
("new-nonce", Some(matches)) => {
parse_new_nonce(matches, default_signer_path, wallet_manager)
}
("new-nonce", Some(matches)) => parse_new_nonce(matches, default_signer, wallet_manager),
("nonce-account", Some(matches)) => parse_show_nonce_account(matches, wallet_manager),
("withdraw-from-nonce-account", Some(matches)) => {
parse_withdraw_from_nonce_account(matches, default_signer_path, wallet_manager)
parse_withdraw_from_nonce_account(matches, default_signer, wallet_manager)
}
// Program Deployment
("deploy", Some(matches)) => {
let (address_signer, _address) = signer_of(matches, "address_signer", wallet_manager)?;
let mut signers = vec![signer_from_path(
matches,
default_signer_path,
"keypair",
wallet_manager,
)?];
let mut signers = vec![default_signer.signer_from_path(matches, wallet_manager)?];
let address = address_signer.map(|signer| {
signers.push(signer);
1
@ -721,74 +629,69 @@ pub fn parse_command(
}
// Stake Commands
("create-stake-account", Some(matches)) => {
parse_stake_create_account(matches, default_signer_path, wallet_manager)
parse_stake_create_account(matches, default_signer, wallet_manager)
}
("delegate-stake", Some(matches)) => {
parse_stake_delegate_stake(matches, default_signer_path, wallet_manager)
parse_stake_delegate_stake(matches, default_signer, wallet_manager)
}
("withdraw-stake", Some(matches)) => {
parse_stake_withdraw_stake(matches, default_signer_path, wallet_manager)
parse_stake_withdraw_stake(matches, default_signer, wallet_manager)
}
("deactivate-stake", Some(matches)) => {
parse_stake_deactivate_stake(matches, default_signer_path, wallet_manager)
parse_stake_deactivate_stake(matches, default_signer, wallet_manager)
}
("split-stake", Some(matches)) => {
parse_split_stake(matches, default_signer_path, wallet_manager)
parse_split_stake(matches, default_signer, wallet_manager)
}
("merge-stake", Some(matches)) => {
parse_merge_stake(matches, default_signer_path, wallet_manager)
parse_merge_stake(matches, default_signer, wallet_manager)
}
("stake-authorize", Some(matches)) => {
parse_stake_authorize(matches, default_signer_path, wallet_manager)
parse_stake_authorize(matches, default_signer, wallet_manager)
}
("stake-set-lockup", Some(matches)) => {
parse_stake_set_lockup(matches, default_signer_path, wallet_manager)
parse_stake_set_lockup(matches, default_signer, wallet_manager)
}
("stake-account", Some(matches)) => parse_show_stake_account(matches, wallet_manager),
("stake-history", Some(matches)) => parse_show_stake_history(matches),
// Validator Info Commands
("validator-info", Some(matches)) => match matches.subcommand() {
("publish", Some(matches)) => {
parse_validator_info_command(matches, default_signer_path, wallet_manager)
parse_validator_info_command(matches, default_signer, wallet_manager)
}
("get", Some(matches)) => parse_get_validator_info_command(matches),
_ => unreachable!(),
},
// Vote Commands
("create-vote-account", Some(matches)) => {
parse_create_vote_account(matches, default_signer_path, wallet_manager)
parse_create_vote_account(matches, default_signer, wallet_manager)
}
("vote-update-validator", Some(matches)) => {
parse_vote_update_validator(matches, default_signer_path, wallet_manager)
parse_vote_update_validator(matches, default_signer, wallet_manager)
}
("vote-update-commission", Some(matches)) => {
parse_vote_update_commission(matches, default_signer_path, wallet_manager)
parse_vote_update_commission(matches, default_signer, wallet_manager)
}
("vote-authorize-voter", Some(matches)) => parse_vote_authorize(
matches,
default_signer_path,
default_signer,
wallet_manager,
VoteAuthorize::Voter,
),
("vote-authorize-withdrawer", Some(matches)) => parse_vote_authorize(
matches,
default_signer_path,
default_signer,
wallet_manager,
VoteAuthorize::Withdrawer,
),
("vote-account", Some(matches)) => parse_vote_get_account_command(matches, wallet_manager),
("withdraw-from-vote-account", Some(matches)) => {
parse_withdraw_from_vote_account(matches, default_signer_path, wallet_manager)
parse_withdraw_from_vote_account(matches, default_signer, wallet_manager)
}
// Wallet Commands
("address", Some(matches)) => Ok(CliCommandInfo {
command: CliCommand::Address,
signers: vec![signer_from_path(
matches,
default_signer_path,
"keypair",
wallet_manager,
)?],
signers: vec![default_signer.signer_from_path(matches, wallet_manager)?],
}),
("airdrop", Some(matches)) => {
let faucet_port = matches
@ -809,12 +712,7 @@ pub fn parse_command(
let signers = if pubkey.is_some() {
vec![]
} else {
vec![signer_from_path(
matches,
default_signer_path,
"keypair",
wallet_manager,
)?]
vec![default_signer.signer_from_path(matches, wallet_manager)?]
};
let lamports = lamports_of_sol(matches, "amount").unwrap();
Ok(CliCommandInfo {
@ -832,12 +730,7 @@ pub fn parse_command(
let signers = if pubkey.is_some() {
vec![]
} else {
vec![signer_from_path(
matches,
default_signer_path,
"keypair",
wallet_manager,
)?]
vec![default_signer.signer_from_path(matches, wallet_manager)?]
};
Ok(CliCommandInfo {
command: CliCommand::Balance {
@ -849,8 +742,7 @@ pub fn parse_command(
}
("cancel", Some(matches)) => {
let process_id = value_of(matches, "process_id").unwrap();
let default_signer =
signer_from_path(matches, default_signer_path, "keypair", wallet_manager)?;
let default_signer = default_signer.signer_from_path(matches, wallet_manager)?;
Ok(CliCommandInfo {
command: CliCommand::Cancel(process_id),
@ -912,12 +804,8 @@ pub fn parse_command(
if nonce_account.is_some() {
bulk_signers.push(nonce_authority);
}
let signer_info = generate_unique_signers(
bulk_signers,
matches,
default_signer_path,
wallet_manager,
)?;
let signer_info =
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
Ok(CliCommandInfo {
command: CliCommand::Pay(PayCommand {
@ -960,8 +848,7 @@ pub fn parse_command(
let to = value_of(matches, "to").unwrap();
let process_id = value_of(matches, "process_id").unwrap();
let default_signer =
signer_from_path(matches, default_signer_path, "keypair", wallet_manager)?;
let default_signer = default_signer.signer_from_path(matches, wallet_manager)?;
Ok(CliCommandInfo {
command: CliCommand::Witness(to, process_id),
@ -982,8 +869,7 @@ pub fn parse_command(
} else {
Utc::now()
};
let default_signer =
signer_from_path(matches, default_signer_path, "keypair", wallet_manager)?;
let default_signer = default_signer.signer_from_path(matches, wallet_manager)?;
Ok(CliCommandInfo {
command: CliCommand::TimeElapsed(to, process_id, dt),
@ -1008,12 +894,8 @@ pub fn parse_command(
bulk_signers.push(nonce_authority);
}
let signer_info = generate_unique_signers(
bulk_signers,
matches,
default_signer_path,
wallet_manager,
)?;
let signer_info =
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
Ok(CliCommandInfo {
command: CliCommand::Transfer {
@ -1044,66 +926,16 @@ pub fn parse_command(
pub type ProcessResult = Result<String, Box<dyn std::error::Error>>;
pub fn get_blockhash_and_fee_calculator(
rpc_client: &RpcClient,
sign_only: bool,
blockhash: Option<Hash>,
) -> Result<(Hash, FeeCalculator), Box<dyn std::error::Error>> {
Ok(if let Some(blockhash) = blockhash {
if sign_only {
(blockhash, FeeCalculator::default())
} else {
(blockhash, rpc_client.get_recent_blockhash()?.1)
}
} else {
rpc_client.get_recent_blockhash()?
})
}
pub fn return_signers(tx: &Transaction, config: &CliConfig) -> ProcessResult {
let verify_results = tx.verify_with_results();
let mut signers = Vec::new();
let mut absent = Vec::new();
let mut bad_sig = Vec::new();
tx.signatures
.iter()
.zip(tx.message.account_keys.iter())
.zip(verify_results.into_iter())
.for_each(|((sig, key), res)| {
if res {
signers.push(format!("{}={}", key, sig))
} else if *sig == Signature::default() {
absent.push(key.to_string());
} else {
bad_sig.push(key.to_string());
}
});
let cli_command = CliSignOnlyData {
blockhash: tx.message.recent_blockhash.to_string(),
signers,
absent,
bad_sig,
};
Ok(config.output_format.formatted_string(&cli_command))
}
pub fn parse_create_address_with_seed(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let from_pubkey = pubkey_of_signer(matches, "from", wallet_manager)?;
let signers = if from_pubkey.is_some() {
vec![]
} else {
vec![signer_from_path(
matches,
default_signer_path,
"keypair",
wallet_manager,
)?]
vec![default_signer.signer_from_path(matches, wallet_manager)?]
};
let program_id = match matches.value_of("program_id").unwrap() {
@ -1553,10 +1385,10 @@ fn process_pay(
if sign_only {
tx.try_partial_sign(&config.signers, blockhash)?;
return_signers(&tx, &config)
return_signers(&tx, &config.output_format)
} else {
if let Some(nonce_account) = &nonce_account {
let nonce_account = nonce::get_account_with_commitment(
let nonce_account = nonce_utils::get_account_with_commitment(
rpc_client,
nonce_account,
config.commitment,
@ -1606,7 +1438,7 @@ fn process_pay(
let mut tx = Transaction::new_unsigned(message);
if sign_only {
tx.try_partial_sign(&[config.signers[0], &contract_state], blockhash)?;
return_signers(&tx, &config)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&[config.signers[0], &contract_state], blockhash)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
@ -1657,7 +1489,7 @@ fn process_pay(
let mut tx = Transaction::new_unsigned(message);
if sign_only {
tx.try_partial_sign(&[config.signers[0], &contract_state], blockhash)?;
return_signers(&tx, &config)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&[config.signers[0], &contract_state], blockhash)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
@ -1785,11 +1617,14 @@ fn process_transfer(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers(&tx, &config)
return_signers(&tx, &config.output_format)
} else {
if let Some(nonce_account) = &nonce_account {
let nonce_account =
nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?;
let nonce_account = nonce_utils::get_account_with_commitment(
rpc_client,
nonce_account,
config.commitment,
)?;
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
}
@ -2506,28 +2341,6 @@ where
}
}
pub(crate) fn build_balance_message(
lamports: u64,
use_lamports_unit: bool,
show_unit: bool,
) -> String {
if use_lamports_unit {
let ess = if lamports == 1 { "" } else { "s" };
let unit = if show_unit {
format!(" lamport{}", ess)
} else {
"".to_string()
};
format!("{:?}{}", lamports, unit)
} else {
let sol = lamports_to_sol(lamports);
let sol_str = format!("{:.9}", sol);
let pretty_sol = sol_str.trim_end_matches('0').trim_end_matches('.');
let unit = if show_unit { " SOL" } else { "" };
format!("{}{}", pretty_sol, unit)
}
}
pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, 'v> {
App::new(name)
.about(about)
@ -2752,8 +2565,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.takes_value(false),
)
.offline_args()
.arg(nonce_arg())
.arg(nonce_authority_arg()),
.nonce_args()
)
.subcommand(
SubCommand::with_name("resolve-signer")
@ -2845,8 +2657,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
.help("Return signature immediately after submitting the transaction, instead of waiting for confirmations"),
)
.offline_args()
.arg(nonce_arg())
.arg(nonce_authority_arg())
.nonce_args()
.arg(fee_payer_arg()),
)
.subcommand(
@ -2883,12 +2694,10 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
mod tests {
use super::*;
use serde_json::Value;
use solana_client::mock_sender::SIGNATURE;
use solana_client::{blockhash_query, mock_sender::SIGNATURE};
use solana_sdk::{
pubkey::Pubkey,
signature::{
keypair_from_seed, read_keypair_file, write_keypair_file, NullSigner, Presigner,
},
signature::{keypair_from_seed, read_keypair_file, write_keypair_file, Presigner},
transaction::TransactionError,
};
use std::path::PathBuf;
@ -2915,13 +2724,19 @@ mod tests {
let default_keypair_file = make_tmp_path("keypair_file");
write_keypair_file(&default_keypair, &default_keypair_file).unwrap();
let signer_info =
generate_unique_signers(vec![], &matches, &default_keypair_file, &mut None).unwrap();
let default_signer = DefaultSigner {
arg_name: "keypair".to_string(),
path: default_keypair_file,
};
let signer_info = default_signer
.generate_unique_signers(vec![], &matches, &mut None)
.unwrap();
assert_eq!(signer_info.signers.len(), 0);
let signer_info =
generate_unique_signers(vec![None, None], &matches, &default_keypair_file, &mut None)
.unwrap();
let signer_info = default_signer
.generate_unique_signers(vec![None, None], &matches, &mut None)
.unwrap();
assert_eq!(signer_info.signers.len(), 1);
assert_eq!(signer_info.index_of(None), Some(0));
assert_eq!(signer_info.index_of(Some(Pubkey::new_rand())), None);
@ -2931,8 +2746,9 @@ mod tests {
let keypair0_clone = keypair_from_seed(&[1u8; 32]).unwrap();
let keypair0_clone_pubkey = keypair0.pubkey();
let signers = vec![None, Some(keypair0.into()), Some(keypair0_clone.into())];
let signer_info =
generate_unique_signers(signers, &matches, &default_keypair_file, &mut None).unwrap();
let signer_info = default_signer
.generate_unique_signers(signers, &matches, &mut None)
.unwrap();
assert_eq!(signer_info.signers.len(), 2);
assert_eq!(signer_info.index_of(None), Some(0));
assert_eq!(signer_info.index_of(Some(keypair0_pubkey)), Some(1));
@ -2942,8 +2758,9 @@ mod tests {
let keypair0_pubkey = keypair0.pubkey();
let keypair0_clone = keypair_from_seed(&[1u8; 32]).unwrap();
let signers = vec![Some(keypair0.into()), Some(keypair0_clone.into())];
let signer_info =
generate_unique_signers(signers, &matches, &default_keypair_file, &mut None).unwrap();
let signer_info = default_signer
.generate_unique_signers(signers, &matches, &mut None)
.unwrap();
assert_eq!(signer_info.signers.len(), 1);
assert_eq!(signer_info.index_of(Some(keypair0_pubkey)), Some(0));
@ -2963,8 +2780,9 @@ mod tests {
Some(presigner1.into()),
Some(keypair1.into()),
];
let signer_info =
generate_unique_signers(signers, &matches, &default_keypair_file, &mut None).unwrap();
let signer_info = default_signer
.generate_unique_signers(signers, &matches, &mut None)
.unwrap();
assert_eq!(signer_info.signers.len(), 2);
assert_eq!(signer_info.index_of(Some(keypair0_pubkey)), Some(0));
assert_eq!(signer_info.index_of(Some(keypair1_pubkey)), Some(1));
@ -2985,13 +2803,21 @@ mod tests {
let witness1_string = format!("{}", witness1);
let dt = Utc.ymd(2018, 9, 19).and_hms(17, 30, 59);
let default_keypair = Keypair::new();
let keypair_file = make_tmp_path("keypair_file");
write_keypair_file(&default_keypair, &keypair_file).unwrap();
let keypair = read_keypair_file(&keypair_file).unwrap();
let default_signer = DefaultSigner {
path: keypair_file.clone(),
arg_name: "".to_string(),
};
// Test Airdrop Subcommand
let test_airdrop =
test_commands
.clone()
.get_matches_from(vec!["test", "airdrop", "50", &pubkey_string]);
assert_eq!(
parse_command(&test_airdrop, "", &mut None).unwrap(),
parse_command(&test_airdrop, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Airdrop {
faucet_host: None,
@ -3004,17 +2830,13 @@ mod tests {
);
// Test Balance Subcommand, incl pubkey and keypair-file inputs
let default_keypair = Keypair::new();
let keypair_file = make_tmp_path("keypair_file");
write_keypair_file(&default_keypair, &keypair_file).unwrap();
let keypair = read_keypair_file(&keypair_file).unwrap();
let test_balance = test_commands.clone().get_matches_from(vec![
"test",
"balance",
&keypair.pubkey().to_string(),
]);
assert_eq!(
parse_command(&test_balance, "", &mut None).unwrap(),
parse_command(&test_balance, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Balance {
pubkey: Some(keypair.pubkey()),
@ -3030,7 +2852,7 @@ mod tests {
"--lamports",
]);
assert_eq!(
parse_command(&test_balance, "", &mut None).unwrap(),
parse_command(&test_balance, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Balance {
pubkey: Some(keypair.pubkey()),
@ -3044,7 +2866,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "balance", "--lamports"]);
assert_eq!(
parse_command(&test_balance, &keypair_file, &mut None).unwrap(),
parse_command(&test_balance, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Balance {
pubkey: None,
@ -3060,7 +2882,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "cancel", &pubkey_string]);
assert_eq!(
parse_command(&test_cancel, &keypair_file, &mut None).unwrap(),
parse_command(&test_cancel, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Cancel(pubkey),
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
@ -3075,7 +2897,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "confirm", &signature_string]);
assert_eq!(
parse_command(&test_confirm, "", &mut None).unwrap(),
parse_command(&test_confirm, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Confirm(signature),
signers: vec![],
@ -3084,7 +2906,7 @@ mod tests {
let test_bad_signature = test_commands
.clone()
.get_matches_from(vec!["test", "confirm", "deadbeef"]);
assert!(parse_command(&test_bad_signature, "", &mut None).is_err());
assert!(parse_command(&test_bad_signature, &default_signer, &mut None).is_err());
// Test CreateAddressWithSeed
let from_pubkey = Some(Pubkey::new_rand());
@ -3103,7 +2925,7 @@ mod tests {
&from_str,
]);
assert_eq!(
parse_command(&test_create_address_with_seed, "", &mut None).unwrap(),
parse_command(&test_create_address_with_seed, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateAddressWithSeed {
from_pubkey,
@ -3121,7 +2943,7 @@ mod tests {
"STAKE",
]);
assert_eq!(
parse_command(&test_create_address_with_seed, &keypair_file, &mut None).unwrap(),
parse_command(&test_create_address_with_seed, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateAddressWithSeed {
from_pubkey: None,
@ -3138,7 +2960,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "deploy", "/Users/test/program.o"]);
assert_eq!(
parse_command(&test_deploy, &keypair_file, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Deploy {
program_location: "/Users/test/program.o".to_string(),
@ -3159,7 +2981,7 @@ mod tests {
&custom_address_file,
]);
assert_eq!(
parse_command(&test_deploy, &keypair_file, &mut None).unwrap(),
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Deploy {
program_location: "/Users/test/program.o".to_string(),
@ -3179,7 +3001,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "resolve-signer", &keypair_file]);
assert_eq!(
parse_command(&test_resolve_signer, "", &mut None).unwrap(),
parse_command(&test_resolve_signer, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::ResolveSigner(Some(keypair_file.clone())),
signers: vec![],
@ -3191,7 +3013,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "resolve-signer", &pubkey_string]);
assert_eq!(
parse_command(&test_resolve_signer, "", &mut None).unwrap(),
parse_command(&test_resolve_signer, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::ResolveSigner(Some(pubkey.to_string())),
signers: vec![],
@ -3204,7 +3026,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "pay", &pubkey_string, "50"]);
assert_eq!(
parse_command(&test_pay, &keypair_file, &mut None).unwrap(),
parse_command(&test_pay, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(50_000_000_000),
@ -3227,7 +3049,7 @@ mod tests {
&witness1_string,
]);
assert_eq!(
parse_command(&test_pay_multiple_witnesses, &keypair_file, &mut None).unwrap(),
parse_command(&test_pay_multiple_witnesses, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(50_000_000_000),
@ -3247,7 +3069,7 @@ mod tests {
&witness0_string,
]);
assert_eq!(
parse_command(&test_pay_single_witness, &keypair_file, &mut None).unwrap(),
parse_command(&test_pay_single_witness, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(50_000_000_000),
@ -3271,7 +3093,7 @@ mod tests {
&witness0_string,
]);
assert_eq!(
parse_command(&test_pay_timestamp, &keypair_file, &mut None).unwrap(),
parse_command(&test_pay_timestamp, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(50_000_000_000),
@ -3297,7 +3119,7 @@ mod tests {
"--sign-only",
]);
assert_eq!(
parse_command(&test_pay, &keypair_file, &mut None).unwrap(),
parse_command(&test_pay, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(50_000_000_000),
@ -3320,7 +3142,7 @@ mod tests {
&blockhash_string,
]);
assert_eq!(
parse_command(&test_pay, &keypair_file, &mut None).unwrap(),
parse_command(&test_pay, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(50_000_000_000),
@ -3349,7 +3171,7 @@ mod tests {
&pubkey_string,
]);
assert_eq!(
parse_command(&test_pay, &keypair_file, &mut None).unwrap(),
parse_command(&test_pay, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(50_000_000_000),
@ -3382,7 +3204,7 @@ mod tests {
&keypair_file,
]);
assert_eq!(
parse_command(&test_pay, &keypair_file, &mut None).unwrap(),
parse_command(&test_pay, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(50_000_000_000),
@ -3420,7 +3242,7 @@ mod tests {
&signer_arg,
]);
assert_eq!(
parse_command(&test_pay, &keypair_file, &mut None).unwrap(),
parse_command(&test_pay, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(50_000_000_000),
@ -3458,7 +3280,7 @@ mod tests {
"--signer",
&signer_arg,
]);
assert!(parse_command(&test_pay, &keypair_file, &mut None).is_err());
assert!(parse_command(&test_pay, &default_signer, &mut None).is_err());
// Test Send-Signature Subcommand
let test_send_signature = test_commands.clone().get_matches_from(vec![
@ -3468,7 +3290,7 @@ mod tests {
&pubkey_string,
]);
assert_eq!(
parse_command(&test_send_signature, &keypair_file, &mut None).unwrap(),
parse_command(&test_send_signature, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Witness(pubkey, pubkey),
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
@ -3489,7 +3311,7 @@ mod tests {
&witness1_string,
]);
assert_eq!(
parse_command(&test_pay_multiple_witnesses, &keypair_file, &mut None).unwrap(),
parse_command(&test_pay_multiple_witnesses, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Pay(PayCommand {
amount: SpendAmount::Some(50_000_000_000),
@ -3513,7 +3335,7 @@ mod tests {
"2018-09-19T17:30:59",
]);
assert_eq!(
parse_command(&test_send_timestamp, &keypair_file, &mut None).unwrap(),
parse_command(&test_send_timestamp, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::TimeElapsed(pubkey, pubkey, dt),
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
@ -3527,7 +3349,7 @@ mod tests {
"--date",
"20180919T17:30:59",
]);
assert!(parse_command(&test_bad_timestamp, &keypair_file, &mut None).is_err());
assert!(parse_command(&test_bad_timestamp, &default_signer, &mut None).is_err());
}
#[test]
@ -3914,6 +3736,10 @@ mod tests {
let default_keypair = Keypair::new();
let default_keypair_file = make_tmp_path("keypair_file");
write_keypair_file(&default_keypair, &default_keypair_file).unwrap();
let default_signer = DefaultSigner {
path: default_keypair_file.clone(),
arg_name: "".to_string(),
};
//Test Transfer Subcommand, SOL
let from_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
@ -3926,7 +3752,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "transfer", &to_string, "42"]);
assert_eq!(
parse_command(&test_transfer, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Transfer {
amount: SpendAmount::Some(42_000_000_000),
@ -3948,7 +3774,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "transfer", &to_string, "ALL"]);
assert_eq!(
parse_command(&test_transfer, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Transfer {
amount: SpendAmount::All,
@ -3974,7 +3800,7 @@ mod tests {
"42",
]);
assert_eq!(
parse_command(&test_transfer, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Transfer {
amount: SpendAmount::Some(42_000_000_000),
@ -4004,7 +3830,7 @@ mod tests {
"--sign-only",
]);
assert_eq!(
parse_command(&test_transfer, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Transfer {
amount: SpendAmount::Some(42_000_000_000),
@ -4039,7 +3865,7 @@ mod tests {
&blockhash_string,
]);
assert_eq!(
parse_command(&test_transfer, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Transfer {
amount: SpendAmount::Some(42_000_000_000),
@ -4078,7 +3904,7 @@ mod tests {
&nonce_authority_file,
]);
assert_eq!(
parse_command(&test_transfer, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Transfer {
amount: SpendAmount::Some(42_000_000_000),
@ -4101,54 +3927,4 @@ mod tests {
}
);
}
#[test]
fn test_return_signers() {
struct BadSigner {
pubkey: Pubkey,
}
impl BadSigner {
pub fn new(pubkey: Pubkey) -> Self {
Self { pubkey }
}
}
impl Signer for BadSigner {
fn try_pubkey(&self) -> Result<Pubkey, SignerError> {
Ok(self.pubkey)
}
fn try_sign_message(&self, _message: &[u8]) -> Result<Signature, SignerError> {
Ok(Signature::new(&[1u8; 64]))
}
}
let mut config = CliConfig::default();
config.output_format = OutputFormat::JsonCompact;
let present: Box<dyn Signer> = Box::new(keypair_from_seed(&[2u8; 32]).unwrap());
let absent: Box<dyn Signer> = Box::new(NullSigner::new(&Pubkey::new(&[3u8; 32])));
let bad: Box<dyn Signer> = Box::new(BadSigner::new(Pubkey::new(&[4u8; 32])));
let to = Pubkey::new(&[5u8; 32]);
let nonce = Pubkey::new(&[6u8; 32]);
let from = present.pubkey();
let fee_payer = absent.pubkey();
let nonce_auth = bad.pubkey();
let mut tx = Transaction::new_unsigned(Message::new_with_nonce(
vec![system_instruction::transfer(&from, &to, 42)],
Some(&fee_payer),
&nonce,
&nonce_auth,
));
let signers = vec![present.as_ref(), absent.as_ref(), bad.as_ref()];
let blockhash = Hash::new(&[7u8; 32]);
tx.try_partial_sign(&signers, blockhash).unwrap();
let res = return_signers(&tx, &config).unwrap();
let sign_only = parse_sign_only_reply_string(&res);
assert_eq!(sign_only.blockhash, blockhash);
assert_eq!(sign_only.present_signers[0].0, present.pubkey());
assert_eq!(sign_only.absent_signers[0], absent.pubkey());
assert_eq!(sign_only.bad_signers[0], bad.pubkey());
}
}

View File

@ -1,15 +1,17 @@
use crate::{
cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
cli_output::*,
display::{
format_labeled_address, new_spinner_progress_bar, println_name_value, println_transaction,
},
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
};
use clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
use console::{style, Emoji};
use solana_clap_utils::{
commitment::commitment_arg, input_parsers::*, input_validators::*, keypair::signer_from_path,
commitment::commitment_arg, input_parsers::*, input_validators::*, keypair::DefaultSigner,
};
use solana_cli_output::{
display::{
format_labeled_address, new_spinner_progress_bar, println_name_value, println_transaction,
},
*,
};
use solana_client::{
pubsub_client::PubsubClient,
@ -332,7 +334,7 @@ pub fn parse_catchup(
pub fn parse_cluster_ping(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let lamports = value_t_or_exit!(matches, "lamports", u64);
@ -350,12 +352,7 @@ pub fn parse_cluster_ping(
count,
timeout,
},
signers: vec![signer_from_path(
matches,
default_signer_path,
"keypair",
wallet_manager,
)?],
signers: vec![default_signer.signer_from_path(matches, wallet_manager)?],
})
}
@ -1480,12 +1477,16 @@ mod tests {
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 default_signer = DefaultSigner {
path: default_keypair_file,
arg_name: String::new(),
};
let test_cluster_version = test_commands
.clone()
.get_matches_from(vec!["test", "cluster-date"]);
assert_eq!(
parse_command(&test_cluster_version, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_cluster_version, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::ClusterDate,
signers: vec![],
@ -1496,7 +1497,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "cluster-version"]);
assert_eq!(
parse_command(&test_cluster_version, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_cluster_version, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::ClusterVersion,
signers: vec![],
@ -1505,7 +1506,7 @@ mod tests {
let test_fees = test_commands.clone().get_matches_from(vec!["test", "fees"]);
assert_eq!(
parse_command(&test_fees, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_fees, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Fees,
signers: vec![],
@ -1518,7 +1519,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "block-time", &slot.to_string()]);
assert_eq!(
parse_command(&test_get_block_time, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_get_block_time, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::GetBlockTime { slot: Some(slot) },
signers: vec![],
@ -1529,7 +1530,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "epoch"]);
assert_eq!(
parse_command(&test_get_epoch, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_get_epoch, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::GetEpoch,
signers: vec![],
@ -1540,7 +1541,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "epoch-info"]);
assert_eq!(
parse_command(&test_get_epoch_info, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_get_epoch_info, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::GetEpochInfo,
signers: vec![],
@ -1551,7 +1552,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "genesis-hash"]);
assert_eq!(
parse_command(&test_get_genesis_hash, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_get_genesis_hash, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::GetGenesisHash,
signers: vec![],
@ -1560,7 +1561,7 @@ mod tests {
let test_get_slot = test_commands.clone().get_matches_from(vec!["test", "slot"]);
assert_eq!(
parse_command(&test_get_slot, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_get_slot, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::GetSlot,
signers: vec![],
@ -1571,7 +1572,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "total-supply"]);
assert_eq!(
parse_command(&test_total_supply, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_total_supply, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::TotalSupply,
signers: vec![],
@ -1582,7 +1583,7 @@ mod tests {
.clone()
.get_matches_from(vec!["test", "transaction-count"]);
assert_eq!(
parse_command(&test_transaction_count, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_transaction_count, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::GetTransactionCount,
signers: vec![],
@ -1602,7 +1603,7 @@ mod tests {
"max",
]);
assert_eq!(
parse_command(&test_ping, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_ping, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::Ping {
lamports: 1,

View File

@ -18,16 +18,12 @@ macro_rules! pubkey {
};
}
#[macro_use]
extern crate serde_derive;
pub mod checks;
pub mod cli;
pub mod cli_output;
pub mod cluster_query;
pub mod display;
pub mod nonce;
pub mod offline;
pub mod spend_utils;
pub mod stake;
pub mod test_utils;

View File

@ -5,22 +5,37 @@ use clap::{
use console::style;
use solana_clap_utils::{
commitment::COMMITMENT_ARG, input_parsers::commitment_of, input_validators::is_url,
keypair::SKIP_SEED_PHRASE_VALIDATION_ARG, DisplayError,
commitment::COMMITMENT_ARG,
input_parsers::commitment_of,
input_validators::is_url,
keypair::{CliSigners, DefaultSigner, SKIP_SEED_PHRASE_VALIDATION_ARG},
DisplayError,
};
use solana_cli::{
cli::{
app, parse_command, process_command, CliCommandInfo, CliConfig, CliSigners,
DEFAULT_RPC_TIMEOUT_SECONDS,
},
cli_output::OutputFormat,
display::{println_name_value, println_name_value_or},
use solana_cli::cli::{
app, parse_command, process_command, CliCommandInfo, CliConfig, SettingType,
DEFAULT_RPC_TIMEOUT_SECONDS,
};
use solana_cli_config::{Config, CONFIG_FILE};
use solana_cli_output::{display::println_name_value, OutputFormat};
use solana_client::rpc_config::RpcSendTransactionConfig;
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use std::{collections::HashMap, error, path::PathBuf, sync::Arc, time::Duration};
pub fn println_name_value_or(name: &str, value: &str, setting_type: SettingType) {
let description = match setting_type {
SettingType::Explicit => "",
SettingType::Computed => "(computed)",
SettingType::SystemDefault => "(default)",
};
println!(
"{} {} {}",
style(name).bold(),
style(value),
style(description).italic(),
);
}
fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error>> {
let parse_args = match matches.subcommand() {
("config", Some(matches)) => {
@ -139,13 +154,19 @@ pub fn parse_args<'a>(
matches.value_of("json_rpc_url").unwrap_or(""),
&config.json_rpc_url,
);
let default_signer_arg_name = "keypair".to_string();
let (_, default_signer_path) = CliConfig::compute_keypair_path_setting(
matches.value_of("keypair").unwrap_or(""),
matches.value_of(&default_signer_arg_name).unwrap_or(""),
&config.keypair_path,
);
let default_signer = DefaultSigner {
arg_name: default_signer_arg_name,
path: default_signer_path.clone(),
};
let CliCommandInfo { command, signers } =
parse_command(&matches, &default_signer_path, &mut wallet_manager)?;
parse_command(&matches, &default_signer, &mut wallet_manager)?;
let output_format = matches
.value_of("output_format")

View File

@ -1,29 +1,26 @@
use crate::{
checks::{check_account_for_fee_with_commitment, check_unique_pubkeys},
cli::{
generate_unique_signers, log_instruction_custom_error, CliCommand, CliCommandInfo,
CliConfig, CliError, ProcessResult, SignerIndex,
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
ProcessResult,
},
cli_output::CliNonceAccount,
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
};
use clap::{App, Arg, ArgMatches, SubCommand};
use solana_clap_utils::{
input_parsers::*, input_validators::*, offline::BLOCKHASH_ARG, ArgConstant,
input_parsers::*,
input_validators::*,
keypair::{DefaultSigner, SignerIndex},
nonce::*,
};
use solana_client::rpc_client::RpcClient;
use solana_cli_output::CliNonceAccount;
use solana_client::{nonce_utils::*, rpc_client::RpcClient};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
account::Account,
account_utils::StateMut,
commitment_config::CommitmentConfig,
hash::Hash,
message::Message,
nonce::{
self,
state::{Data, Versions},
State,
},
nonce::{self, State},
pubkey::Pubkey,
system_instruction::{
advance_nonce_account, authorize_nonce_account, create_nonce_account,
@ -33,64 +30,11 @@ use solana_sdk::{
transaction::Transaction,
};
use std::sync::Arc;
use thiserror::Error;
#[derive(Debug, Error, PartialEq)]
pub enum CliNonceError {
#[error("invalid account owner")]
InvalidAccountOwner,
#[error("invalid account data")]
InvalidAccountData,
#[error("unexpected account data size")]
UnexpectedDataSize,
#[error("query hash does not match stored hash")]
InvalidHash,
#[error("query authority does not match account authority")]
InvalidAuthority,
#[error("invalid state for requested operation")]
InvalidStateForOperation,
#[error("client error: {0}")]
Client(String),
}
pub const NONCE_ARG: ArgConstant<'static> = ArgConstant {
name: "nonce",
long: "nonce",
help: "Provide the nonce account to use when creating a nonced \n\
transaction. Nonced transactions are useful when a transaction \n\
requires a lengthy signing process. Learn more about nonced \n\
transactions at https://docs.solana.com/offline-signing/durable-nonce",
};
pub const NONCE_AUTHORITY_ARG: ArgConstant<'static> = ArgConstant {
name: "nonce_authority",
long: "nonce-authority",
help: "Provide the nonce authority keypair to use when signing a nonced transaction",
};
pub trait NonceSubCommands {
fn nonce_subcommands(self) -> Self;
}
pub fn nonce_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(NONCE_ARG.name)
.long(NONCE_ARG.long)
.takes_value(true)
.value_name("PUBKEY")
.requires(BLOCKHASH_ARG.name)
.validator(is_valid_pubkey)
.help(NONCE_ARG.help)
}
pub fn nonce_authority_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(NONCE_AUTHORITY_ARG.name)
.long(NONCE_AUTHORITY_ARG.long)
.takes_value(true)
.value_name("KEYPAIR")
.validator(is_valid_signer)
.help(NONCE_AUTHORITY_ARG.help)
}
impl NonceSubCommands for App<'_, '_> {
fn nonce_subcommands(self) -> Self {
self.subcommand(
@ -220,64 +164,9 @@ impl NonceSubCommands for App<'_, '_> {
}
}
pub fn get_account(
rpc_client: &RpcClient,
nonce_pubkey: &Pubkey,
) -> Result<Account, CliNonceError> {
get_account_with_commitment(rpc_client, nonce_pubkey, CommitmentConfig::default())
}
pub fn get_account_with_commitment(
rpc_client: &RpcClient,
nonce_pubkey: &Pubkey,
commitment: CommitmentConfig,
) -> Result<Account, CliNonceError> {
rpc_client
.get_account_with_commitment(nonce_pubkey, commitment)
.map_err(|e| CliNonceError::Client(format!("{}", e)))
.and_then(|result| {
result.value.ok_or_else(|| {
CliNonceError::Client(format!("AccountNotFound: pubkey={}", nonce_pubkey))
})
})
.and_then(|a| match account_identity_ok(&a) {
Ok(()) => Ok(a),
Err(e) => Err(e),
})
}
pub fn account_identity_ok(account: &Account) -> Result<(), CliNonceError> {
if account.owner != system_program::id() {
Err(CliNonceError::InvalidAccountOwner)
} else if account.data.is_empty() {
Err(CliNonceError::UnexpectedDataSize)
} else {
Ok(())
}
}
pub fn state_from_account(account: &Account) -> Result<State, CliNonceError> {
account_identity_ok(account)?;
StateMut::<Versions>::state(account)
.map_err(|_| CliNonceError::InvalidAccountData)
.map(|v| v.convert_to_current())
}
pub fn data_from_account(account: &Account) -> Result<Data, CliNonceError> {
account_identity_ok(account)?;
state_from_account(account).and_then(|ref s| data_from_state(s).map(|d| d.clone()))
}
pub fn data_from_state(state: &State) -> Result<&Data, CliNonceError> {
match state {
State::Uninitialized => Err(CliNonceError::InvalidStateForOperation),
State::Initialized(data) => Ok(data),
}
}
pub fn parse_authorize_nonce_account(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let nonce_account = pubkey_of_signer(matches, "nonce_account_pubkey", wallet_manager)?.unwrap();
@ -286,10 +175,9 @@ pub fn parse_authorize_nonce_account(
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
let payer_provided = None;
let signer_info = generate_unique_signers(
let signer_info = default_signer.generate_unique_signers(
vec![payer_provided, nonce_authority],
matches,
default_signer_path,
wallet_manager,
)?;
@ -305,7 +193,7 @@ pub fn parse_authorize_nonce_account(
pub fn parse_nonce_create_account(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let (nonce_account, nonce_account_pubkey) =
@ -315,10 +203,9 @@ pub fn parse_nonce_create_account(
let nonce_authority = pubkey_of_signer(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
let payer_provided = None;
let signer_info = generate_unique_signers(
let signer_info = default_signer.generate_unique_signers(
vec![payer_provided, nonce_account],
matches,
default_signer_path,
wallet_manager,
)?;
@ -348,7 +235,7 @@ pub fn parse_get_nonce(
pub fn parse_new_nonce(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let nonce_account = pubkey_of_signer(matches, "nonce_account_pubkey", wallet_manager)?.unwrap();
@ -356,10 +243,9 @@ pub fn parse_new_nonce(
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
let payer_provided = None;
let signer_info = generate_unique_signers(
let signer_info = default_signer.generate_unique_signers(
vec![payer_provided, nonce_authority],
matches,
default_signer_path,
wallet_manager,
)?;
@ -391,7 +277,7 @@ pub fn parse_show_nonce_account(
pub fn parse_withdraw_from_nonce_account(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let nonce_account = pubkey_of_signer(matches, "nonce_account_pubkey", wallet_manager)?.unwrap();
@ -402,10 +288,9 @@ pub fn parse_withdraw_from_nonce_account(
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
let payer_provided = None;
let signer_info = generate_unique_signers(
let signer_info = default_signer.generate_unique_signers(
vec![payer_provided, nonce_authority],
matches,
default_signer_path,
wallet_manager,
)?;
@ -429,14 +314,14 @@ pub fn check_nonce_account(
match state_from_account(nonce_account)? {
State::Initialized(ref data) => {
if &data.blockhash != nonce_hash {
Err(CliNonceError::InvalidHash.into())
Err(Error::InvalidHash.into())
} else if nonce_authority != &data.authority {
Err(CliNonceError::InvalidAuthority.into())
Err(Error::InvalidAuthority.into())
} else {
Ok(())
}
}
State::Uninitialized => Err(CliNonceError::InvalidStateForOperation.into()),
State::Uninitialized => Err(Error::InvalidStateForOperation.into()),
}
}
@ -691,9 +576,10 @@ mod tests {
use crate::cli::{app, parse_command};
use solana_sdk::{
account::Account,
account_utils::StateMut,
fee_calculator::FeeCalculator,
hash::hash,
nonce::{self, State},
nonce::{self, state::Versions, State},
signature::{read_keypair_file, write_keypair, Keypair, Signer},
system_program,
};
@ -710,6 +596,10 @@ mod tests {
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 default_signer = DefaultSigner {
path: default_keypair_file.clone(),
arg_name: String::new(),
};
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();
@ -728,12 +618,7 @@ mod tests {
&Pubkey::default().to_string(),
]);
assert_eq!(
parse_command(
&test_authorize_nonce_account,
&default_keypair_file,
&mut None
)
.unwrap(),
parse_command(&test_authorize_nonce_account, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::AuthorizeNonceAccount {
nonce_account: nonce_account_pubkey,
@ -754,12 +639,7 @@ mod tests {
&authority_keypair_file,
]);
assert_eq!(
parse_command(
&test_authorize_nonce_account,
&default_keypair_file,
&mut None
)
.unwrap(),
parse_command(&test_authorize_nonce_account, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::AuthorizeNonceAccount {
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
@ -781,7 +661,7 @@ mod tests {
"50",
]);
assert_eq!(
parse_command(&test_create_nonce_account, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_create_nonce_account, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateNonceAccount {
nonce_account: 1,
@ -806,7 +686,7 @@ mod tests {
&authority_keypair_file,
]);
assert_eq!(
parse_command(&test_create_nonce_account, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_create_nonce_account, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateNonceAccount {
nonce_account: 1,
@ -828,7 +708,7 @@ mod tests {
&nonce_account_string,
]);
assert_eq!(
parse_command(&test_get_nonce, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_get_nonce, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::GetNonce(nonce_account_keypair.pubkey()),
signers: vec![],
@ -842,7 +722,7 @@ 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, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_new_nonce, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::NewNonce {
nonce_account: nonce_account.pubkey(),
@ -862,7 +742,7 @@ mod tests {
]);
let nonce_account = read_keypair_file(&keypair_file).unwrap();
assert_eq!(
parse_command(&test_new_nonce, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_new_nonce, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::NewNonce {
nonce_account: nonce_account.pubkey(),
@ -882,7 +762,7 @@ mod tests {
&nonce_account_string,
]);
assert_eq!(
parse_command(&test_show_nonce_account, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_show_nonce_account, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::ShowNonceAccount {
nonce_account_pubkey: nonce_account_keypair.pubkey(),
@ -903,7 +783,7 @@ mod tests {
assert_eq!(
parse_command(
&test_withdraw_from_nonce_account,
&default_keypair_file,
&default_signer,
&mut None
)
.unwrap(),
@ -931,7 +811,7 @@ mod tests {
assert_eq!(
parse_command(
&test_withdraw_from_nonce_account,
&default_keypair_file,
&default_signer,
&mut None
)
.unwrap(),
@ -966,14 +846,14 @@ mod tests {
if let CliError::InvalidNonce(err) =
check_nonce_account(&invalid_owner.unwrap(), &nonce_pubkey, &blockhash).unwrap_err()
{
assert_eq!(err, CliNonceError::InvalidAccountOwner,);
assert_eq!(err, Error::InvalidAccountOwner,);
}
let invalid_data = Account::new_data(1, &"invalid", &system_program::ID);
if let CliError::InvalidNonce(err) =
check_nonce_account(&invalid_data.unwrap(), &nonce_pubkey, &blockhash).unwrap_err()
{
assert_eq!(err, CliNonceError::InvalidAccountData,);
assert_eq!(err, Error::InvalidAccountData,);
}
let data = Versions::new_current(State::Initialized(nonce::state::Data {
@ -985,7 +865,7 @@ mod tests {
if let CliError::InvalidNonce(err) =
check_nonce_account(&invalid_hash.unwrap(), &nonce_pubkey, &blockhash).unwrap_err()
{
assert_eq!(err, CliNonceError::InvalidHash,);
assert_eq!(err, Error::InvalidHash,);
}
let data = Versions::new_current(State::Initialized(nonce::state::Data {
@ -997,7 +877,7 @@ mod tests {
if let CliError::InvalidNonce(err) =
check_nonce_account(&invalid_authority.unwrap(), &nonce_pubkey, &blockhash).unwrap_err()
{
assert_eq!(err, CliNonceError::InvalidAuthority,);
assert_eq!(err, Error::InvalidAuthority,);
}
let data = Versions::new_current(State::Uninitialized);
@ -1005,7 +885,7 @@ mod tests {
if let CliError::InvalidNonce(err) =
check_nonce_account(&invalid_state.unwrap(), &nonce_pubkey, &blockhash).unwrap_err()
{
assert_eq!(err, CliNonceError::InvalidStateForOperation,);
assert_eq!(err, Error::InvalidStateForOperation,);
}
}
@ -1017,14 +897,14 @@ mod tests {
let system_account = Account::new(1, 0, &system_program::id());
assert_eq!(
account_identity_ok(&system_account),
Err(CliNonceError::UnexpectedDataSize),
Err(Error::UnexpectedDataSize),
);
let other_program = Pubkey::new(&[1u8; 32]);
let other_account_no_data = Account::new(1, 0, &other_program);
assert_eq!(
account_identity_ok(&other_account_no_data),
Err(CliNonceError::InvalidAccountOwner),
Err(Error::InvalidAccountOwner),
);
}
@ -1049,7 +929,7 @@ mod tests {
let wrong_data_size_account = Account::new(1, 1, &system_program::id());
assert_eq!(
state_from_account(&wrong_data_size_account),
Err(CliNonceError::InvalidAccountData),
Err(Error::InvalidAccountData),
);
}
@ -1059,11 +939,11 @@ mod tests {
let state = state_from_account(&nonce_account).unwrap();
assert_eq!(
data_from_state(&state),
Err(CliNonceError::InvalidStateForOperation)
Err(Error::InvalidStateForOperation)
);
assert_eq!(
data_from_account(&nonce_account),
Err(CliNonceError::InvalidStateForOperation)
Err(Error::InvalidStateForOperation)
);
let data = nonce::state::Data {

View File

@ -1,129 +0,0 @@
pub mod blockhash_query;
use crate::nonce;
use clap::{App, Arg, ArgMatches};
use serde_json::Value;
use solana_clap_utils::{
input_parsers::{pubkey_of, value_of},
input_validators::{is_hash, is_pubkey_sig},
keypair::presigner_from_pubkey_sigs,
offline::{BLOCKHASH_ARG, SIGNER_ARG, SIGN_ONLY_ARG},
};
use solana_client::rpc_client::RpcClient;
use solana_sdk::{
fee_calculator::FeeCalculator,
hash::Hash,
pubkey::Pubkey,
signature::{Presigner, Signature},
};
use std::str::FromStr;
fn blockhash_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(BLOCKHASH_ARG.name)
.long(BLOCKHASH_ARG.long)
.takes_value(true)
.value_name("BLOCKHASH")
.validator(is_hash)
.help(BLOCKHASH_ARG.help)
}
fn sign_only_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(SIGN_ONLY_ARG.name)
.long(SIGN_ONLY_ARG.long)
.takes_value(false)
.requires(BLOCKHASH_ARG.name)
.help(SIGN_ONLY_ARG.help)
}
fn signer_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(SIGNER_ARG.name)
.long(SIGNER_ARG.long)
.takes_value(true)
.value_name("PUBKEY=SIGNATURE")
.validator(is_pubkey_sig)
.requires(BLOCKHASH_ARG.name)
.multiple(true)
.help(SIGNER_ARG.help)
}
pub trait OfflineArgs {
fn offline_args(self) -> Self;
}
impl OfflineArgs for App<'_, '_> {
fn offline_args(self) -> Self {
self.arg(blockhash_arg())
.arg(sign_only_arg())
.arg(signer_arg())
}
}
pub struct SignOnly {
pub blockhash: Hash,
pub present_signers: Vec<(Pubkey, Signature)>,
pub absent_signers: Vec<Pubkey>,
pub bad_signers: Vec<Pubkey>,
}
impl SignOnly {
pub fn has_all_signers(&self) -> bool {
self.absent_signers.is_empty() && self.bad_signers.is_empty()
}
pub fn presigner_of(&self, pubkey: &Pubkey) -> Option<Presigner> {
presigner_from_pubkey_sigs(pubkey, &self.present_signers)
}
}
pub fn parse_sign_only_reply_string(reply: &str) -> SignOnly {
let object: Value = serde_json::from_str(&reply).unwrap();
let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap();
let blockhash = blockhash_str.parse::<Hash>().unwrap();
let mut present_signers: Vec<(Pubkey, Signature)> = Vec::new();
let signer_strings = object.get("signers");
if let Some(sig_strings) = signer_strings {
present_signers = sig_strings
.as_array()
.unwrap()
.iter()
.map(|signer_string| {
let mut signer = signer_string.as_str().unwrap().split('=');
let key = Pubkey::from_str(signer.next().unwrap()).unwrap();
let sig = Signature::from_str(signer.next().unwrap()).unwrap();
(key, sig)
})
.collect();
}
let mut absent_signers: Vec<Pubkey> = Vec::new();
let signer_strings = object.get("absent");
if let Some(sig_strings) = signer_strings {
absent_signers = sig_strings
.as_array()
.unwrap()
.iter()
.map(|val| {
let s = val.as_str().unwrap();
Pubkey::from_str(s).unwrap()
})
.collect();
}
let mut bad_signers: Vec<Pubkey> = Vec::new();
let signer_strings = object.get("badSig");
if let Some(sig_strings) = signer_strings {
bad_signers = sig_strings
.as_array()
.unwrap()
.iter()
.map(|val| {
let s = val.as_str().unwrap();
Pubkey::from_str(s).unwrap()
})
.collect();
}
SignOnly {
blockhash,
present_signers,
absent_signers,
bad_signers,
}
}

View File

@ -1,18 +1,29 @@
use crate::{
checks::{check_account_for_fee_with_commitment, check_unique_pubkeys},
cli::{
fee_payer_arg, generate_unique_signers, log_instruction_custom_error, nonce_authority_arg,
return_signers, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult,
SignerIndex, FEE_PAYER_ARG,
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
ProcessResult,
},
cli_output::{CliStakeHistory, CliStakeHistoryEntry, CliStakeState, CliStakeType},
nonce::{self, check_nonce_account, nonce_arg, NONCE_ARG, NONCE_AUTHORITY_ARG},
offline::{blockhash_query::BlockhashQuery, *},
nonce::check_nonce_account,
spend_utils::{resolve_spend_tx_and_check_account_balances, SpendAmount},
};
use clap::{App, Arg, ArgGroup, ArgMatches, SubCommand};
use solana_clap_utils::{input_parsers::*, input_validators::*, offline::*, ArgConstant};
use solana_client::{rpc_client::RpcClient, rpc_request::DELINQUENT_VALIDATOR_SLOT_DISTANCE};
use solana_clap_utils::{
fee_payer::{fee_payer_arg, FEE_PAYER_ARG},
input_parsers::*,
input_validators::*,
keypair::{DefaultSigner, SignerIndex},
nonce::*,
offline::*,
ArgConstant,
};
use solana_cli_output::{
return_signers, CliStakeHistory, CliStakeHistoryEntry, CliStakeState, CliStakeType,
};
use solana_client::{
blockhash_query::BlockhashQuery, nonce_utils, rpc_client::RpcClient,
rpc_request::DELINQUENT_VALIDATOR_SLOT_DISTANCE,
};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
account_utils::StateMut,
@ -144,8 +155,7 @@ impl StakeSubCommands for App<'_, '_> {
.help("Source account of funds [default: cli config keypair]"),
)
.offline_args()
.arg(nonce_arg())
.arg(nonce_authority_arg())
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@ -174,8 +184,7 @@ impl StakeSubCommands for App<'_, '_> {
)
.arg(stake_authority_arg())
.offline_args()
.arg(nonce_arg())
.arg(nonce_authority_arg())
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@ -205,8 +214,7 @@ impl StakeSubCommands for App<'_, '_> {
.arg(stake_authority_arg())
.arg(withdraw_authority_arg())
.offline_args()
.arg(nonce_arg())
.arg(nonce_authority_arg())
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@ -221,8 +229,7 @@ impl StakeSubCommands for App<'_, '_> {
)
.arg(stake_authority_arg())
.offline_args()
.arg(nonce_arg())
.arg(nonce_authority_arg())
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@ -262,8 +269,7 @@ impl StakeSubCommands for App<'_, '_> {
)
.arg(stake_authority_arg())
.offline_args()
.arg(nonce_arg())
.arg(nonce_authority_arg())
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@ -285,8 +291,7 @@ impl StakeSubCommands for App<'_, '_> {
)
.arg(stake_authority_arg())
.offline_args()
.arg(nonce_arg())
.arg(nonce_authority_arg())
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@ -317,8 +322,7 @@ impl StakeSubCommands for App<'_, '_> {
)
.arg(withdraw_authority_arg())
.offline_args()
.arg(nonce_arg())
.arg(nonce_authority_arg())
.nonce_args()
.arg(fee_payer_arg())
.arg(
Arg::with_name("custodian")
@ -373,8 +377,7 @@ impl StakeSubCommands for App<'_, '_> {
.help("Keypair of the existing custodian [default: cli config pubkey]")
)
.offline_args()
.arg(nonce_arg())
.arg(nonce_authority_arg())
.nonce_args()
.arg(fee_payer_arg())
)
.subcommand(
@ -411,7 +414,7 @@ impl StakeSubCommands for App<'_, '_> {
pub fn parse_stake_create_account(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let seed = matches.value_of("seed").map(|s| s.to_string());
@ -436,7 +439,7 @@ pub fn parse_stake_create_account(
bulk_signers.push(nonce_authority);
}
let signer_info =
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
Ok(CliCommandInfo {
command: CliCommand::CreateStakeAccount {
@ -463,7 +466,7 @@ pub fn parse_stake_create_account(
pub fn parse_stake_delegate_stake(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let stake_account_pubkey =
@ -485,7 +488,7 @@ pub fn parse_stake_delegate_stake(
bulk_signers.push(nonce_authority);
}
let signer_info =
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
Ok(CliCommandInfo {
command: CliCommand::DelegateStake {
@ -505,7 +508,7 @@ pub fn parse_stake_delegate_stake(
pub fn parse_stake_authorize(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let stake_account_pubkey =
@ -557,7 +560,7 @@ pub fn parse_stake_authorize(
bulk_signers.push(nonce_authority);
}
let signer_info =
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
let new_authorizations = new_authorizations
.into_iter()
@ -588,7 +591,7 @@ pub fn parse_stake_authorize(
pub fn parse_split_stake(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let stake_account_pubkey =
@ -612,7 +615,7 @@ pub fn parse_split_stake(
bulk_signers.push(nonce_authority);
}
let signer_info =
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
Ok(CliCommandInfo {
command: CliCommand::SplitStake {
@ -633,7 +636,7 @@ pub fn parse_split_stake(
pub fn parse_merge_stake(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let stake_account_pubkey =
@ -655,7 +658,7 @@ pub fn parse_merge_stake(
bulk_signers.push(nonce_authority);
}
let signer_info =
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
Ok(CliCommandInfo {
command: CliCommand::MergeStake {
@ -674,7 +677,7 @@ pub fn parse_merge_stake(
pub fn parse_stake_deactivate_stake(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let stake_account_pubkey =
@ -693,7 +696,7 @@ pub fn parse_stake_deactivate_stake(
bulk_signers.push(nonce_authority);
}
let signer_info =
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
Ok(CliCommandInfo {
command: CliCommand::DeactivateStake {
@ -711,7 +714,7 @@ pub fn parse_stake_deactivate_stake(
pub fn parse_stake_withdraw_stake(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let stake_account_pubkey =
@ -737,7 +740,7 @@ pub fn parse_stake_withdraw_stake(
bulk_signers.push(custodian);
}
let signer_info =
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
Ok(CliCommandInfo {
command: CliCommand::WithdrawStake {
@ -758,7 +761,7 @@ pub fn parse_stake_withdraw_stake(
pub fn parse_stake_set_lockup(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let stake_account_pubkey =
@ -781,7 +784,7 @@ pub fn parse_stake_set_lockup(
bulk_signers.push(nonce_authority);
}
let signer_info =
generate_unique_signers(bulk_signers, matches, default_signer_path, wallet_manager)?;
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
Ok(CliCommandInfo {
command: CliCommand::StakeSetLockup {
@ -934,8 +937,11 @@ pub fn process_create_stake_account(
}
if let Some(nonce_account) = &nonce_account {
let nonce_account =
nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?;
let nonce_account = nonce_utils::get_account_with_commitment(
rpc_client,
nonce_account,
config.commitment,
)?;
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
}
}
@ -943,7 +949,7 @@ pub fn process_create_stake_account(
let mut tx = Transaction::new_unsigned(message);
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers(&tx, &config)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
let result = rpc_client.send_and_confirm_transaction_with_spinner_and_config(
@ -1002,12 +1008,15 @@ pub fn process_stake_authorize(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers(&tx, &config)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
let nonce_account =
nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?;
let nonce_account = nonce_utils::get_account_with_commitment(
rpc_client,
nonce_account,
config.commitment,
)?;
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
}
check_account_for_fee_with_commitment(
@ -1062,12 +1071,15 @@ pub fn process_deactivate_stake_account(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers(&tx, &config)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
let nonce_account =
nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?;
let nonce_account = nonce_utils::get_account_with_commitment(
rpc_client,
nonce_account,
config.commitment,
)?;
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
}
check_account_for_fee_with_commitment(
@ -1131,12 +1143,15 @@ pub fn process_withdraw_stake(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers(&tx, &config)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
let nonce_account =
nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?;
let nonce_account = nonce_utils::get_account_with_commitment(
rpc_client,
nonce_account,
config.commitment,
)?;
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
}
check_account_for_fee_with_commitment(
@ -1271,12 +1286,15 @@ pub fn process_split_stake(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers(&tx, &config)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
let nonce_account =
nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?;
let nonce_account = nonce_utils::get_account_with_commitment(
rpc_client,
nonce_account,
config.commitment,
)?;
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
}
check_account_for_fee_with_commitment(
@ -1370,12 +1388,15 @@ pub fn process_merge_stake(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers(&tx, &config)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
let nonce_account =
nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?;
let nonce_account = nonce_utils::get_account_with_commitment(
rpc_client,
nonce_account,
config.commitment,
)?;
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
}
check_account_for_fee_with_commitment(
@ -1433,12 +1454,15 @@ pub fn process_stake_set_lockup(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers(&tx, &config)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
let nonce_account =
nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?;
let nonce_account = nonce_utils::get_account_with_commitment(
rpc_client,
nonce_account,
config.commitment,
)?;
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
}
check_account_for_fee_with_commitment(
@ -1718,12 +1742,15 @@ pub fn process_delegate_stake(
if sign_only {
tx.try_partial_sign(&config.signers, recent_blockhash)?;
return_signers(&tx, &config)
return_signers(&tx, &config.output_format)
} else {
tx.try_sign(&config.signers, recent_blockhash)?;
if let Some(nonce_account) = &nonce_account {
let nonce_account =
nonce::get_account_with_commitment(rpc_client, nonce_account, config.commitment)?;
let nonce_account = nonce_utils::get_account_with_commitment(
rpc_client,
nonce_account,
config.commitment,
)?;
check_nonce_account(&nonce_account, &nonce_authority.pubkey(), &recent_blockhash)?;
}
check_account_for_fee_with_commitment(
@ -1746,6 +1773,7 @@ pub fn process_delegate_stake(
mod tests {
use super::*;
use crate::cli::{app, parse_command};
use solana_client::blockhash_query;
use solana_sdk::{
hash::Hash,
signature::{
@ -1766,6 +1794,10 @@ mod tests {
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 default_signer = DefaultSigner {
path: default_keypair_file.clone(),
arg_name: String::new(),
};
let (keypair_file, mut tmp_file) = make_tmp_file();
let stake_account_keypair = Keypair::new();
write_keypair(&stake_account_keypair, tmp_file.as_file_mut()).unwrap();
@ -1793,7 +1825,7 @@ mod tests {
&new_withdraw_string,
]);
assert_eq!(
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -1827,7 +1859,7 @@ mod tests {
&withdraw_authority_keypair_file,
]);
assert_eq!(
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -1865,7 +1897,7 @@ mod tests {
&withdraw_authority_keypair_file,
]);
assert_eq!(
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -1895,7 +1927,7 @@ mod tests {
&new_stake_string,
]);
assert_eq!(
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -1919,7 +1951,7 @@ mod tests {
&stake_authority_keypair_file,
]);
assert_eq!(
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -1949,7 +1981,7 @@ mod tests {
&withdraw_authority_keypair_file,
]);
assert_eq!(
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -1976,7 +2008,7 @@ mod tests {
&new_withdraw_string,
]);
assert_eq!(
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -2004,7 +2036,7 @@ mod tests {
&withdraw_authority_keypair_file,
]);
assert_eq!(
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -2042,7 +2074,7 @@ mod tests {
"--sign-only",
]);
assert_eq!(
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -2075,7 +2107,7 @@ mod tests {
&pubkey.to_string(),
]);
assert_eq!(
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -2121,7 +2153,7 @@ mod tests {
&pubkey2.to_string(),
]);
assert_eq!(
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -2153,7 +2185,7 @@ mod tests {
&blockhash_string,
]);
assert_eq!(
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -2190,7 +2222,7 @@ mod tests {
&nonce_keypair_file,
]);
assert_eq!(
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -2226,7 +2258,7 @@ mod tests {
&fee_payer_keypair_file,
]);
assert_eq!(
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -2260,7 +2292,7 @@ mod tests {
&signer,
]);
assert_eq!(
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::StakeAuthorize {
stake_account_pubkey,
@ -2301,7 +2333,7 @@ mod tests {
"43",
]);
assert_eq!(
parse_command(&test_create_stake_account, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_create_stake_account, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateStakeAccount {
stake_account: 1,
@ -2342,12 +2374,7 @@ mod tests {
]);
assert_eq!(
parse_command(
&test_create_stake_account2,
&default_keypair_file,
&mut None
)
.unwrap(),
parse_command(&test_create_stake_account2, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateStakeAccount {
stake_account: 1,
@ -2400,12 +2427,7 @@ mod tests {
]);
assert_eq!(
parse_command(
&test_create_stake_account2,
&default_keypair_file,
&mut None
)
.unwrap(),
parse_command(&test_create_stake_account2, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateStakeAccount {
stake_account: 1,
@ -2441,7 +2463,7 @@ mod tests {
&vote_account_string,
]);
assert_eq!(
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DelegateStake {
stake_account_pubkey,
@ -2470,7 +2492,7 @@ mod tests {
&stake_authority_keypair_file,
]);
assert_eq!(
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DelegateStake {
stake_account_pubkey,
@ -2501,7 +2523,7 @@ mod tests {
&vote_account_string,
]);
assert_eq!(
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DelegateStake {
stake_account_pubkey,
@ -2530,7 +2552,7 @@ mod tests {
&blockhash_string,
]);
assert_eq!(
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DelegateStake {
stake_account_pubkey,
@ -2560,7 +2582,7 @@ mod tests {
"--sign-only",
]);
assert_eq!(
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DelegateStake {
stake_account_pubkey,
@ -2594,7 +2616,7 @@ mod tests {
&key1.to_string(),
]);
assert_eq!(
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DelegateStake {
stake_account_pubkey,
@ -2640,7 +2662,7 @@ mod tests {
&key2.to_string(),
]);
assert_eq!(
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DelegateStake {
stake_account_pubkey,
@ -2677,7 +2699,7 @@ mod tests {
&fee_payer_keypair_file,
]);
assert_eq!(
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DelegateStake {
stake_account_pubkey,
@ -2707,7 +2729,7 @@ mod tests {
]);
assert_eq!(
parse_command(&test_withdraw_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_withdraw_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::WithdrawStake {
stake_account_pubkey,
@ -2737,7 +2759,7 @@ mod tests {
]);
assert_eq!(
parse_command(&test_withdraw_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_withdraw_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::WithdrawStake {
stake_account_pubkey,
@ -2772,7 +2794,7 @@ mod tests {
]);
assert_eq!(
parse_command(&test_withdraw_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_withdraw_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::WithdrawStake {
stake_account_pubkey,
@ -2815,7 +2837,7 @@ mod tests {
]);
assert_eq!(
parse_command(&test_withdraw_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_withdraw_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::WithdrawStake {
stake_account_pubkey,
@ -2848,7 +2870,7 @@ mod tests {
&stake_account_string,
]);
assert_eq!(
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DeactivateStake {
stake_account_pubkey,
@ -2872,7 +2894,7 @@ mod tests {
&stake_authority_keypair_file,
]);
assert_eq!(
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DeactivateStake {
stake_account_pubkey,
@ -2903,7 +2925,7 @@ mod tests {
&blockhash_string,
]);
assert_eq!(
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DeactivateStake {
stake_account_pubkey,
@ -2930,7 +2952,7 @@ mod tests {
"--sign-only",
]);
assert_eq!(
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DeactivateStake {
stake_account_pubkey,
@ -2961,7 +2983,7 @@ mod tests {
&key1.to_string(),
]);
assert_eq!(
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DeactivateStake {
stake_account_pubkey,
@ -3004,7 +3026,7 @@ mod tests {
&key2.to_string(),
]);
assert_eq!(
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DeactivateStake {
stake_account_pubkey,
@ -3035,7 +3057,7 @@ mod tests {
&fee_payer_keypair_file,
]);
assert_eq!(
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::DeactivateStake {
stake_account_pubkey,
@ -3069,7 +3091,7 @@ mod tests {
"50",
]);
assert_eq!(
parse_command(&test_split_stake_account, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_split_stake_account, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::SplitStake {
stake_account_pubkey: stake_account_keypair.pubkey(),
@ -3130,7 +3152,7 @@ mod tests {
&stake_signer,
]);
assert_eq!(
parse_command(&test_split_stake_account, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_split_stake_account, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::SplitStake {
stake_account_pubkey: stake_account_keypair.pubkey(),
@ -3170,7 +3192,7 @@ mod tests {
&source_stake_account_pubkey.to_string(),
]);
assert_eq!(
parse_command(&test_merge_stake_account, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_merge_stake_account, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::MergeStake {
stake_account_pubkey: stake_account_keypair.pubkey(),

View File

@ -1,6 +1,5 @@
use crate::{
cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
cli_output::{CliValidatorInfo, CliValidatorInfoVec},
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
};
use bincode::deserialize;
@ -13,8 +12,9 @@ use solana_account_decoder::validator_info::{
use solana_clap_utils::{
input_parsers::pubkey_of,
input_validators::{is_pubkey, is_url},
keypair::signer_from_path,
keypair::DefaultSigner,
};
use solana_cli_output::{CliValidatorInfo, CliValidatorInfoVec};
use solana_client::rpc_client::RpcClient;
use solana_config_program::{config_instruction, get_config_data, ConfigKeys, ConfigState};
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
@ -212,7 +212,7 @@ impl ValidatorInfoSubCommands for App<'_, '_> {
pub fn parse_validator_info_command(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let info_pubkey = pubkey_of(matches, "info_pubkey");
@ -224,12 +224,7 @@ pub fn parse_validator_info_command(
force_keybase: matches.is_present("force"),
info_pubkey,
},
signers: vec![signer_from_path(
matches,
default_signer_path,
"keypair",
wallet_manager,
)?],
signers: vec![default_signer.signer_from_path(matches, wallet_manager)?],
})
}

View File

@ -1,14 +1,19 @@
use crate::{
checks::{check_account_for_fee_with_commitment, check_unique_pubkeys},
cli::{
generate_unique_signers, log_instruction_custom_error, CliCommand, CliCommandInfo,
CliConfig, CliError, ProcessResult, SignerIndex,
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
ProcessResult,
},
cli_output::{CliEpochVotingHistory, CliLockout, CliVoteAccount},
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
};
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
use solana_clap_utils::{commitment::commitment_arg, input_parsers::*, input_validators::*};
use solana_clap_utils::{
commitment::commitment_arg,
input_parsers::*,
input_validators::*,
keypair::{DefaultSigner, SignerIndex},
};
use solana_cli_output::{CliEpochVotingHistory, CliLockout, CliVoteAccount};
use solana_client::rpc_client::RpcClient;
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_sdk::{
@ -246,7 +251,7 @@ impl VoteSubCommands for App<'_, '_> {
pub fn parse_create_vote_account(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let (vote_account, vote_account_pubkey) = signer_of(matches, "vote_account", wallet_manager)?;
@ -258,10 +263,9 @@ pub fn parse_create_vote_account(
let authorized_withdrawer = pubkey_of_signer(matches, "authorized_withdrawer", wallet_manager)?;
let payer_provided = None;
let signer_info = generate_unique_signers(
let signer_info = default_signer.generate_unique_signers(
vec![payer_provided, vote_account, identity_account],
matches,
default_signer_path,
wallet_manager,
)?;
@ -280,7 +284,7 @@ pub fn parse_create_vote_account(
pub fn parse_vote_authorize(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
vote_authorize: VoteAuthorize,
) -> Result<CliCommandInfo, CliError> {
@ -291,10 +295,9 @@ pub fn parse_vote_authorize(
let (authorized, _) = signer_of(matches, "authorized", wallet_manager)?;
let payer_provided = None;
let signer_info = generate_unique_signers(
let signer_info = default_signer.generate_unique_signers(
vec![payer_provided, authorized],
matches,
default_signer_path,
wallet_manager,
)?;
@ -310,7 +313,7 @@ pub fn parse_vote_authorize(
pub fn parse_vote_update_validator(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let vote_account_pubkey =
@ -321,10 +324,9 @@ pub fn parse_vote_update_validator(
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
let payer_provided = None;
let signer_info = generate_unique_signers(
let signer_info = default_signer.generate_unique_signers(
vec![payer_provided, authorized_withdrawer, new_identity_account],
matches,
default_signer_path,
wallet_manager,
)?;
@ -340,7 +342,7 @@ pub fn parse_vote_update_validator(
pub fn parse_vote_update_commission(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let vote_account_pubkey =
@ -350,10 +352,9 @@ pub fn parse_vote_update_commission(
let commission = value_t_or_exit!(matches, "commission", u8);
let payer_provided = None;
let signer_info = generate_unique_signers(
let signer_info = default_signer.generate_unique_signers(
vec![payer_provided, authorized_withdrawer],
matches,
default_signer_path,
wallet_manager,
)?;
@ -385,7 +386,7 @@ pub fn parse_vote_get_account_command(
pub fn parse_withdraw_from_vote_account(
matches: &ArgMatches<'_>,
default_signer_path: &str,
default_signer: &DefaultSigner,
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
) -> Result<CliCommandInfo, CliError> {
let vote_account_pubkey =
@ -398,10 +399,9 @@ pub fn parse_withdraw_from_vote_account(
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
let payer_provided = None;
let signer_info = generate_unique_signers(
let signer_info = default_signer.generate_unique_signers(
vec![payer_provided, withdraw_authority],
matches,
default_signer_path,
wallet_manager,
)?;
@ -794,6 +794,10 @@ mod tests {
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 default_signer = DefaultSigner {
path: default_keypair_file.clone(),
arg_name: String::new(),
};
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
"test",
@ -803,7 +807,7 @@ mod tests {
&pubkey2_string,
]);
assert_eq!(
parse_command(&test_authorize_voter, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::VoteAuthorize {
vote_account_pubkey: pubkey,
@ -826,7 +830,7 @@ mod tests {
&pubkey2_string,
]);
assert_eq!(
parse_command(&test_authorize_voter, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::VoteAuthorize {
vote_account_pubkey: pubkey,
@ -856,7 +860,7 @@ mod tests {
"10",
]);
assert_eq!(
parse_command(&test_create_vote_account, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_create_vote_account, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateVoteAccount {
vote_account: 1,
@ -885,7 +889,7 @@ mod tests {
&identity_keypair_file,
]);
assert_eq!(
parse_command(&test_create_vote_account2, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_create_vote_account2, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateVoteAccount {
vote_account: 1,
@ -918,7 +922,7 @@ mod tests {
&authed.to_string(),
]);
assert_eq!(
parse_command(&test_create_vote_account3, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_create_vote_account3, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateVoteAccount {
vote_account: 1,
@ -949,7 +953,7 @@ mod tests {
&authed.to_string(),
]);
assert_eq!(
parse_command(&test_create_vote_account4, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_create_vote_account4, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::CreateVoteAccount {
vote_account: 1,
@ -975,7 +979,7 @@ mod tests {
&keypair_file,
]);
assert_eq!(
parse_command(&test_update_validator, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_update_validator, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::VoteUpdateValidator {
vote_account_pubkey: pubkey,
@ -998,7 +1002,7 @@ mod tests {
&keypair_file,
]);
assert_eq!(
parse_command(&test_update_commission, &default_keypair_file, &mut None).unwrap(),
parse_command(&test_update_commission, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::VoteUpdateCommission {
vote_account_pubkey: pubkey,
@ -1021,12 +1025,7 @@ mod tests {
"42",
]);
assert_eq!(
parse_command(
&test_withdraw_from_vote_account,
&default_keypair_file,
&mut None
)
.unwrap(),
parse_command(&test_withdraw_from_vote_account, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::WithdrawFromVoteAccount {
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
@ -1047,12 +1046,7 @@ mod tests {
"ALL",
]);
assert_eq!(
parse_command(
&test_withdraw_from_vote_account,
&default_keypair_file,
&mut None
)
.unwrap(),
parse_command(&test_withdraw_from_vote_account, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::WithdrawFromVoteAccount {
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
@ -1078,12 +1072,7 @@ mod tests {
&withdraw_authority_file,
]);
assert_eq!(
parse_command(
&test_withdraw_from_vote_account,
&default_keypair_file,
&mut None
)
.unwrap(),
parse_command(&test_withdraw_from_vote_account, &default_signer, &mut None).unwrap(),
CliCommandInfo {
command: CliCommand::WithdrawFromVoteAccount {
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),

View File

@ -1,15 +1,14 @@
use solana_cli::{
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
cli_output::OutputFormat,
nonce,
offline::{
blockhash_query::{self, BlockhashQuery},
parse_sign_only_reply_string,
},
spend_utils::SpendAmount,
test_utils::{check_ready, check_recent_balance},
};
use solana_client::rpc_client::RpcClient;
use solana_cli_output::{parse_sign_only_reply_string, OutputFormat};
use solana_client::{
blockhash_query::{self, BlockhashQuery},
nonce_utils,
rpc_client::RpcClient,
};
use solana_core::contact_info::ContactInfo;
use solana_core::test_validator::{TestValidator, TestValidatorOptions};
use solana_faucet::faucet::run_local_faucet;
@ -302,11 +301,14 @@ fn test_create_account_with_seed() {
check_recent_balance(0, &rpc_client, &to_address);
// Fetch nonce hash
let nonce_hash =
nonce::get_account_with_commitment(&rpc_client, &nonce_address, CommitmentConfig::recent())
.and_then(|ref a| nonce::data_from_account(a))
.unwrap()
.blockhash;
let nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_address,
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
// Test by creating transfer TX with nonce, fully offline
let mut authority_config = CliConfig::recent_for_tests();

View File

@ -2,16 +2,15 @@ use chrono::prelude::*;
use serde_json::Value;
use solana_cli::{
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig, PayCommand},
cli_output::OutputFormat,
nonce,
offline::{
blockhash_query::{self, BlockhashQuery},
parse_sign_only_reply_string,
},
spend_utils::SpendAmount,
test_utils::check_recent_balance,
};
use solana_client::rpc_client::RpcClient;
use solana_cli_output::{parse_sign_only_reply_string, OutputFormat};
use solana_client::{
blockhash_query::{self, BlockhashQuery},
nonce_utils,
rpc_client::RpcClient,
};
use solana_core::test_validator::TestValidator;
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
@ -411,12 +410,12 @@ fn test_nonced_pay_tx() {
check_recent_balance(minimum_nonce_balance, &rpc_client, &nonce_account.pubkey());
// Fetch nonce hash
let nonce_hash = nonce::get_account_with_commitment(
let nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
@ -438,12 +437,12 @@ fn test_nonced_pay_tx() {
check_recent_balance(10, &rpc_client, &bob_pubkey);
// Verify that nonce has been used
let nonce_hash2 = nonce::get_account_with_commitment(
let nonce_hash2 = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
assert_ne!(nonce_hash, nonce_hash2);

View File

@ -1,15 +1,14 @@
use solana_cli::{
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
cli_output::OutputFormat,
nonce,
offline::{
blockhash_query::{self, BlockhashQuery},
parse_sign_only_reply_string,
},
spend_utils::SpendAmount,
test_utils::{check_ready, check_recent_balance},
};
use solana_client::rpc_client::RpcClient;
use solana_cli_output::{parse_sign_only_reply_string, OutputFormat};
use solana_client::{
blockhash_query::{self, BlockhashQuery},
nonce_utils,
rpc_client::RpcClient,
};
use solana_core::test_validator::{TestValidator, TestValidatorOptions};
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
@ -503,12 +502,12 @@ fn test_nonced_stake_delegation_and_deactivation() {
process_command(&config).unwrap();
// Fetch nonce hash
let nonce_hash = nonce::get_account_with_commitment(
let nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
@ -531,12 +530,12 @@ fn test_nonced_stake_delegation_and_deactivation() {
process_command(&config).unwrap();
// Fetch nonce hash
let nonce_hash = nonce::get_account_with_commitment(
let nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
@ -770,12 +769,12 @@ fn test_stake_authorize() {
process_command(&config).unwrap();
// Fetch nonce hash
let nonce_hash = nonce::get_account_with_commitment(
let nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
@ -824,12 +823,12 @@ fn test_stake_authorize() {
};
assert_eq!(current_authority, online_authority_pubkey);
let new_nonce_hash = nonce::get_account_with_commitment(
let new_nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
assert_ne!(nonce_hash, new_nonce_hash);
@ -1069,12 +1068,12 @@ fn test_stake_split() {
check_recent_balance(minimum_nonce_balance, &rpc_client, &nonce_account.pubkey());
// Fetch nonce hash
let nonce_hash = nonce::get_account_with_commitment(
let nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
@ -1338,12 +1337,12 @@ fn test_stake_set_lockup() {
check_recent_balance(minimum_nonce_balance, &rpc_client, &nonce_account_pubkey);
// Fetch nonce hash
let nonce_hash = nonce::get_account_with_commitment(
let nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
@ -1465,12 +1464,12 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
process_command(&config).unwrap();
// Fetch nonce hash
let nonce_hash = nonce::get_account_with_commitment(
let nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
@ -1520,12 +1519,12 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
check_recent_balance(50_000, &rpc_client, &stake_pubkey);
// Fetch nonce hash
let nonce_hash = nonce::get_account_with_commitment(
let nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
@ -1568,12 +1567,12 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
check_recent_balance(42, &rpc_client, &recipient_pubkey);
// Fetch nonce hash
let nonce_hash = nonce::get_account_with_commitment(
let nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;

View File

@ -1,15 +1,14 @@
use solana_cli::{
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
cli_output::OutputFormat,
nonce,
offline::{
blockhash_query::{self, BlockhashQuery},
parse_sign_only_reply_string,
},
spend_utils::SpendAmount,
test_utils::{check_ready, check_recent_balance},
};
use solana_client::rpc_client::RpcClient;
use solana_cli_output::{parse_sign_only_reply_string, OutputFormat};
use solana_client::{
blockhash_query::{self, BlockhashQuery},
nonce_utils,
rpc_client::RpcClient,
};
use solana_core::test_validator::{TestValidator, TestValidatorOptions};
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{
@ -153,12 +152,12 @@ fn test_transfer() {
check_recent_balance(49_987 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
// Fetch nonce hash
let nonce_hash = nonce::get_account_with_commitment(
let nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
@ -181,12 +180,12 @@ fn test_transfer() {
process_command(&config).unwrap();
check_recent_balance(49_976 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
check_recent_balance(30, &rpc_client, &recipient_pubkey);
let new_nonce_hash = nonce::get_account_with_commitment(
let new_nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;
assert_ne!(nonce_hash, new_nonce_hash);
@ -202,12 +201,12 @@ fn test_transfer() {
check_recent_balance(49_975 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
// Fetch nonce hash
let nonce_hash = nonce::get_account_with_commitment(
let nonce_hash = nonce_utils::get_account_with_commitment(
&rpc_client,
&nonce_account.pubkey(),
CommitmentConfig::recent(),
)
.and_then(|ref a| nonce::data_from_account(a))
.and_then(|ref a| nonce_utils::data_from_account(a))
.unwrap()
.blockhash;

View File

@ -1,10 +1,12 @@
use solana_cli::{
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
offline::{blockhash_query::BlockhashQuery, *},
spend_utils::SpendAmount,
test_utils::check_recent_balance,
};
use solana_client::rpc_client::RpcClient;
use solana_client::{
blockhash_query::{self, BlockhashQuery},
rpc_client::RpcClient,
};
use solana_core::test_validator::TestValidator;
use solana_faucet::faucet::run_local_faucet;
use solana_sdk::{

View File

@ -11,6 +11,7 @@ edition = "2018"
[dependencies]
bincode = "1.3.1"
bs58 = "0.3.1"
clap = "2.33.0"
indicatif = "0.15.0"
jsonrpc-core = "14.2.0"
log = "0.4.8"
@ -20,6 +21,7 @@ serde = "1.0.112"
serde_derive = "1.0.103"
serde_json = "1.0.56"
solana-account-decoder = { path = "../account-decoder", version = "1.3.13" }
solana-clap-utils = { path = "../clap-utils", version = "1.3.13" }
solana-net-utils = { path = "../net-utils", version = "1.3.13" }
solana-sdk = { path = "../sdk", version = "1.3.13" }
solana-transaction-status = { path = "../transaction-status", version = "1.3.13" }

View File

@ -1,5 +1,13 @@
use super::*;
use solana_sdk::commitment_config::CommitmentConfig;
use crate::{nonce_utils, rpc_client::RpcClient};
use clap::ArgMatches;
use solana_clap_utils::{
input_parsers::{pubkey_of, value_of},
nonce::*,
offline::*,
};
use solana_sdk::{
commitment_config::CommitmentConfig, fee_calculator::FeeCalculator, hash::Hash, pubkey::Pubkey,
};
#[derive(Debug, PartialEq)]
pub enum Source {
@ -21,8 +29,8 @@ impl Source {
Ok((res.0, res.1))
}
Self::NonceAccount(ref pubkey) => {
let data = nonce::get_account_with_commitment(rpc_client, pubkey, commitment)
.and_then(|ref a| nonce::data_from_account(a))?;
let data = nonce_utils::get_account_with_commitment(rpc_client, pubkey, commitment)
.and_then(|ref a| nonce_utils::data_from_account(a))?;
Ok((data.blockhash, data.fee_calculator))
}
}
@ -42,8 +50,8 @@ impl Source {
Ok(res)
}
Self::NonceAccount(ref pubkey) => {
let res = nonce::get_account_with_commitment(rpc_client, pubkey, commitment)?;
let res = nonce::data_from_account(&res)?;
let res = nonce_utils::get_account_with_commitment(rpc_client, pubkey, commitment)?;
let res = nonce_utils::data_from_account(&res)?;
Ok(Some(res)
.filter(|d| d.blockhash == *blockhash)
.map(|d| d.fee_calculator))
@ -75,7 +83,7 @@ impl BlockhashQuery {
pub fn new_from_matches(matches: &ArgMatches<'_>) -> Self {
let blockhash = value_of(matches, BLOCKHASH_ARG.name);
let sign_only = matches.is_present(SIGN_ONLY_ARG.name);
let nonce_account = pubkey_of(matches, nonce::NONCE_ARG.name);
let nonce_account = pubkey_of(matches, NONCE_ARG.name);
BlockhashQuery::new(blockhash, sign_only, nonce_account)
}
@ -108,17 +116,15 @@ impl Default for BlockhashQuery {
#[cfg(test)]
mod tests {
use super::*;
use crate::{nonce::nonce_arg, offline::blockhash_query::BlockhashQuery};
use clap::App;
use serde_json::{self, json, Value};
use solana_account_decoder::{UiAccount, UiAccountEncoding};
use solana_client::{
use crate::{
blockhash_query,
rpc_request::RpcRequest,
rpc_response::{Response, RpcFeeCalculator, RpcResponseContext},
};
use solana_sdk::{
account::Account, fee_calculator::FeeCalculator, hash::hash, nonce, system_program,
};
use clap::App;
use serde_json::{self, json, Value};
use solana_account_decoder::{UiAccount, UiAccountEncoding};
use solana_sdk::{account::Account, hash::hash, nonce, system_program};
use std::collections::HashMap;
#[test]
@ -171,9 +177,7 @@ mod tests {
#[test]
fn test_blockhash_query_new_from_matches_ok() {
let test_commands = App::new("blockhash_query_test")
.arg(nonce_arg())
.offline_args();
let test_commands = App::new("blockhash_query_test").nonce_args().offline_args();
let blockhash = hash(&[1u8]);
let blockhash_string = blockhash.to_string();

View File

@ -1,9 +1,11 @@
#[macro_use]
extern crate serde_derive;
pub mod blockhash_query;
pub mod client_error;
pub mod http_sender;
pub mod mock_sender;
pub mod nonce_utils;
pub mod perf_utils;
pub mod pubsub_client;
pub mod rpc_client;

82
client/src/nonce_utils.rs Normal file
View File

@ -0,0 +1,82 @@
use crate::rpc_client::RpcClient;
use solana_sdk::{
account::Account,
account_utils::StateMut,
commitment_config::CommitmentConfig,
nonce::{
state::{Data, Versions},
State,
},
pubkey::Pubkey,
system_program,
};
#[derive(Debug, thiserror::Error, PartialEq)]
pub enum Error {
#[error("invalid account owner")]
InvalidAccountOwner,
#[error("invalid account data")]
InvalidAccountData,
#[error("unexpected account data size")]
UnexpectedDataSize,
#[error("query hash does not match stored hash")]
InvalidHash,
#[error("query authority does not match account authority")]
InvalidAuthority,
#[error("invalid state for requested operation")]
InvalidStateForOperation,
#[error("client error: {0}")]
Client(String),
}
pub fn get_account(rpc_client: &RpcClient, nonce_pubkey: &Pubkey) -> Result<Account, Error> {
get_account_with_commitment(rpc_client, nonce_pubkey, CommitmentConfig::default())
}
pub fn get_account_with_commitment(
rpc_client: &RpcClient,
nonce_pubkey: &Pubkey,
commitment: CommitmentConfig,
) -> Result<Account, Error> {
rpc_client
.get_account_with_commitment(nonce_pubkey, commitment)
.map_err(|e| Error::Client(format!("{}", e)))
.and_then(|result| {
result
.value
.ok_or_else(|| Error::Client(format!("AccountNotFound: pubkey={}", nonce_pubkey)))
})
.and_then(|a| match account_identity_ok(&a) {
Ok(()) => Ok(a),
Err(e) => Err(e),
})
}
pub fn account_identity_ok(account: &Account) -> Result<(), Error> {
if account.owner != system_program::id() {
Err(Error::InvalidAccountOwner)
} else if account.data.is_empty() {
Err(Error::UnexpectedDataSize)
} else {
Ok(())
}
}
pub fn state_from_account(account: &Account) -> Result<State, Error> {
account_identity_ok(account)?;
StateMut::<Versions>::state(account)
.map_err(|_| Error::InvalidAccountData)
.map(|v| v.convert_to_current())
}
pub fn data_from_account(account: &Account) -> Result<Data, Error> {
account_identity_ok(account)?;
state_from_account(account).and_then(|ref s| data_from_state(s).map(|d| d.clone()))
}
pub fn data_from_state(state: &State) -> Result<&Data, Error> {
match state {
State::Uninitialized => Err(Error::InvalidStateForOperation),
State::Initialized(data) => Ok(data),
}
}

View File

@ -20,7 +20,7 @@ regex = "1"
serde_json = "1.0.56"
serde_yaml = "0.8.13"
solana-clap-utils = { path = "../clap-utils", version = "1.3.13" }
solana-cli = { path = "../cli", version = "1.3.13" }
solana-cli-output = { path = "../cli-output", version = "1.3.13" }
solana-ledger = { path = "../ledger", version = "1.3.13" }
solana-logger = { path = "../logger", version = "1.3.13" }
solana-measure = { path = "../measure", version = "1.3.13" }

View File

@ -4,7 +4,7 @@ use solana_clap_utils::{
input_parsers::pubkey_of,
input_validators::{is_slot, is_valid_pubkey},
};
use solana_cli::display::println_transaction;
use solana_cli_output::display::println_transaction;
use solana_ledger::{blockstore::Blockstore, blockstore_db::AccessType};
use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature};
use solana_transaction_status::UiTransactionEncoding;

View File

@ -118,7 +118,7 @@ fn output_entry(
})
.map(|transaction_status| transaction_status.into());
solana_cli::display::println_transaction(
solana_cli_output::display::println_transaction(
&transaction,
&transaction_status,
" ",

View File

@ -13,13 +13,7 @@ use std::ffi::OsString;
use std::process::exit;
fn fee_payer_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name("fee_payer")
.long("fee-payer")
.required(true)
.takes_value(true)
.value_name("KEYPAIR")
.validator(is_valid_signer)
.help("Fee payer")
solana_clap_utils::fee_payer::fee_payer_arg().required(true)
}
fn funding_keypair_arg<'a, 'b>() -> Arg<'a, 'b> {

View File

@ -15,6 +15,7 @@ serde_yaml = "0.8.13"
solana-clap-utils = { path = "../clap-utils", version = "1.3.13" }
solana-client = { path = "../client", version = "1.3.13" }
solana-cli-config = { path = "../cli-config", version = "1.3.13" }
solana-cli-output = { path = "../cli-output", version = "1.3.13" }
solana-cli = { path = "../cli", version = "1.3.13" }
solana-logger = { path = "../logger", version = "1.3.13" }
solana-metrics = { path = "../metrics", version = "1.3.13" }

View File

@ -4,7 +4,7 @@ use solana_clap_utils::{
input_parsers::{keypair_of, pubkey_of},
input_validators::{is_amount, is_keypair, is_pubkey_or_keypair, is_url, is_valid_percentage},
};
use solana_cli::display::format_labeled_address;
use solana_cli_output::display::format_labeled_address;
use solana_client::{
client_error, rpc_client::RpcClient, rpc_request::MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS,
rpc_response::RpcVoteAccountInfo,

View File

@ -14,7 +14,7 @@ log = "0.4.8"
humantime = "2.0.1"
solana-clap-utils = { path = "../clap-utils", version = "1.3.13" }
solana-cli-config = { path = "../cli-config", version = "1.3.13" }
solana-cli = { path = "../cli", version = "1.3.13" }
solana-cli-output = { path = "../cli-output", version = "1.3.13" }
solana-client = { path = "../client", version = "1.3.13" }
solana-logger = { path = "../logger", version = "1.3.13" }
solana-metrics = { path = "../metrics", version = "1.3.13" }

View File

@ -6,7 +6,7 @@ use solana_clap_utils::{
input_parsers::pubkeys_of,
input_validators::{is_pubkey_or_keypair, is_url},
};
use solana_cli::display::{format_labeled_address, write_transaction};
use solana_cli_output::display::{format_labeled_address, write_transaction};
use solana_client::{
client_error::Result as ClientResult, rpc_client::RpcClient, rpc_response::RpcVoteAccountStatus,
};