diff --git a/Cargo.lock b/Cargo.lock index ebc54b40..a2c71222 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -730,9 +730,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" dependencies = [ "serde", ] @@ -7468,6 +7468,7 @@ dependencies = [ name = "spl-stake-pool" version = "2.0.3" dependencies = [ + "agave-feature-set", "arrayref", "assert_matches", "bincode", diff --git a/program/Cargo.toml b/program/Cargo.toml index b0044933..4f4bdec7 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -33,6 +33,7 @@ thiserror = "2.0" bincode = "1.3.1" [dev-dependencies] +agave-feature-set = "2.3.4" assert_matches = "1.5.0" proptest = "1.7" solana-program-test = "2.3.4" diff --git a/program/tests/deposit.rs b/program/tests/deposit.rs index ff2f0475..4c9cb69d 100644 --- a/program/tests/deposit.rs +++ b/program/tests/deposit.rs @@ -7,11 +7,11 @@ use { borsh1::try_from_slice_unchecked, instruction::{AccountMeta, Instruction, InstructionError}, pubkey::Pubkey, - sysvar, }, solana_program_test::*, solana_sdk::{ signature::{Keypair, Signer}, + sysvar, transaction::{Transaction, TransactionError}, transport::TransportError, }, @@ -87,6 +87,7 @@ async fn setup( let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; context.warp_to_slot(first_normal_slot + 1).unwrap(); + fix_stake_history(&mut context).await; stake_pool_accounts .update_all( &mut context.banks_client, diff --git a/program/tests/deposit_edge_cases.rs b/program/tests/deposit_edge_cases.rs index 25822dd0..f9fe6918 100644 --- a/program/tests/deposit_edge_cases.rs +++ b/program/tests/deposit_edge_cases.rs @@ -81,6 +81,7 @@ async fn setup( let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; context.warp_to_slot(first_normal_slot + 1).unwrap(); + fix_stake_history(&mut context).await; stake_pool_accounts .update_all( &mut context.banks_client, diff --git a/program/tests/fixtures/solana_stake_program.so b/program/tests/fixtures/solana_stake_program.so new file mode 100755 index 00000000..2dd18bbd Binary files /dev/null and b/program/tests/fixtures/solana_stake_program.so differ diff --git a/program/tests/helpers/mod.rs b/program/tests/helpers/mod.rs index 5e189d10..4e68f5a4 100644 --- a/program/tests/helpers/mod.rs +++ b/program/tests/helpers/mod.rs @@ -1,6 +1,7 @@ #![allow(dead_code)] use { + agave_feature_set::stake_raise_minimum_delegation_to_1_sol, borsh::BorshDeserialize, solana_program::{ borsh1::{get_instance_packed_len, get_packed_len, try_from_slice_unchecked}, @@ -12,10 +13,11 @@ use { }, solana_program_test::{processor, BanksClient, ProgramTest, ProgramTestContext}, solana_sdk::{ - account::{Account as SolanaAccount, WritableAccount}, + account::{Account as SolanaAccount, AccountSharedData, ReadableAccount, WritableAccount}, clock::{Clock, Epoch}, compute_budget::ComputeBudgetInstruction, signature::{Keypair, Signer}, + sysvar::{stake_history::StakeHistory, SysvarId}, transaction::Transaction, transport::TransportError, }, @@ -53,6 +55,8 @@ const ACCOUNT_RENT_EXEMPTION: u64 = 1_000_000_000; // go with something big to b pub fn program_test() -> ProgramTest { let mut program_test = ProgramTest::new("spl_stake_pool", id(), processor!(Processor::process)); + program_test.add_upgradeable_program_to_genesis("solana_stake_program", &stake::program::id()); + program_test.deactivate_feature(stake_raise_minimum_delegation_to_1_sol::id()); program_test.prefer_bpf(false); program_test.add_program( "spl_token_2022", @@ -64,6 +68,8 @@ pub fn program_test() -> ProgramTest { pub fn program_test_with_metadata_program() -> ProgramTest { let mut program_test = ProgramTest::default(); + program_test.add_upgradeable_program_to_genesis("solana_stake_program", &stake::program::id()); + program_test.deactivate_feature(stake_raise_minimum_delegation_to_1_sol::id()); program_test.add_program("spl_stake_pool", id(), processor!(Processor::process)); program_test.add_program("mpl_token_metadata", inline_mpl_token_metadata::id(), None); program_test.prefer_bpf(false); @@ -83,6 +89,41 @@ pub async fn get_account(banks_client: &mut BanksClient, pubkey: &Pubkey) -> Sol .expect("account not found") } +pub async fn fix_stake_history(context: &mut ProgramTestContext) { + let clock = bincode::deserialize::( + get_account(&mut context.banks_client, &Clock::id()) + .await + .data(), + ) + .unwrap(); + + let stake_history_account = get_account(&mut context.banks_client, &StakeHistory::id()).await; + + let mut stake_history = + bincode::deserialize::(stake_history_account.data()).unwrap(); + + let mut stake_history_entry = stake_history.get(0).cloned().unwrap_or_default(); + stake_history_entry.effective += + stake_history_entry.activating - stake_history_entry.deactivating; + stake_history_entry.activating = 0; + stake_history_entry.deactivating = 0; + + for epoch in 1..clock.epoch { + stake_history.add(epoch, stake_history_entry.clone()); + } + + let stake_history_account = AccountSharedData::create( + stake_history_account.lamports(), + bincode::serialize(&stake_history).unwrap(), + *stake_history_account.owner(), + false, + u64::MAX, + ); + + context.set_account(&StakeHistory::id(), &stake_history_account); + context.warp_to_slot(clock.slot + 1).unwrap(); +} + #[allow(clippy::too_many_arguments)] pub async fn create_mint( banks_client: &mut BanksClient, diff --git a/program/tests/huge_pool.rs b/program/tests/huge_pool.rs index 7fcd4313..2921ad69 100644 --- a/program/tests/huge_pool.rs +++ b/program/tests/huge_pool.rs @@ -449,6 +449,13 @@ async fn add_validator_to_pool(max_validators: u32) { let (mut context, stake_pool_accounts, _, test_vote_address, _, _, _) = setup(max_validators, max_validators - 1, STAKE_AMOUNT).await; + let minimum_delegation = stake_pool_get_minimum_delegation( + &mut context.banks_client, + &context.payer, + &context.last_blockhash, + ) + .await; + let last_index = max_validators as usize - 1; let stake_pool_pubkey = stake_pool_accounts.stake_pool.pubkey(); let (stake_address, _) = @@ -478,7 +485,7 @@ async fn add_validator_to_pool(max_validators: u32) { assert_eq!(last_element.status, StakeStatus::Active.into()); assert_eq!( u64::from(last_element.active_stake_lamports), - LAMPORTS_PER_SOL + STAKE_ACCOUNT_RENT_EXEMPTION + minimum_delegation + STAKE_ACCOUNT_RENT_EXEMPTION ); assert_eq!(u64::from(last_element.transient_stake_lamports), 0); assert_eq!(last_element.vote_account_address, test_vote_address); @@ -516,7 +523,7 @@ async fn add_validator_to_pool(max_validators: u32) { assert_eq!(last_element.status, StakeStatus::Active.into()); assert_eq!( u64::from(last_element.active_stake_lamports), - LAMPORTS_PER_SOL + STAKE_ACCOUNT_RENT_EXEMPTION + minimum_delegation + STAKE_ACCOUNT_RENT_EXEMPTION ); assert_eq!( u64::from(last_element.transient_stake_lamports), diff --git a/program/tests/update_validator_list_balance_hijack.rs b/program/tests/update_validator_list_balance_hijack.rs deleted file mode 100644 index b8f0905f..00000000 --- a/program/tests/update_validator_list_balance_hijack.rs +++ /dev/null @@ -1,548 +0,0 @@ -#![allow(clippy::arithmetic_side_effects)] -use spl_stake_pool::instruction; - -mod helpers; - -use { - helpers::*, - solana_program::{borsh1::try_from_slice_unchecked, pubkey::Pubkey}, - solana_program_test::*, - solana_sdk::{ - hash::Hash, - instruction::InstructionError, - signature::Signer, - transaction::{Transaction, TransactionError}, - }, - solana_stake_interface::{ - instruction as stake_instruction, - state::{Authorized, Lockup, StakeStateV2}, - }, - solana_system_interface::instruction as system_instruction, - spl_stake_pool::{ - error::StakePoolError, find_stake_program_address, find_transient_stake_program_address, - find_withdraw_authority_program_address, id, state::StakePool, MINIMUM_RESERVE_LAMPORTS, - }, - std::num::NonZeroU32, -}; - -async fn setup( - num_validators: usize, -) -> ( - ProgramTestContext, - Hash, - StakePoolAccounts, - Vec, - Vec, - u64, - u64, - u64, -) { - let mut context = program_test().start_with_context().await; - let first_normal_slot = context.genesis_config().epoch_schedule.first_normal_slot; - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - let mut slot = first_normal_slot + 1; - context.warp_to_slot(slot).unwrap(); - - let reserve_stake_amount = TEST_STAKE_AMOUNT * 2 * num_validators as u64; - let stake_pool_accounts = StakePoolAccounts::default(); - stake_pool_accounts - .initialize_stake_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - reserve_stake_amount + MINIMUM_RESERVE_LAMPORTS, - ) - .await - .unwrap(); - - // Add several accounts with some stake - let mut stake_accounts: Vec = vec![]; - let mut deposit_accounts: Vec = vec![]; - for i in 0..num_validators { - let stake_account = ValidatorStakeAccount::new( - &stake_pool_accounts.stake_pool.pubkey(), - NonZeroU32::new(i as u32), - u64::MAX, - ); - create_vote( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_account.validator, - &stake_account.vote, - ) - .await; - - let error = stake_pool_accounts - .add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_account.stake_account, - &stake_account.vote.pubkey(), - stake_account.validator_stake_seed, - ) - .await; - assert!(error.is_none(), "{:?}", error); - - let deposit_account = DepositStakeAccount::new_with_vote( - stake_account.vote.pubkey(), - stake_account.stake_account, - TEST_STAKE_AMOUNT, - ); - deposit_account - .create_and_delegate( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - ) - .await; - - stake_accounts.push(stake_account); - deposit_accounts.push(deposit_account); - } - - // Warp forward so the stakes properly activate, and deposit - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - false, - ) - .await; - - for deposit_account in &mut deposit_accounts { - deposit_account - .deposit_stake( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &stake_pool_accounts, - ) - .await; - } - - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - let last_blockhash = context - .banks_client - .get_new_latest_blockhash(&context.last_blockhash) - .await - .unwrap(); - - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &last_blockhash, - false, - ) - .await; - - let last_blockhash = context - .banks_client - .get_new_latest_blockhash(&last_blockhash) - .await - .unwrap(); - - ( - context, - last_blockhash, - stake_pool_accounts, - stake_accounts, - deposit_accounts, - TEST_STAKE_AMOUNT, - reserve_stake_amount, - slot, - ) -} - -#[tokio::test] -async fn success_ignoring_hijacked_transient_stake_with_authorized() { - let hijacker = Pubkey::new_unique(); - check_ignored_hijacked_transient_stake(Some(&Authorized::auto(&hijacker)), None).await; -} - -#[tokio::test] -async fn success_ignoring_hijacked_transient_stake_with_lockup() { - let hijacker = Pubkey::new_unique(); - check_ignored_hijacked_transient_stake( - None, - Some(&Lockup { - custodian: hijacker, - ..Lockup::default() - }), - ) - .await; -} - -async fn check_ignored_hijacked_transient_stake( - hijack_authorized: Option<&Authorized>, - hijack_lockup: Option<&Lockup>, -) { - let num_validators = 1; - let ( - mut context, - last_blockhash, - stake_pool_accounts, - stake_accounts, - _, - lamports, - _, - mut slot, - ) = setup(num_validators).await; - - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - - let pre_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let (withdraw_authority, _) = - find_withdraw_authority_program_address(&id(), &stake_pool_accounts.stake_pool.pubkey()); - - println!("Decrease from all validators"); - let stake_account = &stake_accounts[0]; - let error = stake_pool_accounts - .decrease_validator_stake_either( - &mut context.banks_client, - &context.payer, - &last_blockhash, - &stake_account.stake_account, - &stake_account.transient_stake_account, - lamports, - stake_account.transient_stake_seed, - DecreaseInstruction::Reserve, - ) - .await; - assert!(error.is_none(), "{:?}", error); - - println!("Warp one epoch so the stakes deactivate and merge"); - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - println!("During update, hijack the transient stake account"); - let validator_list = stake_pool_accounts - .get_validator_list(&mut context.banks_client) - .await; - let transient_stake_address = find_transient_stake_program_address( - &id(), - &stake_account.vote.pubkey(), - &stake_pool_accounts.stake_pool.pubkey(), - stake_account.transient_stake_seed, - ) - .0; - let transaction = Transaction::new_signed_with_payer( - &[ - instruction::update_validator_list_balance_chunk( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &validator_list, - 1, - 0, - /* no_merge = */ false, - ) - .unwrap(), - system_instruction::transfer( - &context.payer.pubkey(), - &transient_stake_address, - stake_rent + MINIMUM_RESERVE_LAMPORTS, - ), - stake_instruction::initialize( - &transient_stake_address, - hijack_authorized.unwrap_or(&Authorized::auto(&withdraw_authority)), - hijack_lockup.unwrap_or(&Lockup::default()), - ), - instruction::update_stake_pool_balance( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &spl_token::id(), - ), - instruction::cleanup_removed_validator_entries( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ), - ], - Some(&context.payer.pubkey()), - &[&context.payer], - last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err(); - assert!(error.is_none(), "{:?}", error); - - println!("Update again normally, should be no change in the lamports"); - let last_blockhash = context - .banks_client - .get_new_latest_blockhash(&last_blockhash) - .await - .unwrap(); - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &last_blockhash, - false, - ) - .await; - - let expected_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - assert_eq!(pre_lamports, expected_lamports); - - let stake_pool_info = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data).unwrap(); - assert_eq!(pre_lamports, stake_pool.total_lamports); -} - -#[tokio::test] -async fn success_ignoring_hijacked_validator_stake_with_authorized() { - let hijacker = Pubkey::new_unique(); - check_ignored_hijacked_transient_stake(Some(&Authorized::auto(&hijacker)), None).await; -} - -#[tokio::test] -async fn success_ignoring_hijacked_validator_stake_with_lockup() { - let hijacker = Pubkey::new_unique(); - check_ignored_hijacked_validator_stake( - None, - Some(&Lockup { - custodian: hijacker, - ..Lockup::default() - }), - ) - .await; -} - -async fn check_ignored_hijacked_validator_stake( - hijack_authorized: Option<&Authorized>, - hijack_lockup: Option<&Lockup>, -) { - let num_validators = 1; - let ( - mut context, - last_blockhash, - stake_pool_accounts, - stake_accounts, - _, - lamports, - _, - mut slot, - ) = setup(num_validators).await; - - let rent = context.banks_client.get_rent().await.unwrap(); - let stake_rent = rent.minimum_balance(std::mem::size_of::()); - - let pre_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let (withdraw_authority, _) = - find_withdraw_authority_program_address(&id(), &stake_pool_accounts.stake_pool.pubkey()); - - let stake_account = &stake_accounts[0]; - let error = stake_pool_accounts - .decrease_validator_stake_either( - &mut context.banks_client, - &context.payer, - &last_blockhash, - &stake_account.stake_account, - &stake_account.transient_stake_account, - lamports, - stake_account.transient_stake_seed, - DecreaseInstruction::Reserve, - ) - .await; - assert!(error.is_none(), "{:?}", error); - - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &last_blockhash, - &stake_account.stake_account, - &stake_account.transient_stake_account, - ) - .await; - assert!(error.is_none(), "{:?}", error); - - println!("Warp one epoch so the stakes deactivate and merge"); - let slots_per_epoch = context.genesis_config().epoch_schedule.slots_per_epoch; - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - println!("During update, hijack the validator stake account"); - let validator_list = stake_pool_accounts - .get_validator_list(&mut context.banks_client) - .await; - let transaction = Transaction::new_signed_with_payer( - &[ - instruction::update_validator_list_balance_chunk( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &validator_list, - 1, - 0, - /* no_merge = */ false, - ) - .unwrap(), - system_instruction::transfer( - &context.payer.pubkey(), - &stake_account.stake_account, - stake_rent + MINIMUM_RESERVE_LAMPORTS, - ), - stake_instruction::initialize( - &stake_account.stake_account, - hijack_authorized.unwrap_or(&Authorized::auto(&withdraw_authority)), - hijack_lockup.unwrap_or(&Lockup::default()), - ), - instruction::update_stake_pool_balance( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &spl_token::id(), - ), - instruction::cleanup_removed_validator_entries( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ), - ], - Some(&context.payer.pubkey()), - &[&context.payer], - last_blockhash, - ); - let error = context - .banks_client - .process_transaction(transaction) - .await - .err(); - assert!(error.is_none(), "{:?}", error); - - println!("Update again normally, should be no change in the lamports"); - let last_blockhash = context - .banks_client - .get_new_latest_blockhash(&last_blockhash) - .await - .unwrap(); - stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &last_blockhash, - false, - ) - .await; - - let expected_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - assert_eq!(pre_lamports, expected_lamports); - - let stake_pool_info = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data).unwrap(); - assert_eq!(pre_lamports, stake_pool.total_lamports); - - println!("Fail adding validator back in with first seed"); - let error = stake_pool_accounts - .add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &last_blockhash, - &stake_account.stake_account, - &stake_account.vote.pubkey(), - stake_account.validator_stake_seed, - ) - .await - .unwrap() - .unwrap(); - assert_eq!( - error, - TransactionError::InstructionError( - 0, - InstructionError::Custom(StakePoolError::AlreadyInUse as u32), - ) - ); - - println!("Succeed adding validator back in with new seed"); - let seed = NonZeroU32::new(1); - let validator = stake_account.vote.pubkey(); - let (stake_account, _) = find_stake_program_address( - &id(), - &validator, - &stake_pool_accounts.stake_pool.pubkey(), - seed, - ); - let error = stake_pool_accounts - .add_validator_to_pool( - &mut context.banks_client, - &context.payer, - &last_blockhash, - &stake_account, - &validator, - seed, - ) - .await; - assert!(error.is_none(), "{:?}", error); - - let stake_pool_info = get_account( - &mut context.banks_client, - &stake_pool_accounts.stake_pool.pubkey(), - ) - .await; - let stake_pool = try_from_slice_unchecked::(&stake_pool_info.data).unwrap(); - assert_eq!(pre_lamports, stake_pool.total_lamports); - - let expected_lamports = get_validator_list_sum( - &mut context.banks_client, - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - assert_eq!(pre_lamports, expected_lamports); -} diff --git a/program/tests/vsa_remove.rs b/program/tests/vsa_remove.rs index bed5ae30..fdeac3ef 100644 --- a/program/tests/vsa_remove.rs +++ b/program/tests/vsa_remove.rs @@ -659,7 +659,7 @@ async fn success_resets_preferred_validator() { } #[tokio::test] -async fn success_with_hijacked_transient_account() { +async fn fail_cannot_hijack_transient_account() { let (mut context, stake_pool_accounts, validator_stake) = setup().await; let rent = context.banks_client.get_rent().await.unwrap(); let stake_rent = rent.minimum_balance(std::mem::size_of::()); @@ -719,7 +719,7 @@ async fn success_with_hijacked_transient_account() { slot += slots_per_epoch; context.warp_to_slot(slot).unwrap(); - // hijack + // attempt to hijack. fails initialization let validator_list = stake_pool_accounts .get_validator_list(&mut context.banks_client) .await; @@ -758,21 +758,6 @@ async fn success_with_hijacked_transient_account() { }, &stake::state::Lockup::default(), ), - instruction::update_stake_pool_balance( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.withdraw_authority, - &stake_pool_accounts.validator_list.pubkey(), - &stake_pool_accounts.reserve_stake.pubkey(), - &stake_pool_accounts.pool_fee_account.pubkey(), - &stake_pool_accounts.pool_mint.pubkey(), - &spl_token::id(), - ), - instruction::cleanup_removed_validator_entries( - &id(), - &stake_pool_accounts.stake_pool.pubkey(), - &stake_pool_accounts.validator_list.pubkey(), - ), ], Some(&context.payer.pubkey()), &[&context.payer], @@ -782,63 +767,12 @@ async fn success_with_hijacked_transient_account() { .banks_client .process_transaction(transaction) .await - .err(); - assert!(error.is_none(), "{:?}", error); - - // activate transient stake account - delegate_stake_account( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &transient_stake_address, - &hijacker, - &validator_stake.vote.pubkey(), - ) - .await; - - // Remove works even though transient account is activating - let error = stake_pool_accounts - .remove_validator_from_pool( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - &validator_stake.stake_account, - &validator_stake.transient_stake_account, - ) - .await; - assert!(error.is_none(), "{:?}", error); - - // warp forward to merge - slot += slots_per_epoch; - context.warp_to_slot(slot).unwrap(); - - let error = stake_pool_accounts - .update_all( - &mut context.banks_client, - &context.payer, - &context.last_blockhash, - false, - ) - .await; - assert!(error.is_none(), "{:?}", error); + .unwrap_err() + .unwrap(); - // Check if account was removed from the list of stake accounts - let validator_list = get_account( - &mut context.banks_client, - &stake_pool_accounts.validator_list.pubkey(), - ) - .await; - let validator_list = - try_from_slice_unchecked::(validator_list.data.as_slice()).unwrap(); assert_eq!( - validator_list, - state::ValidatorList { - header: state::ValidatorListHeader { - account_type: state::AccountType::ValidatorList, - max_validators: stake_pool_accounts.max_validators, - }, - validators: vec![] - } + error, + TransactionError::InstructionError(2, InstructionError::InvalidAccountData) ); }