ntoken_solana_models/states/
turing_machine.rs

1//! State turing machine types
2use crate::constants::account_type::{TYPE_ACCOUNT_TRIGGUER_TURING_MACHINE_ACCOUNT, TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT};
3use crate::constants::{
4    account_size::SPLU_SECONDARY_STRUCT_LEN,
5    account_size::TURING_MACHINE_ACCOUNT_PREFIX,
6    constant::PUBKEY_SIZE
7};
8use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs};
9use serde::{Deserialize, Serialize};
10use solana_program::entrypoint::ProgramResult;
11use solana_program::{
12    program_error::ProgramError,
13    program_pack::Sealed,
14    pubkey::Pubkey,
15};
16use crate::error::PortfolioError;
17
18const TYPE_SIZE: usize = 1;
19const STATE_SIZE: usize = 1;
20const AMOUNT_SIZE: usize = 8;
21const VERSION_SIZE: usize = 1;
22const DATE_SIZE:usize = 8;
23
24/// struct of SPLU of turing
25#[repr(C)]
26#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
27pub struct SpluStateSecondaryStruct {
28    /// SPLU secondary address.
29    pub splu_secondary_address: Pubkey,
30    /// State of SPLU secondary.
31    pub splu_state: u8,
32    /// SPLU secondary address temploral.
33    pub splu_secondary_temporal: Pubkey,
34}
35
36impl SpluStateSecondaryStruct {
37    /// update the state of splu secondary.
38    pub fn update_state_splu(&mut self) -> ProgramResult {
39        self.splu_state = self
40            .splu_state
41            .checked_add(1)
42            .ok_or(PortfolioError::InvalidState)?;
43
44        Ok(())
45    }
46
47    /// Update the state of splu.
48    pub fn update_state_splu_with_param(&mut self, state: u8) -> ProgramResult {
49        self.splu_state = state;
50        Ok(())
51    }
52
53    /// Reset the state of splu secondary.
54    pub fn reset_splu_secondary(&mut self) -> ProgramResult {
55        self.splu_state = 0;
56        Ok(())
57    }
58
59     /// Update splu secondary temporal.
60     pub fn update_splu_sec_tmp(&mut self, splu_sec_tmp: Pubkey) -> ProgramResult {
61        self.splu_secondary_temporal = splu_sec_tmp;
62        Ok(())
63    }
64}
65
66/// Account data.
67#[repr(C)]
68#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
69pub struct TuringMachineAccount {
70    /// The type of account.
71    pub type_account: u8,
72    /// The owner of this account.
73    pub owner: Pubkey,
74    /// The user portfolio linked to this account.
75    pub splm_n_asset: Pubkey,
76    /// State of Turing account to know which step was completed.
77    pub state: u8,
78    /// Last amount deposited or withrawal.
79    pub amount: u64,
80    /// Version of Turing struct.
81    pub version: u8,
82    /// Save a specific date.
83    pub date: i64,
84    /// List of splu state contain the state of each splu secondary after swap [`SpluStateSecondaryStruct`].
85    pub splu_state_list: Vec<SpluStateSecondaryStruct>,
86}
87
88impl Sealed for TuringMachineAccount {}
89
90pub trait IsInitializedTuringMachine {
91    /// Is initialized
92    fn is_initialized(&self) -> bool;
93}
94impl IsInitializedTuringMachine for TuringMachineAccount {
95   fn is_initialized(&self) -> bool {
96       return (self.type_account == TYPE_ACCOUNT_TRIGGUER_TURING_MACHINE_ACCOUNT) || (self.type_account == TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT);
97   }
98}
99/// pack and unpack for turing account
100pub trait PackTuringMachineAccount {
101    /// unpack user portfolio
102    fn unpack_turing_machine_account(src: &[u8]) -> Result<TuringMachineAccount, ProgramError>;
103    /// pack user portfolio
104    fn pack_turing_machine_account(&self, dst: &mut [u8]);
105}
106
107impl PackTuringMachineAccount for TuringMachineAccount {
108    // unpack turing trigguer account
109
110    fn unpack_turing_machine_account(src: &[u8]) -> Result<Self, ProgramError> {
111        let numbre_splu_state =
112            (&src.len() - TURING_MACHINE_ACCOUNT_PREFIX) / SPLU_SECONDARY_STRUCT_LEN;
113        let len_splu_data = &src.len() - TURING_MACHINE_ACCOUNT_PREFIX;
114
115        let src_fix = array_ref![&src, 0, TURING_MACHINE_ACCOUNT_PREFIX];
116
117        let (type_account, owner, splm_n_asset, state, amount, version, date) = array_refs![
118            src_fix,
119            TYPE_SIZE,
120            PUBKEY_SIZE,
121            PUBKEY_SIZE,
122            STATE_SIZE,
123            AMOUNT_SIZE,
124            VERSION_SIZE,
125            DATE_SIZE
126        ];
127
128        let mut splu_vec: Vec<SpluStateSecondaryStruct> = Vec::with_capacity(numbre_splu_state);
129
130        let list_splu_data = &src[TURING_MACHINE_ACCOUNT_PREFIX
131            ..TURING_MACHINE_ACCOUNT_PREFIX + (len_splu_data) as usize];
132
133        // Unpack list of splu struct.
134        let mut offset = 0;
135        for _ in 0..numbre_splu_state {
136            let splu_secondary = array_ref![list_splu_data, offset, SPLU_SECONDARY_STRUCT_LEN];
137            #[allow(clippy::ptr_offset_with_cast)]
138            let (splu_secondary_address, splu_state,splu_secondary_temporal) = array_refs![splu_secondary, PUBKEY_SIZE, 1,PUBKEY_SIZE];
139            splu_vec.push(SpluStateSecondaryStruct {
140                splu_secondary_address: Pubkey::new_from_array(*splu_secondary_address),
141                splu_state: u8::from_le_bytes(*splu_state),
142                splu_secondary_temporal: Pubkey::new_from_array(*splu_secondary_temporal),
143            });
144            offset += SPLU_SECONDARY_STRUCT_LEN;
145        }
146        Ok(TuringMachineAccount {
147            type_account: u8::from_le_bytes(*type_account),
148            owner: Pubkey::new_from_array(*owner),
149            splm_n_asset: Pubkey::new_from_array(*splm_n_asset),
150            state: u8::from_le_bytes(*state),
151            amount: u64::from_le_bytes(*amount),
152            version: u8::from_le_bytes(*version),
153            date: i64::from_le_bytes(*date),
154            splu_state_list: splu_vec.to_vec(),
155        })
156    }
157
158    // Pack turing machine account.
159    fn pack_turing_machine_account(&self, dst: &mut [u8]) {
160        let dst_tmp = array_mut_ref![dst, 0, TURING_MACHINE_ACCOUNT_PREFIX];
161        let (type_account_dst, owner_dst, splm_n_asset_dst, state_dst, amount_dst, version_dst,date_dst) = mut_array_refs![
162            dst_tmp,
163            TYPE_SIZE,
164            PUBKEY_SIZE,
165            PUBKEY_SIZE,
166            STATE_SIZE,
167            AMOUNT_SIZE,
168            VERSION_SIZE,
169            DATE_SIZE
170        ];
171        let TuringMachineAccount {
172            type_account,
173            owner,
174            splm_n_asset,
175            state,
176            amount,
177            version,
178            date,
179            splu_state_list,
180        } = self;
181
182        let splu_vec_tmp = bincode::serialize(&splu_state_list).unwrap();
183        let len_splu = splu_vec_tmp.len();
184        let nbre_splu = (len_splu - 8) / SPLU_SECONDARY_STRUCT_LEN;
185        let len_slu_reel = nbre_splu * SPLU_SECONDARY_STRUCT_LEN;
186        let mut splu_data_tmp = [0; SPLU_SECONDARY_STRUCT_LEN * 10]; // maximum 10 splu
187
188        splu_data_tmp[0..len_slu_reel as usize].clone_from_slice(&splu_vec_tmp[8..len_splu]); // 0..8 : 8 bytes contain length of struct
189
190        *type_account_dst = type_account.to_le_bytes();
191        owner_dst.copy_from_slice(owner.as_ref());
192        splm_n_asset_dst.copy_from_slice(splm_n_asset.as_ref());
193        *state_dst = state.to_le_bytes();
194        *amount_dst = amount.to_le_bytes();
195        *version_dst = version.to_le_bytes();
196        *date_dst = date.to_le_bytes();
197        dst[TURING_MACHINE_ACCOUNT_PREFIX..TURING_MACHINE_ACCOUNT_PREFIX + len_slu_reel as usize]
198            .copy_from_slice(&splu_data_tmp[0..len_slu_reel]);
199    }
200}
201
202#[cfg(test)]
203mod tests {
204    use super::*;
205    use crate::constants::account_type::TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT;
206
207    #[test]
208    fn test_pack_turing_account() {
209        let type_account = TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT;
210        let owner = Pubkey::new_unique();
211        let state = 0;
212        let splm_n_asset = Pubkey::new_unique();
213        let amount = 2;
214        let version = 1;
215        let date = 234;
216
217        let splu_struct = SpluStateSecondaryStruct {
218            splu_secondary_address: Pubkey::new_unique(),
219            splu_state: 0,
220            splu_secondary_temporal: Pubkey::new_unique(),
221        };
222
223        let mut splu_state_list = Vec::new();
224        splu_state_list.push(splu_struct);
225        let turing = TuringMachineAccount {
226            type_account,
227            owner,
228            splm_n_asset,
229            state,
230            amount,
231            version,
232            date,
233            splu_state_list,
234        };
235
236        const LEN: usize = TURING_MACHINE_ACCOUNT_PREFIX + (SPLU_SECONDARY_STRUCT_LEN * 1); // 204: @préfix + 164:splu_len * 1
237        let mut packed = [0u8; LEN];
238
239        TuringMachineAccount::pack_turing_machine_account(&turing, &mut packed[..]);
240        let unpacked = TuringMachineAccount::unpack_turing_machine_account(&packed).unwrap();
241        assert_eq!(turing, unpacked);
242        assert_eq!(unpacked.type_account, TYPE_ACCOUNT_TURING_MACHINE_ACCOUNT);
243    }
244}