Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit ff8b418

Browse files
stake-pool: make update_validator_list_balance() more ergonomic (#6058)
* remove unnecessary vote acc slice * nightly fmt * fix clippy * remove redundant check * restore deprecated update_validator_list_balance, rename update_validator_list_balance_chunk * fix tests * option -> result * fmt
1 parent 80b62da commit ff8b418

16 files changed

+156
-210
lines changed

stake-pool/program/src/instruction.rs

Lines changed: 94 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ use {
88
find_stake_program_address, find_transient_stake_program_address,
99
find_withdraw_authority_program_address,
1010
inline_mpl_token_metadata::{self, pda::find_metadata_account},
11-
state::{Fee, FeeType, StakePool, ValidatorList},
11+
state::{Fee, FeeType, StakePool, ValidatorList, ValidatorStakeInfo},
1212
MAX_VALIDATORS_TO_UPDATE,
1313
},
1414
borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
1515
solana_program::{
1616
instruction::{AccountMeta, Instruction},
17+
program_error::ProgramError,
1718
pubkey::Pubkey,
1819
stake, system_program, sysvar,
1920
},
@@ -1363,6 +1364,10 @@ pub fn decrease_additional_validator_stake_with_vote(
13631364

13641365
/// Creates `UpdateValidatorListBalance` instruction (update validator stake
13651366
/// account balances)
1367+
#[deprecated(
1368+
since = "1.1.0",
1369+
note = "please use `update_validator_list_balance_chunk`"
1370+
)]
13661371
pub fn update_validator_list_balance(
13671372
program_id: &Pubkey,
13681373
stake_pool: &Pubkey,
@@ -1423,6 +1428,74 @@ pub fn update_validator_list_balance(
14231428
}
14241429
}
14251430

