Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stake-pool: add new version of DecreaseValidatorStake to use reserve, add compatibility with master #5322

Merged
merged 6 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions stake-pool/program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ thiserror = "1.0"
bincode = "1.3.1"

[dev-dependencies]
assert_matches = "1.5.0"
proptest = "1.2"
solana-program-test = "1.16.13"
solana-sdk = "1.16.13"
Expand Down
83 changes: 82 additions & 1 deletion stake-pool/program/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ pub enum StakePoolInstruction {
/// 7. `[]` Stake program id,
RemoveValidatorFromPool,

/// NOTE: This instruction has been deprecated since version 0.7.0. Please
/// use `DecreaseValidatorStakeWithReserve` instead.
///
/// (Staker only) Decrease active stake on a validator, eventually moving it to the reserve
///
/// Internally, this instruction splits a validator stake account into its
Expand Down Expand Up @@ -477,6 +480,40 @@ pub enum StakePoolInstruction {
ephemeral_stake_seed: u64,
},

/// (Staker only) Decrease active stake on a validator, eventually moving it to the reserve
///
/// Internally, this instruction:
/// * withdraws enough lamports to make the transient account rent-exempt
/// * splits from a validator stake account into a transient stake account
/// * deactivates the transient stake account
///
/// In order to rebalance the pool without taking custody, the staker needs
/// a way of reducing the stake on a stake account. This instruction splits
/// some amount of stake, up to the total activated stake, from the canonical
/// validator stake account, into its "transient" stake account.
///
/// The instruction only succeeds if the transient stake account does not
/// exist. The amount of lamports to move must be at least rent-exemption plus
/// `max(crate::MINIMUM_ACTIVE_STAKE, solana_program::stake::tools::get_minimum_delegation())`.
///
/// 0. `[]` Stake pool
/// 1. `[s]` Stake pool staker
/// 2. `[]` Stake pool withdraw authority
/// 3. `[w]` Validator list
/// 4. `[w]` Reserve stake account, to fund rent exempt reserve
/// 5. `[w]` Canonical stake account to split from
/// 6. `[w]` Transient stake account to receive split
/// 7. `[]` Clock sysvar
/// 8. '[]' Stake history sysvar
/// 9. `[]` System program
/// 10. `[]` Stake program
DecreaseValidatorStakeWithReserve {
/// amount of lamports to split into the transient stake account
lamports: u64,
/// seed used to create transient stake account
transient_stake_seed: u64,
},

/// (Staker only) Redelegate active stake on a validator, eventually moving it to another
///
/// Internally, this instruction splits a validator stake account into its
Expand Down Expand Up @@ -755,6 +792,10 @@ pub fn remove_validator_from_pool(

/// Creates `DecreaseValidatorStake` instruction (rebalance from validator account to
/// transient account)
#[deprecated(
since = "0.7.0",
note = "please use `decrease_validator_stake_with_reserve`"
)]
pub fn decrease_validator_stake(
program_id: &Pubkey,
stake_pool: &Pubkey,
Expand Down Expand Up @@ -833,6 +874,45 @@ pub fn decrease_additional_validator_stake(
}
}

