From 4facad0eeee3b8f86a34470cce3be330bb65cbf3 Mon Sep 17 00:00:00 2001 From: Coach Chuck <169060940+coachchucksol@users.noreply.github.com> Date: Fri, 28 Jun 2024 10:58:24 -0600 Subject: [PATCH] PROGRAM TWEAKS (#52) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - [x] Separate authorities (blacklist, parameters, admin council: reset, pausing + passthrough?) - [x] Remove staker PDA in favor of State account - [x] Add ValidatorList address to Config so we can validate the list in instructions that don’t pass in the stake pool - [x] Test RemoveValidator for validators that don’t have score computed - [x] Adjust increase_validator_stake reserve_lamports to protect transient stake rent for other accounts - [x] Figure out a better system for persisting blacklist validator indices - [x] Add a check for Deactivate* state at the index marked for removal in epoch_maintenance --------- Co-authored-by: Evan Batsell --- .github/workflows/build.yaml | 2 + Cargo.toml | 2 +- programs/steward/idl/steward.json | 465 ++++++++++-------- programs/steward/src/delegation.rs | 6 +- programs/steward/src/errors.rs | 2 + .../add_validator_to_blacklist.rs | 10 +- .../auto_add_validator_to_pool.rs | 22 +- .../auto_remove_validator_from_pool.rs | 97 ++-- .../instructions/close_steward_accounts.rs | 13 +- .../src/instructions/compute_delegations.rs | 9 +- .../instructions/compute_instant_unstake.rs | 23 +- .../steward/src/instructions/compute_score.rs | 19 +- .../src/instructions/epoch_maintenance.rs | 10 +- programs/steward/src/instructions/idle.rs | 3 - .../src/instructions/initialize_state.rs | 32 -- ...ialize_config.rs => initialize_steward.rs} | 48 +- programs/steward/src/instructions/mod.rs | 6 +- .../steward/src/instructions/pause_steward.rs | 4 +- .../steward/src/instructions/realloc_state.rs | 7 +- .../steward/src/instructions/rebalance.rs | 135 ++++- .../remove_validator_from_blacklist.rs | 13 +- .../src/instructions/reset_steward_state.rs | 4 +- .../src/instructions/resume_steward.rs | 4 +- .../src/instructions/set_new_authority.rs | 77 ++- .../src/instructions/spl_passthrough.rs | 277 +++++------ .../src/instructions/update_parameters.rs | 4 +- programs/steward/src/lib.rs | 27 +- programs/steward/src/score.rs | 12 +- programs/steward/src/state/accounts.rs | 58 ++- programs/steward/src/state/large_bitmask.rs | 104 ++++ programs/steward/src/state/mod.rs | 2 + programs/steward/src/state/steward_state.rs | 85 ++-- programs/steward/src/utils.rs | 23 +- tests/src/steward_fixtures.rs | 48 +- tests/tests/steward/test_algorithms.rs | 196 ++------ tests/tests/steward/test_integration.rs | 53 +- tests/tests/steward/test_parameters.rs | 4 +- tests/tests/steward/test_spl_passthrough.rs | 90 ++-- tests/tests/steward/test_state_methods.rs | 4 +- tests/tests/steward/test_steward.rs | 119 ++++- utils/steward-cli/Cargo.toml | 10 +- .../actions/auto_add_validator_from_pool.rs | 2 - .../auto_remove_validator_from_pool.rs | 2 - .../commands/actions/remove_bad_validators.rs | 5 +- .../commands/cranks/compute_delegations.rs | 1 - .../cranks/compute_instant_unstake.rs | 3 +- .../src/commands/cranks/compute_score.rs | 3 +- utils/steward-cli/src/commands/cranks/idle.rs | 1 - .../src/commands/cranks/rebalance.rs | 6 +- .../src/commands/info/view_config.rs | 32 +- .../src/commands/info/view_state.rs | 4 - .../src/commands/init/init_state.rs | 90 +--- .../init/{init_config.rs => init_steward.rs} | 18 +- utils/steward-cli/src/commands/init/mod.rs | 2 +- utils/steward-cli/src/main.rs | 2 +- utils/steward-cli/src/utils/accounts.rs | 31 +- 56 files changed, 1224 insertions(+), 1107 deletions(-) delete mode 100644 programs/steward/src/instructions/initialize_state.rs rename programs/steward/src/instructions/{initialize_config.rs => initialize_steward.rs} (57%) create mode 100644 programs/steward/src/state/large_bitmask.rs rename utils/steward-cli/src/commands/init/{init_config.rs => init_steward.rs} (83%) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 0cf0cc76..f61fdef7 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -3,11 +3,13 @@ on: push: branches: - master + - steward-test-branch tags: - "v*" pull_request: branches: - master + - steward-test-branch jobs: security_audit: diff --git a/Cargo.toml b/Cargo.toml index d7498e84..af12b8b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,8 +2,8 @@ members = [ "keepers/*", "programs/*", - "utils/*", "tests", + "utils/*", ] [profile.release] diff --git a/programs/steward/idl/steward.json b/programs/steward/idl/steward.json index 37285e0e..57e49a14 100644 --- a/programs/steward/idl/steward.json +++ b/programs/steward/idl/steward.json @@ -35,7 +35,7 @@ ], "args": [ { - "name": "index", + "name": "validator_history_blacklist", "type": "u32" } ] @@ -57,7 +57,7 @@ "name": "config" }, { - "name": "steward_state", + "name": "state_account", "writable": true }, { @@ -67,9 +67,6 @@ "name": "stake_pool", "writable": true }, - { - "name": "staker" - }, { "name": "reserve_stake", "writable": true @@ -107,7 +104,7 @@ "name": "stake_program" }, { - "name": "signer", + "name": "admin", "writable": true, "signer": true } @@ -154,9 +151,6 @@ "name": "stake_pool", "writable": true }, - { - "name": "staker" - }, { "name": "reserve_stake", "writable": true @@ -192,11 +186,6 @@ }, { "name": "stake_program" - }, - { - "name": "signer", - "writable": true, - "signer": true } ], "args": [] @@ -234,9 +223,6 @@ "name": "stake_pool", "writable": true }, - { - "name": "staker" - }, { "name": "reserve_stake", "writable": true @@ -279,11 +265,6 @@ }, { "name": "stake_program" - }, - { - "name": "signer", - "writable": true, - "signer": true } ], "args": [ @@ -314,10 +295,6 @@ { "name": "config" }, - { - "name": "staker", - "writable": true - }, { "name": "state_account", "writable": true @@ -353,11 +330,6 @@ { "name": "state_account", "writable": true - }, - { - "name": "signer", - "writable": true, - "signer": true } ], "args": [] @@ -393,11 +365,6 @@ }, { "name": "cluster_history" - }, - { - "name": "signer", - "writable": true, - "signer": true } ], "args": [ @@ -438,11 +405,6 @@ }, { "name": "cluster_history" - }, - { - "name": "signer", - "writable": true, - "signer": true } ], "args": [ @@ -469,7 +431,7 @@ "name": "config" }, { - "name": "steward_state", + "name": "state_account", "writable": true }, { @@ -485,9 +447,6 @@ { "name": "stake_pool" }, - { - "name": "staker" - }, { "name": "withdraw_authority" }, @@ -524,7 +483,7 @@ "name": "stake_program" }, { - "name": "signer", + "name": "admin", "writable": true, "signer": true } @@ -561,7 +520,7 @@ "name": "config" }, { - "name": "steward_state", + "name": "state_account", "writable": true }, { @@ -575,9 +534,6 @@ "name": "stake_pool", "writable": true }, - { - "name": "staker" - }, { "name": "withdraw_authority" }, @@ -616,7 +572,7 @@ "name": "stake_program" }, { - "name": "signer", + "name": "admin", "writable": true, "signer": true } @@ -693,11 +649,6 @@ { "name": "state_account", "writable": true - }, - { - "name": "signer", - "writable": true, - "signer": true } ], "args": [] @@ -719,7 +670,7 @@ "name": "config" }, { - "name": "steward_state", + "name": "state_account", "writable": true }, { @@ -732,9 +683,6 @@ { "name": "stake_pool" }, - { - "name": "staker" - }, { "name": "withdraw_authority" }, @@ -776,7 +724,7 @@ "name": "stake_program" }, { - "name": "signer", + "name": "admin", "writable": true, "signer": true } @@ -813,7 +761,7 @@ "name": "config" }, { - "name": "steward_state", + "name": "state_account", "writable": true }, { @@ -827,9 +775,6 @@ "name": "stake_pool", "writable": true }, - { - "name": "staker" - }, { "name": "withdraw_authority" }, @@ -871,7 +816,7 @@ "name": "stake_program" }, { - "name": "signer", + "name": "admin", "writable": true, "signer": true } @@ -888,16 +833,16 @@ ] }, { - "name": "initialize_config", + "name": "initialize_steward", "discriminator": [ - 208, - 127, - 21, - 1, - 194, - 190, - 196, - 70 + 195, + 182, + 16, + 84, + 217, + 58, + 220, + 175 ], "accounts": [ { @@ -906,7 +851,7 @@ "signer": true }, { - "name": "staker", + "name": "state_account", "writable": true }, { @@ -920,16 +865,12 @@ "name": "system_program" }, { - "name": "signer", + "name": "current_staker", "writable": true, "signer": true } ], "args": [ - { - "name": "authority", - "type": "pubkey" - }, { "name": "update_parameters_args", "type": { @@ -940,40 +881,6 @@ } ] }, - { - "name": "initialize_state", - "docs": [ - "Creates state account" - ], - "discriminator": [ - 190, - 171, - 224, - 219, - 217, - 72, - 199, - 176 - ], - "accounts": [ - { - "name": "state_account", - "writable": true - }, - { - "name": "config" - }, - { - "name": "system_program" - }, - { - "name": "signer", - "writable": true, - "signer": true - } - ], - "args": [] - }, { "name": "pause_steward", "discriminator": [ @@ -1069,10 +976,6 @@ { "name": "stake_pool" }, - { - "name": "staker", - "writable": true - }, { "name": "withdraw_authority" }, @@ -1115,11 +1018,6 @@ }, { "name": "stake_program" - }, - { - "name": "signer", - "writable": true, - "signer": true } ], "args": [ @@ -1157,7 +1055,7 @@ ], "args": [ { - "name": "index", + "name": "validator_history_blacklist", "type": "u32" } ] @@ -1179,7 +1077,7 @@ "name": "config" }, { - "name": "steward_state", + "name": "state_account", "writable": true }, { @@ -1189,9 +1087,6 @@ "name": "stake_pool", "writable": true }, - { - "name": "staker" - }, { "name": "withdraw_authority" }, @@ -1217,7 +1112,7 @@ "name": "stake_program" }, { - "name": "signer", + "name": "admin", "writable": true, "signer": true } @@ -1312,12 +1207,21 @@ "name": "new_authority" }, { - "name": "authority", + "name": "admin", "writable": true, "signer": true } ], - "args": [] + "args": [ + { + "name": "authority_type", + "type": { + "defined": { + "name": "AuthorityType" + } + } + } + ] }, { "name": "set_preferred_validator", @@ -1335,6 +1239,10 @@ { "name": "config" }, + { + "name": "state_account", + "writable": true + }, { "name": "stake_pool_program" }, @@ -1342,14 +1250,11 @@ "name": "stake_pool", "writable": true }, - { - "name": "staker" - }, { "name": "validator_list" }, { - "name": "signer", + "name": "admin", "writable": true, "signer": true } @@ -1387,6 +1292,10 @@ { "name": "config" }, + { + "name": "state_account", + "writable": true + }, { "name": "stake_pool_program" }, @@ -1394,14 +1303,11 @@ "name": "stake_pool", "writable": true }, - { - "name": "staker" - }, { "name": "new_staker" }, { - "name": "signer", + "name": "admin", "writable": true, "signer": true } @@ -1473,19 +1379,6 @@ 130 ] }, - { - "name": "Staker", - "discriminator": [ - 171, - 229, - 193, - 85, - 67, - 177, - 151, - 4 - ] - }, { "name": "StewardStateAccount", "discriminator": [ @@ -1540,6 +1433,19 @@ 77 ] }, + { + "name": "RebalanceEvent", + "discriminator": [ + 120, + 27, + 117, + 235, + 104, + 42, + 132, + 75 + ] + }, { "name": "ScoreComponents", "discriminator": [ @@ -1570,145 +1476,191 @@ "errors": [ { "code": 6000, + "name": "InvalidAuthorityType", + "msg": "Invalid set authority type: 0: SetAdmin, 1: SetBlacklistAuthority, 2: SetParametersAuthority" + }, + { + "code": 6001, "name": "ScoringNotComplete", "msg": "Scoring must be completed before any other steps can be taken" }, { - "code": 6001, + "code": 6002, "name": "ValidatorNotInList", "msg": "Validator does not exist at the ValidatorList index provided" }, { - "code": 6002, + "code": 6003, "name": "AddValidatorsNotComplete", "msg": "Add validators step must be completed before any other steps can be taken" }, { - "code": 6003, + "code": 6004, "name": "EpochNotOver", "msg": "Cannot reset state before epoch is over" }, { - "code": 6004, + "code": 6005, "name": "Unauthorized", "msg": "Unauthorized to perform this action" }, { - "code": 6005, + "code": 6006, "name": "BitmaskOutOfBounds", "msg": "Bitmask index out of bounds" }, { - "code": 6006, + "code": 6007, "name": "StateNotReset", "msg": "Epoch state not reset" }, { - "code": 6007, + "code": 6008, "name": "ValidatorOutOfRange", "msg": "Validator History created after epoch start, out of range" }, { - "code": 6008, + "code": 6009, "name": "InvalidState" }, { - "code": 6009, + "code": 6010, "name": "ValidatorBelowStakeMinimum", "msg": "Validator not eligible to be added to the pool. Must meet stake minimum" }, { - "code": 6010, + "code": 6011, "name": "ValidatorBelowLivenessMinimum", "msg": "Validator not eligible to be added to the pool. Must meet recent voting minimum" }, { - "code": 6011, + "code": 6012, "name": "VoteHistoryNotRecentEnough", "msg": "Validator History vote data not recent enough to be used for scoring. Must be updated this epoch" }, { - "code": 6012, + "code": 6013, "name": "StakeHistoryNotRecentEnough", "msg": "Validator History stake data not recent enough to be used for scoring. Must be updated this epoch" }, { - "code": 6013, + "code": 6014, "name": "ClusterHistoryNotRecentEnough", "msg": "Cluster History data not recent enough to be used for scoring. Must be updated this epoch" }, { - "code": 6014, + "code": 6015, "name": "StateMachinePaused", "msg": "Steward State Machine is paused. No state machine actions can be taken" }, { - "code": 6015, + "code": 6016, "name": "InvalidParameterValue", "msg": "Config parameter is out of range or otherwise invalid" }, { - "code": 6016, + "code": 6017, "name": "InstantUnstakeNotReady", "msg": "Instant unstake cannot be performed yet." }, { - "code": 6017, + "code": 6018, "name": "ValidatorIndexOutOfBounds", "msg": "Validator index out of bounds of state machine" }, { - "code": 6018, + "code": 6019, "name": "ValidatorListTypeMismatch", "msg": "ValidatorList account type mismatch" }, { - "code": 6019, + "code": 6020, "name": "ArithmeticError", "msg": "An operation caused an overflow/underflow" }, { - "code": 6020, + "code": 6021, "name": "ValidatorNotRemovable", "msg": "Validator not eligible for removal. Must be delinquent or have closed vote account" }, { - "code": 6021, + "code": 6022, "name": "MaxValidatorsReached", "msg": "Max validators reached" }, { - "code": 6022, + "code": 6023, "name": "ValidatorHistoryMismatch", "msg": "Validator history account does not match vote account" }, { - "code": 6023, + "code": 6024, "name": "EpochMaintenanceNotComplete", "msg": "Epoch Maintenance must be called before continuing" }, { - "code": 6024, + "code": 6025, "name": "StakePoolNotUpdated", "msg": "The stake pool must be updated before continuing" }, { - "code": 6025, + "code": 6026, "name": "ValidatorNotMarkedForRemoval", "msg": "Validator not marked for removal" }, { - "code": 6026, + "code": 6027, "name": "ValidatorsHaveNotBeenRemoved", "msg": "Validators have not been removed" }, { - "code": 6027, + "code": 6028, "name": "ListStateMismatch", "msg": "Validator List count does not match state machine" } ], "types": [ + { + "name": "AuthorityType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "SetAdmin", + "fields": [ + { + "name": "SetAdmin", + "type": { + "option": "u8" + } + } + ] + }, + { + "name": "SetBlacklistAuthority", + "fields": [ + { + "name": "SetBlacklistAuthority", + "type": { + "option": "u8" + } + } + ] + }, + { + "name": "SetParameterAuthority", + "fields": [ + { + "name": "SetParameterAuthority", + "type": { + "option": "u8" + } + } + ] + } + ] + } + }, { "name": "BitMask", "docs": [ @@ -1958,20 +1910,49 @@ "type": "pubkey" }, { - "name": "authority", + "name": "validator_list", + "docs": [ + "Validator List" + ], + "type": "pubkey" + }, + { + "name": "admin", + "docs": [ + "Admin", + "- Update the `parameters_authority`", + "- Update the `blacklist_authority`", + "- Can call SPL Passthrough functions", + "- Can pause/reset the state machine" + ], + "type": "pubkey" + }, + { + "name": "parameters_authority", "docs": [ - "Authority for pool stewardship, can execute SPL Staker commands and adjust Delegation parameters" + "Parameters Authority", + "- Can update steward parameters" ], "type": "pubkey" }, { - "name": "blacklist", + "name": "blacklist_authority", "docs": [ - "Bitmask representing index of validators that are not allowed delegation" + "Blacklist Authority", + "- Can add to the blacklist", + "- Can remove from the blacklist" + ], + "type": "pubkey" + }, + { + "name": "validator_history_blacklist", + "docs": [ + "Bitmask representing index of validators that are not allowed delegation", + "NOTE: This is indexed off of the validator history, NOT the validator list" ], "type": { "defined": { - "name": "BitMask" + "name": "LargeBitMask" } } }, @@ -1987,26 +1968,26 @@ } }, { - "name": "_padding", + "name": "paused", "docs": [ - "Padding for future governance parameters" + "Halts any state machine progress" ], "type": { - "array": [ - "u8", - 1023 - ] + "defined": { + "name": "U8Bool" + } } }, { - "name": "paused", + "name": "_padding", "docs": [ - "Halts any state machine progress" + "Padding for future governance parameters" ], "type": { - "defined": { - "name": "U8Bool" - } + "array": [ + "u8", + 1023 + ] } } ] @@ -2107,6 +2088,33 @@ ] } }, + { + "name": "LargeBitMask", + "docs": [ + "Data structure used to efficiently pack a binary array, primarily used to store all validators.", + "Each validator has an index (its index in the spl_stake_pool::ValidatorList), corresponding to a bit in the bitmask.", + "When an operation is executed on a validator, the bit corresponding to that validator's index is set to 1.", + "When all bits are 1, the operation is complete." + ], + "serialization": "bytemuck", + "repr": { + "kind": "c" + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "values", + "type": { + "array": [ + "u64", + 313 + ] + } + } + ] + } + }, { "name": "Parameters", "serialization": "bytemuck", @@ -2269,6 +2277,59 @@ ] } }, + { + "name": "RebalanceEvent", + "type": { + "kind": "struct", + "fields": [ + { + "name": "vote_account", + "type": "pubkey" + }, + { + "name": "epoch", + "type": "u16" + }, + { + "name": "rebalance_type_tag", + "type": { + "defined": { + "name": "RebalanceTypeTag" + } + } + }, + { + "name": "increase_lamports", + "type": "u64" + }, + { + "name": "decrease_components", + "type": { + "defined": { + "name": "DecreaseComponents" + } + } + } + ] + } + }, + { + "name": "RebalanceTypeTag", + "type": { + "kind": "enum", + "variants": [ + { + "name": "None" + }, + { + "name": "Increase" + }, + { + "name": "Decrease" + } + ] + } + }, { "name": "ScoreComponents", "type": { @@ -2356,18 +2417,6 @@ ] } }, - { - "name": "Staker", - "type": { - "kind": "struct", - "fields": [ - { - "name": "bump", - "type": "u8" - } - ] - } - }, { "name": "StateTransition", "type": { 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/errors.rs b/programs/steward/src/errors.rs index 6554baf9..de36d4ad 100644 --- a/programs/steward/src/errors.rs +++ b/programs/steward/src/errors.rs @@ -2,6 +2,8 @@ use anchor_lang::prelude::*; #[error_code] pub enum StewardError { + #[msg("Invalid set authority type: 0: SetAdmin, 1: SetBlacklistAuthority, 2: SetParametersAuthority")] + InvalidAuthorityType, #[msg("Scoring must be completed before any other steps can be taken")] ScoringNotComplete, #[msg("Validator does not exist at the ValidatorList index provided")] diff --git a/programs/steward/src/instructions/add_validator_to_blacklist.rs b/programs/steward/src/instructions/add_validator_to_blacklist.rs index d48774ae..404bee33 100644 --- a/programs/steward/src/instructions/add_validator_to_blacklist.rs +++ b/programs/steward/src/instructions/add_validator_to_blacklist.rs @@ -1,4 +1,4 @@ -use crate::{utils::get_config_authority, Config}; +use crate::{utils::get_config_blacklist_authority, Config}; use anchor_lang::prelude::*; #[derive(Accounts)] @@ -6,14 +6,16 @@ pub struct AddValidatorToBlacklist<'info> { #[account(mut)] pub config: AccountLoader<'info, Config>, - #[account(mut, address = get_config_authority(&config)?)] + #[account(mut, address = get_config_blacklist_authority(&config)?)] pub authority: Signer<'info>, } // Removes ability for validator to receive delegation. Score will be set to 0 and instant unstaking will occur. // Index is the index of the validator from ValidatorHistory. -pub fn handler(ctx: Context, validator_list_index: u32) -> Result<()> { +pub fn handler(ctx: Context, validator_history_index: u32) -> Result<()> { let mut config = ctx.accounts.config.load_mut()?; - config.blacklist.set(validator_list_index as usize, true)?; + config + .validator_history_blacklist + .set(validator_history_index as usize, true)?; Ok(()) } diff --git a/programs/steward/src/instructions/auto_add_validator_to_pool.rs b/programs/steward/src/instructions/auto_add_validator_to_pool.rs index 123e620f..49a57626 100644 --- a/programs/steward/src/instructions/auto_add_validator_to_pool.rs +++ b/programs/steward/src/instructions/auto_add_validator_to_pool.rs @@ -1,6 +1,6 @@ use crate::constants::{MAX_VALIDATORS, STAKE_POOL_WITHDRAW_SEED}; use crate::errors::StewardError; -use crate::state::{Config, Staker, StewardStateAccount}; +use crate::state::{Config, StewardStateAccount}; use crate::utils::{deserialize_stake_pool, get_stake_pool_address}; use anchor_lang::prelude::*; use anchor_lang::solana_program::{program::invoke_signed, stake, sysvar, vote}; @@ -40,12 +40,6 @@ pub struct AutoAddValidator<'info> { )] pub stake_pool: AccountInfo<'info>, - #[account( - seeds = [Staker::SEED, config.key().as_ref()], - bump = staker.bump - )] - pub staker: Account<'info, Staker>, - /// CHECK: passing through, checks are done by spl-stake-pool #[account(mut, address = deserialize_stake_pool(&stake_pool)?.reserve_stake)] pub reserve_stake: AccountInfo<'info>, @@ -98,9 +92,6 @@ pub struct AutoAddValidator<'info> { /// CHECK: passing through, checks are done by spl-stake-pool #[account(address = stake::program::ID)] pub stake_program: AccountInfo<'info>, - - #[account(mut)] - pub signer: Signer<'info>, } /* @@ -156,11 +147,14 @@ pub fn handler(ctx: Context) -> Result<()> { state_account.state.increment_validator_to_add()?; + // Have to drop the state account before calling the CPI + drop(state_account); + invoke_signed( &spl_stake_pool::instruction::add_validator_to_pool( &ctx.accounts.stake_pool_program.key(), &ctx.accounts.stake_pool.key(), - &ctx.accounts.staker.key(), + &ctx.accounts.steward_state.key(), &ctx.accounts.reserve_stake.key(), &ctx.accounts.withdraw_authority.key(), &ctx.accounts.validator_list.key(), @@ -170,7 +164,7 @@ pub fn handler(ctx: Context) -> Result<()> { ), &[ ctx.accounts.stake_pool.to_account_info(), - ctx.accounts.staker.to_account_info(), + ctx.accounts.steward_state.to_account_info(), ctx.accounts.reserve_stake.to_owned(), ctx.accounts.withdraw_authority.to_owned(), ctx.accounts.validator_list.to_account_info(), @@ -184,9 +178,9 @@ pub fn handler(ctx: Context) -> Result<()> { ctx.accounts.stake_program.to_account_info(), ], &[&[ - Staker::SEED, + StewardStateAccount::SEED, &ctx.accounts.config.key().to_bytes(), - &[ctx.accounts.staker.bump], + &[ctx.bumps.steward_state], ]], )?; diff --git a/programs/steward/src/instructions/auto_remove_validator_from_pool.rs b/programs/steward/src/instructions/auto_remove_validator_from_pool.rs index fa4bd358..e18422e4 100644 --- a/programs/steward/src/instructions/auto_remove_validator_from_pool.rs +++ b/programs/steward/src/instructions/auto_remove_validator_from_pool.rs @@ -2,7 +2,7 @@ use std::num::NonZeroU32; use crate::constants::STAKE_POOL_WITHDRAW_SEED; use crate::errors::StewardError; -use crate::state::{Config, Staker}; +use crate::state::Config; use crate::utils::{ deserialize_stake_pool, get_stake_pool_address, get_validator_stake_info_at_index, }; @@ -46,12 +46,6 @@ pub struct AutoRemoveValidator<'info> { )] pub stake_pool: AccountInfo<'info>, - #[account( - seeds = [Staker::SEED, config.key().as_ref()], - bump = staker.bump - )] - pub staker: Account<'info, Staker>, - /// CHECK: passing through, checks are done by spl-stake-pool #[account(mut, address = deserialize_stake_pool(&stake_pool)?.reserve_stake)] pub reserve_stake: AccountInfo<'info>, @@ -123,62 +117,63 @@ pub struct AutoRemoveValidator<'info> { /// CHECK: passing through, checks are done by spl-stake-pool #[account(address = stake::program::ID)] pub stake_program: AccountInfo<'info>, - - #[account(mut)] - pub signer: Signer<'info>, } /* */ pub fn handler(ctx: Context, validator_list_index: usize) -> Result<()> { - let mut state_account = ctx.accounts.state_account.load_mut()?; - let validator_list = &ctx.accounts.validator_list; - let epoch = Clock::get()?.epoch; - - let validator_stake_info = - get_validator_stake_info_at_index(validator_list, validator_list_index)?; - require!( - validator_stake_info.vote_account_address == ctx.accounts.vote_account.key(), - StewardError::ValidatorNotInList - ); - - // Should not be able to remove a validator if update is not complete - require!( - epoch == state_account.state.current_epoch, - StewardError::EpochMaintenanceNotComplete - ); - - // Checks state for deactivate delinquent status, preventing pool from merging stake with activating - let stake_account_deactivated = { - let stake_account_data = &mut ctx.accounts.stake_account.data.borrow_mut(); - let stake_state: StakeStateV2 = - try_from_slice_unchecked::(stake_account_data)?; - - let deactivation_epoch = match stake_state { - StakeStateV2::Stake(_meta, stake, _stake_flags) => stake.delegation.deactivation_epoch, - _ => return Err(StewardError::InvalidState.into()), // TODO fix + { + let mut state_account = ctx.accounts.state_account.load_mut()?; + let validator_list = &ctx.accounts.validator_list; + let epoch = Clock::get()?.epoch; + + let validator_stake_info = + get_validator_stake_info_at_index(validator_list, validator_list_index)?; + require!( + validator_stake_info.vote_account_address == ctx.accounts.vote_account.key(), + StewardError::ValidatorNotInList + ); + + // Should not be able to remove a validator if update is not complete + require!( + epoch == state_account.state.current_epoch, + StewardError::EpochMaintenanceNotComplete + ); + + // Checks state for deactivate delinquent status, preventing pool from merging stake with activating + let stake_account_deactivated = { + let stake_account_data = &mut ctx.accounts.stake_account.data.borrow_mut(); + let stake_state: StakeStateV2 = + try_from_slice_unchecked::(stake_account_data)?; + + let deactivation_epoch = match stake_state { + StakeStateV2::Stake(_meta, stake, _stake_flags) => { + stake.delegation.deactivation_epoch + } + _ => return Err(StewardError::InvalidState.into()), // TODO fix + }; + deactivation_epoch < epoch }; - deactivation_epoch < epoch - }; - // Check if vote account closed - let vote_account_closed = ctx.accounts.vote_account.owner == &system_program::ID; + // Check if vote account closed + let vote_account_closed = ctx.accounts.vote_account.owner == &system_program::ID; - require!( - stake_account_deactivated || vote_account_closed, - StewardError::ValidatorNotRemovable - ); + require!( + stake_account_deactivated || vote_account_closed, + StewardError::ValidatorNotRemovable + ); - state_account - .state - .mark_validator_for_removal(validator_list_index)?; + state_account + .state + .mark_validator_for_removal(validator_list_index)?; + } invoke_signed( &spl_stake_pool::instruction::remove_validator_from_pool( &ctx.accounts.stake_pool_program.key(), &ctx.accounts.stake_pool.key(), - &ctx.accounts.staker.key(), + &ctx.accounts.state_account.key(), &ctx.accounts.withdraw_authority.key(), &ctx.accounts.validator_list.key(), &ctx.accounts.stake_account.key(), @@ -186,7 +181,7 @@ pub fn handler(ctx: Context, validator_list_index: usize) - ), &[ ctx.accounts.stake_pool.to_account_info(), - ctx.accounts.staker.to_account_info(), + ctx.accounts.state_account.to_account_info(), ctx.accounts.reserve_stake.to_owned(), ctx.accounts.withdraw_authority.to_owned(), ctx.accounts.validator_list.to_account_info(), @@ -201,9 +196,9 @@ pub fn handler(ctx: Context, validator_list_index: usize) - ctx.accounts.stake_program.to_account_info(), ], &[&[ - Staker::SEED, + StewardStateAccount::SEED, &ctx.accounts.config.key().to_bytes(), - &[ctx.accounts.staker.bump], + &[ctx.bumps.state_account], ]], )?; diff --git a/programs/steward/src/instructions/close_steward_accounts.rs b/programs/steward/src/instructions/close_steward_accounts.rs index bbf00776..7c561bb8 100644 --- a/programs/steward/src/instructions/close_steward_accounts.rs +++ b/programs/steward/src/instructions/close_steward_accounts.rs @@ -1,7 +1,6 @@ use crate::{ state::{Config, StewardStateAccount}, - utils::get_config_authority, - Staker, + utils::get_config_admin, }; use anchor_lang::prelude::*; @@ -9,14 +8,6 @@ use anchor_lang::prelude::*; pub struct CloseStewardAccounts<'info> { pub config: AccountLoader<'info, Config>, - #[account( - mut, - close = authority, - seeds = [Staker::SEED, config.key().as_ref()], - bump, - )] - staker: Account<'info, Staker>, - #[account( mut, close = authority, @@ -25,7 +16,7 @@ pub struct CloseStewardAccounts<'info> { )] pub state_account: AccountLoader<'info, StewardStateAccount>, - #[account(mut, address = get_config_authority(&config)?)] + #[account(mut, address = get_config_admin(&config)?)] pub authority: Signer<'info>, } diff --git a/programs/steward/src/instructions/compute_delegations.rs b/programs/steward/src/instructions/compute_delegations.rs index 33f29b78..005fe540 100644 --- a/programs/steward/src/instructions/compute_delegations.rs +++ b/programs/steward/src/instructions/compute_delegations.rs @@ -12,9 +12,6 @@ pub struct ComputeDelegations<'info> { bump )] pub state_account: AccountLoader<'info, StewardStateAccount>, - - #[account(mut)] - pub signer: Signer<'info>, } /* @@ -41,12 +38,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..bfb50f44 100644 --- a/programs/steward/src/instructions/compute_instant_unstake.rs +++ b/programs/steward/src/instructions/compute_instant_unstake.rs @@ -1,5 +1,7 @@ use crate::{ - errors::StewardError, maybe_transition_and_emit, utils::get_validator_stake_info_at_index, + errors::StewardError, + maybe_transition_and_emit, + utils::{get_validator_list, get_validator_stake_info_at_index}, Config, StewardStateAccount, }; use anchor_lang::prelude::*; @@ -18,8 +20,8 @@ pub struct ComputeInstantUnstake<'info> { pub validator_history: AccountLoader<'info, ValidatorHistory>, - /// CHECK: TODO add validator list to config - #[account(owner = spl_stake_pool::id())] + #[account(address = get_validator_list(&config)?)] + /// CHECK: We check against the Config pub validator_list: AccountInfo<'info>, #[account( @@ -28,9 +30,6 @@ pub struct ComputeInstantUnstake<'info> { bump )] pub cluster_history: AccountLoader<'info, ClusterHistory>, - - #[account(mut)] - pub signer: Signer<'info>, } pub fn handler(ctx: Context, validator_list_index: usize) -> Result<()> { @@ -58,21 +57,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..585420ae 100644 --- a/programs/steward/src/instructions/compute_score.rs +++ b/programs/steward/src/instructions/compute_score.rs @@ -3,7 +3,7 @@ use anchor_lang::prelude::*; use crate::{ errors::StewardError, maybe_transition_and_emit, - utils::{get_validator_list_length, get_validator_stake_info_at_index}, + utils::{get_validator_list, get_validator_list_length, get_validator_stake_info_at_index}, Config, StewardStateAccount, StewardStateEnum, }; use validator_history::{ClusterHistory, ValidatorHistory}; @@ -22,7 +22,7 @@ pub struct ComputeScore<'info> { pub validator_history: AccountLoader<'info, ValidatorHistory>, /// CHECK: Account owner checked, account type checked in get_validator_stake_info_at_index - #[account(owner = spl_stake_pool::id())] + #[account(address = get_validator_list(&config)?)] pub validator_list: AccountInfo<'info>, #[account( @@ -31,9 +31,6 @@ pub struct ComputeScore<'info> { bump )] pub cluster_history: AccountLoader<'info, ClusterHistory>, - - #[account(mut)] - pub signer: Signer<'info>, } pub fn handler(ctx: Context, validator_list_index: usize) -> Result<()> { @@ -84,7 +81,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 +89,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/epoch_maintenance.rs b/programs/steward/src/instructions/epoch_maintenance.rs index 037ec2d7..ff538c94 100644 --- a/programs/steward/src/instructions/epoch_maintenance.rs +++ b/programs/steward/src/instructions/epoch_maintenance.rs @@ -1,8 +1,8 @@ use crate::{ errors::StewardError, utils::{ - check_validator_list_has_stake_status, deserialize_stake_pool, get_stake_pool_address, - get_validator_list_length, + check_validator_list_has_stake_status_other_than, deserialize_stake_pool, + get_stake_pool_address, get_validator_list_length, }, Config, StewardStateAccount, }; @@ -51,12 +51,13 @@ pub fn handler( if (!state_account.state.checked_validators_removed_from_list).into() { // Ensure there are no validators in the list that have not been removed, that should be require!( - !check_validator_list_has_stake_status( + !check_validator_list_has_stake_status_other_than( &ctx.accounts.validator_list, - StakeStatus::ReadyForRemoval + StakeStatus::Active )?, StewardError::ValidatorsHaveNotBeenRemoved ); + state_account.state.checked_validators_removed_from_list = true.into(); } @@ -74,7 +75,6 @@ pub fn handler( == validators_in_list, StewardError::ListStateMismatch ); - if let Some(validator_index_to_remove) = validator_index_to_remove { state_account .state diff --git a/programs/steward/src/instructions/idle.rs b/programs/steward/src/instructions/idle.rs index 47d594aa..73173e5c 100644 --- a/programs/steward/src/instructions/idle.rs +++ b/programs/steward/src/instructions/idle.rs @@ -14,9 +14,6 @@ pub struct Idle<'info> { bump )] pub state_account: AccountLoader<'info, StewardStateAccount>, - - #[account(mut)] - pub signer: Signer<'info>, } /* diff --git a/programs/steward/src/instructions/initialize_state.rs b/programs/steward/src/instructions/initialize_state.rs deleted file mode 100644 index d637ba84..00000000 --- a/programs/steward/src/instructions/initialize_state.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::{ - constants::MAX_ALLOC_BYTES, - state::{Config, StewardStateAccount}, -}; -use anchor_lang::prelude::*; - -#[derive(Accounts)] -pub struct InitializeState<'info> { - #[account( - init, - payer = signer, - space = MAX_ALLOC_BYTES, - seeds = [StewardStateAccount::SEED, config.key().as_ref()], - bump - )] - pub state_account: AccountLoader<'info, StewardStateAccount>, - - pub config: AccountLoader<'info, Config>, - - pub system_program: Program<'info, System>, - - #[account(mut)] - pub signer: Signer<'info>, -} - -/* -Initializes steward state account, without assigning any values until it has been reallocated to desired size. -Split into multiple instructions due to 10240 byte allocation limit for PDAs. -*/ -pub const fn handler(_ctx: Context) -> Result<()> { - Ok(()) -} diff --git a/programs/steward/src/instructions/initialize_config.rs b/programs/steward/src/instructions/initialize_steward.rs similarity index 57% rename from programs/steward/src/instructions/initialize_config.rs rename to programs/steward/src/instructions/initialize_steward.rs index 12a5ccaa..7c146a0f 100644 --- a/programs/steward/src/instructions/initialize_config.rs +++ b/programs/steward/src/instructions/initialize_steward.rs @@ -1,27 +1,27 @@ use anchor_lang::{prelude::*, solana_program::program::invoke}; -use crate::{utils::deserialize_stake_pool, Config, Staker, UpdateParametersArgs}; +use crate::{ + constants::MAX_ALLOC_BYTES, utils::deserialize_stake_pool, Config, StewardStateAccount, + UpdateParametersArgs, +}; #[derive(Accounts)] -pub struct InitializeConfig<'info> { +pub struct InitializeSteward<'info> { #[account( init, - payer = signer, + payer = current_staker, space = Config::SIZE, )] pub config: AccountLoader<'info, Config>, - // Creates an account that will be used to sign instructions for the stake pool. - // The pool's "staker" keypair needs to be assigned to this address, and it has authority over - // adding validators, removing validators, and delegating stake to validators in the pool. #[account( init, - seeds = [Staker::SEED, config.key().as_ref()], - payer = signer, - space = Staker::SIZE, + payer = current_staker, + space = MAX_ALLOC_BYTES, + seeds = [StewardStateAccount::SEED, config.key().as_ref()], bump )] - pub staker: Account<'info, Staker>, + pub state_account: AccountLoader<'info, StewardStateAccount>, /// CHECK: passing through, checks are done by spl-stake-pool #[account(mut)] @@ -37,19 +37,26 @@ pub struct InitializeConfig<'info> { mut, address = deserialize_stake_pool(&stake_pool)?.staker )] - pub signer: Signer<'info>, + pub current_staker: Signer<'info>, } pub fn handler( - ctx: Context, - authority: Pubkey, + ctx: Context, update_parameters_args: &UpdateParametersArgs, ) -> Result<()> { // Confirm that the stake pool is valid - let _ = deserialize_stake_pool(&ctx.accounts.stake_pool)?; + let stake_pool_account = deserialize_stake_pool(&ctx.accounts.stake_pool)?; let mut config = ctx.accounts.config.load_init()?; + + // Set the stake pool information config.stake_pool = ctx.accounts.stake_pool.key(); - config.authority = authority; + config.validator_list = stake_pool_account.validator_list; + + // Set all authorities to the current_staker + let admin = ctx.accounts.current_staker.key(); + config.admin = admin; + config.blacklist_authority = admin; + config.parameters_authority = admin; // Set Initial Parameters let max_slots_in_epoch = EpochSchedule::get()?.slots_per_epoch; @@ -63,19 +70,18 @@ pub fn handler( config.parameters = initial_parameters; - // Set the staker account - ctx.accounts.staker.bump = ctx.bumps.staker; + // The staker is the state account invoke( &spl_stake_pool::instruction::set_staker( &ctx.accounts.stake_pool_program.key(), &ctx.accounts.stake_pool.key(), - &ctx.accounts.signer.key(), - &ctx.accounts.staker.key(), + &ctx.accounts.current_staker.key(), + &ctx.accounts.state_account.key(), ), &[ ctx.accounts.stake_pool.to_account_info(), - ctx.accounts.signer.to_account_info(), - ctx.accounts.staker.to_account_info(), + ctx.accounts.current_staker.to_account_info(), + ctx.accounts.state_account.to_account_info(), ], )?; Ok(()) diff --git a/programs/steward/src/instructions/mod.rs b/programs/steward/src/instructions/mod.rs index ad9c7c2c..fdef8aa5 100644 --- a/programs/steward/src/instructions/mod.rs +++ b/programs/steward/src/instructions/mod.rs @@ -8,8 +8,7 @@ pub mod compute_instant_unstake; pub mod compute_score; pub mod epoch_maintenance; pub mod idle; -pub mod initialize_config; -pub mod initialize_state; +pub mod initialize_steward; pub mod pause_steward; pub mod realloc_state; pub mod rebalance; @@ -29,8 +28,7 @@ pub use compute_instant_unstake::*; pub use compute_score::*; pub use epoch_maintenance::*; pub use idle::*; -pub use initialize_config::*; -pub use initialize_state::*; +pub use initialize_steward::*; pub use pause_steward::*; pub use realloc_state::*; pub use rebalance::*; diff --git a/programs/steward/src/instructions/pause_steward.rs b/programs/steward/src/instructions/pause_steward.rs index 9d7f18de..94bc0ee7 100644 --- a/programs/steward/src/instructions/pause_steward.rs +++ b/programs/steward/src/instructions/pause_steward.rs @@ -1,13 +1,13 @@ use anchor_lang::prelude::*; -use crate::{utils::get_config_authority, Config}; +use crate::{utils::get_config_admin, Config}; #[derive(Accounts)] pub struct PauseSteward<'info> { #[account(mut)] pub config: AccountLoader<'info, Config>, - #[account(mut, address = get_config_authority(&config)?)] + #[account(mut, address = get_config_admin(&config)?)] pub authority: Signer<'info>, } diff --git a/programs/steward/src/instructions/realloc_state.rs b/programs/steward/src/instructions/realloc_state.rs index 1f543815..1cc13bd8 100644 --- a/programs/steward/src/instructions/realloc_state.rs +++ b/programs/steward/src/instructions/realloc_state.rs @@ -3,6 +3,7 @@ use crate::{ constants::{MAX_ALLOC_BYTES, MAX_VALIDATORS, SORTED_INDEX_DEFAULT}, errors::StewardError, state::{Config, StewardStateAccount}, + utils::get_validator_list, Delegation, StewardStateEnum, STATE_PADDING_0_SIZE, }; use anchor_lang::prelude::*; @@ -43,10 +44,8 @@ pub struct ReallocState<'info> { pub config: AccountLoader<'info, Config>, - /// CHECK: TODO add validator_list address to config - #[account( - owner = spl_stake_pool::ID, - )] + /// CHECK: We check against the Config + #[account(address = get_validator_list(&config)?)] pub validator_list: AccountInfo<'info>, pub system_program: Program<'info, System>, diff --git a/programs/steward/src/instructions/rebalance.rs b/programs/steward/src/instructions/rebalance.rs index 4f6e0ff6..ab338ad7 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,11 +20,11 @@ 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}, - Config, Staker, StewardStateAccount, + Config, StewardStateAccount, }; #[derive(Accounts)] @@ -51,13 +54,6 @@ pub struct Rebalance<'info> { #[account(address = get_stake_pool_address(&config)?)] pub stake_pool: AccountInfo<'info>, - #[account( - mut, - seeds = [Staker::SEED, config.key().as_ref()], - bump = staker.bump - )] - pub staker: Account<'info, Staker>, - /// CHECK: passing through, checks are done by spl-stake-pool #[account( seeds = [ @@ -140,9 +136,6 @@ pub struct Rebalance<'info> { /// CHECK: passing through, checks are done by spl-stake-pool #[account(address = stake::program::ID)] pub stake_program: AccountInfo<'info>, - - #[account(mut)] - pub signer: Signer<'info>, } pub fn handler(ctx: Context, validator_list_index: usize) -> Result<()> { @@ -193,13 +186,15 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Result<( )? }; - match result { + drop(state_account); + + match result.clone() { RebalanceType::Decrease(decrease_components) => { invoke_signed( &spl_stake_pool::instruction::decrease_validator_stake_with_reserve( &ctx.accounts.stake_pool_program.key(), &ctx.accounts.stake_pool.key(), - &ctx.accounts.staker.key(), + &ctx.accounts.state_account.key(), &ctx.accounts.withdraw_authority.key(), &ctx.accounts.validator_list.key(), &ctx.accounts.reserve_stake.key(), @@ -210,7 +205,7 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Result<( ), &[ ctx.accounts.stake_pool.to_account_info(), - ctx.accounts.staker.to_account_info(), + ctx.accounts.state_account.to_account_info(), ctx.accounts.withdraw_authority.to_owned(), ctx.accounts.validator_list.to_account_info(), ctx.accounts.reserve_stake.to_account_info(), @@ -223,9 +218,9 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Result<( ctx.accounts.stake_program.to_account_info(), ], &[&[ - Staker::SEED, + StewardStateAccount::SEED, &ctx.accounts.config.key().to_bytes(), - &[ctx.accounts.staker.bump], + &[ctx.bumps.state_account], ]], )?; } @@ -234,7 +229,7 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Result<( &spl_stake_pool::instruction::increase_validator_stake( &ctx.accounts.stake_pool_program.key(), &ctx.accounts.stake_pool.key(), - &ctx.accounts.staker.key(), + &ctx.accounts.state_account.key(), &ctx.accounts.withdraw_authority.key(), &ctx.accounts.validator_list.key(), &ctx.accounts.reserve_stake.key(), @@ -246,7 +241,7 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Result<( ), &[ ctx.accounts.stake_pool.to_account_info(), - ctx.accounts.staker.to_account_info(), + ctx.accounts.state_account.to_account_info(), ctx.accounts.withdraw_authority.to_owned(), ctx.accounts.validator_list.to_account_info(), ctx.accounts.reserve_stake.to_account_info(), @@ -261,21 +256,107 @@ pub fn handler(ctx: Context, validator_list_index: usize) -> Result<( ctx.accounts.stake_program.to_account_info(), ], &[&[ - Staker::SEED, + StewardStateAccount::SEED, &ctx.accounts.config.key().to_bytes(), - &[ctx.accounts.staker.bump], + &[ctx.bumps.state_account], ]], )?; } RebalanceType::None => {} } - maybe_transition_and_emit( - &mut state_account.state, - &clock, - &config.parameters, - &epoch_schedule, - )?; + { + let mut state_account = ctx.accounts.state_account.load_mut()?; + + 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, + }, + } +} + +#[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/instructions/remove_validator_from_blacklist.rs b/programs/steward/src/instructions/remove_validator_from_blacklist.rs index 1c9c267e..c8e4c57e 100644 --- a/programs/steward/src/instructions/remove_validator_from_blacklist.rs +++ b/programs/steward/src/instructions/remove_validator_from_blacklist.rs @@ -1,4 +1,4 @@ -use crate::{utils::get_config_authority, Config}; +use crate::{utils::get_config_blacklist_authority, Config}; use anchor_lang::prelude::*; #[derive(Accounts)] @@ -6,14 +6,19 @@ pub struct RemoveValidatorFromBlacklist<'info> { #[account(mut)] pub config: AccountLoader<'info, Config>, - #[account(mut, address = get_config_authority(&config)?)] + #[account(mut, address = get_config_blacklist_authority(&config)?)] pub authority: Signer<'info>, } // Removes validator from blacklist. Validator will be eligible to receive delegation again when scores are recomputed. // Index is the index of the validator from ValidatorHistory. -pub fn handler(ctx: Context, index: u32) -> Result<()> { +pub fn handler( + ctx: Context, + validator_history_index: u32, +) -> Result<()> { let mut config = ctx.accounts.config.load_mut()?; - config.blacklist.set(index as usize, false)?; + config + .validator_history_blacklist + .set(validator_history_index as usize, false)?; Ok(()) } diff --git a/programs/steward/src/instructions/reset_steward_state.rs b/programs/steward/src/instructions/reset_steward_state.rs index 9ec002ac..2ed4d167 100644 --- a/programs/steward/src/instructions/reset_steward_state.rs +++ b/programs/steward/src/instructions/reset_steward_state.rs @@ -2,7 +2,7 @@ use crate::{ constants::{MAX_VALIDATORS, SORTED_INDEX_DEFAULT}, errors::StewardError, state::{Config, StewardStateAccount}, - utils::{deserialize_stake_pool, get_config_authority, get_stake_pool_address}, + utils::{deserialize_stake_pool, get_config_admin, get_stake_pool_address}, BitMask, Delegation, StewardStateEnum, STATE_PADDING_0_SIZE, }; use anchor_lang::prelude::*; @@ -27,7 +27,7 @@ pub struct ResetStewardState<'info> { #[account(address = deserialize_stake_pool(&stake_pool)?.validator_list)] pub validator_list: AccountInfo<'info>, - #[account(mut, address = get_config_authority(&config)?)] + #[account(mut, address = get_config_admin(&config)?)] pub authority: Signer<'info>, } diff --git a/programs/steward/src/instructions/resume_steward.rs b/programs/steward/src/instructions/resume_steward.rs index 0b4a6a23..d1b392ce 100644 --- a/programs/steward/src/instructions/resume_steward.rs +++ b/programs/steward/src/instructions/resume_steward.rs @@ -1,13 +1,13 @@ use anchor_lang::prelude::*; -use crate::{utils::get_config_authority, Config}; +use crate::{utils::get_config_admin, Config}; #[derive(Accounts)] pub struct ResumeSteward<'info> { #[account(mut)] pub config: AccountLoader<'info, Config>, - #[account(mut, address = get_config_authority(&config)?)] + #[account(mut, address = get_config_admin(&config)?)] pub authority: Signer<'info>, } diff --git a/programs/steward/src/instructions/set_new_authority.rs b/programs/steward/src/instructions/set_new_authority.rs index cc268ca2..0e82fbbe 100644 --- a/programs/steward/src/instructions/set_new_authority.rs +++ b/programs/steward/src/instructions/set_new_authority.rs @@ -1,7 +1,65 @@ +use anchor_lang::idl::types::*; use anchor_lang::prelude::*; +use anchor_lang::IdlBuild; +use borsh::{BorshDeserialize, BorshSerialize}; use crate::{errors::StewardError, state::Config}; +#[repr(u8)] +#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, PartialEq)] +pub enum AuthorityType { + SetAdmin = 0, + SetBlacklistAuthority = 1, + SetParametersAuthority = 2, +} + +impl AuthorityType { + pub fn to_u8(self) -> u8 { + self as u8 + } +} + +// Implement IdlBuild for AuthorityType +impl IdlBuild for AuthorityType { + fn create_type() -> Option { + Some(IdlTypeDef { + name: "AuthorityType".to_string(), + ty: IdlTypeDefTy::Enum { + variants: vec![ + IdlEnumVariant { + name: "SetAdmin".to_string(), + fields: Some(IdlDefinedFields::Named(vec![IdlField { + name: "SetAdmin".to_string(), + docs: Default::default(), + ty: IdlType::Option(Box::new(IdlType::U8)), + }])), + }, + IdlEnumVariant { + name: "SetBlacklistAuthority".to_string(), + fields: Some(IdlDefinedFields::Named(vec![IdlField { + name: "SetBlacklistAuthority".to_string(), + docs: Default::default(), + ty: IdlType::Option(Box::new(IdlType::U8)), + }])), + }, + IdlEnumVariant { + name: "SetParameterAuthority".to_string(), + fields: Some(IdlDefinedFields::Named(vec![IdlField { + name: "SetParameterAuthority".to_string(), + docs: Default::default(), + ty: IdlType::Option(Box::new(IdlType::U8)), + }])), + }, + ], + }, + docs: Default::default(), + generics: Default::default(), + serialization: Default::default(), + repr: Default::default(), + }) + } +} + #[derive(Accounts)] pub struct SetNewAuthority<'info> { #[account(mut)] @@ -11,15 +69,26 @@ pub struct SetNewAuthority<'info> { pub new_authority: AccountInfo<'info>, #[account(mut)] - pub authority: Signer<'info>, + pub admin: Signer<'info>, } -pub fn handler(ctx: Context) -> Result<()> { +pub fn handler(ctx: Context, authority_type: AuthorityType) -> Result<()> { let mut config = ctx.accounts.config.load_mut()?; - if config.authority != *ctx.accounts.authority.key { + if config.admin != *ctx.accounts.admin.key { return Err(StewardError::Unauthorized.into()); } - config.authority = ctx.accounts.new_authority.key(); + match authority_type { + AuthorityType::SetAdmin => { + config.admin = ctx.accounts.new_authority.key(); + } + AuthorityType::SetBlacklistAuthority => { + config.blacklist_authority = ctx.accounts.new_authority.key(); + } + AuthorityType::SetParametersAuthority => { + config.parameters_authority = ctx.accounts.new_authority.key(); + } + } + Ok(()) } diff --git a/programs/steward/src/instructions/spl_passthrough.rs b/programs/steward/src/instructions/spl_passthrough.rs index 901d6b0b..5f985c74 100644 --- a/programs/steward/src/instructions/spl_passthrough.rs +++ b/programs/steward/src/instructions/spl_passthrough.rs @@ -6,9 +6,9 @@ use crate::constants::MAX_VALIDATORS; use crate::errors::StewardError; -use crate::state::{Config, Staker}; +use crate::state::Config; use crate::utils::{ - deserialize_stake_pool, get_config_authority, get_stake_pool_address, + deserialize_stake_pool, get_config_admin, get_stake_pool_address, get_validator_stake_info_at_index, }; use crate::StewardStateAccount; @@ -29,7 +29,7 @@ pub struct AddValidatorToPool<'info> { seeds = [StewardStateAccount::SEED, config.key().as_ref()], bump )] - pub steward_state: AccountLoader<'info, StewardStateAccount>, + pub state_account: AccountLoader<'info, StewardStateAccount>, /// CHECK: CPI program #[account( address = spl_stake_pool::ID @@ -41,11 +41,7 @@ pub struct AddValidatorToPool<'info> { )] /// CHECK: passing through, checks are done by spl-stake-pool pub stake_pool: AccountInfo<'info>, - #[account( - seeds = [Staker::SEED, config.key().as_ref()], - bump = staker.bump - )] - pub staker: Account<'info, Staker>, + /// CHECK: passing through, checks are done by spl-stake-pool #[account(mut)] pub reserve_stake: AccountInfo<'info>, @@ -72,39 +68,41 @@ pub struct AddValidatorToPool<'info> { /// CHECK: passing through, checks are done by spl-stake-pool #[account(address = stake::program::ID)] pub stake_program: AccountInfo<'info>, - #[account(mut, address = get_config_authority(&config)?)] - pub signer: Signer<'info>, + #[account(mut, address = get_config_admin(&config)?)] + pub admin: Signer<'info>, } pub fn add_validator_to_pool_handler( ctx: Context, validator_seed: Option, ) -> Result<()> { - let mut state_account = ctx.accounts.steward_state.load_mut()?; - let epoch = Clock::get()?.epoch; + { + let mut state_account = ctx.accounts.state_account.load_mut()?; + 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 - ); + // Should not be able to add a validator if update is not complete + require!( + epoch == state_account.state.current_epoch, + StewardError::EpochMaintenanceNotComplete + ); - { - let validator_list_data = &mut ctx.accounts.validator_list.try_borrow_mut_data()?; - let (_, validator_list) = ValidatorListHeader::deserialize_vec(validator_list_data)?; + { + let validator_list_data = &mut ctx.accounts.validator_list.try_borrow_mut_data()?; + let (_, validator_list) = ValidatorListHeader::deserialize_vec(validator_list_data)?; - if validator_list.len().checked_add(1).unwrap() > MAX_VALIDATORS as u32 { - return Err(StewardError::MaxValidatorsReached.into()); + if validator_list.len().checked_add(1).unwrap() > MAX_VALIDATORS as u32 { + return Err(StewardError::MaxValidatorsReached.into()); + } } - } - state_account.state.increment_validator_to_add()?; + state_account.state.increment_validator_to_add()?; + } invoke_signed( &spl_stake_pool::instruction::add_validator_to_pool( &ctx.accounts.stake_pool_program.key(), &ctx.accounts.stake_pool.key(), - &ctx.accounts.staker.key(), + &ctx.accounts.state_account.key(), &ctx.accounts.reserve_stake.key(), &ctx.accounts.withdraw_authority.key(), &ctx.accounts.validator_list.key(), @@ -114,7 +112,7 @@ pub fn add_validator_to_pool_handler( ), &[ ctx.accounts.stake_pool.to_account_info(), - ctx.accounts.staker.to_account_info(), + ctx.accounts.state_account.to_account_info(), ctx.accounts.reserve_stake.to_owned(), ctx.accounts.withdraw_authority.to_owned(), ctx.accounts.validator_list.to_account_info(), @@ -128,9 +126,9 @@ pub fn add_validator_to_pool_handler( ctx.accounts.stake_program.to_account_info(), ], &[&[ - Staker::SEED, + StewardStateAccount::SEED, &ctx.accounts.config.key().to_bytes(), - &[ctx.accounts.staker.bump], + &[ctx.bumps.state_account], ]], )?; Ok(()) @@ -144,7 +142,7 @@ pub struct RemoveValidatorFromPool<'info> { seeds = [StewardStateAccount::SEED, config.key().as_ref()], bump )] - pub steward_state: AccountLoader<'info, StewardStateAccount>, + pub state_account: AccountLoader<'info, StewardStateAccount>, /// CHECK: CPI program #[account( @@ -157,11 +155,7 @@ pub struct RemoveValidatorFromPool<'info> { address = get_stake_pool_address(&config)? )] pub stake_pool: AccountInfo<'info>, - #[account( - seeds = [Staker::SEED, config.key().as_ref()], - bump = staker.bump - )] - pub staker: Account<'info, Staker>, + /// CHECK: passing through, checks are done by spl-stake-pool pub withdraw_authority: AccountInfo<'info>, /// CHECK: passing through, checks are done by spl-stake-pool @@ -178,50 +172,52 @@ pub struct RemoveValidatorFromPool<'info> { /// CHECK: passing through, checks are done by spl-stake-pool #[account(address = stake::program::ID)] pub stake_program: AccountInfo<'info>, - #[account(mut, address = get_config_authority(&config)?)] - pub signer: Signer<'info>, + #[account(mut, address = get_config_admin(&config)?)] + pub admin: Signer<'info>, } pub fn remove_validator_from_pool_handler( ctx: Context, validator_list_index: usize, ) -> Result<()> { - let mut state_account = ctx.accounts.steward_state.load_mut()?; - let epoch = Clock::get()?.epoch; - - // Should not be able to remove a validator if update is not complete - require!( - epoch == state_account.state.current_epoch, - StewardError::EpochMaintenanceNotComplete - ); - - if validator_list_index < state_account.state.num_pool_validators as usize { - let validator_list_stake_info = get_validator_stake_info_at_index( - &ctx.accounts.validator_list.to_account_info(), - validator_list_index, - )?; - - let (validator_list_stake_account, _) = find_stake_program_address( - &ctx.accounts.stake_pool_program.key(), - &validator_list_stake_info.vote_account_address, - &ctx.accounts.stake_pool.key(), - NonZeroU32::new(u32::from(validator_list_stake_info.validator_seed_suffix)), + { + let mut state_account = ctx.accounts.state_account.load_mut()?; + let epoch = Clock::get()?.epoch; + + // Should not be able to remove a validator if update is not complete + require!( + epoch == state_account.state.current_epoch, + StewardError::EpochMaintenanceNotComplete ); - if validator_list_stake_account != ctx.accounts.stake_account.key() { - return Err(StewardError::ValidatorNotInList.into()); + if validator_list_index < state_account.state.num_pool_validators as usize { + let validator_list_stake_info = get_validator_stake_info_at_index( + &ctx.accounts.validator_list.to_account_info(), + validator_list_index, + )?; + + let (validator_list_stake_account, _) = find_stake_program_address( + &ctx.accounts.stake_pool_program.key(), + &validator_list_stake_info.vote_account_address, + &ctx.accounts.stake_pool.key(), + NonZeroU32::new(u32::from(validator_list_stake_info.validator_seed_suffix)), + ); + + if validator_list_stake_account != ctx.accounts.stake_account.key() { + return Err(StewardError::ValidatorNotInList.into()); + } } - } - state_account - .state - .mark_validator_for_removal(validator_list_index)?; + state_account + .state + .mark_validator_for_removal(validator_list_index)?; + } invoke_signed( &spl_stake_pool::instruction::remove_validator_from_pool( &ctx.accounts.stake_pool_program.key(), &ctx.accounts.stake_pool.key(), - &ctx.accounts.staker.key(), + &ctx.accounts.state_account.key(), &ctx.accounts.withdraw_authority.key(), &ctx.accounts.validator_list.key(), &ctx.accounts.stake_account.key(), @@ -229,7 +225,7 @@ pub fn remove_validator_from_pool_handler( ), &[ ctx.accounts.stake_pool.to_account_info(), - ctx.accounts.staker.to_account_info(), + ctx.accounts.state_account.to_account_info(), ctx.accounts.withdraw_authority.to_owned(), ctx.accounts.validator_list.to_account_info(), ctx.accounts.stake_account.to_account_info(), @@ -238,9 +234,9 @@ pub fn remove_validator_from_pool_handler( ctx.accounts.stake_program.to_account_info(), ], &[&[ - Staker::SEED, + StewardStateAccount::SEED, &ctx.accounts.config.key().to_bytes(), - &[ctx.accounts.staker.bump], + &[ctx.bumps.state_account], ]], )?; Ok(()) @@ -249,6 +245,12 @@ pub fn remove_validator_from_pool_handler( #[derive(Accounts)] pub struct SetPreferredValidator<'info> { pub config: AccountLoader<'info, Config>, + #[account( + mut, + seeds = [StewardStateAccount::SEED, config.key().as_ref()], + bump + )] + pub state_account: AccountLoader<'info, StewardStateAccount>, /// CHECK: CPI program #[account( address = spl_stake_pool::ID @@ -260,16 +262,12 @@ pub struct SetPreferredValidator<'info> { address = get_stake_pool_address(&config)? )] pub stake_pool: AccountInfo<'info>, - #[account( - seeds = [Staker::SEED, config.key().as_ref()], - bump = staker.bump - )] - pub staker: Account<'info, Staker>, + /// CHECK: passing through, checks are done by spl-stake-pool #[account(address = deserialize_stake_pool(&stake_pool)?.validator_list)] pub validator_list: AccountInfo<'info>, - #[account(mut, address = get_config_authority(&config)?)] - pub signer: Signer<'info>, + #[account(mut, address = get_config_admin(&config)?)] + pub admin: Signer<'info>, } pub fn set_preferred_validator_handler( @@ -281,20 +279,20 @@ pub fn set_preferred_validator_handler( &spl_stake_pool::instruction::set_preferred_validator( ctx.accounts.stake_pool_program.key, &ctx.accounts.stake_pool.key(), - &ctx.accounts.staker.key(), + &ctx.accounts.state_account.key(), &ctx.accounts.validator_list.key(), validator_type.clone(), validator, ), &[ ctx.accounts.stake_pool.to_account_info(), - ctx.accounts.staker.to_account_info(), + ctx.accounts.state_account.to_account_info(), ctx.accounts.validator_list.to_account_info(), ], &[&[ - Staker::SEED, + StewardStateAccount::SEED, &ctx.accounts.config.key().to_bytes(), - &[ctx.accounts.staker.bump], + &[ctx.bumps.state_account], ]], )?; Ok(()) @@ -308,7 +306,7 @@ pub struct IncreaseValidatorStake<'info> { seeds = [StewardStateAccount::SEED, config.key().as_ref()], bump )] - pub steward_state: AccountLoader<'info, StewardStateAccount>, + pub state_account: AccountLoader<'info, StewardStateAccount>, #[account( mut, seeds = [ValidatorHistory::SEED, vote_account.key().as_ref()], @@ -327,11 +325,7 @@ pub struct IncreaseValidatorStake<'info> { address = get_stake_pool_address(&config)? )] pub stake_pool: AccountInfo<'info>, - #[account( - seeds = [Staker::SEED, config.key().as_ref()], - bump = staker.bump - )] - pub staker: Account<'info, Staker>, + /// CHECK: passing through, checks are done by spl-stake-pool pub withdraw_authority: AccountInfo<'info>, /// CHECK: passing through, checks are done by spl-stake-pool @@ -364,19 +358,17 @@ pub struct IncreaseValidatorStake<'info> { /// CHECK: passing through, checks are done by spl-stake-pool #[account(address = stake::program::ID)] pub stake_program: AccountInfo<'info>, - #[account(mut, address = get_config_authority(&config)?)] - pub signer: Signer<'info>, + #[account(mut, address = get_config_admin(&config)?)] + pub admin: Signer<'info>, } - pub fn increase_validator_stake_handler( ctx: Context, lamports: u64, transient_seed: u64, ) -> Result<()> { - let validator_history = ctx.accounts.validator_history.load()?; - { - let mut state_account = ctx.accounts.steward_state.load_mut()?; + let validator_history = ctx.accounts.validator_history.load()?; + let mut state_account = ctx.accounts.state_account.load_mut()?; // Get the balance let balance = state_account .state @@ -394,7 +386,7 @@ pub fn increase_validator_stake_handler( &spl_stake_pool::instruction::increase_validator_stake( &ctx.accounts.stake_pool_program.key(), &ctx.accounts.stake_pool.key(), - &ctx.accounts.staker.key(), + &ctx.accounts.state_account.key(), &ctx.accounts.withdraw_authority.key(), &ctx.accounts.validator_list.key(), &ctx.accounts.reserve_stake.key(), @@ -406,7 +398,7 @@ pub fn increase_validator_stake_handler( ), &[ ctx.accounts.stake_pool.to_account_info(), - ctx.accounts.staker.to_account_info(), + ctx.accounts.state_account.to_account_info(), ctx.accounts.withdraw_authority.to_owned(), ctx.accounts.validator_list.to_account_info(), ctx.accounts.reserve_stake.to_account_info(), @@ -421,9 +413,9 @@ pub fn increase_validator_stake_handler( ctx.accounts.stake_program.to_account_info(), ], &[&[ - Staker::SEED, + StewardStateAccount::SEED, &ctx.accounts.config.key().to_bytes(), - &[ctx.accounts.staker.bump], + &[ctx.bumps.state_account], ]], )?; Ok(()) @@ -437,7 +429,7 @@ pub struct DecreaseValidatorStake<'info> { seeds = [StewardStateAccount::SEED, config.key().as_ref()], bump )] - pub steward_state: AccountLoader<'info, StewardStateAccount>, + pub state_account: AccountLoader<'info, StewardStateAccount>, #[account( mut, seeds = [ValidatorHistory::SEED, vote_account.key().as_ref()], @@ -456,11 +448,7 @@ pub struct DecreaseValidatorStake<'info> { address = get_stake_pool_address(&config)? )] pub stake_pool: AccountInfo<'info>, - #[account( - seeds = [Staker::SEED, config.key().as_ref()], - bump = staker.bump - )] - pub staker: Account<'info, Staker>, + /// CHECK: passing through, checks are done by spl-stake-pool pub withdraw_authority: AccountInfo<'info>, /// CHECK: passing through, checks are done by spl-stake-pool @@ -490,8 +478,8 @@ pub struct DecreaseValidatorStake<'info> { /// CHECK: passing through, checks are done by spl-stake-pool #[account(address = stake::program::ID)] pub stake_program: AccountInfo<'info>, - #[account(mut, address = get_config_authority(&config)?)] - pub signer: Signer<'info>, + #[account(mut, address = get_config_admin(&config)?)] + pub admin: Signer<'info>, } pub fn decrease_validator_stake_handler( @@ -499,10 +487,9 @@ pub fn decrease_validator_stake_handler( lamports: u64, transient_seed: u64, ) -> Result<()> { - let validator_history = ctx.accounts.validator_history.load()?; - { - let mut state_account = ctx.accounts.steward_state.load_mut()?; + let validator_history = ctx.accounts.validator_history.load()?; + let mut state_account = ctx.accounts.state_account.load_mut()?; // Get the balance let balance = state_account .state @@ -520,7 +507,7 @@ pub fn decrease_validator_stake_handler( &spl_stake_pool::instruction::decrease_validator_stake_with_reserve( &ctx.accounts.stake_pool_program.key(), &ctx.accounts.stake_pool.key(), - &ctx.accounts.staker.key(), + &ctx.accounts.state_account.key(), &ctx.accounts.withdraw_authority.key(), &ctx.accounts.validator_list.key(), &ctx.accounts.reserve_stake.key(), @@ -531,7 +518,7 @@ pub fn decrease_validator_stake_handler( ), &[ ctx.accounts.stake_pool.to_account_info(), - ctx.accounts.staker.to_account_info(), + ctx.accounts.state_account.to_account_info(), ctx.accounts.withdraw_authority.to_owned(), ctx.accounts.validator_list.to_account_info(), ctx.accounts.reserve_stake.to_account_info(), @@ -544,9 +531,9 @@ pub fn decrease_validator_stake_handler( ctx.accounts.stake_program.to_account_info(), ], &[&[ - Staker::SEED, + StewardStateAccount::SEED, &ctx.accounts.config.key().to_bytes(), - &[ctx.accounts.staker.bump], + &[ctx.bumps.state_account], ]], )?; Ok(()) @@ -560,7 +547,7 @@ pub struct IncreaseAdditionalValidatorStake<'info> { seeds = [StewardStateAccount::SEED, config.key().as_ref()], bump )] - pub steward_state: AccountLoader<'info, StewardStateAccount>, + pub state_account: AccountLoader<'info, StewardStateAccount>, #[account( mut, seeds = [ValidatorHistory::SEED, vote_account.key().as_ref()], @@ -578,11 +565,7 @@ pub struct IncreaseAdditionalValidatorStake<'info> { address = get_stake_pool_address(&config)? )] pub stake_pool: AccountInfo<'info>, - #[account( - seeds = [Staker::SEED, config.key().as_ref()], - bump = staker.bump - )] - pub staker: Account<'info, Staker>, + /// CHECK: passing through, checks are done by spl-stake-pool pub withdraw_authority: AccountInfo<'info>, /// CHECK: passing through, checks are done by spl-stake-pool @@ -614,8 +597,8 @@ pub struct IncreaseAdditionalValidatorStake<'info> { /// CHECK: passing through, checks are done by spl-stake-pool #[account(address = stake::program::ID)] pub stake_program: AccountInfo<'info>, - #[account(mut, address = get_config_authority(&config)?)] - pub signer: Signer<'info>, + #[account(mut, address = get_config_admin(&config)?)] + pub admin: Signer<'info>, } pub fn increase_additional_validator_stake_handler( @@ -624,10 +607,9 @@ pub fn increase_additional_validator_stake_handler( transient_seed: u64, ephemeral_seed: u64, ) -> Result<()> { - let validator_history = ctx.accounts.validator_history.load()?; - { - let mut state_account = ctx.accounts.steward_state.load_mut()?; + let validator_history = ctx.accounts.validator_history.load()?; + let mut state_account = ctx.accounts.state_account.load_mut()?; // Get the balance let balance = state_account .state @@ -645,7 +627,7 @@ pub fn increase_additional_validator_stake_handler( &spl_stake_pool::instruction::increase_additional_validator_stake( &ctx.accounts.stake_pool_program.key(), &ctx.accounts.stake_pool.key(), - &ctx.accounts.staker.key(), + &ctx.accounts.state_account.key(), &ctx.accounts.withdraw_authority.key(), &ctx.accounts.validator_list.key(), &ctx.accounts.reserve_stake.key(), @@ -659,7 +641,7 @@ pub fn increase_additional_validator_stake_handler( ), &[ ctx.accounts.stake_pool.to_account_info(), - ctx.accounts.staker.to_account_info(), + ctx.accounts.state_account.to_account_info(), ctx.accounts.withdraw_authority.to_owned(), ctx.accounts.validator_list.to_account_info(), ctx.accounts.reserve_stake.to_account_info(), @@ -674,9 +656,9 @@ pub fn increase_additional_validator_stake_handler( ctx.accounts.stake_program.to_account_info(), ], &[&[ - Staker::SEED, + StewardStateAccount::SEED, &ctx.accounts.config.key().to_bytes(), - &[ctx.accounts.staker.bump], + &[ctx.bumps.state_account], ]], )?; Ok(()) @@ -690,7 +672,7 @@ pub struct DecreaseAdditionalValidatorStake<'info> { seeds = [StewardStateAccount::SEED, config.key().as_ref()], bump )] - pub steward_state: AccountLoader<'info, StewardStateAccount>, + pub state_account: AccountLoader<'info, StewardStateAccount>, #[account( mut, seeds = [ValidatorHistory::SEED, vote_account.key().as_ref()], @@ -713,11 +695,7 @@ pub struct DecreaseAdditionalValidatorStake<'info> { address = get_stake_pool_address(&config)? )] pub stake_pool: AccountInfo<'info>, - #[account( - seeds = [Staker::SEED, config.key().as_ref()], - bump = staker.bump - )] - pub staker: Account<'info, Staker>, + /// CHECK: passing through, checks are done by spl-stake-pool pub withdraw_authority: AccountInfo<'info>, /// CHECK: passing through, checks are done by spl-stake-pool @@ -743,8 +721,8 @@ pub struct DecreaseAdditionalValidatorStake<'info> { /// CHECK: passing through, checks are done by spl-stake-pool #[account(address = stake::program::ID)] pub stake_program: AccountInfo<'info>, - #[account(mut, address = get_config_authority(&config)?)] - pub signer: Signer<'info>, + #[account(mut, address = get_config_admin(&config)?)] + pub admin: Signer<'info>, } pub fn decrease_additional_validator_stake_handler( @@ -753,10 +731,9 @@ pub fn decrease_additional_validator_stake_handler( transient_seed: u64, ephemeral_seed: u64, ) -> Result<()> { - let validator_history = ctx.accounts.validator_history.load()?; - { - let mut state_account = ctx.accounts.steward_state.load_mut()?; + let validator_history = ctx.accounts.validator_history.load()?; + let mut state_account = ctx.accounts.state_account.load_mut()?; // Get the balance let balance = state_account .state @@ -774,7 +751,7 @@ pub fn decrease_additional_validator_stake_handler( &spl_stake_pool::instruction::decrease_additional_validator_stake( &ctx.accounts.stake_pool_program.key(), &ctx.accounts.stake_pool.key(), - &ctx.accounts.staker.key(), + &ctx.accounts.state_account.key(), &ctx.accounts.withdraw_authority.key(), &ctx.accounts.validator_list.key(), &ctx.accounts.reserve_stake.key(), @@ -787,7 +764,7 @@ pub fn decrease_additional_validator_stake_handler( ), &[ ctx.accounts.stake_pool.to_account_info(), - ctx.accounts.staker.to_account_info(), + ctx.accounts.state_account.to_account_info(), ctx.accounts.withdraw_authority.to_owned(), ctx.accounts.validator_list.to_account_info(), ctx.accounts.reserve_stake.to_account_info(), @@ -800,9 +777,9 @@ pub fn decrease_additional_validator_stake_handler( ctx.accounts.stake_program.to_account_info(), ], &[&[ - Staker::SEED, + StewardStateAccount::SEED, &ctx.accounts.config.key().to_bytes(), - &[ctx.accounts.staker.bump], + &[ctx.bumps.state_account], ]], )?; Ok(()) @@ -811,6 +788,12 @@ pub fn decrease_additional_validator_stake_handler( #[derive(Accounts)] pub struct SetStaker<'info> { pub config: AccountLoader<'info, Config>, + #[account( + mut, + seeds = [StewardStateAccount::SEED, config.key().as_ref()], + bump + )] + pub state_account: AccountLoader<'info, StewardStateAccount>, /// CHECK: CPI program #[account( address = spl_stake_pool::ID @@ -821,15 +804,11 @@ pub struct SetStaker<'info> { mut, address = get_stake_pool_address(&config)? )] pub stake_pool: AccountInfo<'info>, - #[account( - seeds = [Staker::SEED, config.key().as_ref()], - bump = staker.bump - )] - pub staker: Account<'info, Staker>, + /// CHECK: passing through, checks are done by spl-stake-pool pub new_staker: AccountInfo<'info>, - #[account(mut, address = get_config_authority(&config)?)] - pub signer: Signer<'info>, + #[account(mut, address = get_config_admin(&config)?)] + pub admin: Signer<'info>, } /// Note this function can only be called once by the Steward, as it will lose it's authority @@ -840,18 +819,18 @@ pub fn set_staker_handler(ctx: Context) -> Result<()> { &spl_stake_pool::instruction::set_staker( &ctx.accounts.stake_pool_program.key(), &ctx.accounts.stake_pool.key(), - &ctx.accounts.staker.key(), + &ctx.accounts.state_account.key(), &ctx.accounts.new_staker.key(), ), &[ ctx.accounts.stake_pool.to_account_info(), - ctx.accounts.staker.to_account_info(), + ctx.accounts.state_account.to_account_info(), ctx.accounts.new_staker.to_account_info(), ], &[&[ - Staker::SEED, + StewardStateAccount::SEED, &ctx.accounts.config.key().to_bytes(), - &[ctx.accounts.staker.bump], + &[ctx.bumps.state_account], ]], )?; Ok(()) diff --git a/programs/steward/src/instructions/update_parameters.rs b/programs/steward/src/instructions/update_parameters.rs index 97032210..02e7f5d9 100644 --- a/programs/steward/src/instructions/update_parameters.rs +++ b/programs/steward/src/instructions/update_parameters.rs @@ -1,4 +1,4 @@ -use crate::{utils::get_config_authority, Config, UpdateParametersArgs}; +use crate::{utils::get_config_parameter_authority, Config, UpdateParametersArgs}; use anchor_lang::prelude::*; #[derive(Accounts)] @@ -6,7 +6,7 @@ pub struct UpdateParameters<'info> { #[account(mut)] pub config: AccountLoader<'info, Config>, - #[account(mut, address = get_config_authority(&config)?)] + #[account(mut, address = get_config_parameter_authority(&config)?)] pub authority: Signer<'info>, } diff --git a/programs/steward/src/lib.rs b/programs/steward/src/lib.rs index 0e280f7b..138daf11 100644 --- a/programs/steward/src/lib.rs +++ b/programs/steward/src/lib.rs @@ -58,17 +58,11 @@ pub mod steward { // Initializes Config and Staker accounts. Must be called before any other instruction // Requires Pool to be initialized - pub fn initialize_config( - ctx: Context, - authority: Pubkey, + pub fn initialize_steward( + ctx: Context, update_parameters_args: UpdateParametersArgs, ) -> Result<()> { - instructions::initialize_config::handler(ctx, authority, &update_parameters_args) - } - - /// Creates state account - pub const fn initialize_state(ctx: Context) -> Result<()> { - instructions::initialize_state::handler(ctx) + instructions::initialize_steward::handler(ctx, &update_parameters_args) } /// Increases state account by 10KiB each ix until it reaches StewardStateAccount::SIZE @@ -133,8 +127,11 @@ pub mod steward { // If `new_authority` is not a pubkey you own, you cannot regain the authority, but you can // use the stake pool manager to set a new staker - pub fn set_new_authority(ctx: Context) -> Result<()> { - instructions::set_new_authority::handler(ctx) + pub fn set_new_authority( + ctx: Context, + authority_type: AuthorityType, + ) -> Result<()> { + instructions::set_new_authority::handler(ctx, authority_type) } pub fn pause_steward(ctx: Context) -> Result<()> { @@ -148,17 +145,17 @@ pub mod steward { /// Adds the validator at `index` to the blacklist. It will be instant unstaked and never receive delegations pub fn add_validator_to_blacklist( ctx: Context, - index: u32, + validator_history_blacklist: u32, ) -> Result<()> { - instructions::add_validator_to_blacklist::handler(ctx, index) + instructions::add_validator_to_blacklist::handler(ctx, validator_history_blacklist) } /// Removes the validator at `index` from the blacklist pub fn remove_validator_from_blacklist( ctx: Context, - index: u32, + validator_history_blacklist: u32, ) -> Result<()> { - instructions::remove_validator_from_blacklist::handler(ctx, index) + instructions::remove_validator_from_blacklist::handler(ctx, validator_history_blacklist) } /// For parameters that are present in args, the instruction checks that they are within sensible bounds and saves them to config struct diff --git a/programs/steward/src/score.rs b/programs/steward/src/score.rs index d492110c..d581e68f 100644 --- a/programs/steward/src/score.rs +++ b/programs/steward/src/score.rs @@ -51,7 +51,6 @@ pub struct ScoreComponents { pub fn validator_score( validator: &ValidatorHistory, - index: usize, cluster: &ClusterHistory, config: &Config, current_epoch: u16, @@ -195,7 +194,11 @@ pub fn validator_score( let superminority_score = if !is_superminority { 1.0 } else { 0.0 }; /////// Blacklist /////// - let blacklisted_score = if config.blacklist.get(index).unwrap_or(false) { + let blacklisted_score = if config + .validator_history_blacklist + .get(validator.index as usize) + .unwrap_or(false) + { 0.0 } else { 1.0 @@ -257,7 +260,6 @@ pub struct InstantUnstakeComponents { /// Before running, checks are needed on cluster and validator history to be updated this epoch past the halfway point of the epoch. pub fn instant_unstake_validator( validator: &ValidatorHistory, - index: usize, cluster: &ClusterHistory, config: &Config, epoch_start_slot: u64, @@ -321,7 +323,9 @@ pub fn instant_unstake_validator( let commission_check = commission > params.commission_threshold; /////// Blacklist /////// - let is_blacklisted = config.blacklist.get(index)?; + let is_blacklisted = config + .validator_history_blacklist + .get(validator.index as usize)?; let instant_unstake = delinquency_check || commission_check || mev_commission_check || is_blacklisted; diff --git a/programs/steward/src/state/accounts.rs b/programs/steward/src/state/accounts.rs index ee252adc..40460d65 100644 --- a/programs/steward/src/state/accounts.rs +++ b/programs/steward/src/state/accounts.rs @@ -4,7 +4,7 @@ use anchor_lang::prelude::*; use borsh::BorshSerialize; use type_layout::TypeLayout; -use crate::{bitmask::BitMask, parameters::Parameters, utils::U8Bool, StewardState}; +use crate::{parameters::Parameters, utils::U8Bool, LargeBitMask, StewardState}; /// Config is a user-provided keypair. /// This is so there can be multiple configs per stake pool, and one party can't @@ -15,20 +15,37 @@ pub struct Config { /// SPL Stake Pool address that this program is managing pub stake_pool: Pubkey, - /// Authority for pool stewardship, can execute SPL Staker commands and adjust Delegation parameters - pub authority: Pubkey, + /// Validator List + pub validator_list: Pubkey, + + /// Admin + /// - Update the `parameters_authority` + /// - Update the `blacklist_authority` + /// - Can call SPL Passthrough functions + /// - Can pause/reset the state machine + pub admin: Pubkey, + + /// Parameters Authority + /// - Can update steward parameters + pub parameters_authority: Pubkey, + + /// Blacklist Authority + /// - Can add to the blacklist + /// - Can remove from the blacklist + pub blacklist_authority: Pubkey, /// Bitmask representing index of validators that are not allowed delegation - pub blacklist: BitMask, + /// NOTE: This is indexed off of the validator history, NOT the validator list + pub validator_history_blacklist: LargeBitMask, /// Parameters for scoring, delegation, and state machine pub parameters: Parameters, - /// Padding for future governance parameters - pub _padding: [u8; 1023], - /// Halts any state machine progress pub paused: U8Bool, + + /// Padding for future governance parameters + pub _padding: [u8; 1023], } impl Config { @@ -44,26 +61,6 @@ impl Config { } } -// PDA that is used to sign instructions for the stake pool. -// The pool's "staker" account needs to be assigned to this address, -// and it has authority over adding validators, removing validators, and delegating stake. -#[account] -pub struct Staker { - pub bump: u8, -} -impl Staker { - pub const SIZE: usize = 8 + size_of::(); - pub const SEED: &'static [u8] = b"staker"; - - pub fn get_address(config: &Pubkey) -> Pubkey { - let (pubkey, _) = - Pubkey::find_program_address(&[Self::SEED, config.as_ref()], &crate::id()); - pubkey - } -} - -// static_assertions::const_assert_eq!(StewardStateAccount::SIZE, 162584); - #[derive(BorshSerialize)] #[account(zero_copy)] pub struct StewardStateAccount { @@ -78,3 +75,10 @@ impl StewardStateAccount { pub const SEED: &'static [u8] = b"steward_state"; pub const IS_INITIALIZED_BYTE_POSITION: usize = Self::SIZE - 8; } + +pub fn derive_steward_state_address(steward_config: &Pubkey) -> (Pubkey, u8) { + Pubkey::find_program_address( + &[StewardStateAccount::SEED, steward_config.as_ref()], + &crate::id(), + ) +} diff --git a/programs/steward/src/state/large_bitmask.rs b/programs/steward/src/state/large_bitmask.rs new file mode 100644 index 00000000..bfb96e78 --- /dev/null +++ b/programs/steward/src/state/large_bitmask.rs @@ -0,0 +1,104 @@ +/* + This file is largely copied over from bitmask.rs + This is because making a generic bitmask struct either didn't play well with + zero-copy, or it added too much overhead to a struct meant for performance. +*/ + +use anchor_lang::{prelude::Result, zero_copy}; +use borsh::{BorshDeserialize, BorshSerialize}; + +use crate::errors::StewardError; + +//We are allocating at this size to handle future growth of ValidatorHistory accounts, at 2800 in June 2024 +const LARGE_BITMASK_INDEXES: usize = 20_000; + +#[allow(clippy::integer_division)] +const LARGE_BITMASK: usize = (LARGE_BITMASK_INDEXES + 64 - 1) / 64; // ceil(LARGE_BITMASK_INDEXES / 64) + +/// Data structure used to efficiently pack a binary array, primarily used to store all validators. +/// Each validator has an index (its index in the spl_stake_pool::ValidatorList), corresponding to a bit in the bitmask. +/// When an operation is executed on a validator, the bit corresponding to that validator's index is set to 1. +/// When all bits are 1, the operation is complete. +#[derive(BorshSerialize, BorshDeserialize)] +#[zero_copy] +pub struct LargeBitMask { + pub values: [u64; LARGE_BITMASK], +} + +impl Default for LargeBitMask { + fn default() -> Self { + Self { + values: [0; LARGE_BITMASK], + } + } +} + +impl LargeBitMask { + #[allow(clippy::integer_division)] + pub fn set(&mut self, index: usize, value: bool) -> Result<()> { + if index >= LARGE_BITMASK_INDEXES { + return Err(StewardError::BitmaskOutOfBounds.into()); + } + let word = index / 64; + let bit = index % 64; + if value { + self.values[word] |= 1 << bit; + } else { + self.values[word] &= !(1 << bit); + } + Ok(()) + } + + #[allow(clippy::integer_division)] + pub fn get(&self, index: usize) -> Result { + if index >= LARGE_BITMASK_INDEXES { + return Err(StewardError::BitmaskOutOfBounds.into()); + } + let word = index / 64; + let bit = index % 64; + Ok((self.values[word] >> bit) & 1 == 1) + } + + /// Unsafe version of get, which does not check if the index is out of bounds. + #[inline] + #[allow(clippy::integer_division, clippy::arithmetic_side_effects)] + pub const fn get_unsafe(&self, index: usize) -> bool { + let word = index / 64; + let bit = index % 64; + (self.values[word] >> bit) & 1 == 1 + } + + pub fn reset(&mut self) { + self.values = [0; LARGE_BITMASK]; + } + + pub fn is_empty(&self) -> bool { + self.values.iter().all(|&x| x == 0) + } + + pub fn count(&self) -> usize { + self.values.iter().map(|x| x.count_ones() as usize).sum() + } + + #[allow(clippy::integer_division)] + pub fn is_complete(&self, num_validators: u64) -> Result { + let num_validators = num_validators as usize; + if num_validators > LARGE_BITMASK_INDEXES { + return Err(StewardError::BitmaskOutOfBounds.into()); + } + let full_words = num_validators / 64; + if !self.values[0..full_words].iter().all(|&x| x == u64::MAX) { + return Ok(false); + } + let remainder = num_validators % 64; + if remainder > 0 { + let mask: u64 = (1u64 << remainder) + .checked_sub(1) + .ok_or(StewardError::ArithmeticError)?; + if self.values[full_words] & mask != mask { + return Ok(false); + } + } + Ok(true) + } +} diff --git a/programs/steward/src/state/mod.rs b/programs/steward/src/state/mod.rs index 6dbaa41f..9877fcfe 100644 --- a/programs/steward/src/state/mod.rs +++ b/programs/steward/src/state/mod.rs @@ -1,9 +1,11 @@ pub mod accounts; pub mod bitmask; +pub mod large_bitmask; pub mod parameters; pub mod steward_state; pub use accounts::*; pub use bitmask::*; +pub use large_bitmask::*; pub use parameters::*; pub use steward_state::*; diff --git a/programs/steward/src/state/steward_state.rs b/programs/steward/src/state/steward_state.rs index 3cf17131..0c091fc9 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 @@ -621,8 +624,7 @@ impl StewardState { return Err(StewardError::ClusterHistoryNotRecentEnough.into()); } - let score = validator_score(validator, index, cluster, config, current_epoch as u16)?; - emit!(score); + let score = validator_score(validator, cluster, config, current_epoch as u16)?; 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); @@ -755,17 +757,16 @@ impl StewardState { let instant_unstake_result = instant_unstake_validator( validator, - index, cluster, config, 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(), @@ -816,14 +817,28 @@ impl StewardState { .checked_add(stake_rent) .ok_or(StewardError::ArithmeticError)?; - // 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( - stake_rent - .checked_mul(2) - .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 (num_validators + 1) * stake_rent, which covers rent for all validators plus the transient rent + let all_accounts_needed_reserve_for_rent = validator_list + .len() + .checked_add(1) + .ok_or(StewardError::ArithmeticError)?; + + let accounts_left_needed_reserve_for_rent = all_accounts_needed_reserve_for_rent + .checked_sub(self.progress.count() as u32) + .ok_or(StewardError::ArithmeticError)?; + + let reserve_minimum = stake_rent + .checked_mul(accounts_left_needed_reserve_for_rent as u64) + .ok_or(StewardError::ArithmeticError)?; + // Saturating_sub because reserve stake may be less than the reserve_minimum but needs more than the reserve_minimum to be able to delegate + let reserve_lamports = reserve_lamports.saturating_sub(reserve_minimum); + // Represents the amount of lamports that can be delegated to validators beyond the fixed costs of rent and minimum_delegation let stake_pool_lamports = stake_pool_lamports .checked_sub( @@ -909,6 +924,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 { @@ -917,13 +941,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); diff --git a/programs/steward/src/utils.rs b/programs/steward/src/utils.rs index 78d52735..7dcce9b2 100644 --- a/programs/steward/src/utils.rs +++ b/programs/steward/src/utils.rs @@ -15,9 +15,24 @@ pub fn get_stake_pool_address(account: &AccountLoader) -> Result Ok(config.stake_pool) } -pub fn get_config_authority(account: &AccountLoader) -> Result { +pub fn get_validator_list(account: &AccountLoader) -> Result { let config = account.load()?; - Ok(config.authority) + Ok(config.validator_list) +} + +pub fn get_config_admin(account: &AccountLoader) -> Result { + let config = account.load()?; + Ok(config.admin) +} + +pub fn get_config_blacklist_authority(account: &AccountLoader) -> Result { + let config = account.load()?; + Ok(config.blacklist_authority) +} + +pub fn get_config_parameter_authority(account: &AccountLoader) -> Result { + let config = account.load()?; + Ok(config.parameters_authority) } pub fn epoch_progress(clock: &Clock, epoch_schedule: &EpochSchedule) -> Result { @@ -86,7 +101,7 @@ pub fn get_validator_stake_info_at_index( Ok(validator_stake_info) } -pub fn check_validator_list_has_stake_status( +pub fn check_validator_list_has_stake_status_other_than( validator_list_account_info: &AccountInfo, flag: StakeStatus, ) -> Result { @@ -105,7 +120,7 @@ pub fn check_validator_list_has_stake_status( let stake_status = validator_list.data[stake_status_index]; - if stake_status == flag as u8 { + if stake_status != flag as u8 { return Ok(true); } } diff --git a/tests/src/steward_fixtures.rs b/tests/src/steward_fixtures.rs index 1ca223b4..05b6f972 100644 --- a/tests/src/steward_fixtures.rs +++ b/tests/src/steward_fixtures.rs @@ -15,8 +15,8 @@ use jito_steward::{ bitmask::BitMask, constants::{MAX_VALIDATORS, SORTED_INDEX_DEFAULT, STAKE_POOL_WITHDRAW_SEED}, utils::StakePool, - Config, Delegation, Parameters, Staker, StewardState, StewardStateAccount, StewardStateEnum, - UpdateParametersArgs, STATE_PADDING_0_SIZE, + Config, Delegation, LargeBitMask, Parameters, StewardState, StewardStateAccount, + StewardStateEnum, UpdateParametersArgs, STATE_PADDING_0_SIZE, }; use solana_program_test::*; use solana_sdk::{ @@ -65,7 +65,6 @@ impl Default for StakePoolMetadata { pub struct TestFixture { pub ctx: Rc>, pub stake_pool_meta: StakePoolMetadata, - pub staker: Pubkey, pub steward_config: Keypair, pub steward_state: Pubkey, pub cluster_history_account: Pubkey, @@ -104,11 +103,6 @@ impl TestFixture { let stake_pool_meta = StakePoolMetadata::default(); let steward_config = Keypair::new(); - let staker = Pubkey::find_program_address( - &[Staker::SEED, steward_config.pubkey().as_ref()], - &jito_steward::id(), - ) - .0; let steward_state = Pubkey::find_program_address( &[StewardStateAccount::SEED, steward_config.pubkey().as_ref()], &jito_steward::id(), @@ -140,7 +134,6 @@ impl TestFixture { Self { ctx, stake_pool_meta, - staker, steward_state, steward_config, validator_history_config, @@ -257,7 +250,7 @@ impl TestFixture { } } - pub async fn initialize_config(&self, parameters: Option) { + pub async fn initialize_steward(&self, parameters: Option) { // Default parameters from JIP let update_parameters_args = parameters.unwrap_or(UpdateParametersArgs { mev_commission_range: Some(0), // Set to pass validation, where epochs starts at 0 @@ -282,17 +275,16 @@ impl TestFixture { let instruction = Instruction { program_id: jito_steward::id(), - accounts: jito_steward::accounts::InitializeConfig { + accounts: jito_steward::accounts::InitializeSteward { config: self.steward_config.pubkey(), stake_pool: self.stake_pool_meta.stake_pool, - staker: self.staker, + state_account: self.steward_state, stake_pool_program: spl_stake_pool::id(), system_program: anchor_lang::solana_program::system_program::id(), - signer: self.keypair.pubkey(), + current_staker: self.keypair.pubkey(), } .to_account_metas(None), - data: jito_steward::instruction::InitializeConfig { - authority: self.keypair.pubkey(), + data: jito_steward::instruction::InitializeSteward { update_parameters_args, } .data(), @@ -307,23 +299,10 @@ impl TestFixture { self.submit_transaction_assert_success(transaction).await; } - pub async fn initialize_steward_state(&self) { - let instruction = Instruction { - program_id: jito_steward::id(), - accounts: jito_steward::accounts::InitializeState { - state_account: self.steward_state, - config: self.steward_config.pubkey(), - system_program: anchor_lang::solana_program::system_program::id(), - signer: self.keypair.pubkey(), - } - .to_account_metas(None), - data: jito_steward::instruction::InitializeState {}.data(), - }; - - let mut ixs = vec![instruction]; - + pub async fn realloc_steward_state(&self) { // Realloc validator history account let mut num_reallocs = (StewardStateAccount::SIZE - MAX_ALLOC_BYTES) / MAX_ALLOC_BYTES + 1; + let mut ixs = vec![]; while num_reallocs > 0 { ixs.extend(vec![ @@ -837,11 +816,14 @@ impl Default for StateMachineFixtures { // Setup Config let config = Config { stake_pool: Pubkey::new_unique(), - authority: Pubkey::new_unique(), - blacklist: BitMask::default(), parameters, - _padding: [0; 1023], paused: false.into(), + validator_list: Pubkey::new_unique(), + admin: Pubkey::new_unique(), + parameters_authority: Pubkey::new_unique(), + blacklist_authority: Pubkey::new_unique(), + validator_history_blacklist: LargeBitMask::default(), + _padding: [0; 1023], }; // Setup Sysvars: Clock, EpochSchedule diff --git a/tests/tests/steward/test_algorithms.rs b/tests/tests/steward/test_algorithms.rs index 83e0b464..901bf0b8 100644 --- a/tests/tests/steward/test_algorithms.rs +++ b/tests/tests/steward/test_algorithms.rs @@ -36,7 +36,6 @@ fn test_compute_score() { // Regular run let components = validator_score( &good_validator, - good_validator.index as usize, &cluster_history, &config, current_epoch as u16, @@ -64,14 +63,8 @@ fn test_compute_score() { let mut validator = good_validator; validator.history.last_mut().unwrap().mev_commission = 1001; - let components = validator_score( - &validator, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -92,14 +85,8 @@ fn test_compute_score() { let mut validator = good_validator; validator.history.arr[11].mev_commission = 1001; - let components = validator_score( - &validator, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -119,14 +106,8 @@ fn test_compute_score() { ); let mut validator = good_validator; validator.history.arr[9].mev_commission = 1001; - let components = validator_score( - &validator, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -148,17 +129,11 @@ fn test_compute_score() { // blacklist let validator = good_validator; config - .blacklist + .validator_history_blacklist .set(validator.index as usize, true) .unwrap(); - let components = validator_score( - &validator, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -176,19 +151,13 @@ fn test_compute_score() { epoch: current_epoch as u16 } ); - config.blacklist.reset(); + config.validator_history_blacklist.reset(); // superminority score let mut validator = good_validator; validator.history.last_mut().unwrap().is_superminority = 1; - let components = validator_score( - &validator, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -212,14 +181,8 @@ fn test_compute_score() { for i in 0..19 { validator.history.arr_mut()[i].is_superminority = 1; } - let components = validator_score( - &validator, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -244,14 +207,8 @@ fn test_compute_score() { validator.history.arr_mut()[i].mev_commission = ValidatorHistoryEntry::default().mev_commission; } - let components = validator_score( - &validator, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -273,14 +230,8 @@ fn test_compute_score() { // commission let mut validator = good_validator; validator.history.last_mut().unwrap().commission = 11; - let components = validator_score( - &validator, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -310,14 +261,8 @@ 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, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -337,14 +282,8 @@ fn test_compute_score() { ); validator.history.arr[0].commission = 16; - let components = validator_score( - &validator, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -371,14 +310,8 @@ fn test_compute_score() { validator.history.arr_mut()[i].epoch_credits = 880; cluster_history.history.arr_mut()[i].total_blocks = 1000; } - let components = validator_score( - &validator, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -400,14 +333,8 @@ fn test_compute_score() { // delinquency let mut validator = good_validator; validator.history.arr[10].epoch_credits = 0; - let components = validator_score( - &validator, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -434,14 +361,8 @@ 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, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -466,14 +387,8 @@ 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, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).unwrap(); assert_eq!( components, ScoreComponents { @@ -505,27 +420,15 @@ 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, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ) - .unwrap(); + let components = + validator_score(&validator, &cluster_history, &config, current_epoch as u16).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, - validator.index as usize, - &cluster_history, - &config, - current_epoch as u16, - ); + let res = validator_score(&validator, &cluster_history, &config, current_epoch as u16); assert!(res == Err(StewardError::StakeHistoryNotRecentEnough.into())); } @@ -557,7 +460,6 @@ fn test_instant_unstake() { let res = instant_unstake_validator( &good_validator, - good_validator.index as usize, &cluster_history, &config, start_slot, @@ -580,17 +482,17 @@ fn test_instant_unstake() { // Is blacklisted config - .blacklist + .validator_history_blacklist .set(good_validator.index as usize, true) .unwrap(); let res = instant_unstake_validator( &good_validator, - good_validator.index as usize, &cluster_history, &config, start_slot, current_epoch, ); + assert!(res.is_ok()); assert!( res.unwrap() @@ -604,17 +506,17 @@ fn test_instant_unstake() { epoch: current_epoch } ); - config.blacklist.reset(); + config.validator_history_blacklist.reset(); // Delinquency threshold + Commission let res = instant_unstake_validator( &bad_validator, - bad_validator.index as usize, &cluster_history, &config, start_slot, current_epoch, ); + assert!(res.is_ok()); assert!( res.unwrap() @@ -635,12 +537,12 @@ fn test_instant_unstake() { ClusterHistoryEntry::default().total_blocks; let res = instant_unstake_validator( &bad_validator, - bad_validator.index as usize, &cluster_history, &config, start_slot, current_epoch, ); + assert!(res == Err(StewardError::ClusterHistoryNotRecentEnough.into())); let cluster_history = default_fixture.cluster_history; @@ -650,13 +552,26 @@ fn test_instant_unstake() { let res = instant_unstake_validator( &validator, - validator.index as usize, &cluster_history, &config, start_slot, current_epoch, ); - assert!(res == Err(StewardError::VoteHistoryNotRecentEnough.into())); + println!("NEED Error: {:?}", res); + + assert!(res.is_ok()); + assert!( + res.unwrap() + == InstantUnstakeComponents { + instant_unstake: true, + delinquency_check: true, + commission_check: false, + mev_commission_check: false, + is_blacklisted: false, + vote_account: validator.vote_account, + epoch: current_epoch + } + ); let mut validator = validators[0]; validator @@ -667,12 +582,12 @@ fn test_instant_unstake() { ValidatorHistoryEntry::default().vote_account_last_update_slot; let res = instant_unstake_validator( &validator, - validator.index as usize, &cluster_history, &config, start_slot, current_epoch, ); + assert!(res == Err(StewardError::VoteHistoryNotRecentEnough.into())); // Not sure how commission would be unset with epoch credits set but test anyway @@ -680,7 +595,6 @@ fn test_instant_unstake() { validator.history.last_mut().unwrap().commission = ValidatorHistoryEntry::default().commission; let res = instant_unstake_validator( &validator, - validator.index as usize, &cluster_history, &config, start_slot, @@ -705,7 +619,6 @@ fn test_instant_unstake() { ValidatorHistoryEntry::default().mev_commission; let res = instant_unstake_validator( &validator, - validator.index as usize, &cluster_history, &config, start_slot, @@ -730,7 +643,6 @@ fn test_instant_unstake() { cluster_history.history.last_mut().unwrap().total_blocks = 0; let res = instant_unstake_validator( &good_validator, - good_validator.index as usize, &cluster_history, &config, start_slot, diff --git a/tests/tests/steward/test_integration.rs b/tests/tests/steward/test_integration.rs index e8dcbc00..dcc0acc3 100644 --- a/tests/tests/steward/test_integration.rs +++ b/tests/tests/steward/test_integration.rs @@ -36,8 +36,8 @@ async fn test_compute_delegations() { let fixture = TestFixture::new().await; let ctx = &fixture.ctx; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; let clock: Clock = fixture.get_sysvar().await; @@ -101,7 +101,6 @@ async fn test_compute_delegations() { accounts: jito_steward::accounts::ComputeDelegations { config: fixture.steward_config.pubkey(), state_account: fixture.steward_state, - signer: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::ComputeDelegations {}.data(), @@ -146,7 +145,6 @@ async fn test_compute_delegations() { accounts: jito_steward::accounts::ComputeDelegations { config: fixture.steward_config.pubkey(), state_account: fixture.steward_state, - signer: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::ComputeDelegations {}.data(), @@ -173,8 +171,8 @@ async fn test_compute_scores() { let fixture = TestFixture::new().await; let ctx = &fixture.ctx; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; let epoch_credits: Vec<(u64, u64, u64)> = vec![(0, 1, 0), (1, 2, 1), (2, 3, 2), (3, 4, 3), (4, 5, 4)]; @@ -311,7 +309,6 @@ async fn test_compute_scores() { validator_history: validator_history_account, validator_list: fixture.stake_pool_meta.validator_list, cluster_history: cluster_history_account, - signer: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::ComputeScore { @@ -469,7 +466,7 @@ async fn test_compute_instant_unstake() { let ctx = &fixture.ctx; fixture.initialize_stake_pool().await; fixture - .initialize_config(Some(UpdateParametersArgs { + .initialize_steward(Some(UpdateParametersArgs { mev_commission_range: Some(0), // Set to pass validation, where epochs starts at 0 epoch_credits_range: Some(0), // Set to pass validation, where epochs starts at 0 commission_range: Some(0), // Set to pass validation, where epochs starts at 0 @@ -490,7 +487,7 @@ async fn test_compute_instant_unstake() { minimum_voting_epochs: Some(0), // Set to pass validation, where epochs starts at 0 })) .await; - fixture.initialize_steward_state().await; + fixture.realloc_steward_state().await; let epoch_credits = vec![(0, 1, 0), (1, 2, 1), (2, 3, 2), (3, 4, 3), (4, 5, 4)]; let vote_account = Pubkey::new_unique(); @@ -620,7 +617,6 @@ async fn test_compute_instant_unstake() { validator_history: validator_history_account, validator_list: fixture.stake_pool_meta.validator_list, cluster_history: cluster_history_account, - signer: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::ComputeInstantUnstake { @@ -703,8 +699,8 @@ async fn test_idle() { let fixture = TestFixture::new().await; let ctx = &fixture.ctx; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; let clock: Clock = fixture.get_sysvar().await; let epoch_schedule: EpochSchedule = fixture.get_sysvar().await; @@ -739,7 +735,6 @@ async fn test_idle() { accounts: jito_steward::accounts::Idle { config: fixture.steward_config.pubkey(), state_account: fixture.steward_state, - signer: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::Idle {}.data(), @@ -839,8 +834,8 @@ async fn test_rebalance_increase() { .advance_num_epochs(epoch_schedule.first_normal_epoch - clock.epoch, 10) .await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; let mut steward_config: Config = fixture .load_and_deserialize(&fixture.steward_config.pubkey()) @@ -969,7 +964,6 @@ async fn test_rebalance_increase() { config: fixture.steward_config.pubkey(), stake_pool_program: spl_stake_pool::id(), stake_pool: fixture.stake_pool_meta.stake_pool, - staker: fixture.staker, reserve_stake: fixture.stake_pool_meta.reserve, withdraw_authority, validator_list: fixture.stake_pool_meta.validator_list, @@ -981,7 +975,6 @@ async fn test_rebalance_increase() { stake_config: stake::config::ID, stake_program: stake::program::id(), system_program: solana_program::system_program::id(), - signer: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::AutoAddValidatorToPool {}.data(), @@ -996,7 +989,6 @@ async fn test_rebalance_increase() { stake_pool: fixture.stake_pool_meta.stake_pool, reserve_stake: fixture.stake_pool_meta.reserve, stake_pool_program: spl_stake_pool::id(), - staker: fixture.staker, withdraw_authority, vote_account, stake_account: stake_account_address, @@ -1007,7 +999,6 @@ async fn test_rebalance_increase() { stake_program: stake::program::id(), stake_config: stake::config::ID, stake_history: solana_program::sysvar::stake_history::id(), - signer: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::Rebalance { @@ -1059,7 +1050,13 @@ async fn test_rebalance_increase() { pool_minimum_delegation ); - let expected_transient_stake = reserve_before_rebalance.lamports - 2 * stake_rent; + let steward_state_account: StewardStateAccount = + fixture.load_and_deserialize(&fixture.steward_state).await; + + let validators_that_need_rent = steward_state_account.state.num_pool_validators + 1 + - (steward_state_account.state.progress.count() as u64 - 1); + let expected_transient_stake = + reserve_before_rebalance.lamports - (stake_rent * validators_that_need_rent); assert_eq!( transient_stake_account.stake().unwrap().delegation.stake, expected_transient_stake @@ -1078,8 +1075,8 @@ async fn test_rebalance_decrease() { .advance_num_epochs(epoch_schedule.first_normal_epoch - clock.epoch, 10) .await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; let mut steward_config: Config = fixture .load_and_deserialize(&fixture.steward_config.pubkey()) @@ -1203,7 +1200,6 @@ async fn test_rebalance_decrease() { config: fixture.steward_config.pubkey(), stake_pool_program: spl_stake_pool::id(), stake_pool: fixture.stake_pool_meta.stake_pool, - staker: fixture.staker, reserve_stake: fixture.stake_pool_meta.reserve, withdraw_authority, validator_list: fixture.stake_pool_meta.validator_list, @@ -1215,7 +1211,6 @@ async fn test_rebalance_decrease() { stake_config: stake::config::ID, stake_program: stake::program::id(), system_program: solana_program::system_program::id(), - signer: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::AutoAddValidatorToPool {}.data(), @@ -1307,7 +1302,6 @@ async fn test_rebalance_decrease() { stake_pool: fixture.stake_pool_meta.stake_pool, reserve_stake: fixture.stake_pool_meta.reserve, stake_pool_program: spl_stake_pool::id(), - staker: fixture.staker, withdraw_authority, vote_account, stake_account: stake_account_address, @@ -1318,7 +1312,6 @@ async fn test_rebalance_decrease() { stake_program: stake::program::id(), stake_config: stake::config::ID, stake_history: solana_program::sysvar::stake_history::id(), - signer: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::Rebalance { @@ -1382,8 +1375,8 @@ async fn test_rebalance_other_cases() { .advance_num_epochs(epoch_schedule.first_normal_epoch - clock.epoch, 10) .await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; let mut steward_config: Config = fixture .load_and_deserialize(&fixture.steward_config.pubkey()) @@ -1445,7 +1438,6 @@ async fn test_rebalance_other_cases() { config: fixture.steward_config.pubkey(), stake_pool_program: spl_stake_pool::id(), stake_pool: fixture.stake_pool_meta.stake_pool, - staker: fixture.staker, reserve_stake: fixture.stake_pool_meta.reserve, withdraw_authority, validator_list: fixture.stake_pool_meta.validator_list, @@ -1457,7 +1449,6 @@ async fn test_rebalance_other_cases() { stake_config: stake::config::ID, stake_program: stake::program::id(), system_program: solana_program::system_program::id(), - signer: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::AutoAddValidatorToPool {}.data(), @@ -1485,7 +1476,6 @@ async fn test_rebalance_other_cases() { stake_pool: fixture.stake_pool_meta.stake_pool, reserve_stake: fixture.stake_pool_meta.reserve, stake_pool_program: spl_stake_pool::id(), - staker: fixture.staker, withdraw_authority, vote_account, stake_account: stake_account_address, @@ -1496,7 +1486,6 @@ async fn test_rebalance_other_cases() { stake_program: stake::program::id(), stake_config: stake::config::ID, stake_history: solana_program::sysvar::stake_history::id(), - signer: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::Rebalance { diff --git a/tests/tests/steward/test_parameters.rs b/tests/tests/steward/test_parameters.rs index 591dce04..6665ab35 100644 --- a/tests/tests/steward/test_parameters.rs +++ b/tests/tests/steward/test_parameters.rs @@ -174,8 +174,8 @@ async fn _set_parameter(fixture: &TestFixture, update_parameters: &UpdateParamet async fn test_update_parameters() { let fixture = TestFixture::new().await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; _set_parameter( &fixture, diff --git a/tests/tests/steward/test_spl_passthrough.rs b/tests/tests/steward/test_spl_passthrough.rs index b0a7b080..1fc9e51f 100644 --- a/tests/tests/steward/test_spl_passthrough.rs +++ b/tests/tests/steward/test_spl_passthrough.rs @@ -6,8 +6,9 @@ use anchor_lang::{ }; use jito_steward::{ constants::MAX_VALIDATORS, + derive_steward_state_address, utils::{StakePool, ValidatorList}, - Config, Delegation, Staker, StewardStateAccount, StewardStateEnum, + Config, Delegation, StewardStateAccount, StewardStateEnum, }; use rand::prelude::SliceRandom; use rand::{rngs::StdRng, SeedableRng}; @@ -179,11 +180,10 @@ async fn _add_test_validator(fixture: &TestFixture, vote_account: Pubkey) { let instruction = Instruction { program_id: jito_steward::id(), accounts: jito_steward::accounts::AddValidatorToPool { - steward_state: fixture.steward_state, + state_account: fixture.steward_state, config: fixture.steward_config.pubkey(), stake_pool_program: spl_stake_pool::id(), stake_pool: fixture.stake_pool_meta.stake_pool, - staker: fixture.staker, reserve_stake: fixture.stake_pool_meta.reserve, withdraw_authority, validator_list: fixture.stake_pool_meta.validator_list, @@ -195,7 +195,7 @@ async fn _add_test_validator(fixture: &TestFixture, vote_account: Pubkey) { stake_config: stake::config::ID, system_program: system_program::id(), stake_program: stake::program::id(), - signer: fixture.keypair.pubkey(), + admin: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::AddValidatorToPool { @@ -242,11 +242,11 @@ async fn _set_and_check_preferred_validator( program_id: jito_steward::id(), accounts: jito_steward::accounts::SetPreferredValidator { config: fixture.steward_config.pubkey(), + state_account: fixture.steward_state, stake_pool_program: spl_stake_pool::id(), stake_pool: fixture.stake_pool_meta.stake_pool, - staker: fixture.staker, validator_list: fixture.stake_pool_meta.validator_list, - signer: fixture.keypair.pubkey(), + admin: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::SetPreferredValidator { @@ -325,11 +325,10 @@ async fn _increase_and_check_stake( program_id: jito_steward::id(), accounts: jito_steward::accounts::IncreaseValidatorStake { config: fixture.steward_config.pubkey(), - steward_state: fixture.steward_state, + state_account: fixture.steward_state, validator_history, stake_pool_program: spl_stake_pool::id(), stake_pool: fixture.stake_pool_meta.stake_pool, - staker: fixture.staker, withdraw_authority, validator_list: fixture.stake_pool_meta.validator_list, reserve_stake: fixture.stake_pool_meta.reserve, @@ -342,7 +341,7 @@ async fn _increase_and_check_stake( stake_config: stake::config::ID, system_program: system_program::id(), stake_program: stake::program::id(), - signer: fixture.keypair.pubkey(), + admin: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::IncreaseValidatorStake { @@ -418,11 +417,10 @@ async fn _increase_and_check_additional_stake( program_id: jito_steward::id(), accounts: jito_steward::accounts::IncreaseAdditionalValidatorStake { config: fixture.steward_config.pubkey(), - steward_state: fixture.steward_state, + state_account: fixture.steward_state, validator_history, stake_pool_program: spl_stake_pool::id(), stake_pool: fixture.stake_pool_meta.stake_pool, - staker: fixture.staker, withdraw_authority, validator_list: fixture.stake_pool_meta.validator_list, reserve_stake: fixture.stake_pool_meta.reserve, @@ -434,7 +432,7 @@ async fn _increase_and_check_additional_stake( stake_config: stake::config::ID, system_program: system_program::id(), stake_program: stake::program::id(), - signer: fixture.keypair.pubkey(), + admin: fixture.keypair.pubkey(), ephemeral_stake_account, } .to_account_metas(None), @@ -470,16 +468,16 @@ async fn _increase_and_check_additional_stake( ); } -pub async fn _set_staker(fixture: &TestFixture, staker: Pubkey, new_staker: Pubkey) { +pub async fn _set_staker(fixture: &TestFixture, new_staker: Pubkey) { let instruction = Instruction { program_id: jito_steward::id(), accounts: jito_steward::accounts::SetStaker { config: fixture.steward_config.pubkey(), stake_pool_program: spl_stake_pool::id(), stake_pool: fixture.stake_pool_meta.stake_pool, - staker, + state_account: fixture.steward_state, new_staker, - signer: fixture.keypair.pubkey(), + admin: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::SetStaker {}.data(), @@ -509,8 +507,8 @@ async fn test_add_validator_to_pool() { // Set up the test fixture let fixture = TestFixture::new().await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; { // Test add 1 validator @@ -532,8 +530,8 @@ async fn test_remove_validator_from_pool() { // Set up the test fixture let fixture = TestFixture::new().await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; // Setup the steward state // _setup_test_steward_state(&fixture, MAX_VALIDATORS, 1_000_000_000).await; @@ -562,10 +560,9 @@ async fn test_remove_validator_from_pool() { program_id: jito_steward::id(), accounts: jito_steward::accounts::RemoveValidatorFromPool { config: fixture.steward_config.pubkey(), - steward_state: fixture.steward_state, + state_account: fixture.steward_state, stake_pool_program: spl_stake_pool::id(), stake_pool: fixture.stake_pool_meta.stake_pool, - staker: fixture.staker, withdraw_authority, validator_list: fixture.stake_pool_meta.validator_list, stake_account: stake_account_address, @@ -573,7 +570,7 @@ async fn test_remove_validator_from_pool() { clock: sysvar::clock::id(), system_program: system_program::id(), stake_program: stake::program::id(), - signer: fixture.keypair.pubkey(), + admin: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::RemoveValidatorFromPool { @@ -627,8 +624,8 @@ async fn test_set_preferred_validator() { // Set up the test fixture let fixture = TestFixture::new().await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; // Assert the validator was added to the validator list _add_test_validator(&fixture, Pubkey::new_unique()).await; @@ -685,8 +682,8 @@ async fn test_increase_validator_stake() { let fixture = TestFixture::new().await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; // Assert the validator was added to the validator list _add_test_validator(&fixture, Pubkey::new_unique()).await; @@ -707,8 +704,8 @@ async fn test_decrease_validator_stake() { let fixture = TestFixture::new().await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; _add_test_validator(&fixture, Pubkey::new_unique()).await; @@ -742,11 +739,10 @@ async fn test_decrease_validator_stake() { program_id: jito_steward::id(), accounts: jito_steward::accounts::DecreaseValidatorStake { config: fixture.steward_config.pubkey(), - steward_state: fixture.steward_state, + state_account: fixture.steward_state, validator_history, stake_pool_program: spl_stake_pool::id(), stake_pool: fixture.stake_pool_meta.stake_pool, - staker: fixture.staker, withdraw_authority, validator_list: fixture.stake_pool_meta.validator_list, reserve_stake: fixture.stake_pool_meta.reserve, @@ -758,7 +754,7 @@ async fn test_decrease_validator_stake() { stake_history: sysvar::stake_history::id(), system_program: system_program::id(), stake_program: stake::program::id(), - signer: fixture.keypair.pubkey(), + admin: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::DecreaseValidatorStake { @@ -787,8 +783,8 @@ async fn test_increase_additional_validator_stake() { let fixture = TestFixture::new().await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; // Assert the validator was added to the validator list _add_test_validator(&fixture, Pubkey::new_unique()).await; @@ -810,8 +806,8 @@ async fn test_decrease_additional_validator_stake() { let fixture = TestFixture::new().await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; _add_test_validator(&fixture, Pubkey::new_unique()).await; @@ -858,11 +854,10 @@ async fn test_decrease_additional_validator_stake() { program_id: jito_steward::id(), accounts: jito_steward::accounts::DecreaseAdditionalValidatorStake { config: fixture.steward_config.pubkey(), - steward_state: fixture.steward_state, + state_account: fixture.steward_state, validator_history, stake_pool_program: spl_stake_pool::id(), stake_pool: fixture.stake_pool_meta.stake_pool, - staker: fixture.staker, withdraw_authority, validator_list: fixture.stake_pool_meta.validator_list, reserve_stake: fixture.stake_pool_meta.reserve, @@ -873,7 +868,7 @@ async fn test_decrease_additional_validator_stake() { stake_history: sysvar::stake_history::id(), system_program: system_program::id(), stake_program: stake::program::id(), - signer: fixture.keypair.pubkey(), + admin: fixture.keypair.pubkey(), ephemeral_stake_account, } .to_account_metas(None), @@ -905,8 +900,8 @@ async fn test_set_staker() { // Set up the test fixture let fixture = TestFixture::new().await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; let new_staker = Keypair::new(); @@ -921,15 +916,12 @@ async fn test_set_staker() { StakePool::try_deserialize_unchecked(&mut stake_pool_account_raw.data.as_slice()) .expect("Failed to deserialize stake pool account"); - let (staker, _) = Pubkey::find_program_address( - &[Staker::SEED, fixture.steward_config.pubkey().as_ref()], - &jito_steward::id(), - ); + let (steward_state, _) = derive_steward_state_address(&fixture.steward_config.pubkey()); // Assert accounts are set up correctly - assert!(stake_pool_account.staker.eq(&staker)); - assert!(fixture.staker.eq(&staker)); - assert!(config_account.authority.eq(&fixture.keypair.pubkey())); + assert!(stake_pool_account.staker.eq(&steward_state)); + assert!(fixture.steward_state.eq(&steward_state)); + assert!(config_account.admin.eq(&fixture.keypair.pubkey())); assert!(config_account .stake_pool .eq(&fixture.stake_pool_meta.stake_pool)); @@ -937,12 +929,12 @@ async fn test_set_staker() { { // Test 1: Set staker to same staker - _set_staker(&fixture, fixture.staker, fixture.staker).await; + _set_staker(&fixture, fixture.steward_state).await; } { // Test 2: Set staker to different staker - _set_staker(&fixture, fixture.staker, new_staker.pubkey()).await; + _set_staker(&fixture, new_staker.pubkey()).await; } drop(fixture); diff --git a/tests/tests/steward/test_state_methods.rs b/tests/tests/steward/test_state_methods.rs index da660681..7bab19ff 100644 --- a/tests/tests/steward/test_state_methods.rs +++ b/tests/tests/steward/test_state_methods.rs @@ -151,7 +151,7 @@ fn test_compute_scores() { // Test blacklist validator config - .blacklist + .validator_history_blacklist .set(validators[0].index as usize, true) .unwrap(); let res = state.compute_score( @@ -446,7 +446,7 @@ fn test_compute_instant_unstake_success() { state.progress.reset(); state.instant_unstake.reset(); config - .blacklist + .validator_history_blacklist .set(validators[0].index as usize, true) .unwrap(); diff --git a/tests/tests/steward/test_steward.rs b/tests/tests/steward/test_steward.rs index 6f759cb0..4126bd3e 100644 --- a/tests/tests/steward/test_steward.rs +++ b/tests/tests/steward/test_steward.rs @@ -3,7 +3,9 @@ use anchor_lang::{ solana_program::{instruction::Instruction, pubkey::Pubkey, stake, sysvar}, InstructionData, ToAccountMetas, }; -use jito_steward::{utils::ValidatorList, Config, StewardStateAccount}; +use jito_steward::{ + instructions::AuthorityType, utils::ValidatorList, Config, StewardStateAccount, +}; use solana_program_test::*; use solana_sdk::{signature::Keypair, signer::Signer, transaction::Transaction}; use tests::steward_fixtures::{ @@ -46,7 +48,6 @@ async fn _auto_add_validator_to_pool(fixture: &TestFixture, vote_account: &Pubke config: fixture.steward_config.pubkey(), stake_pool_program: spl_stake_pool::id(), stake_pool: fixture.stake_pool_meta.stake_pool, - staker: fixture.staker, reserve_stake: fixture.stake_pool_meta.reserve, withdraw_authority, validator_list: fixture.stake_pool_meta.validator_list, @@ -58,7 +59,6 @@ async fn _auto_add_validator_to_pool(fixture: &TestFixture, vote_account: &Pubke stake_config: stake::config::ID, stake_program: stake::program::id(), system_program: solana_program::system_program::id(), - signer: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::AutoAddValidatorToPool {}.data(), @@ -108,8 +108,8 @@ async fn test_auto_add_validator_to_pool() { let fixture = TestFixture::new().await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; _auto_add_validator_to_pool(&fixture, &Pubkey::new_unique()).await; @@ -121,8 +121,8 @@ async fn test_auto_remove() { let fixture = TestFixture::new().await; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; - fixture.initialize_steward_state().await; + fixture.initialize_steward(None).await; + fixture.realloc_steward_state().await; let vote_account = Pubkey::new_unique(); @@ -135,7 +135,10 @@ async fn test_auto_remove() { fixture.stake_accounts_for_validator(vote_account).await; // Add vote account + println!("DID STEWARD STATE"); + _auto_add_validator_to_pool(&fixture, &vote_account).await; + println!("ADDED VALIDATOR"); let auto_remove_validator_ix = Instruction { program_id: jito_steward::id(), @@ -145,7 +148,6 @@ async fn test_auto_remove() { state_account: fixture.steward_state, stake_pool_program: spl_stake_pool::id(), stake_pool: fixture.stake_pool_meta.stake_pool, - staker: fixture.staker, reserve_stake: fixture.stake_pool_meta.reserve, withdraw_authority, validator_list: fixture.stake_pool_meta.validator_list, @@ -158,7 +160,6 @@ async fn test_auto_remove() { stake_config: stake::config::ID, stake_program: stake::program::id(), system_program: solana_program::system_program::id(), - signer: fixture.keypair.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::AutoRemoveValidatorFromPool { @@ -207,7 +208,7 @@ async fn test_pause() { let fixture = TestFixture::new().await; let ctx = &fixture.ctx; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; + fixture.initialize_steward(None).await; let ix = Instruction { program_id: jito_steward::id(), @@ -266,7 +267,7 @@ async fn test_blacklist() { let fixture = TestFixture::new().await; let ctx = &fixture.ctx; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; + fixture.initialize_steward(None).await; let ix = Instruction { program_id: jito_steward::id(), @@ -275,7 +276,10 @@ async fn test_blacklist() { authority: fixture.keypair.pubkey(), } .to_account_metas(None), - data: jito_steward::instruction::AddValidatorToBlacklist { index: 0 }.data(), + data: jito_steward::instruction::AddValidatorToBlacklist { + validator_history_blacklist: 0, + } + .data(), }; let tx = Transaction::new_signed_with_payer( @@ -290,7 +294,7 @@ async fn test_blacklist() { let config: Config = fixture .load_and_deserialize(&fixture.steward_config.pubkey()) .await; - assert!(config.blacklist.get(0).unwrap()); + assert!(config.validator_history_blacklist.get(0).unwrap()); let ix = Instruction { program_id: jito_steward::id(), @@ -299,7 +303,10 @@ async fn test_blacklist() { authority: fixture.keypair.pubkey(), } .to_account_metas(None), - data: jito_steward::instruction::RemoveValidatorFromBlacklist { index: 0 }.data(), + data: jito_steward::instruction::RemoveValidatorFromBlacklist { + validator_history_blacklist: 0, + } + .data(), }; let tx = Transaction::new_signed_with_payer( @@ -313,7 +320,7 @@ async fn test_blacklist() { let config: Config = fixture .load_and_deserialize(&fixture.steward_config.pubkey()) .await; - assert!(!config.blacklist.get(0).unwrap()); + assert!(!config.validator_history_blacklist.get(0).unwrap()); drop(fixture); } @@ -323,7 +330,7 @@ async fn test_set_new_authority() { let fixture = TestFixture::new().await; let ctx = &fixture.ctx; fixture.initialize_stake_pool().await; - fixture.initialize_config(None).await; + fixture.initialize_steward(None).await; // Regular test let new_authority = Keypair::new(); @@ -337,10 +344,13 @@ async fn test_set_new_authority() { accounts: jito_steward::accounts::SetNewAuthority { config: fixture.steward_config.pubkey(), new_authority: new_authority.pubkey(), - authority: fixture.keypair.pubkey(), + admin: fixture.keypair.pubkey(), } .to_account_metas(None), - data: jito_steward::instruction::SetNewAuthority {}.data(), + data: jito_steward::instruction::SetNewAuthority { + authority_type: AuthorityType::SetAdmin, + } + .data(), }; let tx = Transaction::new_signed_with_payer( &[ix], @@ -354,7 +364,58 @@ async fn test_set_new_authority() { let config: Config = fixture .load_and_deserialize(&fixture.steward_config.pubkey()) .await; - assert!(config.authority == new_authority.pubkey()); + assert!(config.admin == new_authority.pubkey()); + + let ix = Instruction { + program_id: jito_steward::id(), + accounts: jito_steward::accounts::SetNewAuthority { + config: fixture.steward_config.pubkey(), + new_authority: new_authority.pubkey(), + admin: new_authority.pubkey(), + } + .to_account_metas(None), + data: jito_steward::instruction::SetNewAuthority { + authority_type: AuthorityType::SetBlacklistAuthority, + } + .data(), + }; + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&new_authority.pubkey()), + &[&new_authority], + ctx.borrow().last_blockhash, + ); + + fixture.submit_transaction_assert_success(tx).await; + + let ix = Instruction { + program_id: jito_steward::id(), + accounts: jito_steward::accounts::SetNewAuthority { + config: fixture.steward_config.pubkey(), + new_authority: new_authority.pubkey(), + admin: new_authority.pubkey(), + } + .to_account_metas(None), + data: jito_steward::instruction::SetNewAuthority { + authority_type: AuthorityType::SetParametersAuthority, + } + .data(), + }; + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&new_authority.pubkey()), + &[&new_authority], + ctx.borrow().last_blockhash, + ); + + fixture.submit_transaction_assert_success(tx).await; + + let config: Config = fixture + .load_and_deserialize(&fixture.steward_config.pubkey()) + .await; + assert!(config.admin == new_authority.pubkey()); + assert!(config.blacklist_authority == new_authority.pubkey()); + assert!(config.parameters_authority == new_authority.pubkey()); // Try to transfer back with original authority let ix = Instruction { @@ -362,21 +423,29 @@ async fn test_set_new_authority() { accounts: jito_steward::accounts::SetNewAuthority { config: fixture.steward_config.pubkey(), new_authority: fixture.keypair.pubkey(), - authority: fixture.keypair.pubkey(), + admin: new_authority.pubkey(), } .to_account_metas(None), - data: jito_steward::instruction::SetNewAuthority {}.data(), + data: jito_steward::instruction::SetNewAuthority { + authority_type: AuthorityType::SetAdmin, + } + .data(), }; let tx = Transaction::new_signed_with_payer( &[ix], - Some(&fixture.keypair.pubkey()), - &[&fixture.keypair], + Some(&new_authority.pubkey()), + &[&new_authority], ctx.borrow().last_blockhash, ); - fixture - .submit_transaction_assert_error(tx, "Unauthorized") + fixture.submit_transaction_assert_success(tx).await; + + let config: Config = fixture + .load_and_deserialize(&fixture.steward_config.pubkey()) .await; + assert!(config.admin == fixture.keypair.pubkey()); + assert!(config.blacklist_authority == new_authority.pubkey()); + assert!(config.parameters_authority == new_authority.pubkey()); drop(fixture); } diff --git a/utils/steward-cli/Cargo.toml b/utils/steward-cli/Cargo.toml index 4a9e9e70..8134dbb6 100644 --- a/utils/steward-cli/Cargo.toml +++ b/utils/steward-cli/Cargo.toml @@ -6,9 +6,13 @@ description = "CLI to manage the steward program" [dependencies] anchor-lang = "0.30.0" +anyhow = "1.0.86" clap = { version = "4.3.0", features = ["derive", "env"] } +dotenv = "0.15.0" futures = "0.3.21" futures-util = "0.3.21" +jito-steward = { features = ["no-entrypoint"], path = "../../programs/steward" } +keeper-core = { path = "../../keepers/keeper-core" } log = "0.4.18" solana-account-decoder = "1.18" solana-clap-utils = "1.18" @@ -16,11 +20,7 @@ solana-client = "1.18" solana-metrics = "1.18" solana-program = "1.18" solana-sdk = "1.18" -thiserror = "1.0.37" spl-stake-pool = { features = ["no-entrypoint"], version = "1.0.0" } +thiserror = "1.0.37" tokio = { version = "1.36.0", features = ["full"] } validator-history = { features = ["no-entrypoint"], path = "../../programs/validator-history" } -jito-steward = { features = ["no-entrypoint"], path = "../../programs/steward" } -keeper-core = { path = "../../keepers/keeper-core" } -dotenv = "0.15.0" -anyhow = "1.0.86" diff --git a/utils/steward-cli/src/commands/actions/auto_add_validator_from_pool.rs b/utils/steward-cli/src/commands/actions/auto_add_validator_from_pool.rs index e0b7206c..9bcea96d 100644 --- a/utils/steward-cli/src/commands/actions/auto_add_validator_from_pool.rs +++ b/utils/steward-cli/src/commands/actions/auto_add_validator_from_pool.rs @@ -56,7 +56,6 @@ pub async fn command_auto_add_validator_from_pool( config: args.permissionless_parameters.steward_config, stake_pool_program: spl_stake_pool::id(), stake_pool: steward_accounts.stake_pool_address, - staker: steward_accounts.staker_address, reserve_stake: steward_accounts.stake_pool_account.reserve_stake, withdraw_authority: steward_accounts.stake_pool_withdraw_authority, validator_list: steward_accounts.validator_list_address, @@ -68,7 +67,6 @@ pub async fn command_auto_add_validator_from_pool( stake_config: stake::config::ID, system_program: system_program::id(), stake_program: stake::program::id(), - signer: payer.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::AutoAddValidatorToPool {}.data(), diff --git a/utils/steward-cli/src/commands/actions/auto_remove_validator_from_pool.rs b/utils/steward-cli/src/commands/actions/auto_remove_validator_from_pool.rs index 9fa2f442..d6cd47be 100644 --- a/utils/steward-cli/src/commands/actions/auto_remove_validator_from_pool.rs +++ b/utils/steward-cli/src/commands/actions/auto_remove_validator_from_pool.rs @@ -68,7 +68,6 @@ pub async fn command_auto_remove_validator_from_pool( state_account: steward_accounts.state_address, stake_pool_program: spl_stake_pool::id(), stake_pool: steward_accounts.stake_pool_address, - staker: steward_accounts.staker_address, reserve_stake: steward_accounts.stake_pool_account.reserve_stake, withdraw_authority: steward_accounts.stake_pool_withdraw_authority, validator_list: steward_accounts.validator_list_address, @@ -81,7 +80,6 @@ pub async fn command_auto_remove_validator_from_pool( stake_config: stake::config::ID, system_program: system_program::id(), stake_program: stake::program::id(), - signer: payer.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::AutoRemoveValidatorFromPool { diff --git a/utils/steward-cli/src/commands/actions/remove_bad_validators.rs b/utils/steward-cli/src/commands/actions/remove_bad_validators.rs index a444ec42..e7740d6b 100644 --- a/utils/steward-cli/src/commands/actions/remove_bad_validators.rs +++ b/utils/steward-cli/src/commands/actions/remove_bad_validators.rs @@ -106,12 +106,11 @@ pub async fn command_remove_bad_validators( Instruction { program_id, accounts: jito_steward::accounts::RemoveValidatorFromPool { - signer: arc_payer.pubkey(), + admin: arc_payer.pubkey(), config: steward_config, - steward_state: steward_accounts.state_address, + state_account: steward_accounts.state_address, stake_pool_program: spl_stake_pool::id(), stake_pool: steward_accounts.stake_pool_address, - staker: steward_accounts.stake_pool_account.staker, withdraw_authority: steward_accounts.stake_pool_withdraw_authority, validator_list: steward_accounts.validator_list_address, stake_account: stake_address, diff --git a/utils/steward-cli/src/commands/cranks/compute_delegations.rs b/utils/steward-cli/src/commands/cranks/compute_delegations.rs index d26183cd..e88073e2 100644 --- a/utils/steward-cli/src/commands/cranks/compute_delegations.rs +++ b/utils/steward-cli/src/commands/cranks/compute_delegations.rs @@ -47,7 +47,6 @@ pub async fn command_crank_compute_delegations( accounts: jito_steward::accounts::ComputeDelegations { config: steward_config, state_account: state_address, - signer: payer.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::ComputeDelegations {}.data(), diff --git a/utils/steward-cli/src/commands/cranks/compute_instant_unstake.rs b/utils/steward-cli/src/commands/cranks/compute_instant_unstake.rs index c4f5f7eb..98921476 100644 --- a/utils/steward-cli/src/commands/cranks/compute_instant_unstake.rs +++ b/utils/steward-cli/src/commands/cranks/compute_instant_unstake.rs @@ -7,7 +7,7 @@ use solana_client::nonblocking::rpc_client::RpcClient; use solana_program::instruction::Instruction; use validator_history::id as validator_history_id; -use solana_sdk::{pubkey::Pubkey, signature::read_keypair_file, signer::Signer}; +use solana_sdk::{pubkey::Pubkey, signature::read_keypair_file}; use crate::{ commands::command_args::CrankComputeInstantUnstake, @@ -80,7 +80,6 @@ pub async fn command_crank_compute_instant_unstake( validator_history: *history_account, validator_list: steward_accounts.validator_list_address, cluster_history, - signer: payer.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::ComputeInstantUnstake { diff --git a/utils/steward-cli/src/commands/cranks/compute_score.rs b/utils/steward-cli/src/commands/cranks/compute_score.rs index 92d888a8..8d2fc086 100644 --- a/utils/steward-cli/src/commands/cranks/compute_score.rs +++ b/utils/steward-cli/src/commands/cranks/compute_score.rs @@ -7,7 +7,7 @@ use solana_client::nonblocking::rpc_client::RpcClient; use solana_program::instruction::Instruction; use validator_history::id as validator_history_id; -use solana_sdk::{pubkey::Pubkey, signature::read_keypair_file, signer::Signer}; +use solana_sdk::{pubkey::Pubkey, signature::read_keypair_file}; use crate::{ commands::command_args::CrankComputeScore, @@ -86,7 +86,6 @@ pub async fn command_crank_compute_score( validator_history: *history_account, validator_list: steward_accounts.validator_list_address, cluster_history, - signer: payer.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::ComputeScore { diff --git a/utils/steward-cli/src/commands/cranks/idle.rs b/utils/steward-cli/src/commands/cranks/idle.rs index 353cd5f2..bc6d6c52 100644 --- a/utils/steward-cli/src/commands/cranks/idle.rs +++ b/utils/steward-cli/src/commands/cranks/idle.rs @@ -44,7 +44,6 @@ pub async fn command_crank_idle( accounts: jito_steward::accounts::Idle { config: steward_config, state_account: state_address, - signer: payer.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::Idle {}.data(), diff --git a/utils/steward-cli/src/commands/cranks/rebalance.rs b/utils/steward-cli/src/commands/cranks/rebalance.rs index 62b94f4b..308260ee 100644 --- a/utils/steward-cli/src/commands/cranks/rebalance.rs +++ b/utils/steward-cli/src/commands/cranks/rebalance.rs @@ -8,9 +8,7 @@ use solana_program::instruction::Instruction; use spl_stake_pool::{find_stake_program_address, find_transient_stake_program_address}; use validator_history::id as validator_history_id; -use solana_sdk::{ - pubkey::Pubkey, signature::read_keypair_file, signer::Signer, stake, system_program, -}; +use solana_sdk::{pubkey::Pubkey, signature::read_keypair_file, stake, system_program}; use crate::{ commands::command_args::CrankRebalance, @@ -97,7 +95,6 @@ pub async fn command_crank_rebalance( validator_history: *history_account, stake_pool_program: spl_stake_pool::id(), stake_pool: steward_accounts.stake_pool_address, - staker: steward_accounts.staker_address, withdraw_authority: steward_accounts.stake_pool_withdraw_authority, validator_list: steward_accounts.validator_list_address, reserve_stake: steward_accounts.stake_pool_account.reserve_stake, @@ -110,7 +107,6 @@ pub async fn command_crank_rebalance( clock: solana_sdk::sysvar::clock::id(), stake_history: solana_sdk::sysvar::stake_history::id(), stake_config: stake::config::ID, - signer: payer.pubkey(), } .to_account_metas(None), data: jito_steward::instruction::Rebalance { diff --git a/utils/steward-cli/src/commands/info/view_config.rs b/utils/steward-cli/src/commands/info/view_config.rs index 75805309..f1fb389c 100644 --- a/utils/steward-cli/src/commands/info/view_config.rs +++ b/utils/steward-cli/src/commands/info/view_config.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use anyhow::Result; -use jito_steward::{Config, Staker}; +use jito_steward::Config; use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::pubkey::Pubkey; @@ -20,38 +20,34 @@ pub async fn command_view_config( let steward_config_account = get_steward_config_account(client, &steward_config).await?; let steward_state = get_steward_state_address(&program_id, &steward_config); - let (steward_staker, _) = - Pubkey::find_program_address(&[Staker::SEED, steward_config.as_ref()], &program_id); // let mut output = String::new(); // Initialize the string directly - _print_default_config( - &steward_config, - &steward_state, - &steward_staker, - &steward_config_account, - ); + _print_default_config(&steward_config, &steward_state, &steward_config_account); Ok(()) } -fn _print_default_config( - steward_config: &Pubkey, - steward_state: &Pubkey, - steward_staker: &Pubkey, - config_account: &Config, -) { +fn _print_default_config(steward_config: &Pubkey, steward_state: &Pubkey, config_account: &Config) { let mut formatted_string = String::new(); formatted_string += "------- Config -------\n"; formatted_string += "📚 Accounts 📚\n"; formatted_string += &format!("Config: {}\n", steward_config); - formatted_string += &format!("Authority: {}\n", config_account.authority); - formatted_string += &format!("Staker: {}\n", steward_staker); + formatted_string += &format!("Admin: {}\n", config_account.admin); + formatted_string += &format!("Blacklist Auth: {}\n", config_account.blacklist_authority); + formatted_string += &format!( + "Parameter Auth: {}\n", + config_account.parameters_authority + ); + formatted_string += &format!("Staker (State): {}\n", steward_state); formatted_string += &format!("State: {}\n", steward_state); formatted_string += &format!("Stake Pool: {}\n", config_account.stake_pool); formatted_string += "\n↺ State ↺\n"; formatted_string += &format!("Is Paused: {:?}\n", config_account.paused); - formatted_string += &format!("Blacklisted: {:?}\n", config_account.blacklist.count()); + formatted_string += &format!( + "Blacklisted: {:?}\n", + config_account.validator_history_blacklist.count() + ); formatted_string += "\n⚙️ Parameters ⚙️\n"; formatted_string += &format!( "Commission Range: {:?}\n", diff --git a/utils/steward-cli/src/commands/info/view_state.rs b/utils/steward-cli/src/commands/info/view_state.rs index a96d8073..af0d9b78 100644 --- a/utils/steward-cli/src/commands/info/view_state.rs +++ b/utils/steward-cli/src/commands/info/view_state.rs @@ -81,10 +81,6 @@ fn _print_verbose_state(steward_state_accounts: &UsefulStewardAccounts) { u64::from(validator.active_stake_lamports) ); formatted_string += &format!("Index: {:?}\n", index); - formatted_string += &format!( - "Is Blacklisted: {:?}\n", - steward_state_accounts.config_account.blacklist.get(index) - ); formatted_string += &format!( "Is Instant Unstake: {:?}\n", steward_state_accounts diff --git a/utils/steward-cli/src/commands/init/init_state.rs b/utils/steward-cli/src/commands/init/init_state.rs index 76290bdf..f347a815 100644 --- a/utils/steward-cli/src/commands/init/init_state.rs +++ b/utils/steward-cli/src/commands/init/init_state.rs @@ -21,7 +21,6 @@ use crate::{ }, }; -const MAX_REALLOCS: usize = (StewardStateAccount::SIZE - MAX_ALLOC_BYTES) / MAX_ALLOC_BYTES + 1; const REALLOCS_PER_TX: usize = 10; pub async fn command_init_state( @@ -44,49 +43,25 @@ pub async fn command_init_state( let validator_list = stake_pool_account.validator_list; - let mut reallocs_left_to_run = MAX_REALLOCS; - let mut should_create = true; - - match client.get_account(&steward_state).await { - Ok(steward_state_account_raw) => { - if steward_state_account_raw.data.len() == StewardStateAccount::SIZE { - match StewardStateAccount::try_deserialize( - &mut steward_state_account_raw.data.as_slice(), - ) { - Ok(steward_state_account) => { - if steward_state_account.is_initialized.into() { - println!("State account already exists"); - return Ok(()); - } - } - Err(_) => { /* Account is not initialized, continue */ } - }; - } - - // if it already exists, we don't need to create it - should_create = false; - - let data_length = steward_state_account_raw.data.len(); - let whats_left = StewardStateAccount::SIZE - data_length.min(StewardStateAccount::SIZE); + let steward_state_account_raw = client.get_account(&steward_state).await?; - reallocs_left_to_run = - (whats_left.max(MAX_ALLOC_BYTES) - MAX_ALLOC_BYTES) / MAX_ALLOC_BYTES + 1; - } - Err(_) => { /* Account does not exist, continue */ } + if steward_state_account_raw.data.len() == StewardStateAccount::SIZE { + match StewardStateAccount::try_deserialize(&mut steward_state_account_raw.data.as_slice()) { + Ok(steward_state_account) => { + if steward_state_account.is_initialized.into() { + println!("State account already exists"); + return Ok(()); + } + } + Err(_) => { /* Account is not initialized, continue */ } + }; } - if should_create { - let signature = _create_state( - client, - &program_id, - &authority, - &steward_state, - &steward_config, - ) - .await?; + let data_length = steward_state_account_raw.data.len(); + let whats_left = StewardStateAccount::SIZE - data_length.min(StewardStateAccount::SIZE); - println!("Created Steward State: {}", signature); - } + let mut reallocs_left_to_run = + (whats_left.max(MAX_ALLOC_BYTES) - MAX_ALLOC_BYTES) / MAX_ALLOC_BYTES + 1; let reallocs_to_run = reallocs_left_to_run; let mut reallocs_ran = 0; @@ -128,41 +103,6 @@ pub async fn command_init_state( Ok(()) } -async fn _create_state( - client: &RpcClient, - program_id: &Pubkey, - authority: &Keypair, - steward_state: &Pubkey, - steward_config: &Pubkey, -) -> Result { - let init_ix = Instruction { - program_id: *program_id, - accounts: jito_steward::accounts::InitializeState { - state_account: *steward_state, - config: *steward_config, - system_program: anchor_lang::solana_program::system_program::id(), - signer: authority.pubkey(), - } - .to_account_metas(None), - data: jito_steward::instruction::InitializeState {}.data(), - }; - - let blockhash = client.get_latest_blockhash().await?; - - let transaction = Transaction::new_signed_with_payer( - &[init_ix], - Some(&authority.pubkey()), - &[&authority], - blockhash, - ); - - let signature = client - .send_and_confirm_transaction_with_spinner(&transaction) - .await?; - - Ok(signature) -} - #[allow(clippy::too_many_arguments)] async fn _realloc_x_times( client: &RpcClient, diff --git a/utils/steward-cli/src/commands/init/init_config.rs b/utils/steward-cli/src/commands/init/init_steward.rs similarity index 83% rename from utils/steward-cli/src/commands/init/init_config.rs rename to utils/steward-cli/src/commands/init/init_steward.rs index 9aa80084..44e64bfb 100644 --- a/utils/steward-cli/src/commands/init/init_config.rs +++ b/utils/steward-cli/src/commands/init/init_steward.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use anchor_lang::{InstructionData, ToAccountMetas}; use anyhow::Result; -use jito_steward::UpdateParametersArgs; +use jito_steward::{derive_steward_state_address, UpdateParametersArgs}; use solana_client::nonblocking::rpc_client::RpcClient; use solana_program::instruction::Instruction; @@ -13,10 +13,7 @@ use solana_sdk::{ transaction::Transaction, }; -use crate::{ - commands::command_args::InitConfig, - utils::{accounts::get_steward_staker_address, transactions::configure_instruction}, -}; +use crate::{commands::command_args::InitConfig, utils::transactions::configure_instruction}; pub async fn command_init_config( args: InitConfig, @@ -44,7 +41,7 @@ pub async fn command_init_config( } }; - let steward_staker = get_steward_staker_address(&program_id, &steward_config.pubkey()); + let (state_account, _) = derive_steward_state_address(&steward_config.pubkey()); let update_parameters_args: UpdateParametersArgs = args.config_parameters.into(); @@ -61,17 +58,16 @@ pub async fn command_init_config( let init_ix = Instruction { program_id, - accounts: jito_steward::accounts::InitializeConfig { + accounts: jito_steward::accounts::InitializeSteward { config: steward_config.pubkey(), stake_pool: args.stake_pool, - staker: steward_staker, + state_account, stake_pool_program: spl_stake_pool::id(), system_program: anchor_lang::solana_program::system_program::id(), - signer: staker_keypair.pubkey(), + current_staker: staker_keypair.pubkey(), } .to_account_metas(None), - data: jito_steward::instruction::InitializeConfig { - authority: authority.pubkey(), + data: jito_steward::instruction::InitializeSteward { update_parameters_args, } .data(), diff --git a/utils/steward-cli/src/commands/init/mod.rs b/utils/steward-cli/src/commands/init/mod.rs index 07eea724..d1692dc5 100644 --- a/utils/steward-cli/src/commands/init/mod.rs +++ b/utils/steward-cli/src/commands/init/mod.rs @@ -1,2 +1,2 @@ -pub mod init_config; pub mod init_state; +pub mod init_steward; diff --git a/utils/steward-cli/src/main.rs b/utils/steward-cli/src/main.rs index 46a27416..79e941a3 100644 --- a/utils/steward-cli/src/main.rs +++ b/utils/steward-cli/src/main.rs @@ -20,7 +20,7 @@ use commands::{ view_next_index_to_remove::command_view_next_index_to_remove, view_state::command_view_state, }, - init::{init_config::command_init_config, init_state::command_init_state}, + init::{init_state::command_init_state, init_steward::command_init_config}, }; use dotenv::dotenv; use solana_client::nonblocking::rpc_client::RpcClient; diff --git a/utils/steward-cli/src/utils/accounts.rs b/utils/steward-cli/src/utils/accounts.rs index ea3c01ea..a3cc8395 100644 --- a/utils/steward-cli/src/utils/accounts.rs +++ b/utils/steward-cli/src/utils/accounts.rs @@ -2,7 +2,7 @@ use anchor_lang::AccountDeserialize; use anyhow::Result; use jito_steward::{ utils::{StakePool, ValidatorList}, - Config, Staker, StewardStateAccount, + Config, StewardStateAccount, }; use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::pubkey::Pubkey; @@ -11,8 +11,6 @@ use validator_history::{ClusterHistory, ValidatorHistory}; pub struct UsefulStewardAccounts { pub config_account: Config, - pub staker_account: Staker, - pub staker_address: Pubkey, pub state_account: StewardStateAccount, pub state_address: Pubkey, pub stake_pool_account: StakePool, @@ -32,8 +30,7 @@ pub async fn get_all_steward_accounts( get_steward_state_account(client, program_id, steward_config).await?; let stake_pool_address = config_account.stake_pool; let stake_pool_account = get_stake_pool_account(client, &stake_pool_address).await?; - let (staker_account, staker_address) = - get_steward_staker_account(client, program_id, steward_config).await?; + let stake_pool_withdraw_authority = get_withdraw_authority_address(&stake_pool_address); let validator_list_address = stake_pool_account.validator_list; let validator_list_account = @@ -43,8 +40,6 @@ pub async fn get_all_steward_accounts( config_account, state_account, state_address, - staker_account, - staker_address, stake_pool_account, stake_pool_address, stake_pool_withdraw_authority, @@ -102,28 +97,6 @@ pub fn get_withdraw_authority_address(stake_pool_address: &Pubkey) -> Pubkey { withdraw_authority } -pub fn get_steward_staker_address(program_id: &Pubkey, steward_config: &Pubkey) -> Pubkey { - let (steward_staker, _) = - Pubkey::find_program_address(&[Staker::SEED, steward_config.as_ref()], program_id); - - steward_staker -} - -pub async fn get_steward_staker_account( - client: &RpcClient, - program_id: &Pubkey, - steward_config: &Pubkey, -) -> Result<(Staker, Pubkey)> { - let steward_staker = get_steward_staker_address(program_id, steward_config); - - let staker_raw_account = client.get_account(&steward_staker).await?; - - Ok(( - Staker::try_deserialize(&mut staker_raw_account.data.as_slice())?, - steward_staker, - )) -} - pub async fn get_validator_list_account( client: &RpcClient, validator_list: &Pubkey,