cartesi_solana/
executor.rs

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        // the addresses changes when you push to vec
215        // so we need to get the pointers here, after
216        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(); // the order of read commands is important!
256        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        // the addresses changes when you push to vec
288        // so we need to get the pointers here, after
289        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}