/// Creates `DecreaseValidatorStakeWithReserve` instruction (rebalance from
/// validator account to transient account)
pub fn decrease_validator_stake_with_reserve(
program_id: &Pubkey,
stake_pool: &Pubkey,
staker: &Pubkey,
stake_pool_withdraw_authority: &Pubkey,
validator_list: &Pubkey,
reserve_stake: &Pubkey,
validator_stake: &Pubkey,
transient_stake: &Pubkey,
lamports: u64,
transient_stake_seed: u64,
) -> Instruction {
let accounts = vec![
AccountMeta::new_readonly(*stake_pool, false),
AccountMeta::new_readonly(*staker, true),
AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
AccountMeta::new(*validator_list, false),
AccountMeta::new(*reserve_stake, false),
AccountMeta::new(*validator_stake, false),
AccountMeta::new(*transient_stake, false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
AccountMeta::new_readonly(system_program::id(), false),
AccountMeta::new_readonly(stake::program::id(), false),
];
Instruction {
program_id: *program_id,
accounts,
data: StakePoolInstruction::DecreaseValidatorStakeWithReserve {
lamports,
transient_stake_seed,
}
.try_to_vec()
.unwrap(),
}
}

/// Creates `IncreaseValidatorStake` instruction (rebalance from reserve account to
/// transient account)
pub fn increase_validator_stake(
Expand Down Expand Up @@ -1174,12 +1254,13 @@ pub fn decrease_validator_stake_with_vote(
stake_pool_address,
transient_stake_seed,
);
decrease_validator_stake(
decrease_validator_stake_with_reserve(
program_id,
stake_pool_address,
&stake_pool.staker,
&pool_withdraw_authority,
&stake_pool.validator_list,
&stake_pool.reserve_stake,
&validator_stake_address,
&transient_stake_address,
lamports,
Expand Down
70 changes: 53 additions & 17 deletions stake-pool/program/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1258,17 +1258,14 @@ impl Processor {
let transient_stake_account_info = next_account_info(account_info_iter)?;
let clock_info = next_account_info(account_info_iter)?;
let clock = &Clock::from_account_info(clock_info)?;
let rent = if maybe_ephemeral_stake_seed.is_some() {
// instruction with ephemeral account doesn't take the rent account
Rent::get()?
} else {
// legacy instruction takes the rent account
let rent_info = next_account_info(account_info_iter)?;
Rent::from_account_info(rent_info)?
};
let maybe_stake_history_info = maybe_ephemeral_stake_seed
.map(|_| next_account_info(account_info_iter))
.transpose()?;
let (rent, maybe_stake_history_info) =
if maybe_ephemeral_stake_seed.is_some() || fund_rent_exempt_reserve {
(Rent::get()?, Some(next_account_info(account_info_iter)?))
} else {
// legacy instruction takes the rent account
let rent_info = next_account_info(account_info_iter)?;
(Rent::from_account_info(rent_info)?, None)
};
let system_program_info = next_account_info(account_info_iter)?;
let stake_program_info = next_account_info(account_info_iter)?;

Expand Down Expand Up @@ -1487,6 +1484,35 @@ impl Processor {
stake_space,
)?;

// if needed, withdraw rent-exempt reserve for transient account
if let Some(reserve_stake_info) = maybe_reserve_stake_info {
let required_lamports =
stake_rent.saturating_sub(transient_stake_account_info.lamports());
// in the case of doing a full split from an ephemeral account,
// the rent-exempt reserve moves over, so no need to fund it from
// the pool reserve
if source_stake_account_info.lamports() != split_lamports {
let stake_history_info =
maybe_stake_history_info.ok_or(StakePoolError::MissingRequiredSysvar)?;
if required_lamports >= reserve_stake_info.lamports() {
return Err(StakePoolError::ReserveDepleted.into());
}
if required_lamports > 0 {
Self::stake_withdraw(
stake_pool_info.key,
reserve_stake_info.clone(),
withdraw_authority_info.clone(),
AUTHORITY_WITHDRAW,
stake_pool.stake_withdraw_bump_seed,
transient_stake_account_info.clone(),
clock_info.clone(),
stake_history_info.clone(),
required_lamports,
)?;
}
}
}

// split into transient stake account
Self::stake_split(
stake_pool_info.key,
Expand Down Expand Up @@ -1517,13 +1543,8 @@ impl Processor {
.checked_sub(lamports)
.ok_or(StakePoolError::CalculationFailure)?
.into();
// `split_lamports` may be greater than `lamports` if the reserve stake
// funded the rent-exempt reserve
validator_stake_info.transient_stake_lamports =
u64::from(validator_stake_info.transient_stake_lamports)
.checked_add(split_lamports)
.ok_or(StakePoolError::CalculationFailure)?
.into();
transient_stake_account_info.lamports().into();
validator_stake_info.transient_seed_suffix = transient_stake_seed.into();

Ok(())
Expand Down Expand Up @@ -3842,6 +3863,7 @@ impl Processor {
transient_stake_seed,
} => {
msg!("Instruction: DecreaseValidatorStake");
msg!("NOTE: This instruction is deprecated, please use `DecreaseValidatorStakeWithReserve`");
Self::process_decrease_validator_stake(
program_id,
accounts,
Expand All @@ -3851,6 +3873,20 @@ impl Processor {
false,
)
}
StakePoolInstruction::DecreaseValidatorStakeWithReserve {
lamports,
transient_stake_seed,
} => {
msg!("Instruction: DecreaseValidatorStakeWithReserve");
Self::process_decrease_validator_stake(
program_id,
accounts,
lamports,
transient_stake_seed,
None,
true,
)
}
StakePoolInstruction::DecreaseAdditionalValidatorStake {
lamports,
transient_stake_seed,
Expand Down
Loading
Loading