uip_solana_sdk/
extension.rs1use solana_program::{clock::Epoch, instruction::AccountMeta, pubkey::Pubkey};
4
5use super::{deser::DeserializeRef, utils::split_at_checked, MessageDataRef};
6
7impl MessageDataRef<'_> {
8 pub unsafe fn load(msg_data_ptr: *const u8, msg_data_len: usize) -> Self {
16 let mut slice = core::slice::from_raw_parts(msg_data_ptr, msg_data_len);
17 MessageDataRef::deserialize_ref(&mut slice).unwrap()
18 }
19}
20
21#[repr(C)]
24pub struct InstructionInfo {
25 pub compute_units: u32,
26 pub heap_frame: u32,
27 pub accounts_len: u32,
28 pub accounts: [AccountMeta; 57],
29}
30
31impl InstructionInfo {
32 pub fn push_account(&mut self, account_meta: AccountMeta) -> Result<(), AccountMeta> {
36 if self.accounts_len as usize >= self.accounts.len() {
37 return Err(account_meta);
38 }
39
40 self.accounts[self.accounts_len as usize] = account_meta;
41 self.accounts_len += 1;
42
43 Ok(())
44 }
45}
46
47#[link(wasm_import_module = "solana_transmitter")]
48extern "C" {
49 fn get_multiple_accounts(keys_ptr: *const Pubkey, keys_len: u32, out_ptr: *mut u8) -> i32;
50}
51
52pub struct HostCallContext {
55 params_ptr: *mut u8,
56 result_ptr: *mut u8,
57}
58
59impl HostCallContext {
60 #[allow(clippy::not_unsafe_ptr_arg_deref)]
63 pub fn new(msg_data_ptr: *const u8, msg_data_len: usize) -> Self {
64 const MAX_RESULT_LEN: usize = core::mem::size_of::<InstructionInfo>();
65 const MAX_PARAMS_LEN: usize = 4 + 32 * 100;
66
67 let offset = msg_data_len + MAX_RESULT_LEN;
68 let offset = offset as isize as usize;
70
71 unsafe {
73 let params_ptr = msg_data_ptr.add(offset).cast_mut();
74 Self {
75 params_ptr,
76 result_ptr: params_ptr.add(MAX_PARAMS_LEN),
77 }
78 }
79 }
80
81 pub unsafe fn get_multiple_accounts<'a>(
98 &mut self,
99 keys: &[Pubkey],
100 ) -> heapless::Vec<Option<AccountRef<'a>>, 100>
101 where
102 Self: 'a,
103 {
104 let params_slice = core::slice::from_raw_parts_mut(self.params_ptr.cast(), keys.len());
105 params_slice.copy_from_slice(keys);
106
107 assert!(
108 get_multiple_accounts(self.params_ptr.cast(), keys.len() as u32, self.result_ptr) == 0
109 );
110
111 let mut result_slice = core::slice::from_raw_parts(self.result_ptr, 1 << (isize::BITS - 1));
112 let mut res = heapless::Vec::new();
113 for _ in 0..keys.len() {
114 let option_tag = result_slice[0];
115 result_slice = &result_slice[1..];
116 if option_tag == 0 {
117 res.push(None).unwrap();
118 } else {
119 res.push(Some(AccountRef::deserialize_ref(&mut result_slice).unwrap())).unwrap();
120 }
121 }
122 self.result_ptr = result_slice.as_ptr().cast_mut();
123 res
124 }
125}
126
127#[derive(Debug)]
129pub struct AccountRef<'a> {
130 pub lamports: u64,
131 pub data: &'a [u8],
132 pub owner: Pubkey,
133 pub executable: bool,
134 pub rent_epoch: Epoch,
135}
136
137impl<'a> DeserializeRef<'a> for AccountRef<'a> {
138 fn deserialize_ref(slice: &mut &'a [u8]) -> Option<Self> {
139 let mut read_data = |count| {
140 let (src, rest) = split_at_checked(slice, count)?;
141 *slice = rest;
142 Some(src)
143 };
144
145 let lamports = u64::from_le_bytes(read_data(8)?.try_into().unwrap());
146
147 let data_len = u32::from_le_bytes(read_data(4)?.try_into().unwrap()) as usize;
148 let data = read_data(data_len)?;
149
150 let owner = Pubkey::new_from_array(read_data(32)?.try_into().unwrap());
151
152 let executable = read_data(1)?[0] != 0;
153
154 let rent_epoch = u64::from_le_bytes(read_data(8)?.try_into().unwrap());
155
156 Some(Self {
157 lamports,
158 data,
159 owner,
160 executable,
161 rent_epoch,
162 })
163 }
164}