Skip to main content

solana_loader_v3_interface/
state.rs

1use solana_pubkey::Pubkey;
2#[cfg(feature = "wincode")]
3use wincode::{SchemaRead, SchemaWrite};
4
5/// Upgradeable loader account states
6#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))]
7#[cfg_attr(
8    feature = "serde",
9    derive(serde_derive::Deserialize, serde_derive::Serialize)
10)]
11#[cfg_attr(feature = "wincode", derive(SchemaRead, SchemaWrite))]
12#[derive(Debug, PartialEq, Eq, Clone, Copy)]
13pub enum UpgradeableLoaderState {
14    /// Account is not initialized.
15    Uninitialized,
16    /// A Buffer account.
17    Buffer {
18        /// Authority address
19        authority_address: Option<Pubkey>,
20        // The raw program data follows this serialized structure in the
21        // account's data.
22    },
23    /// An Program account.
24    Program {
25        /// Address of the ProgramData account.
26        programdata_address: Pubkey,
27    },
28    // A ProgramData account.
29    ProgramData {
30        /// Slot that the program was last modified.
31        slot: u64,
32        /// Address of the Program's upgrade authority.
33        upgrade_authority_address: Option<Pubkey>,
34        // The raw program data follows this serialized structure in the
35        // account's data.
36    },
37}
38impl UpgradeableLoaderState {
39    /// Size of a serialized program account.
40    pub const fn size_of_uninitialized() -> usize {
41        4 // see test_state_size_of_uninitialized
42    }
43
44    /// Size of a buffer account's serialized metadata.
45    pub const fn size_of_buffer_metadata() -> usize {
46        37 // see test_state_size_of_buffer_metadata
47    }
48
49    /// Size of a programdata account's serialized metadata.
50    pub const fn size_of_programdata_metadata() -> usize {
51        45 // see test_state_size_of_programdata_metadata
52    }
53
54    /// Size of a serialized program account.
55    pub const fn size_of_program() -> usize {
56        36 // see test_state_size_of_program
57    }
58
59    /// Size of a serialized buffer account.
60    pub const fn size_of_buffer(program_len: usize) -> usize {
61        Self::size_of_buffer_metadata().saturating_add(program_len)
62    }
63
64    /// Size of a serialized programdata account.
65    pub const fn size_of_programdata(program_len: usize) -> usize {
66        Self::size_of_programdata_metadata().saturating_add(program_len)
67    }
68}
69
70#[cfg(all(test, feature = "wincode"))]
71mod tests {
72    use {super::*, test_case::test_case};
73
74    #[test]
75    fn test_state_size_of_uninitialized() {
76        let state = UpgradeableLoaderState::Uninitialized;
77        let size = wincode::serialized_size(&state).unwrap();
78        assert_eq!(UpgradeableLoaderState::size_of_uninitialized() as u64, size);
79    }
80
81    #[test]
82    fn test_state_size_of_buffer_metadata() {
83        let state = UpgradeableLoaderState::Buffer {
84            authority_address: Some(Pubkey::default()),
85        };
86        let size = wincode::serialized_size(&state).unwrap();
87        assert_eq!(
88            UpgradeableLoaderState::size_of_buffer_metadata() as u64,
89            size
90        );
91    }
92
93    #[test]
94    fn test_state_size_of_programdata_metadata() {
95        let state = UpgradeableLoaderState::ProgramData {
96            upgrade_authority_address: Some(Pubkey::default()),
97            slot: 0,
98        };
99        let size = wincode::serialized_size(&state).unwrap();
100        assert_eq!(
101            UpgradeableLoaderState::size_of_programdata_metadata() as u64,
102            size
103        );
104    }
105
106    #[test]
107    fn test_state_size_of_program() {
108        let state = UpgradeableLoaderState::Program {
109            programdata_address: Pubkey::default(),
110        };
111        let size = wincode::serialized_size(&state).unwrap();
112        assert_eq!(UpgradeableLoaderState::size_of_program() as u64, size);
113    }
114
115    /// Verify that wincode produces the exact same bytes as bincode for
116    /// every state variant, and that both round-trip correctly.
117    #[test_case(UpgradeableLoaderState::Uninitialized)]
118    #[test_case(UpgradeableLoaderState::Buffer { authority_address: Some(Pubkey::default()) })]
119    #[test_case(UpgradeableLoaderState::Buffer { authority_address: None })]
120    #[test_case(UpgradeableLoaderState::Program { programdata_address: Pubkey::default() })]
121    #[test_case(UpgradeableLoaderState::ProgramData { slot: 123_456_789, upgrade_authority_address: Some(Pubkey::default()) })]
122    #[test_case(UpgradeableLoaderState::ProgramData { slot: 0, upgrade_authority_address: None })]
123    fn wire_compat_bincode_vs_wincode(state: UpgradeableLoaderState) {
124        let bincode_bytes = bincode::serialize(&state).unwrap();
125        let wincode_bytes = wincode::serialize(&state).unwrap();
126        assert_eq!(bincode_bytes, wincode_bytes);
127
128        let from_bincode: UpgradeableLoaderState = bincode::deserialize(&bincode_bytes).unwrap();
129        let from_wincode: UpgradeableLoaderState = wincode::deserialize(&wincode_bytes).unwrap();
130        assert_eq!(from_bincode, state);
131        assert_eq!(from_wincode, state);
132    }
133}