1use crate::account_view::AccountView;
8use crate::address::Address;
9use crate::error::ProgramError;
10use crate::raw_account::RuntimeAccount;
11use crate::{ProgramResult, NOT_BORROWED};
12use core::marker::PhantomData;
13
14#[repr(C)]
18#[derive(Debug, Clone)]
19pub struct InstructionAccount<'a> {
20 pub address: &'a Address,
22 pub is_writable: bool,
24 pub is_signer: bool,
26}
27
28impl<'a> InstructionAccount<'a> {
29 #[inline(always)]
31 pub const fn new(address: &'a Address, is_writable: bool, is_signer: bool) -> Self {
32 Self {
33 address,
34 is_writable,
35 is_signer,
36 }
37 }
38
39 #[inline(always)]
41 pub const fn readonly(address: &'a Address) -> Self {
42 Self {
43 address,
44 is_writable: false,
45 is_signer: false,
46 }
47 }
48
49 #[inline(always)]
51 pub const fn writable(address: &'a Address) -> Self {
52 Self {
53 address,
54 is_writable: true,
55 is_signer: false,
56 }
57 }
58
59 #[inline(always)]
61 pub const fn readonly_signer(address: &'a Address) -> Self {
62 Self {
63 address,
64 is_writable: false,
65 is_signer: true,
66 }
67 }
68
69 #[inline(always)]
71 pub const fn writable_signer(address: &'a Address) -> Self {
72 Self {
73 address,
74 is_writable: true,
75 is_signer: true,
76 }
77 }
78}
79
80impl<'a> From<&'a AccountView<'a>> for InstructionAccount<'a> {
81 #[inline(always)]
82 fn from(view: &'a AccountView<'a>) -> Self {
83 Self {
84 address: view.address(),
85 is_writable: view.is_writable(),
86 is_signer: view.is_signer(),
87 }
88 }
89}
90
91#[derive(Debug, Clone)]
95pub struct InstructionView<'a, 'b, 'c, 'd>
96where
97 'a: 'b,
98{
99 pub program_id: &'c Address,
101 pub data: &'d [u8],
103 pub accounts: &'b [InstructionAccount<'a>],
105}
106
107#[repr(C)]
113#[derive(Clone, Copy, Debug)]
114pub struct CpiAccount<'a> {
115 address: *const Address,
116 lamports: *const u64,
117 data_len: u64,
118 data: *const u8,
119 owner: *const Address,
120 rent_epoch: u64,
121 is_signer: bool,
122 is_writable: bool,
123 executable: bool,
124 _account_view: PhantomData<&'a AccountView<'a>>,
125}
126
127const _: () = {
131 use core::mem::{offset_of, size_of};
132 let signer = offset_of!(CpiAccount<'static>, is_signer);
133 assert!(offset_of!(CpiAccount<'static>, is_writable) == signer + 1);
134 assert!(offset_of!(CpiAccount<'static>, executable) == signer + 2);
135 assert!(signer + 4 <= size_of::<CpiAccount<'static>>());
136};
137
138impl<'a> From<&'a AccountView<'a>> for CpiAccount<'a> {
139 #[inline(always)]
140 fn from(view: &'a AccountView<'a>) -> Self {
141 let raw = view.account_ptr();
142 let mut out = core::mem::MaybeUninit::<Self>::uninit();
143 let slot = out.as_mut_ptr();
144 unsafe {
157 core::ptr::addr_of_mut!((*slot).address).write(core::ptr::addr_of!((*raw).address));
158 core::ptr::addr_of_mut!((*slot).lamports).write(core::ptr::addr_of!((*raw).lamports));
159 core::ptr::addr_of_mut!((*slot).data_len).write(view.data_len() as u64);
160 core::ptr::addr_of_mut!((*slot).data).write(view.data_ptr_unchecked());
161 core::ptr::addr_of_mut!((*slot).owner).write(core::ptr::addr_of!((*raw).owner));
162 core::ptr::addr_of_mut!((*slot).rent_epoch).write(0);
163 let flags = core::ptr::read_unaligned((raw as *const u8).add(1) as *const u32);
164 (core::ptr::addr_of_mut!((*slot).is_signer) as *mut u32).write_unaligned(flags);
165 out.assume_init()
166 }
167 }
168}
169
170impl<'a> CpiAccount<'a> {
171 #[inline(always)]
177 pub(crate) fn instruction_account(
178 &self,
179 is_writable: bool,
180 is_signer: bool,
181 ) -> InstructionAccount<'a> {
182 let address = unsafe { &*self.address };
185 InstructionAccount::new(address, is_writable, is_signer)
186 }
187}
188
189#[inline(always)]
197pub(crate) fn preflight_cpi_accounts(
198 accounts: &[CpiAccount<'_>],
199 writable_mask: usize,
200 signer_mask: usize,
201 has_pda_signers: bool,
202) -> ProgramResult {
203 let mut index = 0usize;
204 while index < accounts.len() {
205 let account = &accounts[index];
206 if signer_mask & (1usize << index) != 0 && !account.is_signer && !has_pda_signers {
211 return Err(ProgramError::MissingRequiredSignature);
212 }
213 let is_writable_meta = writable_mask & (1usize << index) != 0;
214 if is_writable_meta && !account.is_writable {
215 return Err(ProgramError::Immutable);
216 }
217
218 let raw = unsafe { account.data.sub(RuntimeAccount::SIZE) as *const RuntimeAccount };
222 let borrow_state = unsafe { (*raw).borrow_state };
225 let compatible = if is_writable_meta {
226 borrow_state == NOT_BORROWED
227 } else {
228 borrow_state != 0
229 };
230 if !compatible {
231 return Err(ProgramError::AccountBorrowFailed);
232 }
233
234 index += 1;
235 }
236 Ok(())
237}
238
239const _: () = {
243 assert!(core::mem::size_of::<InstructionAccount<'static>>() == 16);
244 assert!(core::mem::align_of::<InstructionAccount<'static>>() == 8);
245 assert!(core::mem::offset_of!(InstructionAccount<'static>, address) == 0);
246 assert!(core::mem::offset_of!(InstructionAccount<'static>, is_writable) == 8);
247 assert!(core::mem::offset_of!(InstructionAccount<'static>, is_signer) == 9);
248
249 assert!(core::mem::size_of::<CpiAccount<'static>>() == 56);
250 assert!(core::mem::align_of::<CpiAccount<'static>>() == 8);
251 assert!(core::mem::offset_of!(CpiAccount<'static>, address) == 0);
252 assert!(core::mem::offset_of!(CpiAccount<'static>, lamports) == 8);
253 assert!(core::mem::offset_of!(CpiAccount<'static>, data_len) == 16);
254 assert!(core::mem::offset_of!(CpiAccount<'static>, data) == 24);
255 assert!(core::mem::offset_of!(CpiAccount<'static>, owner) == 32);
256 assert!(core::mem::offset_of!(CpiAccount<'static>, rent_epoch) == 40);
257 assert!(core::mem::offset_of!(CpiAccount<'static>, is_signer) == 48);
258 assert!(core::mem::offset_of!(CpiAccount<'static>, is_writable) == 49);
259 assert!(core::mem::offset_of!(CpiAccount<'static>, executable) == 50);
260};
261
262#[repr(C)]
266#[derive(Debug, Clone)]
267pub struct Seed<'a> {
268 pub(crate) seed: *const u8,
269 pub(crate) len: u64,
270 _bytes: PhantomData<&'a [u8]>,
271}
272
273impl<'a> From<&'a [u8]> for Seed<'a> {
274 #[inline(always)]
275 fn from(bytes: &'a [u8]) -> Self {
276 Self {
277 seed: bytes.as_ptr(),
278 len: bytes.len() as u64,
279 _bytes: PhantomData,
280 }
281 }
282}
283
284impl<'a, const N: usize> From<&'a [u8; N]> for Seed<'a> {
285 #[inline(always)]
286 fn from(bytes: &'a [u8; N]) -> Self {
287 Self {
288 seed: bytes.as_ptr(),
289 len: N as u64,
290 _bytes: PhantomData,
291 }
292 }
293}
294
295impl core::ops::Deref for Seed<'_> {
296 type Target = [u8];
297
298 #[inline(always)]
299 fn deref(&self) -> &[u8] {
300 unsafe { core::slice::from_raw_parts(self.seed, self.len as usize) }
303 }
304}
305
306#[repr(C)]
310#[derive(Debug, Clone)]
311pub struct Signer<'a, 'b> {
312 pub(crate) seeds: *const Seed<'a>,
313 pub(crate) len: u64,
314 _seeds: PhantomData<&'b [Seed<'a>]>,
315}
316
317impl<'a, 'b> From<&'b [Seed<'a>]> for Signer<'a, 'b> {
318 #[inline(always)]
319 fn from(seeds: &'b [Seed<'a>]) -> Self {
320 Self {
321 seeds: seeds.as_ptr(),
322 len: seeds.len() as u64,
323 _seeds: PhantomData,
324 }
325 }
326}
327
328impl<'a, 'b, const N: usize> From<&'b [Seed<'a>; N]> for Signer<'a, 'b> {
329 #[inline(always)]
330 fn from(seeds: &'b [Seed<'a>; N]) -> Self {
331 Self {
332 seeds: seeds.as_ptr(),
333 len: N as u64,
334 _seeds: PhantomData,
335 }
336 }
337}
338
339#[macro_export]
343macro_rules! seeds {
344 ( $($seed:expr),* $(,)? ) => {
345 [$(
346 $crate::instruction::Seed::from($seed),
347 )*]
348 };
349}