solana_instruction/
lib.rs

1//! Types for directing the execution of Solana programs.
2//!
3//! Every invocation of a Solana program executes a single instruction, as
4//! defined by the [`Instruction`] type. An instruction is primarily a vector of
5//! bytes, the contents of which are program-specific, and not interpreted by
6//! the Solana runtime. This allows flexibility in how programs behave, how they
7//! are controlled by client software, and what data encodings they use.
8//!
9//! Besides the instruction data, every account a program may read or write
10//! while executing a given instruction is also included in `Instruction`, as
11//! [`AccountMeta`] values. The runtime uses this information to efficiently
12//! schedule execution of transactions.
13#![cfg_attr(docsrs, feature(doc_auto_cfg))]
14#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
15#![allow(clippy::arithmetic_side_effects)]
16#![no_std]
17
18#[cfg(feature = "std")]
19extern crate std;
20#[cfg(feature = "std")]
21use {solana_pubkey::Pubkey, std::vec::Vec};
22pub mod account_meta;
23#[cfg(feature = "std")]
24pub use account_meta::AccountMeta;
25pub mod error;
26#[cfg(target_os = "solana")]
27pub mod syscalls;
28
29/// A directive for a single invocation of a Solana program.
30///
31/// An instruction specifies which program it is calling, which accounts it may
32/// read or modify, and additional data that serves as input to the program. One
33/// or more instructions are included in transactions submitted by Solana
34/// clients. Instructions are also used to describe [cross-program
35/// invocations][cpi].
36///
37/// [cpi]: https://solana.com/docs/core/cpi
38///
39/// During execution, a program will receive a list of account data as one of
40/// its arguments, in the same order as specified during `Instruction`
41/// construction.
42///
43/// While Solana is agnostic to the format of the instruction data, it has
44/// built-in support for serialization via [`borsh`] and [`bincode`].
45///
46/// [`borsh`]: https://docs.rs/borsh/latest/borsh/
47/// [`bincode`]: https://docs.rs/bincode/latest/bincode/
48///
49/// # Specifying account metadata
50///
51/// When constructing an [`Instruction`], a list of all accounts that may be
52/// read or written during the execution of that instruction must be supplied as
53/// [`AccountMeta`] values.
54///
55/// Any account whose data may be mutated by the program during execution must
56/// be specified as writable. During execution, writing to an account that was
57/// not specified as writable will cause the transaction to fail. Writing to an
58/// account that is not owned by the program will cause the transaction to fail.
59///
60/// Any account whose lamport balance may be mutated by the program during
61/// execution must be specified as writable. During execution, mutating the
62/// lamports of an account that was not specified as writable will cause the
63/// transaction to fail. While _subtracting_ lamports from an account not owned
64/// by the program will cause the transaction to fail, _adding_ lamports to any
65/// account is allowed, as long is it is mutable.
66///
67/// Accounts that are not read or written by the program may still be specified
68/// in an `Instruction`'s account list. These will affect scheduling of program
69/// execution by the runtime, but will otherwise be ignored.
70///
71/// When building a transaction, the Solana runtime coalesces all accounts used
72/// by all instructions in that transaction, along with accounts and permissions
73/// required by the runtime, into a single account list. Some accounts and
74/// account permissions required by the runtime to process a transaction are
75/// _not_ required to be included in an `Instruction`s account list. These
76/// include:
77///
78/// - The program ID — it is a separate field of `Instruction`
79/// - The transaction's fee-paying account — it is added during [`Message`]
80///   construction. A program may still require the fee payer as part of the
81///   account list if it directly references it.
82///
83/// [`Message`]: https://docs.rs/solana-program/latest/solana_program/message/legacy/struct.Message.html
84///
85/// Programs may require signatures from some accounts, in which case they
86/// should be specified as signers during `Instruction` construction. The
87/// program must still validate during execution that the account is a signer.
88#[cfg(all(feature = "std", not(target_arch = "wasm32")))]
89#[cfg_attr(
90    feature = "serde",
91    derive(serde_derive::Serialize, serde_derive::Deserialize)
92)]
93#[derive(Debug, PartialEq, Eq, Clone)]
94pub struct Instruction {
95    /// Pubkey of the program that executes this instruction.
96    pub program_id: Pubkey,
97    /// Metadata describing accounts that should be passed to the program.
98    pub accounts: Vec<AccountMeta>,
99    /// Opaque data passed to the program for its own interpretation.
100    pub data: Vec<u8>,
101}
102
103/// wasm-bindgen version of the Instruction struct.
104/// This duplication is required until https://github.com/rustwasm/wasm-bindgen/issues/3671
105/// is fixed. This must not diverge from the regular non-wasm Instruction struct.
106#[cfg(all(feature = "std", target_arch = "wasm32"))]
107#[wasm_bindgen::prelude::wasm_bindgen]
108#[cfg_attr(
109    feature = "serde",
110    derive(serde_derive::Serialize, serde_derive::Deserialize)
111)]
112#[derive(Debug, PartialEq, Eq, Clone)]
113pub struct Instruction {
114    #[wasm_bindgen(skip)]
115    pub program_id: Pubkey,
116    #[wasm_bindgen(skip)]
117    pub accounts: Vec<AccountMeta>,
118    #[wasm_bindgen(skip)]
119    pub data: Vec<u8>,
120}
121
122#[cfg(feature = "std")]
123impl Instruction {
124    #[cfg(feature = "borsh")]
125    /// Create a new instruction from a value, encoded with [`borsh`].
126    ///
127    /// [`borsh`]: https://docs.rs/borsh/latest/borsh/
128    ///
129    /// `program_id` is the address of the program that will execute the instruction.
130    /// `accounts` contains a description of all accounts that may be accessed by the program.
131    ///
132    /// Borsh serialization is often preferred over bincode as it has a stable
133    /// [specification] and an [implementation in JavaScript][jsb], neither of
134    /// which are true of bincode.
135    ///
136    /// [specification]: https://borsh.io/
137    /// [jsb]: https://github.com/near/borsh-js
138    ///
139    /// # Examples
140    ///
141    /// ```
142    /// # use solana_pubkey::Pubkey;
143    /// # use solana_instruction::{AccountMeta, Instruction};
144    /// # use borsh::{BorshSerialize, BorshDeserialize};
145    /// #
146    /// #[derive(BorshSerialize, BorshDeserialize)]
147    /// # #[borsh(crate = "borsh")]
148    /// pub struct MyInstruction {
149    ///     pub lamports: u64,
150    /// }
151    ///
152    /// pub fn create_instruction(
153    ///     program_id: &Pubkey,
154    ///     from: &Pubkey,
155    ///     to: &Pubkey,
156    ///     lamports: u64,
157    /// ) -> Instruction {
158    ///     let instr = MyInstruction { lamports };
159    ///
160    ///     Instruction::new_with_borsh(
161    ///         *program_id,
162    ///         &instr,
163    ///         vec![
164    ///             AccountMeta::new(*from, true),
165    ///             AccountMeta::new(*to, false),
166    ///         ],
167    ///    )
168    /// }
169    /// ```
170    pub fn new_with_borsh<T: borsh::BorshSerialize>(
171        program_id: Pubkey,
172        data: &T,
173        accounts: Vec<AccountMeta>,
174    ) -> Self {
175        let data = borsh::to_vec(data).unwrap();
176        Self {
177            program_id,
178            accounts,
179            data,
180        }
181    }
182
183    #[cfg(feature = "bincode")]
184    /// Create a new instruction from a value, encoded with [`bincode`].
185    ///
186    /// [`bincode`]: https://docs.rs/bincode/latest/bincode/
187    ///
188    /// `program_id` is the address of the program that will execute the instruction.
189    /// `accounts` contains a description of all accounts that may be accessed by the program.
190    ///
191    /// # Examples
192    ///
193    /// ```
194    /// # use solana_pubkey::Pubkey;
195    /// # use solana_instruction::{AccountMeta, Instruction};
196    /// # use serde::{Serialize, Deserialize};
197    /// #
198    /// #[derive(Serialize, Deserialize)]
199    /// pub struct MyInstruction {
200    ///     pub lamports: u64,
201    /// }
202    ///
203    /// pub fn create_instruction(
204    ///     program_id: &Pubkey,
205    ///     from: &Pubkey,
206    ///     to: &Pubkey,
207    ///     lamports: u64,
208    /// ) -> Instruction {
209    ///     let instr = MyInstruction { lamports };
210    ///
211    ///     Instruction::new_with_bincode(
212    ///         *program_id,
213    ///         &instr,
214    ///         vec![
215    ///             AccountMeta::new(*from, true),
216    ///             AccountMeta::new(*to, false),
217    ///         ],
218    ///    )
219    /// }
220    /// ```
221    pub fn new_with_bincode<T: serde::Serialize>(
222        program_id: Pubkey,
223        data: &T,
224        accounts: Vec<AccountMeta>,
225    ) -> Self {
226        let data = bincode::serialize(data).unwrap();
227        Self {
228            program_id,
229            accounts,
230            data,
231        }
232    }
233
234    /// Create a new instruction from a byte slice.
235    ///
236    /// `program_id` is the address of the program that will execute the instruction.
237    /// `accounts` contains a description of all accounts that may be accessed by the program.
238    ///
239    /// The caller is responsible for ensuring the correct encoding of `data` as expected
240    /// by the callee program.
241    ///
242    /// # Examples
243    ///
244    /// ```
245    /// # use solana_pubkey::Pubkey;
246    /// # use solana_instruction::{AccountMeta, Instruction};
247    /// #
248    /// # use borsh::{io::Error, BorshSerialize, BorshDeserialize};
249    /// #
250    /// #[derive(BorshSerialize, BorshDeserialize)]
251    /// # #[borsh(crate = "borsh")]
252    /// pub struct MyInstruction {
253    ///     pub lamports: u64,
254    /// }
255    ///
256    /// pub fn create_instruction(
257    ///     program_id: &Pubkey,
258    ///     from: &Pubkey,
259    ///     to: &Pubkey,
260    ///     lamports: u64,
261    /// ) -> Result<Instruction, Error> {
262    ///     let instr = MyInstruction { lamports };
263    ///
264    ///     let mut instr_in_bytes: Vec<u8> = Vec::new();
265    ///     instr.serialize(&mut instr_in_bytes)?;
266    ///
267    ///     Ok(Instruction::new_with_bytes(
268    ///         *program_id,
269    ///         &instr_in_bytes,
270    ///         vec![
271    ///             AccountMeta::new(*from, true),
272    ///             AccountMeta::new(*to, false),
273    ///         ],
274    ///    ))
275    /// }
276    /// ```
277    pub fn new_with_bytes(program_id: Pubkey, data: &[u8], accounts: Vec<AccountMeta>) -> Self {
278        Self {
279            program_id,
280            accounts,
281            data: data.to_vec(),
282        }
283    }
284}
285
286// Stack height when processing transaction-level instructions
287pub const TRANSACTION_LEVEL_STACK_HEIGHT: usize = 1;
288
289/// Use to query and convey information about the sibling instruction components
290/// when calling the `sol_get_processed_sibling_instruction` syscall.
291#[repr(C)]
292#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
293pub struct ProcessedSiblingInstruction {
294    /// Length of the instruction data
295    pub data_len: u64,
296    /// Number of AccountMeta structures
297    pub accounts_len: u64,
298}