bitoku_sdk_agent_native/
processor.rs1use solana_program::{
2 account_info::{next_account_info, AccountInfo},
3 entrypoint::ProgramResult,
4 msg,
5 program::invoke_signed,
6 program_memory::sol_memset,
7 program_pack::Pack,
8 pubkey::Pubkey,
9 system_instruction::create_account,
10 sysvar::{rent::Rent, Sysvar},
11};
12
13use crate::{
14 error::BitokuError::{InvalidName, NoAvailableClients, Overflow, UnregisteredClient},
15 instruction::{BitokuInstructions, Request},
16 state::{addel, delel, isel, validate_name, BookKeeper, RequestData},
17};
18
19pub struct Processor;
20
21impl Processor {
22 pub fn process(
23 program_id: &Pubkey,
24 accounts: &[AccountInfo],
25 instruction_data: &[u8],
26 ) -> ProgramResult {
27 let instruction = BitokuInstructions::unpack(instruction_data)?;
28 msg!("{:?}", instruction);
29
30 match instruction {
31 BitokuInstructions::InitBitoku => {
32 msg!("Instruction : InitBitoku");
33 Self::process_init_bitoku(accounts, program_id)
34 }
35 BitokuInstructions::RegisterClient => {
36 msg!("Instruction : RegisterClient");
37 self::Processor::process_register_client(accounts, program_id)
38 }
39
40 BitokuInstructions::RemoveClient { client_id } => {
41 msg!("Instruction : RemoveClient");
42 self::Processor::process_remove_client(accounts, program_id, client_id)
43 }
44
45 BitokuInstructions::SendRequest { request } => {
46 msg!("Instruction : SendRequest");
47 self::Processor::process_send_request(accounts, program_id, request)
48 }
49 }
50 }
51
52 fn process_init_bitoku(accounts: &[AccountInfo], program_id: &Pubkey) -> ProgramResult {
53 let account_iter = &mut accounts.iter();
54
55 let fee_payer = next_account_info(account_iter)?;
56 let bookkeeper = next_account_info(account_iter)?;
57 let system_program = next_account_info(account_iter)?;
58 let rent_sysvar_account = next_account_info(account_iter)?;
59
60 let rent = Rent::from_account_info(rent_sysvar_account)?;
61
62 let (bookkeeper_key, _bump) =
63 Pubkey::find_program_address(&["bookkeeper".as_ref()], program_id);
64
65 let init_bookkeeper = create_account(
66 &fee_payer.key,
67 &bookkeeper_key,
68 rent.minimum_balance(33),
69 33,
70 &program_id,
71 );
72
73 invoke_signed(
74 &init_bookkeeper,
75 &[
76 system_program.clone(),
77 fee_payer.clone(),
78 bookkeeper.clone(),
79 ],
80 &[&["bookkeeper".as_ref(), &[_bump]]],
81 )?;
82
83 Ok(())
84 }
85
86 fn process_register_client(accounts: &[AccountInfo], program_id: &Pubkey) -> ProgramResult {
87 let accounts_iter = &mut accounts.iter();
88
89 let fee_payer = next_account_info(accounts_iter)?;
90 let bookkeeper = next_account_info(accounts_iter)?;
91 let request = next_account_info(accounts_iter)?;
92 let system_program = next_account_info(accounts_iter)?;
93 let rent_sys_var = next_account_info(accounts_iter)?;
94
95 let rent = Rent::from_account_info(rent_sys_var)?;
96
97 let (request_key, bump) =
98 Pubkey::find_program_address(&["request".as_ref(), fee_payer.key.as_ref()], program_id);
99
100 let init_request = create_account(
101 &fee_payer.key,
102 &request_key,
103 rent.minimum_balance(163),
104 163,
105 &program_id,
106 );
107
108 invoke_signed(
109 &init_request,
110 &[system_program.clone(), fee_payer.clone(), request.clone()],
111 &[&["request".as_ref(), fee_payer.key.as_ref(), &[bump]]],
112 )?;
113
114 let mut bookkeeper_data = BookKeeper::unpack_unchecked(&bookkeeper.try_borrow_data()?)?;
115 let my_id = bookkeeper_data.next_id;
116
117 addel(&mut bookkeeper_data.status, my_id);
118
119 let mut request_data = RequestData::unpack_unchecked(&request.try_borrow_data()?)?;
120
121 request_data.client_id = my_id;
122 if bookkeeper_data.next_id == 255 {
123 return Err(NoAvailableClients.into());
124 }
125
126 bookkeeper_data.next_id += 1;
127 BookKeeper::pack(bookkeeper_data, &mut bookkeeper.try_borrow_mut_data()?)?;
128 RequestData::pack(request_data, &mut request.try_borrow_mut_data()?)?;
129
130 Ok(())
131 }
132
133 fn process_remove_client(
134 accounts: &[AccountInfo],
135 _program_id: &Pubkey,
136 client_id: u8,
137 ) -> ProgramResult {
138 let accounts_iter = &mut accounts.iter();
139 let fee_payer = next_account_info(accounts_iter)?;
140 let bookkeeper = next_account_info(accounts_iter)?;
141 let request = next_account_info(accounts_iter)?;
142
143 let mut bookkeeper_data = BookKeeper::unpack_unchecked(&bookkeeper.try_borrow_data()?)?;
144
145 let bool = isel(bookkeeper_data.status, client_id);
146 if !bool {
147 return Err(UnregisteredClient.into());
148 }
149
150 delel(&mut bookkeeper_data.status, client_id);
151
152 BookKeeper::pack(bookkeeper_data, &mut bookkeeper.try_borrow_mut_data()?)?;
153
154 let current_lamps = request.lamports();
156 let account_data_size = request.data_len();
157
158 **request.lamports.borrow_mut() = 0;
160 **fee_payer.lamports.borrow_mut() = fee_payer
161 .lamports()
162 .checked_add(current_lamps)
163 .ok_or(Overflow)?;
164
165 sol_memset(&mut *request.try_borrow_mut_data()?, 0, account_data_size);
167
168 Ok(())
169 }
170
171 fn process_send_request(
172 accounts: &[AccountInfo],
173 _program_id: &Pubkey,
174 request: Request,
175 ) -> ProgramResult {
176 let accounts_iter = &mut accounts.iter();
177
178 let fee_payer = next_account_info(accounts_iter)?;
179 let req = next_account_info(accounts_iter)?;
180
181 let mut request_data = RequestData::unpack_unchecked(&req.try_borrow_data()?)?;
182
183 let s = request.name();
186 let name = String::from_utf8(s.to_vec()).unwrap();
187 if validate_name(&name.as_bytes()) == false {
188 return Err(InvalidName.into());
189 }
190
191 request_data.requester = *fee_payer.key;
192 request_data.request = request;
193
194 RequestData::pack(request_data, &mut req.try_borrow_mut_data()?)?;
195
196 Ok(())
197 }
198}