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