solana_program/instruction.rs
1//! Types for directing the execution of Safecoin programs.
2//!
3//! Every invocation of a Safecoin 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 Safecoin 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
14#![allow(clippy::integer_arithmetic)]
15
16use {
17 crate::{pubkey::Pubkey, sanitize::Sanitize, short_vec, wasm_bindgen},
18 bincode::serialize,
19 borsh::BorshSerialize,
20 serde::Serialize,
21 thiserror::Error,
22};
23
24/// Reasons the runtime might have rejected an instruction.
25///
26/// Instructions errors are included in the bank hashes and therefore are
27/// included as part of the transaction results when determining consensus.
28/// Because of this, members of this enum must not be removed, but new ones can
29/// be added. Also, it is crucial that meta-information if any that comes along
30/// with an error be consistent across software versions. For example, it is
31/// dangerous to include error strings from 3rd party crates because they could
32/// change at any time and changes to them are difficult to detect.
33#[derive(
34 Serialize, Deserialize, Debug, Error, PartialEq, Eq, Clone, AbiExample, AbiEnumVisitor,
35)]
36pub enum InstructionError {
37 /// Deprecated! Use CustomError instead!
38 /// The program instruction returned an error
39 #[error("generic instruction error")]
40 GenericError,
41
42 /// The arguments provided to a program were invalid
43 #[error("invalid program argument")]
44 InvalidArgument,
45
46 /// An instruction's data contents were invalid
47 #[error("invalid instruction data")]
48 InvalidInstructionData,
49
50 /// An account's data contents was invalid
51 #[error("invalid account data for instruction")]
52 InvalidAccountData,
53
54 /// An account's data was too small
55 #[error("account data too small for instruction")]
56 AccountDataTooSmall,
57
58 /// An account's balance was too small to complete the instruction
59 #[error("insufficient funds for instruction")]
60 InsufficientFunds,
61
62 /// The account did not have the expected program id
63 #[error("incorrect program id for instruction")]
64 IncorrectProgramId,
65
66 /// A signature was required but not found
67 #[error("missing required signature for instruction")]
68 MissingRequiredSignature,
69
70 /// An initialize instruction was sent to an account that has already been initialized.
71 #[error("instruction requires an uninitialized account")]
72 AccountAlreadyInitialized,
73
74 /// An attempt to operate on an account that hasn't been initialized.
75 #[error("instruction requires an initialized account")]
76 UninitializedAccount,
77
78 /// Program's instruction lamport balance does not equal the balance after the instruction
79 #[error("sum of account balances before and after instruction do not match")]
80 UnbalancedInstruction,
81
82 /// Program illegally modified an account's program id
83 #[error("instruction illegally modified the program id of an account")]
84 ModifiedProgramId,
85
86 /// Program spent the lamports of an account that doesn't belong to it
87 #[error("instruction spent from the balance of an account it does not own")]
88 ExternalAccountLamportSpend,
89
90 /// Program modified the data of an account that doesn't belong to it
91 #[error("instruction modified data of an account it does not own")]
92 ExternalAccountDataModified,
93
94 /// Read-only account's lamports modified
95 #[error("instruction changed the balance of a read-only account")]
96 ReadonlyLamportChange,
97
98 /// Read-only account's data was modified
99 #[error("instruction modified data of a read-only account")]
100 ReadonlyDataModified,
101
102 /// An account was referenced more than once in a single instruction
103 // Deprecated, instructions can now contain duplicate accounts
104 #[error("instruction contains duplicate accounts")]
105 DuplicateAccountIndex,
106
107 /// Executable bit on account changed, but shouldn't have
108 #[error("instruction changed executable bit of an account")]
109 ExecutableModified,
110
111 /// Rent_epoch account changed, but shouldn't have
112 #[error("instruction modified rent epoch of an account")]
113 RentEpochModified,
114
115 /// The instruction expected additional account keys
116 #[error("insufficient account keys for instruction")]
117 NotEnoughAccountKeys,
118
119 /// Program other than the account's owner changed the size of the account data
120 #[error("program other than the account's owner changed the size of the account data")]
121 AccountDataSizeChanged,
122
123 /// The instruction expected an executable account
124 #[error("instruction expected an executable account")]
125 AccountNotExecutable,
126
127 /// Failed to borrow a reference to account data, already borrowed
128 #[error("instruction tries to borrow reference for an account which is already borrowed")]
129 AccountBorrowFailed,
130
131 /// Account data has an outstanding reference after a program's execution
132 #[error("instruction left account with an outstanding borrowed reference")]
133 AccountBorrowOutstanding,
134
135 /// The same account was multiply passed to an on-chain program's entrypoint, but the program
136 /// modified them differently. A program can only modify one instance of the account because
137 /// the runtime cannot determine which changes to pick or how to merge them if both are modified
138 #[error("instruction modifications of multiply-passed account differ")]
139 DuplicateAccountOutOfSync,
140
141 /// Allows on-chain programs to implement program-specific error types and see them returned
142 /// by the Safecoin runtime. A program-specific error may be any type that is represented as
143 /// or serialized to a u32 integer.
144 #[error("custom program error: {0:#x}")]
145 Custom(u32),
146
147 /// The return value from the program was invalid. Valid errors are either a defined builtin
148 /// error value or a user-defined error in the lower 32 bits.
149 #[error("program returned invalid error code")]
150 InvalidError,
151
152 /// Executable account's data was modified
153 #[error("instruction changed executable accounts data")]
154 ExecutableDataModified,
155
156 /// Executable account's lamports modified
157 #[error("instruction changed the balance of a executable account")]
158 ExecutableLamportChange,
159
160 /// Executable accounts must be rent exempt
161 #[error("executable accounts must be rent exempt")]
162 ExecutableAccountNotRentExempt,
163
164 /// Unsupported program id
165 #[error("Unsupported program id")]
166 UnsupportedProgramId,
167
168 /// Cross-program invocation call depth too deep
169 #[error("Cross-program invocation call depth too deep")]
170 CallDepth,
171
172 /// An account required by the instruction is missing
173 #[error("An account required by the instruction is missing")]
174 MissingAccount,
175
176 /// Cross-program invocation reentrancy not allowed for this instruction
177 #[error("Cross-program invocation reentrancy not allowed for this instruction")]
178 ReentrancyNotAllowed,
179
180 /// Length of the seed is too long for address generation
181 #[error("Length of the seed is too long for address generation")]
182 MaxSeedLengthExceeded,
183
184 /// Provided seeds do not result in a valid address
185 #[error("Provided seeds do not result in a valid address")]
186 InvalidSeeds,
187
188 /// Failed to reallocate account data of this length
189 #[error("Failed to reallocate account data")]
190 InvalidRealloc,
191
192 /// Computational budget exceeded
193 #[error("Computational budget exceeded")]
194 ComputationalBudgetExceeded,
195
196 /// Cross-program invocation with unauthorized signer or writable account
197 #[error("Cross-program invocation with unauthorized signer or writable account")]
198 PrivilegeEscalation,
199
200 /// Failed to create program execution environment
201 #[error("Failed to create program execution environment")]
202 ProgramEnvironmentSetupFailure,
203
204 /// Program failed to complete
205 #[error("Program failed to complete")]
206 ProgramFailedToComplete,
207
208 /// Program failed to compile
209 #[error("Program failed to compile")]
210 ProgramFailedToCompile,
211
212 /// Account is immutable
213 #[error("Account is immutable")]
214 Immutable,
215
216 /// Incorrect authority provided
217 #[error("Incorrect authority provided")]
218 IncorrectAuthority,
219
220 /// Failed to serialize or deserialize account data
221 ///
222 /// Warning: This error should never be emitted by the runtime.
223 ///
224 /// This error includes strings from the underlying 3rd party Borsh crate
225 /// which can be dangerous because the error strings could change across
226 /// Borsh versions. Only programs can use this error because they are
227 /// consistent across Safecoin software versions.
228 ///
229 #[error("Failed to serialize or deserialize account data: {0}")]
230 BorshIoError(String),
231
232 /// An account does not have enough lamports to be rent-exempt
233 #[error("An account does not have enough lamports to be rent-exempt")]
234 AccountNotRentExempt,
235
236 /// Invalid account owner
237 #[error("Invalid account owner")]
238 InvalidAccountOwner,
239
240 /// Program arithmetic overflowed
241 #[error("Program arithmetic overflowed")]
242 ArithmeticOverflow,
243
244 /// Unsupported sysvar
245 #[error("Unsupported sysvar")]
246 UnsupportedSysvar,
247
248 /// Illegal account owner
249 #[error("Provided owner is not allowed")]
250 IllegalOwner,
251
252 /// Account data allocation exceeded the maximum accounts data size limit
253 #[error("Account data allocation exceeded the maximum accounts data size limit")]
254 MaxAccountsDataSizeExceeded,
255
256 /// Max accounts exceeded
257 #[error("Max accounts exceeded")]
258 MaxAccountsExceeded,
259 // Note: For any new error added here an equivalent ProgramError and its
260 // conversions must also be added
261}
262
263/// A directive for a single invocation of a Safecoin program.
264///
265/// An instruction specifies which program it is calling, which accounts it may
266/// read or modify, and additional data that serves as input to the program. One
267/// or more instructions are included in transactions submitted by Safecoin
268/// clients. Instructions are also used to describe [cross-program
269/// invocations][cpi].
270///
271/// [cpi]: https://docs.solana.com/developing/programming-model/calling-between-programs
272///
273/// During execution, a program will receive a list of account data as one of
274/// its arguments, in the same order as specified during `Instruction`
275/// construction.
276///
277/// While Safecoin is agnostic to the format of the instruction data, it has
278/// built-in support for serialization via [`borsh`] and [`bincode`].
279///
280/// [`borsh`]: https://docs.rs/borsh/latest/borsh/
281/// [`bincode`]: https://docs.rs/bincode/latest/bincode/
282///
283/// # Specifying account metadata
284///
285/// When constructing an [`Instruction`], a list of all accounts that may be
286/// read or written during the execution of that instruction must be supplied as
287/// [`AccountMeta`] values.
288///
289/// Any account whose data may be mutated by the program during execution must
290/// be specified as writable. During execution, writing to an account that was
291/// not specified as writable will cause the transaction to fail. Writing to an
292/// account that is not owned by the program will cause the transaction to fail.
293///
294/// Any account whose lamport balance may be mutated by the program during
295/// execution must be specified as writable. During execution, mutating the
296/// lamports of an account that was not specified as writable will cause the
297/// transaction to fail. While _subtracting_ lamports from an account not owned
298/// by the program will cause the transaction to fail, _adding_ lamports to any
299/// account is allowed, as long is it is mutable.
300///
301/// Accounts that are not read or written by the program may still be specified
302/// in an `Instruction`'s account list. These will affect scheduling of program
303/// execution by the runtime, but will otherwise be ignored.
304///
305/// When building a transaction, the Safecoin runtime coalesces all accounts used
306/// by all instructions in that transaction, along with accounts and permissions
307/// required by the runtime, into a single account list. Some accounts and
308/// account permissions required by the runtime to process a transaction are
309/// _not_ required to be included in an `Instruction`s account list. These
310/// include:
311///
312/// - The program ID — it is a separate field of `Instruction`
313/// - The transaction's fee-paying account — it is added during [`Message`]
314/// construction. A program may still require the fee payer as part of the
315/// account list if it directly references it.
316///
317/// [`Message`]: crate::message::Message
318///
319/// Programs may require signatures from some accounts, in which case they
320/// should be specified as signers during `Instruction` construction. The
321/// program must still validate during execution that the account is a signer.
322#[wasm_bindgen]
323#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
324pub struct Instruction {
325 /// Pubkey of the program that executes this instruction.
326 #[wasm_bindgen(skip)]
327 pub program_id: Pubkey,
328 /// Metadata describing accounts that should be passed to the program.
329 #[wasm_bindgen(skip)]
330 pub accounts: Vec<AccountMeta>,
331 /// Opaque data passed to the program for its own interpretation.
332 #[wasm_bindgen(skip)]
333 pub data: Vec<u8>,
334}
335
336impl Instruction {
337 /// Create a new instruction from a value, encoded with [`borsh`].
338 ///
339 /// [`borsh`]: https://docs.rs/borsh/latest/borsh/
340 ///
341 /// `program_id` is the address of the program that will execute the instruction.
342 /// `accounts` contains a description of all accounts that may be accessed by the program.
343 ///
344 /// Borsh serialization is often prefered over bincode as it has a stable
345 /// [specification] and an [implementation in JavaScript][jsb], neither of
346 /// which are true of bincode.
347 ///
348 /// [specification]: https://borsh.io/
349 /// [jsb]: https://github.com/near/borsh-js
350 ///
351 /// # Examples
352 ///
353 /// ```
354 /// # use solana_program::{
355 /// # pubkey::Pubkey,
356 /// # instruction::{AccountMeta, Instruction},
357 /// # };
358 /// # use borsh::{BorshSerialize, BorshDeserialize};
359 /// #
360 /// #[derive(BorshSerialize, BorshDeserialize)]
361 /// pub struct MyInstruction {
362 /// pub lamports: u64,
363 /// }
364 ///
365 /// pub fn create_instruction(
366 /// program_id: &Pubkey,
367 /// from: &Pubkey,
368 /// to: &Pubkey,
369 /// lamports: u64,
370 /// ) -> Instruction {
371 /// let instr = MyInstruction { lamports };
372 ///
373 /// Instruction::new_with_borsh(
374 /// *program_id,
375 /// &instr,
376 /// vec![
377 /// AccountMeta::new(*from, true),
378 /// AccountMeta::new(*to, false),
379 /// ],
380 /// )
381 /// }
382 /// ```
383 pub fn new_with_borsh<T: BorshSerialize>(
384 program_id: Pubkey,
385 data: &T,
386 accounts: Vec<AccountMeta>,
387 ) -> Self {
388 let data = data.try_to_vec().unwrap();
389 Self {
390 program_id,
391 accounts,
392 data,
393 }
394 }
395
396 /// Create a new instruction from a value, encoded with [`bincode`].
397 ///
398 /// [`bincode`]: https://docs.rs/bincode/latest/bincode/
399 ///
400 /// `program_id` is the address of the program that will execute the instruction.
401 /// `accounts` contains a description of all accounts that may be accessed by the program.
402 ///
403 /// # Examples
404 ///
405 /// ```
406 /// # use solana_program::{
407 /// # pubkey::Pubkey,
408 /// # instruction::{AccountMeta, Instruction},
409 /// # };
410 /// # use serde::{Serialize, Deserialize};
411 /// #
412 /// #[derive(Serialize, Deserialize)]
413 /// pub struct MyInstruction {
414 /// pub lamports: u64,
415 /// }
416 ///
417 /// pub fn create_instruction(
418 /// program_id: &Pubkey,
419 /// from: &Pubkey,
420 /// to: &Pubkey,
421 /// lamports: u64,
422 /// ) -> Instruction {
423 /// let instr = MyInstruction { lamports };
424 ///
425 /// Instruction::new_with_bincode(
426 /// *program_id,
427 /// &instr,
428 /// vec![
429 /// AccountMeta::new(*from, true),
430 /// AccountMeta::new(*to, false),
431 /// ],
432 /// )
433 /// }
434 /// ```
435 pub fn new_with_bincode<T: Serialize>(
436 program_id: Pubkey,
437 data: &T,
438 accounts: Vec<AccountMeta>,
439 ) -> Self {
440 let data = serialize(data).unwrap();
441 Self {
442 program_id,
443 accounts,
444 data,
445 }
446 }
447
448 /// Create a new instruction from a byte slice.
449 ///
450 /// `program_id` is the address of the program that will execute the instruction.
451 /// `accounts` contains a description of all accounts that may be accessed by the program.
452 ///
453 /// The caller is responsible for ensuring the correct encoding of `data` as expected
454 /// by the callee program.
455 ///
456 /// # Examples
457 ///
458 /// ```
459 /// # use solana_program::{
460 /// # pubkey::Pubkey,
461 /// # instruction::{AccountMeta, Instruction},
462 /// # };
463 /// # use borsh::{BorshSerialize, BorshDeserialize};
464 /// # use anyhow::Result;
465 /// #
466 /// #[derive(BorshSerialize, BorshDeserialize)]
467 /// pub struct MyInstruction {
468 /// pub lamports: u64,
469 /// }
470 ///
471 /// pub fn create_instruction(
472 /// program_id: &Pubkey,
473 /// from: &Pubkey,
474 /// to: &Pubkey,
475 /// lamports: u64,
476 /// ) -> Result<Instruction> {
477 /// let instr = MyInstruction { lamports };
478 ///
479 /// let mut instr_in_bytes: Vec<u8> = Vec::new();
480 /// instr.serialize(&mut instr_in_bytes)?;
481 ///
482 /// Ok(Instruction::new_with_bytes(
483 /// *program_id,
484 /// &instr_in_bytes,
485 /// vec![
486 /// AccountMeta::new(*from, true),
487 /// AccountMeta::new(*to, false),
488 /// ],
489 /// ))
490 /// }
491 /// ```
492 pub fn new_with_bytes(program_id: Pubkey, data: &[u8], accounts: Vec<AccountMeta>) -> Self {
493 Self {
494 program_id,
495 accounts,
496 data: data.to_vec(),
497 }
498 }
499
500 #[deprecated(
501 since = "1.6.0",
502 note = "Please use another Instruction constructor instead, such as `Instruction::new_with_borsh`"
503 )]
504 pub fn new<T: Serialize>(program_id: Pubkey, data: &T, accounts: Vec<AccountMeta>) -> Self {
505 Self::new_with_bincode(program_id, data, accounts)
506 }
507}
508
509/// Addition that returns [`InstructionError::InsufficientFunds`] on overflow.
510///
511/// This is an internal utility function.
512#[doc(hidden)]
513pub fn checked_add(a: u64, b: u64) -> Result<u64, InstructionError> {
514 a.checked_add(b).ok_or(InstructionError::InsufficientFunds)
515}
516
517/// Describes a single account read or written by a program during instruction
518/// execution.
519///
520/// When constructing an [`Instruction`], a list of all accounts that may be
521/// read or written during the execution of that instruction must be supplied.
522/// Any account that may be mutated by the program during execution, either its
523/// data or metadata such as held lamports, must be writable.
524///
525/// Note that because the Safecoin runtime schedules parallel transaction
526/// execution around which accounts are writable, care should be taken that only
527/// accounts which actually may be mutated are specified as writable. As the
528/// default [`AccountMeta::new`] constructor creates writable accounts, this is
529/// a minor hazard: use [`AccountMeta::new_readonly`] to specify that an account
530/// is not writable.
531#[repr(C)]
532#[derive(Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize)]
533pub struct AccountMeta {
534 /// An account's public key.
535 pub pubkey: Pubkey,
536 /// True if an `Instruction` requires a `Transaction` signature matching `pubkey`.
537 pub is_signer: bool,
538 /// True if the account data or metadata may be mutated during program execution.
539 pub is_writable: bool,
540}
541
542impl AccountMeta {
543 /// Construct metadata for a writable account.
544 ///
545 /// # Examples
546 ///
547 /// ```
548 /// # use solana_program::{
549 /// # pubkey::Pubkey,
550 /// # instruction::{AccountMeta, Instruction},
551 /// # };
552 /// # use borsh::{BorshSerialize, BorshDeserialize};
553 /// #
554 /// # #[derive(BorshSerialize, BorshDeserialize)]
555 /// # pub struct MyInstruction;
556 /// #
557 /// # let instruction = MyInstruction;
558 /// # let from = Pubkey::new_unique();
559 /// # let to = Pubkey::new_unique();
560 /// # let program_id = Pubkey::new_unique();
561 /// let instr = Instruction::new_with_borsh(
562 /// program_id,
563 /// &instruction,
564 /// vec![
565 /// AccountMeta::new(from, true),
566 /// AccountMeta::new(to, false),
567 /// ],
568 /// );
569 /// ```
570 pub fn new(pubkey: Pubkey, is_signer: bool) -> Self {
571 Self {
572 pubkey,
573 is_signer,
574 is_writable: true,
575 }
576 }
577
578 /// Construct metadata for a read-only account.
579 ///
580 /// # Examples
581 ///
582 /// ```
583 /// # use solana_program::{
584 /// # pubkey::Pubkey,
585 /// # instruction::{AccountMeta, Instruction},
586 /// # };
587 /// # use borsh::{BorshSerialize, BorshDeserialize};
588 /// #
589 /// # #[derive(BorshSerialize, BorshDeserialize)]
590 /// # pub struct MyInstruction;
591 /// #
592 /// # let instruction = MyInstruction;
593 /// # let from = Pubkey::new_unique();
594 /// # let to = Pubkey::new_unique();
595 /// # let from_account_storage = Pubkey::new_unique();
596 /// # let program_id = Pubkey::new_unique();
597 /// let instr = Instruction::new_with_borsh(
598 /// program_id,
599 /// &instruction,
600 /// vec![
601 /// AccountMeta::new(from, true),
602 /// AccountMeta::new(to, false),
603 /// AccountMeta::new_readonly(from_account_storage, false),
604 /// ],
605 /// );
606 /// ```
607 pub fn new_readonly(pubkey: Pubkey, is_signer: bool) -> Self {
608 Self {
609 pubkey,
610 is_signer,
611 is_writable: false,
612 }
613 }
614}
615
616/// A compact encoding of an instruction.
617///
618/// A `CompiledInstruction` is a component of a multi-instruction [`Message`],
619/// which is the core of a Safecoin transaction. It is created during the
620/// construction of `Message`. Most users will not interact with it directly.
621///
622/// [`Message`]: crate::message::Message
623#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, AbiExample)]
624#[serde(rename_all = "camelCase")]
625pub struct CompiledInstruction {
626 /// Index into the transaction keys array indicating the program account that executes this instruction.
627 pub program_id_index: u8,
628 /// Ordered indices into the transaction keys array indicating which accounts to pass to the program.
629 #[serde(with = "short_vec")]
630 pub accounts: Vec<u8>,
631 /// The program input data.
632 #[serde(with = "short_vec")]
633 pub data: Vec<u8>,
634}
635
636impl Sanitize for CompiledInstruction {}
637
638impl CompiledInstruction {
639 pub fn new<T: Serialize>(program_ids_index: u8, data: &T, accounts: Vec<u8>) -> Self {
640 let data = serialize(data).unwrap();
641 Self {
642 program_id_index: program_ids_index,
643 accounts,
644 data,
645 }
646 }
647
648 pub fn new_from_raw_parts(program_id_index: u8, data: Vec<u8>, accounts: Vec<u8>) -> Self {
649 Self {
650 program_id_index,
651 accounts,
652 data,
653 }
654 }
655
656 pub fn program_id<'a>(&self, program_ids: &'a [Pubkey]) -> &'a Pubkey {
657 &program_ids[self.program_id_index as usize]
658 }
659}
660
661/// Use to query and convey information about the sibling instruction components
662/// when calling the `sol_get_processed_sibling_instruction` syscall.
663#[repr(C)]
664#[derive(Default, Debug, Clone, Copy)]
665pub struct ProcessedSiblingInstruction {
666 /// Length of the instruction data
667 pub data_len: u64,
668 /// Number of AccountMeta structures
669 pub accounts_len: u64,
670}
671
672/// Returns a sibling instruction from the processed sibling instruction list.
673///
674/// The processed sibling instruction list is a reverse-ordered list of
675/// successfully processed sibling instructions. For example, given the call flow:
676///
677/// A
678/// B -> C -> D
679/// B -> E
680/// B -> F
681///
682/// Then B's processed sibling instruction list is: `[A]`
683/// Then F's processed sibling instruction list is: `[E, C]`
684pub fn get_processed_sibling_instruction(index: usize) -> Option<Instruction> {
685 #[cfg(target_os = "solana")]
686 {
687 let mut meta = ProcessedSiblingInstruction::default();
688 let mut program_id = Pubkey::default();
689
690 if 1 == unsafe {
691 crate::syscalls::sol_get_processed_sibling_instruction(
692 index as u64,
693 &mut meta,
694 &mut program_id,
695 &mut u8::default(),
696 &mut AccountMeta::default(),
697 )
698 } {
699 let mut data = Vec::new();
700 let mut accounts = Vec::new();
701 data.resize_with(meta.data_len as usize, u8::default);
702 accounts.resize_with(meta.accounts_len as usize, AccountMeta::default);
703
704 let _ = unsafe {
705 crate::syscalls::sol_get_processed_sibling_instruction(
706 index as u64,
707 &mut meta,
708 &mut program_id,
709 data.as_mut_ptr(),
710 accounts.as_mut_ptr(),
711 )
712 };
713
714 Some(Instruction::new_with_bytes(program_id, &data, accounts))
715 } else {
716 None
717 }
718 }
719
720 #[cfg(not(target_os = "solana"))]
721 crate::program_stubs::sol_get_processed_sibling_instruction(index)
722}
723
724// Stack height when processing transaction-level instructions
725pub const TRANSACTION_LEVEL_STACK_HEIGHT: usize = 1;
726
727/// Get the current stack height, transaction-level instructions are height
728/// TRANSACTION_LEVEL_STACK_HEIGHT, fist invoked inner instruction is height
729/// TRANSACTION_LEVEL_STACK_HEIGHT + 1, etc...
730pub fn get_stack_height() -> usize {
731 #[cfg(target_os = "solana")]
732 unsafe {
733 crate::syscalls::sol_get_stack_height() as usize
734 }
735
736 #[cfg(not(target_os = "solana"))]
737 {
738 crate::program_stubs::sol_get_stack_height() as usize
739 }
740}
741
742#[test]
743fn test_account_meta_layout() {
744 #[derive(Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize)]
745 struct AccountMetaRust {
746 pub pubkey: Pubkey,
747 pub is_signer: bool,
748 pub is_writable: bool,
749 }
750
751 let account_meta_rust = AccountMetaRust::default();
752 let base_rust_addr = &account_meta_rust as *const _ as u64;
753 let pubkey_rust_addr = &account_meta_rust.pubkey as *const _ as u64;
754 let is_signer_rust_addr = &account_meta_rust.is_signer as *const _ as u64;
755 let is_writable_rust_addr = &account_meta_rust.is_writable as *const _ as u64;
756
757 let account_meta_c = AccountMeta::default();
758 let base_c_addr = &account_meta_c as *const _ as u64;
759 let pubkey_c_addr = &account_meta_c.pubkey as *const _ as u64;
760 let is_signer_c_addr = &account_meta_c.is_signer as *const _ as u64;
761 let is_writable_c_addr = &account_meta_c.is_writable as *const _ as u64;
762
763 assert_eq!(
764 std::mem::size_of::<AccountMetaRust>(),
765 std::mem::size_of::<AccountMeta>()
766 );
767 assert_eq!(
768 pubkey_rust_addr - base_rust_addr,
769 pubkey_c_addr - base_c_addr
770 );
771 assert_eq!(
772 is_signer_rust_addr - base_rust_addr,
773 is_signer_c_addr - base_c_addr
774 );
775 assert_eq!(
776 is_writable_rust_addr - base_rust_addr,
777 is_writable_c_addr - base_c_addr
778 );
779}