solana_program/program.rs
1//! Cross-program invocation.
2//!
3//! Safecoin programs may call other programs, termed [_cross-program
4//! invocations_][cpi] (CPI), with the [`invoke`] and [`invoke_signed`]
5//! functions.
6//!
7//! [`invoke`]: invoke
8//! [`invoke_signed`]: invoke_signed
9//! [cpi]: https://docs.solana.com/developing/programming-model/calling-between-programs
10
11use crate::{
12 account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction, pubkey::Pubkey,
13};
14
15/// Invoke a cross-program instruction.
16///
17/// Invoking one program from another program requires an [`Instruction`]
18/// containing the program ID of the other program, instruction data that
19/// will be understood by the other program, and a list of [`AccountInfo`]s
20/// corresponding to all of the accounts accessed by the other program. Because
21/// the only way for a program to acquire `AccountInfo` values is by receiving
22/// them from the runtime at the [program entrypoint][entrypoint!], any account
23/// required by the callee program must transitively be required by the caller
24/// program, and provided by _its_ caller. The same is true of the program ID of
25/// the called program.
26///
27/// The `Instruction` is usually built from within the calling program, but may
28/// be deserialized from an external source.
29///
30/// This function will not return if the called program returns anything other
31/// than success. If the callee returns an error or aborts then the entire
32/// transaction will immediately fail. To return data as the result of a
33/// cross-program invocation use the [`set_return_data`] / [`get_return_data`]
34/// functions, or have the callee write to a dedicated account for that purpose.
35///
36/// A program may directly call itself recursively, but may not be indirectly
37/// called recursively (reentered) by another program. Indirect reentrancy will
38/// cause the transaction to immediately fail.
39///
40/// # Validation of shared data between programs
41///
42/// The `AccountInfo` structures passed to this function contain data that is
43/// directly accessed by the runtime and is copied to and from the memory space
44/// of the called program. Some of that data, the [`AccountInfo::lamports`] and
45/// [`AccountInfo::data`] fields, may be mutated as a side-effect of the called
46/// program, if that program has writable access to the given account.
47///
48/// These two fields are stored in [`RefCell`]s to enforce the aliasing
49/// discipline for mutated values required by the Rust language. Prior to
50/// invoking the runtime, this routine will test that each `RefCell` is
51/// borrowable as required by the callee and return an error if not.
52///
53/// The CPU cost of these runtime checks can be avoided with the unsafe
54/// [`invoke_unchecked`] function.
55///
56/// [`RefCell`]: std::cell::RefCell
57///
58/// # Errors
59///
60/// If the called program completes successfully and violates no runtime
61/// invariants, then this function will return successfully. If the callee
62/// completes and returns a [`ProgramError`], then the transaction will
63/// immediately fail. Control will not return to the caller.
64///
65/// Various runtime invariants are checked before the callee is invoked and
66/// before returning control to the caller. If any of these invariants are
67/// violated then the transaction will immediately fail. A non-exhaustive list
68/// of these invariants includes:
69///
70/// - The sum of lamports owned by all referenced accounts has not changed.
71/// - A program has not debited lamports from an account it does not own.
72/// - A program has not otherwise written to an account that it does not own.
73/// - A program has not written to an account that is not writable.
74/// - The size of account data has not exceeded applicable limits.
75///
76/// If the invoked program does not exist or is not executable then
77/// the transaction will immediately fail.
78///
79/// If any of the `RefCell`s within the provided `AccountInfo`s cannot be
80/// borrowed in accordance with the call's requirements, an error of
81/// [`ProgramError::AccountBorrowFailed`] is returned.
82///
83/// [`ProgramError`]: crate::program_error::ProgramError
84/// [`ProgramError::AccountBorrowFailed`]: crate::program_error::ProgramError::AccountBorrowFailed
85///
86/// # Examples
87///
88/// A simple example of transferring lamports via CPI:
89///
90/// ```
91/// use solana_program::{
92/// account_info::{next_account_info, AccountInfo},
93/// entrypoint,
94/// entrypoint::ProgramResult,
95/// program::invoke,
96/// pubkey::Pubkey,
97/// system_instruction,
98/// system_program,
99/// };
100///
101/// entrypoint!(process_instruction);
102///
103/// fn process_instruction(
104/// program_id: &Pubkey,
105/// accounts: &[AccountInfo],
106/// instruction_data: &[u8],
107/// ) -> ProgramResult {
108/// let account_info_iter = &mut accounts.iter();
109///
110/// let payer = next_account_info(account_info_iter)?;
111/// let recipient = next_account_info(account_info_iter)?;
112/// // The system program is a required account to invoke a system
113/// // instruction, even though we don't use it directly.
114/// let system_program_account = next_account_info(account_info_iter)?;
115///
116/// assert!(payer.is_writable);
117/// assert!(payer.is_signer);
118/// assert!(recipient.is_writable);
119/// assert!(system_program::check_id(system_program_account.key));
120///
121/// let lamports = 1000000;
122///
123/// invoke(
124/// &system_instruction::transfer(payer.key, recipient.key, lamports),
125/// &[payer.clone(), recipient.clone(), system_program_account.clone()],
126/// )
127/// }
128/// ```
129pub fn invoke(instruction: &Instruction, account_infos: &[AccountInfo]) -> ProgramResult {
130 invoke_signed(instruction, account_infos, &[])
131}
132
133/// Invoke a cross-program instruction but don't enforce Rust's aliasing rules.
134///
135/// This function is like [`invoke`] except that it does not check that
136/// [`RefCell`]s within [`AccountInfo`]s are properly borrowable as described in
137/// the documentation for that function. Those checks consume CPU cycles that
138/// this function avoids.
139///
140/// [`RefCell`]: std::cell::RefCell
141///
142/// # Safety
143///
144/// __This function is incorrectly missing an `unsafe` declaration.__
145///
146/// If any of the writable accounts passed to the callee contain data that is
147/// borrowed within the calling program, and that data is written to by the
148/// callee, then Rust's aliasing rules will be violated and cause undefined
149/// behavior.
150pub fn invoke_unchecked(instruction: &Instruction, account_infos: &[AccountInfo]) -> ProgramResult {
151 invoke_signed_unchecked(instruction, account_infos, &[])
152}
153
154/// Invoke a cross-program instruction with program signatures.
155///
156/// This function is like [`invoke`] with the additional ability to virtually
157/// sign an invocation on behalf of one or more [program derived addresses][pda] (PDAs)
158/// controlled by the calling program, allowing the callee to mutate them, or
159/// otherwise confirm that a PDA program key has authorized the actions of the
160/// callee.
161///
162/// There is no cryptographic signing involved — PDA signing is a runtime
163/// construct that allows the calling program to control accounts as if it could
164/// cryptographically sign for them; and the callee to treat the account as if it
165/// was cryptographically signed.
166///
167/// The `signer_seeds` parameter is a slice of `u8` slices where the inner
168/// slices represent the seeds plus the _bump seed_ used to derive (with
169/// [`Pubkey::find_program_address`]) one of the PDAs within the `account_infos`
170/// slice of `AccountInfo`s. During invocation, the runtime will re-derive the
171/// PDA from the seeds and the calling program's ID, and if it matches one of
172/// the accounts in `account_info`, will consider that account "signed".
173///
174/// [pda]: https://docs.solana.com/developing/programming-model/calling-between-programs#program-derived-addresses
175///
176/// See the documentation for [`Pubkey::find_program_address`] for more
177/// about program derived addresses.
178///
179/// # Examples
180///
181/// A simple example of creating an account for a PDA:
182///
183/// ```
184/// use solana_program::{
185/// account_info::{next_account_info, AccountInfo},
186/// entrypoint,
187/// entrypoint::ProgramResult,
188/// program::invoke_signed,
189/// pubkey::Pubkey,
190/// system_instruction,
191/// system_program,
192/// };
193///
194/// entrypoint!(process_instruction);
195///
196/// fn process_instruction(
197/// program_id: &Pubkey,
198/// accounts: &[AccountInfo],
199/// instruction_data: &[u8],
200/// ) -> ProgramResult {
201/// let account_info_iter = &mut accounts.iter();
202/// let payer = next_account_info(account_info_iter)?;
203/// let vault_pda = next_account_info(account_info_iter)?;
204/// let system_program = next_account_info(account_info_iter)?;
205///
206/// assert!(payer.is_writable);
207/// assert!(payer.is_signer);
208/// assert!(vault_pda.is_writable);
209/// assert_eq!(vault_pda.owner, &system_program::ID);
210/// assert!(system_program::check_id(system_program.key));
211///
212/// let vault_bump_seed = instruction_data[0];
213/// let vault_seeds = &[b"vault", payer.key.as_ref(), &[vault_bump_seed]];
214/// let expected_vault_pda = Pubkey::create_program_address(vault_seeds, program_id)?;
215///
216/// assert_eq!(vault_pda.key, &expected_vault_pda);
217///
218/// let lamports = 10000000;
219/// let vault_size = 16;
220///
221/// invoke_signed(
222/// &system_instruction::create_account(
223/// &payer.key,
224/// &vault_pda.key,
225/// lamports,
226/// vault_size,
227/// &program_id,
228/// ),
229/// &[
230/// payer.clone(),
231/// vault_pda.clone(),
232/// ],
233/// &[
234/// &[
235/// b"vault",
236/// payer.key.as_ref(),
237/// &[vault_bump_seed],
238/// ],
239/// ]
240/// )?;
241/// Ok(())
242/// }
243/// ```
244pub fn invoke_signed(
245 instruction: &Instruction,
246 account_infos: &[AccountInfo],
247 signers_seeds: &[&[&[u8]]],
248) -> ProgramResult {
249 // Check that the account RefCells are consistent with the request
250 for account_meta in instruction.accounts.iter() {
251 for account_info in account_infos.iter() {
252 if account_meta.pubkey == *account_info.key {
253 if account_meta.is_writable {
254 let _ = account_info.try_borrow_mut_lamports()?;
255 let _ = account_info.try_borrow_mut_data()?;
256 } else {
257 let _ = account_info.try_borrow_lamports()?;
258 let _ = account_info.try_borrow_data()?;
259 }
260 break;
261 }
262 }
263 }
264
265 invoke_signed_unchecked(instruction, account_infos, signers_seeds)
266}
267
268/// Invoke a cross-program instruction with signatures but don't enforce Rust's
269/// aliasing rules.
270///
271/// This function is like [`invoke_signed`] except that it does not check that
272/// [`RefCell`]s within [`AccountInfo`]s are properly borrowable as described in
273/// the documentation for that function. Those checks consume CPU cycles that
274/// this function avoids.
275///
276/// [`RefCell`]: std::cell::RefCell
277///
278/// # Safety
279///
280/// __This function is incorrectly missing an `unsafe` declaration.__
281///
282/// If any of the writable accounts passed to the callee contain data that is
283/// borrowed within the calling program, and that data is written to by the
284/// callee, then Rust's aliasing rules will be violated and cause undefined
285/// behavior.
286pub fn invoke_signed_unchecked(
287 instruction: &Instruction,
288 account_infos: &[AccountInfo],
289 signers_seeds: &[&[&[u8]]],
290) -> ProgramResult {
291 #[cfg(target_os = "solana")]
292 {
293 let result = unsafe {
294 crate::syscalls::sol_invoke_signed_rust(
295 instruction as *const _ as *const u8,
296 account_infos as *const _ as *const u8,
297 account_infos.len() as u64,
298 signers_seeds as *const _ as *const u8,
299 signers_seeds.len() as u64,
300 )
301 };
302 match result {
303 crate::entrypoint::SUCCESS => Ok(()),
304 _ => Err(result.into()),
305 }
306 }
307
308 #[cfg(not(target_os = "solana"))]
309 crate::program_stubs::sol_invoke_signed(instruction, account_infos, signers_seeds)
310}
311
312/// Maximum size that can be set using [`set_return_data`].
313pub const MAX_RETURN_DATA: usize = 1024;
314
315/// Set the running program's return data.
316///
317/// Return data is a dedicated per-transaction buffer for data passed
318/// from cross-program invoked programs back to their caller.
319///
320/// The maximum size of return data is [`MAX_RETURN_DATA`]. Return data is
321/// retrieved by the caller with [`get_return_data`].
322pub fn set_return_data(data: &[u8]) {
323 #[cfg(target_os = "solana")]
324 unsafe {
325 crate::syscalls::sol_set_return_data(data.as_ptr(), data.len() as u64)
326 };
327
328 #[cfg(not(target_os = "solana"))]
329 crate::program_stubs::sol_set_return_data(data)
330}
331
332/// Get the return data from an invoked program.
333///
334/// For every transaction there is a single buffer with maximum length
335/// [`MAX_RETURN_DATA`], paired with a [`Pubkey`] representing the program ID of
336/// the program that most recently set the return data. Thus the return data is
337/// a global resource and care must be taken to ensure that it represents what
338/// is expected: called programs are free to set or not set the return data; and
339/// the return data may represent values set by programs multiple calls down the
340/// call stack, depending on the circumstances of transaction execution.
341///
342/// Return data is set by the callee with [`set_return_data`].
343///
344/// Return data is cleared before every CPI invocation — a program that
345/// has invoked no other programs can expect the return data to be `None`; if no
346/// return data was set by the previous CPI invocation, then this function
347/// returns `None`.
348///
349/// Return data is not cleared after returning from CPI invocations — a
350/// program that has called another program may retrieve return data that was
351/// not set by the called program, but instead set by a program further down the
352/// call stack; or, if a program calls itself recursively, it is possible that
353/// the return data was not set by the immediate call to that program, but by a
354/// subsequent recursive call to that program. Likewise, an external RPC caller
355/// may see return data that was not set by the program it is directly calling,
356/// but by a program that program called.
357///
358/// For more about return data see the [documentation for the return data proposal][rdp].
359///
360/// [rdp]: https://docs.solana.com/proposals/return-data
361pub fn get_return_data() -> Option<(Pubkey, Vec<u8>)> {
362 #[cfg(target_os = "solana")]
363 {
364 use std::cmp::min;
365
366 let mut buf = [0u8; MAX_RETURN_DATA];
367 let mut program_id = Pubkey::default();
368
369 let size = unsafe {
370 crate::syscalls::sol_get_return_data(
371 buf.as_mut_ptr(),
372 buf.len() as u64,
373 &mut program_id,
374 )
375 };
376
377 if size == 0 {
378 None
379 } else {
380 let size = min(size as usize, MAX_RETURN_DATA);
381 Some((program_id, buf[..size as usize].to_vec()))
382 }
383 }
384
385 #[cfg(not(target_os = "solana"))]
386 crate::program_stubs::sol_get_return_data()
387}
388
389/// Do sanity checks of type layout.
390#[doc(hidden)]
391#[allow(clippy::integer_arithmetic)]
392pub fn check_type_assumptions() {
393 extern crate memoffset;
394 use {
395 crate::{clock::Epoch, instruction::AccountMeta},
396 memoffset::offset_of,
397 std::{
398 cell::RefCell,
399 mem::{align_of, size_of},
400 rc::Rc,
401 str::FromStr,
402 },
403 };
404
405 // Code in this file assumes that u64 and usize are the same
406 assert_eq!(size_of::<u64>(), size_of::<usize>());
407 // Code in this file assumes that u8 is byte aligned
408 assert_eq!(1, align_of::<u8>());
409
410 // Enforce Instruction layout
411 {
412 assert_eq!(size_of::<AccountMeta>(), 32 + 1 + 1);
413
414 let pubkey1 = Pubkey::from_str("J9PYCcoKusHyKRMXnBL17VTXC3MVETyqBG2KyLXVv6Ai").unwrap();
415 let pubkey2 = Pubkey::from_str("Hvy4GHgPToZNoENTKjC4mJqpzWWjgTwXrFufKfxYiKkV").unwrap();
416 let pubkey3 = Pubkey::from_str("JDMyRL8rCkae7maCSv47upNuBMFd3Mgos1fz2AvYzVzY").unwrap();
417 let account_meta1 = AccountMeta {
418 pubkey: pubkey2,
419 is_signer: true,
420 is_writable: false,
421 };
422 let account_meta2 = AccountMeta {
423 pubkey: pubkey3,
424 is_signer: false,
425 is_writable: true,
426 };
427 let data = vec![1, 2, 3, 4, 5];
428 let instruction = Instruction {
429 program_id: pubkey1,
430 accounts: vec![account_meta1.clone(), account_meta2.clone()],
431 data: data.clone(),
432 };
433 let instruction_addr = &instruction as *const _ as u64;
434
435 // program id
436 assert_eq!(offset_of!(Instruction, program_id), 48);
437 let pubkey_ptr = (instruction_addr + 48) as *const Pubkey;
438 unsafe {
439 assert_eq!(*pubkey_ptr, pubkey1);
440 }
441
442 // accounts
443 assert_eq!(offset_of!(Instruction, accounts), 0);
444 let accounts_ptr = (instruction_addr) as *const *const AccountMeta;
445 let accounts_cap = (instruction_addr + 8) as *const usize;
446 let accounts_len = (instruction_addr + 16) as *const usize;
447 unsafe {
448 assert_eq!(*accounts_cap, 2);
449 assert_eq!(*accounts_len, 2);
450 let account_meta_ptr = *accounts_ptr;
451 assert_eq!(*account_meta_ptr, account_meta1);
452 assert_eq!(*(account_meta_ptr.offset(1)), account_meta2);
453 }
454
455 // data
456 assert_eq!(offset_of!(Instruction, data), 24);
457 let data_ptr = (instruction_addr + 24) as *const *const [u8; 5];
458 let data_cap = (instruction_addr + 24 + 8) as *const usize;
459 let data_len = (instruction_addr + 24 + 16) as *const usize;
460 unsafe {
461 assert_eq!(*data_cap, 5);
462
463 assert_eq!(*data_len, 5);
464 let u8_ptr = *data_ptr;
465 assert_eq!(*u8_ptr, data[..]);
466 }
467 }
468
469 // Enforce AccountInfo layout
470 {
471 let key = Pubkey::from_str("6o8R9NsUxNskF1MfWM1f265y4w86JYbEwqCmTacdLkHp").unwrap();
472 let mut lamports = 31;
473 let mut data = vec![1, 2, 3, 4, 5];
474 let owner = Pubkey::from_str("2tjK4XyNU54XdN9jokx46QzLybbLVGwQQvTfhcuBXAjR").unwrap();
475 let account_info = AccountInfo {
476 key: &key,
477 is_signer: true,
478 is_writable: false,
479 lamports: Rc::new(RefCell::new(&mut lamports)),
480 data: Rc::new(RefCell::new(&mut data)),
481 owner: &owner,
482 executable: true,
483 rent_epoch: 42,
484 };
485 let account_info_addr = &account_info as *const _ as u64;
486
487 // key
488 assert_eq!(offset_of!(AccountInfo, key), 0);
489 let key_ptr = (account_info_addr) as *const &Pubkey;
490 unsafe {
491 assert_eq!(**key_ptr, key);
492 }
493
494 // is_signer
495 assert_eq!(offset_of!(AccountInfo, is_signer), 40);
496 let is_signer_ptr = (account_info_addr + 40) as *const bool;
497 unsafe {
498 assert!(*is_signer_ptr);
499 }
500
501 // is_writable
502 assert_eq!(offset_of!(AccountInfo, is_writable), 41);
503 let is_writable_ptr = (account_info_addr + 41) as *const bool;
504 unsafe {
505 assert!(!*is_writable_ptr);
506 }
507
508 // lamports
509 assert_eq!(offset_of!(AccountInfo, lamports), 8);
510 let lamports_ptr = (account_info_addr + 8) as *const Rc<RefCell<&mut u64>>;
511 unsafe {
512 assert_eq!(**(*lamports_ptr).as_ptr(), 31);
513 }
514
515 // data
516 assert_eq!(offset_of!(AccountInfo, data), 16);
517 let data_ptr = (account_info_addr + 16) as *const Rc<RefCell<&mut [u8]>>;
518 unsafe {
519 assert_eq!((*(*data_ptr).as_ptr())[..], data[..]);
520 }
521
522 // owner
523 assert_eq!(offset_of!(AccountInfo, owner), 24);
524 let owner_ptr = (account_info_addr + 24) as *const &Pubkey;
525 unsafe {
526 assert_eq!(**owner_ptr, owner);
527 }
528
529 // executable
530 assert_eq!(offset_of!(AccountInfo, executable), 42);
531 let executable_ptr = (account_info_addr + 42) as *const bool;
532 unsafe {
533 assert!(*executable_ptr);
534 }
535
536 // rent_epoch
537 assert_eq!(offset_of!(AccountInfo, rent_epoch), 32);
538 let renbt_epoch_ptr = (account_info_addr + 32) as *const Epoch;
539 unsafe {
540 assert_eq!(*renbt_epoch_ptr, 42);
541 }
542 }
543}
544
545#[cfg(test)]
546mod tests {
547 #[test]
548 fn test_check_type_assumptions() {
549 super::check_type_assumptions()
550 }
551}