1431+
/// Creates an `UpdateValidatorListBalance` instruction (update validator stake
1432+
/// account balances) to update `validator_list[start_index..start_index +
1433+
/// len]`.
1434+
///
1435+
/// Returns `Err(ProgramError::InvalidInstructionData)` if:
1436+
/// - `start_index..start_index + len` is out of bounds for
1437+
/// `validator_list.validators`
1438+
pub fn update_validator_list_balance_chunk(
1439+
program_id: &Pubkey,
1440+
stake_pool: &Pubkey,
1441+
stake_pool_withdraw_authority: &Pubkey,
1442+
validator_list_address: &Pubkey,
1443+
reserve_stake: &Pubkey,
1444+
validator_list: &ValidatorList,
1445+
len: usize,
1446+
start_index: usize,
1447+
no_merge: bool,
1448+
) -> Result<Instruction, ProgramError> {
1449+
let mut accounts = vec![
1450+
AccountMeta::new_readonly(*stake_pool, false),
1451+
AccountMeta::new_readonly(*stake_pool_withdraw_authority, false),
1452+
AccountMeta::new(*validator_list_address, false),
1453+
AccountMeta::new(*reserve_stake, false),
1454+
AccountMeta::new_readonly(sysvar::clock::id(), false),
1455+
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
1456+
AccountMeta::new_readonly(stake::program::id(), false),
1457+
];
1458+
let validator_list_subslice = validator_list
1459+
.validators
1460+
.get(start_index..start_index.saturating_add(len))
1461+
.ok_or(ProgramError::InvalidInstructionData)?;
1462+
accounts.extend(validator_list_subslice.iter().flat_map(
1463+
|ValidatorStakeInfo {
1464+
vote_account_address,
1465+
validator_seed_suffix,
1466+
transient_seed_suffix,
1467+
..
1468+
}| {
1469+
let (validator_stake_account, _) = find_stake_program_address(
1470+
program_id,
1471+
vote_account_address,
1472+
stake_pool,
1473+
NonZeroU32::new((*validator_seed_suffix).into()),
1474+
);
1475+
let (transient_stake_account, _) = find_transient_stake_program_address(
1476+
program_id,
1477+
vote_account_address,
1478+
stake_pool,
1479+
(*transient_seed_suffix).into(),
1480+
);
1481+
[
1482+
AccountMeta::new(validator_stake_account, false),
1483+
AccountMeta::new(transient_stake_account, false),
1484+
]
1485+
},
1486+
));
1487+
Ok(Instruction {
1488+
program_id: *program_id,
1489+
accounts,
1490+
data: StakePoolInstruction::UpdateValidatorListBalance {
1491+
start_index: start_index.try_into().unwrap(),
1492+
no_merge,
1493+
}
1494+
.try_to_vec()
1495+
.unwrap(),
1496+
})
1497+
}
1498+
14261499
/// Creates `UpdateStakePoolBalance` instruction (pool balance from the stake
14271500
/// account list balances)
14281501
pub fn update_stake_pool_balance(
@@ -1482,31 +1555,29 @@ pub fn update_stake_pool(
14821555
stake_pool_address: &Pubkey,
14831556
no_merge: bool,
14841557
) -> (Vec<Instruction>, Vec<Instruction>) {
1485-
let vote_accounts: Vec<Pubkey> = validator_list
1486-
.validators
1487-
.iter()
1488-
.map(|item| item.vote_account_address)
1489-
.collect();
1490-
14911558
let (withdraw_authority, _) =
14921559
find_withdraw_authority_program_address(program_id, stake_pool_address);
14931560

1494-
let mut update_list_instructions: Vec<Instruction> = vec![];
1495-
let mut start_index = 0;
1496-
for accounts_chunk in vote_accounts.chunks(MAX_VALIDATORS_TO_UPDATE) {
1497-
update_list_instructions.push(update_validator_list_balance(
1498-
program_id,
1499-
stake_pool_address,
1500-
&withdraw_authority,
1501-
&stake_pool.validator_list,
1502-
&stake_pool.reserve_stake,
1503-
validator_list,
1504-
accounts_chunk,
1505-
start_index,
1506-
no_merge,
1507-
));
1508-
start_index = start_index.saturating_add(MAX_VALIDATORS_TO_UPDATE as u32);
1509-
}
1561+
let update_list_instructions = validator_list
1562+
.validators
1563+
.chunks(MAX_VALIDATORS_TO_UPDATE)
1564+
.enumerate()
1565+
.map(|(i, chunk)| {
1566+
// unwrap-safety: chunk len and offset are derived
1567+
update_validator_list_balance_chunk(
1568+
program_id,
1569+
stake_pool_address,
1570+
&withdraw_authority,
1571+
&stake_pool.validator_list,
1572+
&stake_pool.reserve_stake,
1573+
validator_list,
1574+
chunk.len(),
1575+
i.saturating_mul(MAX_VALIDATORS_TO_UPDATE),
1576+
no_merge,
1577+
)
1578+
.unwrap()
1579+
})
1580+
.collect();
15101581

15111582
let final_instructions = vec![
15121583
update_stake_pool_balance(

stake-pool/program/tests/decrease.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,6 @@ async fn fail_additional_with_increasing() {
624624
&mut context.banks_client,
625625
&context.payer,
626626
&last_blockhash,
627-
&[validator_stake.vote.pubkey()],
628627
false,
629628
)
630629
.await;

stake-pool/program/tests/deposit.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ async fn setup(
9494
&mut context.banks_client,
9595
&context.payer,
9696
&context.last_blockhash,
97-
&[validator_stake_account.vote.pubkey()],
9897
false,
9998
)
10099
.await;

stake-pool/program/tests/deposit_edge_cases.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ async fn setup(
8787
&mut context.banks_client,
8888
&context.payer,
8989
&context.last_blockhash,
90-
&[validator_stake_account.vote.pubkey()],
9190
false,
9291
)
9392
.await;

stake-pool/program/tests/force_destake.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ async fn success_update() {
155155
&mut context.banks_client,
156156
&context.payer,
157157
&context.last_blockhash,
158-
&[voter_pubkey],
159158
false,
160159
)
161160
.await;
@@ -272,7 +271,6 @@ async fn success_remove_validator() {
272271
&mut context.banks_client,
273272
&context.payer,
274273
&context.last_blockhash,
275-
&[voter_pubkey],
276274
false,
277275
)
278276
.await;
@@ -311,7 +309,6 @@ async fn success_remove_validator() {
311309
&mut context.banks_client,
312310
&context.payer,
313311
&context.last_blockhash,
314-
&[voter_pubkey],
315312
false,
316313
)
317314
.await;

stake-pool/program/tests/helpers/mod.rs

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use {
3232
instruction, minimum_delegation,
3333
processor::Processor,
3434
state::{self, FeeType, FutureEpoch, StakePool, ValidatorList},
35-
MINIMUM_RESERVE_LAMPORTS,
35+
MAX_VALIDATORS_TO_UPDATE, MINIMUM_RESERVE_LAMPORTS,
3636
},
3737
spl_token_2022::{
3838
extension::{ExtensionType, StateWithExtensionsOwned},
@@ -1412,21 +1412,22 @@ impl StakePoolAccounts {
14121412
banks_client: &mut BanksClient,
14131413
payer: &Keypair,
14141414
recent_blockhash: &Hash,
1415-
validator_vote_accounts: &[Pubkey],
1415+
len: usize,
14161416
no_merge: bool,
14171417
) -> Option<TransportError> {
14181418
let validator_list = self.get_validator_list(banks_client).await;
1419-
let mut instructions = vec![instruction::update_validator_list_balance(
1419+
let mut instructions = vec![instruction::update_validator_list_balance_chunk(
14201420
&id(),
14211421
&self.stake_pool.pubkey(),
14221422
&self.withdraw_authority,
14231423
&self.validator_list.pubkey(),
14241424
&self.reserve_stake.pubkey(),
14251425
&validator_list,
1426-
validator_vote_accounts,
1426+
len,
14271427
0,
14281428
no_merge,
1429-
)];
1429+
)
1430+
.unwrap()];
14301431
self.maybe_add_compute_budget_instruction(&mut instructions);
14311432
let transaction = Transaction::new_signed_with_payer(
14321433
&instructions,
@@ -1501,22 +1502,31 @@ impl StakePoolAccounts {
15011502
banks_client: &mut BanksClient,
15021503
payer: &Keypair,
15031504
recent_blockhash: &Hash,
1504-
validator_vote_accounts: &[Pubkey],
15051505
no_merge: bool,
15061506
) -> Option<TransportError> {
15071507
let validator_list = self.get_validator_list(banks_client).await;
1508-
let mut instructions = vec![
1509-
instruction::update_validator_list_balance(
1510-
&id(),
1511-
&self.stake_pool.pubkey(),
1512-
&self.withdraw_authority,
1513-
&self.validator_list.pubkey(),
1514-
&self.reserve_stake.pubkey(),
1515-
&validator_list,
1516-
validator_vote_accounts,
1517-
0,
1518-
no_merge,
1519-
),
1508+
let mut instructions = vec![];
1509+
for (i, chunk) in validator_list
1510+
.validators
1511+
.chunks(MAX_VALIDATORS_TO_UPDATE)
1512+
.enumerate()
1513+
{
1514+
instructions.push(
1515+
instruction::update_validator_list_balance_chunk(
1516+
&id(),
1517+
&self.stake_pool.pubkey(),
1518+
&self.withdraw_authority,
1519+
&self.validator_list.pubkey(),
1520+
&self.reserve_stake.pubkey(),
1521+
&validator_list,
1522+
chunk.len(),
1523+
i * MAX_VALIDATORS_TO_UPDATE,
1524+
no_merge,
1525+
)
1526+
.unwrap(),
1527+
);
1528+
}
1529+
instructions.extend([
15201530
instruction::update_stake_pool_balance(
15211531
&id(),
15221532
&self.stake_pool.pubkey(),
@@ -1532,7 +1542,7 @@ impl StakePoolAccounts {
15321542
&self.stake_pool.pubkey(),
15331543
&self.validator_list.pubkey(),
15341544
),
1535-
];
1545+
]);
15361546
self.maybe_add_compute_budget_instruction(&mut instructions);
15371547
let transaction = Transaction::new_signed_with_payer(
15381548
&instructions,

stake-pool/program/tests/huge_pool.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,15 @@ async fn setup(
172172
#[test_case(MAX_POOL_SIZE; "no-compute-budget")]
173173
#[tokio::test]
174174
async fn update(max_validators: u32) {
175-
let (mut context, stake_pool_accounts, vote_account_pubkeys, _, _, _, _) =
175+
let (mut context, stake_pool_accounts, _, _, _, _, _) =
176176
setup(max_validators, max_validators, STAKE_AMOUNT).await;
177177

178178
let error = stake_pool_accounts
179179
.update_validator_list_balance(
180180
&mut context.banks_client,
181181
&context.payer,
182182
&context.last_blockhash,
183-
&vote_account_pubkeys[0..MAX_VALIDATORS_TO_UPDATE],
183+
MAX_VALIDATORS_TO_UPDATE,
184184
false, /* no_merge */
185185
)
186186
.await;
@@ -335,23 +335,24 @@ async fn remove_validator_from_pool(max_validators: u32) {
335335
&mut context.banks_client,
336336
&context.payer,
337337
&context.last_blockhash,
338-
&[first_vote],
338+
1,
339339
false, /* no_merge */
340340
)
341341
.await;
342342
assert!(error.is_none(), "{:?}", error);
343343

344-
let mut instructions = vec![instruction::update_validator_list_balance(
344+
let mut instructions = vec![instruction::update_validator_list_balance_chunk(
345345
&id(),
346346
&stake_pool_accounts.stake_pool.pubkey(),
347347
&stake_pool_accounts.withdraw_authority,
348348
&stake_pool_accounts.validator_list.pubkey(),
349349
&stake_pool_accounts.reserve_stake.pubkey(),
350350
&validator_list,
351-
&[middle_vote],
352-
middle_index as u32,
351+
1,
352+
middle_index,
353353
/* no_merge = */ false,
354-
)];
354+
)
355+
.unwrap()];
355356
stake_pool_accounts.maybe_add_compute_budget_instruction(&mut instructions);
356357
let transaction = Transaction::new_signed_with_payer(
357358
&instructions,
@@ -366,17 +367,18 @@ async fn remove_validator_from_pool(max_validators: u32) {
366367
.err();
367368
assert!(error.is_none(), "{:?}", error);
368369

369-
let mut instructions = vec![instruction::update_validator_list_balance(
370+
let mut instructions = vec![instruction::update_validator_list_balance_chunk(
370371
&id(),
371372
&stake_pool_accounts.stake_pool.pubkey(),
372373
&stake_pool_accounts.withdraw_authority,
373374
&stake_pool_accounts.validator_list.pubkey(),
374375
&stake_pool_accounts.reserve_stake.pubkey(),
375376
&validator_list,
376-
&[last_vote],
377-
last_index as u32,
377+
1,
378+
last_index,
378379
/* no_merge = */ false,
379-
)];
380+
)
381+
.unwrap()];
380382
stake_pool_accounts.maybe_add_compute_budget_instruction(&mut instructions);
381383
let transaction = Transaction::new_signed_with_payer(
382384
&instructions,

stake-pool/program/tests/increase.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,6 @@ async fn fail_additional_with_decreasing() {
548548
&mut context.banks_client,
549549
&context.payer,
550550
&last_blockhash,
551-
&[validator_stake.vote.pubkey()],
552551
false,
553552
)
554553
.await;

0 commit comments

Comments
 (0)