diff --git a/account-decoder/src/parse_account_data.rs b/account-decoder/src/parse_account_data.rs index 641b4f6db2..a8ce3e5f0e 100644 --- a/account-decoder/src/parse_account_data.rs +++ b/account-decoder/src/parse_account_data.rs @@ -118,7 +118,7 @@ mod test { let vote_state = VoteState::default(); let mut vote_account_data: Vec = vec![0; VoteState::size_of()]; - let versioned = VoteStateVersions::Current(Box::new(vote_state)); + let versioned = VoteStateVersions::new_current(vote_state); VoteState::serialize(&versioned, &mut vote_account_data).unwrap(); let parsed = parse_account_data( &account_pubkey, diff --git a/account-decoder/src/parse_vote.rs b/account-decoder/src/parse_vote.rs index 2ff9d4dd13..78ea3e066d 100644 --- a/account-decoder/src/parse_vote.rs +++ b/account-decoder/src/parse_vote.rs @@ -128,7 +128,7 @@ mod test { fn test_parse_vote() { let vote_state = VoteState::default(); let mut vote_account_data: Vec = vec![0; VoteState::size_of()]; - let versioned = VoteStateVersions::Current(Box::new(vote_state)); + let versioned = VoteStateVersions::new_current(vote_state); VoteState::serialize(&versioned, &mut vote_account_data).unwrap(); let mut expected_vote_state = UiVoteState::default(); expected_vote_state.node_pubkey = Pubkey::default().to_string(); diff --git a/core/src/commitment_service.rs b/core/src/commitment_service.rs index 333602b821..98f9f7315e 100644 --- a/core/src/commitment_service.rs +++ b/core/src/commitment_service.rs @@ -433,26 +433,26 @@ mod tests { let mut vote_state1 = VoteState::from(&vote_account1).unwrap(); vote_state1.process_slot_vote_unchecked(3); vote_state1.process_slot_vote_unchecked(5); - let versioned = VoteStateVersions::Current(Box::new(vote_state1)); + let versioned = VoteStateVersions::new_current(vote_state1); VoteState::to(&versioned, &mut vote_account1).unwrap(); bank.store_account(&pk1, &vote_account1); let mut vote_state2 = VoteState::from(&vote_account2).unwrap(); vote_state2.process_slot_vote_unchecked(9); vote_state2.process_slot_vote_unchecked(10); - let versioned = VoteStateVersions::Current(Box::new(vote_state2)); + let versioned = VoteStateVersions::new_current(vote_state2); VoteState::to(&versioned, &mut vote_account2).unwrap(); bank.store_account(&pk2, &vote_account2); let mut vote_state3 = VoteState::from(&vote_account3).unwrap(); vote_state3.root_slot = Some(1); - let versioned = VoteStateVersions::Current(Box::new(vote_state3)); + let versioned = VoteStateVersions::new_current(vote_state3); VoteState::to(&versioned, &mut vote_account3).unwrap(); bank.store_account(&pk3, &vote_account3); let mut vote_state4 = VoteState::from(&vote_account4).unwrap(); vote_state4.root_slot = Some(2); - let versioned = VoteStateVersions::Current(Box::new(vote_state4)); + let versioned = VoteStateVersions::new_current(vote_state4); VoteState::to(&versioned, &mut vote_account4).unwrap(); bank.store_account(&pk4, &vote_account4); diff --git a/core/src/consensus.rs b/core/src/consensus.rs index 7b12a45ada..0cee4cf2c0 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -1581,7 +1581,7 @@ pub mod test { vote_state.process_slot_vote_unchecked(*slot); } VoteState::serialize( - &VoteStateVersions::Current(Box::new(vote_state)), + &VoteStateVersions::new_current(vote_state), &mut account.data, ) .expect("serialize state"); diff --git a/core/src/replay_stage.rs b/core/src/replay_stage.rs index 962e39df86..197d8fbed2 100644 --- a/core/src/replay_stage.rs +++ b/core/src/replay_stage.rs @@ -2546,7 +2546,7 @@ pub(crate) mod tests { let mut leader_vote_account = bank.get_account(&pubkey).unwrap(); let mut vote_state = VoteState::from(&leader_vote_account).unwrap(); vote_state.process_slot_vote_unchecked(vote_slot); - let versioned = VoteStateVersions::Current(Box::new(vote_state)); + let versioned = VoteStateVersions::new_current(vote_state); VoteState::to(&versioned, &mut leader_vote_account).unwrap(); bank.store_account(&pubkey, &leader_vote_account); } diff --git a/ledger/src/blockstore_processor.rs b/ledger/src/blockstore_processor.rs index 18d602d094..eed3b99023 100644 --- a/ledger/src/blockstore_processor.rs +++ b/ledger/src/blockstore_processor.rs @@ -3155,7 +3155,7 @@ pub mod tests { vote_state.root_slot = Some(root); let mut vote_account = Account::new(1, VoteState::size_of(), &solana_vote_program::id()); - let versioned = VoteStateVersions::Current(Box::new(vote_state)); + let versioned = VoteStateVersions::new_current(vote_state); VoteState::serialize(&versioned, &mut vote_account.data).unwrap(); ( solana_sdk::pubkey::new_rand(), diff --git a/ledger/src/staking_utils.rs b/ledger/src/staking_utils.rs index 7436d55c51..f63851c338 100644 --- a/ledger/src/staking_utils.rs +++ b/ledger/src/staking_utils.rs @@ -340,7 +340,7 @@ pub(crate) mod tests { let vote_accounts = stakes.into_iter().map(|(stake, vote_state)| { let account = Account::new_data( rng.gen(), // lamports - &VoteStateVersions::Current(Box::new(vote_state)), + &VoteStateVersions::new_current(vote_state), &Pubkey::new_unique(), // owner ) .unwrap(); diff --git a/programs/stake/src/legacy_stake_state.rs b/programs/stake/src/legacy_stake_state.rs index 6eb4d628af..c8fe272396 100644 --- a/programs/stake/src/legacy_stake_state.rs +++ b/programs/stake/src/legacy_stake_state.rs @@ -1004,7 +1004,7 @@ mod tests { let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account); let vote_state_credits = vote_state.credits(); vote_keyed_account - .set_state(&VoteStateVersions::Current(Box::new(vote_state))) + .set_state(&VoteStateVersions::new_current(vote_state)) .unwrap(); let stake_pubkey = solana_sdk::pubkey::new_rand(); @@ -1902,7 +1902,7 @@ mod tests { )); let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account); vote_keyed_account - .set_state(&VoteStateVersions::Current(Box::new(VoteState::default()))) + .set_state(&VoteStateVersions::new_current(VoteState::default())) .unwrap(); assert_eq!( stake_keyed_account.delegate( @@ -1993,7 +1993,7 @@ mod tests { )); let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account); vote_keyed_account - .set_state(&VoteStateVersions::Current(Box::new(VoteState::default()))) + .set_state(&VoteStateVersions::new_current(VoteState::default())) .unwrap(); stake_keyed_account @@ -2235,7 +2235,7 @@ mod tests { )); let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account); vote_keyed_account - .set_state(&VoteStateVersions::Current(Box::new(VoteState::default()))) + .set_state(&VoteStateVersions::new_current(VoteState::default())) .unwrap(); let signers = vec![stake_pubkey].into_iter().collect(); assert_eq!( @@ -2351,7 +2351,7 @@ mod tests { )); let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account); vote_keyed_account - .set_state(&VoteStateVersions::Current(Box::new(VoteState::default()))) + .set_state(&VoteStateVersions::new_current(VoteState::default())) .unwrap(); let signers = vec![stake_pubkey].into_iter().collect(); assert_eq!( diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index 64f52cb4d3..9a0f15e8f3 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -99,9 +99,17 @@ impl StakeState { } pub fn lockup(&self) -> Option { + self.meta().map(|meta| meta.lockup) + } + + pub fn meta_from(account: &Account) -> Option { + Self::from(account).and_then(|state: Self| state.meta()) + } + + pub fn meta(&self) -> Option { match self { - StakeState::Stake(meta, _stake) => Some(meta.lockup), - StakeState::Initialized(meta) => Some(meta.lockup), + StakeState::Stake(meta, _stake) => Some(*meta), + StakeState::Initialized(meta) => Some(*meta), _ => None, } } @@ -1054,6 +1062,11 @@ impl<'a> StakeAccount for KeyedAccount<'a> { _ => return Err(InstructionError::InvalidAccountData), } + // Deinitialize state upon zero balance + if lamports == self.lamports()? { + self.set_state(&StakeState::Uninitialized)?; + } + split.try_account_ref_mut()?.lamports += lamports; self.try_account_ref_mut()?.lamports -= lamports; Ok(()) @@ -1090,6 +1103,9 @@ impl<'a> StakeAccount for KeyedAccount<'a> { self.set_state(&merged_state)?; } + // Source is about to be drained, deinitialize its state + source_account.set_state(&StakeState::Uninitialized)?; + // Drain the source stake account let lamports = source_account.lamports()?; source_account.try_account_ref_mut()?.lamports -= lamports; @@ -1166,6 +1182,11 @@ impl<'a> StakeAccount for KeyedAccount<'a> { return Err(InstructionError::InsufficientFunds); } + // Deinitialize state upon zero balance + if lamports == self.lamports()? { + self.set_state(&StakeState::Uninitialized)?; + } + self.try_account_ref_mut()?.lamports -= lamports; to.try_account_ref_mut()?.lamports += lamports; Ok(()) @@ -1641,7 +1662,7 @@ mod tests { let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account); let vote_state_credits = vote_state.credits(); vote_keyed_account - .set_state(&VoteStateVersions::Current(Box::new(vote_state))) + .set_state(&VoteStateVersions::new_current(vote_state)) .unwrap(); let stake_pubkey = solana_sdk::pubkey::new_rand(); @@ -2539,7 +2560,7 @@ mod tests { )); let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account); vote_keyed_account - .set_state(&VoteStateVersions::Current(Box::new(VoteState::default()))) + .set_state(&VoteStateVersions::new_current(VoteState::default())) .unwrap(); assert_eq!( stake_keyed_account.delegate( @@ -2630,7 +2651,7 @@ mod tests { )); let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account); vote_keyed_account - .set_state(&VoteStateVersions::Current(Box::new(VoteState::default()))) + .set_state(&VoteStateVersions::new_current(VoteState::default())) .unwrap(); stake_keyed_account @@ -2828,6 +2849,7 @@ mod tests { Ok(()) ); assert_eq!(stake_account.borrow().lamports, 0); + assert_eq!(stake_keyed_account.state(), Ok(StakeState::Uninitialized)); // reset balance stake_account.borrow_mut().lamports = stake_lamports; @@ -2872,7 +2894,7 @@ mod tests { )); let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account); vote_keyed_account - .set_state(&VoteStateVersions::Current(Box::new(VoteState::default()))) + .set_state(&VoteStateVersions::new_current(VoteState::default())) .unwrap(); let signers = vec![stake_pubkey].into_iter().collect(); assert_eq!( @@ -2953,6 +2975,7 @@ mod tests { Ok(()) ); assert_eq!(stake_account.borrow().lamports, 0); + assert_eq!(stake_keyed_account.state(), Ok(StakeState::Uninitialized)); } #[test] @@ -2988,7 +3011,7 @@ mod tests { )); let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account); vote_keyed_account - .set_state(&VoteStateVersions::Current(Box::new(VoteState::default()))) + .set_state(&VoteStateVersions::new_current(VoteState::default())) .unwrap(); let signers = vec![stake_pubkey].into_iter().collect(); assert_eq!( @@ -3128,6 +3151,7 @@ mod tests { ), Ok(()) ); + assert_eq!(stake_keyed_account.state(), Ok(StakeState::Uninitialized)); } #[test] @@ -3184,6 +3208,7 @@ mod tests { ), Ok(()) ); + assert_eq!(stake_keyed_account.state(), Ok(StakeState::Uninitialized)); } } @@ -3600,6 +3625,7 @@ mod tests { ), Ok(()) ); + assert_eq!(stake_keyed_account.state(), Ok(StakeState::Uninitialized)); } #[test] @@ -4498,7 +4524,7 @@ mod tests { match state { StakeState::Initialized(_) => { assert_eq!(Ok(*state), split_stake_keyed_account.state()); - assert_eq!(Ok(*state), stake_keyed_account.state()); + assert_eq!(Ok(StakeState::Uninitialized), stake_keyed_account.state()); } StakeState::Stake(meta, stake) => { assert_eq!( @@ -4514,19 +4540,7 @@ mod tests { )), split_stake_keyed_account.state() ); - assert_eq!( - Ok(StakeState::Stake( - *meta, - Stake { - delegation: Delegation { - stake: 0, - ..stake.delegation - }, - ..*stake - } - )), - stake_keyed_account.state() - ); + assert_eq!(Ok(StakeState::Uninitialized), stake_keyed_account.state()); } _ => unreachable!(), } @@ -4608,19 +4622,7 @@ mod tests { )), split_stake_keyed_account.state() ); - assert_eq!( - Ok(StakeState::Stake( - meta, - Stake { - delegation: Delegation { - stake: 0, - ..stake.delegation - }, - ..stake - } - )), - stake_keyed_account.state() - ); + assert_eq!(Ok(StakeState::Uninitialized), stake_keyed_account.state()); } } } @@ -4722,9 +4724,9 @@ mod tests { Ok(StakeState::Initialized(expected_split_meta)), split_stake_keyed_account.state() ); - assert_eq!(Ok(*state), stake_keyed_account.state()); + assert_eq!(Ok(StakeState::Uninitialized), stake_keyed_account.state()); } - StakeState::Stake(meta, stake) => { + StakeState::Stake(_meta, stake) => { // Expected stake should reflect original stake amount so that extra lamports // from the rent_exempt_reserve inequality do not magically activate let expected_stake = stake_lamports - rent_exempt_reserve; @@ -4748,19 +4750,7 @@ mod tests { + expected_rent_exempt_reserve + (rent_exempt_reserve - expected_rent_exempt_reserve) ); - assert_eq!( - Ok(StakeState::Stake( - *meta, - Stake { - delegation: Delegation { - stake: 0, - ..stake.delegation - }, - ..*stake - } - )), - stake_keyed_account.state() - ); + assert_eq!(Ok(StakeState::Uninitialized), stake_keyed_account.state()); } _ => unreachable!(), } @@ -4836,6 +4826,44 @@ mod tests { stake_lamports * 2 ); assert_eq!(source_stake_keyed_account.account.borrow().lamports, 0); + + // check state + match state { + StakeState::Initialized(meta) => { + assert_eq!( + stake_keyed_account.state(), + Ok(StakeState::Initialized(*meta)), + ); + } + StakeState::Stake(meta, stake) => { + let expected_stake = stake.delegation.stake + + source_state + .stake() + .map(|stake| stake.delegation.stake) + .unwrap_or_else(|| { + stake_lamports + - source_state.meta().unwrap().rent_exempt_reserve + }); + assert_eq!( + stake_keyed_account.state(), + Ok(StakeState::Stake( + *meta, + Stake { + delegation: Delegation { + stake: expected_stake, + ..stake.delegation + }, + ..*stake + } + )), + ); + } + _ => unreachable!(), + } + assert_eq!( + source_stake_keyed_account.state(), + Ok(StakeState::Uninitialized) + ); } } } @@ -5127,7 +5155,11 @@ mod tests { let test_source_keyed = KeyedAccount::new(source_account.unsigned_key(), true, &test_source_account); - test_stake_keyed.merge(&test_source_keyed, clock, stake_history, signers) + let result = test_stake_keyed.merge(&test_source_keyed, clock, stake_history, signers); + if result.is_ok() { + assert_eq!(test_source_keyed.state(), Ok(StakeState::Uninitialized),); + } + result } // stake activation epoch, source initialized succeeds diff --git a/programs/vote/src/vote_state/mod.rs b/programs/vote/src/vote_state/mod.rs index 897599e19e..a29f84a121 100644 --- a/programs/vote/src/vote_state/mod.rs +++ b/programs/vote/src/vote_state/mod.rs @@ -19,6 +19,7 @@ use solana_sdk::{ sysvar::clock::Clock, }; use std::boxed::Box; +use std::cmp::Ordering; use std::collections::{HashSet, VecDeque}; mod vote_state_0_23_5; @@ -214,7 +215,7 @@ impl VoteState { pub fn size_of() -> usize { // Upper limit on the size of the Vote State. Equal to // size_of(VoteState) when votes.len() is MAX_LOCKOUT_HISTORY - let vote_state = VoteStateVersions::Current(Box::new(Self::get_max_sized_vote_state())); + let vote_state = VoteStateVersions::new_current(Self::get_max_sized_vote_state()); serialized_size(&vote_state).unwrap() as usize } @@ -594,7 +595,7 @@ pub fn authorize( } } - vote_account.set_state(&VoteStateVersions::Current(Box::new(vote_state))) + vote_account.set_state(&VoteStateVersions::new_current(vote_state)) } /// Update the node_pubkey, requires signature of the authorized voter @@ -614,7 +615,7 @@ pub fn update_validator_identity( vote_state.node_pubkey = *node_pubkey; - vote_account.set_state(&VoteStateVersions::Current(Box::new(vote_state))) + vote_account.set_state(&VoteStateVersions::new_current(vote_state)) } /// Update the vote account's commission @@ -631,7 +632,7 @@ pub fn update_commission( vote_state.commission = commission; - vote_account.set_state(&VoteStateVersions::Current(Box::new(vote_state))) + vote_account.set_state(&VoteStateVersions::new_current(vote_state)) } fn verify_authorized_signer( @@ -657,8 +658,13 @@ pub fn withdraw( verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?; - if vote_account.lamports()? < lamports { - return Err(InstructionError::InsufficientFunds); + match vote_account.lamports()?.cmp(&lamports) { + Ordering::Less => return Err(InstructionError::InsufficientFunds), + Ordering::Equal => { + // Deinitialize upon zero-balance + vote_account.set_state(&VoteStateVersions::new_current(VoteState::default()))?; + } + _ => (), } vote_account.try_account_ref_mut()?.lamports -= lamports; to_account.try_account_ref_mut()?.lamports += lamports; @@ -683,9 +689,9 @@ pub fn initialize_account( // node must agree to accept this vote account verify_authorized_signer(&vote_init.node_pubkey, signers)?; - vote_account.set_state(&VoteStateVersions::Current(Box::new(VoteState::new( + vote_account.set_state(&VoteStateVersions::new_current(VoteState::new( vote_init, clock, - )))) + ))) } pub fn process_vote( @@ -715,7 +721,7 @@ pub fn process_vote( .ok_or_else(|| VoteError::EmptySlots) .and_then(|slot| vote_state.process_timestamp(*slot, timestamp))?; } - vote_account.set_state(&VoteStateVersions::Current(Box::new(vote_state))) + vote_account.set_state(&VoteStateVersions::new_current(vote_state)) } pub fn create_account_with_authorized( @@ -737,7 +743,7 @@ pub fn create_account_with_authorized( &Clock::default(), ); - let versioned = VoteStateVersions::Current(Box::new(vote_state)); + let versioned = VoteStateVersions::new_current(vote_state); VoteState::to(&versioned, &mut vote_account).unwrap(); vote_account @@ -915,11 +921,11 @@ mod tests { vote_state .votes .resize(MAX_LOCKOUT_HISTORY, Lockout::default()); - let versioned = VoteStateVersions::Current(Box::new(vote_state)); + let versioned = VoteStateVersions::new_current(vote_state); assert!(VoteState::serialize(&versioned, &mut buffer[0..4]).is_err()); VoteState::serialize(&versioned, &mut buffer).unwrap(); assert_eq!( - VoteStateVersions::Current(Box::new(VoteState::deserialize(&buffer).unwrap())), + VoteStateVersions::new_current(VoteState::deserialize(&buffer).unwrap()), versioned ); } @@ -1626,6 +1632,7 @@ mod tests { let lamports = vote_account.borrow().lamports; let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, true, &vote_account)]; let signers: HashSet = get_signers(keyed_accounts); + let pre_state: VoteStateVersions = vote_account.borrow().state().unwrap(); let res = withdraw( &keyed_accounts[0], lamports, @@ -1635,9 +1642,13 @@ mod tests { assert_eq!(res, Ok(())); assert_eq!(vote_account.borrow().lamports, 0); assert_eq!(to_account.borrow().lamports, lamports); + let post_state: VoteStateVersions = vote_account.borrow().state().unwrap(); + // State has been deinitialized since balance is zero + assert!(post_state.is_uninitialized()); - // reset balance, verify that authorized_withdrawer works + // reset balance and restore state, verify that authorized_withdrawer works vote_account.borrow_mut().lamports = lamports; + vote_account.borrow_mut().set_state(&pre_state).unwrap(); // authorize authorized_withdrawer let authorized_withdrawer_pubkey = solana_sdk::pubkey::new_rand(); @@ -1671,6 +1682,9 @@ mod tests { assert_eq!(res, Ok(())); assert_eq!(vote_account.borrow().lamports, 0); assert_eq!(withdrawer_account.borrow().lamports, lamports); + let post_state: VoteStateVersions = vote_account.borrow().state().unwrap(); + // State has been deinitialized since balance is zero + assert!(post_state.is_uninitialized()); } #[test] @@ -1994,9 +2008,17 @@ mod tests { ) }); - let versioned = VoteStateVersions::Current(Box::new(vote_state.take().unwrap())); + let versioned = VoteStateVersions::new_current(vote_state.take().unwrap()); VoteState::serialize(&versioned, &mut max_sized_data).unwrap(); vote_state = Some(versioned.convert_to_current()); } } + + #[test] + fn test_default_vote_state_is_uninitialized() { + // The default `VoteState` is stored to de-initialize a zero-balance vote account, + // so must remain such that `VoteStateVersions::is_uninitialized()` returns true + // when called on a `VoteStateVersions` that stores it + assert!(VoteStateVersions::new_current(VoteState::default()).is_uninitialized()); + } } diff --git a/programs/vote/src/vote_state/vote_state_versions.rs b/programs/vote/src/vote_state/vote_state_versions.rs index b80d83ee4a..f00cc65354 100644 --- a/programs/vote/src/vote_state/vote_state_versions.rs +++ b/programs/vote/src/vote_state/vote_state_versions.rs @@ -8,6 +8,10 @@ pub enum VoteStateVersions { } impl VoteStateVersions { + pub fn new_current(vote_state: VoteState) -> Self { + Self::Current(Box::new(vote_state)) + } + pub fn convert_to_current(self) -> VoteState { match self { VoteStateVersions::V0_23_5(state) => { diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index 51f9e96ed2..e7315c44d7 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -204,6 +204,8 @@ impl Accounts { })? { SystemAccountKind::System => 0, SystemAccountKind::Nonce => { + // Should we ever allow a fees charge to zero a nonce account's + // balance. The state MUST be set to uninitialized in that case rent_collector.rent.minimum_balance(nonce::State::size()) } }; diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 25c8777471..0b88046e07 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -10731,7 +10731,7 @@ pub(crate) mod tests { let mut vote_account = bank.get_account(vote_pubkey).unwrap_or_default(); let mut vote_state = VoteState::from(&vote_account).unwrap_or_default(); vote_state.last_timestamp = timestamp; - let versioned = VoteStateVersions::Current(Box::new(vote_state)); + let versioned = VoteStateVersions::new_current(vote_state); VoteState::to(&versioned, &mut vote_account).unwrap(); bank.store_account(vote_pubkey, &vote_account); } diff --git a/runtime/src/vote_account.rs b/runtime/src/vote_account.rs index d6eea0d948..6b86dd9451 100644 --- a/runtime/src/vote_account.rs +++ b/runtime/src/vote_account.rs @@ -116,7 +116,7 @@ mod tests { let vote_state = VoteState::new(&vote_init, &clock); let account = Account::new_data( rng.gen(), // lamports - &VoteStateVersions::Current(Box::new(vote_state.clone())), + &VoteStateVersions::new_current(vote_state.clone()), &Pubkey::new_unique(), // owner ) .unwrap(); diff --git a/sdk/src/nonce_keyed_account.rs b/sdk/src/nonce_keyed_account.rs index e44feaecd9..8a4f8b2840 100644 --- a/sdk/src/nonce_keyed_account.rs +++ b/sdk/src/nonce_keyed_account.rs @@ -90,6 +90,7 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> { if data.blockhash == recent_blockhashes[0].blockhash { return Err(NonceError::NotExpired.into()); } + self.set_state(&Versions::new_current(State::Uninitialized))?; } else { let min_balance = rent.minimum_balance(self.data_len()?); if lamports + min_balance > self.lamports()? { @@ -272,6 +273,11 @@ mod test { ); // Account balance goes to `to` assert_eq!(to_keyed.account.borrow().lamports, expect_to_lamports); + let state = AccountUtilsState::::state(keyed_account) + .unwrap() + .convert_to_current(); + // Empty balance deinitializes data + assert_eq!(state, State::Uninitialized); }) }) } @@ -628,6 +634,10 @@ mod test { &signers, ) .unwrap(); + let state = AccountUtilsState::::state(nonce_keyed) + .unwrap() + .convert_to_current(); + assert_eq!(state, State::Uninitialized); assert_eq!(nonce_keyed.account.borrow().lamports, nonce_expect_lamports); assert_eq!(to_keyed.account.borrow().lamports, to_expect_lamports); })