Skip to main content

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}