solana-cli: selectively require keypair (#6477)
* Make parse_command consistent * Strip pubkey out of parse_stake_create_account * Move validator-info args into module * Strip pubkey out of parse_validator_info_command * Strip pubkey out of parse_vote_create_account * Strip pubkey out of balance parsing * Strip pubkey out of parse pay * Only verify keypair existence if command requires it * Use struct instead of tuple
This commit is contained in:
parent
564c14a2c6
commit
8319fa05d0
654
cli/src/cli.rs
654
cli/src/cli.rs
|
@ -6,7 +6,7 @@ use chrono::prelude::*;
|
||||||
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
|
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||||
use log::*;
|
use log::*;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
use serde_json::{self, json};
|
use serde_json::{self, json, Value};
|
||||||
use solana_budget_api::budget_instruction::{self, BudgetError};
|
use solana_budget_api::budget_instruction::{self, BudgetError};
|
||||||
use solana_client::{client_error::ClientError, rpc_client::RpcClient};
|
use solana_client::{client_error::ClientError, rpc_client::RpcClient};
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
|
@ -28,9 +28,9 @@ use solana_sdk::{
|
||||||
system_transaction,
|
system_transaction,
|
||||||
transaction::{Transaction, TransactionError},
|
transaction::{Transaction, TransactionError},
|
||||||
};
|
};
|
||||||
use solana_stake_api::stake_state::{Authorized, Lockup, StakeAuthorize};
|
use solana_stake_api::stake_state::{Lockup, StakeAuthorize};
|
||||||
use solana_storage_api::storage_instruction::StorageAccountType;
|
use solana_storage_api::storage_instruction::StorageAccountType;
|
||||||
use solana_vote_api::vote_state::{VoteAuthorize, VoteInit};
|
use solana_vote_api::vote_state::VoteAuthorize;
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
|
@ -63,7 +63,13 @@ pub enum CliCommand {
|
||||||
// Program Deployment
|
// Program Deployment
|
||||||
Deploy(String),
|
Deploy(String),
|
||||||
// Stake Commands
|
// Stake Commands
|
||||||
CreateStakeAccount(Pubkey, Authorized, Lockup, u64),
|
CreateStakeAccount {
|
||||||
|
stake_account_pubkey: Pubkey,
|
||||||
|
staker: Option<Pubkey>,
|
||||||
|
withdrawer: Option<Pubkey>,
|
||||||
|
lockup: Lockup,
|
||||||
|
lamports: u64,
|
||||||
|
},
|
||||||
DeactivateStake(Pubkey),
|
DeactivateStake(Pubkey),
|
||||||
DelegateStake(Pubkey, Pubkey, bool),
|
DelegateStake(Pubkey, Pubkey, bool),
|
||||||
RedeemVoteCredits(Pubkey, Pubkey),
|
RedeemVoteCredits(Pubkey, Pubkey),
|
||||||
|
@ -86,9 +92,19 @@ pub enum CliCommand {
|
||||||
ShowStorageAccount(Pubkey),
|
ShowStorageAccount(Pubkey),
|
||||||
// Validator Info Commands
|
// Validator Info Commands
|
||||||
GetValidatorInfo(Option<Pubkey>),
|
GetValidatorInfo(Option<Pubkey>),
|
||||||
SetValidatorInfo(ValidatorInfo, Option<Pubkey>),
|
SetValidatorInfo {
|
||||||
|
validator_info: Value,
|
||||||
|
force_keybase: bool,
|
||||||
|
info_pubkey: Option<Pubkey>,
|
||||||
|
},
|
||||||
// Vote Commands
|
// Vote Commands
|
||||||
CreateVoteAccount(Pubkey, VoteInit),
|
CreateVoteAccount {
|
||||||
|
vote_account_pubkey: Pubkey,
|
||||||
|
node_pubkey: Pubkey,
|
||||||
|
authorized_voter: Option<Pubkey>,
|
||||||
|
authorized_withdrawer: Option<Pubkey>,
|
||||||
|
commission: u8,
|
||||||
|
},
|
||||||
ShowVoteAccount {
|
ShowVoteAccount {
|
||||||
pubkey: Pubkey,
|
pubkey: Pubkey,
|
||||||
use_lamports_unit: bool,
|
use_lamports_unit: bool,
|
||||||
|
@ -108,7 +124,7 @@ pub enum CliCommand {
|
||||||
use_lamports_unit: bool,
|
use_lamports_unit: bool,
|
||||||
},
|
},
|
||||||
Balance {
|
Balance {
|
||||||
pubkey: Pubkey,
|
pubkey: Option<Pubkey>,
|
||||||
use_lamports_unit: bool,
|
use_lamports_unit: bool,
|
||||||
},
|
},
|
||||||
Cancel(Pubkey),
|
Cancel(Pubkey),
|
||||||
|
@ -119,7 +135,7 @@ pub enum CliCommand {
|
||||||
timestamp: Option<DateTime<Utc>>,
|
timestamp: Option<DateTime<Utc>>,
|
||||||
timestamp_pubkey: Option<Pubkey>,
|
timestamp_pubkey: Option<Pubkey>,
|
||||||
witnesses: Option<Vec<Pubkey>>,
|
witnesses: Option<Vec<Pubkey>>,
|
||||||
cancelable: Option<Pubkey>,
|
cancelable: bool,
|
||||||
},
|
},
|
||||||
ShowAccount {
|
ShowAccount {
|
||||||
pubkey: Pubkey,
|
pubkey: Pubkey,
|
||||||
|
@ -130,6 +146,12 @@ pub enum CliCommand {
|
||||||
Witness(Pubkey, Pubkey), // Witness(to, process_id)
|
Witness(Pubkey, Pubkey), // Witness(to, process_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct CliCommandInfo {
|
||||||
|
pub command: CliCommand,
|
||||||
|
pub require_keypair: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum CliError {
|
pub enum CliError {
|
||||||
BadParameter(String),
|
BadParameter(String),
|
||||||
|
@ -161,7 +183,7 @@ pub struct CliConfig {
|
||||||
pub command: CliCommand,
|
pub command: CliCommand,
|
||||||
pub json_rpc_url: String,
|
pub json_rpc_url: String,
|
||||||
pub keypair: Keypair,
|
pub keypair: Keypair,
|
||||||
pub keypair_path: String,
|
pub keypair_path: Option<String>,
|
||||||
pub rpc_client: Option<RpcClient>,
|
pub rpc_client: Option<RpcClient>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,40 +194,53 @@ impl Default for CliConfig {
|
||||||
|
|
||||||
CliConfig {
|
CliConfig {
|
||||||
command: CliCommand::Balance {
|
command: CliCommand::Balance {
|
||||||
pubkey: Pubkey::default(),
|
pubkey: Some(Pubkey::default()),
|
||||||
use_lamports_unit: false,
|
use_lamports_unit: false,
|
||||||
},
|
},
|
||||||
json_rpc_url: "http://127.0.0.1:8899".to_string(),
|
json_rpc_url: "http://127.0.0.1:8899".to_string(),
|
||||||
keypair: Keypair::new(),
|
keypair: Keypair::new(),
|
||||||
keypair_path: keypair_path.to_str().unwrap().to_string(),
|
keypair_path: Some(keypair_path.to_str().unwrap().to_string()),
|
||||||
rpc_client: None,
|
rpc_client: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_command(
|
pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn error::Error>> {
|
||||||
pubkey: &Pubkey,
|
|
||||||
matches: &ArgMatches<'_>,
|
|
||||||
) -> Result<CliCommand, Box<dyn error::Error>> {
|
|
||||||
let response = match matches.subcommand() {
|
let response = match matches.subcommand() {
|
||||||
// Cluster Query Commands
|
// Cluster Query Commands
|
||||||
("cluster-version", Some(_matches)) => Ok(CliCommand::ClusterVersion),
|
("cluster-version", Some(_matches)) => Ok(CliCommandInfo {
|
||||||
("fees", Some(_fees_matches)) => Ok(CliCommand::Fees),
|
command: CliCommand::ClusterVersion,
|
||||||
("get-epoch-info", Some(_matches)) => Ok(CliCommand::GetEpochInfo),
|
require_keypair: false,
|
||||||
("get-genesis-blockhash", Some(_matches)) => Ok(CliCommand::GetGenesisBlockhash),
|
}),
|
||||||
("get-slot", Some(_matches)) => Ok(CliCommand::GetSlot),
|
("fees", Some(_matches)) => Ok(CliCommandInfo {
|
||||||
("get-transaction-count", Some(_matches)) => Ok(CliCommand::GetTransactionCount),
|
command: CliCommand::Fees,
|
||||||
|
require_keypair: false,
|
||||||
|
}),
|
||||||
|
("get-epoch-info", Some(_matches)) => Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::GetEpochInfo,
|
||||||
|
require_keypair: false,
|
||||||
|
}),
|
||||||
|
("get-genesis-blockhash", Some(_matches)) => Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::GetGenesisBlockhash,
|
||||||
|
require_keypair: false,
|
||||||
|
}),
|
||||||
|
("get-slot", Some(_matches)) => Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::GetSlot,
|
||||||
|
require_keypair: false,
|
||||||
|
}),
|
||||||
|
("get-transaction-count", Some(_matches)) => Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::GetTransactionCount,
|
||||||
|
require_keypair: false,
|
||||||
|
}),
|
||||||
("ping", Some(matches)) => parse_cluster_ping(matches),
|
("ping", Some(matches)) => parse_cluster_ping(matches),
|
||||||
("show-validators", Some(matches)) => parse_show_validators(matches),
|
("show-validators", Some(matches)) => parse_show_validators(matches),
|
||||||
// Program Deployment
|
// Program Deployment
|
||||||
("deploy", Some(deploy_matches)) => Ok(CliCommand::Deploy(
|
("deploy", Some(matches)) => Ok(CliCommandInfo {
|
||||||
deploy_matches
|
command: CliCommand::Deploy(matches.value_of("program_location").unwrap().to_string()),
|
||||||
.value_of("program_location")
|
require_keypair: true,
|
||||||
.unwrap()
|
}),
|
||||||
.to_string(),
|
|
||||||
)),
|
|
||||||
// Stake Commands
|
// Stake Commands
|
||||||
("create-stake-account", Some(matches)) => parse_stake_create_account(pubkey, matches),
|
("create-stake-account", Some(matches)) => parse_stake_create_account(matches),
|
||||||
("delegate-stake", Some(matches)) => parse_stake_delegate_stake(matches),
|
("delegate-stake", Some(matches)) => parse_stake_delegate_stake(matches),
|
||||||
("withdraw-stake", Some(matches)) => parse_stake_withdraw_stake(matches),
|
("withdraw-stake", Some(matches)) => parse_stake_withdraw_stake(matches),
|
||||||
("deactivate-stake", Some(matches)) => parse_stake_deactivate_stake(matches),
|
("deactivate-stake", Some(matches)) => parse_stake_deactivate_stake(matches),
|
||||||
|
@ -228,7 +263,7 @@ pub fn parse_command(
|
||||||
("show-storage-account", Some(matches)) => parse_storage_get_account_command(matches),
|
("show-storage-account", Some(matches)) => parse_storage_get_account_command(matches),
|
||||||
// Validator Info Commands
|
// Validator Info Commands
|
||||||
("validator-info", Some(matches)) => match matches.subcommand() {
|
("validator-info", Some(matches)) => match matches.subcommand() {
|
||||||
("publish", Some(matches)) => parse_validator_info_command(matches, pubkey),
|
("publish", Some(matches)) => parse_validator_info_command(matches),
|
||||||
("get", Some(matches)) => parse_get_validator_info_command(matches),
|
("get", Some(matches)) => parse_get_validator_info_command(matches),
|
||||||
("", None) => {
|
("", None) => {
|
||||||
eprintln!("{}", matches.usage());
|
eprintln!("{}", matches.usage());
|
||||||
|
@ -239,7 +274,7 @@ pub fn parse_command(
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
// Vote Commands
|
// Vote Commands
|
||||||
("create-vote-account", Some(matches)) => parse_vote_create_account(pubkey, matches),
|
("create-vote-account", Some(matches)) => parse_vote_create_account(matches),
|
||||||
("vote-authorize-voter", Some(matches)) => {
|
("vote-authorize-voter", Some(matches)) => {
|
||||||
parse_vote_authorize(matches, VoteAuthorize::Voter)
|
parse_vote_authorize(matches, VoteAuthorize::Voter)
|
||||||
}
|
}
|
||||||
|
@ -249,9 +284,12 @@ pub fn parse_command(
|
||||||
("show-vote-account", Some(matches)) => parse_vote_get_account_command(matches),
|
("show-vote-account", Some(matches)) => parse_vote_get_account_command(matches),
|
||||||
("uptime", Some(matches)) => parse_vote_uptime_command(matches),
|
("uptime", Some(matches)) => parse_vote_uptime_command(matches),
|
||||||
// Wallet Commands
|
// Wallet Commands
|
||||||
("address", Some(_address_matches)) => Ok(CliCommand::Address),
|
("address", Some(_matches)) => Ok(CliCommandInfo {
|
||||||
("airdrop", Some(airdrop_matches)) => {
|
command: CliCommand::Address,
|
||||||
let drone_port = airdrop_matches
|
require_keypair: true,
|
||||||
|
}),
|
||||||
|
("airdrop", Some(matches)) => {
|
||||||
|
let drone_port = matches
|
||||||
.value_of("drone_port")
|
.value_of("drone_port")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse()
|
.parse()
|
||||||
|
@ -272,102 +310,116 @@ pub fn parse_command(
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let lamports = amount_of(airdrop_matches, "amount", "unit").expect("Invalid amount");
|
let lamports = amount_of(matches, "amount", "unit").expect("Invalid amount");
|
||||||
let use_lamports_unit = airdrop_matches.value_of("unit").is_some()
|
let use_lamports_unit = matches.value_of("unit").is_some()
|
||||||
&& airdrop_matches.value_of("unit").unwrap() == "lamports";
|
&& matches.value_of("unit").unwrap() == "lamports";
|
||||||
Ok(CliCommand::Airdrop {
|
Ok(CliCommandInfo {
|
||||||
drone_host,
|
command: CliCommand::Airdrop {
|
||||||
drone_port,
|
drone_host,
|
||||||
lamports,
|
drone_port,
|
||||||
use_lamports_unit,
|
lamports,
|
||||||
|
use_lamports_unit,
|
||||||
|
},
|
||||||
|
require_keypair: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
("balance", Some(balance_matches)) => {
|
("balance", Some(matches)) => {
|
||||||
let pubkey = pubkey_of(&balance_matches, "pubkey").unwrap_or(*pubkey);
|
let pubkey = pubkey_of(&matches, "pubkey");
|
||||||
let use_lamports_unit = balance_matches.is_present("lamports");
|
println!("{:?}", pubkey);
|
||||||
Ok(CliCommand::Balance {
|
Ok(CliCommandInfo {
|
||||||
pubkey,
|
command: CliCommand::Balance {
|
||||||
use_lamports_unit,
|
pubkey,
|
||||||
|
use_lamports_unit: matches.is_present("lamports"),
|
||||||
|
},
|
||||||
|
require_keypair: pubkey.is_none(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
("cancel", Some(cancel_matches)) => {
|
("cancel", Some(matches)) => {
|
||||||
let process_id = value_of(cancel_matches, "process_id").unwrap();
|
let process_id = value_of(matches, "process_id").unwrap();
|
||||||
Ok(CliCommand::Cancel(process_id))
|
Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::Cancel(process_id),
|
||||||
|
require_keypair: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
("confirm", Some(confirm_matches)) => {
|
("confirm", Some(matches)) => match matches.value_of("signature").unwrap().parse() {
|
||||||
match confirm_matches.value_of("signature").unwrap().parse() {
|
Ok(signature) => Ok(CliCommandInfo {
|
||||||
Ok(signature) => Ok(CliCommand::Confirm(signature)),
|
command: CliCommand::Confirm(signature),
|
||||||
_ => {
|
require_keypair: false,
|
||||||
eprintln!("{}", confirm_matches.usage());
|
}),
|
||||||
Err(CliError::BadParameter("Invalid signature".to_string()))
|
_ => {
|
||||||
}
|
eprintln!("{}", matches.usage());
|
||||||
|
Err(CliError::BadParameter("Invalid signature".to_string()))
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
("pay", Some(pay_matches)) => {
|
("pay", Some(matches)) => {
|
||||||
let lamports = amount_of(pay_matches, "amount", "unit").expect("Invalid amount");
|
let lamports = amount_of(matches, "amount", "unit").expect("Invalid amount");
|
||||||
let to = value_of(&pay_matches, "to").unwrap_or(*pubkey);
|
let to = value_of(&matches, "to").unwrap();
|
||||||
let timestamp = if pay_matches.is_present("timestamp") {
|
let timestamp = if matches.is_present("timestamp") {
|
||||||
// Parse input for serde_json
|
// Parse input for serde_json
|
||||||
let date_string = if !pay_matches.value_of("timestamp").unwrap().contains('Z') {
|
let date_string = if !matches.value_of("timestamp").unwrap().contains('Z') {
|
||||||
format!("\"{}Z\"", pay_matches.value_of("timestamp").unwrap())
|
format!("\"{}Z\"", matches.value_of("timestamp").unwrap())
|
||||||
} else {
|
} else {
|
||||||
format!("\"{}\"", pay_matches.value_of("timestamp").unwrap())
|
format!("\"{}\"", matches.value_of("timestamp").unwrap())
|
||||||
};
|
};
|
||||||
Some(serde_json::from_str(&date_string)?)
|
Some(serde_json::from_str(&date_string)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let timestamp_pubkey = value_of(&pay_matches, "timestamp_pubkey");
|
let timestamp_pubkey = value_of(&matches, "timestamp_pubkey");
|
||||||
let witnesses = values_of(&pay_matches, "witness");
|
let witnesses = values_of(&matches, "witness");
|
||||||
let cancelable = if pay_matches.is_present("cancelable") {
|
let cancelable = matches.is_present("cancelable");
|
||||||
Some(*pubkey)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(CliCommand::Pay {
|
Ok(CliCommandInfo {
|
||||||
lamports,
|
command: CliCommand::Pay {
|
||||||
to,
|
lamports,
|
||||||
timestamp,
|
to,
|
||||||
timestamp_pubkey,
|
timestamp,
|
||||||
witnesses,
|
timestamp_pubkey,
|
||||||
cancelable,
|
witnesses,
|
||||||
|
cancelable,
|
||||||
|
},
|
||||||
|
require_keypair: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
("show-account", Some(matches)) => {
|
("show-account", Some(matches)) => {
|
||||||
let account_pubkey = pubkey_of(matches, "account_pubkey").unwrap();
|
let account_pubkey = pubkey_of(matches, "account_pubkey").unwrap();
|
||||||
let output_file = matches.value_of("output_file");
|
let output_file = matches.value_of("output_file");
|
||||||
let use_lamports_unit = matches.is_present("lamports");
|
let use_lamports_unit = matches.is_present("lamports");
|
||||||
Ok(CliCommand::ShowAccount {
|
Ok(CliCommandInfo {
|
||||||
pubkey: account_pubkey,
|
command: CliCommand::ShowAccount {
|
||||||
output_file: output_file.map(ToString::to_string),
|
pubkey: account_pubkey,
|
||||||
use_lamports_unit,
|
output_file: output_file.map(ToString::to_string),
|
||||||
|
use_lamports_unit,
|
||||||
|
},
|
||||||
|
require_keypair: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
("send-signature", Some(sig_matches)) => {
|
("send-signature", Some(matches)) => {
|
||||||
let to = value_of(&sig_matches, "to").unwrap();
|
let to = value_of(&matches, "to").unwrap();
|
||||||
let process_id = value_of(&sig_matches, "process_id").unwrap();
|
let process_id = value_of(&matches, "process_id").unwrap();
|
||||||
Ok(CliCommand::Witness(to, process_id))
|
Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::Witness(to, process_id),
|
||||||
|
require_keypair: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
("send-timestamp", Some(timestamp_matches)) => {
|
("send-timestamp", Some(matches)) => {
|
||||||
let to = value_of(×tamp_matches, "to").unwrap();
|
let to = value_of(&matches, "to").unwrap();
|
||||||
let process_id = value_of(×tamp_matches, "process_id").unwrap();
|
let process_id = value_of(&matches, "process_id").unwrap();
|
||||||
let dt = if timestamp_matches.is_present("datetime") {
|
let dt = if matches.is_present("datetime") {
|
||||||
// Parse input for serde_json
|
// Parse input for serde_json
|
||||||
let date_string = if !timestamp_matches
|
let date_string = if !matches.value_of("datetime").unwrap().contains('Z') {
|
||||||
.value_of("datetime")
|
format!("\"{}Z\"", matches.value_of("datetime").unwrap())
|
||||||
.unwrap()
|
|
||||||
.contains('Z')
|
|
||||||
{
|
|
||||||
format!("\"{}Z\"", timestamp_matches.value_of("datetime").unwrap())
|
|
||||||
} else {
|
} else {
|
||||||
format!("\"{}\"", timestamp_matches.value_of("datetime").unwrap())
|
format!("\"{}\"", matches.value_of("datetime").unwrap())
|
||||||
};
|
};
|
||||||
serde_json::from_str(&date_string)?
|
serde_json::from_str(&date_string)?
|
||||||
} else {
|
} else {
|
||||||
Utc::now()
|
Utc::now()
|
||||||
};
|
};
|
||||||
Ok(CliCommand::TimeElapsed(to, process_id, dt))
|
Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::TimeElapsed(to, process_id, dt),
|
||||||
|
require_keypair: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
("", None) => {
|
("", None) => {
|
||||||
eprintln!("{}", matches.usage());
|
eprintln!("{}", matches.usage());
|
||||||
|
@ -457,11 +509,13 @@ fn process_airdrop(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_balance(
|
fn process_balance(
|
||||||
pubkey: &Pubkey,
|
|
||||||
rpc_client: &RpcClient,
|
rpc_client: &RpcClient,
|
||||||
|
config: &CliConfig,
|
||||||
|
pubkey: &Option<Pubkey>,
|
||||||
use_lamports_unit: bool,
|
use_lamports_unit: bool,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
let balance = rpc_client.retry_get_balance(pubkey, 5)?;
|
let pubkey = pubkey.unwrap_or(config.keypair.pubkey());
|
||||||
|
let balance = rpc_client.retry_get_balance(&pubkey, 5)?;
|
||||||
match balance {
|
match balance {
|
||||||
Some(lamports) => Ok(build_balance_message(lamports, use_lamports_unit)),
|
Some(lamports) => Ok(build_balance_message(lamports, use_lamports_unit)),
|
||||||
None => Err(
|
None => Err(
|
||||||
|
@ -600,7 +654,7 @@ fn process_pay(
|
||||||
timestamp: Option<DateTime<Utc>>,
|
timestamp: Option<DateTime<Utc>>,
|
||||||
timestamp_pubkey: Option<Pubkey>,
|
timestamp_pubkey: Option<Pubkey>,
|
||||||
witnesses: &Option<Vec<Pubkey>>,
|
witnesses: &Option<Vec<Pubkey>>,
|
||||||
cancelable: Option<Pubkey>,
|
cancelable: bool,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
check_unique_pubkeys(
|
check_unique_pubkeys(
|
||||||
(&config.keypair.pubkey(), "cli keypair".to_string()),
|
(&config.keypair.pubkey(), "cli keypair".to_string()),
|
||||||
|
@ -608,6 +662,12 @@ fn process_pay(
|
||||||
)?;
|
)?;
|
||||||
let (blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
let (blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
|
|
||||||
|
let cancelable = if cancelable {
|
||||||
|
Some(config.keypair.pubkey())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
if timestamp == None && *witnesses == None {
|
if timestamp == None && *witnesses == None {
|
||||||
let mut tx = system_transaction::transfer(&config.keypair, to, lamports, blockhash);
|
let mut tx = system_transaction::transfer(&config.keypair, to, lamports, blockhash);
|
||||||
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
||||||
|
@ -725,7 +785,9 @@ fn process_witness(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_command(config: &CliConfig) -> ProcessResult {
|
pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||||
println_name_value("Keypair:", &config.keypair_path);
|
if let Some(keypair_path) = &config.keypair_path {
|
||||||
|
println_name_value("Keypair:", keypair_path);
|
||||||
|
}
|
||||||
if let CliCommand::Address = config.command {
|
if let CliCommand::Address = config.command {
|
||||||
// Get address of this client
|
// Get address of this client
|
||||||
return Ok(format!("{}", config.keypair.pubkey()));
|
return Ok(format!("{}", config.keypair.pubkey()));
|
||||||
|
@ -770,16 +832,21 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||||
// Stake Commands
|
// Stake Commands
|
||||||
|
|
||||||
// Create stake account
|
// Create stake account
|
||||||
CliCommand::CreateStakeAccount(stake_account_pubkey, authorized, lockup, lamports) => {
|
CliCommand::CreateStakeAccount {
|
||||||
process_create_stake_account(
|
stake_account_pubkey,
|
||||||
&rpc_client,
|
staker,
|
||||||
config,
|
withdrawer,
|
||||||
&stake_account_pubkey,
|
lockup,
|
||||||
&authorized,
|
lamports,
|
||||||
lockup,
|
} => process_create_stake_account(
|
||||||
*lamports,
|
&rpc_client,
|
||||||
)
|
config,
|
||||||
}
|
&stake_account_pubkey,
|
||||||
|
staker,
|
||||||
|
withdrawer,
|
||||||
|
lockup,
|
||||||
|
*lamports,
|
||||||
|
),
|
||||||
// Deactivate stake account
|
// Deactivate stake account
|
||||||
CliCommand::DeactivateStake(stake_account_pubkey) => {
|
CliCommand::DeactivateStake(stake_account_pubkey) => {
|
||||||
process_deactivate_stake_account(&rpc_client, config, &stake_account_pubkey)
|
process_deactivate_stake_account(&rpc_client, config, &stake_account_pubkey)
|
||||||
|
@ -866,16 +933,36 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||||
process_get_validator_info(&rpc_client, *info_pubkey)
|
process_get_validator_info(&rpc_client, *info_pubkey)
|
||||||
}
|
}
|
||||||
// Publish validator info
|
// Publish validator info
|
||||||
CliCommand::SetValidatorInfo(validator_info, info_pubkey) => {
|
CliCommand::SetValidatorInfo {
|
||||||
process_set_validator_info(&rpc_client, config, &validator_info, *info_pubkey)
|
validator_info,
|
||||||
}
|
force_keybase,
|
||||||
|
info_pubkey,
|
||||||
|
} => process_set_validator_info(
|
||||||
|
&rpc_client,
|
||||||
|
config,
|
||||||
|
&validator_info,
|
||||||
|
*force_keybase,
|
||||||
|
*info_pubkey,
|
||||||
|
),
|
||||||
|
|
||||||
// Vote Commands
|
// Vote Commands
|
||||||
|
|
||||||
// Create vote account
|
// Create vote account
|
||||||
CliCommand::CreateVoteAccount(vote_account_pubkey, vote_init) => {
|
CliCommand::CreateVoteAccount {
|
||||||
process_create_vote_account(&rpc_client, config, &vote_account_pubkey, &vote_init)
|
vote_account_pubkey,
|
||||||
}
|
node_pubkey,
|
||||||
|
authorized_voter,
|
||||||
|
authorized_withdrawer,
|
||||||
|
commission,
|
||||||
|
} => process_create_vote_account(
|
||||||
|
&rpc_client,
|
||||||
|
config,
|
||||||
|
&vote_account_pubkey,
|
||||||
|
&node_pubkey,
|
||||||
|
authorized_voter,
|
||||||
|
authorized_withdrawer,
|
||||||
|
*commission,
|
||||||
|
),
|
||||||
CliCommand::ShowVoteAccount {
|
CliCommand::ShowVoteAccount {
|
||||||
pubkey: vote_account_pubkey,
|
pubkey: vote_account_pubkey,
|
||||||
use_lamports_unit,
|
use_lamports_unit,
|
||||||
|
@ -937,7 +1024,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||||
CliCommand::Balance {
|
CliCommand::Balance {
|
||||||
pubkey,
|
pubkey,
|
||||||
use_lamports_unit,
|
use_lamports_unit,
|
||||||
} => process_balance(&pubkey, &rpc_client, *use_lamports_unit),
|
} => process_balance(&rpc_client, config, &pubkey, *use_lamports_unit),
|
||||||
// Cancel a contract by contract Pubkey
|
// Cancel a contract by contract Pubkey
|
||||||
CliCommand::Cancel(pubkey) => process_cancel(&rpc_client, config, &pubkey),
|
CliCommand::Cancel(pubkey) => process_cancel(&rpc_client, config, &pubkey),
|
||||||
// Confirm the last client transaction by signature
|
// Confirm the last client transaction by signature
|
||||||
|
@ -1311,78 +1398,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
||||||
.help("Display balance in lamports instead of SOL"),
|
.help("Display balance in lamports instead of SOL"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.validator_info_subcommands()
|
||||||
SubCommand::with_name("validator-info")
|
|
||||||
.about("Publish/get Validator info on Solana")
|
|
||||||
.subcommand(
|
|
||||||
SubCommand::with_name("publish")
|
|
||||||
.about("Publish Validator info on Solana")
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("info_pubkey")
|
|
||||||
.short("p")
|
|
||||||
.long("info-pubkey")
|
|
||||||
.value_name("PUBKEY")
|
|
||||||
.takes_value(true)
|
|
||||||
.validator(is_pubkey)
|
|
||||||
.help("The pubkey of the Validator info account to update"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("name")
|
|
||||||
.index(1)
|
|
||||||
.value_name("NAME")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.validator(is_short_field)
|
|
||||||
.help("Validator name"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("website")
|
|
||||||
.short("w")
|
|
||||||
.long("website")
|
|
||||||
.value_name("URL")
|
|
||||||
.takes_value(true)
|
|
||||||
.validator(check_url)
|
|
||||||
.help("Validator website url"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("keybase_username")
|
|
||||||
.short("n")
|
|
||||||
.long("keybase")
|
|
||||||
.value_name("USERNAME")
|
|
||||||
.takes_value(true)
|
|
||||||
.validator(is_short_field)
|
|
||||||
.help("Validator Keybase username"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("details")
|
|
||||||
.short("d")
|
|
||||||
.long("details")
|
|
||||||
.value_name("DETAILS")
|
|
||||||
.takes_value(true)
|
|
||||||
.validator(check_details_length)
|
|
||||||
.help("Validator description")
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("force")
|
|
||||||
.long("force")
|
|
||||||
.takes_value(false)
|
|
||||||
.hidden(true) // Don't document this argument to discourage its use
|
|
||||||
.help("Override keybase username validity check"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.subcommand(
|
|
||||||
SubCommand::with_name("get")
|
|
||||||
.about("Get and parse Solana Validator info")
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("info_pubkey")
|
|
||||||
.index(1)
|
|
||||||
.value_name("PUBKEY")
|
|
||||||
.takes_value(true)
|
|
||||||
.validator(is_pubkey)
|
|
||||||
.help("The pubkey of the Validator info account; without this argument, returns all"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.vote_subcommands()
|
.vote_subcommands()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1416,8 +1432,7 @@ mod tests {
|
||||||
fn test_bad_amount() {
|
fn test_bad_amount() {
|
||||||
let test_commands = app("test", "desc", "version");
|
let test_commands = app("test", "desc", "version");
|
||||||
let test_bad_airdrop = test_commands.get_matches_from(vec!["test", "airdrop", "notint"]);
|
let test_bad_airdrop = test_commands.get_matches_from(vec!["test", "airdrop", "notint"]);
|
||||||
let pubkey = Pubkey::new_rand();
|
let _ignored = parse_command(&test_bad_airdrop).unwrap();
|
||||||
let _ignored = parse_command(&pubkey, &test_bad_airdrop).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1437,12 +1452,15 @@ mod tests {
|
||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "airdrop", "50", "lamports"]);
|
.get_matches_from(vec!["test", "airdrop", "50", "lamports"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_airdrop).unwrap(),
|
parse_command(&test_airdrop).unwrap(),
|
||||||
CliCommand::Airdrop {
|
CliCommandInfo {
|
||||||
drone_host: None,
|
command: CliCommand::Airdrop {
|
||||||
drone_port: solana_drone::drone::DRONE_PORT,
|
drone_host: None,
|
||||||
lamports: 50,
|
drone_port: solana_drone::drone::DRONE_PORT,
|
||||||
use_lamports_unit: true,
|
lamports: 50,
|
||||||
|
use_lamports_unit: true,
|
||||||
|
},
|
||||||
|
require_keypair: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1456,10 +1474,13 @@ mod tests {
|
||||||
&keypair.pubkey().to_string(),
|
&keypair.pubkey().to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_balance).unwrap(),
|
parse_command(&test_balance).unwrap(),
|
||||||
CliCommand::Balance {
|
CliCommandInfo {
|
||||||
pubkey: keypair.pubkey(),
|
command: CliCommand::Balance {
|
||||||
use_lamports_unit: false
|
pubkey: Some(keypair.pubkey()),
|
||||||
|
use_lamports_unit: false
|
||||||
|
},
|
||||||
|
require_keypair: false
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
let test_balance = test_commands.clone().get_matches_from(vec![
|
let test_balance = test_commands.clone().get_matches_from(vec![
|
||||||
|
@ -1469,10 +1490,27 @@ mod tests {
|
||||||
"--lamports",
|
"--lamports",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_balance).unwrap(),
|
parse_command(&test_balance).unwrap(),
|
||||||
CliCommand::Balance {
|
CliCommandInfo {
|
||||||
pubkey: keypair.pubkey(),
|
command: CliCommand::Balance {
|
||||||
use_lamports_unit: true
|
pubkey: Some(keypair.pubkey()),
|
||||||
|
use_lamports_unit: true
|
||||||
|
},
|
||||||
|
require_keypair: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
let test_balance =
|
||||||
|
test_commands
|
||||||
|
.clone()
|
||||||
|
.get_matches_from(vec!["test", "balance", "--lamports"]);
|
||||||
|
assert_eq!(
|
||||||
|
parse_command(&test_balance).unwrap(),
|
||||||
|
CliCommandInfo {
|
||||||
|
command: CliCommand::Balance {
|
||||||
|
pubkey: None,
|
||||||
|
use_lamports_unit: true
|
||||||
|
},
|
||||||
|
require_keypair: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1482,8 +1520,11 @@ 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(&pubkey, &test_cancel).unwrap(),
|
parse_command(&test_cancel).unwrap(),
|
||||||
CliCommand::Cancel(pubkey)
|
CliCommandInfo {
|
||||||
|
command: CliCommand::Cancel(pubkey),
|
||||||
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test Confirm Subcommand
|
// Test Confirm Subcommand
|
||||||
|
@ -1494,13 +1535,16 @@ 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(&pubkey, &test_confirm).unwrap(),
|
parse_command(&test_confirm).unwrap(),
|
||||||
CliCommand::Confirm(signature)
|
CliCommandInfo {
|
||||||
|
command: CliCommand::Confirm(signature),
|
||||||
|
require_keypair: false
|
||||||
|
}
|
||||||
);
|
);
|
||||||
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(&pubkey, &test_bad_signature).is_err());
|
assert!(parse_command(&test_bad_signature).is_err());
|
||||||
|
|
||||||
// Test Deploy Subcommand
|
// Test Deploy Subcommand
|
||||||
let test_deploy =
|
let test_deploy =
|
||||||
|
@ -1508,8 +1552,11 @@ 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(&pubkey, &test_deploy).unwrap(),
|
parse_command(&test_deploy).unwrap(),
|
||||||
CliCommand::Deploy("/Users/test/program.o".to_string())
|
CliCommandInfo {
|
||||||
|
command: CliCommand::Deploy("/Users/test/program.o".to_string()),
|
||||||
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test Simple Pay Subcommand
|
// Test Simple Pay Subcommand
|
||||||
|
@ -1521,14 +1568,17 @@ mod tests {
|
||||||
"lamports",
|
"lamports",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_pay).unwrap(),
|
parse_command(&test_pay).unwrap(),
|
||||||
CliCommand::Pay {
|
CliCommandInfo {
|
||||||
lamports: 50,
|
command: CliCommand::Pay {
|
||||||
to: pubkey,
|
lamports: 50,
|
||||||
timestamp: None,
|
to: pubkey,
|
||||||
timestamp_pubkey: None,
|
timestamp: None,
|
||||||
witnesses: None,
|
timestamp_pubkey: None,
|
||||||
cancelable: None
|
witnesses: None,
|
||||||
|
cancelable: false,
|
||||||
|
},
|
||||||
|
require_keypair: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1545,14 +1595,17 @@ mod tests {
|
||||||
&witness1_string,
|
&witness1_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_pay_multiple_witnesses).unwrap(),
|
parse_command(&test_pay_multiple_witnesses).unwrap(),
|
||||||
CliCommand::Pay {
|
CliCommandInfo {
|
||||||
lamports: 50,
|
command: CliCommand::Pay {
|
||||||
to: pubkey,
|
lamports: 50,
|
||||||
timestamp: None,
|
to: pubkey,
|
||||||
timestamp_pubkey: None,
|
timestamp: None,
|
||||||
witnesses: Some(vec![witness0, witness1]),
|
timestamp_pubkey: None,
|
||||||
cancelable: None
|
witnesses: Some(vec![witness0, witness1]),
|
||||||
|
cancelable: false,
|
||||||
|
},
|
||||||
|
require_keypair: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
let test_pay_single_witness = test_commands.clone().get_matches_from(vec![
|
let test_pay_single_witness = test_commands.clone().get_matches_from(vec![
|
||||||
|
@ -1565,14 +1618,17 @@ mod tests {
|
||||||
&witness0_string,
|
&witness0_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_pay_single_witness).unwrap(),
|
parse_command(&test_pay_single_witness).unwrap(),
|
||||||
CliCommand::Pay {
|
CliCommandInfo {
|
||||||
lamports: 50,
|
command: CliCommand::Pay {
|
||||||
to: pubkey,
|
lamports: 50,
|
||||||
timestamp: None,
|
to: pubkey,
|
||||||
timestamp_pubkey: None,
|
timestamp: None,
|
||||||
witnesses: Some(vec![witness0]),
|
timestamp_pubkey: None,
|
||||||
cancelable: None
|
witnesses: Some(vec![witness0]),
|
||||||
|
cancelable: false,
|
||||||
|
},
|
||||||
|
require_keypair: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1589,14 +1645,17 @@ mod tests {
|
||||||
&witness0_string,
|
&witness0_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_pay_timestamp).unwrap(),
|
parse_command(&test_pay_timestamp).unwrap(),
|
||||||
CliCommand::Pay {
|
CliCommandInfo {
|
||||||
lamports: 50,
|
command: CliCommand::Pay {
|
||||||
to: pubkey,
|
lamports: 50,
|
||||||
timestamp: Some(dt),
|
to: pubkey,
|
||||||
timestamp_pubkey: Some(witness0),
|
timestamp: Some(dt),
|
||||||
witnesses: None,
|
timestamp_pubkey: Some(witness0),
|
||||||
cancelable: None
|
witnesses: None,
|
||||||
|
cancelable: false,
|
||||||
|
},
|
||||||
|
require_keypair: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1608,8 +1667,11 @@ mod tests {
|
||||||
&pubkey_string,
|
&pubkey_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_send_signature).unwrap(),
|
parse_command(&test_send_signature).unwrap(),
|
||||||
CliCommand::Witness(pubkey, pubkey)
|
CliCommandInfo {
|
||||||
|
command: CliCommand::Witness(pubkey, pubkey),
|
||||||
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
let test_pay_multiple_witnesses = test_commands.clone().get_matches_from(vec![
|
let test_pay_multiple_witnesses = test_commands.clone().get_matches_from(vec![
|
||||||
"test",
|
"test",
|
||||||
|
@ -1627,14 +1689,17 @@ mod tests {
|
||||||
&witness1_string,
|
&witness1_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_pay_multiple_witnesses).unwrap(),
|
parse_command(&test_pay_multiple_witnesses).unwrap(),
|
||||||
CliCommand::Pay {
|
CliCommandInfo {
|
||||||
lamports: 50,
|
command: CliCommand::Pay {
|
||||||
to: pubkey,
|
lamports: 50,
|
||||||
timestamp: Some(dt),
|
to: pubkey,
|
||||||
timestamp_pubkey: Some(witness0),
|
timestamp: Some(dt),
|
||||||
witnesses: Some(vec![witness0, witness1]),
|
timestamp_pubkey: Some(witness0),
|
||||||
cancelable: None
|
witnesses: Some(vec![witness0, witness1]),
|
||||||
|
cancelable: false,
|
||||||
|
},
|
||||||
|
require_keypair: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1648,8 +1713,11 @@ mod tests {
|
||||||
"2018-09-19T17:30:59",
|
"2018-09-19T17:30:59",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_send_timestamp).unwrap(),
|
parse_command(&test_send_timestamp).unwrap(),
|
||||||
CliCommand::TimeElapsed(pubkey, pubkey, dt)
|
CliCommandInfo {
|
||||||
|
command: CliCommand::TimeElapsed(pubkey, pubkey, dt),
|
||||||
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
let test_bad_timestamp = test_commands.clone().get_matches_from(vec![
|
let test_bad_timestamp = test_commands.clone().get_matches_from(vec![
|
||||||
"test",
|
"test",
|
||||||
|
@ -1659,7 +1727,7 @@ mod tests {
|
||||||
"--date",
|
"--date",
|
||||||
"20180919T17:30:59",
|
"20180919T17:30:59",
|
||||||
]);
|
]);
|
||||||
assert!(parse_command(&pubkey, &test_bad_timestamp).is_err());
|
assert!(parse_command(&test_bad_timestamp).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1675,13 +1743,13 @@ mod tests {
|
||||||
assert_eq!(process_command(&config).unwrap(), pubkey);
|
assert_eq!(process_command(&config).unwrap(), pubkey);
|
||||||
|
|
||||||
config.command = CliCommand::Balance {
|
config.command = CliCommand::Balance {
|
||||||
pubkey: config.keypair.pubkey(),
|
pubkey: None,
|
||||||
use_lamports_unit: true,
|
use_lamports_unit: true,
|
||||||
};
|
};
|
||||||
assert_eq!(process_command(&config).unwrap(), "50 lamports");
|
assert_eq!(process_command(&config).unwrap(), "50 lamports");
|
||||||
|
|
||||||
config.command = CliCommand::Balance {
|
config.command = CliCommand::Balance {
|
||||||
pubkey: config.keypair.pubkey(),
|
pubkey: None,
|
||||||
use_lamports_unit: false,
|
use_lamports_unit: false,
|
||||||
};
|
};
|
||||||
assert_eq!(process_command(&config).unwrap(), "0 SOL");
|
assert_eq!(process_command(&config).unwrap(), "0 SOL");
|
||||||
|
@ -1696,15 +1764,13 @@ mod tests {
|
||||||
|
|
||||||
let bob_pubkey = Pubkey::new_rand();
|
let bob_pubkey = Pubkey::new_rand();
|
||||||
let node_pubkey = Pubkey::new_rand();
|
let node_pubkey = Pubkey::new_rand();
|
||||||
config.command = CliCommand::CreateVoteAccount(
|
config.command = CliCommand::CreateVoteAccount {
|
||||||
bob_pubkey,
|
vote_account_pubkey: bob_pubkey,
|
||||||
VoteInit {
|
node_pubkey,
|
||||||
node_pubkey,
|
authorized_voter: Some(bob_pubkey),
|
||||||
authorized_voter: bob_pubkey,
|
authorized_withdrawer: Some(bob_pubkey),
|
||||||
authorized_withdrawer: bob_pubkey,
|
commission: 0,
|
||||||
commission: 0,
|
};
|
||||||
},
|
|
||||||
);
|
|
||||||
let signature = process_command(&config);
|
let signature = process_command(&config);
|
||||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||||
|
|
||||||
|
@ -1716,15 +1782,13 @@ mod tests {
|
||||||
|
|
||||||
let bob_pubkey = Pubkey::new_rand();
|
let bob_pubkey = Pubkey::new_rand();
|
||||||
let custodian = Pubkey::new_rand();
|
let custodian = Pubkey::new_rand();
|
||||||
config.command = CliCommand::CreateStakeAccount(
|
config.command = CliCommand::CreateStakeAccount {
|
||||||
bob_pubkey,
|
stake_account_pubkey: bob_pubkey,
|
||||||
Authorized {
|
staker: None,
|
||||||
staker: config.keypair.pubkey(),
|
withdrawer: None,
|
||||||
withdrawer: config.keypair.pubkey(),
|
lockup: Lockup { slot: 0, custodian },
|
||||||
},
|
lamports: 1234,
|
||||||
Lockup { slot: 0, custodian },
|
};
|
||||||
1234,
|
|
||||||
);
|
|
||||||
let signature = process_command(&config);
|
let signature = process_command(&config);
|
||||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||||
|
|
||||||
|
@ -1751,7 +1815,7 @@ mod tests {
|
||||||
timestamp: None,
|
timestamp: None,
|
||||||
timestamp_pubkey: None,
|
timestamp_pubkey: None,
|
||||||
witnesses: None,
|
witnesses: None,
|
||||||
cancelable: None,
|
cancelable: false,
|
||||||
};
|
};
|
||||||
let signature = process_command(&config);
|
let signature = process_command(&config);
|
||||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||||
|
@ -1764,7 +1828,7 @@ mod tests {
|
||||||
timestamp: Some(dt),
|
timestamp: Some(dt),
|
||||||
timestamp_pubkey: Some(config.keypair.pubkey()),
|
timestamp_pubkey: Some(config.keypair.pubkey()),
|
||||||
witnesses: None,
|
witnesses: None,
|
||||||
cancelable: None,
|
cancelable: false,
|
||||||
};
|
};
|
||||||
let result = process_command(&config);
|
let result = process_command(&config);
|
||||||
let json: Value = serde_json::from_str(&result.unwrap()).unwrap();
|
let json: Value = serde_json::from_str(&result.unwrap()).unwrap();
|
||||||
|
@ -1785,7 +1849,7 @@ mod tests {
|
||||||
timestamp: None,
|
timestamp: None,
|
||||||
timestamp_pubkey: None,
|
timestamp_pubkey: None,
|
||||||
witnesses: Some(vec![witness]),
|
witnesses: Some(vec![witness]),
|
||||||
cancelable: Some(config.keypair.pubkey()),
|
cancelable: true,
|
||||||
};
|
};
|
||||||
let result = process_command(&config);
|
let result = process_command(&config);
|
||||||
let json: Value = serde_json::from_str(&result.unwrap()).unwrap();
|
let json: Value = serde_json::from_str(&result.unwrap()).unwrap();
|
||||||
|
@ -1858,20 +1922,18 @@ mod tests {
|
||||||
assert!(process_command(&config).is_err());
|
assert!(process_command(&config).is_err());
|
||||||
|
|
||||||
config.command = CliCommand::Balance {
|
config.command = CliCommand::Balance {
|
||||||
pubkey: config.keypair.pubkey(),
|
pubkey: None,
|
||||||
use_lamports_unit: false,
|
use_lamports_unit: false,
|
||||||
};
|
};
|
||||||
assert!(process_command(&config).is_err());
|
assert!(process_command(&config).is_err());
|
||||||
|
|
||||||
config.command = CliCommand::CreateVoteAccount(
|
config.command = CliCommand::CreateVoteAccount {
|
||||||
bob_pubkey,
|
vote_account_pubkey: bob_pubkey,
|
||||||
VoteInit {
|
node_pubkey,
|
||||||
node_pubkey,
|
authorized_voter: Some(bob_pubkey),
|
||||||
authorized_voter: bob_pubkey,
|
authorized_withdrawer: Some(bob_pubkey),
|
||||||
authorized_withdrawer: bob_pubkey,
|
commission: 0,
|
||||||
commission: 0,
|
};
|
||||||
},
|
|
||||||
);
|
|
||||||
assert!(process_command(&config).is_err());
|
assert!(process_command(&config).is_err());
|
||||||
|
|
||||||
config.command = CliCommand::VoteAuthorize(bob_pubkey, bob_pubkey, VoteAuthorize::Voter);
|
config.command = CliCommand::VoteAuthorize(bob_pubkey, bob_pubkey, VoteAuthorize::Voter);
|
||||||
|
@ -1889,7 +1951,7 @@ mod tests {
|
||||||
timestamp: None,
|
timestamp: None,
|
||||||
timestamp_pubkey: None,
|
timestamp_pubkey: None,
|
||||||
witnesses: None,
|
witnesses: None,
|
||||||
cancelable: None,
|
cancelable: false,
|
||||||
};
|
};
|
||||||
assert!(process_command(&config).is_err());
|
assert!(process_command(&config).is_err());
|
||||||
|
|
||||||
|
@ -1899,7 +1961,7 @@ mod tests {
|
||||||
timestamp: Some(dt),
|
timestamp: Some(dt),
|
||||||
timestamp_pubkey: Some(config.keypair.pubkey()),
|
timestamp_pubkey: Some(config.keypair.pubkey()),
|
||||||
witnesses: None,
|
witnesses: None,
|
||||||
cancelable: None,
|
cancelable: false,
|
||||||
};
|
};
|
||||||
assert!(process_command(&config).is_err());
|
assert!(process_command(&config).is_err());
|
||||||
|
|
||||||
|
@ -1909,7 +1971,7 @@ mod tests {
|
||||||
timestamp: None,
|
timestamp: None,
|
||||||
timestamp_pubkey: None,
|
timestamp_pubkey: None,
|
||||||
witnesses: Some(vec![witness]),
|
witnesses: Some(vec![witness]),
|
||||||
cancelable: Some(config.keypair.pubkey()),
|
cancelable: true,
|
||||||
};
|
};
|
||||||
assert!(process_command(&config).is_err());
|
assert!(process_command(&config).is_err());
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{
|
cli::{
|
||||||
build_balance_message, check_account_for_fee, CliCommand, CliConfig, CliError,
|
build_balance_message, check_account_for_fee, CliCommand, CliCommandInfo, CliConfig,
|
||||||
ProcessResult,
|
CliError, ProcessResult,
|
||||||
},
|
},
|
||||||
display::println_name_value,
|
display::println_name_value,
|
||||||
};
|
};
|
||||||
|
@ -88,7 +88,7 @@ impl ClusterQuerySubCommands for App<'_, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_cluster_ping(matches: &ArgMatches<'_>) -> Result<CliCommand, CliError> {
|
pub fn parse_cluster_ping(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
let interval = Duration::from_secs(value_t_or_exit!(matches, "interval", u64));
|
let interval = Duration::from_secs(value_t_or_exit!(matches, "interval", u64));
|
||||||
let count = if matches.is_present("count") {
|
let count = if matches.is_present("count") {
|
||||||
Some(value_t_or_exit!(matches, "count", u64))
|
Some(value_t_or_exit!(matches, "count", u64))
|
||||||
|
@ -96,17 +96,23 @@ pub fn parse_cluster_ping(matches: &ArgMatches<'_>) -> Result<CliCommand, CliErr
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let timeout = Duration::from_secs(value_t_or_exit!(matches, "timeout", u64));
|
let timeout = Duration::from_secs(value_t_or_exit!(matches, "timeout", u64));
|
||||||
Ok(CliCommand::Ping {
|
Ok(CliCommandInfo {
|
||||||
interval,
|
command: CliCommand::Ping {
|
||||||
count,
|
interval,
|
||||||
timeout,
|
count,
|
||||||
|
timeout,
|
||||||
|
},
|
||||||
|
require_keypair: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_show_validators(matches: &ArgMatches<'_>) -> Result<CliCommand, CliError> {
|
pub fn parse_show_validators(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
let use_lamports_unit = matches.is_present("lamports");
|
let use_lamports_unit = matches.is_present("lamports");
|
||||||
|
|
||||||
Ok(CliCommand::ShowValidators { use_lamports_unit })
|
Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::ShowValidators { use_lamports_unit },
|
||||||
|
require_keypair: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_cluster_version(rpc_client: &RpcClient, config: &CliConfig) -> ProcessResult {
|
pub fn process_cluster_version(rpc_client: &RpcClient, config: &CliConfig) -> ProcessResult {
|
||||||
|
@ -358,68 +364,87 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::cli::{app, parse_command};
|
use crate::cli::{app, parse_command};
|
||||||
use solana_sdk::pubkey::Pubkey;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_command() {
|
fn test_parse_command() {
|
||||||
let test_commands = app("test", "desc", "version");
|
let test_commands = app("test", "desc", "version");
|
||||||
let pubkey = Pubkey::new_rand();
|
|
||||||
|
|
||||||
let test_cluster_version = test_commands
|
let test_cluster_version = test_commands
|
||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "cluster-version"]);
|
.get_matches_from(vec!["test", "cluster-version"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_cluster_version).unwrap(),
|
parse_command(&test_cluster_version).unwrap(),
|
||||||
CliCommand::ClusterVersion
|
CliCommandInfo {
|
||||||
|
command: CliCommand::ClusterVersion,
|
||||||
|
require_keypair: false
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
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(&pubkey, &test_fees).unwrap(),
|
parse_command(&test_fees).unwrap(),
|
||||||
CliCommand::Fees
|
CliCommandInfo {
|
||||||
|
command: CliCommand::Fees,
|
||||||
|
require_keypair: false
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let test_get_epoch_info = test_commands
|
let test_get_epoch_info = test_commands
|
||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "get-epoch-info"]);
|
.get_matches_from(vec!["test", "get-epoch-info"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_get_epoch_info).unwrap(),
|
parse_command(&test_get_epoch_info).unwrap(),
|
||||||
CliCommand::GetEpochInfo
|
CliCommandInfo {
|
||||||
|
command: CliCommand::GetEpochInfo,
|
||||||
|
require_keypair: false
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let test_get_genesis_blockhash = test_commands
|
let test_get_genesis_blockhash = test_commands
|
||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "get-genesis-blockhash"]);
|
.get_matches_from(vec!["test", "get-genesis-blockhash"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_get_genesis_blockhash).unwrap(),
|
parse_command(&test_get_genesis_blockhash).unwrap(),
|
||||||
CliCommand::GetGenesisBlockhash
|
CliCommandInfo {
|
||||||
|
command: CliCommand::GetGenesisBlockhash,
|
||||||
|
require_keypair: false
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let test_get_slot = test_commands
|
let test_get_slot = test_commands
|
||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "get-slot"]);
|
.get_matches_from(vec!["test", "get-slot"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_get_slot).unwrap(),
|
parse_command(&test_get_slot).unwrap(),
|
||||||
CliCommand::GetSlot
|
CliCommandInfo {
|
||||||
|
command: CliCommand::GetSlot,
|
||||||
|
require_keypair: false
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let test_transaction_count = test_commands
|
let test_transaction_count = test_commands
|
||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "get-transaction-count"]);
|
.get_matches_from(vec!["test", "get-transaction-count"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_transaction_count).unwrap(),
|
parse_command(&test_transaction_count).unwrap(),
|
||||||
CliCommand::GetTransactionCount
|
CliCommandInfo {
|
||||||
|
command: CliCommand::GetTransactionCount,
|
||||||
|
require_keypair: false
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let test_ping = test_commands
|
let test_ping = test_commands
|
||||||
.clone()
|
.clone()
|
||||||
.get_matches_from(vec!["test", "ping", "-i", "1", "-c", "2", "-t", "3"]);
|
.get_matches_from(vec!["test", "ping", "-i", "1", "-c", "2", "-t", "3"]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_ping).unwrap(),
|
parse_command(&test_ping).unwrap(),
|
||||||
CliCommand::Ping {
|
CliCommandInfo {
|
||||||
interval: Duration::from_secs(1),
|
command: CliCommand::Ping {
|
||||||
count: Some(2),
|
interval: Duration::from_secs(1),
|
||||||
timeout: Duration::from_secs(3),
|
count: Some(2),
|
||||||
|
timeout: Duration::from_secs(3),
|
||||||
|
},
|
||||||
|
require_keypair: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use clap::{crate_description, crate_name, crate_version, Arg, ArgGroup, ArgMatches, SubCommand};
|
use clap::{crate_description, crate_name, crate_version, Arg, ArgGroup, ArgMatches, SubCommand};
|
||||||
use console::style;
|
use console::style;
|
||||||
use solana_cli::{
|
use solana_cli::{
|
||||||
cli::{app, parse_command, process_command, CliConfig, CliError},
|
cli::{app, parse_command, process_command, CliCommandInfo, CliConfig, CliError},
|
||||||
config::{self, Config},
|
config::{self, Config},
|
||||||
display::{println_name_value, println_name_value_or},
|
display::{println_name_value, println_name_value_or},
|
||||||
input_validators::is_url,
|
input_validators::is_url,
|
||||||
};
|
};
|
||||||
use solana_sdk::signature::{read_keypair_file, KeypairUtil};
|
use solana_sdk::signature::read_keypair_file;
|
||||||
use std::error;
|
use std::error;
|
||||||
|
|
||||||
fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error>> {
|
fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error>> {
|
||||||
|
@ -18,7 +18,7 @@ fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error
|
||||||
if let Some(field) = subcommand_matches.value_of("specific_setting") {
|
if let Some(field) = subcommand_matches.value_of("specific_setting") {
|
||||||
let (value, default_value) = match field {
|
let (value, default_value) = match field {
|
||||||
"url" => (config.url, default_cli_config.json_rpc_url),
|
"url" => (config.url, default_cli_config.json_rpc_url),
|
||||||
"keypair" => (config.keypair, default_cli_config.keypair_path),
|
"keypair" => (config.keypair, default_cli_config.keypair_path.unwrap()),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
println_name_value_or(&format!("* {}:", field), &value, &default_value);
|
println_name_value_or(&format!("* {}:", field), &value, &default_value);
|
||||||
|
@ -28,7 +28,7 @@ fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error
|
||||||
println_name_value_or(
|
println_name_value_or(
|
||||||
"* keypair:",
|
"* keypair:",
|
||||||
&config.keypair,
|
&config.keypair,
|
||||||
&default_cli_config.keypair_path,
|
&default_cli_config.keypair_path.unwrap(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -80,34 +80,44 @@ pub fn parse_args(matches: &ArgMatches<'_>) -> Result<CliConfig, Box<dyn error::
|
||||||
default.json_rpc_url
|
default.json_rpc_url
|
||||||
};
|
};
|
||||||
|
|
||||||
let keypair_path = if matches.is_present("keypair") {
|
let CliCommandInfo {
|
||||||
matches.value_of("keypair").unwrap().to_string()
|
command,
|
||||||
} else if config.keypair != "" {
|
require_keypair,
|
||||||
config.keypair
|
} = parse_command(&matches)?;
|
||||||
|
|
||||||
|
let (keypair, keypair_path) = if require_keypair {
|
||||||
|
let keypair_path = if matches.is_present("keypair") {
|
||||||
|
matches.value_of("keypair").unwrap().to_string()
|
||||||
|
} else if config.keypair != "" {
|
||||||
|
config.keypair
|
||||||
|
} else {
|
||||||
|
let default = CliConfig::default();
|
||||||
|
let maybe_keypair_path = default.keypair_path.unwrap();
|
||||||
|
if !std::path::Path::new(&maybe_keypair_path).exists() {
|
||||||
|
return Err(CliError::KeypairFileNotFound(
|
||||||
|
"Generate a new keypair with `solana-keygen new`".to_string(),
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
maybe_keypair_path
|
||||||
|
};
|
||||||
|
let keypair = read_keypair_file(&keypair_path).or_else(|err| {
|
||||||
|
Err(CliError::BadParameter(format!(
|
||||||
|
"{}: Unable to open keypair file: {}",
|
||||||
|
err, keypair_path
|
||||||
|
)))
|
||||||
|
})?;
|
||||||
|
(keypair, Some(keypair_path.to_string()))
|
||||||
} else {
|
} else {
|
||||||
let default = CliConfig::default();
|
let default = CliConfig::default();
|
||||||
if !std::path::Path::new(&default.keypair_path).exists() {
|
(default.keypair, None)
|
||||||
return Err(CliError::KeypairFileNotFound(
|
|
||||||
"Generate a new keypair with `solana-keygen new`".to_string(),
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
default.keypair_path
|
|
||||||
};
|
};
|
||||||
let keypair = read_keypair_file(&keypair_path).or_else(|err| {
|
|
||||||
Err(CliError::BadParameter(format!(
|
|
||||||
"{}: Unable to open keypair file: {}",
|
|
||||||
err, keypair_path
|
|
||||||
)))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let command = parse_command(&keypair.pubkey(), &matches)?;
|
|
||||||
|
|
||||||
Ok(CliConfig {
|
Ok(CliConfig {
|
||||||
command,
|
command,
|
||||||
json_rpc_url,
|
json_rpc_url,
|
||||||
keypair,
|
keypair,
|
||||||
keypair_path: keypair_path.to_string(),
|
keypair_path,
|
||||||
rpc_client: None,
|
rpc_client: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
200
cli/src/stake.rs
200
cli/src/stake.rs
|
@ -1,7 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{
|
cli::{
|
||||||
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||||
log_instruction_custom_error, CliCommand, CliConfig, CliError, ProcessResult,
|
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
|
||||||
|
ProcessResult,
|
||||||
},
|
},
|
||||||
input_parsers::*,
|
input_parsers::*,
|
||||||
input_validators::*,
|
input_validators::*,
|
||||||
|
@ -251,83 +252,95 @@ impl StakeSubCommands for App<'_, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_stake_create_account(
|
pub fn parse_stake_create_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
pubkey: &Pubkey,
|
|
||||||
matches: &ArgMatches<'_>,
|
|
||||||
) -> Result<CliCommand, CliError> {
|
|
||||||
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
let slot = value_of(&matches, "lockup").unwrap_or(0);
|
let slot = value_of(&matches, "lockup").unwrap_or(0);
|
||||||
let custodian = pubkey_of(matches, "custodian").unwrap_or_default();
|
let custodian = pubkey_of(matches, "custodian").unwrap_or_default();
|
||||||
let staker = pubkey_of(matches, "authorized_staker").unwrap_or(*pubkey); // defaults to config
|
let staker = pubkey_of(matches, "authorized_staker");
|
||||||
let withdrawer = pubkey_of(matches, "authorized_withdrawer").unwrap_or(*pubkey); // defaults to config
|
let withdrawer = pubkey_of(matches, "authorized_withdrawer");
|
||||||
let lamports = amount_of(matches, "amount", "unit").expect("Invalid amount");
|
let lamports = amount_of(matches, "amount", "unit").expect("Invalid amount");
|
||||||
|
|
||||||
Ok(CliCommand::CreateStakeAccount(
|
Ok(CliCommandInfo {
|
||||||
stake_account_pubkey,
|
command: CliCommand::CreateStakeAccount {
|
||||||
Authorized { staker, withdrawer },
|
stake_account_pubkey,
|
||||||
Lockup { custodian, slot },
|
staker,
|
||||||
lamports,
|
withdrawer,
|
||||||
))
|
lockup: Lockup { custodian, slot },
|
||||||
|
lamports,
|
||||||
|
},
|
||||||
|
require_keypair: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_stake_delegate_stake(matches: &ArgMatches<'_>) -> Result<CliCommand, CliError> {
|
pub fn parse_stake_delegate_stake(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||||
let force = matches.is_present("force");
|
let force = matches.is_present("force");
|
||||||
|
|
||||||
Ok(CliCommand::DelegateStake(
|
Ok(CliCommandInfo {
|
||||||
stake_account_pubkey,
|
command: CliCommand::DelegateStake(stake_account_pubkey, vote_account_pubkey, force),
|
||||||
vote_account_pubkey,
|
require_keypair: true,
|
||||||
force,
|
})
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_stake_authorize(
|
pub fn parse_stake_authorize(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
stake_authorize: StakeAuthorize,
|
stake_authorize: StakeAuthorize,
|
||||||
) -> Result<CliCommand, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
let authorized_pubkey = pubkey_of(matches, "authorized_pubkey").unwrap();
|
let authorized_pubkey = pubkey_of(matches, "authorized_pubkey").unwrap();
|
||||||
|
|
||||||
Ok(CliCommand::StakeAuthorize(
|
Ok(CliCommandInfo {
|
||||||
stake_account_pubkey,
|
command: CliCommand::StakeAuthorize(
|
||||||
authorized_pubkey,
|
stake_account_pubkey,
|
||||||
stake_authorize,
|
authorized_pubkey,
|
||||||
))
|
stake_authorize,
|
||||||
|
),
|
||||||
|
require_keypair: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_redeem_vote_credits(matches: &ArgMatches<'_>) -> Result<CliCommand, CliError> {
|
pub fn parse_redeem_vote_credits(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||||
Ok(CliCommand::RedeemVoteCredits(
|
Ok(CliCommandInfo {
|
||||||
stake_account_pubkey,
|
command: CliCommand::RedeemVoteCredits(stake_account_pubkey, vote_account_pubkey),
|
||||||
vote_account_pubkey,
|
require_keypair: true,
|
||||||
))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_stake_deactivate_stake(matches: &ArgMatches<'_>) -> Result<CliCommand, CliError> {
|
pub fn parse_stake_deactivate_stake(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
Ok(CliCommand::DeactivateStake(stake_account_pubkey))
|
Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::DeactivateStake(stake_account_pubkey),
|
||||||
|
require_keypair: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_stake_withdraw_stake(matches: &ArgMatches<'_>) -> Result<CliCommand, CliError> {
|
pub fn parse_stake_withdraw_stake(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
let destination_account_pubkey = pubkey_of(matches, "destination_account_pubkey").unwrap();
|
let destination_account_pubkey = pubkey_of(matches, "destination_account_pubkey").unwrap();
|
||||||
let lamports = amount_of(matches, "amount", "unit").expect("Invalid amount");
|
let lamports = amount_of(matches, "amount", "unit").expect("Invalid amount");
|
||||||
|
|
||||||
Ok(CliCommand::WithdrawStake(
|
Ok(CliCommandInfo {
|
||||||
stake_account_pubkey,
|
command: CliCommand::WithdrawStake(
|
||||||
destination_account_pubkey,
|
stake_account_pubkey,
|
||||||
lamports,
|
destination_account_pubkey,
|
||||||
))
|
lamports,
|
||||||
|
),
|
||||||
|
require_keypair: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_show_stake_account(matches: &ArgMatches<'_>) -> Result<CliCommand, CliError> {
|
pub fn parse_show_stake_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
let stake_account_pubkey = pubkey_of(matches, "stake_account_pubkey").unwrap();
|
||||||
let use_lamports_unit = matches.is_present("lamports");
|
let use_lamports_unit = matches.is_present("lamports");
|
||||||
Ok(CliCommand::ShowStakeAccount {
|
Ok(CliCommandInfo {
|
||||||
pubkey: stake_account_pubkey,
|
command: CliCommand::ShowStakeAccount {
|
||||||
use_lamports_unit,
|
pubkey: stake_account_pubkey,
|
||||||
|
use_lamports_unit,
|
||||||
|
},
|
||||||
|
require_keypair: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,7 +348,8 @@ pub fn process_create_stake_account(
|
||||||
rpc_client: &RpcClient,
|
rpc_client: &RpcClient,
|
||||||
config: &CliConfig,
|
config: &CliConfig,
|
||||||
stake_account_pubkey: &Pubkey,
|
stake_account_pubkey: &Pubkey,
|
||||||
authorized: &Authorized,
|
staker: &Option<Pubkey>,
|
||||||
|
withdrawer: &Option<Pubkey>,
|
||||||
lockup: &Lockup,
|
lockup: &Lockup,
|
||||||
lamports: u64,
|
lamports: u64,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
|
@ -363,10 +377,16 @@ pub fn process_create_stake_account(
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let authorized = Authorized {
|
||||||
|
staker: staker.unwrap_or(config.keypair.pubkey()),
|
||||||
|
withdrawer: withdrawer.unwrap_or(config.keypair.pubkey()),
|
||||||
|
};
|
||||||
|
println!("{:?}", authorized);
|
||||||
|
|
||||||
let ixs = stake_instruction::create_stake_account_with_lockup(
|
let ixs = stake_instruction::create_stake_account_with_lockup(
|
||||||
&config.keypair.pubkey(),
|
&config.keypair.pubkey(),
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
authorized,
|
&authorized,
|
||||||
lockup,
|
lockup,
|
||||||
lamports,
|
lamports,
|
||||||
);
|
);
|
||||||
|
@ -636,8 +656,11 @@ mod tests {
|
||||||
&pubkey_string,
|
&pubkey_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_authorize_staker).unwrap(),
|
parse_command(&test_authorize_staker).unwrap(),
|
||||||
CliCommand::StakeAuthorize(pubkey, pubkey, StakeAuthorize::Staker)
|
CliCommandInfo {
|
||||||
|
command: CliCommand::StakeAuthorize(pubkey, pubkey, StakeAuthorize::Staker),
|
||||||
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
let test_authorize_withdrawer = test_commands.clone().get_matches_from(vec![
|
let test_authorize_withdrawer = test_commands.clone().get_matches_from(vec![
|
||||||
"test",
|
"test",
|
||||||
|
@ -646,8 +669,11 @@ mod tests {
|
||||||
&pubkey_string,
|
&pubkey_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_authorize_withdrawer).unwrap(),
|
parse_command(&test_authorize_withdrawer).unwrap(),
|
||||||
CliCommand::StakeAuthorize(pubkey, pubkey, StakeAuthorize::Withdrawer)
|
CliCommandInfo {
|
||||||
|
command: CliCommand::StakeAuthorize(pubkey, pubkey, StakeAuthorize::Withdrawer),
|
||||||
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test CreateStakeAccount SubCommand
|
// Test CreateStakeAccount SubCommand
|
||||||
|
@ -671,19 +697,20 @@ mod tests {
|
||||||
"lamports",
|
"lamports",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_create_stake_account).unwrap(),
|
parse_command(&test_create_stake_account).unwrap(),
|
||||||
CliCommand::CreateStakeAccount(
|
CliCommandInfo {
|
||||||
pubkey,
|
command: CliCommand::CreateStakeAccount {
|
||||||
Authorized {
|
stake_account_pubkey: pubkey,
|
||||||
staker: authorized,
|
staker: Some(authorized),
|
||||||
withdrawer: authorized,
|
withdrawer: Some(authorized),
|
||||||
|
lockup: Lockup {
|
||||||
|
slot: 43,
|
||||||
|
custodian,
|
||||||
|
},
|
||||||
|
lamports: 50
|
||||||
},
|
},
|
||||||
Lockup {
|
require_keypair: true
|
||||||
slot: 43,
|
}
|
||||||
custodian,
|
|
||||||
},
|
|
||||||
50
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
let test_create_stake_account2 = test_commands.clone().get_matches_from(vec![
|
let test_create_stake_account2 = test_commands.clone().get_matches_from(vec![
|
||||||
"test",
|
"test",
|
||||||
|
@ -693,19 +720,20 @@ mod tests {
|
||||||
"lamports",
|
"lamports",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_create_stake_account2).unwrap(),
|
parse_command(&test_create_stake_account2).unwrap(),
|
||||||
CliCommand::CreateStakeAccount(
|
CliCommandInfo {
|
||||||
pubkey,
|
command: CliCommand::CreateStakeAccount {
|
||||||
Authorized {
|
stake_account_pubkey: pubkey,
|
||||||
staker: pubkey,
|
staker: None,
|
||||||
withdrawer: pubkey,
|
withdrawer: None,
|
||||||
|
lockup: Lockup {
|
||||||
|
slot: 0,
|
||||||
|
custodian: Pubkey::default(),
|
||||||
|
},
|
||||||
|
lamports: 50
|
||||||
},
|
},
|
||||||
Lockup {
|
require_keypair: true
|
||||||
slot: 0,
|
}
|
||||||
custodian: Pubkey::default(),
|
|
||||||
},
|
|
||||||
50
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test DelegateStake Subcommand
|
// Test DelegateStake Subcommand
|
||||||
|
@ -718,8 +746,11 @@ mod tests {
|
||||||
&pubkey_string,
|
&pubkey_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_delegate_stake).unwrap(),
|
parse_command(&test_delegate_stake).unwrap(),
|
||||||
CliCommand::DelegateStake(stake_pubkey, pubkey, false,)
|
CliCommandInfo {
|
||||||
|
command: CliCommand::DelegateStake(stake_pubkey, pubkey, false),
|
||||||
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
let test_delegate_stake = test_commands.clone().get_matches_from(vec![
|
||||||
|
@ -730,8 +761,11 @@ mod tests {
|
||||||
&pubkey_string,
|
&pubkey_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_delegate_stake).unwrap(),
|
parse_command(&test_delegate_stake).unwrap(),
|
||||||
CliCommand::DelegateStake(stake_pubkey, pubkey, true)
|
CliCommandInfo {
|
||||||
|
command: CliCommand::DelegateStake(stake_pubkey, pubkey, true),
|
||||||
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test WithdrawStake Subcommand
|
// Test WithdrawStake Subcommand
|
||||||
|
@ -745,8 +779,11 @@ mod tests {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_withdraw_stake).unwrap(),
|
parse_command(&test_withdraw_stake).unwrap(),
|
||||||
CliCommand::WithdrawStake(stake_pubkey, pubkey, 42)
|
CliCommandInfo {
|
||||||
|
command: CliCommand::WithdrawStake(stake_pubkey, pubkey, 42),
|
||||||
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test DeactivateStake Subcommand
|
// Test DeactivateStake Subcommand
|
||||||
|
@ -756,8 +793,11 @@ mod tests {
|
||||||
&stake_pubkey_string,
|
&stake_pubkey_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_deactivate_stake).unwrap(),
|
parse_command(&test_deactivate_stake).unwrap(),
|
||||||
CliCommand::DeactivateStake(stake_pubkey)
|
CliCommandInfo {
|
||||||
|
command: CliCommand::DeactivateStake(stake_pubkey),
|
||||||
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// TODO: Add process tests
|
// TODO: Add process tests
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{
|
cli::{
|
||||||
check_account_for_fee, check_unique_pubkeys, log_instruction_custom_error, CliCommand,
|
check_account_for_fee, check_unique_pubkeys, log_instruction_custom_error, CliCommand,
|
||||||
CliConfig, CliError, ProcessResult,
|
CliCommandInfo, CliConfig, CliError, ProcessResult,
|
||||||
},
|
},
|
||||||
input_parsers::*,
|
input_parsers::*,
|
||||||
input_validators::*,
|
input_validators::*,
|
||||||
|
@ -100,40 +100,54 @@ impl StorageSubCommands for App<'_, '_> {
|
||||||
|
|
||||||
pub fn parse_storage_create_archiver_account(
|
pub fn parse_storage_create_archiver_account(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
) -> Result<CliCommand, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
|
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
|
||||||
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
||||||
Ok(CliCommand::CreateStorageAccount {
|
Ok(CliCommandInfo {
|
||||||
account_owner,
|
command: CliCommand::CreateStorageAccount {
|
||||||
storage_account_pubkey,
|
account_owner,
|
||||||
account_type: StorageAccountType::Archiver,
|
storage_account_pubkey,
|
||||||
|
account_type: StorageAccountType::Archiver,
|
||||||
|
},
|
||||||
|
require_keypair: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_storage_create_validator_account(
|
pub fn parse_storage_create_validator_account(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
) -> Result<CliCommand, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
|
let account_owner = pubkey_of(matches, "storage_account_owner").unwrap();
|
||||||
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
||||||
Ok(CliCommand::CreateStorageAccount {
|
Ok(CliCommandInfo {
|
||||||
account_owner,
|
command: CliCommand::CreateStorageAccount {
|
||||||
storage_account_pubkey,
|
account_owner,
|
||||||
account_type: StorageAccountType::Validator,
|
storage_account_pubkey,
|
||||||
|
account_type: StorageAccountType::Validator,
|
||||||
|
},
|
||||||
|
require_keypair: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_storage_claim_reward(matches: &ArgMatches<'_>) -> Result<CliCommand, CliError> {
|
pub fn parse_storage_claim_reward(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
let node_account_pubkey = pubkey_of(matches, "node_account_pubkey").unwrap();
|
let node_account_pubkey = pubkey_of(matches, "node_account_pubkey").unwrap();
|
||||||
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
||||||
Ok(CliCommand::ClaimStorageReward {
|
Ok(CliCommandInfo {
|
||||||
node_account_pubkey,
|
command: CliCommand::ClaimStorageReward {
|
||||||
storage_account_pubkey,
|
node_account_pubkey,
|
||||||
|
storage_account_pubkey,
|
||||||
|
},
|
||||||
|
require_keypair: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_storage_get_account_command(matches: &ArgMatches<'_>) -> Result<CliCommand, CliError> {
|
pub fn parse_storage_get_account_command(
|
||||||
|
matches: &ArgMatches<'_>,
|
||||||
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
let storage_account_pubkey = pubkey_of(matches, "storage_account_pubkey").unwrap();
|
||||||
Ok(CliCommand::ShowStorageAccount(storage_account_pubkey))
|
Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::ShowStorageAccount(storage_account_pubkey),
|
||||||
|
require_keypair: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_create_storage_account(
|
pub fn process_create_storage_account(
|
||||||
|
@ -228,11 +242,14 @@ mod tests {
|
||||||
&storage_account_string,
|
&storage_account_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_create_archiver_storage_account).unwrap(),
|
parse_command(&test_create_archiver_storage_account).unwrap(),
|
||||||
CliCommand::CreateStorageAccount {
|
CliCommandInfo {
|
||||||
account_owner: pubkey,
|
command: CliCommand::CreateStorageAccount {
|
||||||
storage_account_pubkey,
|
account_owner: pubkey,
|
||||||
account_type: StorageAccountType::Archiver,
|
storage_account_pubkey,
|
||||||
|
account_type: StorageAccountType::Archiver,
|
||||||
|
},
|
||||||
|
require_keypair: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -243,11 +260,14 @@ mod tests {
|
||||||
&storage_account_string,
|
&storage_account_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_create_validator_storage_account).unwrap(),
|
parse_command(&test_create_validator_storage_account).unwrap(),
|
||||||
CliCommand::CreateStorageAccount {
|
CliCommandInfo {
|
||||||
account_owner: pubkey,
|
command: CliCommand::CreateStorageAccount {
|
||||||
storage_account_pubkey,
|
account_owner: pubkey,
|
||||||
account_type: StorageAccountType::Validator,
|
storage_account_pubkey,
|
||||||
|
account_type: StorageAccountType::Validator,
|
||||||
|
},
|
||||||
|
require_keypair: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -258,10 +278,13 @@ mod tests {
|
||||||
&storage_account_string,
|
&storage_account_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_claim_storage_reward).unwrap(),
|
parse_command(&test_claim_storage_reward).unwrap(),
|
||||||
CliCommand::ClaimStorageReward {
|
CliCommandInfo {
|
||||||
node_account_pubkey: pubkey,
|
command: CliCommand::ClaimStorageReward {
|
||||||
storage_account_pubkey,
|
node_account_pubkey: pubkey,
|
||||||
|
storage_account_pubkey,
|
||||||
|
},
|
||||||
|
require_keypair: true
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{check_account_for_fee, CliCommand, CliConfig, CliError, ProcessResult},
|
cli::{check_account_for_fee, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
|
||||||
input_validators::is_url,
|
input_parsers::pubkey_of,
|
||||||
|
input_validators::{is_pubkey, is_url},
|
||||||
};
|
};
|
||||||
use bincode::deserialize;
|
use bincode::deserialize;
|
||||||
use clap::ArgMatches;
|
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
|
@ -142,28 +143,123 @@ fn parse_validator_info(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_info_pubkey(matches: &ArgMatches<'_>) -> Result<Option<Pubkey>, CliError> {
|
pub trait ValidatorInfoSubCommands {
|
||||||
let info_pubkey = if let Some(pubkey) = matches.value_of("info_pubkey") {
|
fn validator_info_subcommands(self) -> Self;
|
||||||
Some(pubkey.parse::<Pubkey>().map_err(|err| {
|
|
||||||
CliError::BadParameter(format!("Invalid validator info pubkey: {:?}", err))
|
|
||||||
})?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
Ok(info_pubkey)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_validator_info_command(
|
impl ValidatorInfoSubCommands for App<'_, '_> {
|
||||||
matches: &ArgMatches<'_>,
|
fn validator_info_subcommands(self) -> Self {
|
||||||
validator_pubkey: &Pubkey,
|
self.subcommand(
|
||||||
) -> Result<CliCommand, CliError> {
|
SubCommand::with_name("validator-info")
|
||||||
let info_pubkey = parse_info_pubkey(matches)?;
|
.about("Publish/get Validator info on Solana")
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("publish")
|
||||||
|
.about("Publish Validator info on Solana")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("info_pubkey")
|
||||||
|
.short("p")
|
||||||
|
.long("info-pubkey")
|
||||||
|
.value_name("PUBKEY")
|
||||||
|
.takes_value(true)
|
||||||
|
.validator(is_pubkey)
|
||||||
|
.help("The pubkey of the Validator info account to update"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("name")
|
||||||
|
.index(1)
|
||||||
|
.value_name("NAME")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.validator(is_short_field)
|
||||||
|
.help("Validator name"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("website")
|
||||||
|
.short("w")
|
||||||
|
.long("website")
|
||||||
|
.value_name("URL")
|
||||||
|
.takes_value(true)
|
||||||
|
.validator(check_url)
|
||||||
|
.help("Validator website url"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("keybase_username")
|
||||||
|
.short("n")
|
||||||
|
.long("keybase")
|
||||||
|
.value_name("USERNAME")
|
||||||
|
.takes_value(true)
|
||||||
|
.validator(is_short_field)
|
||||||
|
.help("Validator Keybase username"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("details")
|
||||||
|
.short("d")
|
||||||
|
.long("details")
|
||||||
|
.value_name("DETAILS")
|
||||||
|
.takes_value(true)
|
||||||
|
.validator(check_details_length)
|
||||||
|
.help("Validator description")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("force")
|
||||||
|
.long("force")
|
||||||
|
.takes_value(false)
|
||||||
|
.hidden(true) // Don't document this argument to discourage its use
|
||||||
|
.help("Override keybase username validity check"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("get")
|
||||||
|
.about("Get and parse Solana Validator info")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("info_pubkey")
|
||||||
|
.index(1)
|
||||||
|
.value_name("PUBKEY")
|
||||||
|
.takes_value(true)
|
||||||
|
.validator(is_pubkey)
|
||||||
|
.help("The pubkey of the Validator info account; without this argument, returns all"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_validator_info_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
|
let info_pubkey = pubkey_of(matches, "info_pubkey");
|
||||||
// Prepare validator info
|
// Prepare validator info
|
||||||
let validator_info = parse_args(&matches);
|
let validator_info = parse_args(&matches);
|
||||||
|
Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::SetValidatorInfo {
|
||||||
|
validator_info,
|
||||||
|
force_keybase: matches.is_present("force"),
|
||||||
|
info_pubkey,
|
||||||
|
},
|
||||||
|
require_keypair: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_get_validator_info_command(
|
||||||
|
matches: &ArgMatches<'_>,
|
||||||
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
|
let info_pubkey = pubkey_of(matches, "info_pubkey");
|
||||||
|
Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::GetValidatorInfo(info_pubkey),
|
||||||
|
require_keypair: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_set_validator_info(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
config: &CliConfig,
|
||||||
|
validator_info: &Value,
|
||||||
|
force_keybase: bool,
|
||||||
|
info_pubkey: Option<Pubkey>,
|
||||||
|
) -> ProcessResult {
|
||||||
|
// Validate keybase username
|
||||||
if let Some(string) = validator_info.get("keybaseUsername") {
|
if let Some(string) = validator_info.get("keybaseUsername") {
|
||||||
let result = verify_keybase(&validator_pubkey, &string);
|
let result = verify_keybase(&config.keypair.pubkey(), &string);
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
if matches.is_present("force") {
|
if force_keybase {
|
||||||
println!("--force supplied, ignoring: {:?}", result);
|
println!("--force supplied, ignoring: {:?}", result);
|
||||||
} else {
|
} else {
|
||||||
result.map_err(|err| {
|
result.map_err(|err| {
|
||||||
|
@ -176,20 +272,6 @@ pub fn parse_validator_info_command(
|
||||||
let validator_info = ValidatorInfo {
|
let validator_info = ValidatorInfo {
|
||||||
info: validator_string,
|
info: validator_string,
|
||||||
};
|
};
|
||||||
Ok(CliCommand::SetValidatorInfo(validator_info, info_pubkey))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_get_validator_info_command(matches: &ArgMatches<'_>) -> Result<CliCommand, CliError> {
|
|
||||||
let info_pubkey = parse_info_pubkey(matches)?;
|
|
||||||
Ok(CliCommand::GetValidatorInfo(info_pubkey))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_set_validator_info(
|
|
||||||
rpc_client: &RpcClient,
|
|
||||||
config: &CliConfig,
|
|
||||||
validator_info: &ValidatorInfo,
|
|
||||||
info_pubkey: Option<Pubkey>,
|
|
||||||
) -> ProcessResult {
|
|
||||||
// Check for existing validator-info account
|
// Check for existing validator-info account
|
||||||
let all_config = rpc_client.get_program_accounts(&solana_config_api::id())?;
|
let all_config = rpc_client.get_program_accounts(&solana_config_api::id())?;
|
||||||
let existing_account = all_config
|
let existing_account = all_config
|
||||||
|
@ -239,7 +321,7 @@ pub fn process_set_validator_info(
|
||||||
&info_keypair.pubkey(),
|
&info_keypair.pubkey(),
|
||||||
true,
|
true,
|
||||||
keys,
|
keys,
|
||||||
validator_info,
|
&validator_info,
|
||||||
)]);
|
)]);
|
||||||
let signers = vec![&config.keypair, &info_keypair];
|
let signers = vec![&config.keypair, &info_keypair];
|
||||||
let message = Message::new(instructions);
|
let message = Message::new(instructions);
|
||||||
|
@ -254,7 +336,7 @@ pub fn process_set_validator_info(
|
||||||
&info_pubkey,
|
&info_pubkey,
|
||||||
false,
|
false,
|
||||||
keys,
|
keys,
|
||||||
validator_info,
|
&validator_info,
|
||||||
)];
|
)];
|
||||||
let message = Message::new_with_payer(instructions, Some(&config.keypair.pubkey()));
|
let message = Message::new_with_payer(instructions, Some(&config.keypair.pubkey()));
|
||||||
let signers = vec![&config.keypair];
|
let signers = vec![&config.keypair];
|
||||||
|
|
177
cli/src/vote.rs
177
cli/src/vote.rs
|
@ -1,7 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{
|
cli::{
|
||||||
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||||
log_instruction_custom_error, CliCommand, CliConfig, CliError, ProcessResult,
|
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
|
||||||
|
ProcessResult,
|
||||||
},
|
},
|
||||||
input_parsers::*,
|
input_parsers::*,
|
||||||
input_validators::*,
|
input_validators::*,
|
||||||
|
@ -159,51 +160,57 @@ impl VoteSubCommands for App<'_, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_vote_create_account(
|
pub fn parse_vote_create_account(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
pubkey: &Pubkey,
|
|
||||||
matches: &ArgMatches<'_>,
|
|
||||||
) -> Result<CliCommand, CliError> {
|
|
||||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||||
let node_pubkey = pubkey_of(matches, "node_pubkey").unwrap();
|
let node_pubkey = pubkey_of(matches, "node_pubkey").unwrap();
|
||||||
let commission = value_of(&matches, "commission").unwrap_or(0);
|
let commission = value_of(&matches, "commission").unwrap_or(0);
|
||||||
let authorized_voter = pubkey_of(matches, "authorized_voter").unwrap_or(vote_account_pubkey);
|
let authorized_voter = pubkey_of(matches, "authorized_voter");
|
||||||
let authorized_withdrawer = pubkey_of(matches, "authorized_withdrawer").unwrap_or(*pubkey);
|
let authorized_withdrawer = pubkey_of(matches, "authorized_withdrawer");
|
||||||
|
|
||||||
Ok(CliCommand::CreateVoteAccount(
|
Ok(CliCommandInfo {
|
||||||
vote_account_pubkey,
|
command: CliCommand::CreateVoteAccount {
|
||||||
VoteInit {
|
vote_account_pubkey,
|
||||||
node_pubkey,
|
node_pubkey,
|
||||||
authorized_voter,
|
authorized_voter,
|
||||||
authorized_withdrawer,
|
authorized_withdrawer,
|
||||||
commission,
|
commission,
|
||||||
},
|
},
|
||||||
))
|
require_keypair: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_vote_authorize(
|
pub fn parse_vote_authorize(
|
||||||
matches: &ArgMatches<'_>,
|
matches: &ArgMatches<'_>,
|
||||||
vote_authorize: VoteAuthorize,
|
vote_authorize: VoteAuthorize,
|
||||||
) -> Result<CliCommand, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||||
let new_authorized_pubkey = pubkey_of(matches, "new_authorized_pubkey").unwrap();
|
let new_authorized_pubkey = pubkey_of(matches, "new_authorized_pubkey").unwrap();
|
||||||
|
|
||||||
Ok(CliCommand::VoteAuthorize(
|
Ok(CliCommandInfo {
|
||||||
vote_account_pubkey,
|
command: CliCommand::VoteAuthorize(
|
||||||
new_authorized_pubkey,
|
vote_account_pubkey,
|
||||||
vote_authorize,
|
new_authorized_pubkey,
|
||||||
))
|
vote_authorize,
|
||||||
}
|
),
|
||||||
|
require_keypair: true,
|
||||||
pub fn parse_vote_get_account_command(matches: &ArgMatches<'_>) -> Result<CliCommand, CliError> {
|
|
||||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
|
||||||
let use_lamports_unit = matches.is_present("lamports");
|
|
||||||
Ok(CliCommand::ShowVoteAccount {
|
|
||||||
pubkey: vote_account_pubkey,
|
|
||||||
use_lamports_unit,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_vote_uptime_command(matches: &ArgMatches<'_>) -> Result<CliCommand, CliError> {
|
pub fn parse_vote_get_account_command(
|
||||||
|
matches: &ArgMatches<'_>,
|
||||||
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
|
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||||
|
let use_lamports_unit = matches.is_present("lamports");
|
||||||
|
Ok(CliCommandInfo {
|
||||||
|
command: CliCommand::ShowVoteAccount {
|
||||||
|
pubkey: vote_account_pubkey,
|
||||||
|
use_lamports_unit,
|
||||||
|
},
|
||||||
|
require_keypair: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_vote_uptime_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||||
let aggregate = matches.is_present("aggregate");
|
let aggregate = matches.is_present("aggregate");
|
||||||
let span = if matches.is_present("span") {
|
let span = if matches.is_present("span") {
|
||||||
|
@ -211,10 +218,13 @@ pub fn parse_vote_uptime_command(matches: &ArgMatches<'_>) -> Result<CliCommand,
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
Ok(CliCommand::Uptime {
|
Ok(CliCommandInfo {
|
||||||
pubkey: vote_account_pubkey,
|
command: CliCommand::Uptime {
|
||||||
aggregate,
|
pubkey: vote_account_pubkey,
|
||||||
span,
|
aggregate,
|
||||||
|
span,
|
||||||
|
},
|
||||||
|
require_keypair: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,11 +232,14 @@ pub fn process_create_vote_account(
|
||||||
rpc_client: &RpcClient,
|
rpc_client: &RpcClient,
|
||||||
config: &CliConfig,
|
config: &CliConfig,
|
||||||
vote_account_pubkey: &Pubkey,
|
vote_account_pubkey: &Pubkey,
|
||||||
vote_init: &VoteInit,
|
node_pubkey: &Pubkey,
|
||||||
|
authorized_voter: &Option<Pubkey>,
|
||||||
|
authorized_withdrawer: &Option<Pubkey>,
|
||||||
|
commission: u8,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
check_unique_pubkeys(
|
check_unique_pubkeys(
|
||||||
(vote_account_pubkey, "vote_account_pubkey".to_string()),
|
(vote_account_pubkey, "vote_account_pubkey".to_string()),
|
||||||
(&vote_init.node_pubkey, "node_pubkey".to_string()),
|
(&node_pubkey, "node_pubkey".to_string()),
|
||||||
)?;
|
)?;
|
||||||
check_unique_pubkeys(
|
check_unique_pubkeys(
|
||||||
(&config.keypair.pubkey(), "cli keypair".to_string()),
|
(&config.keypair.pubkey(), "cli keypair".to_string()),
|
||||||
|
@ -239,10 +252,16 @@ pub fn process_create_vote_account(
|
||||||
} else {
|
} else {
|
||||||
1
|
1
|
||||||
};
|
};
|
||||||
|
let vote_init = VoteInit {
|
||||||
|
node_pubkey: *node_pubkey,
|
||||||
|
authorized_voter: authorized_voter.unwrap_or(*vote_account_pubkey),
|
||||||
|
authorized_withdrawer: authorized_withdrawer.unwrap_or(config.keypair.pubkey()),
|
||||||
|
commission,
|
||||||
|
};
|
||||||
let ixs = vote_instruction::create_account(
|
let ixs = vote_instruction::create_account(
|
||||||
&config.keypair.pubkey(),
|
&config.keypair.pubkey(),
|
||||||
vote_account_pubkey,
|
vote_account_pubkey,
|
||||||
vote_init,
|
&vote_init,
|
||||||
lamports,
|
lamports,
|
||||||
);
|
);
|
||||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
|
@ -441,8 +460,11 @@ mod tests {
|
||||||
&pubkey_string,
|
&pubkey_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_authorize_voter).unwrap(),
|
parse_command(&test_authorize_voter).unwrap(),
|
||||||
CliCommand::VoteAuthorize(pubkey, pubkey, VoteAuthorize::Voter)
|
CliCommandInfo {
|
||||||
|
command: CliCommand::VoteAuthorize(pubkey, pubkey, VoteAuthorize::Voter),
|
||||||
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test CreateVoteAccount SubCommand
|
// Test CreateVoteAccount SubCommand
|
||||||
|
@ -457,16 +479,17 @@ mod tests {
|
||||||
"10",
|
"10",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_create_vote_account).unwrap(),
|
parse_command(&test_create_vote_account).unwrap(),
|
||||||
CliCommand::CreateVoteAccount(
|
CliCommandInfo {
|
||||||
pubkey,
|
command: CliCommand::CreateVoteAccount {
|
||||||
VoteInit {
|
vote_account_pubkey: pubkey,
|
||||||
node_pubkey,
|
node_pubkey,
|
||||||
authorized_voter: pubkey,
|
authorized_voter: None,
|
||||||
authorized_withdrawer: pubkey,
|
authorized_withdrawer: None,
|
||||||
commission: 10
|
commission: 10,
|
||||||
}
|
},
|
||||||
)
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
let test_create_vote_account2 = test_commands.clone().get_matches_from(vec![
|
let test_create_vote_account2 = test_commands.clone().get_matches_from(vec![
|
||||||
"test",
|
"test",
|
||||||
|
@ -475,16 +498,17 @@ mod tests {
|
||||||
&node_pubkey_string,
|
&node_pubkey_string,
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_create_vote_account2).unwrap(),
|
parse_command(&test_create_vote_account2).unwrap(),
|
||||||
CliCommand::CreateVoteAccount(
|
CliCommandInfo {
|
||||||
pubkey,
|
command: CliCommand::CreateVoteAccount {
|
||||||
VoteInit {
|
vote_account_pubkey: pubkey,
|
||||||
node_pubkey,
|
node_pubkey,
|
||||||
authorized_voter: pubkey,
|
authorized_voter: None,
|
||||||
authorized_withdrawer: pubkey,
|
authorized_withdrawer: None,
|
||||||
commission: 0
|
commission: 0,
|
||||||
}
|
},
|
||||||
)
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
// test init with an authed voter
|
// test init with an authed voter
|
||||||
let authed = Pubkey::new_rand();
|
let authed = Pubkey::new_rand();
|
||||||
|
@ -497,16 +521,17 @@ mod tests {
|
||||||
&authed.to_string(),
|
&authed.to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_create_vote_account3).unwrap(),
|
parse_command(&test_create_vote_account3).unwrap(),
|
||||||
CliCommand::CreateVoteAccount(
|
CliCommandInfo {
|
||||||
pubkey,
|
command: CliCommand::CreateVoteAccount {
|
||||||
VoteInit {
|
vote_account_pubkey: pubkey,
|
||||||
node_pubkey,
|
node_pubkey,
|
||||||
authorized_voter: authed,
|
authorized_voter: Some(authed),
|
||||||
authorized_withdrawer: pubkey,
|
authorized_withdrawer: None,
|
||||||
commission: 0
|
commission: 0
|
||||||
}
|
},
|
||||||
)
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
// test init with an authed withdrawer
|
// test init with an authed withdrawer
|
||||||
let test_create_vote_account4 = test_commands.clone().get_matches_from(vec![
|
let test_create_vote_account4 = test_commands.clone().get_matches_from(vec![
|
||||||
|
@ -518,16 +543,17 @@ mod tests {
|
||||||
&authed.to_string(),
|
&authed.to_string(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &test_create_vote_account4).unwrap(),
|
parse_command(&test_create_vote_account4).unwrap(),
|
||||||
CliCommand::CreateVoteAccount(
|
CliCommandInfo {
|
||||||
pubkey,
|
command: CliCommand::CreateVoteAccount {
|
||||||
VoteInit {
|
vote_account_pubkey: pubkey,
|
||||||
node_pubkey,
|
node_pubkey,
|
||||||
authorized_voter: pubkey,
|
authorized_voter: None,
|
||||||
authorized_withdrawer: authed,
|
authorized_withdrawer: Some(authed),
|
||||||
commission: 0
|
commission: 0
|
||||||
}
|
},
|
||||||
)
|
require_keypair: true
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test Uptime Subcommand
|
// Test Uptime Subcommand
|
||||||
|
@ -541,11 +567,14 @@ mod tests {
|
||||||
"--aggregate",
|
"--aggregate",
|
||||||
]);
|
]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_command(&pubkey, &matches).unwrap(),
|
parse_command(&matches).unwrap(),
|
||||||
CliCommand::Uptime {
|
CliCommandInfo {
|
||||||
pubkey,
|
command: CliCommand::Uptime {
|
||||||
aggregate: true,
|
pubkey,
|
||||||
span: Some(4)
|
aggregate: true,
|
||||||
|
span: Some(4)
|
||||||
|
},
|
||||||
|
require_keypair: false
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ fn test_cli_timestamp_tx() {
|
||||||
timestamp: Some(dt),
|
timestamp: Some(dt),
|
||||||
timestamp_pubkey: Some(config_witness.keypair.pubkey()),
|
timestamp_pubkey: Some(config_witness.keypair.pubkey()),
|
||||||
witnesses: None,
|
witnesses: None,
|
||||||
cancelable: None,
|
cancelable: false,
|
||||||
};
|
};
|
||||||
let sig_response = process_command(&config_payer);
|
let sig_response = process_command(&config_payer);
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ fn test_cli_witness_tx() {
|
||||||
timestamp: None,
|
timestamp: None,
|
||||||
timestamp_pubkey: None,
|
timestamp_pubkey: None,
|
||||||
witnesses: Some(vec![config_witness.keypair.pubkey()]),
|
witnesses: Some(vec![config_witness.keypair.pubkey()]),
|
||||||
cancelable: None,
|
cancelable: false,
|
||||||
};
|
};
|
||||||
let sig_response = process_command(&config_payer);
|
let sig_response = process_command(&config_payer);
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ fn test_cli_cancel_tx() {
|
||||||
timestamp: None,
|
timestamp: None,
|
||||||
timestamp_pubkey: None,
|
timestamp_pubkey: None,
|
||||||
witnesses: Some(vec![config_witness.keypair.pubkey()]),
|
witnesses: Some(vec![config_witness.keypair.pubkey()]),
|
||||||
cancelable: Some(config_payer.keypair.pubkey()),
|
cancelable: true,
|
||||||
};
|
};
|
||||||
let sig_response = process_command(&config_payer).unwrap();
|
let sig_response = process_command(&config_payer).unwrap();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue