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