Skip to content

Commit

Permalink
Blacklist instructions accept multiple validators (#83)
Browse files Browse the repository at this point in the history
Update both adding and removing instructions to take in a Vec<u32> of
validator history indices for updating the blacklist. This makes
multisig IXs for bulk adding to the blacklist much easier.
  • Loading branch information
ebatsell authored Sep 12, 2024
1 parent 9585307 commit 4ec761c
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 103 deletions.
136 changes: 70 additions & 66 deletions programs/steward/idl/steward.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,6 @@
"description": "Program for permissionlessly managing an SPL Stake Pool"
},
"instructions": [
{
"name": "add_validator_to_blacklist",
"docs": [
"Adds the validator at `index` to the blacklist. It will be instant unstaked and never receive delegations"
],
"discriminator": [
18,
30,
248,
201,
28,
196,
137,
118
],
"accounts": [
{
"name": "config",
"writable": true
},
{
"name": "authority",
"writable": true,
"signer": true
}
],
"args": [
{
"name": "validator_history_blacklist",
"type": "u32"
}
]
},
{
"name": "add_validator_to_pool",
"docs": [
Expand Down Expand Up @@ -121,6 +88,41 @@
}
]
},
{
"name": "add_validators_to_blacklist",
"docs": [
"Adds the validators to the blacklist. They will be instant unstaked and never receive delegations. Each u32 is a ValidatorHistory index."
],
"discriminator": [
204,
81,
61,
86,
100,
92,
226,
86
],
"accounts": [
{
"name": "config",
"writable": true
},
{
"name": "authority",
"writable": true,
"signer": true
}
],
"args": [
{
"name": "validator_history_blacklist",
"type": {
"vec": "u32"
}
}
]
},
{
"name": "admin_mark_for_removal",
"docs": [
Expand Down Expand Up @@ -1133,39 +1135,6 @@
}
]
},
{
"name": "remove_validator_from_blacklist",
"docs": [
"Removes the validator at `index` from the blacklist"
],
"discriminator": [
253,
48,
101,
237,
109,
14,
153,
208
],
"accounts": [
{
"name": "config",
"writable": true
},
{
"name": "authority",
"writable": true,
"signer": true
}
],
"args": [
{
"name": "validator_history_blacklist",
"type": "u32"
}
]
},
{
"name": "remove_validator_from_pool",
"docs": [
Expand Down Expand Up @@ -1233,6 +1202,41 @@
}
]
},
{
"name": "remove_validators_from_blacklist",
"docs": [
"Removes the validators from the blacklist. Each u32 is a ValidatorHistory index."
],
"discriminator": [
233,
114,
77,
164,
159,
209,
137,
137
],
"accounts": [
{
"name": "config",
"writable": true
},
{
"name": "authority",
"writable": true,
"signer": true
}
],
"args": [
{
"name": "validator_history_blacklist",
"type": {
"vec": "u32"
}
}
]
},
{
"name": "reset_steward_state",
"docs": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{utils::get_config_blacklist_authority, Config};
use anchor_lang::prelude::*;

#[derive(Accounts)]
pub struct AddValidatorToBlacklist<'info> {
pub struct AddValidatorsToBlacklist<'info> {
#[account(mut)]
pub config: AccountLoader<'info, Config>,

Expand All @@ -12,10 +12,15 @@ pub struct AddValidatorToBlacklist<'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<AddValidatorToBlacklist>, validator_history_index: u32) -> Result<()> {
pub fn handler(
ctx: Context<AddValidatorsToBlacklist>,
validator_history_indices: &[u32],
) -> Result<()> {
let mut config = ctx.accounts.config.load_mut()?;
config
.validator_history_blacklist
.set(validator_history_index as usize, true)?;
for index in validator_history_indices {
config
.validator_history_blacklist
.set(*index as usize, true)?;
}
Ok(())
}
8 changes: 4 additions & 4 deletions programs/steward/src/instructions/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![allow(ambiguous_glob_reexports)]
pub mod add_validator_to_blacklist;
pub mod add_validators_to_blacklist;
pub mod admin_mark_for_removal;
pub mod auto_add_validator_to_pool;
pub mod auto_remove_validator_from_pool;
Expand All @@ -14,15 +14,15 @@ pub mod instant_remove_validator;
pub mod pause_steward;
pub mod realloc_state;
pub mod rebalance;
pub mod remove_validator_from_blacklist;
pub mod remove_validators_from_blacklist;
pub mod reset_steward_state;
pub mod reset_validator_lamport_balances;
pub mod resume_steward;
pub mod set_new_authority;
pub mod spl_passthrough;
pub mod update_parameters;

pub use add_validator_to_blacklist::*;
pub use add_validators_to_blacklist::*;
pub use admin_mark_for_removal::*;
pub use auto_add_validator_to_pool::*;
pub use auto_remove_validator_from_pool::*;
Expand All @@ -37,7 +37,7 @@ pub use instant_remove_validator::*;
pub use pause_steward::*;
pub use realloc_state::*;
pub use rebalance::*;
pub use remove_validator_from_blacklist::*;
pub use remove_validators_from_blacklist::*;
pub use reset_steward_state::*;
pub use reset_validator_lamport_balances::*;
pub use resume_steward::*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{utils::get_config_blacklist_authority, Config};
use anchor_lang::prelude::*;

#[derive(Accounts)]
pub struct RemoveValidatorFromBlacklist<'info> {
pub struct RemoveValidatorsFromBlacklist<'info> {
#[account(mut)]
pub config: AccountLoader<'info, Config>,

Expand All @@ -13,12 +13,14 @@ pub struct RemoveValidatorFromBlacklist<'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<RemoveValidatorFromBlacklist>,
validator_history_index: u32,
ctx: Context<RemoveValidatorsFromBlacklist>,
validator_history_indices: &[u32],
) -> Result<()> {
let mut config = ctx.accounts.config.load_mut()?;
config
.validator_history_blacklist
.set(validator_history_index as usize, false)?;
for index in validator_history_indices {
config
.validator_history_blacklist
.set(*index as usize, false)?;
}
Ok(())
}
20 changes: 10 additions & 10 deletions programs/steward/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,20 +163,20 @@ pub mod steward {
instructions::resume_steward::handler(ctx)
}

