Skip to content

Commit

Permalink
stake-pool-v0: Add --min-reserve-stake-balance to allow for draw down…
Browse files Browse the repository at this point in the history
… of stake
  • Loading branch information
mvines committed Apr 29, 2021
1 parent 67db42a commit c3d4c6d
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 14 deletions.
12 changes: 12 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,15 @@ fn get_config() -> BoxResult<(Config, RpcClient, Box<dyn GenericStakePool>)> {
.validator(is_pubkey_or_keypair)
.help("The reserve stake account used to fund the stake pool")
)
.arg(
Arg::with_name("min_reserve_stake_balance")
.long("min-reserve-stake-balance")
.value_name("SOL")
.takes_value(true)
.default_value("1")
.validator(is_amount)
.help("The minimum balance to keep in the reserve stake account")
)
.arg(
Arg::with_name("baseline_stake_amount")
.long("baseline-stake-amount")
Expand Down Expand Up @@ -631,13 +640,16 @@ fn get_config() -> BoxResult<(Config, RpcClient, Box<dyn GenericStakePool>)> {
}
("stake-pool-v0", Some(matches)) => {
let reserve_stake_address = pubkey_of(&matches, "reserve_stake_address").unwrap();
let min_reserve_stake_balance =
sol_to_lamports(value_t_or_exit!(matches, "min_reserve_stake_balance", f64));
let baseline_stake_amount =
sol_to_lamports(value_t_or_exit!(matches, "baseline_stake_amount", f64));
let validator_list = validator_list_of(matches, config.cluster.as_str());
Box::new(stake_pool_v0::new(
&rpc_client,
baseline_stake_amount,
reserve_stake_address,
min_reserve_stake_balance,
validator_list,
)?)
}
Expand Down
54 changes: 40 additions & 14 deletions src/stake_pool_v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,25 @@ use {
};

// Minimum amount of lamports in a stake pool account
const MIN_STAKE_ACCOUNT_BALANCE: u64 = LAMPORTS_PER_SOL;
pub const MIN_STAKE_ACCOUNT_BALANCE: u64 = LAMPORTS_PER_SOL;

// Don't bother adjusting stake if less than this amount of lamports will be affected
// (must be >= MIN_STAKE_ACCOUNT_BALANCE)
const MIN_STAKE_CHANGE_AMOUNT: u64 = MIN_STAKE_ACCOUNT_BALANCE;

#[derive(Debug, Default)]
#[derive(Debug)]
pub struct StakePool {
baseline_stake_amount: u64,
reserve_stake_address: Pubkey,
min_reserve_stake_balance: u64,
validator_list: HashSet<Pubkey>,
}

pub fn new(
_rpc_client: &RpcClient,
baseline_stake_amount: u64,
reserve_stake_address: Pubkey,
min_reserve_stake_balance: u64,
validator_list: HashSet<Pubkey>,
) -> Result<StakePool, Box<dyn error::Error>> {
if baseline_stake_amount < MIN_STAKE_CHANGE_AMOUNT {
Expand All @@ -45,9 +47,19 @@ pub fn new(
)
.into());
}

if min_reserve_stake_balance < MIN_STAKE_ACCOUNT_BALANCE {
return Err(format!(
"minimum reserve stake balance is too small: {}",
Sol(min_reserve_stake_balance)
)
.into());
}

Ok(StakePool {
baseline_stake_amount,
reserve_stake_address,
min_reserve_stake_balance,
validator_list,
})
}
Expand Down Expand Up @@ -148,11 +160,12 @@ impl GenericStakePool for StakePool {
authorized_staker,
desired_validator_stake,
self.reserve_stake_address,
self.min_reserve_stake_balance,
&mut busy_validators,
)?;

// `total_stake_amount` excludes the `MIN_STAKE_ACCOUNT_BALANCE` that always remains in the reserve account
let total_stake_amount = all_stake_total_amount - MIN_STAKE_ACCOUNT_BALANCE;
// `total_stake_amount` excludes the amount that always remains in the reserve account
let total_stake_amount = all_stake_total_amount - self.min_reserve_stake_balance;

info!("Total stake pool balance: {}", Sol(total_stake_amount));

