From 7fa0f34f9ac7b55034062e2593e2823a97b30eed Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Mon, 17 Jun 2024 18:57:14 -0400 Subject: [PATCH 1/2] Logs for rebalance debugging --- programs/steward/src/state/steward_state.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/programs/steward/src/state/steward_state.rs b/programs/steward/src/state/steward_state.rs index 3cf17131..6b1e3f62 100644 --- a/programs/steward/src/state/steward_state.rs +++ b/programs/steward/src/state/steward_state.rs @@ -816,6 +816,12 @@ impl StewardState { .checked_add(stake_rent) .ok_or(StewardError::ArithmeticError)?; + msg!("Reserve lamports before adjustment: {}", reserve_lamports); + msg!( + "Stake pool lamports before adjustment: {}", + stake_pool_lamports + ); + // Maximum increase amount is the total lamports in the reserve stake account minus 2 * stake_rent, which accounts for reserve rent + transient rent // Saturating_sub because reserve stake may be less than 2 * stake_rent, but needs more than 2 * stake_rent to be able to delegate let reserve_lamports = reserve_lamports.saturating_sub( @@ -909,6 +915,15 @@ impl StewardState { RebalanceType::None }; + msg!("Reserve lamports after adjustment: {}", reserve_lamports); + msg!( + "Stake pool lamports after adjustment: {}", + stake_pool_lamports + ); + msg!("Rebalance Type: {:?}", rebalance); + msg!("Current Lamports: {}", current_lamports); + msg!("Target Lamports: {}", target_lamports); + // Update internal state based on rebalance match rebalance { RebalanceType::Decrease(DecreaseComponents { From f5c08dd6b5e1476ff798d8e0f2f7283ac8a8e4b7 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Thu, 27 Jun 2024 13:56:53 -0400 Subject: [PATCH 2/2] Emit more things --- programs/steward/src/delegation.rs | 6 +- .../src/instructions/compute_delegations.rs | 6 +- .../instructions/compute_instant_unstake.rs | 12 ++- .../steward/src/instructions/compute_score.rs | 12 ++- .../steward/src/instructions/rebalance.rs | 93 ++++++++++++++++++- programs/steward/src/state/steward_state.rs | 47 +++++----- 6 files changed, 134 insertions(+), 42 deletions(-) diff --git a/programs/steward/src/delegation.rs b/programs/steward/src/delegation.rs index 2ea078ae..14da68d6 100644 --- a/programs/steward/src/delegation.rs +++ b/programs/steward/src/delegation.rs @@ -1,4 +1,6 @@ +use anchor_lang::idl::*; use anchor_lang::prelude::*; +use borsh::BorshSerialize; use spl_stake_pool::big_vec::BigVec; use crate::{ @@ -7,7 +9,7 @@ use crate::{ StewardState, }; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum RebalanceType { Increase(u64), Decrease(DecreaseComponents), @@ -15,7 +17,7 @@ pub enum RebalanceType { } #[event] -#[derive(Debug, PartialEq, Eq)] +#[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct DecreaseComponents { pub scoring_unstake_lamports: u64, pub instant_unstake_lamports: u64, diff --git a/programs/steward/src/instructions/compute_delegations.rs b/programs/steward/src/instructions/compute_delegations.rs index 33f29b78..482f511a 100644 --- a/programs/steward/src/instructions/compute_delegations.rs +++ b/programs/steward/src/instructions/compute_delegations.rs @@ -41,12 +41,14 @@ pub fn handler(ctx: Context) -> Result<()> { .state .compute_delegations(clock.epoch, &config)?; - maybe_transition_and_emit( + if let Some(event) = maybe_transition_and_emit( &mut state_account.state, &clock, &config.parameters, &epoch_schedule, - )?; + )? { + emit!(event); + } Ok(()) } diff --git a/programs/steward/src/instructions/compute_instant_unstake.rs b/programs/steward/src/instructions/compute_instant_unstake.rs index 75eb282f..89a30c71 100644 --- a/programs/steward/src/instructions/compute_instant_unstake.rs +++ b/programs/steward/src/instructions/compute_instant_unstake.rs @@ -58,21 +58,25 @@ pub fn handler(ctx: Context, validator_list_index: usize) return Err(StewardError::StateMachinePaused.into()); } - state_account.state.compute_instant_unstake( + if let Some(instant_unstake) = state_account.state.compute_instant_unstake( &clock, &epoch_schedule, &validator_history, validator_list_index, &cluster, &config, - )?; + )? { + emit!(instant_unstake); + } - maybe_transition_and_emit( + if let Some(event) = maybe_transition_and_emit( &mut state_account.state, &clock, &config.parameters, &epoch_schedule, - )?; + )? { + emit!(event); + } Ok(()) } diff --git a/programs/steward/src/instructions/compute_score.rs b/programs/steward/src/instructions/compute_score.rs index 53d32d51..00df2b75 100644 --- a/programs/steward/src/instructions/compute_score.rs +++ b/programs/steward/src/instructions/compute_score.rs @@ -84,7 +84,7 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Resul StewardError::InvalidState ); - state_account.state.compute_score( + if let Some(score) = state_account.state.compute_score( &clock, &epoch_schedule, &validator_history, @@ -92,14 +92,18 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Resul &cluster_history, &config, num_pool_validators as u64, - )?; + )? { + emit!(score); + } - maybe_transition_and_emit( + if let Some(event) = maybe_transition_and_emit( &mut state_account.state, &clock, &config.parameters, &epoch_schedule, - )?; + )? { + emit!(event); + } Ok(()) } diff --git a/programs/steward/src/instructions/rebalance.rs b/programs/steward/src/instructions/rebalance.rs index 4f6e0ff6..91c45fef 100644 --- a/programs/steward/src/instructions/rebalance.rs +++ b/programs/steward/src/instructions/rebalance.rs @@ -1,6 +1,8 @@ use std::num::NonZeroU32; use anchor_lang::{ + idl::types::*, + idl::*, prelude::*, solana_program::{ program::invoke_signed, @@ -8,6 +10,7 @@ use anchor_lang::{ system_program, sysvar, vote, }, }; +use borsh::{BorshDeserialize, BorshSerialize}; use spl_pod::solana_program::stake::state::StakeStateV2; use spl_stake_pool::{ find_stake_program_address, find_transient_stake_program_address, minimum_delegation, @@ -17,7 +20,7 @@ use validator_history::ValidatorHistory; use crate::{ constants::STAKE_POOL_WITHDRAW_SEED, - delegation::RebalanceType, + delegation::{DecreaseComponents, RebalanceType}, errors::StewardError, maybe_transition_and_emit, utils::{deserialize_stake_pool, get_stake_pool_address, get_validator_stake_info_at_index}, @@ -193,7 +196,7 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Result<( )? }; - match result { + match result.clone() { RebalanceType::Decrease(decrease_components) => { invoke_signed( &spl_stake_pool::instruction::decrease_validator_stake_with_reserve( @@ -270,12 +273,94 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Result<( RebalanceType::None => {} } - maybe_transition_and_emit( + emit!(rebalance_to_event( + ctx.accounts.vote_account.key(), + clock.epoch as u16, + result + )); + + if let Some(event) = maybe_transition_and_emit( &mut state_account.state, &clock, &config.parameters, &epoch_schedule, - )?; + )? { + emit!(event); + } Ok(()) } + +#[event] +pub struct RebalanceEvent { + pub vote_account: Pubkey, + pub epoch: u16, + pub rebalance_type_tag: RebalanceTypeTag, + pub increase_lamports: u64, + pub decrease_components: DecreaseComponents, +} + +fn rebalance_to_event( + vote_account: Pubkey, + epoch: u16, + rebalance_type: RebalanceType, +) -> RebalanceEvent { + match rebalance_type { + RebalanceType::None => RebalanceEvent { + vote_account, + epoch, + rebalance_type_tag: RebalanceTypeTag::None, + increase_lamports: 0, + decrease_components: DecreaseComponents::default(), + }, + RebalanceType::Increase(lamports) => RebalanceEvent { + vote_account, + epoch, + rebalance_type_tag: RebalanceTypeTag::Increase, + increase_lamports: lamports, + decrease_components: DecreaseComponents::default(), + }, + RebalanceType::Decrease(decrease_components) => RebalanceEvent { + vote_account, + epoch, + rebalance_type_tag: RebalanceTypeTag::Decrease, + increase_lamports: 0, + decrease_components: decrease_components, + }, + } +} + +#[derive(BorshSerialize, BorshDeserialize, Debug)] +pub enum RebalanceTypeTag { + None, + Increase, + Decrease, +} + +impl IdlBuild for RebalanceTypeTag { + fn create_type() -> Option { + Some(IdlTypeDef { + name: "RebalanceTypeTag".to_string(), + ty: IdlTypeDefTy::Enum { + variants: vec![ + IdlEnumVariant { + name: "None".to_string(), + fields: None, + }, + IdlEnumVariant { + name: "Increase".to_string(), + fields: None, + }, + IdlEnumVariant { + name: "Decrease".to_string(), + fields: None, + }, + ], + }, + docs: Default::default(), + generics: Default::default(), + serialization: Default::default(), + repr: Default::default(), + }) + } +} diff --git a/programs/steward/src/state/steward_state.rs b/programs/steward/src/state/steward_state.rs index 6b1e3f62..2b8c538a 100644 --- a/programs/steward/src/state/steward_state.rs +++ b/programs/steward/src/state/steward_state.rs @@ -9,7 +9,9 @@ use crate::{ UnstakeState, }, errors::StewardError, - score::{instant_unstake_validator, validator_score}, + score::{ + instant_unstake_validator, validator_score, InstantUnstakeComponents, ScoreComponents, + }, utils::{epoch_progress, get_target_lamports, stake_lamports_at_validator_list_index, U8Bool}, Config, Parameters, }; @@ -27,11 +29,12 @@ fn invalid_state_error(_expected: String, _actual: String) -> Error { } #[event] +#[derive(Debug)] pub struct StateTransition { - epoch: u64, - slot: u64, - previous_state: String, - new_state: String, + pub epoch: u64, + pub slot: u64, + pub previous_state: String, + pub new_state: String, } pub fn maybe_transition_and_emit( @@ -39,19 +42,19 @@ pub fn maybe_transition_and_emit( clock: &Clock, params: &Parameters, epoch_schedule: &EpochSchedule, -) -> Result<()> { +) -> Result> { let initial_state = steward_state.state_tag.to_string(); steward_state.transition(clock, params, epoch_schedule)?; if initial_state != steward_state.state_tag.to_string() { - emit!(StateTransition { + return Ok(Some(StateTransition { epoch: clock.epoch, slot: clock.slot, previous_state: initial_state, new_state: steward_state.state_tag.to_string(), - }); + })); } - Ok(()) + Ok(None) } /// Tracks state of the stake pool. @@ -542,7 +545,7 @@ impl StewardState { cluster: &ClusterHistory, config: &Config, num_pool_validators: u64, - ) -> Result<()> { + ) -> Result> { if matches!(self.state_tag, StewardStateEnum::ComputeScores) { let current_epoch = clock.epoch; let current_slot = clock.slot; @@ -576,7 +579,7 @@ impl StewardState { // Skip scoring if already processed if self.progress.get(index)? { - return Ok(()); + return Ok(None); } // Skip scoring if marked for deletion @@ -602,7 +605,7 @@ impl StewardState { self.progress.set(index, true)?; - return Ok(()); + return Ok(None); } // Check that latest_update_slot is within the current epoch to guarantee previous epoch data is complete @@ -622,7 +625,6 @@ impl StewardState { } let score = validator_score(validator, index, cluster, config, current_epoch as u16)?; - emit!(score); self.scores[index] = (score.score * 1_000_000_000.) as u32; self.yield_scores[index] = (score.yield_score * 1_000_000_000.) as u32; @@ -645,7 +647,7 @@ impl StewardState { )?; self.progress.set(index, true)?; - return Ok(()); + return Ok(Some(score)); } Err(invalid_state_error( "ComputeScores".to_string(), @@ -705,7 +707,7 @@ impl StewardState { index: usize, cluster: &ClusterHistory, config: &Config, - ) -> Result<()> { + ) -> Result> { if matches!(self.state_tag, StewardStateEnum::ComputeInstantUnstake) { if clock.epoch >= self.next_cycle_epoch { return Err(invalid_state_error( @@ -722,13 +724,13 @@ impl StewardState { // Skip if already processed if self.progress.get(index)? { - return Ok(()); + return Ok(None); } // Skip if marked for deletion if self.validators_to_remove.get(index)? { self.progress.set(index, true)?; - return Ok(()); + return Ok(None); } let first_slot = epoch_schedule.get_first_slot_in_epoch(clock.epoch); @@ -761,11 +763,11 @@ impl StewardState { first_slot, clock.epoch as u16, )?; - emit!(instant_unstake_result); + self.instant_unstake .set(index, instant_unstake_result.instant_unstake)?; self.progress.set(index, true)?; - return Ok(()); + return Ok(Some(instant_unstake_result)); } Err(invalid_state_error( "ComputeInstantUnstake".to_string(), @@ -932,13 +934,6 @@ impl StewardState { stake_deposit_unstake_lamports, total_unstake_lamports, }) => { - emit!(DecreaseComponents { - scoring_unstake_lamports, - instant_unstake_lamports, - stake_deposit_unstake_lamports, - total_unstake_lamports, - }); - self.validator_lamport_balances[index] = self.validator_lamport_balances[index] .saturating_sub(total_unstake_lamports);