Cherry-pick vote and stake authority changes (#6127)
* add authorized parameters to vote api (#6072) * add authorized parameters to vote api * code review * add authorities to stake init (#6104) * add authorities to stake init * fixups * code review
This commit is contained in:
147
cli/src/vote.rs
147
cli/src/vote.rs
@@ -15,13 +15,16 @@ use solana_sdk::{
|
||||
};
|
||||
use solana_vote_api::{
|
||||
vote_instruction::{self, VoteError},
|
||||
vote_state::VoteState,
|
||||
vote_state::{VoteAuthorize, VoteInit, VoteState},
|
||||
};
|
||||
|
||||
pub fn parse_vote_create_account(matches: &ArgMatches<'_>) -> Result<WalletCommand, WalletError> {
|
||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||
let node_pubkey = pubkey_of(matches, "node_pubkey").unwrap();
|
||||
let commission = value_of(&matches, "commission").unwrap_or(0);
|
||||
let authorized_voter = pubkey_of(matches, "authorized_voter").unwrap_or(vote_account_pubkey);
|
||||
let authorized_withdrawer =
|
||||
pubkey_of(matches, "authorized_withdrawer").unwrap_or(vote_account_pubkey);
|
||||
let lamports = crate::wallet::parse_amount_lamports(
|
||||
matches.value_of("amount").unwrap(),
|
||||
matches.value_of("unit"),
|
||||
@@ -30,21 +33,29 @@ pub fn parse_vote_create_account(matches: &ArgMatches<'_>) -> Result<WalletComma
|
||||
|
||||
Ok(WalletCommand::CreateVoteAccount(
|
||||
vote_account_pubkey,
|
||||
node_pubkey,
|
||||
commission,
|
||||
VoteInit {
|
||||
node_pubkey,
|
||||
authorized_voter,
|
||||
authorized_withdrawer,
|
||||
commission,
|
||||
},
|
||||
lamports,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn parse_vote_authorize_voter(matches: &ArgMatches<'_>) -> Result<WalletCommand, WalletError> {
|
||||
pub fn parse_vote_authorize(
|
||||
matches: &ArgMatches<'_>,
|
||||
vote_authorize: VoteAuthorize,
|
||||
) -> Result<WalletCommand, WalletError> {
|
||||
let vote_account_pubkey = pubkey_of(matches, "vote_account_pubkey").unwrap();
|
||||
let authorized_voter_keypair = keypair_of(matches, "authorized_voter_keypair_file").unwrap();
|
||||
let new_authorized_voter_pubkey = pubkey_of(matches, "new_authorized_voter_pubkey").unwrap();
|
||||
let authorized_keypair = keypair_of(matches, "authorized_keypair_file").unwrap();
|
||||
let new_authorized_pubkey = pubkey_of(matches, "new_authorized_pubkey").unwrap();
|
||||
|
||||
Ok(WalletCommand::AuthorizeVoter(
|
||||
Ok(WalletCommand::VoteAuthorize(
|
||||
vote_account_pubkey,
|
||||
authorized_voter_keypair,
|
||||
new_authorized_voter_pubkey,
|
||||
authorized_keypair,
|
||||
new_authorized_pubkey,
|
||||
vote_authorize,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -63,13 +74,12 @@ pub fn process_create_vote_account(
|
||||
rpc_client: &RpcClient,
|
||||
config: &WalletConfig,
|
||||
vote_account_pubkey: &Pubkey,
|
||||
node_pubkey: &Pubkey,
|
||||
commission: u8,
|
||||
vote_init: &VoteInit,
|
||||
lamports: u64,
|
||||
) -> ProcessResult {
|
||||
check_unique_pubkeys(
|
||||
(vote_account_pubkey, "vote_account_pubkey".to_string()),
|
||||
(node_pubkey, "node_pubkey".to_string()),
|
||||
(&vote_init.node_pubkey, "node_pubkey".to_string()),
|
||||
)?;
|
||||
check_unique_pubkeys(
|
||||
(&config.keypair.pubkey(), "wallet keypair".to_string()),
|
||||
@@ -78,8 +88,7 @@ pub fn process_create_vote_account(
|
||||
let ixs = vote_instruction::create_account(
|
||||
&config.keypair.pubkey(),
|
||||
vote_account_pubkey,
|
||||
node_pubkey,
|
||||
commission,
|
||||
vote_init,
|
||||
lamports,
|
||||
);
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
@@ -89,36 +98,35 @@ pub fn process_create_vote_account(
|
||||
log_instruction_custom_error::<SystemError>(result)
|
||||
}
|
||||
|
||||
pub fn process_authorize_voter(
|
||||
pub fn process_vote_authorize(
|
||||
rpc_client: &RpcClient,
|
||||
config: &WalletConfig,
|
||||
vote_account_pubkey: &Pubkey,
|
||||
authorized_voter_keypair: &Keypair,
|
||||
new_authorized_voter_pubkey: &Pubkey,
|
||||
authorized_keypair: &Keypair,
|
||||
new_authorized_pubkey: &Pubkey,
|
||||
vote_authorize: VoteAuthorize,
|
||||
) -> ProcessResult {
|
||||
check_unique_pubkeys(
|
||||
(vote_account_pubkey, "vote_account_pubkey".to_string()),
|
||||
(
|
||||
new_authorized_voter_pubkey,
|
||||
"new_authorized_voter_pubkey".to_string(),
|
||||
),
|
||||
(new_authorized_pubkey, "new_authorized_pubkey".to_string()),
|
||||
)?;
|
||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||
let ixs = vec![vote_instruction::authorize_voter(
|
||||
vote_account_pubkey, // vote account to update
|
||||
&authorized_voter_keypair.pubkey(), // current authorized voter (often the vote account itself)
|
||||
new_authorized_voter_pubkey, // new vote signer
|
||||
let ixs = vec![vote_instruction::authorize(
|
||||
vote_account_pubkey, // vote account to update
|
||||
&authorized_keypair.pubkey(), // current authorized voter (often the vote account itself)
|
||||
new_authorized_pubkey, // new vote signer
|
||||
vote_authorize, // vote or withdraw
|
||||
)];
|
||||
|
||||
let mut tx = Transaction::new_signed_with_payer(
|
||||
ixs,
|
||||
Some(&config.keypair.pubkey()),
|
||||
&[&config.keypair, &authorized_voter_keypair],
|
||||
&[&config.keypair, &authorized_keypair],
|
||||
recent_blockhash,
|
||||
);
|
||||
check_account_for_fee(rpc_client, config, &fee_calculator, &tx.message)?;
|
||||
let result = rpc_client
|
||||
.send_and_confirm_transaction(&mut tx, &[&config.keypair, &authorized_voter_keypair]);
|
||||
let result =
|
||||
rpc_client.send_and_confirm_transaction(&mut tx, &[&config.keypair, &authorized_keypair]);
|
||||
log_instruction_custom_error::<VoteError>(result)
|
||||
}
|
||||
|
||||
@@ -162,9 +170,10 @@ pub fn process_show_vote_account(
|
||||
crate::wallet::build_balance_message(vote_account.lamports, use_lamports_unit)
|
||||
);
|
||||
println!("node id: {}", vote_state.node_pubkey);
|
||||
println!("authorized voter: {}", vote_state.authorized_voter);
|
||||
println!(
|
||||
"authorized voter pubkey: {}",
|
||||
vote_state.authorized_voter_pubkey
|
||||
"authorized withdrawer: {}",
|
||||
vote_state.authorized_withdrawer
|
||||
);
|
||||
println!("credits: {}", vote_state.credits());
|
||||
println!(
|
||||
@@ -230,10 +239,7 @@ pub fn process_uptime(
|
||||
})?;
|
||||
|
||||
println!("Node id: {}", vote_state.node_pubkey);
|
||||
println!(
|
||||
"Authorized voter pubkey: {}",
|
||||
vote_state.authorized_voter_pubkey
|
||||
);
|
||||
println!("Authorized voter: {}", vote_state.authorized_voter);
|
||||
if !vote_state.votes.is_empty() {
|
||||
println!("Uptime:");
|
||||
|
||||
@@ -300,14 +306,14 @@ mod tests {
|
||||
|
||||
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"authorize-voter",
|
||||
"vote-authorize-voter",
|
||||
&pubkey_string,
|
||||
&keypair_file,
|
||||
&pubkey_string,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&pubkey, &test_authorize_voter).unwrap(),
|
||||
WalletCommand::AuthorizeVoter(pubkey, keypair, pubkey)
|
||||
WalletCommand::VoteAuthorize(pubkey, keypair, pubkey, VoteAuthorize::Voter)
|
||||
);
|
||||
fs::remove_file(&keypair_file).unwrap();
|
||||
|
||||
@@ -326,7 +332,16 @@ mod tests {
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&pubkey, &test_create_vote_account).unwrap(),
|
||||
WalletCommand::CreateVoteAccount(pubkey, node_pubkey, 10, 50)
|
||||
WalletCommand::CreateVoteAccount(
|
||||
pubkey,
|
||||
VoteInit {
|
||||
node_pubkey,
|
||||
authorized_voter: pubkey,
|
||||
authorized_withdrawer: pubkey,
|
||||
commission: 10
|
||||
},
|
||||
50
|
||||
)
|
||||
);
|
||||
let test_create_vote_account2 = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
@@ -337,7 +352,63 @@ mod tests {
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&pubkey, &test_create_vote_account2).unwrap(),
|
||||
WalletCommand::CreateVoteAccount(pubkey, node_pubkey, 0, 858993459200)
|
||||
WalletCommand::CreateVoteAccount(
|
||||
pubkey,
|
||||
VoteInit {
|
||||
node_pubkey,
|
||||
authorized_voter: pubkey,
|
||||
authorized_withdrawer: pubkey,
|
||||
commission: 0
|
||||
},
|
||||
858993459200
|
||||
)
|
||||
);
|
||||
// test init with an authed voter
|
||||
let authed = Pubkey::new_rand();
|
||||
let test_create_vote_account3 = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"create-vote-account",
|
||||
&pubkey_string,
|
||||
&node_pubkey_string,
|
||||
"50",
|
||||
"--authorized-voter",
|
||||
&authed.to_string(),
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&pubkey, &test_create_vote_account3).unwrap(),
|
||||
WalletCommand::CreateVoteAccount(
|
||||
pubkey,
|
||||
VoteInit {
|
||||
node_pubkey,
|
||||
authorized_voter: authed,
|
||||
authorized_withdrawer: pubkey,
|
||||
commission: 0
|
||||
},
|
||||
858993459200
|
||||
)
|
||||
);
|
||||
// test init with an authed withdrawer
|
||||
let test_create_vote_account4 = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"create-vote-account",
|
||||
&pubkey_string,
|
||||
&node_pubkey_string,
|
||||
"50",
|
||||
"--authorized-withdrawer",
|
||||
&authed.to_string(),
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&pubkey, &test_create_vote_account4).unwrap(),
|
||||
WalletCommand::CreateVoteAccount(
|
||||
pubkey,
|
||||
VoteInit {
|
||||
node_pubkey,
|
||||
authorized_voter: pubkey,
|
||||
authorized_withdrawer: authed,
|
||||
commission: 0
|
||||
},
|
||||
858993459200
|
||||
)
|
||||
);
|
||||
|
||||
// Test Uptime Subcommand
|
||||
|
@@ -7,11 +7,9 @@ use clap::{value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||
use console::{style, Emoji};
|
||||
use log::*;
|
||||
use num_traits::FromPrimitive;
|
||||
use serde_json;
|
||||
use serde_json::{json, Value};
|
||||
use serde_json::{self, json, Value};
|
||||
use solana_budget_api::budget_instruction::{self, BudgetError};
|
||||
use solana_client::client_error::ClientError;
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_client::{client_error::ClientError, rpc_client::RpcClient};
|
||||
#[cfg(not(test))]
|
||||
use solana_drone::drone::request_airdrop_transaction;
|
||||
#[cfg(test)]
|
||||
@@ -31,16 +29,21 @@ use solana_sdk::{
|
||||
system_transaction,
|
||||
transaction::{Transaction, TransactionError},
|
||||
};
|
||||
use solana_stake_api::stake_instruction::{self, StakeError};
|
||||
use solana_stake_api::{
|
||||
stake_instruction::{self, StakeError},
|
||||
stake_state::{Authorized, Lockup},
|
||||
};
|
||||
use solana_storage_api::storage_instruction;
|
||||
use solana_vote_api::vote_state::VoteState;
|
||||
use std::collections::VecDeque;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::thread::sleep;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{error, fmt};
|
||||
use solana_vote_api::vote_state::{VoteAuthorize, VoteInit, VoteState};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
fs::File,
|
||||
io::{Read, Write},
|
||||
net::{IpAddr, SocketAddr},
|
||||
thread::sleep,
|
||||
time::{Duration, Instant},
|
||||
{error, fmt},
|
||||
};
|
||||
|
||||
const USERDATA_CHUNK_SIZE: usize = 229; // Keep program chunks under PACKET_DATA_SIZE
|
||||
|
||||
@@ -64,8 +67,8 @@ pub enum WalletCommand {
|
||||
},
|
||||
Cancel(Pubkey),
|
||||
Confirm(Signature),
|
||||
AuthorizeVoter(Pubkey, Keypair, Pubkey),
|
||||
CreateVoteAccount(Pubkey, Pubkey, u8, u64),
|
||||
VoteAuthorize(Pubkey, Keypair, Pubkey, VoteAuthorize),
|
||||
CreateVoteAccount(Pubkey, VoteInit, u64),
|
||||
ShowAccount {
|
||||
pubkey: Pubkey,
|
||||
output_file: Option<String>,
|
||||
@@ -80,7 +83,7 @@ pub enum WalletCommand {
|
||||
aggregate: bool,
|
||||
span: Option<u64>,
|
||||
},
|
||||
DelegateStake(Keypair, Pubkey, u64, bool),
|
||||
DelegateStake(Keypair, Pubkey, u64, Authorized, bool),
|
||||
WithdrawStake(Keypair, Pubkey, u64),
|
||||
DeactivateStake(Keypair, Pubkey),
|
||||
RedeemVoteCredits(Pubkey, Pubkey),
|
||||
@@ -242,7 +245,12 @@ pub fn parse_command(
|
||||
})
|
||||
}
|
||||
("create-vote-account", Some(matches)) => parse_vote_create_account(matches),
|
||||
("authorize-voter", Some(matches)) => parse_vote_authorize_voter(matches),
|
||||
("vote-authorize-voter", Some(matches)) => {
|
||||
parse_vote_authorize(matches, VoteAuthorize::Voter)
|
||||
}
|
||||
("vote-authorize-withdrawer", Some(matches)) => {
|
||||
parse_vote_authorize(matches, VoteAuthorize::Withdrawer)
|
||||
}
|
||||
("show-vote-account", Some(matches)) => parse_vote_get_account_command(matches),
|
||||
("uptime", Some(matches)) => parse_vote_uptime_command(matches),
|
||||
("delegate-stake", Some(matches)) => {
|
||||
@@ -252,11 +260,13 @@ pub fn parse_command(
|
||||
matches.value_of("amount").unwrap(),
|
||||
matches.value_of("unit"),
|
||||
)?;
|
||||
let authorized = Authorized::auto(&stake_account_keypair.pubkey());
|
||||
let force = matches.is_present("force");
|
||||
Ok(WalletCommand::DelegateStake(
|
||||
stake_account_keypair,
|
||||
vote_account_pubkey,
|
||||
lamports,
|
||||
authorized,
|
||||
force,
|
||||
))
|
||||
}
|
||||
@@ -602,6 +612,7 @@ fn process_delegate_stake(
|
||||
stake_account_keypair: &Keypair,
|
||||
vote_account_pubkey: &Pubkey,
|
||||
lamports: u64,
|
||||
authorized: &Authorized,
|
||||
force: bool,
|
||||
) -> ProcessResult {
|
||||
check_unique_pubkeys(
|
||||
@@ -618,6 +629,7 @@ fn process_delegate_stake(
|
||||
&stake_account_keypair.pubkey(),
|
||||
vote_account_pubkey,
|
||||
lamports,
|
||||
authorized,
|
||||
);
|
||||
|
||||
// Sanity check the vote account to ensure it is attached to a validator that has recently
|
||||
@@ -735,8 +747,16 @@ fn process_show_stake_account(
|
||||
format!("{:?} is not a stake account", stake_account_pubkey).to_string(),
|
||||
))?;
|
||||
}
|
||||
fn show_authorized(authorized: &Authorized) {
|
||||
println!("authorized staker: {}", authorized.staker);
|
||||
println!("authorized withdrawer: {}", authorized.staker);
|
||||
}
|
||||
fn show_lockup(lockup: &Lockup) {
|
||||
println!("lockup slot: {}", lockup.slot);
|
||||
println!("lockup custodian: {}", lockup.custodian);
|
||||
}
|
||||
match stake_account.state() {
|
||||
Ok(StakeState::Stake(stake)) => {
|
||||
Ok(StakeState::Stake(authorized, lockup, stake)) => {
|
||||
println!(
|
||||
"total stake: {}",
|
||||
build_balance_message(stake_account.lamports, use_lamports_unit)
|
||||
@@ -759,11 +779,17 @@ fn process_show_stake_account(
|
||||
stake.deactivation_epoch
|
||||
);
|
||||
}
|
||||
show_authorized(&authorized);
|
||||
show_lockup(&lockup);
|
||||
Ok("".to_string())
|
||||
}
|
||||
Ok(StakeState::RewardsPool) => Ok("Stake account is a rewards pool".to_string()),
|
||||
Ok(StakeState::Uninitialized) | Ok(StakeState::Lockup(_)) => {
|
||||
Ok("Stake account is uninitialized".to_string())
|
||||
Ok(StakeState::Uninitialized) => Ok("Stake account is uninitialized".to_string()),
|
||||
Ok(StakeState::Initialized(authorized, lockup)) => {
|
||||
println!("Stake account is undelegated");
|
||||
show_authorized(&authorized);
|
||||
show_lockup(&lockup);
|
||||
Ok("".to_string())
|
||||
}
|
||||
Err(err) => Err(WalletError::RpcRequestError(format!(
|
||||
"Account data could not be deserialized to stake state: {:?}",
|
||||
@@ -1286,30 +1312,28 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult {
|
||||
WalletCommand::Confirm(signature) => process_confirm(&rpc_client, signature),
|
||||
|
||||
// Create vote account
|
||||
WalletCommand::CreateVoteAccount(
|
||||
vote_account_pubkey,
|
||||
node_pubkey,
|
||||
commission,
|
||||
lamports,
|
||||
) => process_create_vote_account(
|
||||
&rpc_client,
|
||||
config,
|
||||
&vote_account_pubkey,
|
||||
&node_pubkey,
|
||||
*commission,
|
||||
*lamports,
|
||||
),
|
||||
WalletCommand::CreateVoteAccount(vote_account_pubkey, vote_init, lamports) => {
|
||||
process_create_vote_account(
|
||||
&rpc_client,
|
||||
config,
|
||||
&vote_account_pubkey,
|
||||
&vote_init,
|
||||
*lamports,
|
||||
)
|
||||
}
|
||||
|
||||
WalletCommand::AuthorizeVoter(
|
||||
WalletCommand::VoteAuthorize(
|
||||
vote_account_pubkey,
|
||||
authorized_voter_keypair,
|
||||
new_authorized_voter_pubkey,
|
||||
) => process_authorize_voter(
|
||||
authorized_keypair,
|
||||
new_authorized_pubkey,
|
||||
vote_authorize,
|
||||
) => process_vote_authorize(
|
||||
&rpc_client,
|
||||
config,
|
||||
&vote_account_pubkey,
|
||||
&authorized_voter_keypair,
|
||||
&new_authorized_voter_pubkey,
|
||||
&authorized_keypair,
|
||||
&new_authorized_pubkey,
|
||||
*vote_authorize,
|
||||
),
|
||||
|
||||
WalletCommand::ShowAccount {
|
||||
@@ -1344,6 +1368,7 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult {
|
||||
stake_account_keypair,
|
||||
vote_account_pubkey,
|
||||
lamports,
|
||||
authorized,
|
||||
force,
|
||||
) => process_delegate_stake(
|
||||
&rpc_client,
|
||||
@@ -1351,6 +1376,7 @@ pub fn process_command(config: &WalletConfig) -> ProcessResult {
|
||||
&stake_account_keypair,
|
||||
&vote_account_pubkey,
|
||||
*lamports,
|
||||
&authorized,
|
||||
*force,
|
||||
),
|
||||
|
||||
@@ -1675,7 +1701,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("authorize-voter")
|
||||
SubCommand::with_name("vote-authorize-voter")
|
||||
.about("Authorize a new vote signing keypair for the given vote account")
|
||||
.arg(
|
||||
Arg::with_name("vote_account_pubkey")
|
||||
@@ -1687,7 +1713,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
||||
.help("Vote account in which to set the authorized voter"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("authorized_voter_keypair_file")
|
||||
Arg::with_name("authorized_keypair_file")
|
||||
.index(2)
|
||||
.value_name("CURRENT VOTER KEYPAIR FILE")
|
||||
.takes_value(true)
|
||||
@@ -1696,7 +1722,7 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
||||
.help("Keypair file for the currently authorized vote signer"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("new_authorized_voter_pubkey")
|
||||
Arg::with_name("new_authorized_pubkey")
|
||||
.index(3)
|
||||
.value_name("NEW VOTER PUBKEY")
|
||||
.takes_value(true)
|
||||
@@ -1705,6 +1731,37 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
||||
.help("New vote signer to authorize"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("vote-authorize-withdrawer")
|
||||
.about("Authorize a new withdraw signing keypair for the given vote account")
|
||||
.arg(
|
||||
Arg::with_name("vote_account_pubkey")
|
||||
.index(1)
|
||||
.value_name("VOTE ACCOUNT PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_pubkey_or_keypair)
|
||||
.help("Vote account in which to set the authorized withdrawer"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("authorized_keypair_file")
|
||||
.index(2)
|
||||
.value_name("CURRENT WITHDRAWER KEYPAIR FILE")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_keypair)
|
||||
.help("Keypair file for the currently authorized withdrawer"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("new_authorized_pubkey")
|
||||
.index(3)
|
||||
.value_name("NEW WITHDRAWER PUBKEY")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.validator(is_pubkey_or_keypair)
|
||||
.help("New withdrawer to authorize"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("create-vote-account")
|
||||
.about("Create a vote account")
|
||||
@@ -1747,7 +1804,25 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, '
|
||||
.value_name("NUM")
|
||||
.takes_value(true)
|
||||
.help("The commission taken on reward redemption (0-255), default: 0"),
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("authorized_voter")
|
||||
.long("authorized-voter")
|
||||
.value_name("PUBKEY")
|
||||
.takes_value(true)
|
||||
.validator(is_pubkey_or_keypair)
|
||||
.help("Public key of the authorized voter (defaults to vote account pubkey)"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("authorized_withdrawer")
|
||||
.long("authorized-withdrawer")
|
||||
.value_name("PUBKEY")
|
||||
.takes_value(true)
|
||||
.validator(is_pubkey_or_keypair)
|
||||
.help("Public key of the authorized withdrawer (defaults to vote account pubkey)"),
|
||||
)
|
||||
|
||||
,
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("show-account")
|
||||
@@ -2425,9 +2500,16 @@ mod tests {
|
||||
"42",
|
||||
"lamports",
|
||||
]);
|
||||
let stake_pubkey = keypair.pubkey();
|
||||
assert_eq!(
|
||||
parse_command(&pubkey, &test_delegate_stake).unwrap(),
|
||||
WalletCommand::DelegateStake(keypair, pubkey, 42, false)
|
||||
WalletCommand::DelegateStake(
|
||||
keypair,
|
||||
pubkey,
|
||||
42,
|
||||
Authorized::auto(&stake_pubkey),
|
||||
false,
|
||||
)
|
||||
);
|
||||
|
||||
let keypair = read_keypair(&keypair_file).unwrap();
|
||||
@@ -2440,9 +2522,16 @@ mod tests {
|
||||
"42",
|
||||
"lamports",
|
||||
]);
|
||||
let stake_pubkey = keypair.pubkey();
|
||||
assert_eq!(
|
||||
parse_command(&pubkey, &test_delegate_stake).unwrap(),
|
||||
WalletCommand::DelegateStake(keypair, pubkey, 42, true)
|
||||
WalletCommand::DelegateStake(
|
||||
keypair,
|
||||
pubkey,
|
||||
42,
|
||||
Authorized::auto(&stake_pubkey),
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
// Test WithdrawStake Subcommand
|
||||
@@ -2669,14 +2758,27 @@ mod tests {
|
||||
|
||||
let bob_pubkey = Pubkey::new_rand();
|
||||
let node_pubkey = Pubkey::new_rand();
|
||||
config.command = WalletCommand::CreateVoteAccount(bob_pubkey, node_pubkey, 0, 10);
|
||||
config.command = WalletCommand::CreateVoteAccount(
|
||||
bob_pubkey,
|
||||
VoteInit {
|
||||
node_pubkey,
|
||||
authorized_voter: bob_pubkey,
|
||||
authorized_withdrawer: bob_pubkey,
|
||||
commission: 0,
|
||||
},
|
||||
10,
|
||||
);
|
||||
let signature = process_command(&config);
|
||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||
|
||||
let bob_keypair = Keypair::new();
|
||||
let new_authorized_voter_pubkey = Pubkey::new_rand();
|
||||
config.command =
|
||||
WalletCommand::AuthorizeVoter(bob_pubkey, bob_keypair, new_authorized_voter_pubkey);
|
||||
let new_authorized_pubkey = Pubkey::new_rand();
|
||||
config.command = WalletCommand::VoteAuthorize(
|
||||
bob_pubkey,
|
||||
bob_keypair,
|
||||
new_authorized_pubkey,
|
||||
VoteAuthorize::Voter,
|
||||
);
|
||||
let signature = process_command(&config);
|
||||
assert_eq!(signature.unwrap(), SIGNATURE.to_string());
|
||||
|
||||
@@ -2826,10 +2928,24 @@ mod tests {
|
||||
};
|
||||
assert!(process_command(&config).is_err());
|
||||
|
||||
config.command = WalletCommand::CreateVoteAccount(bob_pubkey, node_pubkey, 0, 10);
|
||||
config.command = WalletCommand::CreateVoteAccount(
|
||||
bob_pubkey,
|
||||
VoteInit {
|
||||
node_pubkey,
|
||||
authorized_voter: bob_pubkey,
|
||||
authorized_withdrawer: bob_pubkey,
|
||||
commission: 0,
|
||||
},
|
||||
10,
|
||||
);
|
||||
assert!(process_command(&config).is_err());
|
||||
|
||||
config.command = WalletCommand::AuthorizeVoter(bob_pubkey, Keypair::new(), bob_pubkey);
|
||||
config.command = WalletCommand::VoteAuthorize(
|
||||
bob_pubkey,
|
||||
Keypair::new(),
|
||||
bob_pubkey,
|
||||
VoteAuthorize::Voter,
|
||||
);
|
||||
assert!(process_command(&config).is_err());
|
||||
|
||||
config.command = WalletCommand::GetSlot;
|
||||
|
Reference in New Issue
Block a user