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)); + } +}