Skip to content

Commit

Permalink
stake-pool-cli: don't send UpdateValidatorListBalance transactions …
Browse files Browse the repository at this point in the history
…for subslices of validator list that have already been updated (#6059)

* remove unnecessary vote acc slice

* nightly fmt

* fix clippy

* update stale validator_list_balance only if not force

* merge

* fmt

* merge conflict

* restore stale ixs, add fresh flag to update

* fmt

* fresh -> stale_only, update --force help
  • Loading branch information
billythedummy committed Jan 24, 2024
1 parent 8b22d75 commit 0d6832e
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 18 deletions.
52 changes: 35 additions & 17 deletions stake-pool/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ fn command_vsa_add(
}

if !config.no_update {
command_update(config, stake_pool_address, false, false)?;
command_update(config, stake_pool_address, false, false, false)?;
}

// iterate until a free account is found
Expand Down Expand Up @@ -488,7 +488,7 @@ fn command_vsa_remove(
vote_account: &Pubkey,
) -> CommandResult {
if !config.no_update {
command_update(config, stake_pool_address, false, false)?;
command_update(config, stake_pool_address, false, false, false)?;
}

let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?;
Expand Down Expand Up @@ -535,7 +535,7 @@ fn command_increase_validator_stake(
) -> CommandResult {
let lamports = native_token::sol_to_lamports(amount);
if !config.no_update {
command_update(config, stake_pool_address, false, false)?;
command_update(config, stake_pool_address, false, false, false)?;
}

let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?;
Expand Down Expand Up @@ -574,7 +574,7 @@ fn command_decrease_validator_stake(
) -> CommandResult {
let lamports = native_token::sol_to_lamports(amount);
if !config.no_update {
command_update(config, stake_pool_address, false, false)?;
command_update(config, stake_pool_address, false, false, false)?;
}

let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?;
Expand Down Expand Up @@ -671,7 +671,7 @@ fn command_deposit_stake(
referrer_token_account: &Option<Pubkey>,
) -> CommandResult {
if !config.no_update {
command_update(config, stake_pool_address, false, false)?;
command_update(config, stake_pool_address, false, false, false)?;
}

let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?;
Expand Down Expand Up @@ -802,7 +802,7 @@ fn command_deposit_all_stake(
referrer_token_account: &Option<Pubkey>,
) -> CommandResult {
if !config.no_update {
command_update(config, stake_pool_address, false, false)?;
command_update(config, stake_pool_address, false, false, false)?;
}

let stake_addresses = get_all_stake(&config.rpc_client, stake_authority)?;
Expand Down Expand Up @@ -945,7 +945,7 @@ fn command_deposit_sol(
amount: f64,
) -> CommandResult {
if !config.no_update {
command_update(config, stake_pool_address, false, false)?;
command_update(config, stake_pool_address, false, false, false)?;
}

let amount = native_token::sol_to_lamports(amount);
Expand Down Expand Up @@ -1139,6 +1139,7 @@ fn command_update(
stake_pool_address: &Pubkey,
force: bool,
no_merge: bool,
stale_only: bool,
) -> CommandResult {
if config.no_update {
println!("Update requested, but --no-update flag specified, so doing nothing");
Expand All @@ -1158,14 +1159,24 @@ fn command_update(

let validator_list = get_validator_list(&config.rpc_client, &stake_pool.validator_list)?;

let (mut update_list_instructions, final_instructions) =
let (mut update_list_instructions, final_instructions) = if stale_only {
spl_stake_pool::instruction::update_stale_stake_pool(
&spl_stake_pool::id(),
&stake_pool,
&validator_list,
stake_pool_address,
no_merge,
epoch_info.epoch,
)
} else {
spl_stake_pool::instruction::update_stake_pool(
&spl_stake_pool::id(),
&stake_pool,
&validator_list,
stake_pool_address,
no_merge,
);
)
};

let update_list_instructions_len = update_list_instructions.len();
if update_list_instructions_len > 0 {
Expand Down Expand Up @@ -1360,7 +1371,7 @@ fn command_withdraw_stake(
pool_amount: f64,
) -> CommandResult {
if !config.no_update {
command_update(config, stake_pool_address, false, false)?;
command_update(config, stake_pool_address, false, false, false)?;
}

let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?;
Expand Down Expand Up @@ -1631,7 +1642,7 @@ fn command_withdraw_sol(
pool_amount: f64,
) -> CommandResult {
if !config.no_update {
command_update(config, stake_pool_address, false, false)?;
command_update(config, stake_pool_address, false, false, false)?;
}

let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?;
Expand Down Expand Up @@ -1748,7 +1759,7 @@ fn command_set_manager(
new_fee_receiver: &Option<Pubkey>,
) -> CommandResult {
if !config.no_update {
command_update(config, stake_pool_address, false, false)?;
command_update(config, stake_pool_address, false, false, false)?;
}
let stake_pool = get_stake_pool(&config.rpc_client, stake_pool_address)?;

Expand Down Expand Up @@ -1800,7 +1811,7 @@ fn command_set_staker(
new_staker: &Pubkey,
) -> CommandResult {
if !config.no_update {
command_update(config, stake_pool_address, false, false)?;
command_update(config, stake_pool_address, false, false, false)?;
}
let mut signers = vec![config.fee_payer.as_ref(), config.manager.as_ref()];
unique_signers!(signers);
Expand All @@ -1825,7 +1836,7 @@ fn command_set_funding_authority(
funding_type: FundingType,
) -> CommandResult {
if !config.no_update {
command_update(config, stake_pool_address, false, false)?;
command_update(config, stake_pool_address, false, false, false)?;
}
let mut signers = vec![config.fee_payer.as_ref(), config.manager.as_ref()];
unique_signers!(signers);
Expand All @@ -1850,7 +1861,7 @@ fn command_set_fee(
new_fee: FeeType,
) -> CommandResult {
if !config.no_update {
command_update(config, stake_pool_address, false, false)?;
command_update(config, stake_pool_address, false, false, false)?;
}
let mut signers = vec![config.fee_payer.as_ref(), config.manager.as_ref()];
unique_signers!(signers);
Expand Down Expand Up @@ -2418,14 +2429,20 @@ fn main() {
Arg::with_name("force")
.long("force")
.takes_value(false)
.help("Update all balances, even if it has already been performed this epoch."),
.help("Update balances, even if it has already been performed this epoch."),
)
.arg(
Arg::with_name("no_merge")
.long("no-merge")
.takes_value(false)
.help("Do not automatically merge transient stakes. Useful if the stake pool is in an expected state, but the balances still need to be updated."),
)
.arg(
Arg::with_name("stale_only")
.long("stale-only")
.takes_value(false)
.help("If set, only updates validator list balances that have not been updated for this epoch. Otherwise, updates all validator balances on the validator list."),
)
)
.subcommand(SubCommand::with_name("withdraw-stake")
.about("Withdraw active stake from the stake pool in exchange for pool tokens")
Expand Down Expand Up @@ -2903,7 +2920,8 @@ fn main() {
let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap();
let no_merge = arg_matches.is_present("no_merge");
let force = arg_matches.is_present("force");
command_update(&config, &stake_pool_address, force, no_merge)
let stale_only = arg_matches.is_present("stale_only");
command_update(&config, &stake_pool_address, force, no_merge, stale_only)
}
("withdraw-stake", Some(arg_matches)) => {
let stake_pool_address = pubkey_of(arg_matches, "pool").unwrap();
Expand Down
104 changes: 103 additions & 1 deletion stake-pool/program/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ use {
instruction::{AccountMeta, Instruction},
program_error::ProgramError,
pubkey::Pubkey,
stake, system_program, sysvar,
stake,
stake_history::Epoch,
system_program, sysvar,
},
std::num::NonZeroU32,
};
Expand Down Expand Up @@ -1496,6 +1498,47 @@ pub fn update_validator_list_balance_chunk(
})
}

/// Creates `UpdateValidatorListBalance` instruction (update validator stake
/// account balances)
///
/// Returns `None` if all validators in the given chunk has already been updated
/// for this epoch, returns the required instruction otherwise.
pub fn update_stale_validator_list_balance_chunk(
program_id: &Pubkey,
stake_pool: &Pubkey,
stake_pool_withdraw_authority: &Pubkey,
validator_list_address: &Pubkey,
reserve_stake: &Pubkey,
validator_list: &ValidatorList,
len: usize,
start_index: usize,
no_merge: bool,
current_epoch: Epoch,
) -> Result<Option<Instruction>, ProgramError> {
let validator_list_subslice = validator_list
.validators
.get(start_index..start_index.saturating_add(len))
.ok_or(ProgramError::InvalidInstructionData)?;
if validator_list_subslice.iter().all(|info| {
let last_update_epoch: u64 = info.last_update_epoch.into();
last_update_epoch >= current_epoch
}) {
return Ok(None);
}
update_validator_list_balance_chunk(
program_id,
stake_pool,
stake_pool_withdraw_authority,
validator_list_address,
reserve_stake,
validator_list,
len,
start_index,
no_merge,
)
.map(Some)
}

/// Creates `UpdateStakePoolBalance` instruction (pool balance from the stake
/// account list balances)
pub fn update_stake_pool_balance(
Expand Down Expand Up @@ -1599,6 +1642,65 @@ pub fn update_stake_pool(
(update_list_instructions, final_instructions)
}

/// Creates the `UpdateValidatorListBalance` instructions only for validators on
/// `validator_list` that have not been updated for this epoch, and the
/// `UpdateStakePoolBalance` instruction for fully updating the stake pool.
///
/// Basically same as [`update_stake_pool`], but skips validators that are
/// already updated for this epoch
pub fn update_stale_stake_pool(
program_id: &Pubkey,
stake_pool: &StakePool,
validator_list: &ValidatorList,
stake_pool_address: &Pubkey,
no_merge: bool,
current_epoch: Epoch,
) -> (Vec<Instruction>, Vec<Instruction>) {
let (withdraw_authority, _) =
find_withdraw_authority_program_address(program_id, stake_pool_address);

let update_list_instructions = validator_list
.validators
.chunks(MAX_VALIDATORS_TO_UPDATE)
.enumerate()
.filter_map(|(i, chunk)| {
// unwrap-safety: chunk len and offset are derived
update_stale_validator_list_balance_chunk(
program_id,
stake_pool_address,
&withdraw_authority,
&stake_pool.validator_list,
&stake_pool.reserve_stake,
validator_list,
chunk.len(),
i.saturating_mul(MAX_VALIDATORS_TO_UPDATE),
no_merge,
current_epoch,
)
.unwrap()
})
.collect();

let final_instructions = vec![
update_stake_pool_balance(
program_id,
stake_pool_address,
&withdraw_authority,
&stake_pool.validator_list,
&stake_pool.reserve_stake,
&stake_pool.manager_fee_account,
&stake_pool.pool_mint,
&stake_pool.token_program_id,
),
cleanup_removed_validator_entries(
program_id,
stake_pool_address,
&stake_pool.validator_list,
),
];
(update_list_instructions, final_instructions)
}

fn deposit_stake_internal(
program_id: &Pubkey,
stake_pool: &Pubkey,
Expand Down

0 comments on commit 0d6832e

Please sign in to comment.