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

Commit 1d6cd5d

Browse files
committed
Add another test for hijacked account
1 parent d5257e4 commit 1d6cd5d

File tree

2 files changed

+43
-20
lines changed

2 files changed

+43
-20
lines changed

stake-pool/program/src/processor.rs

+21-8
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,17 @@ fn check_account_owner(
134134
}
135135
}
136136

137+
/// Checks if a stake acount can be managed by the pool
138+
fn stake_is_usable_by_pool(
139+
meta: &stake::state::Meta,
140+
expected_authority: &Pubkey,
141+
expected_lockup: &stake::state::Lockup,
142+
) -> bool {
143+
meta.authorized.staker == *expected_authority
144+
&& meta.authorized.withdrawer == *expected_authority
145+
&& meta.lockup == *expected_lockup
146+
}
147+
137148
/// Create a transient stake account without transferring lamports
138149
fn create_transient_stake_account<'a>(
139150
transient_stake_account_info: AccountInfo<'a>,
@@ -1541,10 +1552,11 @@ impl Processor {
15411552
// * not a stake -> ignore
15421553
match transient_stake_state {
15431554
Some(stake::state::StakeState::Initialized(meta)) => {
1544-
// if transient account was hijacked, ignore it
1545-
if meta.authorized.staker == *withdraw_authority_info.key
1546-
&& meta.authorized.withdrawer == *withdraw_authority_info.key
1547-
{
1555+
if stake_is_usable_by_pool(
1556+
&meta,
1557+
withdraw_authority_info.key,
1558+
&stake_pool.lockup,
1559+
) {
15481560
if no_merge {
15491561
transient_stake_lamports = transient_stake_info.lamports();
15501562
} else {
@@ -1569,10 +1581,11 @@ impl Processor {
15691581
}
15701582
}
15711583
Some(stake::state::StakeState::Stake(meta, stake)) => {
1572-
// if transient account was hijacked, ignore it
1573-
if meta.authorized.staker == *withdraw_authority_info.key
1574-
&& meta.authorized.withdrawer == *withdraw_authority_info.key
1575-
{
1584+
if stake_is_usable_by_pool(
1585+
&meta,
1586+
withdraw_authority_info.key,
1587+
&stake_pool.lockup,
1588+
) {
15761589
let account_stake = meta
15771590
.rent_exempt_reserve
15781591
.saturating_add(stake.delegation.stake);

stake-pool/program/tests/update_validator_list_balance.rs

+22-12
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ use {
77
solana_program::{borsh::try_from_slice_unchecked, program_pack::Pack, pubkey::Pubkey, stake},
88
solana_program_test::*,
99
solana_sdk::{
10+
stake::state::{Authorized, Lockup, StakeState},
1011
signature::{Keypair, Signer},
1112
system_instruction,
1213
transaction::Transaction,
1314
},
1415
spl_stake_pool::{
15-
find_transient_stake_program_address, id, instruction,
16+
find_withdraw_authority_program_address, find_transient_stake_program_address, id, instruction,
1617
state::{StakePool, StakeStatus, ValidatorList},
1718
MAX_VALIDATORS_TO_UPDATE, MINIMUM_ACTIVE_STAKE, MINIMUM_RESERVE_LAMPORTS,
1819
},
@@ -163,7 +164,7 @@ async fn success() {
163164

164165
// Check current balance in the list
165166
let rent = context.banks_client.get_rent().await.unwrap();
166-
let stake_rent = rent.minimum_balance(std::mem::size_of::<stake::state::StakeState>());
167+
let stake_rent = rent.minimum_balance(std::mem::size_of::<StakeState>());
167168
// initially, have all of the deposits plus their rent, and the reserve stake
168169
let initial_lamports =
169170
(validator_lamports + stake_rent) * num_validators as u64 + reserve_lamports;
@@ -436,7 +437,7 @@ async fn merge_into_validator_stake() {
436437

437438
// Check validator stake accounts have the expected balance now:
438439
// validator stake account minimum + deposited lamports + rents + increased lamports
439-
let stake_rent = rent.minimum_balance(std::mem::size_of::<stake::state::StakeState>());
440+
let stake_rent = rent.minimum_balance(std::mem::size_of::<StakeState>());
440441
let expected_lamports = MINIMUM_ACTIVE_STAKE
441442
+ lamports
442443
+ reserve_lamports / stake_accounts.len() as u64
@@ -466,7 +467,7 @@ async fn merge_transient_stake_after_remove() {
466467
setup(1).await;
467468

468469
let rent = context.banks_client.get_rent().await.unwrap();
469-
let stake_rent = rent.minimum_balance(std::mem::size_of::<stake::state::StakeState>());
470+
let stake_rent = rent.minimum_balance(std::mem::size_of::<StakeState>());
470471
let deactivated_lamports = lamports;
471472
let new_authority = Pubkey::new_unique();
472473
let destination_stake = Keypair::new();
@@ -677,20 +678,33 @@ async fn success_with_burned_tokens() {
677678
}
678679

679680
#[tokio::test]
680-
async fn success_ignoring_hijacked_transient_stake() {
681+
async fn success_ignoring_hijacked_transient_stake_with_authorized() {
682+
let hijacker = Pubkey::new_unique();
683+
check_ignored_hijacked_transient_stake(Some(&Authorized::auto(&hijacker)), None).await;
684+
}
685+
686+
#[tokio::test]
687+
async fn success_ignoring_hijacked_transient_stake_with_lockup() {
688+
let hijacker = Pubkey::new_unique();
689+
check_ignored_hijacked_transient_stake(None, Some(&Lockup { custodian: hijacker, ..Lockup::default() })).await;
690+
}
691+
692+
async fn check_ignored_hijacked_transient_stake(hijack_authorized: Option<&Authorized>, hijack_lockup: Option<&Lockup>) {
681693
let num_validators = 1;
682694
let (mut context, stake_pool_accounts, stake_accounts, _, lamports, _, mut slot) =
683695
setup(num_validators).await;
684696

685697
let rent = context.banks_client.get_rent().await.unwrap();
686-
let stake_rent = rent.minimum_balance(std::mem::size_of::<stake::state::StakeState>());
698+
let stake_rent = rent.minimum_balance(std::mem::size_of::<StakeState>());
687699

688700
let pre_lamports = get_validator_list_sum(
689701
&mut context.banks_client,
690702
&stake_pool_accounts.reserve_stake.pubkey(),
691703
&stake_pool_accounts.validator_list.pubkey(),
692704
)
693705
.await;
706+
let (withdraw_authority, _) =
707+
find_withdraw_authority_program_address(&id(), &stake_pool_accounts.stake_pool.pubkey());
694708

695709
println!("Decrease from all validators");
696710
let stake_account = &stake_accounts[0];
@@ -716,7 +730,6 @@ async fn success_ignoring_hijacked_transient_stake() {
716730
let validator_list = stake_pool_accounts
717731
.get_validator_list(&mut context.banks_client)
718732
.await;
719-
let hijacker = Pubkey::new_unique();
720733
let transient_stake_address = find_transient_stake_program_address(
721734
&id(),
722735
&stake_account.vote.pubkey(),
@@ -744,11 +757,8 @@ async fn success_ignoring_hijacked_transient_stake() {
744757
),
745758
stake::instruction::initialize(
746759
&transient_stake_address,
747-
&stake::state::Authorized {
748-
staker: hijacker,
749-
withdrawer: hijacker,
750-
},
751-
&stake::state::Lockup::default(),
760+
&hijack_authorized.unwrap_or(&Authorized::auto(&withdraw_authority)),
761+
&hijack_lockup.unwrap_or(&Lockup::default()),
752762
),
753763
instruction::update_stake_pool_balance(
754764
&id(),

0 commit comments

Comments
 (0)