Expand Down Expand Up @@ -200,34 +213,36 @@ impl GenericStakePool for StakePool {
.filter(|vs| !busy_validators.contains(&vs.identity))
.cloned(),
self.reserve_stake_address,
self.min_reserve_stake_balance,
self.baseline_stake_amount,
bonus_stake_amount,
)?);
Ok(notifications)
}
}

// Get the balance of a stake account excluding `MIN_STAKE_ACCOUNT_BALANCE`
// Get the balance of a stake account excluding the reserve
fn get_available_stake_balance(
rpc_client: &RpcClient,
stake_address: Pubkey,
reserve_stake_balance: u64,
) -> Result<u64, Box<dyn error::Error>> {
let balance = rpc_client.get_balance(&stake_address).map_err(|err| {
format!(
"Unable to get stake account balance: {}: {}",
stake_address, err
)
})?;
if balance < MIN_STAKE_ACCOUNT_BALANCE {
if balance < reserve_stake_balance {
Err(format!(
"Stake account {} balance too low, {}. Minimum is {}",
stake_address,
Sol(balance),
Sol(MIN_STAKE_ACCOUNT_BALANCE)
Sol(reserve_stake_balance)
)
.into())
} else {
Ok(balance - MIN_STAKE_ACCOUNT_BALANCE)
Ok(balance.saturating_sub(reserve_stake_balance))
}
}

Expand Down Expand Up @@ -467,10 +482,12 @@ fn create_validator_stake_accounts(
authorized_staker: &Keypair,
desired_validator_stake: &[ValidatorStake],
reserve_stake_address: Pubkey,
min_reserve_stake_balance: u64,
busy_validators: &mut HashSet<Pubkey>,
) -> Result<(), Box<dyn error::Error>> {
let mut reserve_stake_balance = get_available_stake_balance(rpc_client, reserve_stake_address)
.map_err(|err| {
let mut reserve_stake_balance =
get_available_stake_balance(rpc_client, reserve_stake_address, min_reserve_stake_balance)
.map_err(|err| {
format!(
"Unable to get reserve stake account balance: {}: {}",
reserve_stake_address, err
Expand Down Expand Up @@ -567,14 +584,16 @@ fn distribute_validator_stake<V>(
authorized_staker: &Keypair,
desired_validator_stake: V,
reserve_stake_address: Pubkey,
min_reserve_stake_balance: u64,
baseline_stake_amount: u64,
bonus_stake_amount: u64,
) -> Result<Vec<String>, Box<dyn error::Error>>
where
V: IntoIterator<Item = ValidatorStake>,
{
let mut reserve_stake_balance = get_available_stake_balance(rpc_client, reserve_stake_address)
.map_err(|err| {
let mut reserve_stake_balance =
get_available_stake_balance(rpc_client, reserve_stake_address, min_reserve_stake_balance)
.map_err(|err| {
format!(
"Unable to get reserve stake account balance: {}: {}",
reserve_stake_address, err
Expand Down Expand Up @@ -832,9 +851,10 @@ mod test {
let validators = create_validators(&rpc_client, &authorized_staker, 3).unwrap();

let baseline_stake_amount = sol_to_lamports(10.);
let min_reserve_stake_balance = MIN_STAKE_ACCOUNT_BALANCE;
let total_stake_amount =
(baseline_stake_amount + sol_to_lamports(100.)) * validators.len() as u64;
let total_stake_amount_plus_min = total_stake_amount + MIN_STAKE_ACCOUNT_BALANCE;
let total_stake_amount_plus_min = total_stake_amount + min_reserve_stake_balance;

let reserve_stake_address =
create_stake_account(&rpc_client, &authorized_staker, total_stake_amount_plus_min)
Expand All @@ -848,7 +868,12 @@ mod test {
);
{
assert_eq!(
get_available_stake_balance(&rpc_client, reserve_stake_address).unwrap(),
get_available_stake_balance(
&rpc_client,
reserve_stake_address,
min_reserve_stake_balance
)
.unwrap(),
total_stake_amount
);

Expand All @@ -865,6 +890,7 @@ mod test {
&rpc_client,
baseline_stake_amount,
reserve_stake_address,
min_reserve_stake_balance,
validators.iter().map(|vap| vap.identity).collect(),
)
.unwrap();
Expand Down

0 comments on commit c3d4c6d

Please sign in to comment.