From b23679ace9c48190320a1f2f84494933bb6192de Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Sun, 1 Dec 2024 16:28:08 -0500 Subject: [PATCH 01/11] normalize tvc --- programs/steward/src/constants.rs | 3 ++ .../instructions/compute_instant_unstake.rs | 18 +++++++++ .../steward/src/instructions/compute_score.rs | 23 +++++++++++ programs/steward/src/score.rs | 26 ++++++++---- programs/steward/src/state/steward_state.rs | 11 ++++- programs/validator-history/src/constants.rs | 1 + programs/validator-history/src/state.rs | 40 +++++++++++++++++++ 7 files changed, 113 insertions(+), 9 deletions(-) diff --git a/programs/steward/src/constants.rs b/programs/steward/src/constants.rs index 2b2b391b..ee3caada 100644 --- a/programs/steward/src/constants.rs +++ b/programs/steward/src/constants.rs @@ -20,3 +20,6 @@ pub const COMPUTE_SCORE_SLOT_RANGE_MIN: u64 = 100; pub const VALIDATOR_HISTORY_FIRST_RELIABLE_EPOCH: u64 = 520; #[cfg(not(feature = "mainnet-beta"))] pub const VALIDATOR_HISTORY_FIRST_RELIABLE_EPOCH: u64 = 0; +pub const TVC_FEATURE_PUBKEY: &str = "tvcF6b1TRz353zKuhBjinZkKzjmihXmBAHJdjNYw1sQ"; +pub const TVC_MAINNET_ACTIVATION_EPOCH: u64 = 704; +pub const TVC_TESTNET_ACTIVATION_EPOCH: u64 = 705; diff --git a/programs/steward/src/instructions/compute_instant_unstake.rs b/programs/steward/src/instructions/compute_instant_unstake.rs index 28f52135..49d8c06d 100644 --- a/programs/steward/src/instructions/compute_instant_unstake.rs +++ b/programs/steward/src/instructions/compute_instant_unstake.rs @@ -1,10 +1,12 @@ use crate::{ + constants::TVC_MAINNET_ACTIVATION_EPOCH, errors::StewardError, maybe_transition, utils::{get_validator_list, get_validator_stake_info_at_index, state_checks}, Config, StewardStateAccount, StewardStateEnum, }; use anchor_lang::prelude::*; +use spl_pod::solana_program::feature::Feature; use validator_history::{ClusterHistory, ValidatorHistory}; #[derive(Accounts)] @@ -31,6 +33,8 @@ pub struct ComputeInstantUnstake<'info> { bump )] pub cluster_history: AccountLoader<'info, ClusterHistory>, + + pub maybe_tvc_feature_account: Option>, } pub fn handler(ctx: Context, validator_list_index: usize) -> Result<()> { @@ -42,6 +46,19 @@ pub fn handler(ctx: Context, validator_list_index: usize) let clock = Clock::get()?; let epoch_schedule = EpochSchedule::get()?; + let tvc_activation_epoch = { + if let Some(tvc_feature_account) = ctx.accounts.maybe_tvc_feature_account.as_ref() { + let activation_slot = Feature::from_account_info(tvc_feature_account)?.activated_at; + if let Some(activation_slot) = activation_slot { + epoch_schedule.get_epoch(activation_slot) + } else { + TVC_MAINNET_ACTIVATION_EPOCH + } + } else { + TVC_MAINNET_ACTIVATION_EPOCH + } + }; + // Transitions to Idle before doing compute_instant_unstake if RESET_TO_IDLE is set if let Some(event) = maybe_transition( &mut state_account.state, @@ -75,6 +92,7 @@ pub fn handler(ctx: Context, validator_list_index: usize) validator_list_index, &cluster, &config, + tvc_activation_epoch, )? { emit!(instant_unstake); } diff --git a/programs/steward/src/instructions/compute_score.rs b/programs/steward/src/instructions/compute_score.rs index 580029e9..be2a4fae 100644 --- a/programs/steward/src/instructions/compute_score.rs +++ b/programs/steward/src/instructions/compute_score.rs @@ -1,6 +1,10 @@ +use std::str::FromStr; + use anchor_lang::prelude::*; +use spl_pod::solana_program::{clock::Epoch, feature::Feature}; use crate::{ + constants::{TVC_FEATURE_PUBKEY, TVC_MAINNET_ACTIVATION_EPOCH}, errors::StewardError, maybe_transition, utils::{ @@ -34,6 +38,11 @@ pub struct ComputeScore<'info> { bump )] pub cluster_history: AccountLoader<'info, ClusterHistory>, + + #[account( + address = Pubkey::from_str(TVC_FEATURE_PUBKEY).unwrap() + )] + pub maybe_tvc_feature_account: Option>, } pub fn handler(ctx: Context, validator_list_index: usize) -> Result<()> { @@ -45,6 +54,19 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Resul let clock: Clock = Clock::get()?; let epoch_schedule = EpochSchedule::get()?; + let tvc_activation_epoch = { + if let Some(tvc_feature_account) = ctx.accounts.maybe_tvc_feature_account.as_ref() { + let activation_slot = Feature::from_account_info(tvc_feature_account)?.activated_at; + if let Some(activation_slot) = activation_slot { + epoch_schedule.get_epoch(activation_slot) + } else { + TVC_MAINNET_ACTIVATION_EPOCH + } + } else { + TVC_MAINNET_ACTIVATION_EPOCH + } + }; + // We don't check the state here because we force it below state_checks(&clock, &config, &state_account, validator_list, None)?; @@ -89,6 +111,7 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Resul &cluster_history, &config, num_pool_validators as u64, + tvc_activation_epoch, )? { emit!(score); } diff --git a/programs/steward/src/score.rs b/programs/steward/src/score.rs index e38561fd..f76368bf 100644 --- a/programs/steward/src/score.rs +++ b/programs/steward/src/score.rs @@ -3,7 +3,7 @@ use anchor_lang::IdlBuild; use anchor_lang::{ prelude::event, solana_program::pubkey::Pubkey, AnchorDeserialize, AnchorSerialize, Result, }; -use validator_history::{ClusterHistory, ValidatorHistory}; +use validator_history::{constants::TVC_MULTIPLIER, ClusterHistory, ValidatorHistory}; use crate::{ constants::{ @@ -90,6 +90,7 @@ pub fn validator_score( cluster: &ClusterHistory, config: &Config, current_epoch: u16, + tvc_activation_epoch: u64, ) -> Result { let params = &config.parameters; @@ -107,9 +108,11 @@ pub fn validator_score( // Epoch credits should not include current epoch because it is in progress and data would be incomplete let epoch_credits_end = current_epoch.checked_sub(1).ok_or(ArithmeticError)?; - let epoch_credits_window = validator - .history - .epoch_credits_range(epoch_credits_start, epoch_credits_end); + let normalized_epoch_credits_window = validator.history.epoch_credits_range_normalized( + epoch_credits_start, + epoch_credits_end, + tvc_activation_epoch, + ); let total_blocks_window = cluster .history @@ -132,7 +135,7 @@ pub fn validator_score( let (vote_credits_ratio, delinquency_score, delinquency_ratio, delinquency_epoch) = calculate_epoch_credits( - &epoch_credits_window, + &normalized_epoch_credits_window, &total_blocks_window, epoch_credits_start, params.scoring_delinquency_threshold_ratio, @@ -283,8 +286,11 @@ pub fn calculate_epoch_credits( } } + let normalized_vote_credits_ratio = + average_vote_credits / (average_blocks * (TVC_MULTIPLIER as f64)); + Ok(( - average_vote_credits / average_blocks, + normalized_vote_credits_ratio, delinquency_score, delinquency_ratio, delinquency_epoch, @@ -471,6 +477,7 @@ pub fn instant_unstake_validator( config: &Config, epoch_start_slot: u64, current_epoch: u16, + tvc_activation_epoch: u64, ) -> Result { let params = &config.parameters; @@ -494,7 +501,10 @@ pub fn instant_unstake_validator( .checked_sub(epoch_start_slot) .ok_or(StewardError::ArithmeticError)?; - let epoch_credits_latest = validator.history.epoch_credits_latest().unwrap_or(0); + let epoch_credits_latest = validator + .history + .epoch_credits_latest_normalized(current_epoch as u64, tvc_activation_epoch) + .unwrap_or(0); /////// Component calculations /////// let delinquency_check = calculate_instant_unstake_delinquency( @@ -555,7 +565,7 @@ pub fn calculate_instant_unstake_delinquency( if blocks_produced_rate > 0. { Ok( - (vote_credits_rate / blocks_produced_rate) + (vote_credits_rate / (blocks_produced_rate * (TVC_MULTIPLIER as f64))) < instant_unstake_delinquency_threshold_ratio, ) } else { diff --git a/programs/steward/src/state/steward_state.rs b/programs/steward/src/state/steward_state.rs index c1b0e146..3b5f7e1f 100644 --- a/programs/steward/src/state/steward_state.rs +++ b/programs/steward/src/state/steward_state.rs @@ -600,6 +600,7 @@ impl StewardState { cluster: &ClusterHistory, config: &Config, num_pool_validators: u64, + tvc_activation_epoch: u64, ) -> Result> { if matches!(self.state_tag, StewardStateEnum::ComputeScores) { let current_epoch = clock.epoch; @@ -681,7 +682,13 @@ impl StewardState { return Err(StewardError::ClusterHistoryNotRecentEnough.into()); } - let score = validator_score(validator, cluster, config, current_epoch as u16)?; + let score = validator_score( + validator, + cluster, + config, + current_epoch as u16, + tvc_activation_epoch, + )?; self.scores[index] = (score.score * 1_000_000_000.) as u32; self.yield_scores[index] = (score.yield_score * 1_000_000_000.) as u32; @@ -756,6 +763,7 @@ impl StewardState { index: usize, cluster: &ClusterHistory, config: &Config, + tvc_activation_epoch: u64, ) -> Result> { if matches!(self.state_tag, StewardStateEnum::ComputeInstantUnstake) { if clock.epoch >= self.next_cycle_epoch { @@ -809,6 +817,7 @@ impl StewardState { config, first_slot, clock.epoch as u16, + tvc_activation_epoch, )?; self.instant_unstake diff --git a/programs/validator-history/src/constants.rs b/programs/validator-history/src/constants.rs index 990e9342..4469f1a0 100644 --- a/programs/validator-history/src/constants.rs +++ b/programs/validator-history/src/constants.rs @@ -1,2 +1,3 @@ pub const MAX_ALLOC_BYTES: usize = 10240; pub const MIN_VOTE_EPOCHS: usize = 5; +pub const TVC_MULTIPLIER: u32 = 8; diff --git a/programs/validator-history/src/state.rs b/programs/validator-history/src/state.rs index 6a52f05c..454c0e65 100644 --- a/programs/validator-history/src/state.rs +++ b/programs/validator-history/src/state.rs @@ -1,5 +1,6 @@ use { crate::{ + constants::TVC_MULTIPLIER, crds_value::{ContactInfo, LegacyContactInfo, LegacyVersion, Version2}, errors::ValidatorHistoryError, utils::{cast_epoch, find_insert_position, get_max_epoch, get_min_epoch}, @@ -274,10 +275,49 @@ impl CircBuf { field_latest!(self, epoch_credits) } + /// Normalized epoch credits, accounting for Timely Vote Credits making the max number of credits 8x higher + /// for every epoch starting at `tvc_activation_epoch` + pub fn epoch_credits_latest_normalized( + &self, + current_epoch: u64, + tvc_activation_epoch: u64, + ) -> Option { + self.epoch_credits_latest().map(|credits| { + if current_epoch < tvc_activation_epoch { + credits.saturating_mul(TVC_MULTIPLIER) + } else { + credits + } + }) + } + pub fn epoch_credits_range(&self, start_epoch: u16, end_epoch: u16) -> Vec> { field_range!(self, start_epoch, end_epoch, epoch_credits, u32) } + /// Normalized epoch credits, accounting for Timely Vote Credits making the max number of credits 8x higher + /// for every epoch starting at `tvc_activation_epoch` + pub fn epoch_credits_range_normalized( + &self, + start_epoch: u16, + end_epoch: u16, + tvc_activation_epoch: u64, + ) -> Vec> { + field_range!(self, start_epoch, end_epoch, epoch_credits, u32) + .into_iter() + .zip(start_epoch..=end_epoch) + .map(|(maybe_credits, epoch)| { + maybe_credits.map(|credits| { + if (epoch as u64) < tvc_activation_epoch { + credits.saturating_mul(TVC_MULTIPLIER) + } else { + credits + } + }) + }) + .collect() + } + pub fn superminority_latest(&self) -> Option { // Protect against unexpected values if let Some(value) = field_latest!(self, is_superminority) { From 6e1630d3712e22792cf4d3f064768b134722c2ef Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Tue, 3 Dec 2024 18:18:20 -0500 Subject: [PATCH 02/11] Format for PR --- programs/steward/src/constants.rs | 8 +- .../instructions/compute_instant_unstake.rs | 18 -- .../steward/src/instructions/compute_score.rs | 23 --- programs/steward/src/score.rs | 2 +- programs/steward/src/state/steward_state.rs | 10 +- tests/src/steward_fixtures.rs | 18 +- tests/tests/steward/test_algorithms.rs | 186 ++++++++++++++---- tests/tests/steward/test_integration.rs | 16 +- tests/tests/steward/test_scoring.rs | 52 ++++- 9 files changed, 223 insertions(+), 110 deletions(-) diff --git a/programs/steward/src/constants.rs b/programs/steward/src/constants.rs index ee3caada..1dd6cddb 100644 --- a/programs/steward/src/constants.rs +++ b/programs/steward/src/constants.rs @@ -21,5 +21,9 @@ pub const VALIDATOR_HISTORY_FIRST_RELIABLE_EPOCH: u64 = 520; #[cfg(not(feature = "mainnet-beta"))] pub const VALIDATOR_HISTORY_FIRST_RELIABLE_EPOCH: u64 = 0; pub const TVC_FEATURE_PUBKEY: &str = "tvcF6b1TRz353zKuhBjinZkKzjmihXmBAHJdjNYw1sQ"; -pub const TVC_MAINNET_ACTIVATION_EPOCH: u64 = 704; -pub const TVC_TESTNET_ACTIVATION_EPOCH: u64 = 705; +#[cfg(feature = "mainnet-beta")] +pub const TVC_ACTIVATION_EPOCH: u64 = 704; +#[cfg(all(not(feature = "mainnet-beta"), feature = "testnet"))] +pub const TVC_ACTIVATION_EPOCH: u64 = 705; +#[cfg(all(not(feature = "mainnet-beta"), not(feature = "testnet")))] +pub const TVC_ACTIVATION_EPOCH: u64 = 0; diff --git a/programs/steward/src/instructions/compute_instant_unstake.rs b/programs/steward/src/instructions/compute_instant_unstake.rs index 49d8c06d..28f52135 100644 --- a/programs/steward/src/instructions/compute_instant_unstake.rs +++ b/programs/steward/src/instructions/compute_instant_unstake.rs @@ -1,12 +1,10 @@ use crate::{ - constants::TVC_MAINNET_ACTIVATION_EPOCH, errors::StewardError, maybe_transition, utils::{get_validator_list, get_validator_stake_info_at_index, state_checks}, Config, StewardStateAccount, StewardStateEnum, }; use anchor_lang::prelude::*; -use spl_pod::solana_program::feature::Feature; use validator_history::{ClusterHistory, ValidatorHistory}; #[derive(Accounts)] @@ -33,8 +31,6 @@ pub struct ComputeInstantUnstake<'info> { bump )] pub cluster_history: AccountLoader<'info, ClusterHistory>, - - pub maybe_tvc_feature_account: Option>, } pub fn handler(ctx: Context, validator_list_index: usize) -> Result<()> { @@ -46,19 +42,6 @@ pub fn handler(ctx: Context, validator_list_index: usize) let clock = Clock::get()?; let epoch_schedule = EpochSchedule::get()?; - let tvc_activation_epoch = { - if let Some(tvc_feature_account) = ctx.accounts.maybe_tvc_feature_account.as_ref() { - let activation_slot = Feature::from_account_info(tvc_feature_account)?.activated_at; - if let Some(activation_slot) = activation_slot { - epoch_schedule.get_epoch(activation_slot) - } else { - TVC_MAINNET_ACTIVATION_EPOCH - } - } else { - TVC_MAINNET_ACTIVATION_EPOCH - } - }; - // Transitions to Idle before doing compute_instant_unstake if RESET_TO_IDLE is set if let Some(event) = maybe_transition( &mut state_account.state, @@ -92,7 +75,6 @@ pub fn handler(ctx: Context, validator_list_index: usize) validator_list_index, &cluster, &config, - tvc_activation_epoch, )? { emit!(instant_unstake); } diff --git a/programs/steward/src/instructions/compute_score.rs b/programs/steward/src/instructions/compute_score.rs index be2a4fae..580029e9 100644 --- a/programs/steward/src/instructions/compute_score.rs +++ b/programs/steward/src/instructions/compute_score.rs @@ -1,10 +1,6 @@ -use std::str::FromStr; - use anchor_lang::prelude::*; -use spl_pod::solana_program::{clock::Epoch, feature::Feature}; use crate::{ - constants::{TVC_FEATURE_PUBKEY, TVC_MAINNET_ACTIVATION_EPOCH}, errors::StewardError, maybe_transition, utils::{ @@ -38,11 +34,6 @@ pub struct ComputeScore<'info> { bump )] pub cluster_history: AccountLoader<'info, ClusterHistory>, - - #[account( - address = Pubkey::from_str(TVC_FEATURE_PUBKEY).unwrap() - )] - pub maybe_tvc_feature_account: Option>, } pub fn handler(ctx: Context, validator_list_index: usize) -> Result<()> { @@ -54,19 +45,6 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Resul let clock: Clock = Clock::get()?; let epoch_schedule = EpochSchedule::get()?; - let tvc_activation_epoch = { - if let Some(tvc_feature_account) = ctx.accounts.maybe_tvc_feature_account.as_ref() { - let activation_slot = Feature::from_account_info(tvc_feature_account)?.activated_at; - if let Some(activation_slot) = activation_slot { - epoch_schedule.get_epoch(activation_slot) - } else { - TVC_MAINNET_ACTIVATION_EPOCH - } - } else { - TVC_MAINNET_ACTIVATION_EPOCH - } - }; - // We don't check the state here because we force it below state_checks(&clock, &config, &state_account, validator_list, None)?; @@ -111,7 +89,6 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Resul &cluster_history, &config, num_pool_validators as u64, - tvc_activation_epoch, )? { emit!(score); } diff --git a/programs/steward/src/score.rs b/programs/steward/src/score.rs index f76368bf..59012276 100644 --- a/programs/steward/src/score.rs +++ b/programs/steward/src/score.rs @@ -274,7 +274,7 @@ pub fn calculate_epoch_credits( // If vote credits are None, then validator was not active because we retroactively fill credits for last 64 epochs. // If total blocks are None, then keepers missed an upload and validator should not be punished. let credits = maybe_credits.unwrap_or(0); - let ratio = credits as f64 / *blocks as f64; + let ratio = credits as f64 / (blocks * TVC_MULTIPLIER) as f64; if ratio < scoring_delinquency_threshold_ratio { delinquency_score = 0.0; delinquency_ratio = ratio; diff --git a/programs/steward/src/state/steward_state.rs b/programs/steward/src/state/steward_state.rs index 3b5f7e1f..da1bb620 100644 --- a/programs/steward/src/state/steward_state.rs +++ b/programs/steward/src/state/steward_state.rs @@ -3,7 +3,9 @@ use std::fmt::Display; use crate::{ bitmask::BitMask, - constants::{LAMPORT_BALANCE_DEFAULT, MAX_VALIDATORS, SORTED_INDEX_DEFAULT}, + constants::{ + LAMPORT_BALANCE_DEFAULT, MAX_VALIDATORS, SORTED_INDEX_DEFAULT, TVC_ACTIVATION_EPOCH, + }, delegation::{ decrease_stake_calculation, increase_stake_calculation, RebalanceType, UnstakeState, }, @@ -600,7 +602,6 @@ impl StewardState { cluster: &ClusterHistory, config: &Config, num_pool_validators: u64, - tvc_activation_epoch: u64, ) -> Result> { if matches!(self.state_tag, StewardStateEnum::ComputeScores) { let current_epoch = clock.epoch; @@ -687,7 +688,7 @@ impl StewardState { cluster, config, current_epoch as u16, - tvc_activation_epoch, + TVC_ACTIVATION_EPOCH, )?; self.scores[index] = (score.score * 1_000_000_000.) as u32; @@ -763,7 +764,6 @@ impl StewardState { index: usize, cluster: &ClusterHistory, config: &Config, - tvc_activation_epoch: u64, ) -> Result> { if matches!(self.state_tag, StewardStateEnum::ComputeInstantUnstake) { if clock.epoch >= self.next_cycle_epoch { @@ -817,7 +817,7 @@ impl StewardState { config, first_slot, clock.epoch as u16, - tvc_activation_epoch, + TVC_ACTIVATION_EPOCH, )?; self.instant_unstake diff --git a/tests/src/steward_fixtures.rs b/tests/src/steward_fixtures.rs index 65d53e61..d68108ee 100644 --- a/tests/src/steward_fixtures.rs +++ b/tests/src/steward_fixtures.rs @@ -30,8 +30,10 @@ use spl_stake_pool::{ state::{Fee, StakeStatus, ValidatorList as SPLValidatorList, ValidatorStakeInfo}, }; use validator_history::{ - self, constants::MAX_ALLOC_BYTES, CircBuf, CircBufCluster, ClusterHistory, ClusterHistoryEntry, - ValidatorHistory, ValidatorHistoryEntry, + self, + constants::{MAX_ALLOC_BYTES, TVC_MULTIPLIER}, + CircBuf, CircBufCluster, ClusterHistory, ClusterHistoryEntry, ValidatorHistory, + ValidatorHistoryEntry, }; pub struct StakePoolMetadata { @@ -881,12 +883,18 @@ impl Default for StateMachineFixtures { let vote_account_2 = Pubkey::new_unique(); let vote_account_3 = Pubkey::new_unique(); + //////// + //////// + //////// TODO: update the vote credits to 8x higher here + //////// + //////// + // First one: Good validator let mut validator_history_1 = validator_history_default(vote_account_1, 0); for i in 0..=20 { validator_history_1.history.push(ValidatorHistoryEntry { epoch: i, - epoch_credits: 1000, + epoch_credits: 1000 * TVC_MULTIPLIER, commission: 0, mev_commission: 0, is_superminority: 0, @@ -900,7 +908,7 @@ impl Default for StateMachineFixtures { for i in 0..=20 { validator_history_2.history.push(ValidatorHistoryEntry { epoch: i, - epoch_credits: 200, + epoch_credits: 200 * TVC_MULTIPLIER, commission: 99, mev_commission: 10000, is_superminority: 1, @@ -914,7 +922,7 @@ impl Default for StateMachineFixtures { for i in 0..=20 { validator_history_3.history.push(ValidatorHistoryEntry { epoch: i, - epoch_credits: 1000, + epoch_credits: 1000 * TVC_MULTIPLIER, commission: 5, mev_commission: 500, is_superminority: 0, diff --git a/tests/tests/steward/test_algorithms.rs b/tests/tests/steward/test_algorithms.rs index 2b07210b..c165c389 100644 --- a/tests/tests/steward/test_algorithms.rs +++ b/tests/tests/steward/test_algorithms.rs @@ -1,7 +1,7 @@ // Unit tests for scoring, instant unstake, and delegation methods use anchor_lang::AnchorSerialize; use jito_steward::{ - constants::{EPOCH_DEFAULT, SORTED_INDEX_DEFAULT}, + constants::{EPOCH_DEFAULT, SORTED_INDEX_DEFAULT, TVC_ACTIVATION_EPOCH}, delegation::{ decrease_stake_calculation, increase_stake_calculation, RebalanceType, UnstakeState, }, @@ -17,7 +17,7 @@ use jito_steward::{ use solana_sdk::native_token::LAMPORTS_PER_SOL; use spl_stake_pool::big_vec::BigVec; use tests::steward_fixtures::StateMachineFixtures; -use validator_history::{ClusterHistoryEntry, ValidatorHistoryEntry}; +use validator_history::{constants::TVC_MULTIPLIER, ClusterHistoryEntry, ValidatorHistoryEntry}; #[test] fn test_compute_score() { @@ -40,6 +40,7 @@ fn test_compute_score() { &cluster_history, &config, current_epoch as u16, + TVC_ACTIVATION_EPOCH, ) .unwrap(); assert_eq!( @@ -75,8 +76,14 @@ fn test_compute_score() { let mut validator = good_validator; validator.history.last_mut().unwrap().mev_commission = 1001; - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -108,8 +115,14 @@ fn test_compute_score() { let mut validator = good_validator; validator.history.arr[11].mev_commission = 1001; - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -141,8 +154,14 @@ fn test_compute_score() { // Test high mev commission outside of range let mut validator = good_validator; validator.history.arr[9].mev_commission = 1001; - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -178,8 +197,14 @@ fn test_compute_score() { .validator_history_blacklist .set(validator.index as usize, true) .unwrap(); - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -213,8 +238,14 @@ fn test_compute_score() { // superminority score let mut validator = good_validator; validator.history.last_mut().unwrap().is_superminority = 1; - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -249,8 +280,14 @@ fn test_compute_score() { for i in 0..19 { validator.history.arr_mut()[i].is_superminority = 1; } - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -286,8 +323,14 @@ fn test_compute_score() { validator.history.arr_mut()[i].mev_commission = ValidatorHistoryEntry::default().mev_commission; } - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -320,8 +363,14 @@ fn test_compute_score() { // commission let mut validator = good_validator; validator.history.last_mut().unwrap().commission = 11; - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -362,8 +411,14 @@ fn test_compute_score() { // commission above regular threshold, below historical threshold, outside of regular threshold window validator.history.arr[0].commission = 14; - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -394,8 +449,14 @@ fn test_compute_score() { ); validator.history.arr[0].commission = 16; - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -430,11 +491,17 @@ fn test_compute_score() { // average vote credits + average blocks for i in 0..=20 { - validator.history.arr_mut()[i].epoch_credits = 880; + validator.history.arr_mut()[i].epoch_credits = 880 * TVC_MULTIPLIER; cluster_history.history.arr_mut()[i].total_blocks = 1000; } - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -467,8 +534,14 @@ fn test_compute_score() { // delinquency let mut validator = good_validator; validator.history.arr[10].epoch_credits = 0; - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -506,8 +579,14 @@ fn test_compute_score() { cluster_history.history.arr[10].total_blocks = ClusterHistoryEntry::default().total_blocks; cluster_history.history.arr[11].total_blocks = ClusterHistoryEntry::default().total_blocks; - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -543,8 +622,14 @@ fn test_compute_score() { assert_eq!(current_epoch, 20); validator.history.arr[current_epoch as usize].epoch_credits = 0; cluster_history.history.arr[current_epoch as usize].total_blocks = 0; - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert_eq!( components, ScoreComponentsV2 { @@ -587,15 +672,27 @@ fn test_compute_score() { validator.history.arr[current_epoch as usize - 2].is_superminority = ValidatorHistoryEntry::default().is_superminority; validator.history.arr[current_epoch as usize - 3].is_superminority = 1; - let components = - validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); + let components = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ) + .unwrap(); assert!(components.superminority_score == 0.0); // Test error: superminority should exist if epoch credits exist let mut validator = good_validator; validator.history.arr[current_epoch as usize].is_superminority = ValidatorHistoryEntry::default().is_superminority; - let res = validator_score(&validator, &cluster_history, &config, current_epoch as u16); + let res = validator_score( + &validator, + &cluster_history, + &config, + current_epoch as u16, + TVC_ACTIVATION_EPOCH, + ); assert!(res == Err(StewardError::StakeHistoryNotRecentEnough.into())); } @@ -631,6 +728,7 @@ fn test_instant_unstake() { &config, start_slot, current_epoch, + TVC_ACTIVATION_EPOCH, ); assert!(res.is_ok()); @@ -645,7 +743,7 @@ fn test_instant_unstake() { vote_account: good_validator.vote_account, epoch: current_epoch, details: InstantUnstakeDetails { - epoch_credits_latest: 1000, + epoch_credits_latest: 1000 * (TVC_MULTIPLIER as u64), vote_account_last_update_slot: start_slot + 999, total_blocks_latest: 1000, cluster_history_slot_index: 999, @@ -666,6 +764,7 @@ fn test_instant_unstake() { &config, start_slot, current_epoch, + TVC_ACTIVATION_EPOCH, ); assert!(res.is_ok()); @@ -680,7 +779,7 @@ fn test_instant_unstake() { vote_account: good_validator.vote_account, epoch: current_epoch, details: InstantUnstakeDetails { - epoch_credits_latest: 1000, + epoch_credits_latest: 1000 * (TVC_MULTIPLIER as u64), vote_account_last_update_slot: start_slot + 999, total_blocks_latest: 1000, cluster_history_slot_index: 999, @@ -698,6 +797,7 @@ fn test_instant_unstake() { &config, start_slot, current_epoch, + TVC_ACTIVATION_EPOCH, ); assert!(res.is_ok()); @@ -712,7 +812,7 @@ fn test_instant_unstake() { vote_account: bad_validator.vote_account, epoch: current_epoch, details: InstantUnstakeDetails { - epoch_credits_latest: 200, + epoch_credits_latest: 200 * (TVC_MULTIPLIER as u64), vote_account_last_update_slot: start_slot + 999, total_blocks_latest: 1000, cluster_history_slot_index: 999, @@ -732,6 +832,7 @@ fn test_instant_unstake() { &config, start_slot, current_epoch, + TVC_ACTIVATION_EPOCH, ); assert_eq!(res, Err(StewardError::ClusterHistoryNotRecentEnough.into())); @@ -747,6 +848,7 @@ fn test_instant_unstake() { &config, start_slot, current_epoch, + TVC_ACTIVATION_EPOCH, ); assert!(res.is_ok()); @@ -784,6 +886,7 @@ fn test_instant_unstake() { &config, start_slot, current_epoch, + TVC_ACTIVATION_EPOCH, ); assert_eq!(res, Err(StewardError::VoteHistoryNotRecentEnough.into())); @@ -797,6 +900,7 @@ fn test_instant_unstake() { &config, start_slot, current_epoch, + TVC_ACTIVATION_EPOCH, ); assert!(res.is_ok()); assert_eq!( @@ -810,7 +914,7 @@ fn test_instant_unstake() { vote_account: validator.vote_account, epoch: current_epoch, details: InstantUnstakeDetails { - epoch_credits_latest: 1000, + epoch_credits_latest: 1000 * (TVC_MULTIPLIER as u64), vote_account_last_update_slot: start_slot + 999, total_blocks_latest: 1000, cluster_history_slot_index: 999, @@ -829,6 +933,7 @@ fn test_instant_unstake() { &config, start_slot, current_epoch, + TVC_ACTIVATION_EPOCH, ); assert!(res.is_ok()); assert_eq!( @@ -842,7 +947,7 @@ fn test_instant_unstake() { vote_account: validator.vote_account, epoch: current_epoch, details: InstantUnstakeDetails { - epoch_credits_latest: 1000, + epoch_credits_latest: 1000 * (TVC_MULTIPLIER as u64), vote_account_last_update_slot: start_slot + 999, total_blocks_latest: 1000, cluster_history_slot_index: 999, @@ -861,6 +966,7 @@ fn test_instant_unstake() { &config, start_slot, current_epoch, + TVC_ACTIVATION_EPOCH, ); assert!(res.is_ok()); assert_eq!( @@ -874,7 +980,7 @@ fn test_instant_unstake() { vote_account: good_validator.vote_account, epoch: current_epoch, details: InstantUnstakeDetails { - epoch_credits_latest: 1000, + epoch_credits_latest: 1000 * (TVC_MULTIPLIER as u64), vote_account_last_update_slot: start_slot + 999, total_blocks_latest: 0, cluster_history_slot_index: 999, diff --git a/tests/tests/steward/test_integration.rs b/tests/tests/steward/test_integration.rs index 469f114d..e073636c 100644 --- a/tests/tests/steward/test_integration.rs +++ b/tests/tests/steward/test_integration.rs @@ -27,8 +27,8 @@ use tests::steward_fixtures::{ validator_history_default, TestFixture, }; use validator_history::{ - ClusterHistory, ClusterHistoryEntry, Config as ValidatorHistoryConfig, ValidatorHistory, - ValidatorHistoryEntry, + constants::TVC_MULTIPLIER, ClusterHistory, ClusterHistoryEntry, + Config as ValidatorHistoryConfig, ValidatorHistory, ValidatorHistoryEntry, }; #[tokio::test] @@ -198,7 +198,7 @@ async fn test_compute_scores() { for i in 0..=512 { validator_history.history.push(ValidatorHistoryEntry { epoch: i, - epoch_credits: 1000, + epoch_credits: 1000 * TVC_MULTIPLIER, activated_stake_lamports: 100_000_000_000_000, commission: 0, mev_commission: 0, @@ -343,10 +343,10 @@ async fn test_compute_scores() { steward_state_account.state.state_tag, StewardStateEnum::ComputeScores )); - assert!(steward_state_account.state.scores[0] == 1_000_000_000); - assert!(steward_state_account.state.yield_scores[0] == 1_000_000_000); - assert!(steward_state_account.state.sorted_score_indices[0] == 0); - assert!(steward_state_account.state.sorted_yield_score_indices[0] == 0); + assert_eq!(steward_state_account.state.scores[0], 1_000_000_000); + assert_eq!(steward_state_account.state.yield_scores[0], 1_000_000_000); + assert_eq!(steward_state_account.state.sorted_score_indices[0], 0); + assert_eq!(steward_state_account.state.sorted_yield_score_indices[0], 0); assert!(steward_state_account.state.progress.get(0).unwrap()); assert!(!steward_state_account.state.progress.get(1).unwrap()); @@ -515,7 +515,7 @@ async fn test_compute_instant_unstake() { let mut validator_history = validator_history_default(vote_account, 0); validator_history.history.push(ValidatorHistoryEntry { epoch: clock.epoch as u16, - epoch_credits: 1000, + epoch_credits: 1000 * TVC_MULTIPLIER, activated_stake_lamports: 100_000_000_000_000, commission: 100, // This is the condition causing instant unstake mev_commission: 0, diff --git a/tests/tests/steward/test_scoring.rs b/tests/tests/steward/test_scoring.rs index 43af59b1..3a5b2ca3 100644 --- a/tests/tests/steward/test_scoring.rs +++ b/tests/tests/steward/test_scoring.rs @@ -125,12 +125,17 @@ mod test_calculate_mev_commission { mod test_calculate_epoch_credits { use jito_steward::constants::EPOCH_DEFAULT; + use validator_history::constants::TVC_MULTIPLIER; use super::*; #[test] fn test_normal() { - let epoch_credits = [Some(800), Some(800), Some(800)]; + let epoch_credits = [ + Some(800 * TVC_MULTIPLIER), + Some(800 * TVC_MULTIPLIER), + Some(800 * TVC_MULTIPLIER), + ]; let total_blocks = [Some(1000), Some(1000), Some(1000)]; let epoch_start = 0; let threshold = 0.9; @@ -147,7 +152,11 @@ mod test_calculate_epoch_credits { #[test] fn test_edge_cases() { // Delinquency detected - let epoch_credits = [Some(700), Some(800), Some(850)]; + let epoch_credits = [ + Some(700 * TVC_MULTIPLIER), + Some(800 * TVC_MULTIPLIER), + Some(850 * TVC_MULTIPLIER), + ]; let total_blocks = [Some(1000), Some(1000), Some(1000)]; let (_ratio, delinquency_score, delinquency_ratio, delinquency_epoch) = calculate_epoch_credits(&epoch_credits, &total_blocks, 0, 0.9).unwrap(); @@ -156,7 +165,7 @@ mod test_calculate_epoch_credits { assert_eq!(delinquency_epoch, 0); // Missing data - let epoch_credits = [None, Some(800), Some(900)]; + let epoch_credits = [None, Some(800 * TVC_MULTIPLIER), Some(900 * TVC_MULTIPLIER)]; let total_blocks = [Some(1000), None, Some(1000)]; let (ratio, delinquency_score, delinquency_ratio, delinquency_epoch) = calculate_epoch_credits(&epoch_credits, &total_blocks, 0, 0.9).unwrap(); @@ -166,7 +175,11 @@ mod test_calculate_epoch_credits { assert_eq!(delinquency_epoch, 0); // No delinquent epochs - let epoch_credits = [Some(800), Some(900), Some(1000)]; + let epoch_credits = [ + Some(800 * TVC_MULTIPLIER), + Some(900 * TVC_MULTIPLIER), + Some(1000 * TVC_MULTIPLIER), + ]; let total_blocks = [Some(1000), Some(1000), Some(1000)]; let (ratio, delinquency_score, delinquency_ratio, delinquency_epoch) = calculate_epoch_credits(&epoch_credits, &total_blocks, 0, 0.7).unwrap(); @@ -182,7 +195,7 @@ mod test_calculate_epoch_credits { assert!(result.is_err()); // Test Arithmetic error - let epoch_credits = [Some(1), Some(0)]; + let epoch_credits = [Some(TVC_MULTIPLIER), Some(0)]; let total_blocks = [Some(1), Some(1)]; let result = calculate_epoch_credits(&epoch_credits, &total_blocks, u16::MAX, 0.9); assert!(result.is_err()); @@ -426,13 +439,15 @@ mod test_calculate_blacklist { } mod test_calculate_instant_unstake_delinquency { + use validator_history::constants::TVC_MULTIPLIER; + use super::*; #[test] fn test_normal() { let total_blocks_latest = 1000; let cluster_history_slot_index = 1000; - let epoch_credits_latest = 900; + let epoch_credits_latest = 900 * TVC_MULTIPLIER; let validator_history_slot_index = 1000; let threshold = 0.8; @@ -454,12 +469,33 @@ mod test_calculate_instant_unstake_delinquency { #[test] fn test_edge_cases() { + let total_blocks_latest = 0; + let cluster_history_slot_index = 1000; + let epoch_credits_latest = 900 * TVC_MULTIPLIER; + let validator_history_slot_index = 1000; + let threshold = 0.8; + // Zero blocks produced - let result = calculate_instant_unstake_delinquency(0, 1000, 900, 1000, 0.8).unwrap(); + let result = calculate_instant_unstake_delinquency( + total_blocks_latest, + cluster_history_slot_index, + epoch_credits_latest, + validator_history_slot_index, + threshold, + ) + .unwrap(); assert!(!result); // Zero slots - let result = calculate_instant_unstake_delinquency(1000, 0, 900, 1000, 0.8); + let total_blocks_latest = 1000; + let cluster_history_slot_index = 0; + let result = calculate_instant_unstake_delinquency( + total_blocks_latest, + cluster_history_slot_index, + epoch_credits_latest, + validator_history_slot_index, + threshold, + ); assert!(result.is_err()); } } From efd0bcdc286cb07e1a578fe107c3564cf6eabe01 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Tue, 3 Dec 2024 18:55:45 -0500 Subject: [PATCH 03/11] tests for new epoch credits methods --- tests/tests/validator_history/mod.rs | 2 + tests/tests/validator_history/test_state.rs | 74 +++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 tests/tests/validator_history/test_state.rs diff --git a/tests/tests/validator_history/mod.rs b/tests/tests/validator_history/mod.rs index 1ac5cac7..b801bd03 100644 --- a/tests/tests/validator_history/mod.rs +++ b/tests/tests/validator_history/mod.rs @@ -4,3 +4,5 @@ mod test_initialize; mod test_mev_commission; mod test_stake; mod test_vote_account; + +mod test_state; diff --git a/tests/tests/validator_history/test_state.rs b/tests/tests/validator_history/test_state.rs new file mode 100644 index 00000000..9428bc11 --- /dev/null +++ b/tests/tests/validator_history/test_state.rs @@ -0,0 +1,74 @@ + +se validator_history::constants::TVC_MULTIPLIER; +use validator_history::state::CircBuf; +use validator_history::ValidatorHistoryEntry; + +const MAX_ITEMS: usize = 512; +#[test] +fn test_normalized_epoch_credits_latest() { + let mut circ_buf = CircBuf { + idx: 4, + is_empty: 0, + padding: [0; 7], + arr: [ValidatorHistoryEntry::default(); MAX_ITEMS], + }; + + for i in 0..5 { + circ_buf.arr[i] = ValidatorHistoryEntry { + epoch_credits: 1000, + epoch: i as u16, + ..ValidatorHistoryEntry::default() + }; + } + + // Test normalizing an epoch before tvc activation + assert_eq!( + circ_buf.epoch_credits_latest_normalized(3, 4), + Some(1000 * TVC_MULTIPLIER) + ); + + // Test normalizing an epoch after tvc activation + assert_eq!(circ_buf.epoch_credits_latest_normalized(3, 3), Some(1000)); +} + +#[test] +fn test_epoch_credits_range_normalized() { + let mut circ_buf = CircBuf { + idx: 4, + is_empty: 0, + padding: [0; 7], + arr: [ValidatorHistoryEntry::default(); MAX_ITEMS], + }; + + for i in 0..5 { + circ_buf.arr[i] = ValidatorHistoryEntry { + epoch_credits: 1000, + epoch: i as u16, + ..ValidatorHistoryEntry::default() + }; + } + + // Test normalizing epochs before tvc activation + assert_eq!( + circ_buf.epoch_credits_range_normalized(0, 4, 5), + vec![ + Some(1000 * TVC_MULTIPLIER), + Some(1000 * TVC_MULTIPLIER), + Some(1000 * TVC_MULTIPLIER), + Some(1000 * TVC_MULTIPLIER), + Some(1000 * TVC_MULTIPLIER) + ] + ); + + // Test normalizing epochs with tvc activation in middle of range + assert_eq!( + circ_buf.epoch_credits_range_normalized(0, 4, 2), + vec![ + Some(1000 * TVC_MULTIPLIER), + Some(1000 * TVC_MULTIPLIER), + Some(1000), + Some(1000), + Some(1000) + ] + ); +} From ec11cd24f7c817cd0f92213f8fca8f4ebda45fb0 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Tue, 3 Dec 2024 19:00:26 -0500 Subject: [PATCH 04/11] Fix --- tests/tests/validator_history/test_state.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/tests/validator_history/test_state.rs b/tests/tests/validator_history/test_state.rs index 9428bc11..b5f5eeb6 100644 --- a/tests/tests/validator_history/test_state.rs +++ b/tests/tests/validator_history/test_state.rs @@ -1,5 +1,4 @@ - -se validator_history::constants::TVC_MULTIPLIER; +use validator_history::constants::TVC_MULTIPLIER; use validator_history::state::CircBuf; use validator_history::ValidatorHistoryEntry; From 2b40b30b1d2e8701131615f9fc2f23c3f199afcb Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Wed, 4 Dec 2024 14:57:29 -0500 Subject: [PATCH 05/11] pin solana-verify --- .github/workflows/build.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index dbc46776..826c60f7 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -75,6 +75,7 @@ jobs: uses: baptiste0928/cargo-install@v3 with: crate: solana-verify + version: "0.2.4" - name: Install anchor-cli from crates.io uses: baptiste0928/cargo-install@v3 with: From 4ab838d9ed2f180b29ba593f04139e56d400c3b7 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Wed, 4 Dec 2024 15:05:28 -0500 Subject: [PATCH 06/11] asdf --- .github/workflows/build.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 826c60f7..f8165fd6 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -75,7 +75,7 @@ jobs: uses: baptiste0928/cargo-install@v3 with: crate: solana-verify - version: "0.2.4" + version: "0.2.14" - name: Install anchor-cli from crates.io uses: baptiste0928/cargo-install@v3 with: @@ -157,7 +157,7 @@ jobs: env: RUST_LOG: trace SBF_OUT_DIR: ${{ github.workspace }}/target/deploy - RUST_MIN_STACK: 5000000 + RUST_MIN_STACK: 10000000 # release only runs on tagged commits # it should wait for all the other steps to finish, to ensure releases are the highest quality From 1f0032f2765ba4443614e028c5d37e12f5cd33fb Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Wed, 4 Dec 2024 15:13:59 -0500 Subject: [PATCH 07/11] pls 2 --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index f8165fd6..f25d2d46 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -75,7 +75,7 @@ jobs: uses: baptiste0928/cargo-install@v3 with: crate: solana-verify - version: "0.2.14" + version: "0.2.11" - name: Install anchor-cli from crates.io uses: baptiste0928/cargo-install@v3 with: From 886ce5b97f83db2e36fa292cc581ffc5c649cce9 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Wed, 4 Dec 2024 15:44:39 -0500 Subject: [PATCH 08/11] asdf --- programs/steward/src/constants.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/steward/src/constants.rs b/programs/steward/src/constants.rs index 1dd6cddb..1eebf2b9 100644 --- a/programs/steward/src/constants.rs +++ b/programs/steward/src/constants.rs @@ -22,7 +22,7 @@ pub const VALIDATOR_HISTORY_FIRST_RELIABLE_EPOCH: u64 = 520; pub const VALIDATOR_HISTORY_FIRST_RELIABLE_EPOCH: u64 = 0; pub const TVC_FEATURE_PUBKEY: &str = "tvcF6b1TRz353zKuhBjinZkKzjmihXmBAHJdjNYw1sQ"; #[cfg(feature = "mainnet-beta")] -pub const TVC_ACTIVATION_EPOCH: u64 = 704; +pub const TVC_ACTIVATION_EPOCH: u64 = 703; #[cfg(all(not(feature = "mainnet-beta"), feature = "testnet"))] pub const TVC_ACTIVATION_EPOCH: u64 = 705; #[cfg(all(not(feature = "mainnet-beta"), not(feature = "testnet")))] From 215de94cb02394f3b7d40d53c66ed01fc5f562da Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Fri, 6 Dec 2024 19:07:06 -0500 Subject: [PATCH 09/11] Fix TVC multiplier --- programs/validator-history/src/constants.rs | 2 +- programs/validator-history/src/state.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/validator-history/src/constants.rs b/programs/validator-history/src/constants.rs index 4469f1a0..6aac1fe3 100644 --- a/programs/validator-history/src/constants.rs +++ b/programs/validator-history/src/constants.rs @@ -1,3 +1,3 @@ pub const MAX_ALLOC_BYTES: usize = 10240; pub const MIN_VOTE_EPOCHS: usize = 5; -pub const TVC_MULTIPLIER: u32 = 8; +pub const TVC_MULTIPLIER: u32 = 16; diff --git a/programs/validator-history/src/state.rs b/programs/validator-history/src/state.rs index 454c0e65..545af6e8 100644 --- a/programs/validator-history/src/state.rs +++ b/programs/validator-history/src/state.rs @@ -275,7 +275,7 @@ impl CircBuf { field_latest!(self, epoch_credits) } - /// Normalized epoch credits, accounting for Timely Vote Credits making the max number of credits 8x higher + /// Normalized epoch credits, accounting for Timely Vote Credits making the max number of credits 16x higher /// for every epoch starting at `tvc_activation_epoch` pub fn epoch_credits_latest_normalized( &self, From aea9390a49e6f6a8a0cbe01c04d93e64be7ef6c8 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Fri, 6 Dec 2024 20:04:31 -0500 Subject: [PATCH 10/11] Compiling --- tests/src/steward_fixtures.rs | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/tests/src/steward_fixtures.rs b/tests/src/steward_fixtures.rs index 17bf4418..6296fe75 100644 --- a/tests/src/steward_fixtures.rs +++ b/tests/src/steward_fixtures.rs @@ -1781,28 +1781,26 @@ impl Default for StateMachineFixtures { }; // Setup Sysvars: Clock, EpochSchedule - let epoch_schedule = EpochSchedule::default(); - let clock = Clock { epoch: current_epoch, slot: epoch_schedule.get_last_slot_in_epoch(current_epoch), ..Clock::default() }; - // Setup ValidatorHistory accounts + // Setup vote account addresses let vote_account_1 = Pubkey::new_unique(); let vote_account_2 = Pubkey::new_unique(); let vote_account_3 = Pubkey::new_unique(); // First one: Good validator - let mut validator_history_1 = validator_history_default(vote_address_1, 0); + let mut validator_history_1 = validator_history_default(vote_account_1, 0); let mut epoch_credits: Vec<(u64, u64, u64)> = vec![]; for i in 0..=20 { epoch_credits.push((i, (i + 1) * 1000, i * 1000)); validator_history_1.history.push(ValidatorHistoryEntry { - epoch: i, + epoch: i as u16, epoch_credits: 1000 * TVC_MULTIPLIER, commission: 0, mev_commission: 0, @@ -1812,17 +1810,17 @@ impl Default for StateMachineFixtures { ..ValidatorHistoryEntry::default() }); } - let vote_account_1 = - new_vote_state_versions(vote_address_1, vote_address_1, 0, Some(epoch_credits)); + let vote_account_1_state = + new_vote_state_versions(vote_account_1, vote_account_1, 0, Some(epoch_credits)); // Second one: Bad validator - let mut validator_history_2 = validator_history_default(vote_address_2, 1); + let mut validator_history_2 = validator_history_default(vote_account_2, 1); let mut epoch_credits: Vec<(u64, u64, u64)> = vec![]; for i in 0..=20 { epoch_credits.push((i, (i + 1) * 200, i * 200)); validator_history_2.history.push(ValidatorHistoryEntry { - epoch: i, + epoch: i as u16, epoch_credits: 200 * TVC_MULTIPLIER, commission: 99, mev_commission: 10000, @@ -1832,17 +1830,17 @@ impl Default for StateMachineFixtures { ..ValidatorHistoryEntry::default() }); } - let vote_account_2 = - new_vote_state_versions(vote_address_2, vote_address_2, 99, Some(epoch_credits)); + let vote_account_2_state = + new_vote_state_versions(vote_account_2, vote_account_2, 99, Some(epoch_credits)); // Third one: Good validator - let mut validator_history_3 = validator_history_default(vote_address_3, 2); + let mut validator_history_3 = validator_history_default(vote_account_3, 2); let mut epoch_credits: Vec<(u64, u64, u64)> = vec![]; for i in 0..=20 { epoch_credits.push((i, (i + 1) * 1000, i * 1000)); validator_history_3.history.push(ValidatorHistoryEntry { - epoch: i, + epoch: i as u16, epoch_credits: 1000 * TVC_MULTIPLIER, commission: 5, mev_commission: 500, @@ -1852,8 +1850,8 @@ impl Default for StateMachineFixtures { ..ValidatorHistoryEntry::default() }); } - let vote_account_3 = - new_vote_state_versions(vote_address_3, vote_address_3, 5, Some(epoch_credits)); + let vote_account_3_state = + new_vote_state_versions(vote_account_3, vote_account_3, 5, Some(epoch_credits)); // Setup ClusterHistory let mut cluster_history = cluster_history_default(); @@ -1922,7 +1920,11 @@ impl Default for StateMachineFixtures { validator_history_2, validator_history_3, ], - vote_accounts: vec![vote_account_1, vote_account_2, vote_account_3], + vote_accounts: vec![ + vote_account_1_state, + vote_account_2_state, + vote_account_3_state, + ], cluster_history, config, validator_list, From fbfd5f013620273178df4cff8e06379509544b4d Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Fri, 6 Dec 2024 20:42:42 -0500 Subject: [PATCH 11/11] fix tests --- tests/tests/steward/test_algorithms.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/tests/steward/test_algorithms.rs b/tests/tests/steward/test_algorithms.rs index f506410d..e46d1634 100644 --- a/tests/tests/steward/test_algorithms.rs +++ b/tests/tests/steward/test_algorithms.rs @@ -1,7 +1,9 @@ // Unit tests for scoring, instant unstake, and delegation methods use anchor_lang::AnchorSerialize; use jito_steward::{ - constants::{EPOCH_DEFAULT, LAMPORT_BALANCE_DEFAULT, SORTED_INDEX_DEFAULT, TVC_ACTIVATION_EPOCH}, + constants::{ + EPOCH_DEFAULT, LAMPORT_BALANCE_DEFAULT, SORTED_INDEX_DEFAULT, TVC_ACTIVATION_EPOCH, + }, delegation::{ decrease_stake_calculation, increase_stake_calculation, RebalanceType, UnstakeState, }, @@ -746,7 +748,7 @@ fn test_instant_unstake() { epoch: current_epoch, details: InstantUnstakeDetails { epoch_credits_latest: 1000 * (TVC_MULTIPLIER as u64), - vote_account_last_update_slot: start_slot + 999, + vote_account_last_update_slot: end_slot, total_blocks_latest: 1000, cluster_history_slot_index: slot_index, commission: 0, @@ -782,7 +784,7 @@ fn test_instant_unstake() { epoch: current_epoch, details: InstantUnstakeDetails { epoch_credits_latest: 1000 * (TVC_MULTIPLIER as u64), - vote_account_last_update_slot: start_slot + 999, + vote_account_last_update_slot: end_slot, total_blocks_latest: 1000, cluster_history_slot_index: slot_index, commission: 0, @@ -815,7 +817,7 @@ fn test_instant_unstake() { epoch: current_epoch, details: InstantUnstakeDetails { epoch_credits_latest: 200 * (TVC_MULTIPLIER as u64), - vote_account_last_update_slot: start_slot + 999, + vote_account_last_update_slot: end_slot, total_blocks_latest: 1000, cluster_history_slot_index: slot_index, commission: 99, @@ -917,7 +919,7 @@ fn test_instant_unstake() { epoch: current_epoch, details: InstantUnstakeDetails { epoch_credits_latest: 1000 * (TVC_MULTIPLIER as u64), - vote_account_last_update_slot: start_slot + 999, + vote_account_last_update_slot: end_slot, total_blocks_latest: 1000, cluster_history_slot_index: slot_index, commission: 100, @@ -950,7 +952,7 @@ fn test_instant_unstake() { epoch: current_epoch, details: InstantUnstakeDetails { epoch_credits_latest: 1000 * (TVC_MULTIPLIER as u64), - vote_account_last_update_slot: start_slot + 999, + vote_account_last_update_slot: end_slot, total_blocks_latest: 1000, cluster_history_slot_index: slot_index, commission: 0, @@ -983,7 +985,7 @@ fn test_instant_unstake() { epoch: current_epoch, details: InstantUnstakeDetails { epoch_credits_latest: 1000 * (TVC_MULTIPLIER as u64), - vote_account_last_update_slot: start_slot + 999, + vote_account_last_update_slot: end_slot, total_blocks_latest: 0, cluster_history_slot_index: slot_index, commission: 0,