solana_program_stubs/
sol_side.rs

1#![allow(unexpected_cfgs)]
2
3/// A macro providing the necessary stubs for a Solana program.
4#[macro_export]
5#[cfg(not(target_os = "solana"))]
6macro_rules! declare_sol_app_stubs {
7    () => {
8        $crate::common_stub_types!();
9
10        #[repr(C)]
11        pub struct SolAppSyscallStubs {
12            pub stubs_api: SyscallStubsApi,
13        }
14
15        impl SyscallStubs for SolAppSyscallStubs {
16            fn sol_get_clock_sysvar(&self, var_addr: *mut u8) -> u64 {
17                (self.stubs_api.sol_get_clock_sysvar)(var_addr)
18            }
19            fn sol_get_epoch_rewards_sysvar(&self, var_addr: *mut u8) -> u64 {
20                (self.stubs_api.sol_get_epoch_rewards_sysvar)(var_addr)
21            }
22            fn sol_get_epoch_schedule_sysvar(&self, var_addr: *mut u8) -> u64 {
23                (self.stubs_api.sol_get_epoch_schedule_sysvar)(var_addr)
24            }
25            fn sol_get_epoch_stake(&self, vote_address: *const u8) -> u64 {
26                (self.stubs_api.sol_get_epoch_stake)(vote_address)
27            }
28            fn sol_get_fees_sysvar(&self, var_addr: *mut u8) -> u64 {
29                (self.stubs_api.sol_get_fees_sysvar)(var_addr)
30            }
31            fn sol_get_last_restart_slot(&self, var_addr: *mut u8) -> u64 {
32                (self.stubs_api.sol_get_last_restart_slot)(var_addr)
33            }
34            fn sol_get_rent_sysvar(&self, var_addr: *mut u8) -> u64 {
35                (self.stubs_api.sol_get_rent_sysvar)(var_addr)
36            }
37            fn sol_get_stack_height(&self) -> u64 {
38                (self.stubs_api.sol_get_stack_height)()
39            }
40            fn sol_remaining_compute_units(&self) -> u64 {
41                (self.stubs_api.sol_remaining_compute_units)()
42            }
43            unsafe fn sol_memcmp(&self, s1: *const u8, s2: *const u8, n: usize, result: *mut i32) {
44                (self.stubs_api.sol_memcmp_)(s1, s2, n as u64, result);
45            }
46            unsafe fn sol_memcpy(&self, dst: *mut u8, src: *const u8, n: usize) {
47                (self.stubs_api.sol_memcpy_)(dst, src, n as u64)
48            }
49            unsafe fn sol_memmove(&self, dst: *mut u8, src: *const u8, n: usize) {
50                (self.stubs_api.sol_memmove_)(dst, src, n as u64)
51            }
52            unsafe fn sol_memset(&self, s: *mut u8, c: u8, n: usize) {
53                (self.stubs_api.sol_memset_)(s, c, n as u64)
54            }
55            fn sol_get_sysvar(
56                &self,
57                sysvar_id_addr: *const u8,
58                var_addr: *mut u8,
59                offset: u64,
60                length: u64,
61            ) -> u64 {
62                (self.stubs_api.sol_get_sysvar)(sysvar_id_addr, var_addr, offset, length)
63            }
64            fn sol_log_compute_units(&self) {
65                (self.stubs_api.sol_log_compute_units_)()
66            }
67            fn sol_log(&self, message: &str) {
68                (self.stubs_api.sol_log_)(message.as_ptr(), message.len() as u64)
69            }
70            fn sol_log_data(&self, fields: &[&[u8]]) {
71                (self.stubs_api.sol_log_data)(fields.as_ptr() as *const u8, fields.len() as u64);
72            }
73            fn sol_set_return_data(&self, data: &[u8]) {
74                (self.stubs_api.sol_set_return_data)(data.as_ptr(), data.len() as u64);
75            }
76            fn sol_get_return_data(&self) -> Option<(Pubkey, Vec<u8>)> {
77                let mut program_id = CPubkey::from([0u8; 32]);
78                let data_bytes_to_alloc =
79                    (self.stubs_api.sol_get_return_data)(&mut u8::default(), 0, &mut program_id);
80                if data_bytes_to_alloc == 0 {
81                    return None;
82                }
83                let mut vdata = vec![0u8; data_bytes_to_alloc as usize];
84                let same_bytes_num_expected = (self.stubs_api.sol_get_return_data)(
85                    vdata.as_mut_ptr(),
86                    vdata.len() as _,
87                    &mut program_id,
88                );
89                if same_bytes_num_expected == data_bytes_to_alloc {
90                    Some((Pubkey::new_from_array(*program_id.as_array()), vdata))
91                } else {
92                    None
93                }
94            }
95            fn sol_get_processed_sibling_instruction(&self, index: usize) -> Option<Instruction> {
96                let mut meta = CProcessedSiblingInstruction {
97                    accounts_len: 0,
98                    data_len: 0,
99                };
100                let mut program_id = CPubkey::from([0u8; 32]);
101                if 1 == (self.stubs_api.sol_get_processed_sibling_instruction)(
102                    index as _,
103                    &mut meta,
104                    &mut program_id,
105                    &mut u8::default(),
106                    &mut CAccountMeta::default(),
107                ) {
108                    let accounts_to_alloc = meta.accounts_len;
109                    let data_bytes_to_alloc = meta.data_len;
110                    let mut caccount_metas = vec![CAccountMeta::default(); accounts_to_alloc as _];
111                    let mut vdata = vec![0u8; data_bytes_to_alloc as _];
112                    let res = (self.stubs_api.sol_get_processed_sibling_instruction)(
113                        index as _,
114                        &mut meta,
115                        &mut program_id,
116                        vdata.as_mut_ptr(),
117                        caccount_metas.as_mut_ptr(),
118                    );
119                    if res != 0 && res != 1 {
120                        let mut account_metas = vec![];
121                        for cai in &caccount_metas {
122                            // let pubkey = unsafe { *Box::from_raw(cai.pubkey as *mut _) };
123                            let pubkey = unsafe { *(*cai.pubkey).as_array() };
124                            let account_meta = AccountMeta {
125                                is_signer: cai.is_signer,
126                                is_writable: cai.is_writable,
127                                pubkey: Pubkey::new_from_array(pubkey),
128                            };
129                            account_metas.push(account_meta);
130                        }
131                        return Some(Instruction {
132                            accounts: account_metas,
133                            data: vdata,
134                            program_id: Pubkey::new_from_array(*program_id.as_array()),
135                        });
136                    }
137                }
138                None
139            }
140            fn sol_invoke_signed(
141                &self,
142                instruction: &Instruction,
143                account_infos: &[AccountInfo],
144                signers_seeds: &[&[&[u8]]],
145            ) -> ProgramResult {
146                let mut caccounts = vec![];
147                for account_meta in &instruction.accounts {
148                    let caccount = CAccountMeta {
149                        is_signer: account_meta.is_signer,
150                        is_writable: account_meta.is_writable,
151                        pubkey: &account_meta.pubkey as *const _ as *const CPubkey,
152                    };
153                    caccounts.push(caccount);
154                }
155                let cinstr = CInstruction {
156                    program_id: &instruction.program_id as *const _ as *const CPubkey,
157                    accounts_len: instruction.accounts.len() as _,
158                    data_len: instruction.data.len() as _,
159                    accounts: caccounts.as_ptr(),
160                    data: instruction.data.as_ptr(),
161                };
162                let mut caccount_infos = vec![];
163                for account_info in account_infos {
164                    let lamports_ref = &mut *account_info.lamports.borrow_mut();
165                    let data_ref = &mut *account_info.data.borrow_mut();
166                    let caccount_info = CAccountInfo {
167                        is_signer: account_info.is_signer,
168                        is_writable: account_info.is_writable,
169                        executable: account_info.executable,
170                        rent_epoch: account_info.rent_epoch,
171                        data_len: data_ref.len() as _,
172                        data: data_ref.as_mut_ptr(),
173                        lamports: *lamports_ref as *mut u64,
174                        key: account_info.key as *const _ as *const CPubkey,
175                        owner: account_info.owner as *const _ as *const CPubkey,
176                    };
177                    let cai = &caccount_info;
178                    let key: &Pubkey = unsafe { &*((*cai).key as *const Pubkey) };
179                    let owner: &Pubkey = unsafe { &*((*cai).owner as *const Pubkey) };
180                    caccount_infos.push(caccount_info);
181                }
182
183                let res = (self.stubs_api.sol_invoke_signed_c)(
184                    &cinstr as *const _ as *const u8,
185                    caccount_infos.as_ptr() as *const u8,
186                    caccount_infos.len() as _,
187                    signers_seeds.as_ptr() as *const u8,
188                    signers_seeds.len() as _,
189                );
190                if res == 0 {
191                    for (i, ai) in account_infos.iter().enumerate() {
192                        let new_data_slice = unsafe {
193                            std::slice::from_raw_parts_mut(
194                                (*ai.data.borrow_mut()).as_mut_ptr(),
195                                caccount_infos[i].data_len as _,
196                            )
197                        };
198                        *ai.data.borrow_mut() = new_data_slice;
199                        assert!(ai.lamports() == unsafe { *caccount_infos[i].lamports });
200                    }
201                    Ok(())
202                } else {
203                    Err(ProgramError::Custom(res as _))
204                }
205            }
206        }
207
208        #[no_mangle]
209        pub extern "C" fn set_stubs(stubs_api: SyscallStubsApi) {
210            let stubs = Box::new(SolAppSyscallStubs { stubs_api });
211            let _ = set_syscall_stubs(stubs);
212        }
213    };
214}