|solana withdraw-from-vote-account| now supports ALL, and refuses to deallocate the vote account (#10602)
(cherry picked from commit 296ac10b3a
)
This commit is contained in:
@ -396,7 +396,7 @@ pub enum CliCommand {
|
|||||||
vote_account_pubkey: Pubkey,
|
vote_account_pubkey: Pubkey,
|
||||||
destination_account_pubkey: Pubkey,
|
destination_account_pubkey: Pubkey,
|
||||||
withdraw_authority: SignerIndex,
|
withdraw_authority: SignerIndex,
|
||||||
lamports: u64,
|
withdraw_amount: SpendAmount,
|
||||||
},
|
},
|
||||||
VoteAuthorize {
|
VoteAuthorize {
|
||||||
vote_account_pubkey: Pubkey,
|
vote_account_pubkey: Pubkey,
|
||||||
@ -2155,14 +2155,14 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||||||
CliCommand::WithdrawFromVoteAccount {
|
CliCommand::WithdrawFromVoteAccount {
|
||||||
vote_account_pubkey,
|
vote_account_pubkey,
|
||||||
withdraw_authority,
|
withdraw_authority,
|
||||||
lamports,
|
withdraw_amount,
|
||||||
destination_account_pubkey,
|
destination_account_pubkey,
|
||||||
} => process_withdraw_from_vote_account(
|
} => process_withdraw_from_vote_account(
|
||||||
&rpc_client,
|
&rpc_client,
|
||||||
config,
|
config,
|
||||||
vote_account_pubkey,
|
vote_account_pubkey,
|
||||||
*withdraw_authority,
|
*withdraw_authority,
|
||||||
*lamports,
|
*withdraw_amount,
|
||||||
destination_account_pubkey,
|
destination_account_pubkey,
|
||||||
),
|
),
|
||||||
CliCommand::VoteAuthorize {
|
CliCommand::VoteAuthorize {
|
||||||
|
@ -16,8 +16,9 @@ use solana_clap_utils::{
|
|||||||
use solana_client::rpc_client::RpcClient;
|
use solana_client::rpc_client::RpcClient;
|
||||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account, commitment_config::CommitmentConfig, message::Message, pubkey::Pubkey,
|
account::Account, commitment_config::CommitmentConfig, message::Message,
|
||||||
system_instruction::SystemError, transaction::Transaction,
|
native_token::lamports_to_sol, pubkey::Pubkey, system_instruction::SystemError,
|
||||||
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_vote_program::{
|
use solana_vote_program::{
|
||||||
vote_instruction::{self, withdraw, VoteError},
|
vote_instruction::{self, withdraw, VoteError},
|
||||||
@ -232,8 +233,8 @@ impl VoteSubCommands for App<'_, '_> {
|
|||||||
.value_name("AMOUNT")
|
.value_name("AMOUNT")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.required(true)
|
.required(true)
|
||||||
.validator(is_amount)
|
.validator(is_amount_or_all)
|
||||||
.help("The amount to withdraw, in SOL"),
|
.help("The amount to withdraw, in SOL; accepts keyword ALL"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("authorized_withdrawer")
|
Arg::with_name("authorized_withdrawer")
|
||||||
@ -392,7 +393,8 @@ pub fn parse_withdraw_from_vote_account(
|
|||||||
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
|
pubkey_of_signer(matches, "vote_account_pubkey", wallet_manager)?.unwrap();
|
||||||
let destination_account_pubkey =
|
let destination_account_pubkey =
|
||||||
pubkey_of_signer(matches, "destination_account_pubkey", wallet_manager)?.unwrap();
|
pubkey_of_signer(matches, "destination_account_pubkey", wallet_manager)?.unwrap();
|
||||||
let lamports = lamports_of_sol(matches, "amount").unwrap();
|
let withdraw_amount = SpendAmount::new_from_matches(matches, "amount");
|
||||||
|
|
||||||
let (withdraw_authority, withdraw_authority_pubkey) =
|
let (withdraw_authority, withdraw_authority_pubkey) =
|
||||||
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
|
signer_of(matches, "authorized_withdrawer", wallet_manager)?;
|
||||||
|
|
||||||
@ -409,7 +411,7 @@ pub fn parse_withdraw_from_vote_account(
|
|||||||
vote_account_pubkey,
|
vote_account_pubkey,
|
||||||
destination_account_pubkey,
|
destination_account_pubkey,
|
||||||
withdraw_authority: signer_info.index_of(withdraw_authority_pubkey).unwrap(),
|
withdraw_authority: signer_info.index_of(withdraw_authority_pubkey).unwrap(),
|
||||||
lamports,
|
withdraw_amount,
|
||||||
},
|
},
|
||||||
signers: signer_info.signers,
|
signers: signer_info.signers,
|
||||||
})
|
})
|
||||||
@ -683,12 +685,28 @@ pub fn process_withdraw_from_vote_account(
|
|||||||
config: &CliConfig,
|
config: &CliConfig,
|
||||||
vote_account_pubkey: &Pubkey,
|
vote_account_pubkey: &Pubkey,
|
||||||
withdraw_authority: SignerIndex,
|
withdraw_authority: SignerIndex,
|
||||||
lamports: u64,
|
withdraw_amount: SpendAmount,
|
||||||
destination_account_pubkey: &Pubkey,
|
destination_account_pubkey: &Pubkey,
|
||||||
) -> ProcessResult {
|
) -> ProcessResult {
|
||||||
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
let (recent_blockhash, fee_calculator) = rpc_client.get_recent_blockhash()?;
|
||||||
let withdraw_authority = config.signers[withdraw_authority];
|
let withdraw_authority = config.signers[withdraw_authority];
|
||||||
|
|
||||||
|
let current_balance = rpc_client.get_balance(&vote_account_pubkey)?;
|
||||||
|
let minimum_balance = rpc_client.get_minimum_balance_for_rent_exemption(VoteState::size_of())?;
|
||||||
|
|
||||||
|
let lamports = match withdraw_amount {
|
||||||
|
SpendAmount::All => current_balance.saturating_sub(minimum_balance),
|
||||||
|
SpendAmount::Some(withdraw_amount) => {
|
||||||
|
if current_balance.saturating_sub(withdraw_amount) < minimum_balance {
|
||||||
|
return Err(CliError::BadParameter(format!(
|
||||||
|
"Withdraw amount too large. The vote account balance must be at least {} SOL to remain rent exempt", lamports_to_sol(minimum_balance)
|
||||||
|
))
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
withdraw_amount
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let ix = withdraw(
|
let ix = withdraw(
|
||||||
vote_account_pubkey,
|
vote_account_pubkey,
|
||||||
&withdraw_authority.pubkey(),
|
&withdraw_authority.pubkey(),
|
||||||
@ -966,7 +984,33 @@ mod tests {
|
|||||||
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
||||||
destination_account_pubkey: pubkey,
|
destination_account_pubkey: pubkey,
|
||||||
withdraw_authority: 0,
|
withdraw_authority: 0,
|
||||||
lamports: 42_000_000_000
|
withdraw_amount: SpendAmount::Some(42_000_000_000),
|
||||||
|
},
|
||||||
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test WithdrawFromVoteAccount subcommand
|
||||||
|
let test_withdraw_from_vote_account = test_commands.clone().get_matches_from(vec![
|
||||||
|
"test",
|
||||||
|
"withdraw-from-vote-account",
|
||||||
|
&keypair_file,
|
||||||
|
&pubkey_string,
|
||||||
|
"ALL",
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
parse_command(
|
||||||
|
&test_withdraw_from_vote_account,
|
||||||
|
&default_keypair_file,
|
||||||
|
&mut None
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
CliCommandInfo {
|
||||||
|
command: CliCommand::WithdrawFromVoteAccount {
|
||||||
|
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
||||||
|
destination_account_pubkey: pubkey,
|
||||||
|
withdraw_authority: 0,
|
||||||
|
withdraw_amount: SpendAmount::All,
|
||||||
},
|
},
|
||||||
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
signers: vec![read_keypair_file(&default_keypair_file).unwrap().into()],
|
||||||
}
|
}
|
||||||
@ -997,7 +1041,7 @@ mod tests {
|
|||||||
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
vote_account_pubkey: read_keypair_file(&keypair_file).unwrap().pubkey(),
|
||||||
destination_account_pubkey: pubkey,
|
destination_account_pubkey: pubkey,
|
||||||
withdraw_authority: 1,
|
withdraw_authority: 1,
|
||||||
lamports: 42_000_000_000
|
withdraw_amount: SpendAmount::Some(42_000_000_000),
|
||||||
},
|
},
|
||||||
signers: vec![
|
signers: vec![
|
||||||
read_keypair_file(&default_keypair_file).unwrap().into(),
|
read_keypair_file(&default_keypair_file).unwrap().into(),
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
use solana_cli::cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig};
|
use solana_cli::{
|
||||||
use solana_cli::test_utils::check_balance;
|
cli::{process_command, request_and_confirm_airdrop, CliCommand, CliConfig},
|
||||||
|
offline::{blockhash_query::BlockhashQuery, *},
|
||||||
|
spend_utils::SpendAmount,
|
||||||
|
test_utils::check_balance,
|
||||||
|
};
|
||||||
use solana_client::rpc_client::RpcClient;
|
use solana_client::rpc_client::RpcClient;
|
||||||
use solana_core::validator::TestValidator;
|
use solana_core::validator::TestValidator;
|
||||||
use solana_faucet::faucet::run_local_faucet;
|
use solana_faucet::faucet::run_local_faucet;
|
||||||
@ -64,6 +68,23 @@ fn test_vote_authorize_and_withdraw() {
|
|||||||
.max(1);
|
.max(1);
|
||||||
check_balance(expected_balance, &rpc_client, &vote_account_pubkey);
|
check_balance(expected_balance, &rpc_client, &vote_account_pubkey);
|
||||||
|
|
||||||
|
// Transfer in some more SOL
|
||||||
|
config.signers = vec![&default_signer];
|
||||||
|
config.command = CliCommand::Transfer {
|
||||||
|
amount: SpendAmount::Some(1_000),
|
||||||
|
to: vote_account_pubkey,
|
||||||
|
from: 0,
|
||||||
|
sign_only: false,
|
||||||
|
no_wait: false,
|
||||||
|
blockhash_query: BlockhashQuery::All(blockhash_query::Source::Cluster),
|
||||||
|
nonce_account: None,
|
||||||
|
nonce_authority: 0,
|
||||||
|
fee_payer: 0,
|
||||||
|
};
|
||||||
|
process_command(&config).unwrap();
|
||||||
|
let expected_balance = expected_balance + 1_000;
|
||||||
|
check_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 withdraw_authority = Keypair::new();
|
||||||
config.signers = vec![&default_signer];
|
config.signers = vec![&default_signer];
|
||||||
@ -86,7 +107,7 @@ fn test_vote_authorize_and_withdraw() {
|
|||||||
config.command = CliCommand::WithdrawFromVoteAccount {
|
config.command = CliCommand::WithdrawFromVoteAccount {
|
||||||
vote_account_pubkey,
|
vote_account_pubkey,
|
||||||
withdraw_authority: 1,
|
withdraw_authority: 1,
|
||||||
lamports: 100,
|
withdraw_amount: SpendAmount::Some(100),
|
||||||
destination_account_pubkey: destination_account,
|
destination_account_pubkey: destination_account,
|
||||||
};
|
};
|
||||||
process_command(&config).unwrap();
|
process_command(&config).unwrap();
|
||||||
|
Reference in New Issue
Block a user