spl_record/
state.rs

1//! Program state
2use {
3    borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
4    solana_program::{program_pack::IsInitialized, pubkey::Pubkey},
5};
6
7/// Struct wrapping data and providing metadata
8#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, PartialEq)]
9pub struct RecordData {
10    /// Struct version, allows for upgrades to the program
11    pub version: u8,
12
13    /// The account allowed to update the data
14    pub authority: Pubkey,
15
16    /// The data contained by the account, could be anything serializable
17    pub data: Data,
18}
19
20/// Struct just for data
21#[derive(Clone, Debug, Default, BorshSerialize, BorshDeserialize, BorshSchema, PartialEq)]
22pub struct Data {
23    /// The data contained by the account, could be anything or serializable
24    pub bytes: [u8; Self::DATA_SIZE],
25}
26
27impl Data {
28    /// very small data for easy testing
29    pub const DATA_SIZE: usize = 8;
30}
31
32impl RecordData {
33    /// Version to fill in on new created accounts
34    pub const CURRENT_VERSION: u8 = 1;
35
36    /// Start of writable account data, after version and authority
37    pub const WRITABLE_START_INDEX: usize = 33;
38}
39
40impl IsInitialized for RecordData {
41    /// Is initialized
42    fn is_initialized(&self) -> bool {
43        self.version == Self::CURRENT_VERSION
44    }
45}
46
47#[cfg(test)]
48pub mod tests {
49    use super::*;
50    use solana_program::program_error::ProgramError;
51
52    /// Version for tests
53    pub const TEST_VERSION: u8 = 1;
54    /// Pubkey for tests
55    pub const TEST_PUBKEY: Pubkey = Pubkey::new_from_array([100; 32]);
56    /// Bytes for tests
57    pub const TEST_BYTES: [u8; Data::DATA_SIZE] = [42; Data::DATA_SIZE];
58    /// Data for tests
59    pub const TEST_DATA: Data = Data { bytes: TEST_BYTES };
60    /// RecordData for tests
61    pub const TEST_RECORD_DATA: RecordData = RecordData {
62        version: TEST_VERSION,
63        authority: TEST_PUBKEY,
64        data: TEST_DATA,
65    };
66
67    #[test]
68    fn serialize_data() {
69        let mut expected = vec![TEST_VERSION];
70        expected.extend_from_slice(&TEST_PUBKEY.to_bytes());
71        expected.extend_from_slice(&TEST_DATA.bytes);
72        assert_eq!(TEST_RECORD_DATA.try_to_vec().unwrap(), expected);
73        assert_eq!(
74            RecordData::try_from_slice(&expected).unwrap(),
75            TEST_RECORD_DATA
76        );
77    }
78
79    #[test]
80    fn deserialize_invalid_slice() {
81        let data = [200; Data::DATA_SIZE - 1];
82        let mut expected = vec![TEST_VERSION];
83        expected.extend_from_slice(&TEST_PUBKEY.to_bytes());
84        expected.extend_from_slice(&data);
85        let err: ProgramError = RecordData::try_from_slice(&expected).unwrap_err().into();
86        assert!(matches!(err, ProgramError::BorshIoError(_)));
87    }
88}