* 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,
|
message::Message,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Signature, Signer, SignerError},
|
signature::{Signature, Signer, SignerError},
|
||||||
stake::{
|
stake::{self, instruction::LockupArgs, state::Lockup},
|
||||||
self,
|
|
||||||
instruction::LockupArgs,
|
|
||||||
state::{Lockup, StakeAuthorize},
|
|
||||||
},
|
|
||||||
system_instruction::{self, SystemError},
|
system_instruction::{self, SystemError},
|
||||||
system_program,
|
system_program,
|
||||||
transaction::{Transaction, TransactionError},
|
transaction::{Transaction, TransactionError},
|
||||||
@ -63,6 +59,7 @@ use thiserror::Error;
|
|||||||
|
|
||||||
pub const DEFAULT_RPC_TIMEOUT_SECONDS: &str = "30";
|
pub const DEFAULT_RPC_TIMEOUT_SECONDS: &str = "30";
|
||||||
pub const DEFAULT_CONFIRM_TX_TIMEOUT_SECONDS: &str = "5";
|
pub const DEFAULT_CONFIRM_TX_TIMEOUT_SECONDS: &str = "5";
|
||||||
|
const CHECKED: bool = true;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
@ -198,6 +195,7 @@ pub enum CliCommand {
|
|||||||
seed: Option<String>,
|
seed: Option<String>,
|
||||||
staker: Option<Pubkey>,
|
staker: Option<Pubkey>,
|
||||||
withdrawer: Option<Pubkey>,
|
withdrawer: Option<Pubkey>,
|
||||||
|
withdrawer_signer: Option<SignerIndex>,
|
||||||
lockup: Lockup,
|
lockup: Lockup,
|
||||||
amount: SpendAmount,
|
amount: SpendAmount,
|
||||||
sign_only: bool,
|
sign_only: bool,
|
||||||
@ -271,7 +269,7 @@ pub enum CliCommand {
|
|||||||
},
|
},
|
||||||
StakeAuthorize {
|
StakeAuthorize {
|
||||||
stake_account_pubkey: Pubkey,
|
stake_account_pubkey: Pubkey,
|
||||||
new_authorizations: Vec<(StakeAuthorize, Pubkey, SignerIndex)>,
|
new_authorizations: Vec<StakeAuthorizationIndexed>,
|
||||||
sign_only: bool,
|
sign_only: bool,
|
||||||
dump_transaction_message: bool,
|
dump_transaction_message: bool,
|
||||||
blockhash_query: BlockhashQuery,
|
blockhash_query: BlockhashQuery,
|
||||||
@ -286,6 +284,7 @@ pub enum CliCommand {
|
|||||||
stake_account_pubkey: Pubkey,
|
stake_account_pubkey: Pubkey,
|
||||||
lockup: LockupArgs,
|
lockup: LockupArgs,
|
||||||
custodian: SignerIndex,
|
custodian: SignerIndex,
|
||||||
|
new_custodian_signer: Option<SignerIndex>,
|
||||||
sign_only: bool,
|
sign_only: bool,
|
||||||
dump_transaction_message: bool,
|
dump_transaction_message: bool,
|
||||||
blockhash_query: BlockhashQuery,
|
blockhash_query: BlockhashQuery,
|
||||||
@ -343,6 +342,8 @@ pub enum CliCommand {
|
|||||||
new_authorized_pubkey: Pubkey,
|
new_authorized_pubkey: Pubkey,
|
||||||
vote_authorize: VoteAuthorize,
|
vote_authorize: VoteAuthorize,
|
||||||
memo: Option<String>,
|
memo: Option<String>,
|
||||||
|
authorized: SignerIndex,
|
||||||
|
new_authorized: Option<SignerIndex>,
|
||||||
},
|
},
|
||||||
VoteUpdateValidator {
|
VoteUpdateValidator {
|
||||||
vote_account_pubkey: Pubkey,
|
vote_account_pubkey: Pubkey,
|
||||||
@ -719,7 +720,10 @@ pub fn parse_command(
|
|||||||
}
|
}
|
||||||
// Stake Commands
|
// Stake Commands
|
||||||
("create-stake-account", Some(matches)) => {
|
("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)) => {
|
("delegate-stake", Some(matches)) => {
|
||||||
parse_stake_delegate_stake(matches, default_signer, wallet_manager)
|
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)
|
parse_merge_stake(matches, default_signer, wallet_manager)
|
||||||
}
|
}
|
||||||
("stake-authorize", Some(matches)) => {
|
("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)) => {
|
("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-account", Some(matches)) => parse_show_stake_account(matches, wallet_manager),
|
||||||
("stake-history", Some(matches)) => parse_show_stake_history(matches),
|
("stake-history", Some(matches)) => parse_show_stake_history(matches),
|
||||||
@ -767,12 +777,28 @@ pub fn parse_command(
|
|||||||
default_signer,
|
default_signer,
|
||||||
wallet_manager,
|
wallet_manager,
|
||||||
VoteAuthorize::Voter,
|
VoteAuthorize::Voter,
|
||||||
|
!CHECKED,
|
||||||
),
|
),
|
||||||
("vote-authorize-withdrawer", Some(matches)) => parse_vote_authorize(
|
("vote-authorize-withdrawer", Some(matches)) => parse_vote_authorize(
|
||||||
matches,
|
matches,
|
||||||
default_signer,
|
default_signer,
|
||||||
wallet_manager,
|
wallet_manager,
|
||||||
VoteAuthorize::Withdrawer,
|
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),
|
("vote-account", Some(matches)) => parse_vote_get_account_command(matches, wallet_manager),
|
||||||
("withdraw-from-vote-account", Some(matches)) => {
|
("withdraw-from-vote-account", Some(matches)) => {
|
||||||
@ -1533,6 +1559,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||||||
seed,
|
seed,
|
||||||
staker,
|
staker,
|
||||||
withdrawer,
|
withdrawer,
|
||||||
|
withdrawer_signer,
|
||||||
lockup,
|
lockup,
|
||||||
amount,
|
amount,
|
||||||
sign_only,
|
sign_only,
|
||||||
@ -1550,6 +1577,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||||||
seed,
|
seed,
|
||||||
staker,
|
staker,
|
||||||
withdrawer,
|
withdrawer,
|
||||||
|
*withdrawer_signer,
|
||||||
lockup,
|
lockup,
|
||||||
*amount,
|
*amount,
|
||||||
*sign_only,
|
*sign_only,
|
||||||
@ -1711,8 +1739,9 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||||||
),
|
),
|
||||||
CliCommand::StakeSetLockup {
|
CliCommand::StakeSetLockup {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
mut lockup,
|
lockup,
|
||||||
custodian,
|
custodian,
|
||||||
|
new_custodian_signer,
|
||||||
sign_only,
|
sign_only,
|
||||||
dump_transaction_message,
|
dump_transaction_message,
|
||||||
blockhash_query,
|
blockhash_query,
|
||||||
@ -1724,7 +1753,8 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||||||
&rpc_client,
|
&rpc_client,
|
||||||
config,
|
config,
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
&mut lockup,
|
lockup,
|
||||||
|
*new_custodian_signer,
|
||||||
*custodian,
|
*custodian,
|
||||||
*sign_only,
|
*sign_only,
|
||||||
*dump_transaction_message,
|
*dump_transaction_message,
|
||||||
@ -1838,12 +1868,16 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||||||
new_authorized_pubkey,
|
new_authorized_pubkey,
|
||||||
vote_authorize,
|
vote_authorize,
|
||||||
memo,
|
memo,
|
||||||
|
authorized,
|
||||||
|
new_authorized,
|
||||||
} => process_vote_authorize(
|
} => process_vote_authorize(
|
||||||
&rpc_client,
|
&rpc_client,
|
||||||
config,
|
config,
|
||||||
vote_account_pubkey,
|
vote_account_pubkey,
|
||||||
new_authorized_pubkey,
|
new_authorized_pubkey,
|
||||||
*vote_authorize,
|
*vote_authorize,
|
||||||
|
*authorized,
|
||||||
|
*new_authorized,
|
||||||
memo.as_ref(),
|
memo.as_ref(),
|
||||||
),
|
),
|
||||||
CliCommand::VoteUpdateValidator {
|
CliCommand::VoteUpdateValidator {
|
||||||
@ -2645,6 +2679,8 @@ mod tests {
|
|||||||
new_authorized_pubkey,
|
new_authorized_pubkey,
|
||||||
vote_authorize: VoteAuthorize::Voter,
|
vote_authorize: VoteAuthorize::Voter,
|
||||||
memo: None,
|
memo: None,
|
||||||
|
authorized: 0,
|
||||||
|
new_authorized: None,
|
||||||
};
|
};
|
||||||
let result = process_command(&config);
|
let result = process_command(&config);
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
@ -2668,6 +2704,7 @@ mod tests {
|
|||||||
seed: None,
|
seed: None,
|
||||||
staker: None,
|
staker: None,
|
||||||
withdrawer: None,
|
withdrawer: None,
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup: Lockup {
|
lockup: Lockup {
|
||||||
epoch: 0,
|
epoch: 0,
|
||||||
unix_timestamp: 0,
|
unix_timestamp: 0,
|
||||||
@ -2840,6 +2877,8 @@ mod tests {
|
|||||||
new_authorized_pubkey: bob_pubkey,
|
new_authorized_pubkey: bob_pubkey,
|
||||||
vote_authorize: VoteAuthorize::Voter,
|
vote_authorize: VoteAuthorize::Voter,
|
||||||
memo: None,
|
memo: None,
|
||||||
|
authorized: 0,
|
||||||
|
new_authorized: None,
|
||||||
};
|
};
|
||||||
assert!(process_command(&config).is_err());
|
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())
|
.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(
|
||||||
SubCommand::with_name("vote-update-validator")
|
SubCommand::with_name("vote-update-validator")
|
||||||
.about("Update the vote account's validator identity")
|
.about("Update the vote account's validator identity")
|
||||||
@ -311,19 +369,25 @@ pub fn parse_vote_authorize(
|
|||||||
default_signer: &DefaultSigner,
|
default_signer: &DefaultSigner,
|
||||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||||
vote_authorize: VoteAuthorize,
|
vote_authorize: VoteAuthorize,
|
||||||
|
checked: bool,
|
||||||
) -> Result<CliCommandInfo, CliError> {
|
) -> Result<CliCommandInfo, CliError> {
|
||||||
let vote_account_pubkey =
|
let vote_account_pubkey =
|
||||||
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
|
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
|
||||||
let new_authorized_pubkey =
|
let (authorized, authorized_pubkey) = signer_of(matches, "authorized", wallet_manager)?;
|
||||||
pubkey_of_signer(matches, "new_authorized_pubkey", wallet_manager)?.unwrap();
|
|
||||||
let (authorized, _) = signer_of(matches, "authorized", wallet_manager)?;
|
|
||||||
|
|
||||||
let payer_provided = None;
|
let payer_provided = None;
|
||||||
let signer_info = default_signer.generate_unique_signers(
|
let mut signers = vec![payer_provided, authorized];
|
||||||
vec![payer_provided, authorized],
|
|
||||||
matches,
|
let new_authorized_pubkey = if checked {
|
||||||
wallet_manager,
|
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);
|
let memo = matches.value_of(MEMO_ARG.name).map(String::from);
|
||||||
|
|
||||||
Ok(CliCommandInfo {
|
Ok(CliCommandInfo {
|
||||||
@ -332,6 +396,12 @@ pub fn parse_vote_authorize(
|
|||||||
new_authorized_pubkey,
|
new_authorized_pubkey,
|
||||||
vote_authorize,
|
vote_authorize,
|
||||||
memo,
|
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,
|
signers: signer_info.signers,
|
||||||
})
|
})
|
||||||
@ -558,28 +628,34 @@ pub fn process_vote_authorize(
|
|||||||
vote_account_pubkey: &Pubkey,
|
vote_account_pubkey: &Pubkey,
|
||||||
new_authorized_pubkey: &Pubkey,
|
new_authorized_pubkey: &Pubkey,
|
||||||
vote_authorize: VoteAuthorize,
|
vote_authorize: VoteAuthorize,
|
||||||
|
authorized: SignerIndex,
|
||||||
|
new_authorized: Option<SignerIndex>,
|
||||||
memo: Option<&String>,
|
memo: Option<&String>,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
// If the `authorized_account` is also the fee payer, `config.signers` will only have one
|
let authorized = config.signers[authorized];
|
||||||
// keypair in it
|
let new_authorized_signer = new_authorized.map(|index| config.signers[index]);
|
||||||
let authorized = if config.signers.len() == 2 {
|
|
||||||
config.signers[1]
|
|
||||||
} else {
|
|
||||||
config.signers[0]
|
|
||||||
};
|
|
||||||
|
|
||||||
check_unique_pubkeys(
|
check_unique_pubkeys(
|
||||||
(&authorized.pubkey(), "authorized_account".to_string()),
|
(&authorized.pubkey(), "authorized_account".to_string()),
|
||||||
(new_authorized_pubkey, "new_authorized_pubkey".to_string()),
|
(new_authorized_pubkey, "new_authorized_pubkey".to_string()),
|
||||||
)?;
|
)?;
|
||||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
let ixs = vec![vote_instruction::authorize(
|
let vote_ix = if new_authorized_signer.is_some() {
|
||||||
vote_account_pubkey, // vote account to update
|
vote_instruction::authorize_checked(
|
||||||
&authorized.pubkey(), // current authorized
|
vote_account_pubkey, // vote account to update
|
||||||
new_authorized_pubkey, // new vote signer/withdrawer
|
&authorized.pubkey(), // current authorized
|
||||||
vote_authorize, // vote or withdraw
|
new_authorized_pubkey, // new vote signer/withdrawer
|
||||||
)]
|
vote_authorize, // vote or withdraw
|
||||||
.with_memo(memo);
|
)
|
||||||
|
} 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 message = Message::new(&ixs, Some(&config.signers[0].pubkey()));
|
||||||
let mut tx = Transaction::new_unsigned(message);
|
let mut tx = Transaction::new_unsigned(message);
|
||||||
@ -843,6 +919,8 @@ mod tests {
|
|||||||
new_authorized_pubkey: pubkey2,
|
new_authorized_pubkey: pubkey2,
|
||||||
vote_authorize: VoteAuthorize::Voter,
|
vote_authorize: VoteAuthorize::Voter,
|
||||||
memo: None,
|
memo: None,
|
||||||
|
authorized: 0,
|
||||||
|
new_authorized: None,
|
||||||
},
|
},
|
||||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||||
}
|
}
|
||||||
@ -867,6 +945,8 @@ mod tests {
|
|||||||
new_authorized_pubkey: pubkey2,
|
new_authorized_pubkey: pubkey2,
|
||||||
vote_authorize: VoteAuthorize::Voter,
|
vote_authorize: VoteAuthorize::Voter,
|
||||||
memo: None,
|
memo: None,
|
||||||
|
authorized: 1,
|
||||||
|
new_authorized: None,
|
||||||
},
|
},
|
||||||
signers: vec![
|
signers: vec![
|
||||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
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_file, mut tmp_file) = make_tmp_file();
|
||||||
let keypair = Keypair::new();
|
let keypair = Keypair::new();
|
||||||
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
|
write_keypair(&keypair, tmp_file.as_file_mut()).unwrap();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use solana_cli::{
|
use solana_cli::{
|
||||||
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
|
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
|
||||||
spend_utils::SpendAmount,
|
spend_utils::SpendAmount,
|
||||||
|
stake::StakeAuthorizationIndexed,
|
||||||
test_utils::{check_ready, check_recent_balance},
|
test_utils::{check_ready, check_recent_balance},
|
||||||
};
|
};
|
||||||
use solana_cli_output::{parse_sign_only_reply_string, OutputFormat};
|
use solana_cli_output::{parse_sign_only_reply_string, OutputFormat};
|
||||||
@ -64,6 +65,7 @@ fn test_stake_delegation_force() {
|
|||||||
seed: None,
|
seed: None,
|
||||||
staker: None,
|
staker: None,
|
||||||
withdrawer: None,
|
withdrawer: None,
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup: Lockup::default(),
|
lockup: Lockup::default(),
|
||||||
amount: SpendAmount::Some(50_000),
|
amount: SpendAmount::Some(50_000),
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
@ -151,6 +153,7 @@ fn test_seed_stake_delegation_and_deactivation() {
|
|||||||
seed: Some("hi there".to_string()),
|
seed: Some("hi there".to_string()),
|
||||||
staker: None,
|
staker: None,
|
||||||
withdrawer: None,
|
withdrawer: None,
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup: Lockup::default(),
|
lockup: Lockup::default(),
|
||||||
amount: SpendAmount::Some(50_000),
|
amount: SpendAmount::Some(50_000),
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
@ -231,6 +234,7 @@ fn test_stake_delegation_and_deactivation() {
|
|||||||
seed: None,
|
seed: None,
|
||||||
staker: None,
|
staker: None,
|
||||||
withdrawer: None,
|
withdrawer: None,
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup: Lockup::default(),
|
lockup: Lockup::default(),
|
||||||
amount: SpendAmount::Some(50_000),
|
amount: SpendAmount::Some(50_000),
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
@ -332,6 +336,7 @@ fn test_offline_stake_delegation_and_deactivation() {
|
|||||||
seed: None,
|
seed: None,
|
||||||
staker: Some(config_offline.signers[0].pubkey()),
|
staker: Some(config_offline.signers[0].pubkey()),
|
||||||
withdrawer: None,
|
withdrawer: None,
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup: Lockup::default(),
|
lockup: Lockup::default(),
|
||||||
amount: SpendAmount::Some(50_000),
|
amount: SpendAmount::Some(50_000),
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
@ -451,6 +456,7 @@ fn test_nonced_stake_delegation_and_deactivation() {
|
|||||||
seed: None,
|
seed: None,
|
||||||
staker: None,
|
staker: None,
|
||||||
withdrawer: None,
|
withdrawer: None,
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup: Lockup::default(),
|
lockup: Lockup::default(),
|
||||||
amount: SpendAmount::Some(50_000),
|
amount: SpendAmount::Some(50_000),
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
@ -581,6 +587,7 @@ fn test_stake_authorize() {
|
|||||||
seed: None,
|
seed: None,
|
||||||
staker: None,
|
staker: None,
|
||||||
withdrawer: None,
|
withdrawer: None,
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup: Lockup::default(),
|
lockup: Lockup::default(),
|
||||||
amount: SpendAmount::Some(50_000),
|
amount: SpendAmount::Some(50_000),
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
@ -600,7 +607,12 @@ fn test_stake_authorize() {
|
|||||||
config.signers.pop();
|
config.signers.pop();
|
||||||
config.command = CliCommand::StakeAuthorize {
|
config.command = CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
new_authorizations: vec![(StakeAuthorize::Staker, online_authority_pubkey, 0)],
|
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Staker,
|
||||||
|
new_authority_pubkey: online_authority_pubkey,
|
||||||
|
authority: 0,
|
||||||
|
new_authority_signer: None,
|
||||||
|
}],
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
blockhash_query: BlockhashQuery::default(),
|
blockhash_query: BlockhashQuery::default(),
|
||||||
@ -629,8 +641,18 @@ fn test_stake_authorize() {
|
|||||||
config.command = CliCommand::StakeAuthorize {
|
config.command = CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
new_authorizations: vec![
|
new_authorizations: vec![
|
||||||
(StakeAuthorize::Staker, online_authority2_pubkey, 1),
|
StakeAuthorizationIndexed {
|
||||||
(StakeAuthorize::Withdrawer, withdraw_authority_pubkey, 0),
|
authorization_type: StakeAuthorize::Staker,
|
||||||
|
new_authority_pubkey: online_authority2_pubkey,
|
||||||
|
authority: 1,
|
||||||
|
new_authority_signer: None,
|
||||||
|
},
|
||||||
|
StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Withdrawer,
|
||||||
|
new_authority_pubkey: withdraw_authority_pubkey,
|
||||||
|
authority: 0,
|
||||||
|
new_authority_signer: None,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
@ -657,7 +679,12 @@ fn test_stake_authorize() {
|
|||||||
config.signers.push(&online_authority2);
|
config.signers.push(&online_authority2);
|
||||||
config.command = CliCommand::StakeAuthorize {
|
config.command = CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
new_authorizations: vec![(StakeAuthorize::Staker, offline_authority_pubkey, 1)],
|
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Staker,
|
||||||
|
new_authority_pubkey: offline_authority_pubkey,
|
||||||
|
authority: 1,
|
||||||
|
new_authority_signer: None,
|
||||||
|
}],
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
blockhash_query: BlockhashQuery::default(),
|
blockhash_query: BlockhashQuery::default(),
|
||||||
@ -683,7 +710,12 @@ fn test_stake_authorize() {
|
|||||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||||
config_offline.command = CliCommand::StakeAuthorize {
|
config_offline.command = CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
new_authorizations: vec![(StakeAuthorize::Staker, nonced_authority_pubkey, 0)],
|
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Staker,
|
||||||
|
new_authority_pubkey: nonced_authority_pubkey,
|
||||||
|
authority: 0,
|
||||||
|
new_authority_signer: None,
|
||||||
|
}],
|
||||||
sign_only: true,
|
sign_only: true,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
blockhash_query: BlockhashQuery::None(blockhash),
|
blockhash_query: BlockhashQuery::None(blockhash),
|
||||||
@ -702,7 +734,12 @@ fn test_stake_authorize() {
|
|||||||
config.signers = vec![&offline_presigner];
|
config.signers = vec![&offline_presigner];
|
||||||
config.command = CliCommand::StakeAuthorize {
|
config.command = CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
new_authorizations: vec![(StakeAuthorize::Staker, nonced_authority_pubkey, 0)],
|
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Staker,
|
||||||
|
new_authority_pubkey: nonced_authority_pubkey,
|
||||||
|
authority: 0,
|
||||||
|
new_authority_signer: None,
|
||||||
|
}],
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
|
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
|
||||||
@ -753,7 +790,12 @@ fn test_stake_authorize() {
|
|||||||
config_offline.signers.push(&nonced_authority);
|
config_offline.signers.push(&nonced_authority);
|
||||||
config_offline.command = CliCommand::StakeAuthorize {
|
config_offline.command = CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
new_authorizations: vec![(StakeAuthorize::Staker, online_authority_pubkey, 1)],
|
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Staker,
|
||||||
|
new_authority_pubkey: online_authority_pubkey,
|
||||||
|
authority: 1,
|
||||||
|
new_authority_signer: None,
|
||||||
|
}],
|
||||||
sign_only: true,
|
sign_only: true,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
blockhash_query: BlockhashQuery::None(nonce_hash),
|
blockhash_query: BlockhashQuery::None(nonce_hash),
|
||||||
@ -773,7 +815,12 @@ fn test_stake_authorize() {
|
|||||||
config.signers = vec![&offline_presigner, &nonced_authority_presigner];
|
config.signers = vec![&offline_presigner, &nonced_authority_presigner];
|
||||||
config.command = CliCommand::StakeAuthorize {
|
config.command = CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
new_authorizations: vec![(StakeAuthorize::Staker, online_authority_pubkey, 1)],
|
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Staker,
|
||||||
|
new_authority_pubkey: online_authority_pubkey,
|
||||||
|
authority: 1,
|
||||||
|
new_authority_signer: None,
|
||||||
|
}],
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
blockhash_query: BlockhashQuery::FeeCalculator(
|
blockhash_query: BlockhashQuery::FeeCalculator(
|
||||||
@ -861,6 +908,7 @@ fn test_stake_authorize_with_fee_payer() {
|
|||||||
seed: None,
|
seed: None,
|
||||||
staker: None,
|
staker: None,
|
||||||
withdrawer: None,
|
withdrawer: None,
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup: Lockup::default(),
|
lockup: Lockup::default(),
|
||||||
amount: SpendAmount::Some(50_000),
|
amount: SpendAmount::Some(50_000),
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
@ -880,7 +928,12 @@ fn test_stake_authorize_with_fee_payer() {
|
|||||||
config.signers = vec![&default_signer, &payer_keypair];
|
config.signers = vec![&default_signer, &payer_keypair];
|
||||||
config.command = CliCommand::StakeAuthorize {
|
config.command = CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
new_authorizations: vec![(StakeAuthorize::Staker, offline_pubkey, 0)],
|
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Staker,
|
||||||
|
new_authority_pubkey: offline_pubkey,
|
||||||
|
authority: 0,
|
||||||
|
new_authority_signer: None,
|
||||||
|
}],
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
||||||
@ -902,7 +955,12 @@ fn test_stake_authorize_with_fee_payer() {
|
|||||||
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
let (blockhash, _) = rpc_client.get_recent_blockhash().unwrap();
|
||||||
config_offline.command = CliCommand::StakeAuthorize {
|
config_offline.command = CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
new_authorizations: vec![(StakeAuthorize::Staker, payer_pubkey, 0)],
|
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Staker,
|
||||||
|
new_authority_pubkey: payer_pubkey,
|
||||||
|
authority: 0,
|
||||||
|
new_authority_signer: None,
|
||||||
|
}],
|
||||||
sign_only: true,
|
sign_only: true,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
blockhash_query: BlockhashQuery::None(blockhash),
|
blockhash_query: BlockhashQuery::None(blockhash),
|
||||||
@ -921,7 +979,12 @@ fn test_stake_authorize_with_fee_payer() {
|
|||||||
config.signers = vec![&offline_presigner];
|
config.signers = vec![&offline_presigner];
|
||||||
config.command = CliCommand::StakeAuthorize {
|
config.command = CliCommand::StakeAuthorize {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
new_authorizations: vec![(StakeAuthorize::Staker, payer_pubkey, 0)],
|
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Staker,
|
||||||
|
new_authority_pubkey: payer_pubkey,
|
||||||
|
authority: 0,
|
||||||
|
new_authority_signer: None,
|
||||||
|
}],
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
|
blockhash_query: BlockhashQuery::FeeCalculator(blockhash_query::Source::Cluster, blockhash),
|
||||||
@ -985,6 +1048,7 @@ fn test_stake_split() {
|
|||||||
seed: None,
|
seed: None,
|
||||||
staker: Some(offline_pubkey),
|
staker: Some(offline_pubkey),
|
||||||
withdrawer: Some(offline_pubkey),
|
withdrawer: Some(offline_pubkey),
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup: Lockup::default(),
|
lockup: Lockup::default(),
|
||||||
amount: SpendAmount::Some(10 * minimum_stake_balance),
|
amount: SpendAmount::Some(10 * minimum_stake_balance),
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
@ -1135,6 +1199,7 @@ fn test_stake_set_lockup() {
|
|||||||
seed: None,
|
seed: None,
|
||||||
staker: Some(offline_pubkey),
|
staker: Some(offline_pubkey),
|
||||||
withdrawer: Some(config.signers[0].pubkey()),
|
withdrawer: Some(config.signers[0].pubkey()),
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup,
|
lockup,
|
||||||
amount: SpendAmount::Some(10 * minimum_stake_balance),
|
amount: SpendAmount::Some(10 * minimum_stake_balance),
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
@ -1163,6 +1228,7 @@ fn test_stake_set_lockup() {
|
|||||||
config.command = CliCommand::StakeSetLockup {
|
config.command = CliCommand::StakeSetLockup {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
lockup,
|
lockup,
|
||||||
|
new_custodian_signer: None,
|
||||||
custodian: 0,
|
custodian: 0,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
@ -1198,6 +1264,7 @@ fn test_stake_set_lockup() {
|
|||||||
config.command = CliCommand::StakeSetLockup {
|
config.command = CliCommand::StakeSetLockup {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
lockup,
|
lockup,
|
||||||
|
new_custodian_signer: None,
|
||||||
custodian: 0,
|
custodian: 0,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
@ -1218,6 +1285,7 @@ fn test_stake_set_lockup() {
|
|||||||
config.command = CliCommand::StakeSetLockup {
|
config.command = CliCommand::StakeSetLockup {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
lockup,
|
lockup,
|
||||||
|
new_custodian_signer: None,
|
||||||
custodian: 1,
|
custodian: 1,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
@ -1250,6 +1318,7 @@ fn test_stake_set_lockup() {
|
|||||||
config.command = CliCommand::StakeSetLockup {
|
config.command = CliCommand::StakeSetLockup {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
lockup,
|
lockup,
|
||||||
|
new_custodian_signer: None,
|
||||||
custodian: 1,
|
custodian: 1,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
@ -1297,6 +1366,7 @@ fn test_stake_set_lockup() {
|
|||||||
config_offline.command = CliCommand::StakeSetLockup {
|
config_offline.command = CliCommand::StakeSetLockup {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
lockup,
|
lockup,
|
||||||
|
new_custodian_signer: None,
|
||||||
custodian: 0,
|
custodian: 0,
|
||||||
sign_only: true,
|
sign_only: true,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
@ -1315,6 +1385,7 @@ fn test_stake_set_lockup() {
|
|||||||
config.command = CliCommand::StakeSetLockup {
|
config.command = CliCommand::StakeSetLockup {
|
||||||
stake_account_pubkey,
|
stake_account_pubkey,
|
||||||
lockup,
|
lockup,
|
||||||
|
new_custodian_signer: None,
|
||||||
custodian: 0,
|
custodian: 0,
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
dump_transaction_message: false,
|
dump_transaction_message: false,
|
||||||
@ -1409,6 +1480,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
|||||||
seed: None,
|
seed: None,
|
||||||
staker: None,
|
staker: None,
|
||||||
withdrawer: None,
|
withdrawer: None,
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup: Lockup::default(),
|
lockup: Lockup::default(),
|
||||||
amount: SpendAmount::Some(50_000),
|
amount: SpendAmount::Some(50_000),
|
||||||
sign_only: true,
|
sign_only: true,
|
||||||
@ -1432,6 +1504,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
|||||||
seed: None,
|
seed: None,
|
||||||
staker: Some(offline_pubkey),
|
staker: Some(offline_pubkey),
|
||||||
withdrawer: None,
|
withdrawer: None,
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup: Lockup::default(),
|
lockup: Lockup::default(),
|
||||||
amount: SpendAmount::Some(50_000),
|
amount: SpendAmount::Some(50_000),
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
@ -1521,6 +1594,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
|||||||
seed: Some(seed.to_string()),
|
seed: Some(seed.to_string()),
|
||||||
staker: None,
|
staker: None,
|
||||||
withdrawer: None,
|
withdrawer: None,
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup: Lockup::default(),
|
lockup: Lockup::default(),
|
||||||
amount: SpendAmount::Some(50_000),
|
amount: SpendAmount::Some(50_000),
|
||||||
sign_only: true,
|
sign_only: true,
|
||||||
@ -1542,6 +1616,7 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
|||||||
seed: Some(seed.to_string()),
|
seed: Some(seed.to_string()),
|
||||||
staker: Some(offline_pubkey),
|
staker: Some(offline_pubkey),
|
||||||
withdrawer: Some(offline_pubkey),
|
withdrawer: Some(offline_pubkey),
|
||||||
|
withdrawer_signer: None,
|
||||||
lockup: Lockup::default(),
|
lockup: Lockup::default(),
|
||||||
amount: SpendAmount::Some(50_000),
|
amount: SpendAmount::Some(50_000),
|
||||||
sign_only: false,
|
sign_only: false,
|
||||||
@ -1561,3 +1636,228 @@ fn test_offline_nonced_create_stake_account_and_withdraw() {
|
|||||||
Pubkey::create_with_seed(&stake_pubkey, seed, &stake::program::id()).unwrap();
|
Pubkey::create_with_seed(&stake_pubkey, seed, &stake::program::id()).unwrap();
|
||||||
check_recent_balance(50_000, &rpc_client, &seed_address);
|
check_recent_balance(50_000, &rpc_client, &seed_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_stake_checked_instructions() {
|
||||||
|
solana_logger::setup();
|
||||||
|
|
||||||
|
let mint_keypair = Keypair::new();
|
||||||
|
let mint_pubkey = mint_keypair.pubkey();
|
||||||
|
let faucet_addr = run_local_faucet(mint_keypair, None);
|
||||||
|
let test_validator = TestValidator::with_no_fees(mint_pubkey, Some(faucet_addr));
|
||||||
|
|
||||||
|
let rpc_client =
|
||||||
|
RpcClient::new_with_commitment(test_validator.rpc_url(), CommitmentConfig::processed());
|
||||||
|
let default_signer = Keypair::new();
|
||||||
|
|
||||||
|
let mut config = CliConfig::recent_for_tests();
|
||||||
|
config.json_rpc_url = test_validator.rpc_url();
|
||||||
|
config.signers = vec![&default_signer];
|
||||||
|
|
||||||
|
request_and_confirm_airdrop(&rpc_client, &config, &config.signers[0].pubkey(), 100_000)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Create stake account with withdrawer
|
||||||
|
let stake_keypair = Keypair::new();
|
||||||
|
let stake_account_pubkey = stake_keypair.pubkey();
|
||||||
|
let withdrawer_keypair = Keypair::new();
|
||||||
|
let withdrawer_pubkey = withdrawer_keypair.pubkey();
|
||||||
|
config.signers.push(&stake_keypair);
|
||||||
|
config.command = CliCommand::CreateStakeAccount {
|
||||||
|
stake_account: 1,
|
||||||
|
seed: None,
|
||||||
|
staker: None,
|
||||||
|
withdrawer: Some(withdrawer_pubkey),
|
||||||
|
withdrawer_signer: Some(1),
|
||||||
|
lockup: Lockup::default(),
|
||||||
|
amount: SpendAmount::Some(50_000),
|
||||||
|
sign_only: false,
|
||||||
|
dump_transaction_message: false,
|
||||||
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
||||||
|
nonce_account: None,
|
||||||
|
nonce_authority: 0,
|
||||||
|
memo: None,
|
||||||
|
fee_payer: 0,
|
||||||
|
from: 0,
|
||||||
|
};
|
||||||
|
process_command(&config).unwrap_err(); // unsigned authority should fail
|
||||||
|
|
||||||
|
config.signers = vec![&default_signer, &stake_keypair, &withdrawer_keypair];
|
||||||
|
config.command = CliCommand::CreateStakeAccount {
|
||||||
|
stake_account: 1,
|
||||||
|
seed: None,
|
||||||
|
staker: None,
|
||||||
|
withdrawer: Some(withdrawer_pubkey),
|
||||||
|
withdrawer_signer: Some(1),
|
||||||
|
lockup: Lockup::default(),
|
||||||
|
amount: SpendAmount::Some(50_000),
|
||||||
|
sign_only: false,
|
||||||
|
dump_transaction_message: false,
|
||||||
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
||||||
|
nonce_account: None,
|
||||||
|
nonce_authority: 0,
|
||||||
|
memo: None,
|
||||||
|
fee_payer: 0,
|
||||||
|
from: 0,
|
||||||
|
};
|
||||||
|
process_command(&config).unwrap();
|
||||||
|
|
||||||
|
// Re-authorize account, checking new authority
|
||||||
|
let staker_keypair = Keypair::new();
|
||||||
|
let staker_pubkey = staker_keypair.pubkey();
|
||||||
|
config.signers = vec![&default_signer];
|
||||||
|
config.command = CliCommand::StakeAuthorize {
|
||||||
|
stake_account_pubkey,
|
||||||
|
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Staker,
|
||||||
|
new_authority_pubkey: staker_pubkey,
|
||||||
|
authority: 0,
|
||||||
|
new_authority_signer: Some(0),
|
||||||
|
}],
|
||||||
|
sign_only: false,
|
||||||
|
dump_transaction_message: false,
|
||||||
|
blockhash_query: BlockhashQuery::default(),
|
||||||
|
nonce_account: None,
|
||||||
|
nonce_authority: 0,
|
||||||
|
memo: None,
|
||||||
|
fee_payer: 0,
|
||||||
|
custodian: None,
|
||||||
|
no_wait: false,
|
||||||
|
};
|
||||||
|
process_command(&config).unwrap_err(); // unsigned authority should fail
|
||||||
|
|
||||||
|
config.signers = vec![&default_signer, &staker_keypair];
|
||||||
|
config.command = CliCommand::StakeAuthorize {
|
||||||
|
stake_account_pubkey,
|
||||||
|
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Staker,
|
||||||
|
new_authority_pubkey: staker_pubkey,
|
||||||
|
authority: 0,
|
||||||
|
new_authority_signer: Some(1),
|
||||||
|
}],
|
||||||
|
sign_only: false,
|
||||||
|
dump_transaction_message: false,
|
||||||
|
blockhash_query: BlockhashQuery::default(),
|
||||||
|
nonce_account: None,
|
||||||
|
nonce_authority: 0,
|
||||||
|
memo: None,
|
||||||
|
fee_payer: 0,
|
||||||
|
custodian: None,
|
||||||
|
no_wait: false,
|
||||||
|
};
|
||||||
|
process_command(&config).unwrap();
|
||||||
|
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||||
|
let stake_state: StakeState = stake_account.state().unwrap();
|
||||||
|
let current_authority = match stake_state {
|
||||||
|
StakeState::Initialized(meta) => meta.authorized.staker,
|
||||||
|
_ => panic!("Unexpected stake state!"),
|
||||||
|
};
|
||||||
|
assert_eq!(current_authority, staker_pubkey);
|
||||||
|
|
||||||
|
let new_withdrawer_keypair = Keypair::new();
|
||||||
|
let new_withdrawer_pubkey = new_withdrawer_keypair.pubkey();
|
||||||
|
config.signers = vec![&default_signer, &withdrawer_keypair];
|
||||||
|
config.command = CliCommand::StakeAuthorize {
|
||||||
|
stake_account_pubkey,
|
||||||
|
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Withdrawer,
|
||||||
|
new_authority_pubkey: new_withdrawer_pubkey,
|
||||||
|
authority: 1,
|
||||||
|
new_authority_signer: Some(1),
|
||||||
|
}],
|
||||||
|
sign_only: false,
|
||||||
|
dump_transaction_message: false,
|
||||||
|
blockhash_query: BlockhashQuery::default(),
|
||||||
|
nonce_account: None,
|
||||||
|
nonce_authority: 0,
|
||||||
|
memo: None,
|
||||||
|
fee_payer: 0,
|
||||||
|
custodian: None,
|
||||||
|
no_wait: false,
|
||||||
|
};
|
||||||
|
process_command(&config).unwrap_err(); // unsigned authority should fail
|
||||||
|
|
||||||
|
config.signers = vec![
|
||||||
|
&default_signer,
|
||||||
|
&withdrawer_keypair,
|
||||||
|
&new_withdrawer_keypair,
|
||||||
|
];
|
||||||
|
config.command = CliCommand::StakeAuthorize {
|
||||||
|
stake_account_pubkey,
|
||||||
|
new_authorizations: vec![StakeAuthorizationIndexed {
|
||||||
|
authorization_type: StakeAuthorize::Withdrawer,
|
||||||
|
new_authority_pubkey: new_withdrawer_pubkey,
|
||||||
|
authority: 1,
|
||||||
|
new_authority_signer: Some(2),
|
||||||
|
}],
|
||||||
|
sign_only: false,
|
||||||
|
dump_transaction_message: false,
|
||||||
|
blockhash_query: BlockhashQuery::default(),
|
||||||
|
nonce_account: None,
|
||||||
|
nonce_authority: 0,
|
||||||
|
memo: None,
|
||||||
|
fee_payer: 0,
|
||||||
|
custodian: None,
|
||||||
|
no_wait: false,
|
||||||
|
};
|
||||||
|
process_command(&config).unwrap();
|
||||||
|
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||||
|
let stake_state: StakeState = stake_account.state().unwrap();
|
||||||
|
let current_authority = match stake_state {
|
||||||
|
StakeState::Initialized(meta) => meta.authorized.withdrawer,
|
||||||
|
_ => panic!("Unexpected stake state!"),
|
||||||
|
};
|
||||||
|
assert_eq!(current_authority, new_withdrawer_pubkey);
|
||||||
|
|
||||||
|
// Set lockup, checking new custodian
|
||||||
|
let custodian = Keypair::new();
|
||||||
|
let custodian_pubkey = custodian.pubkey();
|
||||||
|
let lockup = LockupArgs {
|
||||||
|
unix_timestamp: Some(1_581_534_570),
|
||||||
|
epoch: Some(200),
|
||||||
|
custodian: Some(custodian_pubkey),
|
||||||
|
};
|
||||||
|
config.signers = vec![&default_signer, &new_withdrawer_keypair];
|
||||||
|
config.command = CliCommand::StakeSetLockup {
|
||||||
|
stake_account_pubkey,
|
||||||
|
lockup,
|
||||||
|
new_custodian_signer: Some(1),
|
||||||
|
custodian: 1,
|
||||||
|
sign_only: false,
|
||||||
|
dump_transaction_message: false,
|
||||||
|
blockhash_query: BlockhashQuery::default(),
|
||||||
|
nonce_account: None,
|
||||||
|
nonce_authority: 0,
|
||||||
|
memo: None,
|
||||||
|
fee_payer: 0,
|
||||||
|
};
|
||||||
|
process_command(&config).unwrap_err(); // unsigned new custodian should fail
|
||||||
|
|
||||||
|
config.signers = vec![&default_signer, &new_withdrawer_keypair, &custodian];
|
||||||
|
config.command = CliCommand::StakeSetLockup {
|
||||||
|
stake_account_pubkey,
|
||||||
|
lockup,
|
||||||
|
new_custodian_signer: Some(2),
|
||||||
|
custodian: 1,
|
||||||
|
sign_only: false,
|
||||||
|
dump_transaction_message: false,
|
||||||
|
blockhash_query: BlockhashQuery::default(),
|
||||||
|
nonce_account: None,
|
||||||
|
nonce_authority: 0,
|
||||||
|
memo: None,
|
||||||
|
fee_payer: 0,
|
||||||
|
};
|
||||||
|
process_command(&config).unwrap();
|
||||||
|
let stake_account = rpc_client.get_account(&stake_account_pubkey).unwrap();
|
||||||
|
let stake_state: StakeState = stake_account.state().unwrap();
|
||||||
|
let current_lockup = match stake_state {
|
||||||
|
StakeState::Initialized(meta) => meta.lockup,
|
||||||
|
_ => panic!("Unexpected stake state!"),
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
current_lockup.unix_timestamp,
|
||||||
|
lockup.unix_timestamp.unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(current_lockup.epoch, lockup.epoch.unwrap());
|
||||||
|
assert_eq!(current_lockup.custodian, custodian_pubkey);
|
||||||
|
}
|
||||||
|
@ -83,13 +83,48 @@ fn test_vote_authorize_and_withdraw() {
|
|||||||
check_recent_balance(expected_balance, &rpc_client, &vote_account_pubkey);
|
check_recent_balance(expected_balance, &rpc_client, &vote_account_pubkey);
|
||||||
|
|
||||||
// Authorize vote account withdrawal to another signer
|
// Authorize vote account withdrawal to another signer
|
||||||
let withdraw_authority = Keypair::new();
|
let first_withdraw_authority = Keypair::new();
|
||||||
config.signers = vec![&default_signer];
|
config.signers = vec![&default_signer];
|
||||||
|
config.command = CliCommand::VoteAuthorize {
|
||||||
|
vote_account_pubkey,
|
||||||
|
new_authorized_pubkey: first_withdraw_authority.pubkey(),
|
||||||
|
vote_authorize: VoteAuthorize::Withdrawer,
|
||||||
|
memo: None,
|
||||||
|
authorized: 0,
|
||||||
|
new_authorized: None,
|
||||||
|
};
|
||||||
|
process_command(&config).unwrap();
|
||||||
|
let vote_account = rpc_client
|
||||||
|
.get_account(&vote_account_keypair.pubkey())
|
||||||
|
.unwrap();
|
||||||
|
let vote_state: VoteStateVersions = vote_account.state().unwrap();
|
||||||
|
let authorized_withdrawer = vote_state.convert_to_current().authorized_withdrawer;
|
||||||
|
assert_eq!(authorized_withdrawer, first_withdraw_authority.pubkey());
|
||||||
|
|
||||||
|
// Authorize vote account withdrawal to another signer with checked instruction
|
||||||
|
let withdraw_authority = Keypair::new();
|
||||||
|
config.signers = vec![&default_signer, &first_withdraw_authority];
|
||||||
config.command = CliCommand::VoteAuthorize {
|
config.command = CliCommand::VoteAuthorize {
|
||||||
vote_account_pubkey,
|
vote_account_pubkey,
|
||||||
new_authorized_pubkey: withdraw_authority.pubkey(),
|
new_authorized_pubkey: withdraw_authority.pubkey(),
|
||||||
vote_authorize: VoteAuthorize::Withdrawer,
|
vote_authorize: VoteAuthorize::Withdrawer,
|
||||||
memo: None,
|
memo: None,
|
||||||
|
authorized: 1,
|
||||||
|
new_authorized: Some(1),
|
||||||
|
};
|
||||||
|
process_command(&config).unwrap_err(); // unsigned by new authority should fail
|
||||||
|
config.signers = vec![
|
||||||
|
&default_signer,
|
||||||
|
&first_withdraw_authority,
|
||||||
|
&withdraw_authority,
|
||||||
|
];
|
||||||
|
config.command = CliCommand::VoteAuthorize {
|
||||||
|
vote_account_pubkey,
|
||||||
|
new_authorized_pubkey: withdraw_authority.pubkey(),
|
||||||
|
vote_authorize: VoteAuthorize::Withdrawer,
|
||||||
|
memo: None,
|
||||||
|
authorized: 1,
|
||||||
|
new_authorized: Some(2),
|
||||||
};
|
};
|
||||||
process_command(&config).unwrap();
|
process_command(&config).unwrap();
|
||||||
let vote_account = rpc_client
|
let vote_account = rpc_client
|
||||||
|
Reference in New Issue
Block a user