| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  | //! Defines a composable Instruction type and a memory-efficient CompiledInstruction.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-29 18:12:51 -07:00
										 |  |  | use crate::sanitize::Sanitize;
 | 
					
						
							| 
									
										
										
										
											2020-01-28 16:11:22 -08:00
										 |  |  | use crate::{pubkey::Pubkey, short_vec, system_instruction::SystemError};
 | 
					
						
							| 
									
										
										
										
											2019-03-24 22:51:56 -07:00
										 |  |  | use bincode::serialize;
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  | use serde::Serialize;
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  | use thiserror::Error;
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | /// Reasons the runtime might have rejected an instruction.
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  | #[derive(Serialize, Deserialize, Debug, Error, PartialEq, Eq, Clone)]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  | pub enum InstructionError {
 | 
					
						
							|  |  |  |     /// Deprecated! Use CustomError instead!
 | 
					
						
							|  |  |  |     /// The program instruction returned an error
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("generic instruction error")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     GenericError,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     /// The arguments provided to a program were invalid
 | 
					
						
							|  |  |  |     #[error("invalid program argument")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     InvalidArgument,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     /// An instruction's data contents were invalid
 | 
					
						
							|  |  |  |     #[error("invalid instruction data")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     InvalidInstructionData,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// An account's data contents was invalid
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("invalid account data for instruction")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     InvalidAccountData,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// An account's data was too small
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("account data too small for instruction")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     AccountDataTooSmall,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-10 12:17:29 -07:00
										 |  |  |     /// An account's balance was too small to complete the instruction
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("insufficient funds for instruction")]
 | 
					
						
							| 
									
										
										
										
											2019-06-10 12:17:29 -07:00
										 |  |  |     InsufficientFunds,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     /// The account did not have the expected program id
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("incorrect program id for instruction")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     IncorrectProgramId,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// A signature was required but not found
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("missing required signature for instruction")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     MissingRequiredSignature,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// An initialize instruction was sent to an account that has already been initialized.
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("instruction requires an uninitialized account")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     AccountAlreadyInitialized,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// An attempt to operate on an account that hasn't been initialized.
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("instruction requires an initialized account")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     UninitializedAccount,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Program's instruction lamport balance does not equal the balance after the instruction
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("sum of account balances before and after instruction do not match")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     UnbalancedInstruction,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Program modified an account's program id
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("instruction modified the program id of an account")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     ModifiedProgramId,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Program spent the lamports of an account that doesn't belong to it
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("instruction spent from the balance of an account it does not own")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     ExternalAccountLamportSpend,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Program modified the data of an account that doesn't belong to it
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("instruction modified data of an account it does not own")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     ExternalAccountDataModified,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |     /// Read-only account's lamports modified
 | 
					
						
							|  |  |  |     #[error("instruction changed the balance of a read-only account")]
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |     ReadonlyLamportChange,
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 17:10:11 -07:00
										 |  |  |     /// Read-only account's data was modified
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("instruction modified data of a read-only account")]
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |     ReadonlyDataModified,
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     /// An account was referenced more than once in a single instruction
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |     // Deprecated, instructions can now contain duplicate accounts
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("instruction contains duplicate accounts")]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     DuplicateAccountIndex,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |     /// Executable bit on account changed, but shouldn't have
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("instruction changed executable bit of an account")]
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |     ExecutableModified,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-26 11:04:20 -07:00
										 |  |  |     /// Rent_epoch account changed, but shouldn't have
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("instruction modified rent epoch of an account")]
 | 
					
						
							| 
									
										
										
										
											2019-08-26 11:04:20 -07:00
										 |  |  |     RentEpochModified,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-10 06:30:42 -06:00
										 |  |  |     /// The instruction expected additional account keys
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     #[error("insufficient account keys for instruction")]
 | 
					
						
							| 
									
										
										
										
											2019-10-10 06:30:42 -06:00
										 |  |  |     NotEnoughAccountKeys,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-16 10:47:45 -07:00
										 |  |  |     /// A non-system program changed the size of the account data
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("non-system instruction changed account size")]
 | 
					
						
							| 
									
										
										
										
											2019-10-16 10:47:45 -07:00
										 |  |  |     AccountDataSizeChanged,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-20 15:27:36 -08:00
										 |  |  |     /// The instruction expected an executable account
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("instruction expected an executable account")]
 | 
					
						
							| 
									
										
										
										
											2019-11-08 09:19:19 -08:00
										 |  |  |     AccountNotExecutable,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-30 20:40:27 -08:00
										 |  |  |     /// Failed to borrow a reference to account data, already borrowed
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("instruction tries to borrow reference for an account which is already borrowed")]
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |     AccountBorrowFailed,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-30 20:40:27 -08:00
										 |  |  |     /// Account data has an outstanding reference after a program's execution
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("instruction left account with an outstanding reference borrowed")]
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |     AccountBorrowOutstanding,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// The same account was multiply passed to an on-chain program's entrypoint, but the program
 | 
					
						
							|  |  |  |     /// modified them differently.  A program can only modify one instance of the account because
 | 
					
						
							|  |  |  |     /// the runtime cannot determine which changes to pick or how to merge them if both are modified
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("instruction modifications of multiply-passed account differ")]
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |     DuplicateAccountOutOfSync,
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-31 10:58:07 -08:00
										 |  |  |     /// Allows on-chain programs to implement program-specific error types and see them returned
 | 
					
						
							|  |  |  |     /// by the Solana runtime. A program-specific error may be any type that is represented as
 | 
					
						
							|  |  |  |     /// or serialized to a u32 integer.
 | 
					
						
							| 
									
										
										
										
											2020-04-01 09:01:11 -07:00
										 |  |  |     #[error("custom program error: {0:#x}")]
 | 
					
						
							|  |  |  |     Custom(u32),
 | 
					
						
							| 
									
										
										
										
											2020-02-27 14:41:17 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// The return value from the program was invalid.  Valid errors are either a defined builtin
 | 
					
						
							|  |  |  |     /// error value or a user-defined error in the lower 32 bits.
 | 
					
						
							| 
									
										
										
										
											2020-03-13 00:20:49 -06:00
										 |  |  |     #[error("program returned invalid error code")]
 | 
					
						
							| 
									
										
										
										
											2020-02-27 14:41:17 -07:00
										 |  |  |     InvalidError,
 | 
					
						
							| 
									
										
										
										
											2020-03-26 17:10:11 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Executable account's data was modified
 | 
					
						
							|  |  |  |     #[error("instruction changed executable accounts data")]
 | 
					
						
							|  |  |  |     ExecutableDataModified,
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Executable account's lamports modified
 | 
					
						
							|  |  |  |     #[error("instruction changed the balance of a executable account")]
 | 
					
						
							|  |  |  |     ExecutableLamportChange,
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Executable accounts must be rent exempt
 | 
					
						
							|  |  |  |     #[error("executable accounts must be rent exempt")]
 | 
					
						
							|  |  |  |     ExecutableAccountNotRentExempt,
 | 
					
						
							| 
									
										
										
										
											2020-04-15 09:41:29 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Unsupported program id
 | 
					
						
							|  |  |  |     #[error("Unsupported program id")]
 | 
					
						
							|  |  |  |     UnsupportedProgramId,
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Writable bit on account info changed, but shouldn't have
 | 
					
						
							|  |  |  |     #[error("Writable bit on account info changed, but shouldn't have")]
 | 
					
						
							|  |  |  |     WritableModified,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Signer bit on account info changed, but shouldn't have
 | 
					
						
							|  |  |  |     #[error("Signer bit on account info changed, but shouldn't have")]
 | 
					
						
							|  |  |  |     SignerModified,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Cross-program invocation call depth too deep
 | 
					
						
							|  |  |  |     #[error("Cross-program invocation call depth too deep")]
 | 
					
						
							|  |  |  |     CallDepth,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// An account required by the instruction is missing
 | 
					
						
							|  |  |  |     #[error("An account required by the instruction is missing")]
 | 
					
						
							|  |  |  |     MissingAccount,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Cross-program invocation reentrancy not allowed for this instruction
 | 
					
						
							|  |  |  |     #[error("Cross-program invocation reentrancy not allowed for this instruction")]
 | 
					
						
							|  |  |  |     ReentrancyNotAllowed,
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | impl InstructionError {
 | 
					
						
							|  |  |  |     pub fn new_result_with_negative_lamports() -> Self {
 | 
					
						
							| 
									
										
										
										
											2020-02-14 13:58:33 -08:00
										 |  |  |         SystemError::ResultWithNegativeLamports.into()
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-29 16:11:21 -06:00
										 |  |  | #[derive(Debug, PartialEq, Clone)]
 | 
					
						
							| 
									
										
										
										
											2019-03-27 17:06:50 -06:00
										 |  |  | pub struct Instruction {
 | 
					
						
							|  |  |  |     /// Pubkey of the instruction processor that executes this instruction
 | 
					
						
							| 
									
										
										
										
											2019-07-01 18:34:22 -06:00
										 |  |  |     pub program_id: Pubkey,
 | 
					
						
							| 
									
										
										
										
											2019-03-27 17:06:50 -06:00
										 |  |  |     /// Metadata for what accounts should be passed to the instruction processor
 | 
					
						
							|  |  |  |     pub accounts: Vec<AccountMeta>,
 | 
					
						
							|  |  |  |     /// Opaque data passed to the instruction processor
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     pub data: Vec<u8>,
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-27 17:06:50 -06:00
										 |  |  | impl Instruction {
 | 
					
						
							| 
									
										
										
										
											2019-07-01 18:34:22 -06:00
										 |  |  |     pub fn new<T: Serialize>(program_id: Pubkey, data: &T, accounts: Vec<AccountMeta>) -> Self {
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |         let data = serialize(data).unwrap();
 | 
					
						
							|  |  |  |         Self {
 | 
					
						
							| 
									
										
										
										
											2019-07-01 18:34:22 -06:00
										 |  |  |             program_id,
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |             data,
 | 
					
						
							|  |  |  |             accounts,
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /// Account metadata used to define Instructions
 | 
					
						
							| 
									
										
										
										
											2019-03-29 16:11:21 -06:00
										 |  |  | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  | pub struct AccountMeta {
 | 
					
						
							|  |  |  |     /// An account's public key
 | 
					
						
							|  |  |  |     pub pubkey: Pubkey,
 | 
					
						
							| 
									
										
										
										
											2019-11-25 21:09:57 -08:00
										 |  |  |     /// True if an Instruction requires a Transaction signature matching `pubkey`.
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     pub is_signer: bool,
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |     /// True if the `pubkey` can be loaded as a read-write account.
 | 
					
						
							|  |  |  |     pub is_writable: bool,
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | impl AccountMeta {
 | 
					
						
							|  |  |  |     pub fn new(pubkey: Pubkey, is_signer: bool) -> Self {
 | 
					
						
							| 
									
										
										
										
											2019-05-23 18:19:53 -04:00
										 |  |  |         Self {
 | 
					
						
							|  |  |  |             pubkey,
 | 
					
						
							|  |  |  |             is_signer,
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |             is_writable: true,
 | 
					
						
							| 
									
										
										
										
											2019-05-23 18:19:53 -04:00
										 |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |     pub fn new_readonly(pubkey: Pubkey, is_signer: bool) -> Self {
 | 
					
						
							| 
									
										
										
										
											2019-05-23 18:19:53 -04:00
										 |  |  |         Self {
 | 
					
						
							|  |  |  |             pubkey,
 | 
					
						
							|  |  |  |             is_signer,
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |             is_writable: false,
 | 
					
						
							| 
									
										
										
										
											2019-05-23 18:19:53 -04:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 15:43:47 -05:00
										 |  |  | /// Trait for adding a signer Pubkey to an existing data structure
 | 
					
						
							|  |  |  | pub trait WithSigner {
 | 
					
						
							|  |  |  |     /// Add a signer Pubkey
 | 
					
						
							|  |  |  |     fn with_signer(self, signer: &Pubkey) -> Self;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | impl WithSigner for Vec<AccountMeta> {
 | 
					
						
							|  |  |  |     fn with_signer(mut self, signer: &Pubkey) -> Self {
 | 
					
						
							|  |  |  |         for meta in self.iter_mut() {
 | 
					
						
							|  |  |  |             // signer might already appear in parameters
 | 
					
						
							|  |  |  |             if &meta.pubkey == signer {
 | 
					
						
							|  |  |  |                 meta.is_signer = true; // found it, we're done
 | 
					
						
							|  |  |  |                 return self;
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // signer wasn't in metas, append it after normal parameters
 | 
					
						
							|  |  |  |         self.push(AccountMeta::new_readonly(*signer, true));
 | 
					
						
							|  |  |  |         self
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-27 17:06:50 -06:00
										 |  |  | /// An instruction to execute a program
 | 
					
						
							|  |  |  | #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
 | 
					
						
							| 
									
										
										
										
											2019-11-19 15:55:32 -07:00
										 |  |  | #[serde(rename_all = "camelCase")]
 | 
					
						
							| 
									
										
										
										
											2019-03-27 17:06:50 -06:00
										 |  |  | pub struct CompiledInstruction {
 | 
					
						
							| 
									
										
										
										
											2019-05-22 18:23:16 -04:00
										 |  |  |     /// Index into the transaction keys array indicating the program account that executes this instruction
 | 
					
						
							| 
									
										
										
										
											2019-07-01 18:34:22 -06:00
										 |  |  |     pub program_id_index: u8,
 | 
					
						
							| 
									
										
										
										
											2019-03-27 17:06:50 -06:00
										 |  |  |     /// Ordered indices into the transaction keys array indicating which accounts to pass to the program
 | 
					
						
							| 
									
										
										
										
											2019-03-25 09:15:16 -06:00
										 |  |  |     #[serde(with = "short_vec")]
 | 
					
						
							| 
									
										
										
										
											2019-03-27 17:06:50 -06:00
										 |  |  |     pub accounts: Vec<u8>,
 | 
					
						
							|  |  |  |     /// The program input data
 | 
					
						
							| 
									
										
										
										
											2019-03-25 09:15:16 -06:00
										 |  |  |     #[serde(with = "short_vec")]
 | 
					
						
							| 
									
										
										
										
											2019-03-27 17:06:50 -06:00
										 |  |  |     pub data: Vec<u8>,
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-29 18:12:51 -07:00
										 |  |  | impl Sanitize for CompiledInstruction {}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  | impl CompiledInstruction {
 | 
					
						
							| 
									
										
										
										
											2019-03-27 17:06:50 -06:00
										 |  |  |     pub fn new<T: Serialize>(program_ids_index: u8, data: &T, accounts: Vec<u8>) -> Self {
 | 
					
						
							|  |  |  |         let data = serialize(data).unwrap();
 | 
					
						
							|  |  |  |         Self {
 | 
					
						
							| 
									
										
										
										
											2019-07-01 18:34:22 -06:00
										 |  |  |             program_id_index: program_ids_index,
 | 
					
						
							| 
									
										
										
										
											2019-03-27 17:06:50 -06:00
										 |  |  |             data,
 | 
					
						
							|  |  |  |             accounts,
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-04-02 16:02:57 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     pub fn program_id<'a>(&self, program_ids: &'a [Pubkey]) -> &'a Pubkey {
 | 
					
						
							| 
									
										
										
										
											2019-07-01 18:34:22 -06:00
										 |  |  |         &program_ids[self.program_id_index as usize]
 | 
					
						
							| 
									
										
										
										
											2019-04-02 16:02:57 -06:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-03-12 09:08:39 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Visit each unique instruction account index once
 | 
					
						
							|  |  |  |     pub fn visit_each_account(
 | 
					
						
							|  |  |  |         &self,
 | 
					
						
							|  |  |  |         work: &mut dyn FnMut(usize, usize) -> Result<(), InstructionError>,
 | 
					
						
							|  |  |  |     ) -> Result<(), InstructionError> {
 | 
					
						
							|  |  |  |         let mut unique_index = 0;
 | 
					
						
							|  |  |  |         'root: for (i, account_index) in self.accounts.iter().enumerate() {
 | 
					
						
							|  |  |  |             // Note: This is an O(n^2) algorithm,
 | 
					
						
							|  |  |  |             // but performed on a very small slice and requires no heap allocations
 | 
					
						
							|  |  |  |             for account_index_before in self.accounts[..i].iter() {
 | 
					
						
							|  |  |  |                 if account_index_before == account_index {
 | 
					
						
							|  |  |  |                     continue 'root; // skip dups
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |             work(unique_index, *account_index as usize)?;
 | 
					
						
							|  |  |  |             unique_index += 1;
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         Ok(())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-03-23 21:12:27 -06:00
										 |  |  | }
 | 
					
						
							| 
									
										
										
										
											2019-11-18 15:43:47 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | #[cfg(test)]
 | 
					
						
							|  |  |  | mod test {
 | 
					
						
							|  |  |  |     use super::*;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_account_meta_list_with_signer() {
 | 
					
						
							|  |  |  |         let account_pubkey = Pubkey::new_rand();
 | 
					
						
							|  |  |  |         let signer_pubkey = Pubkey::new_rand();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let account_meta = AccountMeta::new(account_pubkey, false);
 | 
					
						
							|  |  |  |         let signer_account_meta = AccountMeta::new(signer_pubkey, false);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let metas = vec![].with_signer(&signer_pubkey);
 | 
					
						
							|  |  |  |         assert_eq!(metas.len(), 1);
 | 
					
						
							|  |  |  |         assert!(metas[0].is_signer);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let metas = vec![account_meta.clone()].with_signer(&signer_pubkey);
 | 
					
						
							|  |  |  |         assert_eq!(metas.len(), 2);
 | 
					
						
							|  |  |  |         assert!(!metas[0].is_signer);
 | 
					
						
							|  |  |  |         assert!(metas[1].is_signer);
 | 
					
						
							|  |  |  |         assert_eq!(metas[1].pubkey, signer_pubkey);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let metas = vec![signer_account_meta.clone()].with_signer(&signer_pubkey);
 | 
					
						
							|  |  |  |         assert_eq!(metas.len(), 1);
 | 
					
						
							|  |  |  |         assert!(metas[0].is_signer);
 | 
					
						
							|  |  |  |         assert_eq!(metas[0].pubkey, signer_pubkey);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let metas = vec![account_meta, signer_account_meta].with_signer(&signer_pubkey);
 | 
					
						
							|  |  |  |         assert_eq!(metas.len(), 2);
 | 
					
						
							|  |  |  |         assert!(!metas[0].is_signer);
 | 
					
						
							|  |  |  |         assert!(metas[1].is_signer);
 | 
					
						
							|  |  |  |         assert_eq!(metas[1].pubkey, signer_pubkey);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-03-12 09:08:39 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_visit_each_account() {
 | 
					
						
							|  |  |  |         let do_work = |accounts: &[u8]| -> (usize, usize) {
 | 
					
						
							|  |  |  |             let mut unique_total = 0;
 | 
					
						
							|  |  |  |             let mut account_total = 0;
 | 
					
						
							|  |  |  |             let mut work = |unique_index: usize, account_index: usize| {
 | 
					
						
							|  |  |  |                 unique_total += unique_index;
 | 
					
						
							|  |  |  |                 account_total += account_index;
 | 
					
						
							|  |  |  |                 Ok(())
 | 
					
						
							|  |  |  |             };
 | 
					
						
							|  |  |  |             let instruction = CompiledInstruction::new(0, &[0], accounts.to_vec());
 | 
					
						
							|  |  |  |             instruction.visit_each_account(&mut work).unwrap();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             (unique_total, account_total)
 | 
					
						
							|  |  |  |         };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         assert_eq!((6, 6), do_work(&[0, 1, 2, 3]));
 | 
					
						
							|  |  |  |         assert_eq!((6, 6), do_work(&[0, 1, 1, 2, 3]));
 | 
					
						
							|  |  |  |         assert_eq!((6, 6), do_work(&[0, 1, 2, 3, 3]));
 | 
					
						
							|  |  |  |         assert_eq!((6, 6), do_work(&[0, 0, 1, 1, 2, 2, 3, 3]));
 | 
					
						
							|  |  |  |         assert_eq!((0, 2), do_work(&[2, 2]));
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-11-18 15:43:47 -05:00
										 |  |  | }
 |