Code cleanup v2

This commit is contained in:
Michael Vines 2021-03-31 18:39:50 -07:00
parent 2cd7adbf87
commit b97849d206
4 changed files with 39 additions and 150 deletions

View File

@ -607,7 +607,7 @@ fn command_list(config: &Config, pool: &Pubkey) -> CommandResult {
for validator in validator_list.validators { for validator in validator_list.validators {
println!( println!(
"Vote Account: {}\tBalance: {}\tEpoch: {}", "Vote Account: {}\tBalance: {}\tEpoch: {}",
validator.validator_account, validator.balance, validator.last_update_epoch validator.vote_account, validator.balance, validator.last_update_epoch
); );
} }
} }
@ -654,7 +654,7 @@ fn command_update(config: &Config, pool: &Pubkey) -> CommandResult {
} else { } else {
let (stake_account, _) = find_stake_address_for_validator( let (stake_account, _) = find_stake_address_for_validator(
&spl_stake_pool::id(), &spl_stake_pool::id(),
&item.validator_account, &item.vote_account,
&pool, &pool,
); );
Some(stake_account) Some(stake_account)

View File

@ -66,14 +66,14 @@ impl Processor {
/// Checks if validator stake account is a proper program address /// Checks if validator stake account is a proper program address
pub fn is_validator_stake_address( pub fn is_validator_stake_address(
validator_account: &Pubkey, vote_account: &Pubkey,
program_id: &Pubkey, program_id: &Pubkey,
stake_pool_info: &AccountInfo, stake_pool_info: &AccountInfo,
stake_account_info: &AccountInfo, stake_account_info: &AccountInfo,
) -> bool { ) -> bool {
// Check stake account address validity // Check stake account address validity
let (stake_address, _) = let (stake_address, _) =
find_stake_address_for_validator(&program_id, &validator_account, &stake_pool_info.key); find_stake_address_for_validator(&program_id, &vote_account, &stake_pool_info.key);
stake_address == *stake_account_info.key stake_address == *stake_account_info.key
} }
@ -83,17 +83,17 @@ impl Processor {
stake_pool_info: &AccountInfo, stake_pool_info: &AccountInfo,
stake_account_info: &AccountInfo, stake_account_info: &AccountInfo,
) -> Result<Pubkey, ProgramError> { ) -> Result<Pubkey, ProgramError> {
let validator_account = Self::get_validator(stake_account_info)?; let vote_account = Self::get_validator(stake_account_info)?;
if !Self::is_validator_stake_address( if !Self::is_validator_stake_address(
&validator_account, &vote_account,
program_id, program_id,
stake_pool_info, stake_pool_info,
stake_account_info, stake_account_info,
) { ) {
return Err(StakePoolError::InvalidStakeAccountAddress.into()); return Err(StakePoolError::InvalidStakeAccountAddress.into());
} }
Ok(validator_account) Ok(vote_account)
} }
/// Issue a stake_split instruction. /// Issue a stake_split instruction.
@ -249,33 +249,27 @@ impl Processor {
let validator_list_info = next_account_info(account_info_iter)?; let validator_list_info = next_account_info(account_info_iter)?;
let pool_mint_info = next_account_info(account_info_iter)?; let pool_mint_info = next_account_info(account_info_iter)?;
let owner_fee_info = next_account_info(account_info_iter)?; let owner_fee_info = next_account_info(account_info_iter)?;
// Clock sysvar account
let clock_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 clock = &Clock::from_account_info(clock_info)?;
// Rent sysvar account
let rent_info = next_account_info(account_info_iter)?; let rent_info = next_account_info(account_info_iter)?;
let rent = &Rent::from_account_info(rent_info)?; let rent = &Rent::from_account_info(rent_info)?;
// Token program ID
let token_program_info = next_account_info(account_info_iter)?; let token_program_info = next_account_info(account_info_iter)?;
// Check if transaction was signed by owner
if !owner_info.is_signer { if !owner_info.is_signer {
return Err(StakePoolError::SignatureMissing.into()); return Err(StakePoolError::SignatureMissing.into());
} }
let mut stake_pool = StakePool::try_from_slice(&stake_pool_info.data.borrow())?; let mut stake_pool = StakePool::try_from_slice(&stake_pool_info.data.borrow())?;
// Stake pool account should not be already initialized
if !stake_pool.is_uninitialized() { if !stake_pool.is_uninitialized() {
return Err(StakePoolError::AlreadyInUse.into()); return Err(StakePoolError::AlreadyInUse.into());
} }
// Check if validator stake list storage is unitialized
let mut validator_list = let mut validator_list =
try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?; try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?;
if !validator_list.is_uninitialized() { if !validator_list.is_uninitialized() {
return Err(StakePoolError::AlreadyInUse.into()); return Err(StakePoolError::AlreadyInUse.into());
} }
// Check validator list size
let data_length = validator_list_info.data_len(); let data_length = validator_list_info.data_len();
let expected_max_validators = ValidatorList::calculate_max_validators(data_length); let expected_max_validators = ValidatorList::calculate_max_validators(data_length);
if expected_max_validators != max_validators as usize || max_validators == 0 { if expected_max_validators != max_validators as usize || max_validators == 0 {
@ -285,13 +279,11 @@ impl Processor {
validator_list.validators.clear(); validator_list.validators.clear();
validator_list.max_validators = max_validators; validator_list.max_validators = max_validators;
// Check if stake pool account is rent-exempt
if !rent.is_exempt(stake_pool_info.lamports(), stake_pool_info.data_len()) { if !rent.is_exempt(stake_pool_info.lamports(), stake_pool_info.data_len()) {
msg!("Stake pool not rent-exempt"); msg!("Stake pool not rent-exempt");
return Err(ProgramError::AccountNotRentExempt); return Err(ProgramError::AccountNotRentExempt);
} }
// Check if validator stake list account is rent-exempt
if !rent.is_exempt( if !rent.is_exempt(
validator_list_info.lamports(), validator_list_info.lamports(),
validator_list_info.data_len(), validator_list_info.data_len(),
@ -305,17 +297,14 @@ impl Processor {
return Err(StakePoolError::FeeTooHigh.into()); return Err(StakePoolError::FeeTooHigh.into());
} }
// Check if fee account's owner the same as token program id
if owner_fee_info.owner != token_program_info.key { if owner_fee_info.owner != token_program_info.key {
return Err(StakePoolError::InvalidFeeAccount.into()); return Err(StakePoolError::InvalidFeeAccount.into());
} }
// Check pool mint program ID
if pool_mint_info.owner != token_program_info.key { if pool_mint_info.owner != token_program_info.key {
return Err(ProgramError::IncorrectProgramId); return Err(ProgramError::IncorrectProgramId);
} }
// Check for owner fee account to have proper mint assigned
if *pool_mint_info.key if *pool_mint_info.key
!= spl_token::state::Account::unpack_from_slice(&owner_fee_info.data.borrow())?.mint != spl_token::state::Account::unpack_from_slice(&owner_fee_info.data.borrow())?.mint
{ {
@ -360,31 +349,19 @@ impl Processor {
accounts: &[AccountInfo], accounts: &[AccountInfo],
) -> ProgramResult { ) -> ProgramResult {
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
// Stake pool account
let stake_pool_info = next_account_info(account_info_iter)?; let stake_pool_info = next_account_info(account_info_iter)?;
// Owner account
let owner_info = next_account_info(account_info_iter)?; let owner_info = next_account_info(account_info_iter)?;
// Account creation funder account
let funder_info = next_account_info(account_info_iter)?; let funder_info = next_account_info(account_info_iter)?;
// Stake account to be created
let stake_account_info = next_account_info(account_info_iter)?; let stake_account_info = next_account_info(account_info_iter)?;
// Validator this stake account will vote for
let validator_info = next_account_info(account_info_iter)?; let validator_info = next_account_info(account_info_iter)?;
// Rent sysvar account
let rent_info = next_account_info(account_info_iter)?; let rent_info = next_account_info(account_info_iter)?;
let rent = &Rent::from_account_info(rent_info)?; let rent = &Rent::from_account_info(rent_info)?;
// Clock sysvar account
let clock_info = next_account_info(account_info_iter)?; let clock_info = next_account_info(account_info_iter)?;
// Stake history sysvar account
let stake_history_info = next_account_info(account_info_iter)?; let stake_history_info = next_account_info(account_info_iter)?;
// Stake config sysvar account
let stake_config_info = next_account_info(account_info_iter)?; let stake_config_info = next_account_info(account_info_iter)?;
// System program id
let system_program_info = next_account_info(account_info_iter)?; let system_program_info = next_account_info(account_info_iter)?;
// Staking program id
let stake_program_info = next_account_info(account_info_iter)?; let stake_program_info = next_account_info(account_info_iter)?;
// Get stake pool stake (and check if it is initialized)
if stake_pool_info.owner != program_id { if stake_pool_info.owner != program_id {
return Err(ProgramError::IncorrectProgramId); return Err(ProgramError::IncorrectProgramId);
} }
@ -394,7 +371,6 @@ impl Processor {
} }
stake_pool.check_owner(owner_info)?; stake_pool.check_owner(owner_info)?;
// Check program ids
if *system_program_info.key != solana_program::system_program::id() { if *system_program_info.key != solana_program::system_program::id() {
return Err(ProgramError::IncorrectProgramId); return Err(ProgramError::IncorrectProgramId);
} }
@ -402,7 +378,6 @@ impl Processor {
return Err(ProgramError::IncorrectProgramId); return Err(ProgramError::IncorrectProgramId);
} }
// Check stake account address validity
let (stake_address, bump_seed) = find_stake_address_for_validator( let (stake_address, bump_seed) = find_stake_address_for_validator(
&program_id, &program_id,
&validator_info.key, &validator_info.key,
@ -474,52 +449,35 @@ impl Processor {
accounts: &[AccountInfo], accounts: &[AccountInfo],
) -> ProgramResult { ) -> ProgramResult {
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
// Stake pool account
let stake_pool_info = next_account_info(account_info_iter)?; let stake_pool_info = next_account_info(account_info_iter)?;
// Pool owner account
let owner_info = next_account_info(account_info_iter)?; let owner_info = next_account_info(account_info_iter)?;
// Stake pool deposit authority
let deposit_info = next_account_info(account_info_iter)?; let deposit_info = next_account_info(account_info_iter)?;
// Stake pool withdraw authority
let withdraw_info = next_account_info(account_info_iter)?; let withdraw_info = next_account_info(account_info_iter)?;
// Account storing validator stake list
let validator_list_info = next_account_info(account_info_iter)?; let validator_list_info = next_account_info(account_info_iter)?;
// Stake account to add to the pool
let stake_account_info = next_account_info(account_info_iter)?; let stake_account_info = next_account_info(account_info_iter)?;
// User account to receive pool tokens
let dest_user_info = next_account_info(account_info_iter)?; let dest_user_info = next_account_info(account_info_iter)?;
// Pool token mint account
let pool_mint_info = next_account_info(account_info_iter)?; let pool_mint_info = next_account_info(account_info_iter)?;
// Clock sysvar account
let clock_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 clock = &Clock::from_account_info(clock_info)?;
// Stake history sysvar account
let stake_history_info = next_account_info(account_info_iter)?; let stake_history_info = next_account_info(account_info_iter)?;
let stake_history = &StakeHistory::from_account_info(stake_history_info)?; let stake_history = &StakeHistory::from_account_info(stake_history_info)?;
// Pool token program id
let token_program_info = next_account_info(account_info_iter)?; let token_program_info = next_account_info(account_info_iter)?;
// Staking program id
let stake_program_info = next_account_info(account_info_iter)?; let stake_program_info = next_account_info(account_info_iter)?;
// Check program ids
if *stake_program_info.key != stake_program::id() { if *stake_program_info.key != stake_program::id() {
return Err(ProgramError::IncorrectProgramId); return Err(ProgramError::IncorrectProgramId);
} }
// Get stake pool stake (and check if it is initialized)
let mut stake_pool = StakePool::try_from_slice(&stake_pool_info.data.borrow())?; let mut stake_pool = StakePool::try_from_slice(&stake_pool_info.data.borrow())?;
if !stake_pool.is_valid() { if !stake_pool.is_valid() {
return Err(StakePoolError::InvalidState.into()); return Err(StakePoolError::InvalidState.into());
} }
// Check authority accounts
stake_pool.check_authority_withdraw(withdraw_info.key, program_id, stake_pool_info.key)?; stake_pool.check_authority_withdraw(withdraw_info.key, program_id, stake_pool_info.key)?;
stake_pool.check_authority_deposit(deposit_info.key, program_id, stake_pool_info.key)?; stake_pool.check_authority_deposit(deposit_info.key, program_id, stake_pool_info.key)?;
// Check owner validity and signature
stake_pool.check_owner(owner_info)?; stake_pool.check_owner(owner_info)?;
// Check stake pool last update epoch
if stake_pool.last_update_epoch < clock.epoch { if stake_pool.last_update_epoch < clock.epoch {
return Err(StakePoolError::StakeListAndPoolOutOfDate.into()); return Err(StakePoolError::StakeListAndPoolOutOfDate.into());
} }
@ -531,12 +489,10 @@ impl Processor {
return Err(StakePoolError::WrongPoolMint.into()); return Err(StakePoolError::WrongPoolMint.into());
} }
// Check validator stake account list storage
if *validator_list_info.key != stake_pool.validator_list { if *validator_list_info.key != stake_pool.validator_list {
return Err(StakePoolError::InvalidValidatorStakeList.into()); return Err(StakePoolError::InvalidValidatorStakeList.into());
} }
// Read validator stake list account and check if it is valid
let mut validator_list = let mut validator_list =
try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?; try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?;
if !validator_list.is_valid() { if !validator_list.is_valid() {
@ -546,10 +502,10 @@ impl Processor {
return Err(ProgramError::AccountDataTooSmall); return Err(ProgramError::AccountDataTooSmall);
} }
let validator_account = let vote_account =
Self::get_validator_checked(program_id, stake_pool_info, stake_account_info)?; Self::get_validator_checked(program_id, stake_pool_info, stake_account_info)?;
if validator_list.contains(&validator_account) { if validator_list.contains(&vote_account) {
return Err(StakePoolError::ValidatorAlreadyAdded.into()); return Err(StakePoolError::ValidatorAlreadyAdded.into());
} }
@ -592,7 +548,7 @@ impl Processor {
// Add validator to the list and save // Add validator to the list and save
validator_list.validators.push(ValidatorStakeInfo { validator_list.validators.push(ValidatorStakeInfo {
validator_account, vote_account,
balance: stake_lamports, balance: stake_lamports,
last_update_epoch: clock.epoch, last_update_epoch: clock.epoch,
}); });
@ -613,48 +569,31 @@ impl Processor {
accounts: &[AccountInfo], accounts: &[AccountInfo],
) -> ProgramResult { ) -> ProgramResult {
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
// Stake pool account
let stake_pool_info = next_account_info(account_info_iter)?; let stake_pool_info = next_account_info(account_info_iter)?;
// Pool owner account
let owner_info = next_account_info(account_info_iter)?; let owner_info = next_account_info(account_info_iter)?;
// Stake pool withdraw authority
let withdraw_info = next_account_info(account_info_iter)?; let withdraw_info = next_account_info(account_info_iter)?;
// New stake authority
let new_stake_authority_info = next_account_info(account_info_iter)?; let new_stake_authority_info = next_account_info(account_info_iter)?;
// Account storing validator stake list
let validator_list_info = next_account_info(account_info_iter)?; let validator_list_info = next_account_info(account_info_iter)?;
// Stake account to remove from the pool
let stake_account_info = next_account_info(account_info_iter)?; let stake_account_info = next_account_info(account_info_iter)?;
// User account with pool tokens to burn from
let burn_from_info = next_account_info(account_info_iter)?; let burn_from_info = next_account_info(account_info_iter)?;
// Pool token mint account
let pool_mint_info = next_account_info(account_info_iter)?; let pool_mint_info = next_account_info(account_info_iter)?;
// Clock sysvar account
let clock_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 clock = &Clock::from_account_info(clock_info)?;
// Pool token program id
let token_program_info = next_account_info(account_info_iter)?; let token_program_info = next_account_info(account_info_iter)?;
// Staking program id
let stake_program_info = next_account_info(account_info_iter)?; let stake_program_info = next_account_info(account_info_iter)?;
// Check program ids
if *stake_program_info.key != stake_program::id() { if *stake_program_info.key != stake_program::id() {
return Err(ProgramError::IncorrectProgramId); return Err(ProgramError::IncorrectProgramId);
} }
// Get stake pool stake (and check if it is initialized)
let mut stake_pool = StakePool::try_from_slice(&stake_pool_info.data.borrow())?; let mut stake_pool = StakePool::try_from_slice(&stake_pool_info.data.borrow())?;
if !stake_pool.is_valid() { if !stake_pool.is_valid() {
return Err(StakePoolError::InvalidState.into()); return Err(StakePoolError::InvalidState.into());
} }
// Check authority account
stake_pool.check_authority_withdraw(withdraw_info.key, program_id, stake_pool_info.key)?; stake_pool.check_authority_withdraw(withdraw_info.key, program_id, stake_pool_info.key)?;
// Check owner validity and signature
stake_pool.check_owner(owner_info)?; stake_pool.check_owner(owner_info)?;
// Check stake pool last update epoch
if stake_pool.last_update_epoch < clock.epoch { if stake_pool.last_update_epoch < clock.epoch {
return Err(StakePoolError::StakeListAndPoolOutOfDate.into()); return Err(StakePoolError::StakeListAndPoolOutOfDate.into());
} }
@ -666,26 +605,23 @@ impl Processor {
return Err(StakePoolError::WrongPoolMint.into()); return Err(StakePoolError::WrongPoolMint.into());
} }
// Check validator stake account list storage
if *validator_list_info.key != stake_pool.validator_list { if *validator_list_info.key != stake_pool.validator_list {
return Err(StakePoolError::InvalidValidatorStakeList.into()); return Err(StakePoolError::InvalidValidatorStakeList.into());
} }
// Read validator stake list account and check if it is valid
let mut validator_list = let mut validator_list =
try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?; try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?;
if !validator_list.is_valid() { if !validator_list.is_valid() {
return Err(StakePoolError::InvalidState.into()); return Err(StakePoolError::InvalidState.into());
} }
let validator_account = let vote_account =
Self::get_validator_checked(program_id, stake_pool_info, stake_account_info)?; Self::get_validator_checked(program_id, stake_pool_info, stake_account_info)?;
if !validator_list.contains(&validator_account) { if !validator_list.contains(&vote_account) {
return Err(StakePoolError::ValidatorNotFound.into()); return Err(StakePoolError::ValidatorNotFound.into());
} }
// Update Withdrawer and Staker authority to the provided authority
for authority in &[ for authority in &[
stake_program::StakeAuthorize::Withdrawer, stake_program::StakeAuthorize::Withdrawer,
stake_program::StakeAuthorize::Staker, stake_program::StakeAuthorize::Staker,
@ -722,7 +658,7 @@ impl Processor {
// Remove validator from the list and save // Remove validator from the list and save
validator_list validator_list
.validators .validators
.retain(|item| item.validator_account != validator_account); .retain(|item| item.vote_account != vote_account);
validator_list.serialize(&mut *validator_list_info.data.borrow_mut())?; validator_list.serialize(&mut *validator_list_info.data.borrow_mut())?;
// Save amounts to the stake pool state // Save amounts to the stake pool state
@ -740,22 +676,18 @@ impl Processor {
accounts: &[AccountInfo], accounts: &[AccountInfo],
) -> ProgramResult { ) -> ProgramResult {
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
// Account storing validator stake list
let validator_list_info = next_account_info(account_info_iter)?; let validator_list_info = next_account_info(account_info_iter)?;
// Clock sysvar account
let clock_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 clock = &Clock::from_account_info(clock_info)?;
// Validator stake accounts
let validator_stake_accounts = account_info_iter.as_slice(); let validator_stake_accounts = account_info_iter.as_slice();
// Read validator stake list account and check if it is valid
let mut validator_list = let mut validator_list =
try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?; try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?;
if !validator_list.is_valid() { if !validator_list.is_valid() {
return Err(StakePoolError::InvalidState.into()); return Err(StakePoolError::InvalidState.into());
} }
let validator_accounts: Vec<Option<Pubkey>> = validator_stake_accounts let vote_accounts: Vec<Option<Pubkey>> = validator_stake_accounts
.iter() .iter()
.map(|stake| Self::get_validator(stake).ok()) .map(|stake| Self::get_validator(stake).ok())
.collect(); .collect();
@ -766,12 +698,11 @@ impl Processor {
if validator_stake_record.last_update_epoch >= clock.epoch { if validator_stake_record.last_update_epoch >= clock.epoch {
continue; continue;
} }
for (validator_stake_account, validator_account) in validator_stake_accounts for (validator_stake_account, vote_account) in
.iter() validator_stake_accounts.iter().zip(vote_accounts.iter())
.zip(validator_accounts.iter())
{ {
if validator_stake_record.validator_account if validator_stake_record.vote_account
!= validator_account.ok_or(StakePoolError::WrongStakeState)? != vote_account.ok_or(StakePoolError::WrongStakeState)?
{ {
continue; continue;
} }
@ -794,26 +725,20 @@ impl Processor {
accounts: &[AccountInfo], accounts: &[AccountInfo],
) -> ProgramResult { ) -> ProgramResult {
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
// Stake pool account
let stake_pool_info = next_account_info(account_info_iter)?; let stake_pool_info = next_account_info(account_info_iter)?;
// Account storing validator stake list
let validator_list_info = next_account_info(account_info_iter)?; let validator_list_info = next_account_info(account_info_iter)?;
// Clock sysvar account
let clock_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 clock = &Clock::from_account_info(clock_info)?;
// Get stake pool stake (and check if it is initialized)
let mut stake_pool = StakePool::try_from_slice(&stake_pool_info.data.borrow())?; let mut stake_pool = StakePool::try_from_slice(&stake_pool_info.data.borrow())?;
if !stake_pool.is_valid() { if !stake_pool.is_valid() {
return Err(StakePoolError::InvalidState.into()); return Err(StakePoolError::InvalidState.into());
} }
// Check validator stake account list storage
if *validator_list_info.key != stake_pool.validator_list { if *validator_list_info.key != stake_pool.validator_list {
return Err(StakePoolError::InvalidValidatorStakeList.into()); return Err(StakePoolError::InvalidValidatorStakeList.into());
} }
// Read validator stake list account and check if it is valid
let validator_list = let validator_list =
try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?; try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?;
if !validator_list.is_valid() { if !validator_list.is_valid() {
@ -867,36 +792,22 @@ impl Processor {
/// Processes [Deposit](enum.Instruction.html). /// Processes [Deposit](enum.Instruction.html).
pub fn process_deposit(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { pub fn process_deposit(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
// Stake pool
let stake_pool_info = next_account_info(account_info_iter)?; let stake_pool_info = next_account_info(account_info_iter)?;
// Account storing validator stake list
let validator_list_info = next_account_info(account_info_iter)?; let validator_list_info = next_account_info(account_info_iter)?;
// Stake pool deposit authority
let deposit_info = next_account_info(account_info_iter)?; let deposit_info = next_account_info(account_info_iter)?;
// Stake pool withdraw authority
let withdraw_info = next_account_info(account_info_iter)?; let withdraw_info = next_account_info(account_info_iter)?;
// Stake account to join the pool (withdraw should be set to stake pool deposit)
let stake_info = next_account_info(account_info_iter)?; let stake_info = next_account_info(account_info_iter)?;
// Validator stake account to merge with
let validator_stake_account_info = next_account_info(account_info_iter)?; let validator_stake_account_info = next_account_info(account_info_iter)?;
// User account to receive pool tokens
let dest_user_info = next_account_info(account_info_iter)?; let dest_user_info = next_account_info(account_info_iter)?;
// Account to receive pool fee tokens
let owner_fee_info = next_account_info(account_info_iter)?; let owner_fee_info = next_account_info(account_info_iter)?;
// Pool token mint account
let pool_mint_info = next_account_info(account_info_iter)?; let pool_mint_info = next_account_info(account_info_iter)?;
// Clock sysvar account
let clock_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 clock = &Clock::from_account_info(clock_info)?;
// Stake history sysvar account
let stake_history_info = next_account_info(account_info_iter)?; let stake_history_info = next_account_info(account_info_iter)?;
let stake_history = &StakeHistory::from_account_info(stake_history_info)?; let stake_history = &StakeHistory::from_account_info(stake_history_info)?;
// Pool token program id
let token_program_info = next_account_info(account_info_iter)?; let token_program_info = next_account_info(account_info_iter)?;
// Stake program id
let stake_program_info = next_account_info(account_info_iter)?; let stake_program_info = next_account_info(account_info_iter)?;
// Check program ids
if *stake_program_info.key != stake_program::id() { if *stake_program_info.key != stake_program::id() {
return Err(ProgramError::IncorrectProgramId); return Err(ProgramError::IncorrectProgramId);
} }
@ -906,10 +817,8 @@ impl Processor {
return Err(StakePoolError::InvalidState.into()); return Err(StakePoolError::InvalidState.into());
} }
// Check if stake is active
Self::check_stake_activation(stake_info, clock, stake_history)?; Self::check_stake_activation(stake_info, clock, stake_history)?;
// Check authority accounts
stake_pool.check_authority_withdraw(withdraw_info.key, program_id, stake_pool_info.key)?; stake_pool.check_authority_withdraw(withdraw_info.key, program_id, stake_pool_info.key)?;
stake_pool.check_authority_deposit(deposit_info.key, program_id, stake_pool_info.key)?; stake_pool.check_authority_deposit(deposit_info.key, program_id, stake_pool_info.key)?;
@ -920,28 +829,25 @@ impl Processor {
return Err(ProgramError::IncorrectProgramId); return Err(ProgramError::IncorrectProgramId);
} }
// Check validator stake account list storage
if *validator_list_info.key != stake_pool.validator_list { if *validator_list_info.key != stake_pool.validator_list {
return Err(StakePoolError::InvalidValidatorStakeList.into()); return Err(StakePoolError::InvalidValidatorStakeList.into());
} }
// Check stake pool last update epoch
if stake_pool.last_update_epoch < clock.epoch { if stake_pool.last_update_epoch < clock.epoch {
return Err(StakePoolError::StakeListAndPoolOutOfDate.into()); return Err(StakePoolError::StakeListAndPoolOutOfDate.into());
} }
// Read validator stake list account and check if it is valid
let mut validator_list = let mut validator_list =
try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?; try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?;
if !validator_list.is_valid() { if !validator_list.is_valid() {
return Err(StakePoolError::InvalidState.into()); return Err(StakePoolError::InvalidState.into());
} }
let validator_account = let vote_account =
Self::get_validator_checked(program_id, stake_pool_info, validator_stake_account_info)?; Self::get_validator_checked(program_id, stake_pool_info, validator_stake_account_info)?;
let validator_list_item = validator_list let validator_list_item = validator_list
.find_mut(&validator_account) .find_mut(&vote_account)
.ok_or(StakePoolError::ValidatorNotFound)?; .ok_or(StakePoolError::ValidatorNotFound)?;
let stake_lamports = **stake_info.lamports.borrow(); let stake_lamports = **stake_info.lamports.borrow();
@ -1031,31 +937,19 @@ impl Processor {
accounts: &[AccountInfo], accounts: &[AccountInfo],
) -> ProgramResult { ) -> ProgramResult {
let account_info_iter = &mut accounts.iter(); let account_info_iter = &mut accounts.iter();
// Stake pool
let stake_pool_info = next_account_info(account_info_iter)?; let stake_pool_info = next_account_info(account_info_iter)?;
// Account storing validator stake list
let validator_list_info = next_account_info(account_info_iter)?; let validator_list_info = next_account_info(account_info_iter)?;
// Stake pool withdraw authority
let withdraw_info = next_account_info(account_info_iter)?; let withdraw_info = next_account_info(account_info_iter)?;
// Stake account to split
let stake_split_from = next_account_info(account_info_iter)?; let stake_split_from = next_account_info(account_info_iter)?;
// Unitialized stake account to receive withdrawal
let stake_split_to = next_account_info(account_info_iter)?; let stake_split_to = next_account_info(account_info_iter)?;
// User account to set as a new withdraw authority
let user_stake_authority = next_account_info(account_info_iter)?; let user_stake_authority = next_account_info(account_info_iter)?;
// User account with pool tokens to burn from
let burn_from_info = next_account_info(account_info_iter)?; let burn_from_info = next_account_info(account_info_iter)?;
// Pool token mint account
let pool_mint_info = next_account_info(account_info_iter)?; let pool_mint_info = next_account_info(account_info_iter)?;
// Clock sysvar account
let clock_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 clock = &Clock::from_account_info(clock_info)?;
// Pool token program id
let token_program_info = next_account_info(account_info_iter)?; let token_program_info = next_account_info(account_info_iter)?;
// Stake program id
let stake_program_info = next_account_info(account_info_iter)?; let stake_program_info = next_account_info(account_info_iter)?;
// Check program ids
if *stake_program_info.key != stake_program::id() { if *stake_program_info.key != stake_program::id() {
return Err(ProgramError::IncorrectProgramId); return Err(ProgramError::IncorrectProgramId);
} }
@ -1065,35 +959,31 @@ impl Processor {
return Err(StakePoolError::InvalidState.into()); return Err(StakePoolError::InvalidState.into());
} }
// Check authority account
stake_pool.check_authority_withdraw(withdraw_info.key, program_id, stake_pool_info.key)?; stake_pool.check_authority_withdraw(withdraw_info.key, program_id, stake_pool_info.key)?;
if stake_pool.token_program_id != *token_program_info.key { if stake_pool.token_program_id != *token_program_info.key {
return Err(ProgramError::IncorrectProgramId); return Err(ProgramError::IncorrectProgramId);
} }
// Check validator stake account list storage
if *validator_list_info.key != stake_pool.validator_list { if *validator_list_info.key != stake_pool.validator_list {
return Err(StakePoolError::InvalidValidatorStakeList.into()); return Err(StakePoolError::InvalidValidatorStakeList.into());
} }
// Check stake pool last update epoch
if stake_pool.last_update_epoch < clock.epoch { if stake_pool.last_update_epoch < clock.epoch {
return Err(StakePoolError::StakeListAndPoolOutOfDate.into()); return Err(StakePoolError::StakeListAndPoolOutOfDate.into());
} }
// Read validator stake list account and check if it is valid
let mut validator_list = let mut validator_list =
try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?; try_from_slice_unchecked::<ValidatorList>(&validator_list_info.data.borrow())?;
if !validator_list.is_valid() { if !validator_list.is_valid() {
return Err(StakePoolError::InvalidState.into()); return Err(StakePoolError::InvalidState.into());
} }
let validator_account = let vote_account =
Self::get_validator_checked(program_id, stake_pool_info, stake_split_from)?; Self::get_validator_checked(program_id, stake_pool_info, stake_split_from)?;
let validator_list_item = validator_list let validator_list_item = validator_list
.find_mut(&validator_account) .find_mut(&vote_account)
.ok_or(StakePoolError::ValidatorNotFound)?; .ok_or(StakePoolError::ValidatorNotFound)?;
let stake_amount = stake_pool let stake_amount = stake_pool
@ -1168,10 +1058,8 @@ impl Processor {
return Err(StakePoolError::InvalidState.into()); return Err(StakePoolError::InvalidState.into());
} }
// Check owner validity and signature
stake_pool.check_owner(owner_info)?; stake_pool.check_owner(owner_info)?;
// Check for owner fee account to have proper mint assigned
if stake_pool.pool_mint if stake_pool.pool_mint
!= spl_token::state::Account::unpack_from_slice(&new_owner_fee_info.data.borrow())?.mint != spl_token::state::Account::unpack_from_slice(&new_owner_fee_info.data.borrow())?.mint
{ {
@ -1183,6 +1071,7 @@ impl Processor {
stake_pool.serialize(&mut *stake_pool_info.data.borrow_mut())?; stake_pool.serialize(&mut *stake_pool_info.data.borrow_mut())?;
Ok(()) Ok(())
} }
/// Processes [Instruction](enum.Instruction.html). /// Processes [Instruction](enum.Instruction.html).
pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult { pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult {
let instruction = StakePoolInstruction::try_from_slice(input)?; let instruction = StakePoolInstruction::try_from_slice(input)?;

View File

@ -170,10 +170,10 @@ pub struct ValidatorList {
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] #[derive(Clone, Copy, Debug, Default, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)]
pub struct ValidatorStakeInfo { pub struct ValidatorStakeInfo {
/// Validator account pubkey /// Validator vote account address
pub validator_account: Pubkey, pub vote_account: Pubkey,
/// Account balance in lamports /// Balance of the validator's stake account
pub balance: u64, pub balance: u64,
/// Last epoch balance field was updated /// Last epoch balance field was updated
@ -197,23 +197,23 @@ impl ValidatorList {
} }
/// Check if contains validator with particular pubkey /// Check if contains validator with particular pubkey
pub fn contains(&self, validator: &Pubkey) -> bool { pub fn contains(&self, vote_account: &Pubkey) -> bool {
self.validators self.validators
.iter() .iter()
.any(|x| x.validator_account == *validator) .any(|x| x.vote_account == *vote_account)
} }
/// Check if contains validator with particular pubkey (mutable) /// Check if contains validator with particular pubkey
pub fn find_mut(&mut self, validator: &Pubkey) -> Option<&mut ValidatorStakeInfo> { pub fn find_mut(&mut self, vote_account: &Pubkey) -> Option<&mut ValidatorStakeInfo> {
self.validators self.validators
.iter_mut() .iter_mut()
.find(|x| x.validator_account == *validator) .find(|x| x.vote_account == *vote_account)
} }
/// Check if contains validator with particular pubkey (immutable) /// Check if contains validator with particular pubkey
pub fn find(&self, validator: &Pubkey) -> Option<&ValidatorStakeInfo> { pub fn find(&self, vote_account: &Pubkey) -> Option<&ValidatorStakeInfo> {
self.validators self.validators
.iter() .iter()
.find(|x| x.validator_account == *validator) .find(|x| x.vote_account == *vote_account)
} }
/// Check if validator stake list is actually initialized as a validator stake list /// Check if validator stake list is actually initialized as a validator stake list
@ -271,17 +271,17 @@ mod test {
max_validators, max_validators,
validators: vec![ validators: vec![
ValidatorStakeInfo { ValidatorStakeInfo {
validator_account: Pubkey::new_from_array([1; 32]), vote_account: Pubkey::new_from_array([1; 32]),
balance: 123456789, balance: 123456789,
last_update_epoch: 987654321, last_update_epoch: 987654321,
}, },
ValidatorStakeInfo { ValidatorStakeInfo {
validator_account: Pubkey::new_from_array([2; 32]), vote_account: Pubkey::new_from_array([2; 32]),
balance: 998877665544, balance: 998877665544,
last_update_epoch: 11223445566, last_update_epoch: 11223445566,
}, },
ValidatorStakeInfo { ValidatorStakeInfo {
validator_account: Pubkey::new_from_array([3; 32]), vote_account: Pubkey::new_from_array([3; 32]),
balance: 0, balance: 0,
last_update_epoch: 999999999999999, last_update_epoch: 999999999999999,
}, },

View File

@ -129,7 +129,7 @@ async fn test_add_validator_to_pool() {
account_type: state::AccountType::ValidatorList, account_type: state::AccountType::ValidatorList,
max_validators: stake_pool_accounts.max_validators, max_validators: stake_pool_accounts.max_validators,
validators: vec![state::ValidatorStakeInfo { validators: vec![state::ValidatorStakeInfo {
validator_account: user_stake.vote.pubkey(), vote_account: user_stake.vote.pubkey(),
last_update_epoch: 0, last_update_epoch: 0,
balance: stake_account_balance, balance: stake_account_balance,
}] }]