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