CLI: Factor out offline helpers (bp #12382)
This commit is contained in:
committed by
mergify[bot]
parent
dfabe35b27
commit
f4a2045876
28
Cargo.lock
generated
28
Cargo.lock
generated
@ -3488,6 +3488,7 @@ dependencies = [
|
|||||||
"solana-budget-program",
|
"solana-budget-program",
|
||||||
"solana-clap-utils",
|
"solana-clap-utils",
|
||||||
"solana-cli-config",
|
"solana-cli-config",
|
||||||
|
"solana-cli-output",
|
||||||
"solana-client",
|
"solana-client",
|
||||||
"solana-config-program",
|
"solana-config-program",
|
||||||
"solana-core",
|
"solana-core",
|
||||||
@ -3518,6 +3519,26 @@ dependencies = [
|
|||||||
"url 2.1.1",
|
"url 2.1.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "solana-cli-output"
|
||||||
|
version = "1.2.30"
|
||||||
|
dependencies = [
|
||||||
|
"Inflector",
|
||||||
|
"chrono",
|
||||||
|
"console 0.10.3",
|
||||||
|
"humantime 2.0.1",
|
||||||
|
"indicatif",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"solana-clap-utils",
|
||||||
|
"solana-client",
|
||||||
|
"solana-sdk 1.2.30",
|
||||||
|
"solana-stake-program",
|
||||||
|
"solana-transaction-status",
|
||||||
|
"solana-vote-program",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana-client"
|
name = "solana-client"
|
||||||
version = "1.2.30"
|
version = "1.2.30"
|
||||||
@ -3525,6 +3546,7 @@ dependencies = [
|
|||||||
"assert_matches",
|
"assert_matches",
|
||||||
"bincode",
|
"bincode",
|
||||||
"bs58",
|
"bs58",
|
||||||
|
"clap",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"jsonrpc-core",
|
"jsonrpc-core",
|
||||||
"jsonrpc-http-server",
|
"jsonrpc-http-server",
|
||||||
@ -3535,6 +3557,7 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"solana-account-decoder",
|
"solana-account-decoder",
|
||||||
|
"solana-clap-utils",
|
||||||
"solana-logger 1.2.30",
|
"solana-logger 1.2.30",
|
||||||
"solana-net-utils",
|
"solana-net-utils",
|
||||||
"solana-sdk 1.2.30",
|
"solana-sdk 1.2.30",
|
||||||
@ -3927,7 +3950,7 @@ dependencies = [
|
|||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"solana-clap-utils",
|
"solana-clap-utils",
|
||||||
"solana-cli",
|
"solana-cli-output",
|
||||||
"solana-ledger",
|
"solana-ledger",
|
||||||
"solana-logger 1.2.30",
|
"solana-logger 1.2.30",
|
||||||
"solana-measure",
|
"solana-measure",
|
||||||
@ -4375,6 +4398,7 @@ dependencies = [
|
|||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"solana-clap-utils",
|
"solana-clap-utils",
|
||||||
"solana-cli-config",
|
"solana-cli-config",
|
||||||
|
"solana-cli-output",
|
||||||
"solana-client",
|
"solana-client",
|
||||||
"solana-logger 1.2.30",
|
"solana-logger 1.2.30",
|
||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
@ -4604,8 +4628,8 @@ dependencies = [
|
|||||||
"humantime 2.0.1",
|
"humantime 2.0.1",
|
||||||
"log 0.4.8",
|
"log 0.4.8",
|
||||||
"solana-clap-utils",
|
"solana-clap-utils",
|
||||||
"solana-cli",
|
|
||||||
"solana-cli-config",
|
"solana-cli-config",
|
||||||
|
"solana-cli-output",
|
||||||
"solana-client",
|
"solana-client",
|
||||||
"solana-logger 1.2.30",
|
"solana-logger 1.2.30",
|
||||||
"solana-metrics",
|
"solana-metrics",
|
||||||
|
@ -6,6 +6,7 @@ members = [
|
|||||||
"accounts-bench",
|
"accounts-bench",
|
||||||
"banking-bench",
|
"banking-bench",
|
||||||
"cli-config",
|
"cli-config",
|
||||||
|
"cli-output",
|
||||||
"client",
|
"client",
|
||||||
"core",
|
"core",
|
||||||
"dos",
|
"dos",
|
||||||
|
19
clap-utils/src/fee_payer.rs
Normal file
19
clap-utils/src/fee_payer.rs
Normal 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)
|
||||||
|
}
|
@ -11,6 +11,7 @@ use solana_remote_wallet::{
|
|||||||
remote_wallet::{maybe_wallet_manager, RemoteWalletError, RemoteWalletManager},
|
remote_wallet::{maybe_wallet_manager, RemoteWalletError, RemoteWalletManager},
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
|
hash::Hash,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{
|
signature::{
|
||||||
keypair_from_seed, keypair_from_seed_phrase_and_passphrase, read_keypair,
|
keypair_from_seed, keypair_from_seed_phrase_and_passphrase, read_keypair,
|
||||||
@ -25,6 +26,81 @@ use std::{
|
|||||||
sync::Arc,
|
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 {
|
pub enum KeypairUrl {
|
||||||
Ask,
|
Ask,
|
||||||
Filepath(String),
|
Filepath(String),
|
||||||
|
@ -24,7 +24,9 @@ impl std::fmt::Debug for DisplayError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod commitment;
|
pub mod commitment;
|
||||||
|
pub mod fee_payer;
|
||||||
pub mod input_parsers;
|
pub mod input_parsers;
|
||||||
pub mod input_validators;
|
pub mod input_validators;
|
||||||
pub mod keypair;
|
pub mod keypair;
|
||||||
|
pub mod nonce;
|
||||||
pub mod offline;
|
pub mod offline;
|
||||||
|
47
clap-utils/src/nonce.rs
Normal file
47
clap-utils/src/nonce.rs
Normal 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))
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
use crate::ArgConstant;
|
use crate::{input_validators::*, ArgConstant};
|
||||||
|
use clap::{App, Arg};
|
||||||
|
|
||||||
pub const BLOCKHASH_ARG: ArgConstant<'static> = ArgConstant {
|
pub const BLOCKHASH_ARG: ArgConstant<'static> = ArgConstant {
|
||||||
name: "blockhash",
|
name: "blockhash",
|
||||||
@ -17,3 +18,43 @@ pub const SIGNER_ARG: ArgConstant<'static> = ArgConstant {
|
|||||||
long: "signer",
|
long: "signer",
|
||||||
help: "Provide a public-key/signature pair for the transaction",
|
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
28
cli-output/Cargo.toml
Normal 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.2.30"
|
||||||
|
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.10.1"
|
||||||
|
humantime = "2.0.0"
|
||||||
|
Inflector = "0.11.4"
|
||||||
|
indicatif = "0.14.0"
|
||||||
|
serde = "1.0.110"
|
||||||
|
serde_derive = "1.0.103"
|
||||||
|
serde_json = "1.0.53"
|
||||||
|
solana-clap-utils = { path = "../clap-utils", version = "1.2.30" }
|
||||||
|
solana-client = { path = "../client", version = "1.2.30" }
|
||||||
|
solana-sdk = { path = "../sdk", version = "1.2.30" }
|
||||||
|
solana-stake-program = { path = "../programs/stake", version = "1.2.30" }
|
||||||
|
solana-transaction-status = { path = "../transaction-status", version = "1.2.30" }
|
||||||
|
solana-vote-program = { path = "../programs/vote", version = "1.2.30" }
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
targets = ["x86_64-unknown-linux-gnu"]
|
@ -1,24 +1,29 @@
|
|||||||
use crate::{cli::build_balance_message, display::writeln_name_value};
|
use crate::display::{build_balance_message, writeln_name_value};
|
||||||
use chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc};
|
use chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc};
|
||||||
use console::{style, Emoji};
|
use console::{style, Emoji};
|
||||||
use inflector::cases::titlecase::to_title_case;
|
use inflector::cases::titlecase::to_title_case;
|
||||||
use serde::Serialize;
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
use solana_clap_utils::keypair::SignOnly;
|
||||||
use solana_client::rpc_response::{
|
use solana_client::rpc_response::{
|
||||||
RpcAccountBalance, RpcKeyedAccount, RpcSupply, RpcVoteAccountInfo,
|
RpcAccountBalance, RpcKeyedAccount, RpcSupply, RpcVoteAccountInfo,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::{self, Epoch, Slot, UnixTimestamp},
|
clock::{self, Epoch, Slot, UnixTimestamp},
|
||||||
epoch_info::EpochInfo,
|
epoch_info::EpochInfo,
|
||||||
|
hash::Hash,
|
||||||
native_token::lamports_to_sol,
|
native_token::lamports_to_sol,
|
||||||
|
pubkey::Pubkey,
|
||||||
|
signature::Signature,
|
||||||
stake_history::StakeHistoryEntry,
|
stake_history::StakeHistoryEntry,
|
||||||
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_stake_program::stake_state::{Authorized, Lockup};
|
use solana_stake_program::stake_state::{Authorized, Lockup};
|
||||||
use solana_vote_program::{
|
use solana_vote_program::{
|
||||||
authorized_voters::AuthorizedVoters,
|
authorized_voters::AuthorizedVoters,
|
||||||
vote_state::{BlockTimestamp, Lockout},
|
vote_state::{BlockTimestamp, Lockout},
|
||||||
};
|
};
|
||||||
use std::{collections::BTreeMap, fmt, time::Duration};
|
use std::{collections::BTreeMap, fmt, str::FromStr, time::Duration};
|
||||||
|
|
||||||
static WARNING: Emoji = Emoji("⚠️", "!");
|
static WARNING: Emoji = Emoji("⚠️", "!");
|
||||||
|
|
||||||
@ -1086,3 +1091,149 @@ impl fmt::Display for CliFees {
|
|||||||
Ok(())
|
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());
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
use crate::cli::SettingType;
|
|
||||||
use console::style;
|
use console::style;
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@ -8,6 +7,24 @@ use solana_sdk::{
|
|||||||
use solana_transaction_status::UiTransactionStatusMeta;
|
use solana_transaction_status::UiTransactionStatusMeta;
|
||||||
use std::{fmt, io};
|
use std::{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"
|
// Pretty print a "name value"
|
||||||
pub fn println_name_value(name: &str, value: &str) {
|
pub fn println_name_value(name: &str, value: &str) {
|
||||||
let styled_value = if value == "" {
|
let styled_value = if value == "" {
|
||||||
@ -27,21 +44,6 @@ pub fn writeln_name_value(f: &mut fmt::Formatter, name: &str, value: &str) -> fm
|
|||||||
writeln!(f, "{} {}", style(name).bold(), styled_value)
|
writeln!(f, "{} {}", style(name).bold(), styled_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
pub fn println_signers(
|
||||||
blockhash: &Hash,
|
blockhash: &Hash,
|
||||||
signers: &[String],
|
signers: &[String],
|
3
cli-output/src/lib.rs
Normal file
3
cli-output/src/lib.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
mod cli_output;
|
||||||
|
pub mod display;
|
||||||
|
pub use cli_output::*;
|
@ -31,6 +31,7 @@ solana-account-decoder = { path = "../account-decoder", version = "1.2.30" }
|
|||||||
solana-budget-program = { path = "../programs/budget", version = "1.2.30" }
|
solana-budget-program = { path = "../programs/budget", version = "1.2.30" }
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.2.30" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.2.30" }
|
||||||
solana-cli-config = { path = "../cli-config", version = "1.2.30" }
|
solana-cli-config = { path = "../cli-config", version = "1.2.30" }
|
||||||
|
solana-cli-output = { path = "../cli-output", version = "1.2.30" }
|
||||||
solana-client = { path = "../client", version = "1.2.30" }
|
solana-client = { path = "../client", version = "1.2.30" }
|
||||||
solana-config-program = { path = "../programs/config", version = "1.2.30" }
|
solana-config-program = { path = "../programs/config", version = "1.2.30" }
|
||||||
solana-faucet = { path = "../faucet", version = "1.2.30" }
|
solana-faucet = { path = "../faucet", version = "1.2.30" }
|
||||||
|
481
cli/src/cli.rs
481
cli/src/cli.rs
@ -1,14 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
checks::*,
|
checks::*, cluster_query::*, nonce::*, spend_utils::*, stake::*, validator_info::*, vote::*,
|
||||||
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::*,
|
|
||||||
};
|
};
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use clap::{value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
use clap::{value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||||
@ -18,15 +9,25 @@ use serde_json::{self, json, Value};
|
|||||||
use solana_account_decoder::{UiAccount, UiAccountEncoding};
|
use solana_account_decoder::{UiAccount, UiAccountEncoding};
|
||||||
use solana_budget_program::budget_instruction::{self, BudgetError};
|
use solana_budget_program::budget_instruction::{self, BudgetError};
|
||||||
use solana_clap_utils::{
|
use solana_clap_utils::{
|
||||||
|
self,
|
||||||
commitment::{commitment_arg_with_default, COMMITMENT_ARG},
|
commitment::{commitment_arg_with_default, COMMITMENT_ARG},
|
||||||
|
fee_payer::{fee_payer_arg, FEE_PAYER_ARG},
|
||||||
input_parsers::*,
|
input_parsers::*,
|
||||||
input_validators::*,
|
input_validators::*,
|
||||||
keypair::signer_from_path,
|
keypair::*,
|
||||||
offline::SIGN_ONLY_ARG,
|
nonce::*,
|
||||||
ArgConstant,
|
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::{
|
use solana_client::{
|
||||||
|
blockhash_query::BlockhashQuery,
|
||||||
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
|
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
|
||||||
|
nonce_utils,
|
||||||
rpc_client::RpcClient,
|
rpc_client::RpcClient,
|
||||||
rpc_config::{RpcLargestAccountsFilter, RpcSendTransactionConfig},
|
rpc_config::{RpcLargestAccountsFilter, RpcSendTransactionConfig},
|
||||||
rpc_response::{Response, RpcKeyedAccount},
|
rpc_response::{Response, RpcKeyedAccount},
|
||||||
@ -41,12 +42,10 @@ use solana_sdk::{
|
|||||||
clock::{Epoch, Slot, DEFAULT_TICKS_PER_SECOND},
|
clock::{Epoch, Slot, DEFAULT_TICKS_PER_SECOND},
|
||||||
commitment_config::CommitmentConfig,
|
commitment_config::CommitmentConfig,
|
||||||
decode_error::DecodeError,
|
decode_error::DecodeError,
|
||||||
fee_calculator::FeeCalculator,
|
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
loader_instruction,
|
loader_instruction,
|
||||||
message::Message,
|
message::Message,
|
||||||
native_token::lamports_to_sol,
|
|
||||||
pubkey::{Pubkey, MAX_SEED_LEN},
|
pubkey::{Pubkey, MAX_SEED_LEN},
|
||||||
signature::{Keypair, Signature, Signer, SignerError},
|
signature::{Keypair, Signature, Signer, SignerError},
|
||||||
signers::Signers,
|
signers::Signers,
|
||||||
@ -73,96 +72,8 @@ use std::{
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use url::Url;
|
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
|
const DATA_CHUNK_SIZE: usize = 229; // Keep program chunks under PACKET_DATA_SIZE
|
||||||
|
|
||||||
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)]
|
#[derive(Default, Debug, PartialEq)]
|
||||||
pub struct PayCommand {
|
pub struct PayCommand {
|
||||||
pub amount: SpendAmount,
|
pub amount: SpendAmount,
|
||||||
@ -475,7 +386,7 @@ pub enum CliError {
|
|||||||
#[error("insufficient funds for spend ({0} SOL) and fee ({1} SOL)")]
|
#[error("insufficient funds for spend ({0} SOL) and fee ({1} SOL)")]
|
||||||
InsufficientFundsForSpendAndFee(f64, f64),
|
InsufficientFundsForSpendAndFee(f64, f64),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
InvalidNonce(CliNonceError),
|
InvalidNonce(nonce_utils::Error),
|
||||||
#[error("dynamic program error: {0}")]
|
#[error("dynamic program error: {0}")]
|
||||||
DynamicProgramError(String),
|
DynamicProgramError(String),
|
||||||
#[error("rpc request error: {0}")]
|
#[error("rpc request error: {0}")]
|
||||||
@ -490,10 +401,10 @@ impl From<Box<dyn error::Error>> for CliError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CliNonceError> for CliError {
|
impl From<nonce_utils::Error> for CliError {
|
||||||
fn from(error: CliNonceError) -> Self {
|
fn from(error: nonce_utils::Error) -> Self {
|
||||||
match error {
|
match error {
|
||||||
CliNonceError::Client(client_error) => Self::RpcRequestError(client_error),
|
nonce_utils::Error::Client(client_error) => Self::RpcRequestError(client_error),
|
||||||
_ => Self::InvalidNonce(error),
|
_ => Self::InvalidNonce(error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -613,7 +524,7 @@ impl Default for CliConfig<'_> {
|
|||||||
|
|
||||||
pub fn parse_command(
|
pub fn parse_command(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, Box<dyn error::Error>> {
|
) -> Result<CliCommandInfo, Box<dyn error::Error>> {
|
||||||
let response = match matches.subcommand() {
|
let response = match matches.subcommand() {
|
||||||
@ -628,7 +539,7 @@ pub fn parse_command(
|
|||||||
signers: vec![],
|
signers: vec![],
|
||||||
}),
|
}),
|
||||||
("create-address-with-seed", Some(matches)) => {
|
("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 {
|
("fees", Some(_matches)) => Ok(CliCommandInfo {
|
||||||
command: CliCommand::Fees,
|
command: CliCommand::Fees,
|
||||||
@ -650,7 +561,7 @@ pub fn parse_command(
|
|||||||
command: CliCommand::LeaderSchedule,
|
command: CliCommand::LeaderSchedule,
|
||||||
signers: vec![],
|
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 {
|
("live-slots", Some(_matches)) => Ok(CliCommandInfo {
|
||||||
command: CliCommand::LiveSlots,
|
command: CliCommand::LiveSlots,
|
||||||
signers: vec![],
|
signers: vec![],
|
||||||
@ -667,99 +578,87 @@ pub fn parse_command(
|
|||||||
}
|
}
|
||||||
// Nonce Commands
|
// Nonce Commands
|
||||||
("authorize-nonce-account", Some(matches)) => {
|
("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)) => {
|
("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),
|
("nonce", Some(matches)) => parse_get_nonce(matches, wallet_manager),
|
||||||
("new-nonce", Some(matches)) => {
|
("new-nonce", Some(matches)) => parse_new_nonce(matches, default_signer, wallet_manager),
|
||||||
parse_new_nonce(matches, default_signer_path, wallet_manager)
|
|
||||||
}
|
|
||||||
("nonce-account", Some(matches)) => parse_show_nonce_account(matches, wallet_manager),
|
("nonce-account", Some(matches)) => parse_show_nonce_account(matches, wallet_manager),
|
||||||
("withdraw-from-nonce-account", Some(matches)) => {
|
("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
|
// Program Deployment
|
||||||
("deploy", Some(matches)) => Ok(CliCommandInfo {
|
("deploy", Some(matches)) => Ok(CliCommandInfo {
|
||||||
command: CliCommand::Deploy(matches.value_of("program_location").unwrap().to_string()),
|
command: CliCommand::Deploy(matches.value_of("program_location").unwrap().to_string()),
|
||||||
signers: vec![signer_from_path(
|
signers: vec![default_signer.signer_from_path(matches, wallet_manager)?],
|
||||||
matches,
|
|
||||||
default_signer_path,
|
|
||||||
"keypair",
|
|
||||||
wallet_manager,
|
|
||||||
)?],
|
|
||||||
}),
|
}),
|
||||||
// Stake Commands
|
// Stake Commands
|
||||||
("create-stake-account", Some(matches)) => {
|
("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)) => {
|
("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)) => {
|
("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)) => {
|
("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)) => {
|
("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)) => {
|
("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)) => {
|
("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)) => {
|
("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-account", Some(matches)) => parse_show_stake_account(matches, wallet_manager),
|
||||||
("stake-history", Some(matches)) => parse_show_stake_history(matches),
|
("stake-history", Some(matches)) => parse_show_stake_history(matches),
|
||||||
// Validator Info Commands
|
// Validator Info Commands
|
||||||
("validator-info", Some(matches)) => match matches.subcommand() {
|
("validator-info", Some(matches)) => match matches.subcommand() {
|
||||||
("publish", Some(matches)) => {
|
("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),
|
("get", Some(matches)) => parse_get_validator_info_command(matches),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
// Vote Commands
|
// Vote Commands
|
||||||
("create-vote-account", Some(matches)) => {
|
("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)) => {
|
("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)) => {
|
("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(
|
("vote-authorize-voter", Some(matches)) => parse_vote_authorize(
|
||||||
matches,
|
matches,
|
||||||
default_signer_path,
|
default_signer,
|
||||||
wallet_manager,
|
wallet_manager,
|
||||||
VoteAuthorize::Voter,
|
VoteAuthorize::Voter,
|
||||||
),
|
),
|
||||||
("vote-authorize-withdrawer", Some(matches)) => parse_vote_authorize(
|
("vote-authorize-withdrawer", Some(matches)) => parse_vote_authorize(
|
||||||
matches,
|
matches,
|
||||||
default_signer_path,
|
default_signer,
|
||||||
wallet_manager,
|
wallet_manager,
|
||||||
VoteAuthorize::Withdrawer,
|
VoteAuthorize::Withdrawer,
|
||||||
),
|
),
|
||||||
("vote-account", Some(matches)) => parse_vote_get_account_command(matches, wallet_manager),
|
("vote-account", Some(matches)) => parse_vote_get_account_command(matches, wallet_manager),
|
||||||
("withdraw-from-vote-account", Some(matches)) => {
|
("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
|
// Wallet Commands
|
||||||
("address", Some(matches)) => Ok(CliCommandInfo {
|
("address", Some(matches)) => Ok(CliCommandInfo {
|
||||||
command: CliCommand::Address,
|
command: CliCommand::Address,
|
||||||
signers: vec![signer_from_path(
|
signers: vec![default_signer.signer_from_path(matches, wallet_manager)?],
|
||||||
matches,
|
|
||||||
default_signer_path,
|
|
||||||
"keypair",
|
|
||||||
wallet_manager,
|
|
||||||
)?],
|
|
||||||
}),
|
}),
|
||||||
("airdrop", Some(matches)) => {
|
("airdrop", Some(matches)) => {
|
||||||
let faucet_port = matches
|
let faucet_port = matches
|
||||||
@ -787,12 +686,7 @@ pub fn parse_command(
|
|||||||
let signers = if pubkey.is_some() {
|
let signers = if pubkey.is_some() {
|
||||||
vec![]
|
vec![]
|
||||||
} else {
|
} else {
|
||||||
vec![signer_from_path(
|
vec![default_signer.signer_from_path(matches, wallet_manager)?]
|
||||||
matches,
|
|
||||||
default_signer_path,
|
|
||||||
"keypair",
|
|
||||||
wallet_manager,
|
|
||||||
)?]
|
|
||||||
};
|
};
|
||||||
let lamports = lamports_of_sol(matches, "amount").unwrap();
|
let lamports = lamports_of_sol(matches, "amount").unwrap();
|
||||||
Ok(CliCommandInfo {
|
Ok(CliCommandInfo {
|
||||||
@ -811,12 +705,7 @@ pub fn parse_command(
|
|||||||
let signers = if pubkey.is_some() {
|
let signers = if pubkey.is_some() {
|
||||||
vec![]
|
vec![]
|
||||||
} else {
|
} else {
|
||||||
vec![signer_from_path(
|
vec![default_signer.signer_from_path(matches, wallet_manager)?]
|
||||||
matches,
|
|
||||||
default_signer_path,
|
|
||||||
"keypair",
|
|
||||||
wallet_manager,
|
|
||||||
)?]
|
|
||||||
};
|
};
|
||||||
Ok(CliCommandInfo {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::Balance {
|
command: CliCommand::Balance {
|
||||||
@ -829,8 +718,7 @@ pub fn parse_command(
|
|||||||
}
|
}
|
||||||
("cancel", Some(matches)) => {
|
("cancel", Some(matches)) => {
|
||||||
let process_id = value_of(matches, "process_id").unwrap();
|
let process_id = value_of(matches, "process_id").unwrap();
|
||||||
let default_signer =
|
let default_signer = default_signer.signer_from_path(matches, wallet_manager)?;
|
||||||
signer_from_path(matches, default_signer_path, "keypair", wallet_manager)?;
|
|
||||||
|
|
||||||
Ok(CliCommandInfo {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::Cancel(process_id),
|
command: CliCommand::Cancel(process_id),
|
||||||
@ -892,12 +780,8 @@ pub fn parse_command(
|
|||||||
if nonce_account.is_some() {
|
if nonce_account.is_some() {
|
||||||
bulk_signers.push(nonce_authority);
|
bulk_signers.push(nonce_authority);
|
||||||
}
|
}
|
||||||
let signer_info = generate_unique_signers(
|
let signer_info =
|
||||||
bulk_signers,
|
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
|
||||||
matches,
|
|
||||||
default_signer_path,
|
|
||||||
wallet_manager,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(CliCommandInfo {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::Pay(PayCommand {
|
command: CliCommand::Pay(PayCommand {
|
||||||
@ -940,8 +824,7 @@ pub fn parse_command(
|
|||||||
let to = value_of(matches, "to").unwrap();
|
let to = value_of(matches, "to").unwrap();
|
||||||
let process_id = value_of(matches, "process_id").unwrap();
|
let process_id = value_of(matches, "process_id").unwrap();
|
||||||
|
|
||||||
let default_signer =
|
let default_signer = default_signer.signer_from_path(matches, wallet_manager)?;
|
||||||
signer_from_path(matches, default_signer_path, "keypair", wallet_manager)?;
|
|
||||||
|
|
||||||
Ok(CliCommandInfo {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::Witness(to, process_id),
|
command: CliCommand::Witness(to, process_id),
|
||||||
@ -962,8 +845,7 @@ pub fn parse_command(
|
|||||||
} else {
|
} else {
|
||||||
Utc::now()
|
Utc::now()
|
||||||
};
|
};
|
||||||
let default_signer =
|
let default_signer = default_signer.signer_from_path(matches, wallet_manager)?;
|
||||||
signer_from_path(matches, default_signer_path, "keypair", wallet_manager)?;
|
|
||||||
|
|
||||||
Ok(CliCommandInfo {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::TimeElapsed(to, process_id, dt),
|
command: CliCommand::TimeElapsed(to, process_id, dt),
|
||||||
@ -988,12 +870,8 @@ pub fn parse_command(
|
|||||||
bulk_signers.push(nonce_authority);
|
bulk_signers.push(nonce_authority);
|
||||||
}
|
}
|
||||||
|
|
||||||
let signer_info = generate_unique_signers(
|
let signer_info =
|
||||||
bulk_signers,
|
default_signer.generate_unique_signers(bulk_signers, matches, wallet_manager)?;
|
||||||
matches,
|
|
||||||
default_signer_path,
|
|
||||||
wallet_manager,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(CliCommandInfo {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::Transfer {
|
command: CliCommand::Transfer {
|
||||||
@ -1024,66 +902,16 @@ pub fn parse_command(
|
|||||||
|
|
||||||
pub type ProcessResult = Result<String, Box<dyn std::error::Error>>;
|
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(
|
pub fn parse_create_address_with_seed(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let from_pubkey = pubkey_of_signer(matches, "from", wallet_manager)?;
|
let from_pubkey = pubkey_of_signer(matches, "from", wallet_manager)?;
|
||||||
let signers = if from_pubkey.is_some() {
|
let signers = if from_pubkey.is_some() {
|
||||||
vec![]
|
vec![]
|
||||||
} else {
|
} else {
|
||||||
vec![signer_from_path(
|
vec![default_signer.signer_from_path(matches, wallet_manager)?]
|
||||||
matches,
|
|
||||||
default_signer_path,
|
|
||||||
"keypair",
|
|
||||||
wallet_manager,
|
|
||||||
)?]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let program_id = match matches.value_of("program_id").unwrap() {
|
let program_id = match matches.value_of("program_id").unwrap() {
|
||||||
@ -1508,7 +1336,7 @@ fn process_pay(
|
|||||||
|
|
||||||
if sign_only {
|
if sign_only {
|
||||||
tx.try_partial_sign(&config.signers, blockhash)?;
|
tx.try_partial_sign(&config.signers, blockhash)?;
|
||||||
return_signers(&tx, &config)
|
return_signers(&tx, &config.output_format)
|
||||||
} else {
|
} else {
|
||||||
if let Some(nonce_account) = &nonce_account {
|
if let Some(nonce_account) = &nonce_account {
|
||||||
let nonce_account = rpc_client.get_account(nonce_account)?;
|
let nonce_account = rpc_client.get_account(nonce_account)?;
|
||||||
@ -1552,7 +1380,7 @@ fn process_pay(
|
|||||||
let mut tx = Transaction::new_unsigned(message);
|
let mut tx = Transaction::new_unsigned(message);
|
||||||
if sign_only {
|
if sign_only {
|
||||||
tx.try_partial_sign(&[config.signers[0], &contract_state], blockhash)?;
|
tx.try_partial_sign(&[config.signers[0], &contract_state], blockhash)?;
|
||||||
return_signers(&tx, &config)
|
return_signers(&tx, &config.output_format)
|
||||||
} else {
|
} else {
|
||||||
tx.try_sign(&[config.signers[0], &contract_state], blockhash)?;
|
tx.try_sign(&[config.signers[0], &contract_state], blockhash)?;
|
||||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||||
@ -1598,7 +1426,7 @@ fn process_pay(
|
|||||||
let mut tx = Transaction::new_unsigned(message);
|
let mut tx = Transaction::new_unsigned(message);
|
||||||
if sign_only {
|
if sign_only {
|
||||||
tx.try_partial_sign(&[config.signers[0], &contract_state], blockhash)?;
|
tx.try_partial_sign(&[config.signers[0], &contract_state], blockhash)?;
|
||||||
return_signers(&tx, &config)
|
return_signers(&tx, &config.output_format)
|
||||||
} else {
|
} else {
|
||||||
tx.try_sign(&[config.signers[0], &contract_state], blockhash)?;
|
tx.try_sign(&[config.signers[0], &contract_state], blockhash)?;
|
||||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||||
@ -1707,7 +1535,7 @@ fn process_transfer(
|
|||||||
|
|
||||||
if sign_only {
|
if sign_only {
|
||||||
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
||||||
return_signers(&tx, &config)
|
return_signers(&tx, &config.output_format)
|
||||||
} else {
|
} else {
|
||||||
if let Some(nonce_account) = &nonce_account {
|
if let Some(nonce_account) = &nonce_account {
|
||||||
let nonce_account = rpc_client.get_account(nonce_account)?;
|
let nonce_account = rpc_client.get_account(nonce_account)?;
|
||||||
@ -2436,28 +2264,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> {
|
pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, 'v> {
|
||||||
App::new(name)
|
App::new(name)
|
||||||
.about(about)
|
.about(about)
|
||||||
@ -2667,8 +2473,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
.takes_value(false),
|
.takes_value(false),
|
||||||
)
|
)
|
||||||
.offline_args()
|
.offline_args()
|
||||||
.arg(nonce_arg())
|
.nonce_args()
|
||||||
.arg(nonce_authority_arg()),
|
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("resolve-signer")
|
SubCommand::with_name("resolve-signer")
|
||||||
@ -2760,8 +2565,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"),
|
.help("Return signature immediately after submitting the transaction, instead of waiting for confirmations"),
|
||||||
)
|
)
|
||||||
.offline_args()
|
.offline_args()
|
||||||
.arg(nonce_arg())
|
.nonce_args()
|
||||||
.arg(nonce_authority_arg())
|
|
||||||
.arg(fee_payer_arg()),
|
.arg(fee_payer_arg()),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
@ -2798,12 +2602,10 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use solana_client::mock_sender::SIGNATURE;
|
use solana_client::{blockhash_query, mock_sender::SIGNATURE};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{
|
signature::{keypair_from_seed, read_keypair_file, write_keypair_file, Presigner},
|
||||||
keypair_from_seed, read_keypair_file, write_keypair_file, NullSigner, Presigner,
|
|
||||||
},
|
|
||||||
transaction::TransactionError,
|
transaction::TransactionError,
|
||||||
};
|
};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -2830,13 +2632,19 @@ mod tests {
|
|||||||
let default_keypair_file = make_tmp_path("keypair_file");
|
let default_keypair_file = make_tmp_path("keypair_file");
|
||||||
write_keypair_file(&default_keypair, &default_keypair_file).unwrap();
|
write_keypair_file(&default_keypair, &default_keypair_file).unwrap();
|
||||||
|
|
||||||
let signer_info =
|
let default_signer = DefaultSigner {
|
||||||
generate_unique_signers(vec![], &matches, &default_keypair_file, &mut None).unwrap();
|
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);
|
assert_eq!(signer_info.signers.len(), 0);
|
||||||
|
|
||||||
let signer_info =
|
let signer_info = default_signer
|
||||||
generate_unique_signers(vec![None, None], &matches, &default_keypair_file, &mut None)
|
.generate_unique_signers(vec![None, None], &matches, &mut None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(signer_info.signers.len(), 1);
|
assert_eq!(signer_info.signers.len(), 1);
|
||||||
assert_eq!(signer_info.index_of(None), Some(0));
|
assert_eq!(signer_info.index_of(None), Some(0));
|
||||||
assert_eq!(signer_info.index_of(Some(Pubkey::new_rand())), None);
|
assert_eq!(signer_info.index_of(Some(Pubkey::new_rand())), None);
|
||||||
@ -2846,8 +2654,9 @@ mod tests {
|
|||||||
let keypair0_clone = keypair_from_seed(&[1u8; 32]).unwrap();
|
let keypair0_clone = keypair_from_seed(&[1u8; 32]).unwrap();
|
||||||
let keypair0_clone_pubkey = keypair0.pubkey();
|
let keypair0_clone_pubkey = keypair0.pubkey();
|
||||||
let signers = vec![None, Some(keypair0.into()), Some(keypair0_clone.into())];
|
let signers = vec![None, Some(keypair0.into()), Some(keypair0_clone.into())];
|
||||||
let signer_info =
|
let signer_info = default_signer
|
||||||
generate_unique_signers(signers, &matches, &default_keypair_file, &mut None).unwrap();
|
.generate_unique_signers(signers, &matches, &mut None)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(signer_info.signers.len(), 2);
|
assert_eq!(signer_info.signers.len(), 2);
|
||||||
assert_eq!(signer_info.index_of(None), Some(0));
|
assert_eq!(signer_info.index_of(None), Some(0));
|
||||||
assert_eq!(signer_info.index_of(Some(keypair0_pubkey)), Some(1));
|
assert_eq!(signer_info.index_of(Some(keypair0_pubkey)), Some(1));
|
||||||
@ -2857,8 +2666,9 @@ mod tests {
|
|||||||
let keypair0_pubkey = keypair0.pubkey();
|
let keypair0_pubkey = keypair0.pubkey();
|
||||||
let keypair0_clone = keypair_from_seed(&[1u8; 32]).unwrap();
|
let keypair0_clone = keypair_from_seed(&[1u8; 32]).unwrap();
|
||||||
let signers = vec![Some(keypair0.into()), Some(keypair0_clone.into())];
|
let signers = vec![Some(keypair0.into()), Some(keypair0_clone.into())];
|
||||||
let signer_info =
|
let signer_info = default_signer
|
||||||
generate_unique_signers(signers, &matches, &default_keypair_file, &mut None).unwrap();
|
.generate_unique_signers(signers, &matches, &mut None)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(signer_info.signers.len(), 1);
|
assert_eq!(signer_info.signers.len(), 1);
|
||||||
assert_eq!(signer_info.index_of(Some(keypair0_pubkey)), Some(0));
|
assert_eq!(signer_info.index_of(Some(keypair0_pubkey)), Some(0));
|
||||||
|
|
||||||
@ -2878,8 +2688,9 @@ mod tests {
|
|||||||
Some(presigner1.into()),
|
Some(presigner1.into()),
|
||||||
Some(keypair1.into()),
|
Some(keypair1.into()),
|
||||||
];
|
];
|
||||||
let signer_info =
|
let signer_info = default_signer
|
||||||
generate_unique_signers(signers, &matches, &default_keypair_file, &mut None).unwrap();
|
.generate_unique_signers(signers, &matches, &mut None)
|
||||||
|
.unwrap();
|
||||||
assert_eq!(signer_info.signers.len(), 2);
|
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(keypair0_pubkey)), Some(0));
|
||||||
assert_eq!(signer_info.index_of(Some(keypair1_pubkey)), Some(1));
|
assert_eq!(signer_info.index_of(Some(keypair1_pubkey)), Some(1));
|
||||||
@ -2900,13 +2711,21 @@ mod tests {
|
|||||||
let witness1_string = format!("{}", witness1);
|
let witness1_string = format!("{}", witness1);
|
||||||
let dt = Utc.ymd(2018, 9, 19).and_hms(17, 30, 59);
|
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
|
// Test Airdrop Subcommand
|
||||||
let test_airdrop =
|
let test_airdrop =
|
||||||
test_commands
|
test_commands
|
||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "airdrop", "50", &pubkey_string]);
|
.get_matches_from(vec!["test", "airdrop", "50", &pubkey_string]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_airdrop, "", &mut None).unwrap(),
|
parse_command(&test_airdrop, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Airdrop {
|
command: CliCommand::Airdrop {
|
||||||
faucet_host: None,
|
faucet_host: None,
|
||||||
@ -2919,17 +2738,13 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Test Balance Subcommand, incl pubkey and keypair-file inputs
|
// 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![
|
let test_balance = test_commands.clone().get_matches_from(vec![
|
||||||
"test",
|
"test",
|
||||||
"balance",
|
"balance",
|
||||||
&keypair.pubkey().to_string(),
|
&keypair.pubkey().to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_balance, "", &mut None).unwrap(),
|
parse_command(&test_balance, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Balance {
|
command: CliCommand::Balance {
|
||||||
pubkey: Some(keypair.pubkey()),
|
pubkey: Some(keypair.pubkey()),
|
||||||
@ -2946,7 +2761,7 @@ mod tests {
|
|||||||
"--lamports",
|
"--lamports",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_balance, "", &mut None).unwrap(),
|
parse_command(&test_balance, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Balance {
|
command: CliCommand::Balance {
|
||||||
pubkey: Some(keypair.pubkey()),
|
pubkey: Some(keypair.pubkey()),
|
||||||
@ -2961,7 +2776,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "balance", "--lamports"]);
|
.get_matches_from(vec!["test", "balance", "--lamports"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_balance, &keypair_file, &mut None).unwrap(),
|
parse_command(&test_balance, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Balance {
|
command: CliCommand::Balance {
|
||||||
pubkey: None,
|
pubkey: None,
|
||||||
@ -2978,7 +2793,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "cancel", &pubkey_string]);
|
.get_matches_from(vec!["test", "cancel", &pubkey_string]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_cancel, &keypair_file, &mut None).unwrap(),
|
parse_command(&test_cancel, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Cancel(pubkey),
|
command: CliCommand::Cancel(pubkey),
|
||||||
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
||||||
@ -2993,7 +2808,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "confirm", &signature_string]);
|
.get_matches_from(vec!["test", "confirm", &signature_string]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_confirm, "", &mut None).unwrap(),
|
parse_command(&test_confirm, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Confirm(signature),
|
command: CliCommand::Confirm(signature),
|
||||||
signers: vec![],
|
signers: vec![],
|
||||||
@ -3002,7 +2817,7 @@ mod tests {
|
|||||||
let test_bad_signature = test_commands
|
let test_bad_signature = test_commands
|
||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "confirm", "deadbeef"]);
|
.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
|
// Test CreateAddressWithSeed
|
||||||
let from_pubkey = Some(Pubkey::new_rand());
|
let from_pubkey = Some(Pubkey::new_rand());
|
||||||
@ -3021,7 +2836,7 @@ mod tests {
|
|||||||
&from_str,
|
&from_str,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::CreateAddressWithSeed {
|
command: CliCommand::CreateAddressWithSeed {
|
||||||
from_pubkey,
|
from_pubkey,
|
||||||
@ -3039,7 +2854,7 @@ mod tests {
|
|||||||
"STAKE",
|
"STAKE",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::CreateAddressWithSeed {
|
command: CliCommand::CreateAddressWithSeed {
|
||||||
from_pubkey: None,
|
from_pubkey: None,
|
||||||
@ -3056,7 +2871,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "deploy", "/Users/test/program.o"]);
|
.get_matches_from(vec!["test", "deploy", "/Users/test/program.o"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_deploy, &keypair_file, &mut None).unwrap(),
|
parse_command(&test_deploy, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Deploy("/Users/test/program.o".to_string()),
|
command: CliCommand::Deploy("/Users/test/program.o".to_string()),
|
||||||
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
||||||
@ -3069,7 +2884,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "resolve-signer", &keypair_file]);
|
.get_matches_from(vec!["test", "resolve-signer", &keypair_file]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_resolve_signer, "", &mut None).unwrap(),
|
parse_command(&test_resolve_signer, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::ResolveSigner(Some(keypair_file.clone())),
|
command: CliCommand::ResolveSigner(Some(keypair_file.clone())),
|
||||||
signers: vec![],
|
signers: vec![],
|
||||||
@ -3081,7 +2896,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "resolve-signer", &pubkey_string]);
|
.get_matches_from(vec!["test", "resolve-signer", &pubkey_string]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_resolve_signer, "", &mut None).unwrap(),
|
parse_command(&test_resolve_signer, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::ResolveSigner(Some(pubkey.to_string())),
|
command: CliCommand::ResolveSigner(Some(pubkey.to_string())),
|
||||||
signers: vec![],
|
signers: vec![],
|
||||||
@ -3094,7 +2909,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "pay", &pubkey_string, "50"]);
|
.get_matches_from(vec!["test", "pay", &pubkey_string, "50"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_pay, &keypair_file, &mut None).unwrap(),
|
parse_command(&test_pay, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Pay(PayCommand {
|
command: CliCommand::Pay(PayCommand {
|
||||||
amount: SpendAmount::Some(50_000_000_000),
|
amount: SpendAmount::Some(50_000_000_000),
|
||||||
@ -3117,7 +2932,7 @@ mod tests {
|
|||||||
&witness1_string,
|
&witness1_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::Pay(PayCommand {
|
command: CliCommand::Pay(PayCommand {
|
||||||
amount: SpendAmount::Some(50_000_000_000),
|
amount: SpendAmount::Some(50_000_000_000),
|
||||||
@ -3137,7 +2952,7 @@ mod tests {
|
|||||||
&witness0_string,
|
&witness0_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::Pay(PayCommand {
|
command: CliCommand::Pay(PayCommand {
|
||||||
amount: SpendAmount::Some(50_000_000_000),
|
amount: SpendAmount::Some(50_000_000_000),
|
||||||
@ -3161,7 +2976,7 @@ mod tests {
|
|||||||
&witness0_string,
|
&witness0_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_pay_timestamp, &keypair_file, &mut None).unwrap(),
|
parse_command(&test_pay_timestamp, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Pay(PayCommand {
|
command: CliCommand::Pay(PayCommand {
|
||||||
amount: SpendAmount::Some(50_000_000_000),
|
amount: SpendAmount::Some(50_000_000_000),
|
||||||
@ -3187,7 +3002,7 @@ mod tests {
|
|||||||
"--sign-only",
|
"--sign-only",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_pay, &keypair_file, &mut None).unwrap(),
|
parse_command(&test_pay, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Pay(PayCommand {
|
command: CliCommand::Pay(PayCommand {
|
||||||
amount: SpendAmount::Some(50_000_000_000),
|
amount: SpendAmount::Some(50_000_000_000),
|
||||||
@ -3210,7 +3025,7 @@ mod tests {
|
|||||||
&blockhash_string,
|
&blockhash_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_pay, &keypair_file, &mut None).unwrap(),
|
parse_command(&test_pay, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Pay(PayCommand {
|
command: CliCommand::Pay(PayCommand {
|
||||||
amount: SpendAmount::Some(50_000_000_000),
|
amount: SpendAmount::Some(50_000_000_000),
|
||||||
@ -3239,7 +3054,7 @@ mod tests {
|
|||||||
&pubkey_string,
|
&pubkey_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_pay, &keypair_file, &mut None).unwrap(),
|
parse_command(&test_pay, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Pay(PayCommand {
|
command: CliCommand::Pay(PayCommand {
|
||||||
amount: SpendAmount::Some(50_000_000_000),
|
amount: SpendAmount::Some(50_000_000_000),
|
||||||
@ -3272,7 +3087,7 @@ mod tests {
|
|||||||
&keypair_file,
|
&keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_pay, &keypair_file, &mut None).unwrap(),
|
parse_command(&test_pay, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Pay(PayCommand {
|
command: CliCommand::Pay(PayCommand {
|
||||||
amount: SpendAmount::Some(50_000_000_000),
|
amount: SpendAmount::Some(50_000_000_000),
|
||||||
@ -3310,7 +3125,7 @@ mod tests {
|
|||||||
&signer_arg,
|
&signer_arg,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_pay, &keypair_file, &mut None).unwrap(),
|
parse_command(&test_pay, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Pay(PayCommand {
|
command: CliCommand::Pay(PayCommand {
|
||||||
amount: SpendAmount::Some(50_000_000_000),
|
amount: SpendAmount::Some(50_000_000_000),
|
||||||
@ -3348,7 +3163,7 @@ mod tests {
|
|||||||
"--signer",
|
"--signer",
|
||||||
&signer_arg,
|
&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
|
// Test Send-Signature Subcommand
|
||||||
let test_send_signature = test_commands.clone().get_matches_from(vec![
|
let test_send_signature = test_commands.clone().get_matches_from(vec![
|
||||||
@ -3358,7 +3173,7 @@ mod tests {
|
|||||||
&pubkey_string,
|
&pubkey_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_send_signature, &keypair_file, &mut None).unwrap(),
|
parse_command(&test_send_signature, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Witness(pubkey, pubkey),
|
command: CliCommand::Witness(pubkey, pubkey),
|
||||||
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
||||||
@ -3379,7 +3194,7 @@ mod tests {
|
|||||||
&witness1_string,
|
&witness1_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::Pay(PayCommand {
|
command: CliCommand::Pay(PayCommand {
|
||||||
amount: SpendAmount::Some(50_000_000_000),
|
amount: SpendAmount::Some(50_000_000_000),
|
||||||
@ -3403,7 +3218,7 @@ mod tests {
|
|||||||
"2018-09-19T17:30:59",
|
"2018-09-19T17:30:59",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_send_timestamp, &keypair_file, &mut None).unwrap(),
|
parse_command(&test_send_timestamp, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::TimeElapsed(pubkey, pubkey, dt),
|
command: CliCommand::TimeElapsed(pubkey, pubkey, dt),
|
||||||
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
signers: vec![read_keypair_file(&keypair_file).unwrap().into()],
|
||||||
@ -3417,7 +3232,7 @@ mod tests {
|
|||||||
"--date",
|
"--date",
|
||||||
"20180919T17:30:59",
|
"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]
|
#[test]
|
||||||
@ -3807,6 +3622,10 @@ mod tests {
|
|||||||
let default_keypair = Keypair::new();
|
let default_keypair = Keypair::new();
|
||||||
let default_keypair_file = make_tmp_path("keypair_file");
|
let default_keypair_file = make_tmp_path("keypair_file");
|
||||||
write_keypair_file(&default_keypair, &default_keypair_file).unwrap();
|
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
|
//Test Transfer Subcommand, SOL
|
||||||
let from_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
|
let from_keypair = keypair_from_seed(&[0u8; 32]).unwrap();
|
||||||
@ -3819,7 +3638,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "transfer", &to_string, "42"]);
|
.get_matches_from(vec!["test", "transfer", &to_string, "42"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_transfer, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Transfer {
|
command: CliCommand::Transfer {
|
||||||
amount: SpendAmount::Some(42_000_000_000),
|
amount: SpendAmount::Some(42_000_000_000),
|
||||||
@ -3841,7 +3660,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "transfer", &to_string, "ALL"]);
|
.get_matches_from(vec!["test", "transfer", &to_string, "ALL"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_transfer, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Transfer {
|
command: CliCommand::Transfer {
|
||||||
amount: SpendAmount::All,
|
amount: SpendAmount::All,
|
||||||
@ -3867,7 +3686,7 @@ mod tests {
|
|||||||
"42",
|
"42",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_transfer, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Transfer {
|
command: CliCommand::Transfer {
|
||||||
amount: SpendAmount::Some(42_000_000_000),
|
amount: SpendAmount::Some(42_000_000_000),
|
||||||
@ -3897,7 +3716,7 @@ mod tests {
|
|||||||
"--sign-only",
|
"--sign-only",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_transfer, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Transfer {
|
command: CliCommand::Transfer {
|
||||||
amount: SpendAmount::Some(42_000_000_000),
|
amount: SpendAmount::Some(42_000_000_000),
|
||||||
@ -3932,7 +3751,7 @@ mod tests {
|
|||||||
&blockhash_string,
|
&blockhash_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_transfer, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Transfer {
|
command: CliCommand::Transfer {
|
||||||
amount: SpendAmount::Some(42_000_000_000),
|
amount: SpendAmount::Some(42_000_000_000),
|
||||||
@ -3971,7 +3790,7 @@ mod tests {
|
|||||||
&nonce_authority_file,
|
&nonce_authority_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_transfer, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_transfer, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Transfer {
|
command: CliCommand::Transfer {
|
||||||
amount: SpendAmount::Some(42_000_000_000),
|
amount: SpendAmount::Some(42_000_000_000),
|
||||||
@ -3994,54 +3813,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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
|
cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
|
||||||
cli_output::*,
|
|
||||||
display::{new_spinner_progress_bar, println_name_value},
|
|
||||||
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
||||||
};
|
};
|
||||||
use clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
use clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||||
@ -10,7 +8,11 @@ use solana_clap_utils::{
|
|||||||
commitment::{commitment_arg, COMMITMENT_ARG},
|
commitment::{commitment_arg, COMMITMENT_ARG},
|
||||||
input_parsers::*,
|
input_parsers::*,
|
||||||
input_validators::*,
|
input_validators::*,
|
||||||
keypair::signer_from_path,
|
keypair::DefaultSigner,
|
||||||
|
};
|
||||||
|
use solana_cli_output::{
|
||||||
|
display::{new_spinner_progress_bar, println_name_value},
|
||||||
|
*,
|
||||||
};
|
};
|
||||||
use solana_client::{
|
use solana_client::{
|
||||||
pubsub_client::{PubsubClient, SlotInfoMessage},
|
pubsub_client::{PubsubClient, SlotInfoMessage},
|
||||||
@ -306,7 +308,7 @@ pub fn parse_catchup(
|
|||||||
|
|
||||||
pub fn parse_cluster_ping(
|
pub fn parse_cluster_ping(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let lamports = value_t_or_exit!(matches, "lamports", u64);
|
let lamports = value_t_or_exit!(matches, "lamports", u64);
|
||||||
@ -326,12 +328,7 @@ pub fn parse_cluster_ping(
|
|||||||
timeout,
|
timeout,
|
||||||
commitment_config,
|
commitment_config,
|
||||||
},
|
},
|
||||||
signers: vec![signer_from_path(
|
signers: vec![default_signer.signer_from_path(matches, wallet_manager)?],
|
||||||
matches,
|
|
||||||
default_signer_path,
|
|
||||||
"keypair",
|
|
||||||
wallet_manager,
|
|
||||||
)?],
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1342,12 +1339,16 @@ mod tests {
|
|||||||
let default_keypair = Keypair::new();
|
let default_keypair = Keypair::new();
|
||||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
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
|
let test_cluster_version = test_commands
|
||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "cluster-date"]);
|
.get_matches_from(vec!["test", "cluster-date"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_cluster_version, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_cluster_version, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::ClusterDate,
|
command: CliCommand::ClusterDate,
|
||||||
signers: vec![],
|
signers: vec![],
|
||||||
@ -1358,7 +1359,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "cluster-version"]);
|
.get_matches_from(vec!["test", "cluster-version"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_cluster_version, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_cluster_version, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::ClusterVersion,
|
command: CliCommand::ClusterVersion,
|
||||||
signers: vec![],
|
signers: vec![],
|
||||||
@ -1367,7 +1368,7 @@ mod tests {
|
|||||||
|
|
||||||
let test_fees = test_commands.clone().get_matches_from(vec!["test", "fees"]);
|
let test_fees = test_commands.clone().get_matches_from(vec!["test", "fees"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_fees, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_fees, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Fees,
|
command: CliCommand::Fees,
|
||||||
signers: vec![],
|
signers: vec![],
|
||||||
@ -1380,7 +1381,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "block-time", &slot.to_string()]);
|
.get_matches_from(vec!["test", "block-time", &slot.to_string()]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::GetBlockTime { slot: Some(slot) },
|
command: CliCommand::GetBlockTime { slot: Some(slot) },
|
||||||
signers: vec![],
|
signers: vec![],
|
||||||
@ -1391,7 +1392,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "epoch-info"]);
|
.get_matches_from(vec!["test", "epoch-info"]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::GetEpochInfo {
|
command: CliCommand::GetEpochInfo {
|
||||||
commitment_config: CommitmentConfig::recent(),
|
commitment_config: CommitmentConfig::recent(),
|
||||||
@ -1404,7 +1405,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "genesis-hash"]);
|
.get_matches_from(vec!["test", "genesis-hash"]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::GetGenesisHash,
|
command: CliCommand::GetGenesisHash,
|
||||||
signers: vec![],
|
signers: vec![],
|
||||||
@ -1413,7 +1414,7 @@ mod tests {
|
|||||||
|
|
||||||
let test_get_slot = test_commands.clone().get_matches_from(vec!["test", "slot"]);
|
let test_get_slot = test_commands.clone().get_matches_from(vec!["test", "slot"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_get_slot, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_get_slot, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::GetSlot {
|
command: CliCommand::GetSlot {
|
||||||
commitment_config: CommitmentConfig::recent(),
|
commitment_config: CommitmentConfig::recent(),
|
||||||
@ -1426,7 +1427,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "epoch"]);
|
.get_matches_from(vec!["test", "epoch"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_get_epoch, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_get_epoch, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::GetEpoch {
|
command: CliCommand::GetEpoch {
|
||||||
commitment_config: CommitmentConfig::recent(),
|
commitment_config: CommitmentConfig::recent(),
|
||||||
@ -1439,7 +1440,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "total-supply"]);
|
.get_matches_from(vec!["test", "total-supply"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_total_supply, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_total_supply, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::TotalSupply {
|
command: CliCommand::TotalSupply {
|
||||||
commitment_config: CommitmentConfig::recent(),
|
commitment_config: CommitmentConfig::recent(),
|
||||||
@ -1452,7 +1453,7 @@ mod tests {
|
|||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "transaction-count"]);
|
.get_matches_from(vec!["test", "transaction-count"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_transaction_count, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_transaction_count, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::GetTransactionCount {
|
command: CliCommand::GetTransactionCount {
|
||||||
commitment_config: CommitmentConfig::recent(),
|
commitment_config: CommitmentConfig::recent(),
|
||||||
@ -1474,7 +1475,7 @@ mod tests {
|
|||||||
"max",
|
"max",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_ping, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_ping, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::Ping {
|
command: CliCommand::Ping {
|
||||||
lamports: 1,
|
lamports: 1,
|
||||||
|
@ -18,16 +18,12 @@ macro_rules! pubkey {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
pub mod checks;
|
pub mod checks;
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
pub mod cli_output;
|
|
||||||
pub mod cluster_query;
|
pub mod cluster_query;
|
||||||
pub mod display;
|
|
||||||
pub mod nonce;
|
pub mod nonce;
|
||||||
pub mod offline;
|
|
||||||
pub mod spend_utils;
|
pub mod spend_utils;
|
||||||
pub mod stake;
|
pub mod stake;
|
||||||
pub mod test_utils;
|
pub mod test_utils;
|
||||||
|
@ -2,17 +2,33 @@ use clap::{crate_description, crate_name, AppSettings, Arg, ArgGroup, ArgMatches
|
|||||||
use console::style;
|
use console::style;
|
||||||
|
|
||||||
use solana_clap_utils::{
|
use solana_clap_utils::{
|
||||||
input_validators::is_url, keypair::SKIP_SEED_PHRASE_VALIDATION_ARG, DisplayError,
|
input_validators::is_url,
|
||||||
|
keypair::{CliSigners, DefaultSigner, SKIP_SEED_PHRASE_VALIDATION_ARG},
|
||||||
|
DisplayError,
|
||||||
};
|
};
|
||||||
use solana_cli::{
|
use solana_cli::cli::{
|
||||||
cli::{app, parse_command, process_command, CliCommandInfo, CliConfig, CliSigners},
|
app, parse_command, process_command, CliCommandInfo, CliConfig, SettingType,
|
||||||
cli_output::OutputFormat,
|
|
||||||
display::{println_name_value, println_name_value_or},
|
|
||||||
};
|
};
|
||||||
use solana_cli_config::{Config, CONFIG_FILE};
|
use solana_cli_config::{Config, CONFIG_FILE};
|
||||||
|
use solana_cli_output::{display::println_name_value, OutputFormat};
|
||||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||||
use std::{error, sync::Arc};
|
use std::{error, sync::Arc};
|
||||||
|
|
||||||
|
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>> {
|
fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error>> {
|
||||||
let parse_args = match matches.subcommand() {
|
let parse_args = match matches.subcommand() {
|
||||||
("config", Some(matches)) => match matches.subcommand() {
|
("config", Some(matches)) => match matches.subcommand() {
|
||||||
@ -119,13 +135,19 @@ pub fn parse_args<'a>(
|
|||||||
matches.value_of("json_rpc_url").unwrap_or(""),
|
matches.value_of("json_rpc_url").unwrap_or(""),
|
||||||
&config.json_rpc_url,
|
&config.json_rpc_url,
|
||||||
);
|
);
|
||||||
|
let default_signer_arg_name = "keypair".to_string();
|
||||||
let (_, default_signer_path) = CliConfig::compute_keypair_path_setting(
|
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,
|
&config.keypair_path,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let default_signer = DefaultSigner {
|
||||||
|
arg_name: default_signer_arg_name,
|
||||||
|
path: default_signer_path.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
let CliCommandInfo { command, signers } =
|
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
|
let output_format = matches
|
||||||
.value_of("output_format")
|
.value_of("output_format")
|
||||||
|
198
cli/src/nonce.rs
198
cli/src/nonce.rs
@ -1,28 +1,26 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
checks::{check_account_for_fee, check_unique_pubkeys},
|
checks::{check_account_for_fee, check_unique_pubkeys},
|
||||||
cli::{
|
cli::{
|
||||||
generate_unique_signers, log_instruction_custom_error, CliCommand, CliCommandInfo,
|
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
|
||||||
CliConfig, CliError, ProcessResult, SignerIndex,
|
ProcessResult,
|
||||||
},
|
},
|
||||||
cli_output::CliNonceAccount,
|
|
||||||
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
||||||
};
|
};
|
||||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||||
use solana_clap_utils::{
|
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_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
account_utils::StateMut,
|
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
message::Message,
|
message::Message,
|
||||||
nonce::{
|
nonce::{self, State},
|
||||||
self,
|
|
||||||
state::{Data, Versions},
|
|
||||||
State,
|
|
||||||
},
|
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
system_instruction::{
|
system_instruction::{
|
||||||
advance_nonce_account, authorize_nonce_account, create_nonce_account,
|
advance_nonce_account, authorize_nonce_account, create_nonce_account,
|
||||||
@ -32,64 +30,11 @@ use solana_sdk::{
|
|||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
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 {
|
pub trait NonceSubCommands {
|
||||||
fn nonce_subcommands(self) -> Self;
|
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<'_, '_> {
|
impl NonceSubCommands for App<'_, '_> {
|
||||||
fn nonce_subcommands(self) -> Self {
|
fn nonce_subcommands(self) -> Self {
|
||||||
self.subcommand(
|
self.subcommand(
|
||||||
@ -219,51 +164,9 @@ impl NonceSubCommands for App<'_, '_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_account(
|
|
||||||
rpc_client: &RpcClient,
|
|
||||||
nonce_pubkey: &Pubkey,
|
|
||||||
) -> Result<Account, CliNonceError> {
|
|
||||||
rpc_client
|
|
||||||
.get_account(nonce_pubkey)
|
|
||||||
.map_err(|e| CliNonceError::Client(format!("{}", e)))
|
|
||||||
.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(
|
pub fn parse_authorize_nonce_account(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let nonce_account = pubkey_of_signer(matches, "nonce_account_pubkey", wallet_manager)?.unwrap();
|
let nonce_account = pubkey_of_signer(matches, "nonce_account_pubkey", wallet_manager)?.unwrap();
|
||||||
@ -272,10 +175,9 @@ pub fn parse_authorize_nonce_account(
|
|||||||
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
||||||
|
|
||||||
let payer_provided = None;
|
let payer_provided = None;
|
||||||
let signer_info = generate_unique_signers(
|
let signer_info = default_signer.generate_unique_signers(
|
||||||
vec![payer_provided, nonce_authority],
|
vec![payer_provided, nonce_authority],
|
||||||
matches,
|
matches,
|
||||||
default_signer_path,
|
|
||||||
wallet_manager,
|
wallet_manager,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -291,7 +193,7 @@ pub fn parse_authorize_nonce_account(
|
|||||||
|
|
||||||
pub fn parse_nonce_create_account(
|
pub fn parse_nonce_create_account(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let (nonce_account, nonce_account_pubkey) =
|
let (nonce_account, nonce_account_pubkey) =
|
||||||
@ -301,10 +203,9 @@ pub fn parse_nonce_create_account(
|
|||||||
let nonce_authority = pubkey_of_signer(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
let nonce_authority = pubkey_of_signer(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
||||||
|
|
||||||
let payer_provided = None;
|
let payer_provided = None;
|
||||||
let signer_info = generate_unique_signers(
|
let signer_info = default_signer.generate_unique_signers(
|
||||||
vec![payer_provided, nonce_account],
|
vec![payer_provided, nonce_account],
|
||||||
matches,
|
matches,
|
||||||
default_signer_path,
|
|
||||||
wallet_manager,
|
wallet_manager,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -334,7 +235,7 @@ pub fn parse_get_nonce(
|
|||||||
|
|
||||||
pub fn parse_new_nonce(
|
pub fn parse_new_nonce(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let nonce_account = pubkey_of_signer(matches, "nonce_account_pubkey", wallet_manager)?.unwrap();
|
let nonce_account = pubkey_of_signer(matches, "nonce_account_pubkey", wallet_manager)?.unwrap();
|
||||||
@ -342,10 +243,9 @@ pub fn parse_new_nonce(
|
|||||||
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
||||||
|
|
||||||
let payer_provided = None;
|
let payer_provided = None;
|
||||||
let signer_info = generate_unique_signers(
|
let signer_info = default_signer.generate_unique_signers(
|
||||||
vec![payer_provided, nonce_authority],
|
vec![payer_provided, nonce_authority],
|
||||||
matches,
|
matches,
|
||||||
default_signer_path,
|
|
||||||
wallet_manager,
|
wallet_manager,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -377,7 +277,7 @@ pub fn parse_show_nonce_account(
|
|||||||
|
|
||||||
pub fn parse_withdraw_from_nonce_account(
|
pub fn parse_withdraw_from_nonce_account(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let nonce_account = pubkey_of_signer(matches, "nonce_account_pubkey", wallet_manager)?.unwrap();
|
let nonce_account = pubkey_of_signer(matches, "nonce_account_pubkey", wallet_manager)?.unwrap();
|
||||||
@ -388,10 +288,9 @@ pub fn parse_withdraw_from_nonce_account(
|
|||||||
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
signer_of(matches, NONCE_AUTHORITY_ARG.name, wallet_manager)?;
|
||||||
|
|
||||||
let payer_provided = None;
|
let payer_provided = None;
|
||||||
let signer_info = generate_unique_signers(
|
let signer_info = default_signer.generate_unique_signers(
|
||||||
vec![payer_provided, nonce_authority],
|
vec![payer_provided, nonce_authority],
|
||||||
matches,
|
matches,
|
||||||
default_signer_path,
|
|
||||||
wallet_manager,
|
wallet_manager,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -415,14 +314,14 @@ pub fn check_nonce_account(
|
|||||||
match state_from_account(nonce_account)? {
|
match state_from_account(nonce_account)? {
|
||||||
State::Initialized(ref data) => {
|
State::Initialized(ref data) => {
|
||||||
if &data.blockhash != nonce_hash {
|
if &data.blockhash != nonce_hash {
|
||||||
Err(CliNonceError::InvalidHash.into())
|
Err(Error::InvalidHash.into())
|
||||||
} else if nonce_authority != &data.authority {
|
} else if nonce_authority != &data.authority {
|
||||||
Err(CliNonceError::InvalidAuthority.into())
|
Err(Error::InvalidAuthority.into())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
State::Uninitialized => Err(CliNonceError::InvalidStateForOperation.into()),
|
State::Uninitialized => Err(Error::InvalidStateForOperation.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,9 +537,10 @@ mod tests {
|
|||||||
use crate::cli::{app, parse_command};
|
use crate::cli::{app, parse_command};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
|
account_utils::StateMut,
|
||||||
fee_calculator::FeeCalculator,
|
fee_calculator::FeeCalculator,
|
||||||
hash::hash,
|
hash::hash,
|
||||||
nonce::{self, State},
|
nonce::{self, state::Versions, State},
|
||||||
signature::{read_keypair_file, write_keypair, Keypair, Signer},
|
signature::{read_keypair_file, write_keypair, Keypair, Signer},
|
||||||
system_program,
|
system_program,
|
||||||
};
|
};
|
||||||
@ -657,6 +557,10 @@ mod tests {
|
|||||||
let default_keypair = Keypair::new();
|
let default_keypair = Keypair::new();
|
||||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
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 (keypair_file, mut tmp_file) = make_tmp_file();
|
||||||
let nonce_account_keypair = Keypair::new();
|
let nonce_account_keypair = Keypair::new();
|
||||||
write_keypair(&nonce_account_keypair, tmp_file.as_file_mut()).unwrap();
|
write_keypair(&nonce_account_keypair, tmp_file.as_file_mut()).unwrap();
|
||||||
@ -675,12 +579,7 @@ mod tests {
|
|||||||
&Pubkey::default().to_string(),
|
&Pubkey::default().to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(
|
parse_command(&test_authorize_nonce_account, &default_signer, &mut None).unwrap(),
|
||||||
&test_authorize_nonce_account,
|
|
||||||
&default_keypair_file,
|
|
||||||
&mut None
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::AuthorizeNonceAccount {
|
command: CliCommand::AuthorizeNonceAccount {
|
||||||
nonce_account: nonce_account_pubkey,
|
nonce_account: nonce_account_pubkey,
|
||||||
@ -701,12 +600,7 @@ mod tests {
|
|||||||
&authority_keypair_file,
|
&authority_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(
|
parse_command(&test_authorize_nonce_account, &default_signer, &mut None).unwrap(),
|
||||||
&test_authorize_nonce_account,
|
|
||||||
&default_keypair_file,
|
|
||||||
&mut None
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::AuthorizeNonceAccount {
|
command: CliCommand::AuthorizeNonceAccount {
|
||||||
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
nonce_account: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
||||||
@ -728,7 +622,7 @@ mod tests {
|
|||||||
"50",
|
"50",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::CreateNonceAccount {
|
command: CliCommand::CreateNonceAccount {
|
||||||
nonce_account: 1,
|
nonce_account: 1,
|
||||||
@ -753,7 +647,7 @@ mod tests {
|
|||||||
&authority_keypair_file,
|
&authority_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::CreateNonceAccount {
|
command: CliCommand::CreateNonceAccount {
|
||||||
nonce_account: 1,
|
nonce_account: 1,
|
||||||
@ -775,7 +669,7 @@ mod tests {
|
|||||||
&nonce_account_string,
|
&nonce_account_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_get_nonce, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_get_nonce, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::GetNonce(nonce_account_keypair.pubkey()),
|
command: CliCommand::GetNonce(nonce_account_keypair.pubkey()),
|
||||||
signers: vec![],
|
signers: vec![],
|
||||||
@ -789,7 +683,7 @@ mod tests {
|
|||||||
.get_matches_from(vec!["test", "new-nonce", &keypair_file]);
|
.get_matches_from(vec!["test", "new-nonce", &keypair_file]);
|
||||||
let nonce_account = read_keypair_file(&keypair_file).unwrap();
|
let nonce_account = read_keypair_file(&keypair_file).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_new_nonce, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_new_nonce, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::NewNonce {
|
command: CliCommand::NewNonce {
|
||||||
nonce_account: nonce_account.pubkey(),
|
nonce_account: nonce_account.pubkey(),
|
||||||
@ -809,7 +703,7 @@ mod tests {
|
|||||||
]);
|
]);
|
||||||
let nonce_account = read_keypair_file(&keypair_file).unwrap();
|
let nonce_account = read_keypair_file(&keypair_file).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_new_nonce, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_new_nonce, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::NewNonce {
|
command: CliCommand::NewNonce {
|
||||||
nonce_account: nonce_account.pubkey(),
|
nonce_account: nonce_account.pubkey(),
|
||||||
@ -829,7 +723,7 @@ mod tests {
|
|||||||
&nonce_account_string,
|
&nonce_account_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::ShowNonceAccount {
|
command: CliCommand::ShowNonceAccount {
|
||||||
nonce_account_pubkey: nonce_account_keypair.pubkey(),
|
nonce_account_pubkey: nonce_account_keypair.pubkey(),
|
||||||
@ -850,7 +744,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(
|
parse_command(
|
||||||
&test_withdraw_from_nonce_account,
|
&test_withdraw_from_nonce_account,
|
||||||
&default_keypair_file,
|
&default_signer,
|
||||||
&mut None
|
&mut None
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
@ -878,7 +772,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(
|
parse_command(
|
||||||
&test_withdraw_from_nonce_account,
|
&test_withdraw_from_nonce_account,
|
||||||
&default_keypair_file,
|
&default_signer,
|
||||||
&mut None
|
&mut None
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
@ -913,14 +807,14 @@ mod tests {
|
|||||||
if let CliError::InvalidNonce(err) =
|
if let CliError::InvalidNonce(err) =
|
||||||
check_nonce_account(&invalid_owner.unwrap(), &nonce_pubkey, &blockhash).unwrap_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);
|
let invalid_data = Account::new_data(1, &"invalid", &system_program::ID);
|
||||||
if let CliError::InvalidNonce(err) =
|
if let CliError::InvalidNonce(err) =
|
||||||
check_nonce_account(&invalid_data.unwrap(), &nonce_pubkey, &blockhash).unwrap_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 {
|
let data = Versions::new_current(State::Initialized(nonce::state::Data {
|
||||||
@ -932,7 +826,7 @@ mod tests {
|
|||||||
if let CliError::InvalidNonce(err) =
|
if let CliError::InvalidNonce(err) =
|
||||||
check_nonce_account(&invalid_hash.unwrap(), &nonce_pubkey, &blockhash).unwrap_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 {
|
let data = Versions::new_current(State::Initialized(nonce::state::Data {
|
||||||
@ -944,7 +838,7 @@ mod tests {
|
|||||||
if let CliError::InvalidNonce(err) =
|
if let CliError::InvalidNonce(err) =
|
||||||
check_nonce_account(&invalid_authority.unwrap(), &nonce_pubkey, &blockhash).unwrap_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);
|
let data = Versions::new_current(State::Uninitialized);
|
||||||
@ -952,7 +846,7 @@ mod tests {
|
|||||||
if let CliError::InvalidNonce(err) =
|
if let CliError::InvalidNonce(err) =
|
||||||
check_nonce_account(&invalid_state.unwrap(), &nonce_pubkey, &blockhash).unwrap_err()
|
check_nonce_account(&invalid_state.unwrap(), &nonce_pubkey, &blockhash).unwrap_err()
|
||||||
{
|
{
|
||||||
assert_eq!(err, CliNonceError::InvalidStateForOperation,);
|
assert_eq!(err, Error::InvalidStateForOperation,);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -964,14 +858,14 @@ mod tests {
|
|||||||
let system_account = Account::new(1, 0, &system_program::id());
|
let system_account = Account::new(1, 0, &system_program::id());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
account_identity_ok(&system_account),
|
account_identity_ok(&system_account),
|
||||||
Err(CliNonceError::UnexpectedDataSize),
|
Err(Error::UnexpectedDataSize),
|
||||||
);
|
);
|
||||||
|
|
||||||
let other_program = Pubkey::new(&[1u8; 32]);
|
let other_program = Pubkey::new(&[1u8; 32]);
|
||||||
let other_account_no_data = Account::new(1, 0, &other_program);
|
let other_account_no_data = Account::new(1, 0, &other_program);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
account_identity_ok(&other_account_no_data),
|
account_identity_ok(&other_account_no_data),
|
||||||
Err(CliNonceError::InvalidAccountOwner),
|
Err(Error::InvalidAccountOwner),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -996,7 +890,7 @@ mod tests {
|
|||||||
let wrong_data_size_account = Account::new(1, 1, &system_program::id());
|
let wrong_data_size_account = Account::new(1, 1, &system_program::id());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
state_from_account(&wrong_data_size_account),
|
state_from_account(&wrong_data_size_account),
|
||||||
Err(CliNonceError::InvalidAccountData),
|
Err(Error::InvalidAccountData),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1006,11 +900,11 @@ mod tests {
|
|||||||
let state = state_from_account(&nonce_account).unwrap();
|
let state = state_from_account(&nonce_account).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
data_from_state(&state),
|
data_from_state(&state),
|
||||||
Err(CliNonceError::InvalidStateForOperation)
|
Err(Error::InvalidStateForOperation)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
data_from_account(&nonce_account),
|
data_from_account(&nonce_account),
|
||||||
Err(CliNonceError::InvalidStateForOperation)
|
Err(Error::InvalidStateForOperation)
|
||||||
);
|
);
|
||||||
|
|
||||||
let data = nonce::state::Data {
|
let data = nonce::state::Data {
|
||||||
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
194
cli/src/stake.rs
194
cli/src/stake.rs
@ -1,18 +1,29 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
checks::{check_account_for_fee, check_unique_pubkeys},
|
checks::{check_account_for_fee, check_unique_pubkeys},
|
||||||
cli::{
|
cli::{
|
||||||
fee_payer_arg, generate_unique_signers, log_instruction_custom_error, nonce_authority_arg,
|
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
|
||||||
return_signers, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult,
|
ProcessResult,
|
||||||
SignerIndex, FEE_PAYER_ARG,
|
|
||||||
},
|
},
|
||||||
cli_output::{CliStakeHistory, CliStakeHistoryEntry, CliStakeState, CliStakeType},
|
nonce::check_nonce_account,
|
||||||
nonce::{check_nonce_account, nonce_arg, NONCE_ARG, NONCE_AUTHORITY_ARG},
|
|
||||||
offline::{blockhash_query::BlockhashQuery, *},
|
|
||||||
spend_utils::{resolve_spend_tx_and_check_account_balances, SpendAmount},
|
spend_utils::{resolve_spend_tx_and_check_account_balances, SpendAmount},
|
||||||
};
|
};
|
||||||
use clap::{App, Arg, ArgGroup, ArgMatches, SubCommand};
|
use clap::{App, Arg, ArgGroup, ArgMatches, SubCommand};
|
||||||
use solana_clap_utils::{input_parsers::*, input_validators::*, offline::*, ArgConstant};
|
use solana_clap_utils::{
|
||||||
use solana_client::{rpc_client::RpcClient, rpc_request::DELINQUENT_VALIDATOR_SLOT_DISTANCE};
|
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, rpc_client::RpcClient,
|
||||||
|
rpc_request::DELINQUENT_VALIDATOR_SLOT_DISTANCE,
|
||||||
|
};
|
||||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account_utils::StateMut,
|
account_utils::StateMut,
|
||||||
@ -142,8 +153,7 @@ impl StakeSubCommands for App<'_, '_> {
|
|||||||
.help("Source account of funds [default: cli config keypair]"),
|
.help("Source account of funds [default: cli config keypair]"),
|
||||||
)
|
)
|
||||||
.offline_args()
|
.offline_args()
|
||||||
.arg(nonce_arg())
|
.nonce_args()
|
||||||
.arg(nonce_authority_arg())
|
|
||||||
.arg(fee_payer_arg())
|
.arg(fee_payer_arg())
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
@ -172,8 +182,7 @@ impl StakeSubCommands for App<'_, '_> {
|
|||||||
)
|
)
|
||||||
.arg(stake_authority_arg())
|
.arg(stake_authority_arg())
|
||||||
.offline_args()
|
.offline_args()
|
||||||
.arg(nonce_arg())
|
.nonce_args()
|
||||||
.arg(nonce_authority_arg())
|
|
||||||
.arg(fee_payer_arg())
|
.arg(fee_payer_arg())
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
@ -203,8 +212,7 @@ impl StakeSubCommands for App<'_, '_> {
|
|||||||
.arg(stake_authority_arg())
|
.arg(stake_authority_arg())
|
||||||
.arg(withdraw_authority_arg())
|
.arg(withdraw_authority_arg())
|
||||||
.offline_args()
|
.offline_args()
|
||||||
.arg(nonce_arg())
|
.nonce_args()
|
||||||
.arg(nonce_authority_arg())
|
|
||||||
.arg(fee_payer_arg())
|
.arg(fee_payer_arg())
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
@ -219,8 +227,7 @@ impl StakeSubCommands for App<'_, '_> {
|
|||||||
)
|
)
|
||||||
.arg(stake_authority_arg())
|
.arg(stake_authority_arg())
|
||||||
.offline_args()
|
.offline_args()
|
||||||
.arg(nonce_arg())
|
.nonce_args()
|
||||||
.arg(nonce_authority_arg())
|
|
||||||
.arg(fee_payer_arg())
|
.arg(fee_payer_arg())
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
@ -260,8 +267,7 @@ impl StakeSubCommands for App<'_, '_> {
|
|||||||
)
|
)
|
||||||
.arg(stake_authority_arg())
|
.arg(stake_authority_arg())
|
||||||
.offline_args()
|
.offline_args()
|
||||||
.arg(nonce_arg())
|
.nonce_args()
|
||||||
.arg(nonce_authority_arg())
|
|
||||||
.arg(fee_payer_arg())
|
.arg(fee_payer_arg())
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
@ -283,8 +289,7 @@ impl StakeSubCommands for App<'_, '_> {
|
|||||||
)
|
)
|
||||||
.arg(stake_authority_arg())
|
.arg(stake_authority_arg())
|
||||||
.offline_args()
|
.offline_args()
|
||||||
.arg(nonce_arg())
|
.nonce_args()
|
||||||
.arg(nonce_authority_arg())
|
|
||||||
.arg(fee_payer_arg())
|
.arg(fee_payer_arg())
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
@ -315,8 +320,7 @@ impl StakeSubCommands for App<'_, '_> {
|
|||||||
)
|
)
|
||||||
.arg(withdraw_authority_arg())
|
.arg(withdraw_authority_arg())
|
||||||
.offline_args()
|
.offline_args()
|
||||||
.arg(nonce_arg())
|
.nonce_args()
|
||||||
.arg(nonce_authority_arg())
|
|
||||||
.arg(fee_payer_arg())
|
.arg(fee_payer_arg())
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("custodian")
|
Arg::with_name("custodian")
|
||||||
@ -371,8 +375,7 @@ impl StakeSubCommands for App<'_, '_> {
|
|||||||
.help("Keypair of the existing custodian [default: cli config pubkey]")
|
.help("Keypair of the existing custodian [default: cli config pubkey]")
|
||||||
)
|
)
|
||||||
.offline_args()
|
.offline_args()
|
||||||
.arg(nonce_arg())
|
.nonce_args()
|
||||||
.arg(nonce_authority_arg())
|
|
||||||
.arg(fee_payer_arg())
|
.arg(fee_payer_arg())
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
@ -409,7 +412,7 @@ impl StakeSubCommands for App<'_, '_> {
|
|||||||
|
|
||||||
pub fn parse_stake_create_account(
|
pub fn parse_stake_create_account(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let seed = matches.value_of("seed").map(|s| s.to_string());
|
let seed = matches.value_of("seed").map(|s| s.to_string());
|
||||||
@ -434,7 +437,7 @@ pub fn parse_stake_create_account(
|
|||||||
bulk_signers.push(nonce_authority);
|
bulk_signers.push(nonce_authority);
|
||||||
}
|
}
|
||||||
let signer_info =
|
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 {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::CreateStakeAccount {
|
command: CliCommand::CreateStakeAccount {
|
||||||
@ -461,7 +464,7 @@ pub fn parse_stake_create_account(
|
|||||||
|
|
||||||
pub fn parse_stake_delegate_stake(
|
pub fn parse_stake_delegate_stake(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let stake_account_pubkey =
|
let stake_account_pubkey =
|
||||||
@ -483,7 +486,7 @@ pub fn parse_stake_delegate_stake(
|
|||||||
bulk_signers.push(nonce_authority);
|
bulk_signers.push(nonce_authority);
|
||||||
}
|
}
|
||||||
let signer_info =
|
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 {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::DelegateStake {
|
command: CliCommand::DelegateStake {
|
||||||
@ -503,7 +506,7 @@ pub fn parse_stake_delegate_stake(
|
|||||||
|
|
||||||
pub fn parse_stake_authorize(
|
pub fn parse_stake_authorize(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let stake_account_pubkey =
|
let stake_account_pubkey =
|
||||||
@ -555,7 +558,7 @@ pub fn parse_stake_authorize(
|
|||||||
bulk_signers.push(nonce_authority);
|
bulk_signers.push(nonce_authority);
|
||||||
}
|
}
|
||||||
let signer_info =
|
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
|
let new_authorizations = new_authorizations
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -586,7 +589,7 @@ pub fn parse_stake_authorize(
|
|||||||
|
|
||||||
pub fn parse_split_stake(
|
pub fn parse_split_stake(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let stake_account_pubkey =
|
let stake_account_pubkey =
|
||||||
@ -610,7 +613,7 @@ pub fn parse_split_stake(
|
|||||||
bulk_signers.push(nonce_authority);
|
bulk_signers.push(nonce_authority);
|
||||||
}
|
}
|
||||||
let signer_info =
|
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 {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::SplitStake {
|
command: CliCommand::SplitStake {
|
||||||
@ -631,7 +634,7 @@ pub fn parse_split_stake(
|
|||||||
|
|
||||||
pub fn parse_merge_stake(
|
pub fn parse_merge_stake(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let stake_account_pubkey =
|
let stake_account_pubkey =
|
||||||
@ -653,7 +656,7 @@ pub fn parse_merge_stake(
|
|||||||
bulk_signers.push(nonce_authority);
|
bulk_signers.push(nonce_authority);
|
||||||
}
|
}
|
||||||
let signer_info =
|
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 {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::MergeStake {
|
command: CliCommand::MergeStake {
|
||||||
@ -672,7 +675,7 @@ pub fn parse_merge_stake(
|
|||||||
|
|
||||||
pub fn parse_stake_deactivate_stake(
|
pub fn parse_stake_deactivate_stake(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let stake_account_pubkey =
|
let stake_account_pubkey =
|
||||||
@ -691,7 +694,7 @@ pub fn parse_stake_deactivate_stake(
|
|||||||
bulk_signers.push(nonce_authority);
|
bulk_signers.push(nonce_authority);
|
||||||
}
|
}
|
||||||
let signer_info =
|
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 {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::DeactivateStake {
|
command: CliCommand::DeactivateStake {
|
||||||
@ -709,7 +712,7 @@ pub fn parse_stake_deactivate_stake(
|
|||||||
|
|
||||||
pub fn parse_stake_withdraw_stake(
|
pub fn parse_stake_withdraw_stake(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let stake_account_pubkey =
|
let stake_account_pubkey =
|
||||||
@ -735,7 +738,7 @@ pub fn parse_stake_withdraw_stake(
|
|||||||
bulk_signers.push(custodian);
|
bulk_signers.push(custodian);
|
||||||
}
|
}
|
||||||
let signer_info =
|
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 {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::WithdrawStake {
|
command: CliCommand::WithdrawStake {
|
||||||
@ -756,7 +759,7 @@ pub fn parse_stake_withdraw_stake(
|
|||||||
|
|
||||||
pub fn parse_stake_set_lockup(
|
pub fn parse_stake_set_lockup(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let stake_account_pubkey =
|
let stake_account_pubkey =
|
||||||
@ -779,7 +782,7 @@ pub fn parse_stake_set_lockup(
|
|||||||
bulk_signers.push(nonce_authority);
|
bulk_signers.push(nonce_authority);
|
||||||
}
|
}
|
||||||
let signer_info =
|
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 {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::StakeSetLockup {
|
command: CliCommand::StakeSetLockup {
|
||||||
@ -939,7 +942,7 @@ pub fn process_create_stake_account(
|
|||||||
let mut tx = Transaction::new_unsigned(message);
|
let mut tx = Transaction::new_unsigned(message);
|
||||||
if sign_only {
|
if sign_only {
|
||||||
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
||||||
return_signers(&tx, &config)
|
return_signers(&tx, &config.output_format)
|
||||||
} else {
|
} else {
|
||||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||||
@ -994,7 +997,7 @@ pub fn process_stake_authorize(
|
|||||||
|
|
||||||
if sign_only {
|
if sign_only {
|
||||||
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
||||||
return_signers(&tx, &config)
|
return_signers(&tx, &config.output_format)
|
||||||
} else {
|
} else {
|
||||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||||
if let Some(nonce_account) = &nonce_account {
|
if let Some(nonce_account) = &nonce_account {
|
||||||
@ -1048,7 +1051,7 @@ pub fn process_deactivate_stake_account(
|
|||||||
|
|
||||||
if sign_only {
|
if sign_only {
|
||||||
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
||||||
return_signers(&tx, &config)
|
return_signers(&tx, &config.output_format)
|
||||||
} else {
|
} else {
|
||||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||||
if let Some(nonce_account) = &nonce_account {
|
if let Some(nonce_account) = &nonce_account {
|
||||||
@ -1111,7 +1114,7 @@ pub fn process_withdraw_stake(
|
|||||||
|
|
||||||
if sign_only {
|
if sign_only {
|
||||||
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
||||||
return_signers(&tx, &config)
|
return_signers(&tx, &config.output_format)
|
||||||
} else {
|
} else {
|
||||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||||
if let Some(nonce_account) = &nonce_account {
|
if let Some(nonce_account) = &nonce_account {
|
||||||
@ -1245,7 +1248,7 @@ pub fn process_split_stake(
|
|||||||
|
|
||||||
if sign_only {
|
if sign_only {
|
||||||
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
||||||
return_signers(&tx, &config)
|
return_signers(&tx, &config.output_format)
|
||||||
} else {
|
} else {
|
||||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||||
if let Some(nonce_account) = &nonce_account {
|
if let Some(nonce_account) = &nonce_account {
|
||||||
@ -1338,7 +1341,7 @@ pub fn process_merge_stake(
|
|||||||
|
|
||||||
if sign_only {
|
if sign_only {
|
||||||
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
||||||
return_signers(&tx, &config)
|
return_signers(&tx, &config.output_format)
|
||||||
} else {
|
} else {
|
||||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||||
if let Some(nonce_account) = &nonce_account {
|
if let Some(nonce_account) = &nonce_account {
|
||||||
@ -1395,7 +1398,7 @@ pub fn process_stake_set_lockup(
|
|||||||
|
|
||||||
if sign_only {
|
if sign_only {
|
||||||
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
||||||
return_signers(&tx, &config)
|
return_signers(&tx, &config.output_format)
|
||||||
} else {
|
} else {
|
||||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||||
if let Some(nonce_account) = &nonce_account {
|
if let Some(nonce_account) = &nonce_account {
|
||||||
@ -1648,7 +1651,7 @@ pub fn process_delegate_stake(
|
|||||||
|
|
||||||
if sign_only {
|
if sign_only {
|
||||||
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
tx.try_partial_sign(&config.signers, recent_blockhash)?;
|
||||||
return_signers(&tx, &config)
|
return_signers(&tx, &config.output_format)
|
||||||
} else {
|
} else {
|
||||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||||
if let Some(nonce_account) = &nonce_account {
|
if let Some(nonce_account) = &nonce_account {
|
||||||
@ -1670,6 +1673,7 @@ pub fn process_delegate_stake(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::cli::{app, parse_command};
|
use crate::cli::{app, parse_command};
|
||||||
|
use solana_client::blockhash_query;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
signature::{
|
signature::{
|
||||||
@ -1690,6 +1694,10 @@ mod tests {
|
|||||||
let default_keypair = Keypair::new();
|
let default_keypair = Keypair::new();
|
||||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
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 (keypair_file, mut tmp_file) = make_tmp_file();
|
||||||
let stake_account_keypair = Keypair::new();
|
let stake_account_keypair = Keypair::new();
|
||||||
write_keypair(&stake_account_keypair, tmp_file.as_file_mut()).unwrap();
|
write_keypair(&stake_account_keypair, tmp_file.as_file_mut()).unwrap();
|
||||||
@ -1717,7 +1725,7 @@ mod tests {
|
|||||||
&new_withdraw_string,
|
&new_withdraw_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -1751,7 +1759,7 @@ mod tests {
|
|||||||
&withdraw_authority_keypair_file,
|
&withdraw_authority_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -1789,7 +1797,7 @@ mod tests {
|
|||||||
&withdraw_authority_keypair_file,
|
&withdraw_authority_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -1819,7 +1827,7 @@ mod tests {
|
|||||||
&new_stake_string,
|
&new_stake_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -1843,7 +1851,7 @@ mod tests {
|
|||||||
&stake_authority_keypair_file,
|
&stake_authority_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -1873,7 +1881,7 @@ mod tests {
|
|||||||
&withdraw_authority_keypair_file,
|
&withdraw_authority_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -1900,7 +1908,7 @@ mod tests {
|
|||||||
&new_withdraw_string,
|
&new_withdraw_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -1928,7 +1936,7 @@ mod tests {
|
|||||||
&withdraw_authority_keypair_file,
|
&withdraw_authority_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_stake_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_stake_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -1966,7 +1974,7 @@ mod tests {
|
|||||||
"--sign-only",
|
"--sign-only",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -1999,7 +2007,7 @@ mod tests {
|
|||||||
&pubkey.to_string(),
|
&pubkey.to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2045,7 +2053,7 @@ mod tests {
|
|||||||
&pubkey2.to_string(),
|
&pubkey2.to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2077,7 +2085,7 @@ mod tests {
|
|||||||
&blockhash_string,
|
&blockhash_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2114,7 +2122,7 @@ mod tests {
|
|||||||
&nonce_keypair_file,
|
&nonce_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2150,7 +2158,7 @@ mod tests {
|
|||||||
&fee_payer_keypair_file,
|
&fee_payer_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2184,7 +2192,7 @@ mod tests {
|
|||||||
&signer,
|
&signer,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_authorize, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_authorize, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::StakeAuthorize {
|
command: CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2225,7 +2233,7 @@ mod tests {
|
|||||||
"43",
|
"43",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::CreateStakeAccount {
|
command: CliCommand::CreateStakeAccount {
|
||||||
stake_account: 1,
|
stake_account: 1,
|
||||||
@ -2266,12 +2274,7 @@ mod tests {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(
|
parse_command(&test_create_stake_account2, &default_signer, &mut None).unwrap(),
|
||||||
&test_create_stake_account2,
|
|
||||||
&default_keypair_file,
|
|
||||||
&mut None
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::CreateStakeAccount {
|
command: CliCommand::CreateStakeAccount {
|
||||||
stake_account: 1,
|
stake_account: 1,
|
||||||
@ -2324,12 +2327,7 @@ mod tests {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(
|
parse_command(&test_create_stake_account2, &default_signer, &mut None).unwrap(),
|
||||||
&test_create_stake_account2,
|
|
||||||
&default_keypair_file,
|
|
||||||
&mut None
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::CreateStakeAccount {
|
command: CliCommand::CreateStakeAccount {
|
||||||
stake_account: 1,
|
stake_account: 1,
|
||||||
@ -2365,7 +2363,7 @@ mod tests {
|
|||||||
&vote_account_string,
|
&vote_account_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DelegateStake {
|
command: CliCommand::DelegateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2394,7 +2392,7 @@ mod tests {
|
|||||||
&stake_authority_keypair_file,
|
&stake_authority_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DelegateStake {
|
command: CliCommand::DelegateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2425,7 +2423,7 @@ mod tests {
|
|||||||
&vote_account_string,
|
&vote_account_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DelegateStake {
|
command: CliCommand::DelegateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2454,7 +2452,7 @@ mod tests {
|
|||||||
&blockhash_string,
|
&blockhash_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DelegateStake {
|
command: CliCommand::DelegateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2484,7 +2482,7 @@ mod tests {
|
|||||||
"--sign-only",
|
"--sign-only",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DelegateStake {
|
command: CliCommand::DelegateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2518,7 +2516,7 @@ mod tests {
|
|||||||
&key1.to_string(),
|
&key1.to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DelegateStake {
|
command: CliCommand::DelegateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2564,7 +2562,7 @@ mod tests {
|
|||||||
&key2.to_string(),
|
&key2.to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DelegateStake {
|
command: CliCommand::DelegateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2601,7 +2599,7 @@ mod tests {
|
|||||||
&fee_payer_keypair_file,
|
&fee_payer_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_delegate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_delegate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DelegateStake {
|
command: CliCommand::DelegateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2631,7 +2629,7 @@ mod tests {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_withdraw_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_withdraw_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::WithdrawStake {
|
command: CliCommand::WithdrawStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2661,7 +2659,7 @@ mod tests {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_withdraw_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_withdraw_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::WithdrawStake {
|
command: CliCommand::WithdrawStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2696,7 +2694,7 @@ mod tests {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_withdraw_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_withdraw_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::WithdrawStake {
|
command: CliCommand::WithdrawStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2739,7 +2737,7 @@ mod tests {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_withdraw_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_withdraw_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::WithdrawStake {
|
command: CliCommand::WithdrawStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2772,7 +2770,7 @@ mod tests {
|
|||||||
&stake_account_string,
|
&stake_account_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DeactivateStake {
|
command: CliCommand::DeactivateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2796,7 +2794,7 @@ mod tests {
|
|||||||
&stake_authority_keypair_file,
|
&stake_authority_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DeactivateStake {
|
command: CliCommand::DeactivateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2827,7 +2825,7 @@ mod tests {
|
|||||||
&blockhash_string,
|
&blockhash_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DeactivateStake {
|
command: CliCommand::DeactivateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2854,7 +2852,7 @@ mod tests {
|
|||||||
"--sign-only",
|
"--sign-only",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DeactivateStake {
|
command: CliCommand::DeactivateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2885,7 +2883,7 @@ mod tests {
|
|||||||
&key1.to_string(),
|
&key1.to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DeactivateStake {
|
command: CliCommand::DeactivateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2928,7 +2926,7 @@ mod tests {
|
|||||||
&key2.to_string(),
|
&key2.to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DeactivateStake {
|
command: CliCommand::DeactivateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2959,7 +2957,7 @@ mod tests {
|
|||||||
&fee_payer_keypair_file,
|
&fee_payer_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_deactivate_stake, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_deactivate_stake, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::DeactivateStake {
|
command: CliCommand::DeactivateStake {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
@ -2993,7 +2991,7 @@ mod tests {
|
|||||||
"50",
|
"50",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::SplitStake {
|
command: CliCommand::SplitStake {
|
||||||
stake_account_pubkey: stake_account_keypair.pubkey(),
|
stake_account_pubkey: stake_account_keypair.pubkey(),
|
||||||
@ -3054,7 +3052,7 @@ mod tests {
|
|||||||
&stake_signer,
|
&stake_signer,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::SplitStake {
|
command: CliCommand::SplitStake {
|
||||||
stake_account_pubkey: stake_account_keypair.pubkey(),
|
stake_account_pubkey: stake_account_keypair.pubkey(),
|
||||||
@ -3094,7 +3092,7 @@ mod tests {
|
|||||||
&source_stake_account_pubkey.to_string(),
|
&source_stake_account_pubkey.to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::MergeStake {
|
command: CliCommand::MergeStake {
|
||||||
stake_account_pubkey: stake_account_keypair.pubkey(),
|
stake_account_pubkey: stake_account_keypair.pubkey(),
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
|
cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
|
||||||
cli_output::{CliValidatorInfo, CliValidatorInfoVec},
|
|
||||||
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
||||||
};
|
};
|
||||||
use bincode::deserialize;
|
use bincode::deserialize;
|
||||||
@ -13,8 +12,9 @@ use solana_account_decoder::validator_info::{
|
|||||||
use solana_clap_utils::{
|
use solana_clap_utils::{
|
||||||
input_parsers::pubkey_of,
|
input_parsers::pubkey_of,
|
||||||
input_validators::{is_pubkey, is_url},
|
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_client::rpc_client::RpcClient;
|
||||||
use solana_config_program::{config_instruction, get_config_data, ConfigKeys, ConfigState};
|
use solana_config_program::{config_instruction, get_config_data, ConfigKeys, ConfigState};
|
||||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||||
@ -212,7 +212,7 @@ impl ValidatorInfoSubCommands for App<'_, '_> {
|
|||||||
|
|
||||||
pub fn parse_validator_info_command(
|
pub fn parse_validator_info_command(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let info_pubkey = pubkey_of(matches, "info_pubkey");
|
let info_pubkey = pubkey_of(matches, "info_pubkey");
|
||||||
@ -224,12 +224,7 @@ pub fn parse_validator_info_command(
|
|||||||
force_keybase: matches.is_present("force"),
|
force_keybase: matches.is_present("force"),
|
||||||
info_pubkey,
|
info_pubkey,
|
||||||
},
|
},
|
||||||
signers: vec![signer_from_path(
|
signers: vec![default_signer.signer_from_path(matches, wallet_manager)?],
|
||||||
matches,
|
|
||||||
default_signer_path,
|
|
||||||
"keypair",
|
|
||||||
wallet_manager,
|
|
||||||
)?],
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
checks::{check_account_for_fee, check_unique_pubkeys},
|
checks::{check_account_for_fee, check_unique_pubkeys},
|
||||||
cli::{
|
cli::{
|
||||||
generate_unique_signers, log_instruction_custom_error, CliCommand, CliCommandInfo,
|
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
|
||||||
CliConfig, CliError, ProcessResult, SignerIndex,
|
ProcessResult,
|
||||||
},
|
},
|
||||||
cli_output::{CliEpochVotingHistory, CliLockout, CliVoteAccount},
|
|
||||||
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
||||||
};
|
};
|
||||||
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
||||||
@ -12,7 +11,9 @@ use solana_clap_utils::{
|
|||||||
commitment::{commitment_arg, COMMITMENT_ARG},
|
commitment::{commitment_arg, COMMITMENT_ARG},
|
||||||
input_parsers::*,
|
input_parsers::*,
|
||||||
input_validators::*,
|
input_validators::*,
|
||||||
|
keypair::{DefaultSigner, SignerIndex},
|
||||||
};
|
};
|
||||||
|
use solana_cli_output::{CliEpochVotingHistory, CliLockout, CliVoteAccount};
|
||||||
use solana_client::rpc_client::RpcClient;
|
use solana_client::rpc_client::RpcClient;
|
||||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@ -250,7 +251,7 @@ impl VoteSubCommands for App<'_, '_> {
|
|||||||
|
|
||||||
pub fn parse_create_vote_account(
|
pub fn parse_create_vote_account(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let (vote_account, vote_account_pubkey) = signer_of(matches, "vote_account", wallet_manager)?;
|
let (vote_account, vote_account_pubkey) = signer_of(matches, "vote_account", wallet_manager)?;
|
||||||
@ -262,10 +263,9 @@ pub fn parse_create_vote_account(
|
|||||||
let authorized_withdrawer = pubkey_of_signer(matches, "authorized_withdrawer", wallet_manager)?;
|
let authorized_withdrawer = pubkey_of_signer(matches, "authorized_withdrawer", wallet_manager)?;
|
||||||
|
|
||||||
let payer_provided = None;
|
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],
|
vec![payer_provided, vote_account, identity_account],
|
||||||
matches,
|
matches,
|
||||||
default_signer_path,
|
|
||||||
wallet_manager,
|
wallet_manager,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -284,7 +284,7 @@ pub fn parse_create_vote_account(
|
|||||||
|
|
||||||
pub fn parse_vote_authorize(
|
pub fn parse_vote_authorize(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
vote_authorize: VoteAuthorize,
|
vote_authorize: VoteAuthorize,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
@ -295,10 +295,9 @@ pub fn parse_vote_authorize(
|
|||||||
let (authorized, _) = signer_of(matches, "authorized", wallet_manager)?;
|
let (authorized, _) = signer_of(matches, "authorized", wallet_manager)?;
|
||||||
|
|
||||||
let payer_provided = None;
|
let payer_provided = None;
|
||||||
let signer_info = generate_unique_signers(
|
let signer_info = default_signer.generate_unique_signers(
|
||||||
vec![payer_provided, authorized],
|
vec![payer_provided, authorized],
|
||||||
matches,
|
matches,
|
||||||
default_signer_path,
|
|
||||||
wallet_manager,
|
wallet_manager,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -314,7 +313,7 @@ pub fn parse_vote_authorize(
|
|||||||
|
|
||||||
pub fn parse_vote_update_validator(
|
pub fn parse_vote_update_validator(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let vote_account_pubkey =
|
let vote_account_pubkey =
|
||||||
@ -325,10 +324,9 @@ pub fn parse_vote_update_validator(
|
|||||||
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
|
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
|
||||||
|
|
||||||
let payer_provided = None;
|
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],
|
vec![payer_provided, authorized_withdrawer, new_identity_account],
|
||||||
matches,
|
matches,
|
||||||
default_signer_path,
|
|
||||||
wallet_manager,
|
wallet_manager,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -344,7 +342,7 @@ pub fn parse_vote_update_validator(
|
|||||||
|
|
||||||
pub fn parse_vote_update_commission(
|
pub fn parse_vote_update_commission(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let vote_account_pubkey =
|
let vote_account_pubkey =
|
||||||
@ -354,10 +352,9 @@ pub fn parse_vote_update_commission(
|
|||||||
let commission = value_t_or_exit!(matches, "commission", u8);
|
let commission = value_t_or_exit!(matches, "commission", u8);
|
||||||
|
|
||||||
let payer_provided = None;
|
let payer_provided = None;
|
||||||
let signer_info = generate_unique_signers(
|
let signer_info = default_signer.generate_unique_signers(
|
||||||
vec![payer_provided, authorized_withdrawer],
|
vec![payer_provided, authorized_withdrawer],
|
||||||
matches,
|
matches,
|
||||||
default_signer_path,
|
|
||||||
wallet_manager,
|
wallet_manager,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -391,7 +388,7 @@ pub fn parse_vote_get_account_command(
|
|||||||
|
|
||||||
pub fn parse_withdraw_from_vote_account(
|
pub fn parse_withdraw_from_vote_account(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
default_signer_path: &str,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let vote_account_pubkey =
|
let vote_account_pubkey =
|
||||||
@ -404,10 +401,9 @@ pub fn parse_withdraw_from_vote_account(
|
|||||||
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
|
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
|
||||||
|
|
||||||
let payer_provided = None;
|
let payer_provided = None;
|
||||||
let signer_info = generate_unique_signers(
|
let signer_info = default_signer.generate_unique_signers(
|
||||||
vec![payer_provided, withdraw_authority],
|
vec![payer_provided, withdraw_authority],
|
||||||
matches,
|
matches,
|
||||||
default_signer_path,
|
|
||||||
wallet_manager,
|
wallet_manager,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -760,6 +756,10 @@ mod tests {
|
|||||||
let default_keypair = Keypair::new();
|
let default_keypair = Keypair::new();
|
||||||
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
let (default_keypair_file, mut tmp_file) = make_tmp_file();
|
||||||
write_keypair(&default_keypair, tmp_file.as_file_mut()).unwrap();
|
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![
|
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
||||||
"test",
|
"test",
|
||||||
@ -769,7 +769,7 @@ mod tests {
|
|||||||
&pubkey2_string,
|
&pubkey2_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_authorize_voter, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::VoteAuthorize {
|
command: CliCommand::VoteAuthorize {
|
||||||
vote_account_pubkey: pubkey,
|
vote_account_pubkey: pubkey,
|
||||||
@ -792,7 +792,7 @@ mod tests {
|
|||||||
&pubkey2_string,
|
&pubkey2_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_authorize_voter, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::VoteAuthorize {
|
command: CliCommand::VoteAuthorize {
|
||||||
vote_account_pubkey: pubkey,
|
vote_account_pubkey: pubkey,
|
||||||
@ -822,7 +822,7 @@ mod tests {
|
|||||||
"10",
|
"10",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::CreateVoteAccount {
|
command: CliCommand::CreateVoteAccount {
|
||||||
vote_account: 1,
|
vote_account: 1,
|
||||||
@ -851,7 +851,7 @@ mod tests {
|
|||||||
&identity_keypair_file,
|
&identity_keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::CreateVoteAccount {
|
command: CliCommand::CreateVoteAccount {
|
||||||
vote_account: 1,
|
vote_account: 1,
|
||||||
@ -884,7 +884,7 @@ mod tests {
|
|||||||
&authed.to_string(),
|
&authed.to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::CreateVoteAccount {
|
command: CliCommand::CreateVoteAccount {
|
||||||
vote_account: 1,
|
vote_account: 1,
|
||||||
@ -915,7 +915,7 @@ mod tests {
|
|||||||
&authed.to_string(),
|
&authed.to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
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 {
|
CliCommandInfo {
|
||||||
command: CliCommand::CreateVoteAccount {
|
command: CliCommand::CreateVoteAccount {
|
||||||
vote_account: 1,
|
vote_account: 1,
|
||||||
@ -941,7 +941,7 @@ mod tests {
|
|||||||
&keypair_file,
|
&keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_update_validator, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_update_validator, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::VoteUpdateValidator {
|
command: CliCommand::VoteUpdateValidator {
|
||||||
vote_account_pubkey: pubkey,
|
vote_account_pubkey: pubkey,
|
||||||
@ -964,7 +964,7 @@ mod tests {
|
|||||||
&keypair_file,
|
&keypair_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&test_update_commission, &default_keypair_file, &mut None).unwrap(),
|
parse_command(&test_update_commission, &default_signer, &mut None).unwrap(),
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::VoteUpdateCommission {
|
command: CliCommand::VoteUpdateCommission {
|
||||||
vote_account_pubkey: pubkey,
|
vote_account_pubkey: pubkey,
|
||||||
@ -987,12 +987,7 @@ mod tests {
|
|||||||
"42",
|
"42",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(
|
parse_command(&test_withdraw_from_vote_account, &default_signer, &mut None).unwrap(),
|
||||||
&test_withdraw_from_vote_account,
|
|
||||||
&default_keypair_file,
|
|
||||||
&mut None
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::WithdrawFromVoteAccount {
|
command: CliCommand::WithdrawFromVoteAccount {
|
||||||
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
||||||
@ -1013,12 +1008,7 @@ mod tests {
|
|||||||
"ALL",
|
"ALL",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(
|
parse_command(&test_withdraw_from_vote_account, &default_signer, &mut None).unwrap(),
|
||||||
&test_withdraw_from_vote_account,
|
|
||||||
&default_keypair_file,
|
|
||||||
&mut None
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::WithdrawFromVoteAccount {
|
command: CliCommand::WithdrawFromVoteAccount {
|
||||||
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
||||||
@ -1044,12 +1034,7 @@ mod tests {
|
|||||||
&withdraw_authority_file,
|
&withdraw_authority_file,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(
|
parse_command(&test_withdraw_from_vote_account, &default_signer, &mut None).unwrap(),
|
||||||
&test_withdraw_from_vote_account,
|
|
||||||
&default_keypair_file,
|
|
||||||
&mut None
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
CliCommandInfo {
|
CliCommandInfo {
|
||||||
command: CliCommand::WithdrawFromVoteAccount {
|
command: CliCommand::WithdrawFromVoteAccount {
|
||||||
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
use solana_cli::test_utils::check_balance;
|
use solana_cli::test_utils::check_balance;
|
||||||
use solana_cli::{
|
use solana_cli::{
|
||||||
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
|
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,
|
spend_utils::SpendAmount,
|
||||||
};
|
};
|
||||||
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::contact_info::ContactInfo;
|
||||||
use solana_core::validator::{TestValidator, TestValidatorOptions};
|
use solana_core::validator::{TestValidator, TestValidatorOptions};
|
||||||
use solana_faucet::faucet::run_local_faucet;
|
use solana_faucet::faucet::run_local_faucet;
|
||||||
@ -299,8 +298,8 @@ fn test_create_account_with_seed() {
|
|||||||
check_balance(0, &rpc_client, &to_address);
|
check_balance(0, &rpc_client, &to_address);
|
||||||
|
|
||||||
// Fetch nonce hash
|
// Fetch nonce hash
|
||||||
let nonce_hash = nonce::get_account(&rpc_client, &nonce_address)
|
let nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_address)
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
|
|
||||||
|
@ -3,15 +3,14 @@ use serde_json::Value;
|
|||||||
use solana_cli::test_utils::check_balance;
|
use solana_cli::test_utils::check_balance;
|
||||||
use solana_cli::{
|
use solana_cli::{
|
||||||
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig, PayCommand},
|
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,
|
spend_utils::SpendAmount,
|
||||||
};
|
};
|
||||||
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::validator::TestValidator;
|
use solana_core::validator::TestValidator;
|
||||||
use solana_faucet::faucet::run_local_faucet;
|
use solana_faucet::faucet::run_local_faucet;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@ -410,8 +409,8 @@ fn test_nonced_pay_tx() {
|
|||||||
check_balance(minimum_nonce_balance, &rpc_client, &nonce_account.pubkey());
|
check_balance(minimum_nonce_balance, &rpc_client, &nonce_account.pubkey());
|
||||||
|
|
||||||
// Fetch nonce hash
|
// Fetch nonce hash
|
||||||
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
|
|
||||||
@ -433,8 +432,8 @@ fn test_nonced_pay_tx() {
|
|||||||
check_balance(10, &rpc_client, &bob_pubkey);
|
check_balance(10, &rpc_client, &bob_pubkey);
|
||||||
|
|
||||||
// Verify that nonce has been used
|
// Verify that nonce has been used
|
||||||
let nonce_hash2 = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let nonce_hash2 = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
assert_ne!(nonce_hash, nonce_hash2);
|
assert_ne!(nonce_hash, nonce_hash2);
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
use solana_cli::test_utils::check_balance;
|
use solana_cli::test_utils::check_balance;
|
||||||
use solana_cli::{
|
use solana_cli::{
|
||||||
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
|
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,
|
spend_utils::SpendAmount,
|
||||||
};
|
};
|
||||||
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::validator::{TestValidator, TestValidatorOptions};
|
use solana_core::validator::{TestValidator, TestValidatorOptions};
|
||||||
use solana_faucet::faucet::run_local_faucet;
|
use solana_faucet::faucet::run_local_faucet;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@ -502,8 +501,8 @@ fn test_nonced_stake_delegation_and_deactivation() {
|
|||||||
process_command(&config).unwrap();
|
process_command(&config).unwrap();
|
||||||
|
|
||||||
// Fetch nonce hash
|
// Fetch nonce hash
|
||||||
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
|
|
||||||
@ -526,8 +525,8 @@ fn test_nonced_stake_delegation_and_deactivation() {
|
|||||||
process_command(&config).unwrap();
|
process_command(&config).unwrap();
|
||||||
|
|
||||||
// Fetch nonce hash
|
// Fetch nonce hash
|
||||||
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
|
|
||||||
@ -742,8 +741,8 @@ fn test_stake_authorize() {
|
|||||||
process_command(&config).unwrap();
|
process_command(&config).unwrap();
|
||||||
|
|
||||||
// Fetch nonce hash
|
// Fetch nonce hash
|
||||||
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
|
|
||||||
@ -788,8 +787,8 @@ fn test_stake_authorize() {
|
|||||||
};
|
};
|
||||||
assert_eq!(current_authority, online_authority_pubkey);
|
assert_eq!(current_authority, online_authority_pubkey);
|
||||||
|
|
||||||
let new_nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let new_nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
assert_ne!(nonce_hash, new_nonce_hash);
|
assert_ne!(nonce_hash, new_nonce_hash);
|
||||||
@ -1024,8 +1023,8 @@ fn test_stake_split() {
|
|||||||
check_balance(minimum_nonce_balance, &rpc_client, &nonce_account.pubkey());
|
check_balance(minimum_nonce_balance, &rpc_client, &nonce_account.pubkey());
|
||||||
|
|
||||||
// Fetch nonce hash
|
// Fetch nonce hash
|
||||||
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
|
|
||||||
@ -1281,8 +1280,8 @@ fn test_stake_set_lockup() {
|
|||||||
check_balance(minimum_nonce_balance, &rpc_client, &nonce_account_pubkey);
|
check_balance(minimum_nonce_balance, &rpc_client, &nonce_account_pubkey);
|
||||||
|
|
||||||
// Fetch nonce hash
|
// Fetch nonce hash
|
||||||
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
|
|
||||||
@ -1400,8 +1399,8 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
|||||||
process_command(&config).unwrap();
|
process_command(&config).unwrap();
|
||||||
|
|
||||||
// Fetch nonce hash
|
// Fetch nonce hash
|
||||||
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
|
|
||||||
@ -1451,8 +1450,8 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
|||||||
check_balance(50_000, &rpc_client, &stake_pubkey);
|
check_balance(50_000, &rpc_client, &stake_pubkey);
|
||||||
|
|
||||||
// Fetch nonce hash
|
// Fetch nonce hash
|
||||||
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
|
|
||||||
@ -1495,8 +1494,8 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
|||||||
check_balance(42, &rpc_client, &recipient_pubkey);
|
check_balance(42, &rpc_client, &recipient_pubkey);
|
||||||
|
|
||||||
// Fetch nonce hash
|
// Fetch nonce hash
|
||||||
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
|
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
use solana_cli::test_utils::check_balance;
|
use solana_cli::test_utils::check_balance;
|
||||||
use solana_cli::{
|
use solana_cli::{
|
||||||
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
|
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,
|
spend_utils::SpendAmount,
|
||||||
};
|
};
|
||||||
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::validator::{TestValidator, TestValidatorOptions};
|
use solana_core::validator::{TestValidator, TestValidatorOptions};
|
||||||
use solana_faucet::faucet::run_local_faucet;
|
use solana_faucet::faucet::run_local_faucet;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
@ -147,8 +146,8 @@ fn test_transfer() {
|
|||||||
check_balance(49_987 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
|
check_balance(49_987 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
|
||||||
|
|
||||||
// Fetch nonce hash
|
// Fetch nonce hash
|
||||||
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
|
|
||||||
@ -171,8 +170,8 @@ fn test_transfer() {
|
|||||||
process_command(&config).unwrap();
|
process_command(&config).unwrap();
|
||||||
check_balance(49_976 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
|
check_balance(49_976 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
|
||||||
check_balance(30, &rpc_client, &recipient_pubkey);
|
check_balance(30, &rpc_client, &recipient_pubkey);
|
||||||
let new_nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let new_nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
assert_ne!(nonce_hash, new_nonce_hash);
|
assert_ne!(nonce_hash, new_nonce_hash);
|
||||||
@ -188,8 +187,8 @@ fn test_transfer() {
|
|||||||
check_balance(49_975 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
|
check_balance(49_975 - minimum_nonce_balance, &rpc_client, &sender_pubkey);
|
||||||
|
|
||||||
// Fetch nonce hash
|
// Fetch nonce hash
|
||||||
let nonce_hash = nonce::get_account(&rpc_client, &nonce_account.pubkey())
|
let nonce_hash = nonce_utils::get_account(&rpc_client, &nonce_account.pubkey())
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.blockhash;
|
.blockhash;
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use solana_cli::{
|
use solana_cli::{
|
||||||
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
|
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
|
||||||
offline::{blockhash_query::BlockhashQuery, *},
|
|
||||||
spend_utils::SpendAmount,
|
spend_utils::SpendAmount,
|
||||||
test_utils::check_balance,
|
test_utils::check_balance,
|
||||||
};
|
};
|
||||||
use solana_client::rpc_client::RpcClient;
|
use solana_client::{
|
||||||
|
blockhash_query::{self, BlockhashQuery},
|
||||||
|
rpc_client::RpcClient,
|
||||||
|
};
|
||||||
use solana_core::validator::TestValidator;
|
use solana_core::validator::TestValidator;
|
||||||
use solana_faucet::faucet::run_local_faucet;
|
use solana_faucet::faucet::run_local_faucet;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
|
@ -11,6 +11,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bincode = "1.3.1"
|
bincode = "1.3.1"
|
||||||
bs58 = "0.3.1"
|
bs58 = "0.3.1"
|
||||||
|
clap = "2.33.0"
|
||||||
indicatif = "0.14.0"
|
indicatif = "0.14.0"
|
||||||
jsonrpc-core = "14.1.0"
|
jsonrpc-core = "14.1.0"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
@ -20,6 +21,7 @@ serde = "1.0.110"
|
|||||||
serde_derive = "1.0.103"
|
serde_derive = "1.0.103"
|
||||||
serde_json = "1.0.53"
|
serde_json = "1.0.53"
|
||||||
solana-account-decoder = { path = "../account-decoder", version = "1.2.30" }
|
solana-account-decoder = { path = "../account-decoder", version = "1.2.30" }
|
||||||
|
solana-clap-utils = { path = "../clap-utils", version = "1.2.30" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.2.30" }
|
solana-net-utils = { path = "../net-utils", version = "1.2.30" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.2.30" }
|
solana-sdk = { path = "../sdk", version = "1.2.30" }
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "1.2.30" }
|
solana-transaction-status = { path = "../transaction-status", version = "1.2.30" }
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
use super::*;
|
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::{fee_calculator::FeeCalculator, hash::Hash, pubkey::Pubkey};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Source {
|
pub enum Source {
|
||||||
@ -17,8 +24,8 @@ impl Source {
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
Self::NonceAccount(ref pubkey) => {
|
Self::NonceAccount(ref pubkey) => {
|
||||||
let data = nonce::get_account(rpc_client, pubkey)
|
let data = nonce_utils::get_account(rpc_client, pubkey)
|
||||||
.and_then(|ref a| nonce::data_from_account(a))?;
|
.and_then(|ref a| nonce_utils::data_from_account(a))?;
|
||||||
Ok((data.blockhash, data.fee_calculator))
|
Ok((data.blockhash, data.fee_calculator))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,8 +42,8 @@ impl Source {
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
Self::NonceAccount(ref pubkey) => {
|
Self::NonceAccount(ref pubkey) => {
|
||||||
let res = nonce::get_account(rpc_client, pubkey)
|
let res = nonce_utils::get_account(rpc_client, pubkey)
|
||||||
.and_then(|ref a| nonce::data_from_account(a))
|
.and_then(|ref a| nonce_utils::data_from_account(a))
|
||||||
.and_then(|d| {
|
.and_then(|d| {
|
||||||
if d.blockhash == *blockhash {
|
if d.blockhash == *blockhash {
|
||||||
Ok(Some(d.fee_calculator))
|
Ok(Some(d.fee_calculator))
|
||||||
@ -73,7 +80,7 @@ impl BlockhashQuery {
|
|||||||
pub fn new_from_matches(matches: &ArgMatches<'_>) -> Self {
|
pub fn new_from_matches(matches: &ArgMatches<'_>) -> Self {
|
||||||
let blockhash = value_of(matches, BLOCKHASH_ARG.name);
|
let blockhash = value_of(matches, BLOCKHASH_ARG.name);
|
||||||
let sign_only = matches.is_present(SIGN_ONLY_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)
|
BlockhashQuery::new(blockhash, sign_only, nonce_account)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,17 +110,15 @@ impl Default for BlockhashQuery {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{nonce::nonce_arg, offline::blockhash_query::BlockhashQuery};
|
use crate::{
|
||||||
use clap::App;
|
blockhash_query,
|
||||||
use serde_json::{self, json, Value};
|
|
||||||
use solana_account_decoder::{UiAccount, UiAccountEncoding};
|
|
||||||
use solana_client::{
|
|
||||||
rpc_request::RpcRequest,
|
rpc_request::RpcRequest,
|
||||||
rpc_response::{Response, RpcFeeCalculator, RpcResponseContext},
|
rpc_response::{Response, RpcFeeCalculator, RpcResponseContext},
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use clap::App;
|
||||||
account::Account, fee_calculator::FeeCalculator, hash::hash, nonce, system_program,
|
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;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -166,9 +171,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_blockhash_query_new_from_matches_ok() {
|
fn test_blockhash_query_new_from_matches_ok() {
|
||||||
let test_commands = App::new("blockhash_query_test")
|
let test_commands = App::new("blockhash_query_test").nonce_args().offline_args();
|
||||||
.arg(nonce_arg())
|
|
||||||
.offline_args();
|
|
||||||
let blockhash = hash(&[1u8]);
|
let blockhash = hash(&[1u8]);
|
||||||
let blockhash_string = blockhash.to_string();
|
let blockhash_string = blockhash.to_string();
|
||||||
|
|
@ -1,9 +1,11 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
pub mod blockhash_query;
|
||||||
pub mod client_error;
|
pub mod client_error;
|
||||||
pub mod http_sender;
|
pub mod http_sender;
|
||||||
pub mod mock_sender;
|
pub mod mock_sender;
|
||||||
|
pub mod nonce_utils;
|
||||||
pub mod perf_utils;
|
pub mod perf_utils;
|
||||||
pub mod pubsub_client;
|
pub mod pubsub_client;
|
||||||
pub mod rpc_client;
|
pub mod rpc_client;
|
||||||
|
68
client/src/nonce_utils.rs
Normal file
68
client/src/nonce_utils.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
use crate::rpc_client::RpcClient;
|
||||||
|
use solana_sdk::{
|
||||||
|
account::Account,
|
||||||
|
account_utils::StateMut,
|
||||||
|
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> {
|
||||||
|
rpc_client
|
||||||
|
.get_account(nonce_pubkey)
|
||||||
|
.map_err(|e| Error::Client(format!("{}", e)))
|
||||||
|
.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),
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,7 @@ regex = "1"
|
|||||||
serde_json = "1.0.53"
|
serde_json = "1.0.53"
|
||||||
serde_yaml = "0.8.12"
|
serde_yaml = "0.8.12"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.2.30" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.2.30" }
|
||||||
solana-cli = { path = "../cli", version = "1.2.30" }
|
solana-cli-output = { path = "../cli-output", version = "1.2.30" }
|
||||||
solana-ledger = { path = "../ledger", version = "1.2.30" }
|
solana-ledger = { path = "../ledger", version = "1.2.30" }
|
||||||
solana-logger = { path = "../logger", version = "1.2.30" }
|
solana-logger = { path = "../logger", version = "1.2.30" }
|
||||||
solana-measure = { path = "../measure", version = "1.2.30" }
|
solana-measure = { path = "../measure", version = "1.2.30" }
|
||||||
|
@ -4,7 +4,7 @@ use solana_clap_utils::{
|
|||||||
input_parsers::pubkey_of,
|
input_parsers::pubkey_of,
|
||||||
input_validators::{is_slot, is_valid_pubkey},
|
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_ledger::{blockstore::Blockstore, blockstore_db::AccessType};
|
||||||
use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature};
|
use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature};
|
||||||
use solana_transaction_status::UiTransactionEncoding;
|
use solana_transaction_status::UiTransactionEncoding;
|
||||||
|
@ -124,7 +124,7 @@ fn output_slot(
|
|||||||
})
|
})
|
||||||
.map(|transaction_status| transaction_status.into());
|
.map(|transaction_status| transaction_status.into());
|
||||||
|
|
||||||
solana_cli::display::println_transaction(
|
solana_cli_output::display::println_transaction(
|
||||||
&transaction,
|
&transaction,
|
||||||
&transaction_status,
|
&transaction_status,
|
||||||
" ",
|
" ",
|
||||||
|
@ -13,13 +13,7 @@ use std::ffi::OsString;
|
|||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
fn fee_payer_arg<'a, 'b>() -> Arg<'a, 'b> {
|
fn fee_payer_arg<'a, 'b>() -> Arg<'a, 'b> {
|
||||||
Arg::with_name("fee_payer")
|
solana_clap_utils::fee_payer::fee_payer_arg().required(true)
|
||||||
.long("fee-payer")
|
|
||||||
.required(true)
|
|
||||||
.takes_value(true)
|
|
||||||
.value_name("KEYPAIR")
|
|
||||||
.validator(is_valid_signer)
|
|
||||||
.help("Fee payer")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn funding_keypair_arg<'a, 'b>() -> Arg<'a, 'b> {
|
fn funding_keypair_arg<'a, 'b>() -> Arg<'a, 'b> {
|
||||||
|
@ -15,6 +15,7 @@ serde_yaml = "0.8.12"
|
|||||||
solana-clap-utils = { path = "../clap-utils", version = "1.2.30" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.2.30" }
|
||||||
solana-client = { path = "../client", version = "1.2.30" }
|
solana-client = { path = "../client", version = "1.2.30" }
|
||||||
solana-cli-config = { path = "../cli-config", version = "1.2.30" }
|
solana-cli-config = { path = "../cli-config", version = "1.2.30" }
|
||||||
|
solana-cli-output = { path = "../cli-output", version = "1.2.30" }
|
||||||
solana-logger = { path = "../logger", version = "1.2.30" }
|
solana-logger = { path = "../logger", version = "1.2.30" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.2.30" }
|
solana-metrics = { path = "../metrics", version = "1.2.30" }
|
||||||
solana-notifier = { path = "../notifier", version = "1.2.30" }
|
solana-notifier = { path = "../notifier", version = "1.2.30" }
|
||||||
|
@ -14,7 +14,7 @@ log = "0.4.8"
|
|||||||
humantime = "2.0.0"
|
humantime = "2.0.0"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.2.30" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.2.30" }
|
||||||
solana-cli-config = { path = "../cli-config", version = "1.2.30" }
|
solana-cli-config = { path = "../cli-config", version = "1.2.30" }
|
||||||
solana-cli = { path = "../cli", version = "1.2.30" }
|
solana-cli-output = { path = "../cli-output", version = "1.2.30" }
|
||||||
solana-client = { path = "../client", version = "1.2.30" }
|
solana-client = { path = "../client", version = "1.2.30" }
|
||||||
solana-logger = { path = "../logger", version = "1.2.30" }
|
solana-logger = { path = "../logger", version = "1.2.30" }
|
||||||
solana-metrics = { path = "../metrics", version = "1.2.30" }
|
solana-metrics = { path = "../metrics", version = "1.2.30" }
|
||||||
|
@ -184,7 +184,7 @@ fn process_confirmed_block(notifier: &Notifier, slot: Slot, confirmed_block: Con
|
|||||||
|
|
||||||
if notify {
|
if notify {
|
||||||
let mut w = Vec::new();
|
let mut w = Vec::new();
|
||||||
if solana_cli::display::write_transaction(
|
if solana_cli_output::display::write_transaction(
|
||||||
&mut w,
|
&mut w,
|
||||||
&transaction,
|
&transaction,
|
||||||
&rpc_transaction.meta,
|
&rpc_transaction.meta,
|
||||||
|
Reference in New Issue
Block a user