1use crate::{
15 account_info::AccountInfo, clock::Slot, instruction::Instruction, program_error::ProgramError,
16 pubkey::Pubkey, rent::Rent, system_instruction,
17};
18
19crate::declare_id!("Feature111111111111111111111111111111111111");
20
21#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Eq)]
22pub struct Feature {
23 pub activated_at: Option<Slot>,
24}
25
26impl Feature {
27 pub const fn size_of() -> usize {
28 9 }
30
31 pub fn from_account_info(account_info: &AccountInfo) -> Result<Self, ProgramError> {
32 if *account_info.owner != id() {
33 return Err(ProgramError::InvalidArgument);
34 }
35 bincode::deserialize(&account_info.data.borrow()).map_err(|_| ProgramError::InvalidArgument)
36 }
37}
38
39pub fn activate(feature_id: &Pubkey, funding_address: &Pubkey, rent: &Rent) -> Vec<Instruction> {
41 activate_with_scoobies(
42 feature_id,
43 funding_address,
44 rent.minimum_balance(Feature::size_of()),
45 )
46}
47
48pub fn activate_with_scoobies(
49 feature_id: &Pubkey,
50 funding_address: &Pubkey,
51 scoobies: u64,
52) -> Vec<Instruction> {
53 vec![
54 system_instruction::transfer(funding_address, feature_id, scoobies),
55 system_instruction::allocate(feature_id, Feature::size_of() as u64),
56 system_instruction::assign(feature_id, &id()),
57 ]
58}
59
60#[cfg(test)]
61mod test {
62 use {super::*, cbe_program::clock::Slot};
63
64 #[test]
65 fn test_feature_size_of() {
66 assert_eq!(Feature::size_of() as u64, {
67 let feature = Feature {
68 activated_at: Some(0),
69 };
70 bincode::serialized_size(&feature).unwrap()
71 });
72 assert!(
73 Feature::size_of() >= bincode::serialized_size(&Feature::default()).unwrap() as usize
74 );
75 assert_eq!(Feature::default(), Feature { activated_at: None });
76
77 let features = [
78 Feature {
79 activated_at: Some(0),
80 },
81 Feature {
82 activated_at: Some(Slot::MAX),
83 },
84 ];
85 for feature in &features {
86 assert_eq!(
87 Feature::size_of(),
88 bincode::serialized_size(feature).unwrap() as usize
89 );
90 }
91 }
92}