Skip to main content

solana_instruction_view/
cpi.rs

1//! Cross-program invocation helpers.
2
3#[cfg(feature = "slice-cpi")]
4extern crate alloc;
5
6#[cfg(feature = "slice-cpi")]
7use alloc::boxed::Box;
8#[cfg(any(target_os = "solana", target_arch = "bpf"))]
9pub use solana_define_syscall::{
10    define_syscall,
11    definitions::{sol_get_return_data, sol_invoke_signed_c, sol_set_return_data},
12};
13use {
14    crate::InstructionView,
15    core::{marker::PhantomData, mem::MaybeUninit, ops::Deref, slice::from_raw_parts},
16    solana_account_view::AccountView,
17    solana_address::Address,
18    solana_program_error::{ProgramError, ProgramResult},
19};
20
21/// Maximum number of accounts allowed in `invoke` and `invoke_with_bounds`
22/// functions.
23pub const MAX_STATIC_CPI_ACCOUNTS: usize = 64;
24
25/// Maximum number of accounts allowed in a cross-program invocation.
26//
27// Note: This value will increase to 255 when SIMD-0339 is activated.
28pub const MAX_CPI_ACCOUNTS: usize = 128;
29
30/// An account for CPI invocations.
31///
32/// This struct contains the same information as an [`AccountView`], but has
33/// the memory layout as expected by `sol_invoke_signed_c` syscall.
34#[repr(C)]
35#[derive(Clone, Copy, Debug)]
36pub struct CpiAccount<'a> {
37    /// Address of the account.
38    address: *const Address,
39
40    /// Number of lamports owned by this account.
41    lamports: *const u64,
42
43    /// Length of data in bytes.
44    data_len: u64,
45
46    /// On-chain data within this account.
47    data: *const u8,
48
49    /// Program that owns this account.
50    owner: *const Address,
51
52    /// The epoch at which this account will next owe rent.
53    rent_epoch: u64,
54
55    /// Transaction was signed by this account's key?
56    is_signer: bool,
57
58    /// Is the account writable?
59    is_writable: bool,
60
61    /// This account's data contains a loaded program (and is now read-only).
62    executable: bool,
63
64    /// The pointers to the `AccountView` data are only valid for as long as the
65    /// `&'a AccountView` lives. Instead of holding a reference to the actual `AccountView`,
66    /// which would increase the size of the type, we claim to hold a reference without
67    /// actually holding one using a `PhantomData<&'a AccountView>`.
68    _account_view: PhantomData<&'a AccountView>,
69}
70
71impl From<&AccountView> for CpiAccount<'_> {
72    fn from(account: &AccountView) -> Self {
73        Self {
74            address: account.address(),
75            // SAFETY:  Dereferencing `account.account_ptr()` to access its
76            // `lamports` field.
77            lamports: unsafe { &(*account.account_ptr()).lamports },
78            data_len: account.data_len() as u64,
79            data: account.data_ptr(),
80            owner: account.owner(),
81            // The `rent_epoch` field is not present in the `AccountView` struct,
82            // since the value occurs after the variable data of the account in
83            // the runtime input data.
84            rent_epoch: 0,
85            is_signer: account.is_signer(),
86            is_writable: account.is_writable(),
87            executable: account.executable(),
88            _account_view: PhantomData::<&AccountView>,
89        }
90    }
91}
92
93/// Represents a signer seed.
94///
95/// This struct contains the same information as a `[u8]`, but
96/// has the memory layout as expected by `sol_invoke_signed_c`
97/// syscall.
98#[repr(C)]
99#[derive(Debug, Clone)]
100pub struct Seed<'a> {
101    /// Seed bytes.
102    pub(crate) seed: *const u8,
103
104    /// Length of the seed bytes.
105    pub(crate) len: u64,
106
107    /// The pointer to the seed bytes is only valid while the `&'a [u8]` lives. Instead
108    /// of holding a reference to the actual `[u8]`, which would increase the size of the
109    /// type, we claim to hold a reference without actually holding one using a
110    /// `PhantomData<&'a [u8]>`.
111    _bytes: PhantomData<&'a [u8]>,
112}
113
114impl<'a> From<&'a [u8]> for Seed<'a> {
115    fn from(value: &'a [u8]) -> Self {
116        Self {
117            seed: value.as_ptr(),
118            len: value.len() as u64,
119            _bytes: PhantomData::<&[u8]>,
120        }
121    }
122}
123
124impl<'a, const SIZE: usize> From<&'a [u8; SIZE]> for Seed<'a> {
125    fn from(value: &'a [u8; SIZE]) -> Self {
126        Self {
127            seed: value.as_ptr(),
128            len: value.len() as u64,
129            _bytes: PhantomData::<&[u8]>,
130        }
131    }
132}
133
134impl Deref for Seed<'_> {
135    type Target = [u8];
136
137    fn deref(&self) -> &Self::Target {
138        unsafe { from_raw_parts(self.seed, self.len as usize) }
139    }
140}
141
142/// Represents a [program derived address][pda] (PDA) signer controlled by the
143/// calling program.
144///
145/// [pda]: https://solana.com/docs/core/cpi#program-derived-addresses
146#[repr(C)]
147#[derive(Debug, Clone)]
148pub struct Signer<'a, 'b> {
149    /// Signer seeds.
150    pub(crate) seeds: *const Seed<'a>,
151
152    /// Number of seeds.
153    pub(crate) len: u64,
154
155    /// The pointer to the seeds is only valid while the `&'b [Seed<'a>]` lives. Instead
156    /// of holding a reference to the actual `[Seed<'a>]`, which would increase the size
157    /// of the type, we claim to hold a reference without actually holding one using a
158    /// `PhantomData<&'b [Seed<'a>]>`.
159    _seeds: PhantomData<&'b [Seed<'a>]>,
160}
161
162impl<'a, 'b> From<&'b [Seed<'a>]> for Signer<'a, 'b> {
163    fn from(value: &'b [Seed<'a>]) -> Self {
164        Self {
165            seeds: value.as_ptr(),
166            len: value.len() as u64,
167            _seeds: PhantomData::<&'b [Seed<'a>]>,
168        }
169    }
170}
171
172impl<'a, 'b, const SIZE: usize> From<&'b [Seed<'a>; SIZE]> for Signer<'a, 'b> {
173    fn from(value: &'b [Seed<'a>; SIZE]) -> Self {
174        Self {
175            seeds: value.as_ptr(),
176            len: value.len() as u64,
177            _seeds: PhantomData::<&'b [Seed<'a>]>,
178        }
179    }
180}
181
182/// Convenience macro for constructing a `[Seed; N]` array from a list of seeds
183/// to create a [`Signer`].
184///
185/// # Example
186///
187/// Creating seeds array and signer for a PDA with a single seed and bump value:
188/// ```
189/// use solana_address::Address;
190/// use solana_instruction_view::{cpi::Signer, seeds};
191///
192/// let pda_bump = 0xffu8;
193/// let pda_ref = &[pda_bump];
194/// let example_key = Address::default();
195/// let seeds = seeds!(b"seed", example_key.as_ref(), pda_ref);
196/// let signer = Signer::from(&seeds);
197/// ```
198#[macro_export]
199macro_rules! seeds {
200    ( $($seed:expr),* ) => {
201        [$(
202            $crate::cpi::Seed::from($seed),
203        )*]
204    };
205}
206
207/// Invoke a cross-program instruction from an array of `AccountView`s.
208///
209/// This function is a convenience wrapper around the [`invoke_signed`] function
210/// with the signers' seeds set to an empty slice.
211///
212/// Note that this function is inlined to avoid the overhead of a function call,
213/// but uses stack memory allocation. When a large number of accounts is needed,
214/// it is recommended to use the [`invoke_with_slice`] function instead to reduce
215/// stack memory utilization.
216///
217/// # Important
218///
219/// The accounts on the `account_views` slice must be in the same order as the
220/// `accounts` field of the `instruction`. When the instruction has duplicated
221/// accounts, it is necessary to pass a duplicated reference to the same account
222/// to maintain the 1:1 relationship between accounts and instruction accounts.
223#[inline(always)]
224pub fn invoke<const ACCOUNTS: usize, A: AsRef<AccountView>>(
225    instruction: &InstructionView,
226    account_views: &[A; ACCOUNTS],
227) -> ProgramResult {
228    invoke_signed::<ACCOUNTS, A>(instruction, account_views, &[])
229}
230
231/// Invoke a cross-program instruction from a slice of `AccountView`s.
232///
233/// This function is a convenience wrapper around the [`invoke_signed_with_bounds`]
234/// function with the signers' seeds set to an empty slice.
235///
236/// The `MAX_ACCOUNTS` constant defines the maximum number of accounts expected
237/// to be passed to the cross-program invocation. This provides an upper bound to
238/// the number of accounts that need to be statically allocated for cases where the
239/// number of instruction accounts is not known at compile time. The final number of
240/// accounts passed to the cross-program invocation will be the number of accounts
241/// required by the `instruction`, even if `MAX_ACCOUNTS` is greater than that. When
242/// `MAX_ACCOUNTS` is lower than the number of accounts expected by the instruction,
243/// this function will return a [`ProgramError::InvalidArgument`] error.
244///
245/// Note that this function is inlined to avoid the overhead of a function call,
246/// but uses stack memory allocation. When a large number of accounts is needed,
247/// it is recommended to use the [`invoke_with_slice`] function instead to reduce
248/// stack memory utilization.
249///
250/// # Important
251///
252/// The accounts on the `account_views` slice must be in the same order as the
253/// `accounts` field of the `instruction`. When the instruction has duplicated
254/// accounts, it is necessary to pass a duplicated reference to the same account
255/// to maintain the 1:1 relationship between accounts and instruction accounts.
256#[inline(always)]
257pub fn invoke_with_bounds<const MAX_ACCOUNTS: usize, A: AsRef<AccountView>>(
258    instruction: &InstructionView,
259    account_views: &[A],
260) -> ProgramResult {
261    invoke_signed_with_bounds::<MAX_ACCOUNTS, A>(instruction, account_views, &[])
262}
263
264#[cfg(feature = "slice-cpi")]
265/// Invoke a cross-program instruction from a slice of `AccountView`s.
266///
267/// This function is a convenience wrapper around the [`invoke_signed_with_slice`]
268/// function with the signers' seeds set to an empty slice.
269///
270/// Note that this function will allocate heap memory to store up to
271/// `MAX_CPI_ACCOUNTS` accounts.
272///
273/// # Important
274///
275/// The accounts on the `account_views` slice must be in the same order as the
276/// `accounts` field of the `instruction`. When the instruction has duplicated
277/// accounts, it is necessary to pass a duplicated reference to the same account
278/// to maintain the 1:1 relationship between accounts and instruction accounts.
279#[inline(always)]
280pub fn invoke_with_slice<A: AsRef<AccountView>>(
281    instruction: &InstructionView,
282    account_views: &[A],
283) -> ProgramResult {
284    invoke_signed_with_slice(instruction, account_views, &[])
285}
286
287/// Invoke a cross-program instruction with signatures from an array of
288/// `AccountView`s.
289///
290/// This function performs validation of the `account_views` array to ensure that:
291///   1. It has at least as many accounts as the number of accounts expected by
292///      the instruction.
293///   2. The accounts match the expected accounts in the instruction, i.e., their
294///      `Address` matches the `address` in the `AccountView`.
295///   3. The borrow state of the accounts is compatible with the mutability of the
296///      instruction accounts.
297///
298/// This validation is done to ensure that the borrow checker rules are followed,
299/// consuming CUs in the process. The [`invoke_signed_unchecked`] is an alternative
300/// to this function that have lower CU consumption since it does not perform
301/// any validation. This should only be used when the caller is sure that the borrow
302/// checker rules are followed.
303///
304/// Note that this function is inlined to avoid the overhead of a function call,
305/// but uses stack memory allocation. When a large number of accounts is needed,
306/// it is recommended to use the [`invoke_signed_with_slice`] function instead
307/// to reduce stack memory utilization.
308///
309/// # Important
310///
311/// The accounts on the `account_views` array must be in the same order as the
312/// `accounts` field of the `instruction`. When the instruction has duplicated
313/// accounts, it is necessary to pass a duplicated reference to the same account
314/// to maintain the 1:1 relationship between accounts and instruction accounts.
315#[inline(always)]
316pub fn invoke_signed<const ACCOUNTS: usize, A: AsRef<AccountView>>(
317    instruction: &InstructionView,
318    account_views: &[A; ACCOUNTS],
319    signers_seeds: &[Signer],
320) -> ProgramResult {
321    // Check that the number of `ACCOUNTS` provided is not greater than
322    // the maximum number of accounts allowed.
323    const {
324        assert!(
325            ACCOUNTS <= MAX_STATIC_CPI_ACCOUNTS,
326            "ACCOUNTS is greater than allowed MAX_STATIC_CPI_ACCOUNTS"
327        );
328    }
329
330    let mut accounts = [const { MaybeUninit::<CpiAccount>::uninit() }; ACCOUNTS];
331
332    // SAFETY: The array of `AccountView`s will be checked to ensure that it has
333    // the same number of accounts as the instruction – this indirectly validates
334    // that the stack allocated account storage `ACCOUNTS` is sufficient for the
335    // number of accounts expected by the instruction.
336    unsafe {
337        inner_invoke_signed_with_slice::<A>(
338            instruction,
339            account_views.as_slice(),
340            accounts.as_mut_slice(),
341            signers_seeds,
342        )
343    }
344}
345
346/// Invoke a cross-program instruction with signatures from a slice of
347/// `AccountView`s.
348///
349/// This function performs validation of the `account_views` slice to ensure that:
350///   1. It has at least as many accounts as the number of accounts expected by
351///      the instruction.
352///   2. The accounts match the expected accounts in the instruction, i.e., their
353///      `Address` matches the `address` in the `AccountView`.
354///   3. The borrow state of the accounts is compatible with the mutability of the
355///      instruction accounts.
356///
357/// This validation is done to ensure that the borrow checker rules are followed,
358/// consuming CUs in the process. The [`invoke_signed_unchecked`] is an alternative
359/// to this function that has lower CU consumption since it does not perform
360/// any validation. This should only be used when the caller is sure that the borrow
361/// checker rules are followed.
362///
363/// The `MAX_ACCOUNTS` constant defines the maximum number of accounts expected
364/// to be passed to the cross-program invocation. This provides an upper bound to
365/// the number of accounts that need to be statically allocated for cases where the
366/// number of instruction accounts is not known at compile time. The final number of
367/// accounts passed to the cross-program invocation will be the number of accounts
368/// required by the `instruction`, even if `MAX_ACCOUNTS` is greater than that. When
369/// `MAX_ACCOUNTS` is lower than the number of accounts expected by the instruction,
370/// this function will return a [`ProgramError::InvalidArgument`] error.
371///
372/// Note that this function is inlined to avoid the overhead of a function call,
373/// but uses stack memory allocation. When a large number of accounts is needed,
374/// it is recommended to use the [`invoke_signed_with_slice`] function instead to reduce
375/// stack memory utilization.
376///
377/// # Important
378///
379/// The accounts on the `account_views` slice must be in the same order as the
380/// `accounts` field of the `instruction`. When the instruction has duplicated
381/// accounts, it is necessary to pass a duplicated reference to the same account
382/// to maintain the 1:1 relationship between accounts and instruction accounts.
383#[inline(always)]
384pub fn invoke_signed_with_bounds<const MAX_ACCOUNTS: usize, A: AsRef<AccountView>>(
385    instruction: &InstructionView,
386    account_views: &[A],
387    signers_seeds: &[Signer],
388) -> ProgramResult {
389    // Check that the number of `MAX_ACCOUNTS` provided is not greater than
390    // the maximum number of static accounts allowed.
391    const {
392        assert!(
393            MAX_ACCOUNTS <= MAX_STATIC_CPI_ACCOUNTS,
394            "MAX_ACCOUNTS is greater than allowed MAX_STATIC_CPI_ACCOUNTS"
395        );
396    }
397
398    // Check that the stack allocated account storage `MAX_ACCOUNTS` is sufficient
399    // for the number of accounts expected by the instruction.
400    if MAX_ACCOUNTS < instruction.accounts.len() {
401        return Err(ProgramError::InvalidArgument);
402    }
403
404    let mut accounts = [const { MaybeUninit::<CpiAccount>::uninit() }; MAX_ACCOUNTS];
405
406    // SAFETY: The stack allocated account storage `MAX_ACCOUNTS` was validated
407    // to be sufficient for the number of accounts expected by the instruction.
408    unsafe {
409        inner_invoke_signed_with_slice::<A>(
410            instruction,
411            account_views,
412            accounts.as_mut_slice(),
413            signers_seeds,
414        )
415    }
416}
417
418#[cfg(feature = "slice-cpi")]
419/// Invoke a cross-program instruction with signatures from a slice of
420/// `AccountView`s.
421///
422/// This function performs validation of the `account_views` slice to ensure that:
423///   1. It has at least as many accounts as the number of accounts expected by
424///      the instruction.
425///   2. The accounts match the expected accounts in the instruction, i.e., their
426///      `Address` matches the `address` in the `AccountView`.
427///   3. The borrow state of the accounts is compatible with the mutability of the
428///      instruction accounts.
429///
430/// This validation is done to ensure that the borrow checker rules are followed,
431/// consuming CUs in the process. The [`invoke_signed_unchecked`] is an alternative
432/// to this function that have lower CU consumption since it does not perform
433/// any validation. This should only be used when the caller is sure that the borrow
434/// checker rules are followed.
435///
436/// Note that this function will allocate heap memory to store up to
437/// `MAX_CPI_ACCOUNTS` accounts.
438///
439/// # Important
440///
441/// The accounts on the `account_views` slice must be in the same order as the
442/// `accounts` field of the `instruction`. When the instruction has duplicated
443/// accounts, it is necessary to pass a duplicated reference to the same account
444/// to maintain the 1:1 relationship between accounts and instruction accounts.
445#[inline(always)]
446pub fn invoke_signed_with_slice<A: AsRef<AccountView>>(
447    instruction: &InstructionView,
448    account_views: &[A],
449    signers_seeds: &[Signer],
450) -> ProgramResult {
451    // Check that the number of instruction accounts does not exceed
452    // the maximum allowed number of CPI accounts.
453    if MAX_CPI_ACCOUNTS < instruction.accounts.len() {
454        return Err(ProgramError::InvalidArgument);
455    }
456
457    let mut accounts = Box::<[CpiAccount]>::new_uninit_slice(instruction.accounts.len());
458
459    // SAFETY: The allocated `accounts` slice has the same size as the expected number
460    // of instruction accounts.
461    unsafe {
462        inner_invoke_signed_with_slice::<A>(
463            instruction,
464            account_views,
465            &mut accounts,
466            signers_seeds,
467        )
468    }
469}
470
471/// Internal function to invoke a cross-program instruction with signatures
472/// from a slice of `AccountView`s performing borrow checking.
473///
474/// This function performs validation of the `account_views` slice to ensure that:
475///   1. It has at least as many accounts as the number of accounts expected by
476///      the instruction.
477///   2. The accounts match the expected accounts in the instruction, i.e., their
478///      `Address` matches the `address` in the `AccountView`.
479///   3. The borrow state of the accounts is compatible with the mutability of the
480///      instruction accounts.
481///
482/// # Safety
483///
484/// This function is unsafe because it does not check that `accounts` is sufficiently
485/// large for the number of accounts expected by the instruction. Using an `accounts` slice
486/// shorter than the number of accounts expected by the instruction will result in
487/// undefined behavior.
488#[inline(always)]
489unsafe fn inner_invoke_signed_with_slice<A: AsRef<AccountView>>(
490    instruction: &InstructionView,
491    account_views: &[A],
492    accounts: &mut [MaybeUninit<CpiAccount>],
493    signers_seeds: &[Signer],
494) -> ProgramResult {
495    // Check that the number of accounts provided is not less than
496    // the number of accounts expected by the instruction.
497    if account_views.len() < instruction.accounts.len() {
498        return Err(ProgramError::NotEnoughAccountKeys);
499    }
500
501    account_views
502        .iter()
503        .zip(instruction.accounts.iter())
504        .zip(accounts.iter_mut())
505        .try_for_each(|((account_view, instruction_account), account)| {
506            // In order to check whether the borrow state is compatible
507            // with the invocation, we need to check that we have the
508            // correct account view and instruction account pair.
509            if account_view.as_ref().address() != instruction_account.address {
510                return Err(ProgramError::InvalidArgument);
511            }
512
513            // Determines the borrow state that would be invalid according
514            // to their mutability on the instruction.
515            let borrowed = if instruction_account.is_writable {
516                // If the account is required to be writable, it cannot
517                //  be currently borrowed.
518                account_view.as_ref().is_borrowed()
519            } else {
520                // If the account is required to be read-only, it cannot
521                // be currently mutably borrowed.
522                account_view.as_ref().is_borrowed_mut()
523            };
524
525            if borrowed {
526                return Err(ProgramError::AccountBorrowFailed);
527            }
528
529            account.write(CpiAccount::from(account_view.as_ref()));
530
531            Ok(())
532        })?;
533
534    // SAFETY: At this point it is guaranteed that instruction accounts are
535    // borrowable according to their mutability on the instruction.
536    unsafe {
537        invoke_signed_unchecked(
538            instruction,
539            from_raw_parts(accounts.as_ptr() as _, instruction.accounts.len()),
540            signers_seeds,
541        );
542    }
543
544    Ok(())
545}
546
547/// Invoke a cross-program instruction but don't enforce Rust's aliasing rules.
548///
549/// This function does not check that [`CpiAccount`]s are properly borrowable.
550/// Those checks consume CUs that this function avoids.
551///
552/// Note that the maximum number of accounts that can be passed to a cross-program
553/// invocation is defined by the `MAX_CPI_ACCOUNTS` constant. Even if the `[CpiAccount]`
554/// slice has more accounts, only the number of accounts required by the `instruction`
555/// will be used.
556///
557/// # Safety
558///
559/// If any of the writable accounts passed to the callee contain data that is
560/// borrowed within the calling program, and that data is written to by the
561/// callee, then Rust's aliasing rules will be violated and cause undefined
562/// behavior.
563#[inline(always)]
564pub unsafe fn invoke_unchecked(instruction: &InstructionView, accounts: &[CpiAccount]) {
565    invoke_signed_unchecked(instruction, accounts, &[])
566}
567
568/// Invoke a cross-program instruction with signatures but don't enforce Rust's
569/// aliasing rules.
570///
571/// This function does not check that [`CpiAccount`]s are properly borrowable.
572/// Those checks consume CUs that this function avoids.
573///
574/// Note that the maximum number of accounts that can be passed to a cross-program
575/// invocation is defined by the `MAX_CPI_ACCOUNTS` constant. Even if the `[CpiAccount]`
576/// slice has more accounts, only the number of accounts required by the `instruction`
577/// will be used.
578///
579/// # Safety
580///
581/// If any of the writable accounts passed to the callee contain data that is
582/// borrowed within the calling program, and that data is written to by the
583/// callee, then Rust's aliasing rules will be violated and cause undefined
584/// behavior.
585#[inline(always)]
586pub unsafe fn invoke_signed_unchecked(
587    instruction: &InstructionView,
588    accounts: &[CpiAccount],
589    signers_seeds: &[Signer],
590) {
591    #[cfg(any(target_os = "solana", target_arch = "bpf"))]
592    {
593        use crate::InstructionAccount;
594
595        /// An `Instruction` as expected by `sol_invoke_signed_c`.
596        ///
597        /// DO NOT EXPOSE THIS STRUCT:
598        ///
599        /// To ensure pointers are valid upon use, the scope of this struct should
600        /// only be limited to the stack where `sol_invoke_signed_c` happens and then
601        /// discarded immediately after.
602        #[repr(C)]
603        struct CInstruction<'a> {
604            /// Public key of the program.
605            program_id: *const Address,
606
607            /// Accounts expected by the program instruction.
608            accounts: *const InstructionAccount<'a>,
609
610            /// Number of accounts expected by the program instruction.
611            accounts_len: u64,
612
613            /// Data expected by the program instruction.
614            data: *const u8,
615
616            /// Length of the data expected by the program instruction.
617            data_len: u64,
618        }
619
620        let cpi_instruction = CInstruction {
621            program_id: instruction.program_id,
622            accounts: instruction.accounts.as_ptr(),
623            accounts_len: instruction.accounts.len() as u64,
624            data: instruction.data.as_ptr(),
625            data_len: instruction.data.len() as u64,
626        };
627
628        unsafe {
629            sol_invoke_signed_c(
630                &cpi_instruction as *const _ as *const u8,
631                accounts as *const _ as *const u8,
632                accounts.len() as u64,
633                signers_seeds as *const _ as *const u8,
634                signers_seeds.len() as u64,
635            )
636        };
637    }
638
639    #[cfg(not(any(target_os = "solana", target_arch = "bpf")))]
640    core::hint::black_box((instruction, accounts, signers_seeds));
641}
642
643/// Maximum size that can be set using [`set_return_data`].
644pub const MAX_RETURN_DATA: usize = 1024;
645
646/// Set the running program's return data.
647///
648/// Return data is a dedicated per-transaction buffer for data passed
649/// from cross-program invoked programs back to their caller.
650///
651/// The maximum size of return data is [`MAX_RETURN_DATA`]. Return data is
652/// retrieved by the caller with [`get_return_data`].
653#[inline(always)]
654pub fn set_return_data(data: &[u8]) {
655    #[cfg(any(target_os = "solana", target_arch = "bpf"))]
656    unsafe {
657        sol_set_return_data(data.as_ptr(), data.len() as u64)
658    };
659
660    #[cfg(not(any(target_os = "solana", target_arch = "bpf")))]
661    core::hint::black_box(data);
662}
663
664/// Get the return data from an invoked program.
665///
666/// For every transaction there is a single buffer with maximum length
667/// [`MAX_RETURN_DATA`], paired with an [`Address`] representing the program ID of
668/// the program that most recently set the return data. Thus the return data is
669/// a global resource and care must be taken to ensure that it represents what
670/// is expected: called programs are free to set or not set the return data; and
671/// the return data may represent values set by programs multiple calls down the
672/// call stack, depending on the circumstances of transaction execution.
673///
674/// Return data is set by the callee with [`set_return_data`].
675///
676/// Return data is cleared before every CPI invocation - a program that
677/// has invoked no other programs can expect the return data to be `None`; if no
678/// return data was set by the previous CPI invocation, then this function
679/// returns `None`.
680///
681/// Return data is not cleared after returning from CPI invocations. A
682/// program that has called another program may retrieve return data that was
683/// not set by the called program, but instead set by a program further down the
684/// call stack; or, if a program calls itself recursively, it is possible that
685/// the return data was not set by the immediate call to that program, but by a
686/// subsequent recursive call to that program. Likewise, an external RPC caller
687/// may see return data that was not set by the program it is directly calling,
688/// but by a program that program called.
689///
690/// For more about return data see the [documentation for the return data proposal][rdp].
691///
692/// [rdp]: https://docs.solanalabs.com/proposals/return-data
693#[inline]
694pub fn get_return_data() -> Option<ReturnData> {
695    #[cfg(any(target_os = "solana", target_arch = "bpf"))]
696    {
697        const UNINIT_BYTE: MaybeUninit<u8> = MaybeUninit::<u8>::uninit();
698        let mut data = [UNINIT_BYTE; MAX_RETURN_DATA];
699        let mut program_id = MaybeUninit::<Address>::uninit();
700
701        let size = unsafe {
702            sol_get_return_data(
703                data.as_mut_ptr() as *mut u8,
704                data.len() as u64,
705                program_id.as_mut_ptr() as *mut _ as *mut u8,
706            )
707        };
708
709        if size == 0 {
710            None
711        } else {
712            Some(ReturnData {
713                program_id: unsafe { program_id.assume_init() },
714                data,
715                size: core::cmp::min(size as usize, MAX_RETURN_DATA),
716            })
717        }
718    }
719
720    #[cfg(not(any(target_os = "solana", target_arch = "bpf")))]
721    core::hint::black_box(None)
722}
723
724/// Struct to hold the return data from an invoked program.
725#[derive(Debug)]
726pub struct ReturnData {
727    /// Program that most recently set the return data.
728    program_id: Address,
729
730    /// Return data set by the program.
731    data: [MaybeUninit<u8>; MAX_RETURN_DATA],
732
733    /// Length of the return data.
734    size: usize,
735}
736
737impl ReturnData {
738    /// Returns the program that most recently set the return data.
739    pub fn program_id(&self) -> &Address {
740        &self.program_id
741    }
742
743    /// Return the data set by the program.
744    pub fn as_slice(&self) -> &[u8] {
745        unsafe { from_raw_parts(self.data.as_ptr() as _, self.size) }
746    }
747}