solana_program/
instruction.rs

1#[cfg(feature = "frozen-abi")]
2use solana_frozen_abi_macro::AbiExample;
3pub use solana_instruction::{
4    error::InstructionError, AccountMeta, Instruction, ProcessedSiblingInstruction,
5    TRANSACTION_LEVEL_STACK_HEIGHT,
6};
7use {
8    bincode::serialize, serde::Serialize, solana_pubkey::Pubkey, solana_sanitize::Sanitize,
9    solana_short_vec as short_vec,
10};
11
12/// A compact encoding of an instruction.
13///
14/// A `CompiledInstruction` is a component of a multi-instruction [`Message`],
15/// which is the core of a Solana transaction. It is created during the
16/// construction of `Message`. Most users will not interact with it directly.
17///
18/// [`Message`]: crate::message::Message
19#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
20#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
21#[serde(rename_all = "camelCase")]
22pub struct CompiledInstruction {
23    /// Index into the transaction keys array indicating the program account that executes this instruction.
24    pub program_id_index: u8,
25    /// Ordered indices into the transaction keys array indicating which accounts to pass to the program.
26    #[serde(with = "short_vec")]
27    pub accounts: Vec<u8>,
28    /// The program input data.
29    #[serde(with = "short_vec")]
30    pub data: Vec<u8>,
31}
32
33impl Sanitize for CompiledInstruction {}
34
35impl CompiledInstruction {
36    pub fn new<T: Serialize>(program_ids_index: u8, data: &T, accounts: Vec<u8>) -> Self {
37        let data = serialize(data).unwrap();
38        Self {
39            program_id_index: program_ids_index,
40            accounts,
41            data,
42        }
43    }
44
45    pub fn new_from_raw_parts(program_id_index: u8, data: Vec<u8>, accounts: Vec<u8>) -> Self {
46        Self {
47            program_id_index,
48            accounts,
49            data,
50        }
51    }
52
53    pub fn program_id<'a>(&self, program_ids: &'a [Pubkey]) -> &'a Pubkey {
54        &program_ids[self.program_id_index as usize]
55    }
56}
57
58/// Returns a sibling instruction from the processed sibling instruction list.
59///
60/// The processed sibling instruction list is a reverse-ordered list of
61/// successfully processed sibling instructions. For example, given the call flow:
62///
63/// A
64/// B -> C -> D
65/// B -> E
66/// B -> F
67///
68/// Then B's processed sibling instruction list is: `[A]`
69/// Then F's processed sibling instruction list is: `[E, C]`
70pub fn get_processed_sibling_instruction(index: usize) -> Option<Instruction> {
71    #[cfg(target_os = "solana")]
72    {
73        let mut meta = ProcessedSiblingInstruction::default();
74        let mut program_id = solana_pubkey::Pubkey::default();
75
76        if 1 == unsafe {
77            solana_instruction::syscalls::sol_get_processed_sibling_instruction(
78                index as u64,
79                &mut meta,
80                &mut program_id,
81                &mut u8::default(),
82                &mut AccountMeta::default(),
83            )
84        } {
85            let mut data = Vec::new();
86            let mut accounts = Vec::new();
87            data.resize_with(meta.data_len as usize, u8::default);
88            accounts.resize_with(meta.accounts_len as usize, AccountMeta::default);
89
90            let _ = unsafe {
91                solana_instruction::syscalls::sol_get_processed_sibling_instruction(
92                    index as u64,
93                    &mut meta,
94                    &mut program_id,
95                    data.as_mut_ptr(),
96                    accounts.as_mut_ptr(),
97                )
98            };
99
100            Some(Instruction::new_with_bytes(program_id, &data, accounts))
101        } else {
102            None
103        }
104    }
105
106    #[cfg(not(target_os = "solana"))]
107    crate::program_stubs::sol_get_processed_sibling_instruction(index)
108}
109
110/// Get the current stack height, transaction-level instructions are height
111/// TRANSACTION_LEVEL_STACK_HEIGHT, fist invoked inner instruction is height
112/// TRANSACTION_LEVEL_STACK_HEIGHT + 1, etc...
113pub fn get_stack_height() -> usize {
114    #[cfg(target_os = "solana")]
115    unsafe {
116        solana_instruction::syscalls::sol_get_stack_height() as usize
117    }
118
119    #[cfg(not(target_os = "solana"))]
120    {
121        crate::program_stubs::sol_get_stack_height() as usize
122    }
123}
124
125// TODO: remove this.
126/// Addition that returns [`InstructionError::InsufficientFunds`] on overflow.
127///
128/// This is an internal utility function.
129#[doc(hidden)]
130pub fn checked_add(a: u64, b: u64) -> Result<u64, InstructionError> {
131    a.checked_add(b).ok_or(InstructionError::InsufficientFunds)
132}