diff --git a/account-decoder/src/parse_stake.rs b/account-decoder/src/parse_stake.rs index 22a6aa506c66f4..50197cb0d3c58e 100644 --- a/account-decoder/src/parse_stake.rs +++ b/account-decoder/src/parse_stake.rs @@ -136,7 +136,7 @@ impl From for UiDelegation { #[cfg(test)] mod test { - use {super::*, bincode::serialize, solana_sdk::stake::state::StakeFlags}; + use {super::*, bincode::serialize, solana_sdk::stake::stake_flags::StakeFlags}; #[test] fn test_parse_stake() { diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index 192fcf8c4a3229..b1a9effc32ac26 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -526,7 +526,8 @@ mod tests { set_lockup_checked, AuthorizeCheckedWithSeedArgs, AuthorizeWithSeedArgs, LockupArgs, StakeError, }, - state::{Authorized, Lockup, StakeActivationStatus, StakeAuthorize, StakeFlags}, + stake_flags::StakeFlags, + state::{Authorized, Lockup, StakeActivationStatus, StakeAuthorize}, MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION, }, stake_history::{StakeHistory, StakeHistoryEntry}, diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index 0626226623ff9f..fbe470301a4ead 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -25,6 +25,7 @@ use { config::Config, instruction::{LockupArgs, StakeError}, program::id, + stake_flags::StakeFlags, tools::{acceptable_reference_epoch_credits, eligible_for_deactivate_delinquent}, }, stake_history::{StakeHistory, StakeHistoryEntry}, diff --git a/runtime/src/stake_account.rs b/runtime/src/stake_account.rs index 4ff960cf538ec0..d2180e41ed5fdb 100644 --- a/runtime/src/stake_account.rs +++ b/runtime/src/stake_account.rs @@ -125,7 +125,10 @@ impl AbiExample for StakeAccount { fn example() -> Self { use solana_sdk::{ account::Account, - stake::state::{Meta, Stake, StakeFlags}, + stake::{ + stake_flags::StakeFlags, + state::{Meta, Stake}, + }, }; let stake_state = StakeState::Stake(Meta::example(), Stake::example(), StakeFlags::example()); diff --git a/sdk/program/src/stake/mod.rs b/sdk/program/src/stake/mod.rs index f498e9f297224e..a1fc97f227b51a 100644 --- a/sdk/program/src/stake/mod.rs +++ b/sdk/program/src/stake/mod.rs @@ -4,6 +4,7 @@ pub mod config; pub mod instruction; +pub mod stake_flags; pub mod state; pub mod tools; diff --git a/sdk/program/src/stake/stake_flags.rs b/sdk/program/src/stake/stake_flags.rs new file mode 100644 index 00000000000000..1d56c77fb9e0c0 --- /dev/null +++ b/sdk/program/src/stake/stake_flags.rs @@ -0,0 +1,94 @@ +use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; + +/// Additional flags for stake state. +#[derive( + Serialize, + Deserialize, + AbiExample, + BorshDeserialize, + BorshSchema, + BorshSerialize, + Copy, + PartialEq, + Eq, + Clone, + PartialOrd, + Ord, + Hash, + Debug, +)] +pub struct StakeFlags { + bits: u8, +} + +/// Currently, only bit 1 is used. The other 7 bits are reserved for future usage. +impl StakeFlags { + /// Stake must be fully activated before deactivation is allowed (bit 1). + pub const MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED: Self = + Self { bits: 0b0000_0001 }; + + pub const fn empty() -> Self { + Self { bits: 0 } + } + + pub const fn contains(&self, other: Self) -> bool { + (self.bits & other.bits) == other.bits + } + + pub fn remove(&mut self, other: Self) { + self.bits &= !other.bits; + } + + pub fn set(&mut self, other: Self) { + self.bits |= other.bits; + } + + pub const fn union(self, other: Self) -> Self { + Self { + bits: self.bits | other.bits, + } + } +} + +impl Default for StakeFlags { + fn default() -> Self { + StakeFlags::empty() + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_stake_flags() { + let mut f = StakeFlags::empty(); + assert!(!f.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED)); + + f.set(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED); + assert!(f.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED)); + + f.remove(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED); + assert!(!f.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED)); + + let f1 = StakeFlags::empty(); + let f2 = StakeFlags::empty(); + let f3 = f1.union(f2); + assert!(!f3.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED)); + + let f1 = StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED; + let f2 = StakeFlags::empty(); + let f3 = f1.union(f2); + assert!(f3.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED)); + + let f1 = StakeFlags::empty(); + let f2 = StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED; + let f3 = f1.union(f2); + assert!(f3.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED)); + + let f1 = StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED; + let f2 = StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED; + let f3 = f1.union(f2); + assert!(f3.contains(StakeFlags::MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED)); + } +} diff --git a/sdk/program/src/stake/state.rs b/sdk/program/src/stake/state.rs index a16da52458f826..8248f67e58ca8b 100644 --- a/sdk/program/src/stake/state.rs +++ b/sdk/program/src/stake/state.rs @@ -7,39 +7,16 @@ use { stake::{ config::Config, instruction::{LockupArgs, StakeError}, + stake_flags::StakeFlags, }, stake_history::{StakeHistory, StakeHistoryEntry}, }, - bitflags::bitflags, borsh::{maybestd::io, BorshDeserialize, BorshSchema, BorshSerialize}, std::collections::HashSet, }; pub type StakeActivationStatus = StakeHistoryEntry; -bitflags! { - #[derive( - Serialize, - Deserialize, - AbiExample, - BorshDeserialize, - BorshSchema, - BorshSerialize, - )] - // Additional flags for stake state. - // Currently only bit 1 is used. The other 7 bits are reserved for future. - pub struct StakeFlags : u8 { - // Stake must be fully activated before deactivation is allowed - const MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED = 0b0000_0001; - } -} - -impl Default for StakeFlags { - fn default() -> Self { - StakeFlags::empty() - } -} - #[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)] #[allow(clippy::large_enum_variant)] pub enum StakeState {