solana_feature_gate_program/
instruction.rs

1//! Program instructions
2
3use {
4    num_enum::{IntoPrimitive, TryFromPrimitive},
5    shank::ShankInstruction,
6    solana_program::{
7        incinerator,
8        instruction::{AccountMeta, Instruction},
9        program_error::ProgramError,
10        pubkey::Pubkey,
11        system_program,
12    },
13};
14
15/// Feature Gate program instructions
16#[rustfmt::skip]
17#[derive(Clone, Debug, PartialEq, IntoPrimitive, ShankInstruction, TryFromPrimitive)]
18#[repr(u8)]
19pub enum FeatureGateInstruction {
20    /// Revoke a pending feature activation.
21    ///
22    /// This instruction will burn any lamports in the feature account.
23    ///
24    /// A "pending" feature activation is a feature account that has been
25    /// allocated and assigned, but hasn't yet been updated by the runtime
26    /// with an `activation_slot`.
27    ///
28    /// Features that _have_ been activated by the runtime cannot be revoked.
29    ///
30    /// Accounts expected by this instruction:
31    ///
32    ///   0. `[w+s]`    Feature account
33    ///   1. `[w]`      Incinerator
34    ///   2. `[ ]`      System program
35    #[account(
36        0,
37        writable,
38        signer,
39        name = "feature",
40        description = "The feature account to revoke"
41    )]
42    #[account(
43        1,
44        writable,
45        name = "incinerator",
46        description = "The incinerator account"
47    )]
48    #[account(
49        2,
50        name = "system_program",
51        description = "The system program"
52    )]
53    RevokePendingActivation,
54}
55impl FeatureGateInstruction {
56    /// Unpacks a byte buffer into a
57    /// [FeatureGateInstruction](enum.FeatureGateInstruction.html).
58    pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
59        if input.len() != 1 {
60            return Err(ProgramError::InvalidInstructionData);
61        }
62        Self::try_from(input[0]).map_err(|_| ProgramError::InvalidInstructionData)
63    }
64
65    /// Packs a [FeatureGateInstruction](enum.FeatureGateInstruction.html) into
66    /// a byte buffer.
67    pub fn pack(&self) -> Vec<u8> {
68        vec![self.to_owned().into()]
69    }
70}
71
72/// Creates a 'RevokePendingActivation' instruction.
73pub fn revoke_pending_activation(feature_id: &Pubkey) -> Instruction {
74    let accounts = vec![
75        AccountMeta::new(*feature_id, true),
76        AccountMeta::new(incinerator::id(), false),
77        AccountMeta::new_readonly(system_program::id(), false),
78    ];
79
80    let data = FeatureGateInstruction::RevokePendingActivation.pack();
81
82    Instruction {
83        program_id: crate::id(),
84        accounts,
85        data,
86    }
87}
88
89#[cfg(test)]
90mod test {
91    use super::*;
92
93    fn test_pack_unpack(instruction: &FeatureGateInstruction) {
94        let packed = instruction.pack();
95        let unpacked = FeatureGateInstruction::unpack(&packed).unwrap();
96        assert_eq!(instruction, &unpacked);
97    }
98
99    #[test]
100    fn test_pack_unpack_revoke_pending_activation() {
101        test_pack_unpack(&FeatureGateInstruction::RevokePendingActivation);
102    }
103}