* Refactor VoteAuthorize to use SignerIndex and support vote-authorize-*-checked
* Add checked bool const and use in command parsing
* Add create-stake-account-checked handling
* Add stake-set-lockup-checked handling
* Remove unnecessary mut
* Add stake-authorized-checked handling
(cherry picked from commit aeb30fa873
)
Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
This commit is contained in:
@@ -44,11 +44,7 @@ use solana_sdk::{
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
signature::{Signature, Signer, SignerError},
|
||||
stake::{
|
||||
self,
|
||||
instruction::LockupArgs,
|
||||
state::{Lockup, StakeAuthorize},
|
||||
},
|
||||
stake::{self, instruction::LockupArgs, state::Lockup},
|
||||
system_instruction::{self, SystemError},
|
||||
system_program,
|
||||
transaction::{Transaction, TransactionError},
|
||||
@@ -63,6 +59,7 @@ use thiserror::Error;
|
||||
|
||||
pub const DEFAULT_RPC_TIMEOUT_SECONDS: &str = "30";
|
||||
pub const DEFAULT_CONFIRM_TX_TIMEOUT_SECONDS: &str = "5";
|
||||
const CHECKED: bool = true;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
@@ -198,6 +195,7 @@ pub enum CliCommand {
|
||||
seed: Option<String>,
|
||||
staker: Option<Pubkey>,
|
||||
withdrawer: Option<Pubkey>,
|
||||
withdrawer_signer: Option<SignerIndex>,
|
||||
lockup: Lockup,
|
||||
amount: SpendAmount,
|
||||
sign_only: bool,
|
||||
@@ -271,7 +269,7 @@ pub enum CliCommand {
|
||||
},
|
||||
StakeAuthorize {
|
||||
stake_account_pubkey: Pubkey,
|
||||
new_authorizations: Vec<(StakeAuthorize, Pubkey, SignerIndex)>,
|
||||
new_authorizations: Vec<StakeAuthorizationIndexed>,
|
||||
sign_only: bool,
|
||||
dump_transaction_message: bool,
|
||||
blockhash_query: BlockhashQuery,
|
||||
@@ -286,6 +284,7 @@ pub enum CliCommand {
|
||||
stake_account_pubkey: Pubkey,
|
||||
lockup: LockupArgs,
|
||||
custodian: SignerIndex,
|
||||
new_custodian_signer: Option<SignerIndex>,
|
||||
sign_only: bool,
|
||||
dump_transaction_message: bool,
|
||||
blockhash_query: BlockhashQuery,
|
||||
@@ -343,6 +342,8 @@ pub enum CliCommand {
|
||||
new_authorized_pubkey: Pubkey,
|
||||
vote_authorize: VoteAuthorize,
|
||||
memo: Option<String>,
|
||||
authorized: SignerIndex,
|
||||
new_authorized: Option<SignerIndex>,
|
||||
},
|
||||
VoteUpdateValidator {
|
||||
vote_account_pubkey: Pubkey,
|
||||
@@ -719,7 +720,10 @@ pub fn parse_command(
|
||||
}
|
||||
// Stake Commands
|
||||
("create-stake-account", Some(matches)) => {
|
||||
parse_create_stake_account(matches, default_signer, wallet_manager)
|
||||
parse_create_stake_account(matches, default_signer, wallet_manager, !CHECKED)
|
||||
}
|
||||
("create-stake-account-checked", Some(matches)) => {
|
||||
parse_create_stake_account(matches, default_signer, wallet_manager, CHECKED)
|
||||
}
|
||||
("delegate-stake", Some(matches)) => {
|
||||
parse_stake_delegate_stake(matches, default_signer, wallet_manager)
|
||||
@@ -737,10 +741,16 @@ pub fn parse_command(
|
||||
parse_merge_stake(matches, default_signer, wallet_manager)
|
||||
}
|
||||
("stake-authorize", Some(matches)) => {
|
||||
parse_stake_authorize(matches, default_signer, wallet_manager)
|
||||
parse_stake_authorize(matches, default_signer, wallet_manager, !CHECKED)
|
||||
}
|
||||
("stake-authorize-checked", Some(matches)) => {
|
||||
parse_stake_authorize(matches, default_signer, wallet_manager, CHECKED)
|
||||
}
|
||||
("stake-set-lockup", Some(matches)) => {
|
||||
parse_stake_set_lockup(matches, default_signer, wallet_manager)
|
||||
parse_stake_set_lockup(matches, default_signer, wallet_manager, !CHECKED)
|
||||
}
|
||||
("stake-set-lockup-checked", Some(matches)) => {
|
||||
parse_stake_set_lockup(matches, default_signer, wallet_manager, CHECKED)
|
||||
}
|
||||
("stake-account", Some(matches)) => parse_show_stake_account(matches, wallet_manager),
|
||||
("stake-history", Some(matches)) => parse_show_stake_history(matches),
|
||||
@@ -767,12 +777,28 @@ pub fn parse_command(
|
||||
default_signer,
|
||||
wallet_manager,
|
||||
VoteAuthorize::Voter,
|
||||
!CHECKED,
|
||||
),
|
||||
("vote-authorize-withdrawer", Some(matches)) => parse_vote_authorize(
|
||||
matches,
|
||||
default_signer,
|
||||
wallet_manager,
|
||||
VoteAuthorize::Withdrawer,
|
||||
!CHECKED,
|
||||
),
|
||||
("vote-authorize-voter-checked", Some(matches)) => parse_vote_authorize(
|
||||
matches,
|
||||
default_signer,
|
||||
wallet_manager,
|
||||
VoteAuthorize::Voter,
|
||||
CHECKED,
|
||||
),
|
||||
("vote-authorize-withdrawer-checked", Some(matches)) => parse_vote_authorize(
|
||||
matches,
|
||||
default_signer,
|
||||
wallet_manager,
|
||||
VoteAuthorize::Withdrawer,
|
||||
CHECKED,
|
||||
),
|
||||
("vote-account", Some(matches)) => parse_vote_get_account_command(matches, wallet_manager),
|
||||
("withdraw-from-vote-account", Some(matches)) => {
|
||||
@@ -1533,6 +1559,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
seed,
|
||||
staker,
|
||||
withdrawer,
|
||||
withdrawer_signer,
|
||||
lockup,
|
||||
amount,
|
||||
sign_only,
|
||||
@@ -1550,6 +1577,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
seed,
|
||||
staker,
|
||||
withdrawer,
|
||||
*withdrawer_signer,
|
||||
lockup,
|
||||
*amount,
|
||||
*sign_only,
|
||||
@@ -1711,8 +1739,9 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
),
|
||||
CliCommand::StakeSetLockup {
|
||||
stake_account_pubkey,
|
||||
mut lockup,
|
||||
lockup,
|
||||
custodian,
|
||||
new_custodian_signer,
|
||||
sign_only,
|
||||
dump_transaction_message,
|
||||
blockhash_query,
|
||||
@@ -1724,7 +1753,8 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
&rpc_client,
|
||||
config,
|
||||
stake_account_pubkey,
|
||||
&mut lockup,
|
||||
lockup,
|
||||
*new_custodian_signer,
|
||||
*custodian,
|
||||
*sign_only,
|
||||
*dump_transaction_message,
|
||||
@@ -1838,12 +1868,16 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
new_authorized_pubkey,
|
||||
vote_authorize,
|
||||
memo,
|
||||
authorized,
|
||||
new_authorized,
|
||||
} => process_vote_authorize(
|
||||
&rpc_client,
|
||||
config,
|
||||
vote_account_pubkey,
|
||||
new_authorized_pubkey,
|
||||
*vote_authorize,
|
||||
*authorized,
|
||||
*new_authorized,
|
||||
memo.as_ref(),
|
||||
),
|
||||
CliCommand::VoteUpdateValidator {
|
||||
@@ -2645,6 +2679,8 @@ mod tests {
|
||||
new_authorized_pubkey,
|
||||
vote_authorize: VoteAuthorize::Voter,
|
||||
memo: None,
|
||||
authorized: 0,
|
||||
new_authorized: None,
|
||||
};
|
||||
let result = process_command(&config);
|
||||
assert!(result.is_ok());
|
||||
@@ -2668,6 +2704,7 @@ mod tests {
|
||||
seed: None,
|
||||
staker: None,
|
||||
withdrawer: None,
|
||||
withdrawer_signer: None,
|
||||
lockup: Lockup {
|
||||
epoch: 0,
|
||||
unix_timestamp: 0,
|
||||
@@ -2840,6 +2877,8 @@ mod tests {
|
||||
new_authorized_pubkey: bob_pubkey,
|
||||
vote_authorize: VoteAuthorize::Voter,
|
||||
memo: None,
|
||||
authorized: 0,
|
||||
new_authorized: None,
|
||||
};
|
||||
assert!(process_command(&config).is_err());
|
||||
|
||||
|
920
cli/src/stake.rs
920
cli/src/stake.rs
File diff suppressed because it is too large
Load Diff
188
cli/src/vote.rs
188
cli/src/vote.rs
@@ -138,6 +138,64 @@ impl VoteSubCommands for App<'_, '_> {
|
||||
)
|
||||
.arg(memo_arg())
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("vote-authorize-voter-checked")
|
||||
.about("Authorize a new vote signing keypair for the given vote account, \
|
||||
checking the new authority as a signer")
|
||||
.arg(
|
||||
pubkey!(Arg::with_name("vote_account_pubkey")
|
||||
.index(1)
|
||||
.value_name("VOTE_ACCOUNT_ADDRESS")
|
||||
.required(true),
|
||||
"Vote account in which to set the authorized voter. "),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("authorized")
|
||||
.index(2)
|
||||
.value_name("AUTHORIZED_KEYPAIR")
|
||||
.required(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("Current authorized vote signer."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("new_authorized")
|
||||
.index(3)
|
||||
.value_name("NEW_AUTHORIZED_KEYPAIR")
|
||||
.required(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("New authorized vote signer."),
|
||||
)
|
||||
.arg(memo_arg())
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("vote-authorize-withdrawer-checked")
|
||||
.about("Authorize a new withdraw signing keypair for the given vote account, \
|
||||
checking the new authority as a signer")
|
||||
.arg(
|
||||
pubkey!(Arg::with_name("vote_account_pubkey")
|
||||
.index(1)
|
||||
.value_name("VOTE_ACCOUNT_ADDRESS")
|
||||
.required(true),
|
||||
"Vote account in which to set the authorized withdrawer. "),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("authorized")
|
||||
.index(2)
|
||||
.value_name("AUTHORIZED_KEYPAIR")
|
||||
.required(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("Current authorized withdrawer."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("new_authorized")
|
||||
.index(3)
|
||||
.value_name("NEW_AUTHORIZED_KEYPAIR")
|
||||
.required(true)
|
||||
.validator(is_valid_signer)
|
||||
.help("New authorized withdrawer."),
|
||||
)
|
||||
.arg(memo_arg())
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("vote-update-validator")
|
||||
.about("Update the vote account's validator identity")
|
||||
@@ -311,19 +369,25 @@ pub fn parse_vote_authorize(
|
||||
default_signer: &DefaultSigner,
|
||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||
vote_authorize: VoteAuthorize,
|
||||
checked: bool,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let vote_account_pubkey =
|
||||
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
|
||||
let new_authorized_pubkey =
|
||||
pubkey_of_signer(matches, "new_authorized_pubkey", wallet_manager)?.unwrap();
|
||||
let (authorized, _) = signer_of(matches, "authorized", wallet_manager)?;
|
||||
let (authorized, authorized_pubkey) = signer_of(matches, "authorized", wallet_manager)?;
|
||||
|
||||
let payer_provided = None;
|
||||
let signer_info = default_signer.generate_unique_signers(
|
||||
vec![payer_provided, authorized],
|
||||
matches,
|
||||
wallet_manager,
|
||||
)?;
|
||||
let mut signers = vec![payer_provided, authorized];
|
||||
|
||||
let new_authorized_pubkey = if checked {
|
||||
let (new_authorized_signer, new_authorized_pubkey) =
|
||||
signer_of(matches, "new_authorized", wallet_manager)?;
|
||||
signers.push(new_authorized_signer);
|
||||
new_authorized_pubkey.unwrap()
|
||||
} else {
|
||||
pubkey_of_signer(matches, "new_authorized_pubkey", wallet_manager)?.unwrap()
|
||||
};
|
||||
|
||||
let signer_info = default_signer.generate_unique_signers(signers, matches, wallet_manager)?;
|
||||
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
@@ -332,6 +396,12 @@ pub fn parse_vote_authorize(
|
||||
new_authorized_pubkey,
|
||||
vote_authorize,
|
||||
memo,
|
||||
authorized: signer_info.index_of(authorized_pubkey).unwrap(),
|
||||
new_authorized: if checked {
|
||||
signer_info.index_of(Some(new_authorized_pubkey))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
},
|
||||
signers: signer_info.signers,
|
||||
})
|
||||
@@ -558,28 +628,34 @@ pub fn process_vote_authorize(
|
||||
vote_account_pubkey: &Pubkey,
|
||||
new_authorized_pubkey: &Pubkey,
|
||||
vote_authorize: VoteAuthorize,
|
||||
authorized: SignerIndex,
|
||||
new_authorized: Option<SignerIndex>,
|
||||
memo: Option<&String>,
|
||||
) -> ProcessResult {
|
||||
// If the `authorized_account` is also the fee payer, `config.signers` will only have one
|
||||
// keypair in it
|
||||
let authorized = if config.signers.len() == 2 {
|
||||
config.signers[1]
|
||||
} else {
|
||||
config.signers[0]
|
||||
};
|
||||
let authorized = config.signers[authorized];
|
||||
let new_authorized_signer = new_authorized.map(|index| config.signers[index]);
|
||||
|
||||
check_unique_pubkeys(
|
||||
(&authorized.pubkey(), "authorized_account".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(
|
||||
vote_account_pubkey, // vote account to update
|
||||
&authorized.pubkey(), // current authorized
|
||||
new_authorized_pubkey, // new vote signer/withdrawer
|
||||
vote_authorize, // vote or withdraw
|
||||
)]
|
||||
.with_memo(memo);
|
||||
let vote_ix = if new_authorized_signer.is_some() {
|
||||
vote_instruction::authorize_checked(
|
||||
vote_account_pubkey, // vote account to update
|
||||
&authorized.pubkey(), // current authorized
|
||||
new_authorized_pubkey, // new vote signer/withdrawer
|
||||
vote_authorize, // vote or withdraw
|
||||
)
|
||||
} else {
|
||||
vote_instruction::authorize(
|
||||
vote_account_pubkey, // vote account to update
|
||||
&authorized.pubkey(), // current authorized
|
||||
new_authorized_pubkey, // new vote signer/withdrawer
|
||||
vote_authorize, // vote or withdraw
|
||||
)
|
||||
};
|
||||
let ixs = vec![vote_ix].with_memo(memo);
|
||||
|
||||
let message = Message::new(&ixs, Some(&config.signers[0].pubkey()));
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
@@ -843,6 +919,8 @@ mod tests {
|
||||
new_authorized_pubkey: pubkey2,
|
||||
vote_authorize: VoteAuthorize::Voter,
|
||||
memo: None,
|
||||
authorized: 0,
|
||||
new_authorized: None,
|
||||
},
|
||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||
}
|
||||
@@ -867,6 +945,8 @@ mod tests {
|
||||
new_authorized_pubkey: pubkey2,
|
||||
vote_authorize: VoteAuthorize::Voter,
|
||||
memo: None,
|
||||
authorized: 1,
|
||||
new_authorized: None,
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
@@ -875,6 +955,70 @@ mod tests {
|
||||
}
|
||||
);
|
||||
|
||||
let (voter_keypair_file, mut tmp_file) = make_tmp_file();
|
||||
let voter_keypair = Keypair::new();
|
||||
write_keypair(&voter_keypair, tmp_file.as_file_mut()).unwrap();
|
||||
|
||||
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"vote-authorize-voter-checked",
|
||||
&pubkey_string,
|
||||
&default_keypair_file,
|
||||
&voter_keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::VoteAuthorize {
|
||||
vote_account_pubkey: pubkey,
|
||||
new_authorized_pubkey: voter_keypair.pubkey(),
|
||||
vote_authorize: VoteAuthorize::Voter,
|
||||
memo: None,
|
||||
authorized: 0,
|
||||
new_authorized: Some(1),
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
read_keypair_file(&voter_keypair_file).unwrap().into()
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"vote-authorize-voter-checked",
|
||||
&pubkey_string,
|
||||
&authorized_keypair_file,
|
||||
&voter_keypair_file,
|
||||
]);
|
||||
assert_eq!(
|
||||
parse_command(&test_authorize_voter, &default_signer, &mut None).unwrap(),
|
||||
CliCommandInfo {
|
||||
command: CliCommand::VoteAuthorize {
|
||||
vote_account_pubkey: pubkey,
|
||||
new_authorized_pubkey: voter_keypair.pubkey(),
|
||||
vote_authorize: VoteAuthorize::Voter,
|
||||
memo: None,
|
||||
authorized: 1,
|
||||
new_authorized: Some(2),
|
||||
},
|
||||
signers: vec![
|
||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||
read_keypair_file(&authorized_keypair_file).unwrap().into(),
|
||||
read_keypair_file(&voter_keypair_file).unwrap().into(),
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
let test_authorize_voter = test_commands.clone().get_matches_from(vec![
|
||||
"test",
|
||||
"vote-authorize-voter-checked",
|
||||
&pubkey_string,
|
||||
&authorized_keypair_file,
|
||||
&pubkey2_string,
|
||||
]);
|
||||
assert!(parse_command(&test_authorize_voter, &default_signer, &mut None).is_err());
|
||||
|
||||
let (keypair_file, mut tmp_file) = make_tmp_file();
|
||||
let keypair = Keypair::new();
|
||||
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
|
||||
|
Reference in New Issue
Block a user