Skip to content

Commit

Permalink
TWEAKS: Last cleanup (#62)
Browse files Browse the repository at this point in the history
Co-authored-by: Christian  Krueger <[email protected]>
  • Loading branch information
coachchucksol and Christian Krueger authored Jul 24, 2024
1 parent a7dccae commit f4ea93a
Show file tree
Hide file tree
Showing 27 changed files with 522 additions and 378 deletions.
171 changes: 98 additions & 73 deletions programs/steward/idl/steward.json

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions programs/steward/src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
pub const MAX_ALLOC_BYTES: usize = 10240;
pub const MAX_ALLOC_BYTES: usize = 10_240;
pub const VEC_SIZE_BYTES: usize = 4;
pub const U64_SIZE: usize = 8;
pub const STAKE_STATUS_OFFSET: usize = 40;
pub const STAKE_POOL_WITHDRAW_SEED: &[u8] = b"withdraw";
pub const STAKE_POOL_TRANSIENT_SEED: &[u8] = b"transient";
pub const MAX_VALIDATORS: usize = 5000;
pub const BASIS_POINTS_MAX: u16 = 10000;
pub const MAX_VALIDATORS: usize = 5_000;
pub const BASIS_POINTS_MAX: u16 = 10_000;
pub const COMMISSION_MAX: u8 = 100;
pub const SORTED_INDEX_DEFAULT: u16 = u16::MAX;
// Need at least 1% of slots remaining (4320 slots) to execute steps in state machine
Expand Down
3 changes: 2 additions & 1 deletion programs/steward/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ pub fn increase_stake_calculation(
}
return Err(StewardError::ValidatorIndexOutOfBounds.into());
}
Err(StewardError::InvalidState.into())

Err(StewardError::ValidatorIndexOutOfBounds.into())
}

