1use {
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
32pub 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}