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