#[derive(Default)]
Expand Down
20 changes: 7 additions & 13 deletions programs/steward/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,14 @@ pub enum StewardError {
ScoringNotComplete,
#[msg("Validator does not exist at the ValidatorList index provided")]
ValidatorNotInList,
#[msg("Add validators step must be completed before any other steps can be taken")]
AddValidatorsNotComplete,
#[msg("Cannot reset state before epoch is over")]
EpochNotOver,
#[msg("Unauthorized to perform this action")]
Unauthorized,
#[msg("Bitmask index out of bounds")]
BitmaskOutOfBounds,
#[msg("Epoch state not reset")]
StateNotReset,
#[msg("Validator History created after epoch start, out of range")]
ValidatorOutOfRange,
// Use invalid_state_error method to ensure expected and actual are logged
#[msg("Invalid state")]
InvalidState,
#[msg("Stake state is not Stake")]
StakeStateIsNotStake,
#[msg("Validator not eligible to be added to the pool. Must meet stake minimum")]
ValidatorBelowStakeMinimum,
#[msg("Validator not eligible to be added to the pool. Must meet recent voting minimum")]
Expand Down Expand Up @@ -52,8 +46,6 @@ pub enum StewardError {
ValidatorMarkedActive,
#[msg("Max validators reached")]
MaxValidatorsReached,
#[msg("Validator history account does not match vote account")]
ValidatorHistoryMismatch,
#[msg("Epoch Maintenance must be called before continuing")]
EpochMaintenanceNotComplete,
#[msg("The stake pool must be updated before continuing")]
Expand All @@ -62,12 +54,14 @@ pub enum StewardError {
EpochMaintenanceAlreadyComplete,
#[msg("Validators are marked for immediate removal")]
ValidatorsNeedToBeRemoved,
#[msg("No validators are marked for immediate removal")]
NoValidatorsNeedToBeRemoved,
#[msg("Validator not marked for removal")]
ValidatorNotMarkedForRemoval,
#[msg("Validators have not been removed")]
ValidatorsHaveNotBeenRemoved,
#[msg("Validator List count does not match state machine")]
ListStateMismatch,
#[msg("Vote account does not match")]
VoteAccountDoesNotMatch,
#[msg("Validator needs to be marked for removal")]
ValidatorNeedsToBeMarkedForRemoval,
}
9 changes: 7 additions & 2 deletions programs/steward/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use anchor_lang::solana_program::pubkey::Pubkey;
use borsh::{BorshDeserialize, BorshSerialize};

#[event]
#[derive(Debug, Clone)]

pub struct AutoRemoveValidatorEvent {
pub validator_list_index: u64,
pub vote_account: Pubkey,
Expand All @@ -16,12 +18,14 @@ pub struct AutoRemoveValidatorEvent {
}

#[event]
#[derive(Debug, Clone)]
pub struct AutoAddValidatorEvent {
pub validator_list_index: u64,
pub vote_account: Pubkey,
}

#[event]
#[derive(Debug, Clone)]
pub struct EpochMaintenanceEvent {
pub validator_index_to_remove: Option<u64>,
pub validator_list_length: u64,
Expand All @@ -32,7 +36,7 @@ pub struct EpochMaintenanceEvent {
}

#[event]
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct StateTransition {
pub epoch: u64,
pub slot: u64,
Expand All @@ -50,6 +54,7 @@ pub struct DecreaseComponents {
}

#[event]
#[derive(Debug, Clone)]
pub struct RebalanceEvent {
pub vote_account: Pubkey,
pub epoch: u16,
Expand All @@ -58,7 +63,7 @@ pub struct RebalanceEvent {
pub decrease_components: DecreaseComponents,
}

#[derive(BorshSerialize, BorshDeserialize, Debug)]
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
pub enum RebalanceTypeTag {
None,
Increase,
Expand Down
126 changes: 56 additions & 70 deletions programs/steward/src/instructions/auto_add_validator_to_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ use crate::constants::{MAX_VALIDATORS, STAKE_POOL_WITHDRAW_SEED};
use crate::errors::StewardError;
use crate::events::AutoAddValidatorEvent;
use crate::state::{Config, StewardStateAccount};
use crate::utils::{deserialize_stake_pool, get_stake_pool_address};
use crate::utils::{
add_validator_check, deserialize_stake_pool, get_stake_pool_address, get_validator_list_length,
};
use anchor_lang::prelude::*;
use anchor_lang::solana_program::{program::invoke_signed, stake, sysvar, vote};
use spl_stake_pool::find_stake_program_address;
use spl_stake_pool::state::ValidatorListHeader;
use validator_history::state::ValidatorHistory;
use validator_history::ValidatorHistoryEntry;

#[derive(Accounts)]
pub struct AutoAddValidator<'info> {
Expand All @@ -28,12 +30,6 @@ pub struct AutoAddValidator<'info> {
)]
pub validator_history_account: AccountLoader<'info, ValidatorHistory>,

/// CHECK: CPI address
#[account(
address = spl_stake_pool::ID
)]
pub stake_pool_program: AccountInfo<'info>,

/// CHECK: passing through, checks are done by spl-stake-pool
#[account(
mut,
Expand Down Expand Up @@ -76,10 +72,6 @@ pub struct AutoAddValidator<'info> {
#[account(owner = vote::program::ID)]
pub vote_account: AccountInfo<'info>,

pub rent: Sysvar<'info, Rent>,

pub clock: Sysvar<'info, Clock>,

/// CHECK: passing through, checks are done by spl-stake-pool
#[account(address = sysvar::stake_history::ID)]
pub stake_history: AccountInfo<'info>,
Expand All @@ -88,11 +80,21 @@ pub struct AutoAddValidator<'info> {
#[account(address = stake::config::ID)]
pub stake_config: AccountInfo<'info>,

pub system_program: Program<'info, System>,

/// CHECK: passing through, checks are done by spl-stake-pool
#[account(address = stake::program::ID)]
pub stake_program: AccountInfo<'info>,

/// CHECK: CPI address
#[account(
address = spl_stake_pool::ID
)]
pub stake_pool_program: AccountInfo<'info>,

pub system_program: Program<'info, System>,

pub rent: Sysvar<'info, Rent>,

pub clock: Sysvar<'info, Clock>,
}

