spl_record/
processor.rs

1//! Program state processor
2
3use {
4    crate::{
5        error::RecordError,
6        instruction::RecordInstruction,
7        state::{Data, RecordData},
8    },
9    borsh::{BorshDeserialize, BorshSerialize},
10    solana_program::{
11        account_info::{next_account_info, AccountInfo},
12        entrypoint::ProgramResult,
13        msg,
14        program_error::ProgramError,
15        program_pack::IsInitialized,
16        pubkey::Pubkey,
17    },
18};
19
20fn check_authority(authority_info: &AccountInfo, expected_authority: &Pubkey) -> ProgramResult {
21    if expected_authority != authority_info.key {
22        msg!("Incorrect record authority provided");
23        return Err(RecordError::IncorrectAuthority.into());
24    }
25    if !authority_info.is_signer {
26        msg!("Record authority signature missing");
27        return Err(ProgramError::MissingRequiredSignature);
28    }
29    Ok(())
30}
31
32/// Instruction processor
33pub fn process_instruction(
34    _program_id: &Pubkey,
35    accounts: &[AccountInfo],
36    input: &[u8],
37) -> ProgramResult {
38    let instruction = RecordInstruction::try_from_slice(input)?;
39    let account_info_iter = &mut accounts.iter();
40
41    match instruction {
42        RecordInstruction::Initialize => {
43            msg!("RecordInstruction::Initialize");
44
45            let data_info = next_account_info(account_info_iter)?;
46            let authority_info = next_account_info(account_info_iter)?;
47
48            let mut account_data = RecordData::try_from_slice(*data_info.data.borrow())?;
49            if account_data.is_initialized() {
50                msg!("Record account already initialized");
51                return Err(ProgramError::AccountAlreadyInitialized);
52            }
53
54            account_data.authority = *authority_info.key;
55            account_data.version = RecordData::CURRENT_VERSION;
56            account_data
57                .serialize(&mut *data_info.data.borrow_mut())
58                .map_err(|e| e.into())
59        }
60
61        RecordInstruction::Write { offset, data } => {
62            msg!("RecordInstruction::Write");
63            let data_info = next_account_info(account_info_iter)?;
64            let authority_info = next_account_info(account_info_iter)?;
65            let account_data = RecordData::try_from_slice(&data_info.data.borrow())?;
66            if !account_data.is_initialized() {
67                msg!("Record account not initialized");
68                return Err(ProgramError::UninitializedAccount);
69            }
70            check_authority(authority_info, &account_data.authority)?;
71            let start = RecordData::WRITABLE_START_INDEX.saturating_add(offset as usize);
72            let end = start.saturating_add(data.len());
73            if end > data_info.data.borrow().len() {
74                Err(ProgramError::AccountDataTooSmall)
75            } else {
76                data_info.data.borrow_mut()[start..end].copy_from_slice(&data);
77                Ok(())
78            }
79        }
80
81        RecordInstruction::SetAuthority => {
82            msg!("RecordInstruction::SetAuthority");
83            let data_info = next_account_info(account_info_iter)?;
84            let authority_info = next_account_info(account_info_iter)?;
85            let new_authority_info = next_account_info(account_info_iter)?;
86            let mut account_data = RecordData::try_from_slice(&data_info.data.borrow())?;
87            if !account_data.is_initialized() {
88                msg!("Record account not initialized");
89                return Err(ProgramError::UninitializedAccount);
90            }
91            check_authority(authority_info, &account_data.authority)?;
92            account_data.authority = *new_authority_info.key;
93            account_data
94                .serialize(&mut *data_info.data.borrow_mut())
95                .map_err(|e| e.into())
96        }
97
98        RecordInstruction::CloseAccount => {
99            msg!("RecordInstruction::CloseAccount");
100            let data_info = next_account_info(account_info_iter)?;
101            let authority_info = next_account_info(account_info_iter)?;
102            let destination_info = next_account_info(account_info_iter)?;
103            let mut account_data = RecordData::try_from_slice(&data_info.data.borrow())?;
104            if !account_data.is_initialized() {
105                msg!("Record not initialized");
106                return Err(ProgramError::UninitializedAccount);
107            }
108            check_authority(authority_info, &account_data.authority)?;
109            let destination_starting_lamports = destination_info.lamports();
110            let data_lamports = data_info.lamports();
111            **data_info.lamports.borrow_mut() = 0;
112            **destination_info.lamports.borrow_mut() = destination_starting_lamports
113                .checked_add(data_lamports)
114                .ok_or(RecordError::Overflow)?;
115            account_data.data = Data::default();
116            account_data
117                .serialize(&mut *data_info.data.borrow_mut())
118                .map_err(|e| e.into())
119        }
120    }
121}