* Deinitialize nonce data upon zero balance (cherry picked from commit3881ae10fb
) * vote: Add helper for creating current-versioned states (cherry picked from commit5b903318b2
) * Deinitialize vote data upon zero balance (cherry picked from commitdb5bd6ea1a
) * Deinitialize stake data upon zero balance (cherry picked from commit50710473a8
) Co-authored-by: Trent Nelson <trent@solana.com>
This commit is contained in:
@ -118,7 +118,7 @@ mod test {
|
|||||||
|
|
||||||
let vote_state = VoteState::default();
|
let vote_state = VoteState::default();
|
||||||
let mut vote_account_data: Vec<u8> = vec![0; VoteState::size_of()];
|
let mut vote_account_data: Vec<u8> = 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();
|
VoteState::serialize(&versioned, &mut vote_account_data).unwrap();
|
||||||
let parsed = parse_account_data(
|
let parsed = parse_account_data(
|
||||||
&account_pubkey,
|
&account_pubkey,
|
||||||
|
@ -128,7 +128,7 @@ mod test {
|
|||||||
fn test_parse_vote() {
|
fn test_parse_vote() {
|
||||||
let vote_state = VoteState::default();
|
let vote_state = VoteState::default();
|
||||||
let mut vote_account_data: Vec<u8> = vec![0; VoteState::size_of()];
|
let mut vote_account_data: Vec<u8> = 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();
|
VoteState::serialize(&versioned, &mut vote_account_data).unwrap();
|
||||||
let mut expected_vote_state = UiVoteState::default();
|
let mut expected_vote_state = UiVoteState::default();
|
||||||
expected_vote_state.node_pubkey = Pubkey::default().to_string();
|
expected_vote_state.node_pubkey = Pubkey::default().to_string();
|
||||||
|
@ -433,26 +433,26 @@ mod tests {
|
|||||||
let mut vote_state1 = VoteState::from(&vote_account1).unwrap();
|
let mut vote_state1 = VoteState::from(&vote_account1).unwrap();
|
||||||
vote_state1.process_slot_vote_unchecked(3);
|
vote_state1.process_slot_vote_unchecked(3);
|
||||||
vote_state1.process_slot_vote_unchecked(5);
|
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();
|
VoteState::to(&versioned, &mut vote_account1).unwrap();
|
||||||
bank.store_account(&pk1, &vote_account1);
|
bank.store_account(&pk1, &vote_account1);
|
||||||
|
|
||||||
let mut vote_state2 = VoteState::from(&vote_account2).unwrap();
|
let mut vote_state2 = VoteState::from(&vote_account2).unwrap();
|
||||||
vote_state2.process_slot_vote_unchecked(9);
|
vote_state2.process_slot_vote_unchecked(9);
|
||||||
vote_state2.process_slot_vote_unchecked(10);
|
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();
|
VoteState::to(&versioned, &mut vote_account2).unwrap();
|
||||||
bank.store_account(&pk2, &vote_account2);
|
bank.store_account(&pk2, &vote_account2);
|
||||||
|
|
||||||
let mut vote_state3 = VoteState::from(&vote_account3).unwrap();
|
let mut vote_state3 = VoteState::from(&vote_account3).unwrap();
|
||||||
vote_state3.root_slot = Some(1);
|
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();
|
VoteState::to(&versioned, &mut vote_account3).unwrap();
|
||||||
bank.store_account(&pk3, &vote_account3);
|
bank.store_account(&pk3, &vote_account3);
|
||||||
|
|
||||||
let mut vote_state4 = VoteState::from(&vote_account4).unwrap();
|
let mut vote_state4 = VoteState::from(&vote_account4).unwrap();
|
||||||
vote_state4.root_slot = Some(2);
|
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();
|
VoteState::to(&versioned, &mut vote_account4).unwrap();
|
||||||
bank.store_account(&pk4, &vote_account4);
|
bank.store_account(&pk4, &vote_account4);
|
||||||
|
|
||||||
|
@ -1581,7 +1581,7 @@ pub mod test {
|
|||||||
vote_state.process_slot_vote_unchecked(*slot);
|
vote_state.process_slot_vote_unchecked(*slot);
|
||||||
}
|
}
|
||||||
VoteState::serialize(
|
VoteState::serialize(
|
||||||
&VoteStateVersions::Current(Box::new(vote_state)),
|
&VoteStateVersions::new_current(vote_state),
|
||||||
&mut account.data,
|
&mut account.data,
|
||||||
)
|
)
|
||||||
.expect("serialize state");
|
.expect("serialize state");
|
||||||
|
@ -2546,7 +2546,7 @@ pub(crate) mod tests {
|
|||||||
let mut leader_vote_account = bank.get_account(&pubkey).unwrap();
|
let mut leader_vote_account = bank.get_account(&pubkey).unwrap();
|
||||||
let mut vote_state = VoteState::from(&leader_vote_account).unwrap();
|
let mut vote_state = VoteState::from(&leader_vote_account).unwrap();
|
||||||
vote_state.process_slot_vote_unchecked(vote_slot);
|
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();
|
VoteState::to(&versioned, &mut leader_vote_account).unwrap();
|
||||||
bank.store_account(&pubkey, &leader_vote_account);
|
bank.store_account(&pubkey, &leader_vote_account);
|
||||||
}
|
}
|
||||||
|
@ -3155,7 +3155,7 @@ pub mod tests {
|
|||||||
vote_state.root_slot = Some(root);
|
vote_state.root_slot = Some(root);
|
||||||
let mut vote_account =
|
let mut vote_account =
|
||||||
Account::new(1, VoteState::size_of(), &solana_vote_program::id());
|
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();
|
VoteState::serialize(&versioned, &mut vote_account.data).unwrap();
|
||||||
(
|
(
|
||||||
solana_sdk::pubkey::new_rand(),
|
solana_sdk::pubkey::new_rand(),
|
||||||
|
@ -340,7 +340,7 @@ pub(crate) mod tests {
|
|||||||
let vote_accounts = stakes.into_iter().map(|(stake, vote_state)| {
|
let vote_accounts = stakes.into_iter().map(|(stake, vote_state)| {
|
||||||
let account = Account::new_data(
|
let account = Account::new_data(
|
||||||
rng.gen(), // lamports
|
rng.gen(), // lamports
|
||||||
&VoteStateVersions::Current(Box::new(vote_state)),
|
&VoteStateVersions::new_current(vote_state),
|
||||||
&Pubkey::new_unique(), // owner
|
&Pubkey::new_unique(), // owner
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -1004,7 +1004,7 @@ mod tests {
|
|||||||
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
||||||
let vote_state_credits = vote_state.credits();
|
let vote_state_credits = vote_state.credits();
|
||||||
vote_keyed_account
|
vote_keyed_account
|
||||||
.set_state(&VoteStateVersions::Current(Box::new(vote_state)))
|
.set_state(&VoteStateVersions::new_current(vote_state))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let stake_pubkey = solana_sdk::pubkey::new_rand();
|
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);
|
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
||||||
vote_keyed_account
|
vote_keyed_account
|
||||||
.set_state(&VoteStateVersions::Current(Box::new(VoteState::default())))
|
.set_state(&VoteStateVersions::new_current(VoteState::default()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.delegate(
|
stake_keyed_account.delegate(
|
||||||
@ -1993,7 +1993,7 @@ mod tests {
|
|||||||
));
|
));
|
||||||
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
||||||
vote_keyed_account
|
vote_keyed_account
|
||||||
.set_state(&VoteStateVersions::Current(Box::new(VoteState::default())))
|
.set_state(&VoteStateVersions::new_current(VoteState::default()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
stake_keyed_account
|
stake_keyed_account
|
||||||
@ -2235,7 +2235,7 @@ mod tests {
|
|||||||
));
|
));
|
||||||
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
||||||
vote_keyed_account
|
vote_keyed_account
|
||||||
.set_state(&VoteStateVersions::Current(Box::new(VoteState::default())))
|
.set_state(&VoteStateVersions::new_current(VoteState::default()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers = vec![stake_pubkey].into_iter().collect();
|
let signers = vec![stake_pubkey].into_iter().collect();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -2351,7 +2351,7 @@ mod tests {
|
|||||||
));
|
));
|
||||||
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
||||||
vote_keyed_account
|
vote_keyed_account
|
||||||
.set_state(&VoteStateVersions::Current(Box::new(VoteState::default())))
|
.set_state(&VoteStateVersions::new_current(VoteState::default()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers = vec![stake_pubkey].into_iter().collect();
|
let signers = vec![stake_pubkey].into_iter().collect();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -99,9 +99,17 @@ impl StakeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn lockup(&self) -> Option<Lockup> {
|
pub fn lockup(&self) -> Option<Lockup> {
|
||||||
|
self.meta().map(|meta| meta.lockup)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn meta_from(account: &Account) -> Option<Meta> {
|
||||||
|
Self::from(account).and_then(|state: Self| state.meta())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn meta(&self) -> Option<Meta> {
|
||||||
match self {
|
match self {
|
||||||
StakeState::Stake(meta, _stake) => Some(meta.lockup),
|
StakeState::Stake(meta, _stake) => Some(*meta),
|
||||||
StakeState::Initialized(meta) => Some(meta.lockup),
|
StakeState::Initialized(meta) => Some(*meta),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1054,6 +1062,11 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
|||||||
_ => return Err(InstructionError::InvalidAccountData),
|
_ => 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;
|
split.try_account_ref_mut()?.lamports += lamports;
|
||||||
self.try_account_ref_mut()?.lamports -= lamports;
|
self.try_account_ref_mut()?.lamports -= lamports;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1090,6 +1103,9 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
|||||||
self.set_state(&merged_state)?;
|
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
|
// Drain the source stake account
|
||||||
let lamports = source_account.lamports()?;
|
let lamports = source_account.lamports()?;
|
||||||
source_account.try_account_ref_mut()?.lamports -= lamports;
|
source_account.try_account_ref_mut()?.lamports -= lamports;
|
||||||
@ -1166,6 +1182,11 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
|||||||
return Err(InstructionError::InsufficientFunds);
|
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;
|
self.try_account_ref_mut()?.lamports -= lamports;
|
||||||
to.try_account_ref_mut()?.lamports += lamports;
|
to.try_account_ref_mut()?.lamports += lamports;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1641,7 +1662,7 @@ mod tests {
|
|||||||
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
||||||
let vote_state_credits = vote_state.credits();
|
let vote_state_credits = vote_state.credits();
|
||||||
vote_keyed_account
|
vote_keyed_account
|
||||||
.set_state(&VoteStateVersions::Current(Box::new(vote_state)))
|
.set_state(&VoteStateVersions::new_current(vote_state))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let stake_pubkey = solana_sdk::pubkey::new_rand();
|
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);
|
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
||||||
vote_keyed_account
|
vote_keyed_account
|
||||||
.set_state(&VoteStateVersions::Current(Box::new(VoteState::default())))
|
.set_state(&VoteStateVersions::new_current(VoteState::default()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake_keyed_account.delegate(
|
stake_keyed_account.delegate(
|
||||||
@ -2630,7 +2651,7 @@ mod tests {
|
|||||||
));
|
));
|
||||||
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
||||||
vote_keyed_account
|
vote_keyed_account
|
||||||
.set_state(&VoteStateVersions::Current(Box::new(VoteState::default())))
|
.set_state(&VoteStateVersions::new_current(VoteState::default()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
stake_keyed_account
|
stake_keyed_account
|
||||||
@ -2828,6 +2849,7 @@ mod tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
assert_eq!(stake_account.borrow().lamports, 0);
|
assert_eq!(stake_account.borrow().lamports, 0);
|
||||||
|
assert_eq!(stake_keyed_account.state(), Ok(StakeState::Uninitialized));
|
||||||
|
|
||||||
// reset balance
|
// reset balance
|
||||||
stake_account.borrow_mut().lamports = stake_lamports;
|
stake_account.borrow_mut().lamports = stake_lamports;
|
||||||
@ -2872,7 +2894,7 @@ mod tests {
|
|||||||
));
|
));
|
||||||
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
||||||
vote_keyed_account
|
vote_keyed_account
|
||||||
.set_state(&VoteStateVersions::Current(Box::new(VoteState::default())))
|
.set_state(&VoteStateVersions::new_current(VoteState::default()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers = vec![stake_pubkey].into_iter().collect();
|
let signers = vec![stake_pubkey].into_iter().collect();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -2953,6 +2975,7 @@ mod tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
assert_eq!(stake_account.borrow().lamports, 0);
|
assert_eq!(stake_account.borrow().lamports, 0);
|
||||||
|
assert_eq!(stake_keyed_account.state(), Ok(StakeState::Uninitialized));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -2988,7 +3011,7 @@ mod tests {
|
|||||||
));
|
));
|
||||||
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
let vote_keyed_account = KeyedAccount::new(&vote_pubkey, false, &vote_account);
|
||||||
vote_keyed_account
|
vote_keyed_account
|
||||||
.set_state(&VoteStateVersions::Current(Box::new(VoteState::default())))
|
.set_state(&VoteStateVersions::new_current(VoteState::default()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let signers = vec![stake_pubkey].into_iter().collect();
|
let signers = vec![stake_pubkey].into_iter().collect();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -3128,6 +3151,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
assert_eq!(stake_keyed_account.state(), Ok(StakeState::Uninitialized));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -3184,6 +3208,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
assert_eq!(stake_keyed_account.state(), Ok(StakeState::Uninitialized));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3600,6 +3625,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
|
assert_eq!(stake_keyed_account.state(), Ok(StakeState::Uninitialized));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -4498,7 +4524,7 @@ mod tests {
|
|||||||
match state {
|
match state {
|
||||||
StakeState::Initialized(_) => {
|
StakeState::Initialized(_) => {
|
||||||
assert_eq!(Ok(*state), split_stake_keyed_account.state());
|
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) => {
|
StakeState::Stake(meta, stake) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -4514,19 +4540,7 @@ mod tests {
|
|||||||
)),
|
)),
|
||||||
split_stake_keyed_account.state()
|
split_stake_keyed_account.state()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(Ok(StakeState::Uninitialized), stake_keyed_account.state());
|
||||||
Ok(StakeState::Stake(
|
|
||||||
*meta,
|
|
||||||
Stake {
|
|
||||||
delegation: Delegation {
|
|
||||||
stake: 0,
|
|
||||||
..stake.delegation
|
|
||||||
},
|
|
||||||
..*stake
|
|
||||||
}
|
|
||||||
)),
|
|
||||||
stake_keyed_account.state()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@ -4608,19 +4622,7 @@ mod tests {
|
|||||||
)),
|
)),
|
||||||
split_stake_keyed_account.state()
|
split_stake_keyed_account.state()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(Ok(StakeState::Uninitialized), stake_keyed_account.state());
|
||||||
Ok(StakeState::Stake(
|
|
||||||
meta,
|
|
||||||
Stake {
|
|
||||||
delegation: Delegation {
|
|
||||||
stake: 0,
|
|
||||||
..stake.delegation
|
|
||||||
},
|
|
||||||
..stake
|
|
||||||
}
|
|
||||||
)),
|
|
||||||
stake_keyed_account.state()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4722,9 +4724,9 @@ mod tests {
|
|||||||
Ok(StakeState::Initialized(expected_split_meta)),
|
Ok(StakeState::Initialized(expected_split_meta)),
|
||||||
split_stake_keyed_account.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) => {
|
StakeState::Stake(_meta, stake) => {
|
||||||
// Expected stake should reflect original stake amount so that extra lamports
|
// Expected stake should reflect original stake amount so that extra lamports
|
||||||
// from the rent_exempt_reserve inequality do not magically activate
|
// from the rent_exempt_reserve inequality do not magically activate
|
||||||
let expected_stake = stake_lamports - rent_exempt_reserve;
|
let expected_stake = stake_lamports - rent_exempt_reserve;
|
||||||
@ -4748,19 +4750,7 @@ mod tests {
|
|||||||
+ expected_rent_exempt_reserve
|
+ expected_rent_exempt_reserve
|
||||||
+ (rent_exempt_reserve - expected_rent_exempt_reserve)
|
+ (rent_exempt_reserve - expected_rent_exempt_reserve)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(Ok(StakeState::Uninitialized), stake_keyed_account.state());
|
||||||
Ok(StakeState::Stake(
|
|
||||||
*meta,
|
|
||||||
Stake {
|
|
||||||
delegation: Delegation {
|
|
||||||
stake: 0,
|
|
||||||
..stake.delegation
|
|
||||||
},
|
|
||||||
..*stake
|
|
||||||
}
|
|
||||||
)),
|
|
||||||
stake_keyed_account.state()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@ -4836,6 +4826,44 @@ mod tests {
|
|||||||
stake_lamports * 2
|
stake_lamports * 2
|
||||||
);
|
);
|
||||||
assert_eq!(source_stake_keyed_account.account.borrow().lamports, 0);
|
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 =
|
let test_source_keyed =
|
||||||
KeyedAccount::new(source_account.unsigned_key(), true, &test_source_account);
|
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
|
// stake activation epoch, source initialized succeeds
|
||||||
|
@ -19,6 +19,7 @@ use solana_sdk::{
|
|||||||
sysvar::clock::Clock,
|
sysvar::clock::Clock,
|
||||||
};
|
};
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
|
use std::cmp::Ordering;
|
||||||
use std::collections::{HashSet, VecDeque};
|
use std::collections::{HashSet, VecDeque};
|
||||||
|
|
||||||
mod vote_state_0_23_5;
|
mod vote_state_0_23_5;
|
||||||
@ -214,7 +215,7 @@ impl VoteState {
|
|||||||
pub fn size_of() -> usize {
|
pub fn size_of() -> usize {
|
||||||
// Upper limit on the size of the Vote State. Equal to
|
// Upper limit on the size of the Vote State. Equal to
|
||||||
// size_of(VoteState) when votes.len() is MAX_LOCKOUT_HISTORY
|
// 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
|
serialized_size(&vote_state).unwrap() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -594,7 +595,7 @@ pub fn authorize<S: std::hash::BuildHasher>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
/// Update the node_pubkey, requires signature of the authorized voter
|
||||||
@ -614,7 +615,7 @@ pub fn update_validator_identity<S: std::hash::BuildHasher>(
|
|||||||
|
|
||||||
vote_state.node_pubkey = *node_pubkey;
|
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
|
/// Update the vote account's commission
|
||||||
@ -631,7 +632,7 @@ pub fn update_commission<S: std::hash::BuildHasher>(
|
|||||||
|
|
||||||
vote_state.commission = 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<S: std::hash::BuildHasher>(
|
fn verify_authorized_signer<S: std::hash::BuildHasher>(
|
||||||
@ -657,8 +658,13 @@ pub fn withdraw<S: std::hash::BuildHasher>(
|
|||||||
|
|
||||||
verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
|
verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
|
||||||
|
|
||||||
if vote_account.lamports()? < lamports {
|
match vote_account.lamports()?.cmp(&lamports) {
|
||||||
return Err(InstructionError::InsufficientFunds);
|
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;
|
vote_account.try_account_ref_mut()?.lamports -= lamports;
|
||||||
to_account.try_account_ref_mut()?.lamports += lamports;
|
to_account.try_account_ref_mut()?.lamports += lamports;
|
||||||
@ -683,9 +689,9 @@ pub fn initialize_account<S: std::hash::BuildHasher>(
|
|||||||
// node must agree to accept this vote account
|
// node must agree to accept this vote account
|
||||||
verify_authorized_signer(&vote_init.node_pubkey, signers)?;
|
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,
|
vote_init, clock,
|
||||||
))))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_vote<S: std::hash::BuildHasher>(
|
pub fn process_vote<S: std::hash::BuildHasher>(
|
||||||
@ -715,7 +721,7 @@ pub fn process_vote<S: std::hash::BuildHasher>(
|
|||||||
.ok_or_else(|| VoteError::EmptySlots)
|
.ok_or_else(|| VoteError::EmptySlots)
|
||||||
.and_then(|slot| vote_state.process_timestamp(*slot, timestamp))?;
|
.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(
|
pub fn create_account_with_authorized(
|
||||||
@ -737,7 +743,7 @@ pub fn create_account_with_authorized(
|
|||||||
&Clock::default(),
|
&Clock::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let versioned = VoteStateVersions::Current(Box::new(vote_state));
|
let versioned = VoteStateVersions::new_current(vote_state);
|
||||||
VoteState::to(&versioned, &mut vote_account).unwrap();
|
VoteState::to(&versioned, &mut vote_account).unwrap();
|
||||||
|
|
||||||
vote_account
|
vote_account
|
||||||
@ -915,11 +921,11 @@ mod tests {
|
|||||||
vote_state
|
vote_state
|
||||||
.votes
|
.votes
|
||||||
.resize(MAX_LOCKOUT_HISTORY, Lockout::default());
|
.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());
|
assert!(VoteState::serialize(&versioned, &mut buffer[0..4]).is_err());
|
||||||
VoteState::serialize(&versioned, &mut buffer).unwrap();
|
VoteState::serialize(&versioned, &mut buffer).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
VoteStateVersions::Current(Box::new(VoteState::deserialize(&buffer).unwrap())),
|
VoteStateVersions::new_current(VoteState::deserialize(&buffer).unwrap()),
|
||||||
versioned
|
versioned
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1626,6 +1632,7 @@ mod tests {
|
|||||||
let lamports = vote_account.borrow().lamports;
|
let lamports = vote_account.borrow().lamports;
|
||||||
let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, true, &vote_account)];
|
let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, true, &vote_account)];
|
||||||
let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
|
let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
|
||||||
|
let pre_state: VoteStateVersions = vote_account.borrow().state().unwrap();
|
||||||
let res = withdraw(
|
let res = withdraw(
|
||||||
&keyed_accounts[0],
|
&keyed_accounts[0],
|
||||||
lamports,
|
lamports,
|
||||||
@ -1635,9 +1642,13 @@ mod tests {
|
|||||||
assert_eq!(res, Ok(()));
|
assert_eq!(res, Ok(()));
|
||||||
assert_eq!(vote_account.borrow().lamports, 0);
|
assert_eq!(vote_account.borrow().lamports, 0);
|
||||||
assert_eq!(to_account.borrow().lamports, lamports);
|
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().lamports = lamports;
|
||||||
|
vote_account.borrow_mut().set_state(&pre_state).unwrap();
|
||||||
|
|
||||||
// authorize authorized_withdrawer
|
// authorize authorized_withdrawer
|
||||||
let authorized_withdrawer_pubkey = solana_sdk::pubkey::new_rand();
|
let authorized_withdrawer_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
@ -1671,6 +1682,9 @@ mod tests {
|
|||||||
assert_eq!(res, Ok(()));
|
assert_eq!(res, Ok(()));
|
||||||
assert_eq!(vote_account.borrow().lamports, 0);
|
assert_eq!(vote_account.borrow().lamports, 0);
|
||||||
assert_eq!(withdrawer_account.borrow().lamports, lamports);
|
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]
|
#[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();
|
VoteState::serialize(&versioned, &mut max_sized_data).unwrap();
|
||||||
vote_state = Some(versioned.convert_to_current());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,10 @@ pub enum VoteStateVersions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VoteStateVersions {
|
impl VoteStateVersions {
|
||||||
|
pub fn new_current(vote_state: VoteState) -> Self {
|
||||||
|
Self::Current(Box::new(vote_state))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn convert_to_current(self) -> VoteState {
|
pub fn convert_to_current(self) -> VoteState {
|
||||||
match self {
|
match self {
|
||||||
VoteStateVersions::V0_23_5(state) => {
|
VoteStateVersions::V0_23_5(state) => {
|
||||||
|
@ -204,6 +204,8 @@ impl Accounts {
|
|||||||
})? {
|
})? {
|
||||||
SystemAccountKind::System => 0,
|
SystemAccountKind::System => 0,
|
||||||
SystemAccountKind::Nonce => {
|
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())
|
rent_collector.rent.minimum_balance(nonce::State::size())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -10731,7 +10731,7 @@ pub(crate) mod tests {
|
|||||||
let mut vote_account = bank.get_account(vote_pubkey).unwrap_or_default();
|
let mut vote_account = bank.get_account(vote_pubkey).unwrap_or_default();
|
||||||
let mut vote_state = VoteState::from(&vote_account).unwrap_or_default();
|
let mut vote_state = VoteState::from(&vote_account).unwrap_or_default();
|
||||||
vote_state.last_timestamp = timestamp;
|
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();
|
VoteState::to(&versioned, &mut vote_account).unwrap();
|
||||||
bank.store_account(vote_pubkey, &vote_account);
|
bank.store_account(vote_pubkey, &vote_account);
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ mod tests {
|
|||||||
let vote_state = VoteState::new(&vote_init, &clock);
|
let vote_state = VoteState::new(&vote_init, &clock);
|
||||||
let account = Account::new_data(
|
let account = Account::new_data(
|
||||||
rng.gen(), // lamports
|
rng.gen(), // lamports
|
||||||
&VoteStateVersions::Current(Box::new(vote_state.clone())),
|
&VoteStateVersions::new_current(vote_state.clone()),
|
||||||
&Pubkey::new_unique(), // owner
|
&Pubkey::new_unique(), // owner
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -90,6 +90,7 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
|
|||||||
if data.blockhash == recent_blockhashes[0].blockhash {
|
if data.blockhash == recent_blockhashes[0].blockhash {
|
||||||
return Err(NonceError::NotExpired.into());
|
return Err(NonceError::NotExpired.into());
|
||||||
}
|
}
|
||||||
|
self.set_state(&Versions::new_current(State::Uninitialized))?;
|
||||||
} else {
|
} else {
|
||||||
let min_balance = rent.minimum_balance(self.data_len()?);
|
let min_balance = rent.minimum_balance(self.data_len()?);
|
||||||
if lamports + min_balance > self.lamports()? {
|
if lamports + min_balance > self.lamports()? {
|
||||||
@ -272,6 +273,11 @@ mod test {
|
|||||||
);
|
);
|
||||||
// Account balance goes to `to`
|
// Account balance goes to `to`
|
||||||
assert_eq!(to_keyed.account.borrow().lamports, expect_to_lamports);
|
assert_eq!(to_keyed.account.borrow().lamports, expect_to_lamports);
|
||||||
|
let state = AccountUtilsState::<Versions>::state(keyed_account)
|
||||||
|
.unwrap()
|
||||||
|
.convert_to_current();
|
||||||
|
// Empty balance deinitializes data
|
||||||
|
assert_eq!(state, State::Uninitialized);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -628,6 +634,10 @@ mod test {
|
|||||||
&signers,
|
&signers,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
|
||||||
|
.unwrap()
|
||||||
|
.convert_to_current();
|
||||||
|
assert_eq!(state, State::Uninitialized);
|
||||||
assert_eq!(nonce_keyed.account.borrow().lamports, nonce_expect_lamports);
|
assert_eq!(nonce_keyed.account.borrow().lamports, nonce_expect_lamports);
|
||||||
assert_eq!(to_keyed.account.borrow().lamports, to_expect_lamports);
|
assert_eq!(to_keyed.account.borrow().lamports, to_expect_lamports);
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user