/*
Expand All @@ -101,68 +103,52 @@ all the validators we want to be eligible for delegation, as well as to accept s
Performs some eligibility checks in order to not fill up the validator list with offline or malicious validators.
*/
pub fn handler(ctx: Context<AutoAddValidator>) -> Result<()> {
let mut state_account = ctx.accounts.steward_state.load_mut()?;
let config = ctx.accounts.config.load()?;
let validator_history = ctx.accounts.validator_history_account.load()?;
let epoch = Clock::get()?.epoch;

// Should not be able to add a validator if update is not complete
{
require!(
epoch == state_account.state.current_epoch,
StewardError::EpochMaintenanceNotComplete
);

require!(
state_account.state.validators_for_immediate_removal.count() == 0,
StewardError::ValidatorsNeedToBeRemoved
);
}

let validator_list_len = {
let validator_list_data = &mut ctx.accounts.validator_list.try_borrow_mut_data()?;
let (_, validator_list) = ValidatorListHeader::deserialize_vec(validator_list_data)?;

validator_list.len()
};
if validator_list_len.checked_add(1).unwrap() > MAX_VALIDATORS as u32 {
return Err(StewardError::MaxValidatorsReached.into());
}
let mut state_account = ctx.accounts.steward_state.load_mut()?;
let config = ctx.accounts.config.load()?;
let validator_history = ctx.accounts.validator_history_account.load()?;
let validator_list = &ctx.accounts.validator_list;
let clock = Clock::get()?;
let epoch = clock.epoch;

add_validator_check(&clock, &config, &state_account, validator_list)?;

let validator_list_len = get_validator_list_length(&ctx.accounts.validator_list)?;
if validator_list_len.checked_add(1).unwrap() > MAX_VALIDATORS {
return Err(StewardError::MaxValidatorsReached.into());
}

let start_epoch =
epoch.saturating_sub(config.parameters.minimum_voting_epochs.saturating_sub(1));
if let Some(entry) = validator_history.history.last() {
// Steward requires that validators have been active for last minimum_voting_epochs epochs
if validator_history
.history
.epoch_credits_range(start_epoch as u16, epoch as u16)
.iter()
.any(|entry| entry.is_none())
{
let start_epoch =
epoch.saturating_sub(config.parameters.minimum_voting_epochs.saturating_sub(1));
if let Some(entry) = validator_history.history.last() {
// Steward requires that validators have been active for last minimum_voting_epochs epochs
if validator_history
.history
.epoch_credits_range(start_epoch as u16, epoch as u16)
.iter()
.any(|entry| entry.is_none())
{
return Err(StewardError::ValidatorBelowLivenessMinimum.into());
}
if entry.activated_stake_lamports
== ValidatorHistoryEntry::default().activated_stake_lamports
{
return Err(StewardError::StakeHistoryNotRecentEnough.into());
}
if entry.activated_stake_lamports < config.parameters.minimum_stake_lamports {
return Err(StewardError::ValidatorBelowStakeMinimum.into());
}
} else {
return Err(StewardError::ValidatorBelowLivenessMinimum.into());
}
if entry.activated_stake_lamports < config.parameters.minimum_stake_lamports {
msg!(
"Validator {} below minimum. Required: {} Actual: {}",
validator_history.vote_account,
config.parameters.minimum_stake_lamports,
entry.activated_stake_lamports
);
return Err(StewardError::ValidatorBelowStakeMinimum.into());
}
} else {
return Err(StewardError::ValidatorBelowLivenessMinimum.into());
}

state_account.state.increment_validator_to_add()?;
state_account.state.increment_validator_to_add()?;

// Have to drop the state account before calling the CPI
drop(state_account);

emit!(AutoAddValidatorEvent {
vote_account: ctx.accounts.vote_account.key(),
validator_list_index: validator_list_len as u64
});
emit!(AutoAddValidatorEvent {
vote_account: ctx.accounts.vote_account.key(),
validator_list_index: validator_list_len as u64
});
}

invoke_signed(
&spl_stake_pool::instruction::add_validator_to_pool(
Expand Down
Loading

0 comments on commit f4ea93a

Please sign in to comment.