1use crate::account_view::AccountView;
7use crate::address::Address;
8use crate::error::ProgramError;
9use crate::raw_account::RuntimeAccount;
10use crate::{ProgramResult, NOT_BORROWED};
11use core::marker::PhantomData;
12
13#[repr(C)]
17#[derive(Debug, Clone)]
18pub struct InstructionAccount<'a> {
19 pub address: &'a Address,
21 pub is_writable: bool,
23 pub is_signer: bool,
25}
26
27impl<'a> InstructionAccount<'a> {
28 #[inline(always)]
30 pub const fn new(address: &'a Address, is_writable: bool, is_signer: bool) -> Self {
31 Self {
32 address,
33 is_writable,
34 is_signer,
35 }
36 }
37
38 #[inline(always)]
40 pub const fn readonly(address: &'a Address) -> Self {
41 Self {
42 address,
43 is_writable: false,
44 is_signer: false,
45 }
46 }
47
48 #[inline(always)]
50 pub const fn writable(address: &'a Address) -> Self {
51 Self {
52 address,
53 is_writable: true,
54 is_signer: false,
55 }
56 }
57
58 #[inline(always)]
60 pub const fn readonly_signer(address: &'a Address) -> Self {
61 Self {
62 address,
63 is_writable: false,
64 is_signer: true,
65 }
66 }
67
68 #[inline(always)]
70 pub const fn writable_signer(address: &'a Address) -> Self {
71 Self {
72 address,
73 is_writable: true,
74 is_signer: true,
75 }
76 }
77}
78
79impl<'a> From<&'a AccountView<'a>> for InstructionAccount<'a> {
80 #[inline(always)]
81 fn from(view: &'a AccountView<'a>) -> Self {
82 Self {
83 address: view.address(),
84 is_writable: view.is_writable(),
85 is_signer: view.is_signer(),
86 }
87 }
88}
89
90#[derive(Debug, Clone)]
94pub struct InstructionView<'a, 'b, 'c, 'd>
95where
96 'a: 'b,
97{
98 pub program_id: &'c Address,
100 pub data: &'d [u8],
102 pub accounts: &'b [InstructionAccount<'a>],
104}
105
106#[repr(C)]
112#[derive(Clone, Copy, Debug)]
113pub struct CpiAccount<'a> {
114 address: *const Address,
115 lamports: *const u64,
116 data_len: u64,
117 data: *const u8,
118 owner: *const Address,
119 rent_epoch: u64,
120 is_signer: bool,
121 is_writable: bool,
122 executable: bool,
123 _account_view: PhantomData<&'a AccountView<'a>>,
124}
125
126impl<'a> From<&'a AccountView<'a>> for CpiAccount<'a> {
127 #[inline(always)]
128 fn from(view: &'a AccountView<'a>) -> Self {
129 let raw = view.account_ptr();
130 let header = unsafe { core::ptr::read_unaligned(raw as *const u32) };
137 Self {
138 address: unsafe { &(*raw).address as *const Address },
139 lamports: unsafe { &(*raw).lamports as *const u64 },
141 data_len: view.data_len() as u64,
142 data: view.data_ptr_unchecked(),
143 owner: unsafe { &(*raw).owner as *const Address },
145 rent_epoch: 0,
146 is_signer: header & 0x0000_FF00 != 0,
147 is_writable: header & 0x00FF_0000 != 0,
148 executable: header & 0xFF00_0000 != 0,
149 _account_view: PhantomData,
150 }
151 }
152}
153
154impl<'a> CpiAccount<'a> {
155 #[inline(always)]
161 pub(crate) fn instruction_account(
162 &self,
163 is_writable: bool,
164 is_signer: bool,
165 ) -> InstructionAccount<'a> {
166 let address = unsafe { &*self.address };
169 InstructionAccount::new(address, is_writable, is_signer)
170 }
171}
172
173#[inline(always)]
181pub(crate) fn preflight_cpi_accounts(
182 accounts: &[CpiAccount<'_>],
183 writable_mask: usize,
184 signer_mask: usize,
185 has_pda_signers: bool,
186) -> ProgramResult {
187 let mut index = 0usize;
188 while index < accounts.len() {
189 let account = &accounts[index];
190 if signer_mask & (1usize << index) != 0 && !account.is_signer && !has_pda_signers {
195 return Err(ProgramError::MissingRequiredSignature);
196 }
197 let is_writable_meta = writable_mask & (1usize << index) != 0;
198 if is_writable_meta && !account.is_writable {
199 return Err(ProgramError::Immutable);
200 }
201
202 let raw = unsafe { account.data.sub(RuntimeAccount::SIZE) as *const RuntimeAccount };
206 let borrow_state = unsafe { (*raw).borrow_state };
209 let compatible = if is_writable_meta {
210 borrow_state == NOT_BORROWED
211 } else {
212 borrow_state != 0
213 };
214 if !compatible {
215 return Err(ProgramError::AccountBorrowFailed);
216 }
217
218 index += 1;
219 }
220 Ok(())
221}
222
223const _: () = {
227 assert!(core::mem::size_of::<InstructionAccount<'static>>() == 16);
228 assert!(core::mem::align_of::<InstructionAccount<'static>>() == 8);
229 assert!(core::mem::offset_of!(InstructionAccount<'static>, address) == 0);
230 assert!(core::mem::offset_of!(InstructionAccount<'static>, is_writable) == 8);
231 assert!(core::mem::offset_of!(InstructionAccount<'static>, is_signer) == 9);
232
233 assert!(core::mem::size_of::<CpiAccount<'static>>() == 56);
234 assert!(core::mem::align_of::<CpiAccount<'static>>() == 8);
235 assert!(core::mem::offset_of!(CpiAccount<'static>, address) == 0);
236 assert!(core::mem::offset_of!(CpiAccount<'static>, lamports) == 8);
237 assert!(core::mem::offset_of!(CpiAccount<'static>, data_len) == 16);
238 assert!(core::mem::offset_of!(CpiAccount<'static>, data) == 24);
239 assert!(core::mem::offset_of!(CpiAccount<'static>, owner) == 32);
240 assert!(core::mem::offset_of!(CpiAccount<'static>, rent_epoch) == 40);
241 assert!(core::mem::offset_of!(CpiAccount<'static>, is_signer) == 48);
242 assert!(core::mem::offset_of!(CpiAccount<'static>, is_writable) == 49);
243 assert!(core::mem::offset_of!(CpiAccount<'static>, executable) == 50);
244};
245
246#[repr(C)]
250#[derive(Debug, Clone)]
251pub struct Seed<'a> {
252 pub(crate) seed: *const u8,
253 pub(crate) len: u64,
254 _bytes: PhantomData<&'a [u8]>,
255}
256
257impl<'a> From<&'a [u8]> for Seed<'a> {
258 #[inline(always)]
259 fn from(bytes: &'a [u8]) -> Self {
260 Self {
261 seed: bytes.as_ptr(),
262 len: bytes.len() as u64,
263 _bytes: PhantomData,
264 }
265 }
266}
267
268impl<'a, const N: usize> From<&'a [u8; N]> for Seed<'a> {
269 #[inline(always)]
270 fn from(bytes: &'a [u8; N]) -> Self {
271 Self {
272 seed: bytes.as_ptr(),
273 len: N as u64,
274 _bytes: PhantomData,
275 }
276 }
277}
278
279impl core::ops::Deref for Seed<'_> {
280 type Target = [u8];
281
282 #[inline(always)]
283 fn deref(&self) -> &[u8] {
284 unsafe { core::slice::from_raw_parts(self.seed, self.len as usize) }
286 }
287}
288
289#[repr(C)]
293#[derive(Debug, Clone)]
294pub struct Signer<'a, 'b> {
295 pub(crate) seeds: *const Seed<'a>,
296 pub(crate) len: u64,
297 _seeds: PhantomData<&'b [Seed<'a>]>,
298}
299
300impl<'a, 'b> From<&'b [Seed<'a>]> for Signer<'a, 'b> {
301 #[inline(always)]
302 fn from(seeds: &'b [Seed<'a>]) -> Self {
303 Self {
304 seeds: seeds.as_ptr(),
305 len: seeds.len() as u64,
306 _seeds: PhantomData,
307 }
308 }
309}
310
311impl<'a, 'b, const N: usize> From<&'b [Seed<'a>; N]> for Signer<'a, 'b> {
312 #[inline(always)]
313 fn from(seeds: &'b [Seed<'a>; N]) -> Self {
314 Self {
315 seeds: seeds.as_ptr(),
316 len: N as u64,
317 _seeds: PhantomData,
318 }
319 }
320}
321
322#[macro_export]
326macro_rules! seeds {
327 ( $($seed:expr),* $(,)? ) => {
328 [$(
329 $crate::instruction::Seed::from($seed),
330 )*]
331 };
332}