1use std::{
2 cell::RefCell,
3 io::{self, Result},
4 rc::Rc,
5};
6
7use solana_program::{
8 account_info::AccountInfo,
9 instruction::{CompiledInstruction, Instruction},
10 pubkey::Pubkey,
11};
12
13use crate::{
14 account_manager::{self, create_account_manager, AccountFileData},
15 adapter::{check_header, check_signer_by_sender, load_account_info_data, set_timestamp},
16 cartesi_stub::{AccountInfoSerialize},
17 cpi, owner_manager, transaction,
18};
19
20struct DataHolder {
21 pubkey: Pubkey,
22 lamports: u64,
23 data: Vec<u8>,
24 owner: Pubkey,
25}
26
27pub struct Executor<'a, LR: LineReader> {
28 pub stdin: LR,
29 pub program_id: Option<Pubkey>,
30 pub accounts: Vec<AccountInfo<'a>>,
31 pub account_keys: Vec<Pubkey>,
32}
33
34impl<'a, LR> Executor<'a, LR>
35where
36 LR: LineReader,
37{
38 pub fn create_with_stdin(stdin: LR) -> Self {
39 let program_id = Some(Pubkey::default());
40
41 Self {
42 stdin,
43 program_id,
44 accounts: vec![],
45 account_keys: vec![],
46 }
47 }
48 pub fn get_processor_args<F>(&'a mut self, closure_fn: F)
49 where
50 F: for<'b> Fn(&'b Pubkey, &'b Vec<AccountInfo<'b>>, &'b Vec<u8>),
51 {
52 let header = self.read_line();
53 println!("header: {}", header);
54 match check_header(&header) {
55 crate::adapter::SmartContractType::ExternalPI => self.handle_external_call(closure_fn),
56 crate::adapter::SmartContractType::CPI => self.handle_cpi_call(closure_fn),
57 };
58 }
59
60 fn read_line(&mut self) -> String {
61 let mut current_line = String::new();
62 self.stdin.read_line(&mut current_line).unwrap();
63 current_line[..current_line.len() - 1].to_string()
64 }
65
66 fn read_instruction_index(&mut self) -> usize {
67 let instruction_index = self.read_line();
68 let instruction_index: usize = instruction_index
69 .trim()
70 .parse()
71 .expect("Input is not an integer");
72 instruction_index
73 }
74
75 fn read_and_set_timestamp(&mut self) {
76 let timestamp = self.read_line();
77 let timestamp: i64 = timestamp
78 .trim()
79 .parse()
80 .expect("Timestamp is not an integer");
81 set_timestamp(timestamp);
82 }
83
84 fn read_transaction(&mut self) -> transaction::Transaction {
85 let payload = self.read_line();
86 let decoded = base64::decode(payload).unwrap();
87 let tx: transaction::Transaction = bincode::deserialize(&decoded).unwrap();
88 tx
89 }
90
91 fn sender_bytes(&mut self, msg_sender: &String) -> Vec<u8> {
92 let sender_bytes: Vec<u8> = hex::decode(&msg_sender[2..])
93 .unwrap()
94 .into_iter()
95 .rev()
96 .collect();
97 sender_bytes
98 }
99
100 fn load_persisted_data(&self, account_keys: &Vec<Pubkey>) -> Vec<DataHolder> {
101 let mut data_holder = vec![];
102 for (i, pkey) in account_keys.iter().enumerate() {
103 let (data, lamports, owner) = load_account_info_data(&pkey);
104 println!(
105 "loading account[{}] with key = {:?}; data.len() = {}; program_id = {:?}",
106 i,
107 &pkey,
108 data.len(),
109 self.program_id
110 );
111 data_holder.push(DataHolder {
112 pubkey: pkey.to_owned(),
113 lamports,
114 data,
115 owner,
116 });
117 }
118 data_holder
119 }
120
121 fn get_ordered_account_keys(
122 &mut self,
123 tx: &transaction::Transaction,
124 tx_instruction: &CompiledInstruction,
125 ) -> Vec<Pubkey> {
126 let mut ordered_accounts: Vec<Pubkey> = Vec::new();
127 let tot = tx_instruction.accounts.len();
128 for j in 0..tot {
129 let index = tx_instruction.accounts[j];
130 let i: usize = index.into();
131 ordered_accounts.push(tx.message.account_keys[i].to_owned());
132 }
133 ordered_accounts
134 }
135
136 fn read_cpi_instruction(&mut self) -> Instruction {
137 let instruction = self.read_line();
138 let instruction = base64::decode(&instruction.trim()).unwrap();
139 let instruction: Instruction = bincode::deserialize(&instruction).unwrap();
140 instruction
141 }
142
143 fn read_cpi_accounts(&mut self) -> Vec<AccountInfoSerialize> {
144 let accounts = self.read_line();
145 let accounts = base64::decode(accounts).unwrap();
146 let accounts: Vec<AccountInfoSerialize> = bincode::deserialize(&accounts).unwrap();
147 accounts
148 }
149
150 fn read_signers_seeds(&mut self) -> Vec<Vec<Vec<u8>>> {
151 let signers_seed = self.read_line();
152 let signers_seed = base64::decode(signers_seed).unwrap();
153 let signers_seed: Vec<Vec<Vec<u8>>> = bincode::deserialize(&signers_seed).unwrap();
154 signers_seed
155 }
156
157 fn read_pubkey(&mut self) -> Pubkey {
158 let caller_program_id = self.read_line();
159 let caller_program_id = base64::decode(caller_program_id).unwrap();
160 let caller_program_id = Pubkey::new(&caller_program_id);
161 caller_program_id
162 }
163
164 fn setup_cartesi_stubs(&mut self, _program_id: Pubkey) {
165 #[cfg(not(target_arch = "bpf"))]
166 solana_program::program_stubs::set_syscall_stubs(Box::new(crate::cartesi_stub::CartesiStubs { program_id: _program_id }));
167 }
168
169 fn handle_cpi_call<F>(&mut self, closure_fn: F)
170 where
171 F: for<'b> Fn(&'b Pubkey, &'b Vec<AccountInfo<'b>>, &'b Vec<u8>),
172 {
173 let instruction = self.read_cpi_instruction();
174 let accounts = self.read_cpi_accounts();
175 let signers_seeds = self.read_signers_seeds();
176
177 self.read_and_set_timestamp();
178 let caller_program_id = self.read_pubkey();
179
180 let pda_signature: Vec<Vec<&[u8]>> = signers_seeds
181 .iter()
182 .map(|x| x.iter().map(|y| y.as_slice()).collect())
183 .collect();
184
185 let pda_signature: Vec<&[&[u8]]> = pda_signature.iter().map(|x| x.as_slice()).collect();
186 let pda_signature: &[&[&[u8]]] = pda_signature.as_slice();
187
188 cpi::check_signature(&caller_program_id, &instruction, &pda_signature);
189 let pubkeys: Vec<Pubkey> = instruction.accounts.iter().map(|acc| acc.pubkey).collect();
190
191 let mut ordered_accounts = vec![];
192 for key in pubkeys.iter() {
193 let account_find = accounts.iter().find(|acc| &acc.key == key);
194 match account_find {
195 Some(account_serialize) => ordered_accounts.push(account_serialize.to_owned()),
196 None => panic!("Account not found {:?}", key),
197 }
198 }
199
200 let mut accounts: Vec<AccountInfo> = ordered_accounts
201 .iter_mut()
202 .map(|account| AccountInfo {
203 key: &account.key,
204 is_signer: account.is_signer,
205 is_writable: true,
206 lamports: Rc::new(RefCell::new(&mut account.lamports)),
207 data: Rc::new(RefCell::new(&mut account.data)),
208 owner: &account.owner,
209 executable: false,
210 rent_epoch: 1,
211 })
212 .collect();
213
214 let tot = accounts.len();
217 for j in 0..tot {
218 let p: *mut &Pubkey = std::ptr::addr_of_mut!(accounts[j].owner);
219 owner_manager::add_ptr(p as *mut Pubkey, accounts[j].key.clone());
220 }
221 self.setup_cartesi_stubs(instruction.program_id.clone());
222
223 closure_fn(&instruction.program_id, &accounts, &instruction.data);
224 let new_owners: Vec<Pubkey> = accounts
225 .iter()
226 .map(|account| account.owner.to_owned())
227 .collect();
228 let data_holder: Vec<DataHolder> = self.to_data_holder(ordered_accounts);
229
230 persist_accounts(data_holder, new_owners);
231 }
232
233 fn to_data_holder(&mut self, ordered_accounts: Vec<AccountInfoSerialize>) -> Vec<DataHolder> {
234 let data_holder: Vec<DataHolder> = ordered_accounts
235 .iter()
236 .map(|account| DataHolder {
237 pubkey: account.key.to_owned(),
238 lamports: account.lamports,
239 data: account.data.to_vec(),
240 owner: account.owner.to_owned(),
241 })
242 .collect();
243 data_holder
244 }
245
246 fn is_executable(&mut self, program_id: &Pubkey) -> bool {
247 let path = std::path::Path::new(&crate::adapter::get_binary_base_path()).join(program_id.to_string());
248 path.exists()
249 }
250
251 fn handle_external_call<F>(&'a mut self, closure_fn: F)
252 where
253 F: for<'b> Fn(&'b Pubkey, &'b Vec<AccountInfo<'b>>, &'b Vec<u8>),
254 {
255 let msg_sender = self.read_line(); let sender_bytes = self.sender_bytes(&msg_sender);
257 let tx = self.read_transaction();
258 let instruction_index = self.read_instruction_index();
259 self.read_and_set_timestamp();
260 let tx_instruction = &tx.message.instructions[instruction_index];
261 let pidx: usize = (tx_instruction.program_id_index).into();
262 let program_id: &Pubkey = &tx.message.account_keys[pidx];
263 self.setup_cartesi_stubs(program_id.clone());
264
265 self.program_id = Some(program_id.to_owned());
266 let program_id = self.program_id.unwrap();
267 let ordered_accounts = self.get_ordered_account_keys(&tx, tx_instruction);
268
269 let mut data_holder = self.load_persisted_data(&ordered_accounts);
270 let mut accounts = vec![];
271 for holder in data_holder.iter_mut() {
272 let key = &holder.pubkey;
273 let is_signer = check_signer_by_sender(key, &sender_bytes);
274 let account_info = AccountInfo {
275 key: &holder.pubkey,
276 is_signer,
277 is_writable: true,
278 lamports: Rc::new(RefCell::new(&mut holder.lamports)),
279 data: Rc::new(RefCell::new(&mut holder.data)),
280 owner: &holder.owner,
281 executable: self.is_executable(key),
282 rent_epoch: 1,
283 };
284 accounts.push(account_info);
285 }
286
287 let tot = accounts.len();
290 for j in 0..tot {
291 let p: *mut &Pubkey = std::ptr::addr_of_mut!(accounts[j].owner);
292 owner_manager::add_ptr(p as *mut Pubkey, accounts[j].key.clone());
293 }
294
295 closure_fn(&program_id, &accounts, &tx_instruction.data);
296 let new_owners: Vec<Pubkey> = accounts
297 .iter()
298 .map(|account| account.owner.to_owned())
299 .collect();
300 persist_accounts(data_holder, new_owners);
301 }
302}
303
304pub fn create_executor<'b>() -> Executor<'b, DefaultStdin> {
305 let stdin = DefaultStdin {};
306 Executor::create_with_stdin(stdin)
307}
308
309fn persist_accounts(data_holder: Vec<DataHolder>, new_owners: Vec<Pubkey>) {
310 let account_manager = create_account_manager();
311 for (i, holder) in data_holder.iter().enumerate() {
312 let key = &holder.pubkey;
313 let res = account_manager::get_resized(key);
314 let mut final_data = holder.data.to_owned();
315 if let Some(data) = res {
316 final_data = data;
317 }
318 let account_file_data = AccountFileData {
319 owner: new_owners[i].to_owned(),
320 data: final_data.to_owned(),
321 lamports: holder.lamports,
322 };
323 if account_file_data.lamports <= 0 {
324 account_manager.delete_account(&key).unwrap();
325 println!("!e deleted = {:?}", key);
326 } else {
327 account_manager
328 .write_account(&key, &account_file_data)
329 .unwrap();
330 println!(" e) saved = {:?};", key);
331 println!(" owner = {:?}", account_file_data.owner.to_string());
332 }
333 }
334}
335
336pub trait LineReader {
337 fn read_line(&mut self, buf: &mut String) -> Result<usize>;
338}
339
340pub struct DefaultStdin {}
341
342impl LineReader for DefaultStdin {
343 fn read_line(&mut self, _buf: &mut String) -> io::Result<usize> {
344 #[cfg(not(target_arch = "bpf"))]
345 {
346 return std::io::stdin().read_line(_buf);
347 }
348 #[cfg(target_arch = "bpf")]
349 {
350 return io::Result::Ok(0);
351 }
352 }
353}