diff --git a/runtime/tests/stake.rs b/runtime/tests/stake.rs index cc4054e69..62d620c42 100644 --- a/runtime/tests/stake.rs +++ b/runtime/tests/stake.rs @@ -11,6 +11,7 @@ use { client::SyncClient, message::Message, pubkey::Pubkey, + rent::Rent, signature::{Keypair, Signer}, stake::{ self, instruction as stake_instruction, @@ -116,14 +117,20 @@ fn test_stake_create_and_split_single_signature() { let staker_pubkey = staker_keypair.pubkey(); - let bank_client = BankClient::new_shared(&Arc::new(Bank::new_for_tests(&genesis_config))); + let bank = Arc::new(Bank::new_for_tests(&genesis_config)); + let bank_client = BankClient::new_shared(&bank); let stake_address = Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::program::id()).unwrap(); let authorized = Authorized::auto(&staker_pubkey); - let lamports = 1_000_000; + let lamports = { + let rent = &bank.rent_collector().rent; + let rent_exempt_reserve = rent.minimum_balance(StakeState::size_of()); + let minimum_delegation = solana_stake_program::get_minimum_delegation(&bank.feature_set); + 2 * (rent_exempt_reserve + minimum_delegation) + }; // Create stake account with seed let message = Message::new( @@ -186,14 +193,20 @@ fn test_stake_create_and_split_to_existing_system_account() { let staker_pubkey = staker_keypair.pubkey(); - let bank_client = BankClient::new_shared(&Arc::new(Bank::new_for_tests(&genesis_config))); + let bank = Arc::new(Bank::new_for_tests(&genesis_config)); + let bank_client = BankClient::new_shared(&bank); let stake_address = Pubkey::create_with_seed(&staker_pubkey, "stake", &stake::program::id()).unwrap(); let authorized = Authorized::auto(&staker_pubkey); - let lamports = 1_000_000; + let lamports = { + let rent = &bank.rent_collector().rent; + let rent_exempt_reserve = rent.minimum_balance(StakeState::size_of()); + let minimum_delegation = solana_stake_program::get_minimum_delegation(&bank.feature_set); + 2 * (rent_exempt_reserve + minimum_delegation) + }; // Create stake account with seed let message = Message::new( @@ -257,19 +270,29 @@ fn test_stake_account_lifetime() { let identity_pubkey = identity_keypair.pubkey(); let GenesisConfigInfo { - genesis_config, + mut genesis_config, mint_keypair, .. } = create_genesis_config_with_leader( 100_000_000_000, &solana_sdk::pubkey::new_rand(), - 1_000_000, + 2_000_000_000, ); + genesis_config.rent = Rent::default(); let bank = Bank::new_for_tests(&genesis_config); let mint_pubkey = mint_keypair.pubkey(); let mut bank = Arc::new(bank); let bank_client = BankClient::new_shared(&bank); + let (vote_balance, stake_rent_exempt_reserve, stake_minimum_delegation) = { + let rent = &bank.rent_collector().rent; + ( + rent.minimum_balance(VoteState::size_of()), + rent.minimum_balance(StakeState::size_of()), + solana_stake_program::get_minimum_delegation(&bank.feature_set), + ) + }; + // Create Vote Account let message = Message::new( &vote_instruction::create_account( @@ -281,7 +304,7 @@ fn test_stake_account_lifetime() { authorized_withdrawer: vote_pubkey, commission: 50, }, - 10, + vote_balance, ), Some(&mint_pubkey), ); @@ -290,6 +313,11 @@ fn test_stake_account_lifetime() { .expect("failed to create vote account"); let authorized = Authorized::auto(&stake_pubkey); + let bonus_delegation = 1_000_000_000; + let stake_starting_delegation = + 2 * stake_minimum_delegation + bonus_delegation + stake_rent_exempt_reserve; + let stake_starting_balance = stake_starting_delegation + stake_rent_exempt_reserve; + // Create stake account and delegate to vote account let message = Message::new( &stake_instruction::create_account_and_delegate_stake( @@ -298,7 +326,7 @@ fn test_stake_account_lifetime() { &vote_pubkey, &authorized, &Lockup::default(), - 1_000_000, + stake_starting_balance, ), Some(&mint_pubkey), ); @@ -310,7 +338,7 @@ fn test_stake_account_lifetime() { let account = bank.get_account(&stake_pubkey).expect("account not found"); let stake_state = account.state().expect("couldn't unpack account data"); if let StakeState::Stake(_meta, stake) = stake_state { - assert_eq!(stake.delegation.stake, 1_000_000); + assert_eq!(stake.delegation.stake, stake_starting_delegation,); } else { panic!("wrong account type found") } @@ -334,7 +362,7 @@ fn test_stake_account_lifetime() { let account = bank.get_account(&stake_pubkey).expect("account not found"); let stake_state = account.state().expect("couldn't unpack account data"); if let StakeState::Stake(_meta, stake) = stake_state { - assert_eq!(stake.delegation.stake, 1_000_000); + assert_eq!(stake.delegation.stake, stake_starting_delegation,); } else { panic!("wrong account type found") } @@ -361,18 +389,20 @@ fn test_stake_account_lifetime() { assert_eq!(vote_state.votes.len(), 31); // one vote per slot, might be more slots than 32 in the epoch assert!(vote_state.credits() >= 1); + bank = fill_epoch_with_votes(&bank, &vote_keypair, &mint_keypair); let pre_staked = get_staked(&bank, &stake_pubkey); + let pre_balance = bank.get_balance(&stake_pubkey); // next epoch bank should pay rewards bank = next_epoch(&bank); // Test that balance increased, and that the balance got staked let staked = get_staked(&bank, &stake_pubkey); - let lamports = bank.get_balance(&stake_pubkey); + let balance = bank.get_balance(&stake_pubkey); assert!(staked > pre_staked); - assert!(lamports > 1_000_000); + assert!(balance > pre_balance); // split the stake let split_stake_keypair = Keypair::new(); @@ -380,11 +410,13 @@ fn test_stake_account_lifetime() { let bank_client = BankClient::new_shared(&bank); // Test split + let split_starting_delegation = stake_minimum_delegation + bonus_delegation; + let split_starting_balance = split_starting_delegation + stake_rent_exempt_reserve; let message = Message::new( &stake_instruction::split( &stake_pubkey, &stake_pubkey, - lamports / 2, + split_starting_balance, &split_stake_pubkey, ), Some(&mint_pubkey), @@ -395,6 +427,11 @@ fn test_stake_account_lifetime() { message ) .is_ok()); + assert_eq!( + get_staked(&bank, &split_stake_pubkey), + split_starting_delegation, + ); + let stake_remaining_balance = balance - split_starting_balance; // Deactivate the split let message = Message::new( @@ -407,8 +444,10 @@ fn test_stake_account_lifetime() { assert!(bank_client .send_and_confirm_message(&[&mint_keypair, &stake_keypair], message) .is_ok()); - - let split_staked = get_staked(&bank, &split_stake_pubkey); + assert_eq!( + get_staked(&bank, &split_stake_pubkey), + split_starting_delegation, + ); // Test that we cannot withdraw above what's staked let message = Message::new( @@ -416,7 +455,7 @@ fn test_stake_account_lifetime() { &split_stake_pubkey, &stake_pubkey, &solana_sdk::pubkey::new_rand(), - lamports / 2 - split_staked + 1, + split_starting_delegation + 1, None, )], Some(&mint_pubkey), @@ -433,33 +472,34 @@ fn test_stake_account_lifetime() { assert!(split_staked > 0); // withdrawal in cooldown + let split_balance = bank.get_balance(&split_stake_pubkey); let message = Message::new( &[stake_instruction::withdraw( &split_stake_pubkey, &stake_pubkey, &solana_sdk::pubkey::new_rand(), - lamports / 2, + split_balance, None, )], Some(&mint_pubkey), ); - assert!(bank_client .send_and_confirm_message(&[&mint_keypair, &stake_keypair], message) .is_err()); // but we can withdraw unstaked + let split_unstaked = split_balance - split_staked - stake_rent_exempt_reserve; + assert!(split_unstaked > 0); let message = Message::new( &[stake_instruction::withdraw( &split_stake_pubkey, &stake_pubkey, &solana_sdk::pubkey::new_rand(), - lamports / 2 - split_staked, + split_unstaked, None, )], Some(&mint_pubkey), ); - // assert we can withdraw unstaked tokens assert!(bank_client .send_and_confirm_message(&[&mint_keypair, &stake_keypair], message) .is_ok()); @@ -474,12 +514,13 @@ fn test_stake_account_lifetime() { let bank_client = BankClient::new_shared(&bank); // Test that we can withdraw everything else out of the split + let split_remaining_balance = split_balance - split_unstaked; let message = Message::new( &[stake_instruction::withdraw( &split_stake_pubkey, &stake_pubkey, &solana_sdk::pubkey::new_rand(), - split_staked, + split_remaining_balance, None, )], Some(&mint_pubkey), @@ -490,7 +531,7 @@ fn test_stake_account_lifetime() { // verify all the math sums to zero assert_eq!(bank.get_balance(&split_stake_pubkey), 0); - assert_eq!(bank.get_balance(&stake_pubkey), lamports - lamports / 2); + assert_eq!(bank.get_balance(&stake_pubkey), stake_remaining_balance); } #[test] @@ -537,6 +578,13 @@ fn test_create_stake_account_from_seed() { .expect("failed to create vote account"); let authorized = Authorized::auto(&mint_pubkey); + let (balance, delegation) = { + let rent = &bank.rent_collector().rent; + let rent_exempt_reserve = rent.minimum_balance(StakeState::size_of()); + let minimum_delegation = solana_stake_program::get_minimum_delegation(&bank.feature_set); + (rent_exempt_reserve + minimum_delegation, minimum_delegation) + }; + // Create stake account and delegate to vote account let message = Message::new( &stake_instruction::create_account_with_seed_and_delegate_stake( @@ -547,7 +595,7 @@ fn test_create_stake_account_from_seed() { &vote_pubkey, &authorized, &Lockup::default(), - 1_000_000, + balance, ), Some(&mint_pubkey), ); @@ -559,7 +607,7 @@ fn test_create_stake_account_from_seed() { let account = bank.get_account(&stake_pubkey).expect("account not found"); let stake_state = account.state().expect("couldn't unpack account data"); if let StakeState::Stake(_meta, stake) = stake_state { - assert_eq!(stake.delegation.stake, 1_000_000); + assert_eq!(stake.delegation.stake, delegation); } else { panic!("wrong account type found") }