/// 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<AddValidatorToBlacklist>,
validator_history_blacklist: u32,
/// Adds the validators to the blacklist. They will be instant unstaked and never receive delegations. Each u32 is a ValidatorHistory index.
pub fn add_validators_to_blacklist(
ctx: Context<AddValidatorsToBlacklist>,
validator_history_blacklist: Vec<u32>,
) -> Result<()> {
instructions::add_validator_to_blacklist::handler(ctx, validator_history_blacklist)
instructions::add_validators_to_blacklist::handler(ctx, &validator_history_blacklist)
}

/// Removes the validator at `index` from the blacklist
pub fn remove_validator_from_blacklist(
ctx: Context<RemoveValidatorFromBlacklist>,
validator_history_blacklist: u32,
/// Removes the validators from the blacklist. Each u32 is a ValidatorHistory index.
pub fn remove_validators_from_blacklist(
ctx: Context<RemoveValidatorsFromBlacklist>,
validator_history_blacklist: Vec<u32>,
) -> Result<()> {
instructions::remove_validator_from_blacklist::handler(ctx, validator_history_blacklist)
instructions::remove_validators_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
Expand Down
80 changes: 74 additions & 6 deletions tests/tests/steward/test_steward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,13 +294,13 @@ async fn test_blacklist() {

let ix = Instruction {
program_id: jito_steward::id(),
accounts: jito_steward::accounts::AddValidatorToBlacklist {
accounts: jito_steward::accounts::AddValidatorsToBlacklist {
config: fixture.steward_config.pubkey(),
authority: fixture.keypair.pubkey(),
}
.to_account_metas(None),
data: jito_steward::instruction::AddValidatorToBlacklist {
validator_history_blacklist: 0,
data: jito_steward::instruction::AddValidatorsToBlacklist {
validator_history_blacklist: vec![0, 4, 8],
}
.data(),
};
Expand All @@ -318,16 +318,18 @@ async fn test_blacklist() {
.load_and_deserialize(&fixture.steward_config.pubkey())
.await;
assert!(config.validator_history_blacklist.get(0).unwrap());
assert!(config.validator_history_blacklist.get(4).unwrap());
assert!(config.validator_history_blacklist.get(8).unwrap());

let ix = Instruction {
program_id: jito_steward::id(),
accounts: jito_steward::accounts::RemoveValidatorFromBlacklist {
accounts: jito_steward::accounts::RemoveValidatorsFromBlacklist {
config: fixture.steward_config.pubkey(),
authority: fixture.keypair.pubkey(),
}
.to_account_metas(None),
data: jito_steward::instruction::RemoveValidatorFromBlacklist {
validator_history_blacklist: 0,
data: jito_steward::instruction::RemoveValidatorsFromBlacklist {
validator_history_blacklist: vec![4, 0],
}
.data(),
};
Expand All @@ -344,6 +346,72 @@ async fn test_blacklist() {
.load_and_deserialize(&fixture.steward_config.pubkey())
.await;
assert!(!config.validator_history_blacklist.get(0).unwrap());
assert!(!config.validator_history_blacklist.get(4).unwrap());
assert!(config.validator_history_blacklist.get(8).unwrap());
}

#[tokio::test]
async fn test_blacklist_edge_cases() {
let fixture = TestFixture::new().await;
let ctx = &fixture.ctx;
fixture.initialize_stake_pool().await;
fixture.initialize_steward(None).await;

// Test empty blacklist should not change anything
let ix = Instruction {
program_id: jito_steward::id(),
accounts: jito_steward::accounts::RemoveValidatorsFromBlacklist {
config: fixture.steward_config.pubkey(),
authority: fixture.keypair.pubkey(),
}
.to_account_metas(None),
data: jito_steward::instruction::RemoveValidatorsFromBlacklist {
validator_history_blacklist: vec![],
}
.data(),
};

let tx = Transaction::new_signed_with_payer(
&[ix],
Some(&fixture.keypair.pubkey()),
&[&fixture.keypair],
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.validator_history_blacklist.is_empty());

// Test deactivating a validator that is not in the blacklist shouldn't break anything
let ix = Instruction {
program_id: jito_steward::id(),
accounts: jito_steward::accounts::RemoveValidatorsFromBlacklist {
config: fixture.steward_config.pubkey(),
authority: fixture.keypair.pubkey(),
}
.to_account_metas(None),
data: jito_steward::instruction::RemoveValidatorsFromBlacklist {
validator_history_blacklist: vec![1],
}
.data(),
};

let tx = Transaction::new_signed_with_payer(
&[ix],
Some(&fixture.keypair.pubkey()),
&[&fixture.keypair],
ctx.borrow().last_blockhash,
);
fixture.submit_transaction_assert_success(tx).await;

// assert nothing changed
let config: Config = fixture
.load_and_deserialize(&fixture.steward_config.pubkey())
.await;
assert!(config.validator_history_blacklist.is_empty());

drop(fixture);
}
Expand Down
Loading

0 comments on commit 4ec761c

Please sign in to comment.