Restore ALL behavior; add enum variant, comments, and help text to make behavior clearer (#21854)
This commit is contained in:
@ -16,6 +16,7 @@ use {
|
|||||||
pub enum SpendAmount {
|
pub enum SpendAmount {
|
||||||
All,
|
All,
|
||||||
Some(u64),
|
Some(u64),
|
||||||
|
RentExempt,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SpendAmount {
|
impl Default for SpendAmount {
|
||||||
@ -89,6 +90,7 @@ where
|
|||||||
0,
|
0,
|
||||||
from_pubkey,
|
from_pubkey,
|
||||||
fee_pubkey,
|
fee_pubkey,
|
||||||
|
0,
|
||||||
build_message,
|
build_message,
|
||||||
);
|
);
|
||||||
Ok((message, spend))
|
Ok((message, spend))
|
||||||
@ -96,12 +98,19 @@ where
|
|||||||
let from_balance = rpc_client
|
let from_balance = rpc_client
|
||||||
.get_balance_with_commitment(from_pubkey, commitment)?
|
.get_balance_with_commitment(from_pubkey, commitment)?
|
||||||
.value;
|
.value;
|
||||||
|
let from_rent_exempt_minimum = if amount == SpendAmount::RentExempt {
|
||||||
|
let data = rpc_client.get_account_data(from_pubkey)?;
|
||||||
|
rpc_client.get_minimum_balance_for_rent_exemption(data.len())?
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
let (message, SpendAndFee { spend, fee }) = resolve_spend_message(
|
let (message, SpendAndFee { spend, fee }) = resolve_spend_message(
|
||||||
amount,
|
amount,
|
||||||
fee_calculator,
|
fee_calculator,
|
||||||
from_balance,
|
from_balance,
|
||||||
from_pubkey,
|
from_pubkey,
|
||||||
fee_pubkey,
|
fee_pubkey,
|
||||||
|
from_rent_exempt_minimum,
|
||||||
build_message,
|
build_message,
|
||||||
);
|
);
|
||||||
if from_pubkey == fee_pubkey {
|
if from_pubkey == fee_pubkey {
|
||||||
@ -137,6 +146,7 @@ fn resolve_spend_message<F>(
|
|||||||
from_balance: u64,
|
from_balance: u64,
|
||||||
from_pubkey: &Pubkey,
|
from_pubkey: &Pubkey,
|
||||||
fee_pubkey: &Pubkey,
|
fee_pubkey: &Pubkey,
|
||||||
|
from_rent_exempt_minimum: u64,
|
||||||
build_message: F,
|
build_message: F,
|
||||||
) -> (Message, SpendAndFee)
|
) -> (Message, SpendAndFee)
|
||||||
where
|
where
|
||||||
@ -170,5 +180,22 @@ where
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
SpendAmount::RentExempt => {
|
||||||
|
let dummy_message = build_message(0);
|
||||||
|
let fee = calculate_fee(fee_calculator, &[&dummy_message]);
|
||||||
|
let mut lamports = if from_pubkey == fee_pubkey {
|
||||||
|
from_balance.saturating_sub(fee)
|
||||||
|
} else {
|
||||||
|
from_balance
|
||||||
|
};
|
||||||
|
lamports = lamports.saturating_sub(from_rent_exempt_minimum);
|
||||||
|
(
|
||||||
|
build_message(lamports),
|
||||||
|
SpendAndFee {
|
||||||
|
spend: lamports,
|
||||||
|
fee,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ impl VoteSubCommands for App<'_, '_> {
|
|||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.required(true)
|
.required(true)
|
||||||
.validator(is_amount_or_all)
|
.validator(is_amount_or_all)
|
||||||
.help("The amount to withdraw, in SOL; accepts keyword ALL"),
|
.help("The amount to withdraw, in SOL; accepts keyword ALL, which for this command means account balance minus rent-exempt minimum"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("authorized_withdrawer")
|
Arg::with_name("authorized_withdrawer")
|
||||||
@ -621,7 +621,13 @@ 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 withdraw_amount = SpendAmount::new_from_matches(matches, "amount");
|
let mut withdraw_amount = SpendAmount::new_from_matches(matches, "amount");
|
||||||
|
// As a safeguard for vote accounts for running validators, `ALL` withdraws only the amount in
|
||||||
|
// excess of the rent-exempt minimum. In order to close the account with this subcommand, a
|
||||||
|
// validator must specify the withdrawal amount precisely.
|
||||||
|
if withdraw_amount == SpendAmount::All {
|
||||||
|
withdraw_amount = SpendAmount::RentExempt;
|
||||||
|
}
|
||||||
|
|
||||||
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)?;
|
||||||
@ -1877,7 +1883,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: 0,
|
withdraw_authority: 0,
|
||||||
withdraw_amount: SpendAmount::All,
|
withdraw_amount: SpendAmount::RentExempt,
|
||||||
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),
|
||||||
|
Reference in New Issue
Block a user