solana_cpi/lib.rs
1//! Cross-program invocation.
2//!
3//! Solana programs may call other programs, termed [_cross-program
4//! invocations_][cpi] (CPI), with the [`invoke`] and [`invoke_signed`]
5//! functions.
6//!
7//! This crate does not support overwriting syscall stubs for offchain code.
8//! If you want to overwrite syscall stubs, use the wrapper functions in
9//! [`solana_program::program`].
10//!
11//! [`invoke`]: invoke
12//! [`invoke_signed`]: invoke_signed
13//! [cpi]: https://solana.com/docs/core/cpi
14//! [`solana_program::program`]: https://docs.rs/solana-program/latest/solana_program/program/
15
16use {
17 solana_account_info::AccountInfo, solana_instruction::Instruction,
18 solana_program_error::ProgramResult, solana_pubkey::Pubkey,
19};
20#[cfg(target_os = "solana")]
21pub mod syscalls;
22
23/// Invoke a cross-program instruction.
24///
25/// Invoking one program from another program requires an [`Instruction`]
26/// containing the program ID of the other program, instruction data that
27/// will be understood by the other program, and a list of [`AccountInfo`]s
28/// corresponding to all of the accounts accessed by the other program. Because
29/// the only way for a program to acquire `AccountInfo` values is by receiving
30/// them from the runtime at the [program entrypoint][entrypoint!], any account
31/// required by the callee program must transitively be required by the caller
32/// program, and provided by _its_ caller. The same is true of the program ID of
33/// the called program.
34///
35/// [entrypoint!]: https://docs.rs/solana-entrypoint/latest/solana_entrypoint/macro.entrypoint.html
36///
37/// The `Instruction` is usually built from within the calling program, but may
38/// be deserialized from an external source.
39///
40/// This function will not return if the called program returns anything other
41/// than success. If the callee returns an error or aborts then the entire
42/// transaction will immediately fail. To return data as the result of a
43/// cross-program invocation use the [`set_return_data`] / [`get_return_data`]
44/// functions, or have the callee write to a dedicated account for that purpose.
45///
46/// A program may directly call itself recursively, but may not be indirectly
47/// called recursively (reentered) by another program. Indirect reentrancy will
48/// cause the transaction to immediately fail.
49///
50/// # Validation of shared data between programs
51///
52/// The `AccountInfo` structures passed to this function contain data that is
53/// directly accessed by the runtime and is copied to and from the memory space
54/// of the called program. Some of that data, the [`AccountInfo::lamports`] and
55/// [`AccountInfo::data`] fields, may be mutated as a side-effect of the called
56/// program, if that program has writable access to the given account.
57///
58/// These two fields are stored in [`RefCell`]s to enforce the aliasing
59/// discipline for mutated values required by the Rust language. Prior to
60/// invoking the runtime, this routine will test that each `RefCell` is
61/// borrowable as required by the callee and return an error if not.
62///
63/// The CPU cost of these runtime checks can be avoided with the unsafe
64/// [`invoke_unchecked`] function.
65///
66/// [`RefCell`]: std::cell::RefCell
67///
68/// # Errors
69///
70/// If the called program completes successfully and violates no runtime
71/// invariants, then this function will return successfully. If the callee
72/// completes and returns a [`ProgramError`], then the transaction will
73/// immediately fail. Control will not return to the caller.
74///
75/// Various runtime invariants are checked before the callee is invoked and
76/// before returning control to the caller. If any of these invariants are
77/// violated then the transaction will immediately fail. A non-exhaustive list
78/// of these invariants includes:
79///
80/// - The sum of lamports owned by all referenced accounts has not changed.
81/// - A program has not debited lamports from an account it does not own.
82/// - A program has not otherwise written to an account that it does not own.
83/// - A program has not written to an account that is not writable.
84/// - The size of account data has not exceeded applicable limits.
85///
86/// If the invoked program does not exist or is not executable then
87/// the transaction will immediately fail.
88///
89/// If any of the `RefCell`s within the provided `AccountInfo`s cannot be
90/// borrowed in accordance with the call's requirements, an error of
91/// [`ProgramError::AccountBorrowFailed`] is returned.
92///
93/// [`ProgramError`]: https://docs.rs/solana-program-error/latest/solana_program_error/enum.ProgramError.html
94/// [`ProgramError::AccountBorrowFailed`]: https://docs.rs/solana-program-error/latest/solana_program_error/enum.ProgramError.html#variant.AccountBorrowFailed
95///
96/// # Examples
97///
98/// A simple example of transferring lamports via CPI:
99///
100/// ```
101/// use solana_cpi::invoke;
102/// use solana_account_info::{next_account_info, AccountInfo};
103/// use solana_program_entrypoint::entrypoint;
104/// use solana_program_error::ProgramResult;
105/// use solana_pubkey::Pubkey;
106/// use solana_program::{
107/// system_instruction,
108/// system_program,
109/// };
110///
111/// entrypoint!(process_instruction);
112///
113/// fn process_instruction(
114/// program_id: &Pubkey,
115/// accounts: &[AccountInfo],
116/// instruction_data: &[u8],
117/// ) -> ProgramResult {
118/// let account_info_iter = &mut accounts.iter();
119///
120/// let payer = next_account_info(account_info_iter)?;
121/// let recipient = next_account_info(account_info_iter)?;
122/// // The system program is a required account to invoke a system
123/// // instruction, even though we don't use it directly.
124/// let system_program_account = next_account_info(account_info_iter)?;
125///
126/// assert!(payer.is_writable);
127/// assert!(payer.is_signer);
128/// assert!(recipient.is_writable);
129/// assert!(system_program::check_id(system_program_account.key));
130///
131/// let lamports = 1000000;
132///
133/// invoke(
134/// &system_instruction::transfer(payer.key, recipient.key, lamports),
135/// &[payer.clone(), recipient.clone(), system_program_account.clone()],
136/// )
137/// }
138/// ```
139pub fn invoke(instruction: &Instruction, account_infos: &[AccountInfo]) -> ProgramResult {
140 invoke_signed(instruction, account_infos, &[])
141}
142
143/// Invoke a cross-program instruction but don't enforce Rust's aliasing rules.
144///
145/// This function is like [`invoke`] except that it does not check that
146/// [`RefCell`]s within [`AccountInfo`]s are properly borrowable as described in
147/// the documentation for that function. Those checks consume CPU cycles that
148/// this function avoids.
149///
150/// [`RefCell`]: std::cell::RefCell
151///
152/// # Safety
153///
154/// __This function is incorrectly missing an `unsafe` declaration.__
155///
156/// If any of the writable accounts passed to the callee contain data that is
157/// borrowed within the calling program, and that data is written to by the
158/// callee, then Rust's aliasing rules will be violated and cause undefined
159/// behavior.
160pub fn invoke_unchecked(instruction: &Instruction, account_infos: &[AccountInfo]) -> ProgramResult {
161 invoke_signed_unchecked(instruction, account_infos, &[])
162}
163
164/// Invoke a cross-program instruction with program signatures.
165///
166/// This function is like [`invoke`] with the additional ability to virtually
167/// sign an invocation on behalf of one or more [program derived addresses][pda] (PDAs)
168/// controlled by the calling program, allowing the callee to mutate them, or
169/// otherwise confirm that a PDA program key has authorized the actions of the
170/// callee.
171///
172/// There is no cryptographic signing involved — PDA signing is a runtime
173/// construct that allows the calling program to control accounts as if it could
174/// cryptographically sign for them; and the callee to treat the account as if it
175/// was cryptographically signed.
176///
177/// The `signer_seeds` parameter is a slice of `u8` slices where the inner
178/// slices represent the seeds plus the _bump seed_ used to derive (with
179/// [`Pubkey::find_program_address`]) one of the PDAs within the `account_infos`
180/// slice of `AccountInfo`s. During invocation, the runtime will re-derive the
181/// PDA from the seeds and the calling program's ID, and if it matches one of
182/// the accounts in `account_info`, will consider that account "signed".
183///
184/// [pda]: https://solana.com/docs/core/cpi#program-derived-addresses
185/// [`Pubkey::find_program_address`]: https://docs.rs/solana-pubkey/latest/solana_pubkey/struct.Pubkey.html#method.find_program_address
186///
187/// See the documentation for [`Pubkey::find_program_address`] for more
188/// about program derived addresses.
189///
190/// # Examples
191///
192/// A simple example of creating an account for a PDA:
193///
194/// ```
195/// use solana_cpi::invoke_signed;
196/// use solana_account_info::{next_account_info, AccountInfo};
197/// use solana_program_entrypoint::entrypoint;
198/// use solana_program_error::ProgramResult;
199/// use solana_pubkey::Pubkey;
200/// use solana_program::{
201/// system_instruction,
202/// system_program,
203/// };
204///
205/// entrypoint!(process_instruction);
206///
207/// fn process_instruction(
208/// program_id: &Pubkey,
209/// accounts: &[AccountInfo],
210/// instruction_data: &[u8],
211/// ) -> ProgramResult {
212/// let account_info_iter = &mut accounts.iter();
213/// let payer = next_account_info(account_info_iter)?;
214/// let vault_pda = next_account_info(account_info_iter)?;
215/// let system_program = next_account_info(account_info_iter)?;
216///
217/// assert!(payer.is_writable);
218/// assert!(payer.is_signer);
219/// assert!(vault_pda.is_writable);
220/// assert_eq!(vault_pda.owner, &system_program::ID);
221/// assert!(system_program::check_id(system_program.key));
222///
223/// let vault_bump_seed = instruction_data[0];
224/// let vault_seeds = &[b"vault", payer.key.as_ref(), &[vault_bump_seed]];
225/// let expected_vault_pda = Pubkey::create_program_address(vault_seeds, program_id)?;
226///
227/// assert_eq!(vault_pda.key, &expected_vault_pda);
228///
229/// let lamports = 10000000;
230/// let vault_size = 16;
231///
232/// invoke_signed(
233/// &system_instruction::create_account(
234/// &payer.key,
235/// &vault_pda.key,
236/// lamports,
237/// vault_size,
238/// &program_id,
239/// ),
240/// &[
241/// payer.clone(),
242/// vault_pda.clone(),
243/// ],
244/// &[
245/// &[
246/// b"vault",
247/// payer.key.as_ref(),
248/// &[vault_bump_seed],
249/// ],
250/// ]
251/// )?;
252/// Ok(())
253/// }
254/// ```
255pub fn invoke_signed(
256 instruction: &Instruction,
257 account_infos: &[AccountInfo],
258 signers_seeds: &[&[&[u8]]],
259) -> ProgramResult {
260 // Check that the account RefCells are consistent with the request
261 for account_meta in instruction.accounts.iter() {
262 for account_info in account_infos.iter() {
263 if account_meta.pubkey == *account_info.key {
264 if account_meta.is_writable {
265 let _ = account_info.try_borrow_mut_lamports()?;
266 let _ = account_info.try_borrow_mut_data()?;
267 } else {
268 let _ = account_info.try_borrow_lamports()?;
269 let _ = account_info.try_borrow_data()?;
270 }
271 break;
272 }
273 }
274 }
275
276 invoke_signed_unchecked(instruction, account_infos, signers_seeds)
277}
278
279/// Copied from `solana_program::entrypoint::SUCCESS`
280/// to avoid a `solana_program` dependency
281const _SUCCESS: u64 = 0;
282#[cfg(test)]
283static_assertions::const_assert_eq!(_SUCCESS, solana_program_entrypoint::SUCCESS);
284
285/// Invoke a cross-program instruction with signatures but don't enforce Rust's
286/// aliasing rules.
287///
288/// This function is like [`invoke_signed`] except that it does not check that
289/// [`RefCell`]s within [`AccountInfo`]s are properly borrowable as described in
290/// the documentation for that function. Those checks consume CPU cycles that
291/// this function avoids.
292///
293/// [`RefCell`]: std::cell::RefCell
294///
295/// # Safety
296///
297/// __This function is incorrectly missing an `unsafe` declaration.__
298///
299/// If any of the writable accounts passed to the callee contain data that is
300/// borrowed within the calling program, and that data is written to by the
301/// callee, then Rust's aliasing rules will be violated and cause undefined
302/// behavior.
303#[allow(unused_variables)]
304pub fn invoke_signed_unchecked(
305 instruction: &Instruction,
306 account_infos: &[AccountInfo],
307 signers_seeds: &[&[&[u8]]],
308) -> ProgramResult {
309 #[cfg(target_os = "solana")]
310 {
311 let instruction =
312 solana_stable_layout::stable_instruction::StableInstruction::from(instruction.clone());
313 let result = unsafe {
314 crate::syscalls::sol_invoke_signed_rust(
315 &instruction as *const _ as *const u8,
316 account_infos as *const _ as *const u8,
317 account_infos.len() as u64,
318 signers_seeds as *const _ as *const u8,
319 signers_seeds.len() as u64,
320 )
321 };
322 match result {
323 _SUCCESS => Ok(()),
324 _ => Err(result.into()),
325 }
326 }
327
328 #[cfg(not(target_os = "solana"))]
329 Ok(())
330}
331
332/// Maximum size that can be set using [`set_return_data`].
333pub const MAX_RETURN_DATA: usize = 1024;
334
335/// Set the running program's return data.
336///
337/// Return data is a dedicated per-transaction buffer for data passed
338/// from cross-program invoked programs back to their caller.
339///
340/// The maximum size of return data is [`MAX_RETURN_DATA`]. Return data is
341/// retrieved by the caller with [`get_return_data`].
342#[allow(unused_variables)]
343pub fn set_return_data(data: &[u8]) {
344 #[cfg(target_os = "solana")]
345 unsafe {
346 crate::syscalls::sol_set_return_data(data.as_ptr(), data.len() as u64)
347 };
348}
349
350/// Get the return data from an invoked program.
351///
352/// For every transaction there is a single buffer with maximum length
353/// [`MAX_RETURN_DATA`], paired with a [`Pubkey`] representing the program ID of
354/// the program that most recently set the return data. Thus the return data is
355/// a global resource and care must be taken to ensure that it represents what
356/// is expected: called programs are free to set or not set the return data; and
357/// the return data may represent values set by programs multiple calls down the
358/// call stack, depending on the circumstances of transaction execution.
359///
360/// Return data is set by the callee with [`set_return_data`].
361///
362/// Return data is cleared before every CPI invocation — a program that
363/// has invoked no other programs can expect the return data to be `None`; if no
364/// return data was set by the previous CPI invocation, then this function
365/// returns `None`.
366///
367/// Return data is not cleared after returning from CPI invocations — a
368/// program that has called another program may retrieve return data that was
369/// not set by the called program, but instead set by a program further down the
370/// call stack; or, if a program calls itself recursively, it is possible that
371/// the return data was not set by the immediate call to that program, but by a
372/// subsequent recursive call to that program. Likewise, an external RPC caller
373/// may see return data that was not set by the program it is directly calling,
374/// but by a program that program called.
375///
376/// For more about return data see the [documentation for the return data proposal][rdp].
377///
378/// [rdp]: https://docs.solanalabs.com/proposals/return-data
379pub fn get_return_data() -> Option<(Pubkey, Vec<u8>)> {
380 #[cfg(target_os = "solana")]
381 {
382 use std::cmp::min;
383
384 let mut buf = [0u8; MAX_RETURN_DATA];
385 let mut program_id = Pubkey::default();
386
387 let size = unsafe {
388 crate::syscalls::sol_get_return_data(
389 buf.as_mut_ptr(),
390 buf.len() as u64,
391 &mut program_id,
392 )
393 };
394
395 if size == 0 {
396 None
397 } else {
398 let size = min(size as usize, MAX_RETURN_DATA);
399 Some((program_id, buf[..size as usize].to_vec()))
400 }
401 }
402
403 #[cfg(not(target_os = "solana"))]
404 None
405}