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}