| 
									
										
										
										
											2020-06-06 10:18:28 -07:00
										 |  |  | use crate::{
 | 
					
						
							| 
									
										
										
										
											2020-10-30 13:40:55 -07:00
										 |  |  |     instruction_recorder::InstructionRecorder, log_collector::LogCollector,
 | 
					
						
							|  |  |  |     native_loader::NativeLoader, rent_collector::RentCollector,
 | 
					
						
							| 
									
										
										
										
											2020-06-06 10:18:28 -07:00
										 |  |  | };
 | 
					
						
							|  |  |  | use log::*;
 | 
					
						
							| 
									
										
										
										
											2019-05-30 21:31:35 -07:00
										 |  |  | use serde::{Deserialize, Serialize};
 | 
					
						
							| 
									
										
										
										
											2020-01-28 17:03:20 -08:00
										 |  |  | use solana_sdk::{
 | 
					
						
							| 
									
										
										
										
											2020-10-26 09:14:57 -07:00
										 |  |  |     account::Account,
 | 
					
						
							| 
									
										
										
										
											2020-12-18 11:23:00 -08:00
										 |  |  |     account_utils::StateMut,
 | 
					
						
							|  |  |  |     bpf_loader_upgradeable::{self, UpgradeableLoaderState},
 | 
					
						
							| 
									
										
										
										
											2020-10-30 13:40:55 -07:00
										 |  |  |     feature_set::{instructions_sysvar_enabled, FeatureSet},
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |     instruction::{CompiledInstruction, Instruction, InstructionError},
 | 
					
						
							| 
									
										
										
										
											2020-10-26 09:14:57 -07:00
										 |  |  |     keyed_account::{create_keyed_readonly_accounts, KeyedAccount},
 | 
					
						
							| 
									
										
										
										
											2020-01-28 17:03:20 -08:00
										 |  |  |     message::Message,
 | 
					
						
							| 
									
										
										
										
											2020-04-15 09:41:29 -07:00
										 |  |  |     native_loader,
 | 
					
						
							| 
									
										
										
										
											2020-10-28 20:21:50 -07:00
										 |  |  |     process_instruction::{
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |         BpfComputeBudget, ComputeMeter, Executor, InvokeContext, Logger,
 | 
					
						
							|  |  |  |         ProcessInstructionWithContext,
 | 
					
						
							| 
									
										
										
										
											2020-10-28 20:21:50 -07:00
										 |  |  |     },
 | 
					
						
							| 
									
										
										
										
											2020-01-28 17:03:20 -08:00
										 |  |  |     pubkey::Pubkey,
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     rent::Rent,
 | 
					
						
							| 
									
										
										
										
											2020-01-28 17:03:20 -08:00
										 |  |  |     system_program,
 | 
					
						
							|  |  |  |     transaction::TransactionError,
 | 
					
						
							|  |  |  | };
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  | use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc};
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | pub struct Executors {
 | 
					
						
							|  |  |  |     pub executors: HashMap<Pubkey, Arc<dyn Executor>>,
 | 
					
						
							|  |  |  |     pub is_dirty: bool,
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | impl Default for Executors {
 | 
					
						
							|  |  |  |     fn default() -> Self {
 | 
					
						
							|  |  |  |         Self {
 | 
					
						
							|  |  |  |             executors: HashMap::default(),
 | 
					
						
							|  |  |  |             is_dirty: false,
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | impl Executors {
 | 
					
						
							|  |  |  |     pub fn insert(&mut self, key: Pubkey, executor: Arc<dyn Executor>) {
 | 
					
						
							|  |  |  |         let _ = self.executors.insert(key, executor);
 | 
					
						
							|  |  |  |         self.is_dirty = true;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     pub fn get(&self, key: &Pubkey) -> Option<Arc<dyn Executor>> {
 | 
					
						
							|  |  |  |         self.executors.get(key).cloned()
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2019-03-13 11:55:43 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-05 10:57:32 -08:00
										 |  |  | // The relevant state of an account before an Instruction executes, used
 | 
					
						
							|  |  |  | // to verify account integrity after the Instruction completes
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | #[derive(Clone, Debug, Default)]
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  | pub struct PreAccount {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     key: Pubkey,
 | 
					
						
							|  |  |  |     is_signer: bool,
 | 
					
						
							|  |  |  |     is_writable: bool,
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |     account: RefCell<Account>,
 | 
					
						
							| 
									
										
										
										
											2019-11-05 10:57:32 -08:00
										 |  |  | }
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  | impl PreAccount {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     pub fn new(key: &Pubkey, account: &Account, is_signer: bool, is_writable: bool) -> Self {
 | 
					
						
							| 
									
										
										
										
											2019-11-05 10:57:32 -08:00
										 |  |  |         Self {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |             key: *key,
 | 
					
						
							|  |  |  |             is_signer,
 | 
					
						
							| 
									
										
										
										
											2019-11-05 10:57:32 -08:00
										 |  |  |             is_writable,
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |             account: RefCell::new(account.clone()),
 | 
					
						
							| 
									
										
										
										
											2019-11-05 10:57:32 -08:00
										 |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |     pub fn verify(
 | 
					
						
							|  |  |  |         &self,
 | 
					
						
							|  |  |  |         program_id: &Pubkey,
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         rent: &Rent,
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |         post: &Account,
 | 
					
						
							|  |  |  |     ) -> Result<(), InstructionError> {
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |         let pre = self.account.borrow();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         // Only the owner of the account may change owner and
 | 
					
						
							|  |  |  |         //   only if the account is writable and
 | 
					
						
							| 
									
										
										
										
											2020-12-07 11:37:07 -08:00
										 |  |  |         //   only if the account is not executable and
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         //   only if the data is zero-initialized or empty
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |         if pre.owner != post.owner
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |             && (!self.is_writable // line coverage used to get branch coverage
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |                 || pre.executable
 | 
					
						
							|  |  |  |                 || *program_id != pre.owner
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |             || !Self::is_zeroed(&post.data))
 | 
					
						
							|  |  |  |         {
 | 
					
						
							|  |  |  |             return Err(InstructionError::ModifiedProgramId);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         // An account not assigned to the program cannot have its balance decrease.
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |         if *program_id != pre.owner // line coverage used to get branch coverage
 | 
					
						
							|  |  |  |          && pre.lamports > post.lamports
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         {
 | 
					
						
							|  |  |  |             return Err(InstructionError::ExternalAccountLamportSpend);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |         // The balance of read-only and executable accounts may not change
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |         if pre.lamports != post.lamports {
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |             if !self.is_writable {
 | 
					
						
							|  |  |  |                 return Err(InstructionError::ReadonlyLamportChange);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |             if pre.executable {
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |                 return Err(InstructionError::ExecutableLamportChange);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Only the system program can change the size of the data
 | 
					
						
							|  |  |  |         //  and only if the system program owns the account
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |         if pre.data.len() != post.data.len()
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |             && (!system_program::check_id(program_id) // line coverage used to get branch coverage
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |                 || !system_program::check_id(&pre.owner))
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         {
 | 
					
						
							|  |  |  |             return Err(InstructionError::AccountDataSizeChanged);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         // Only the owner may change account data
 | 
					
						
							|  |  |  |         //   and if the account is writable
 | 
					
						
							|  |  |  |         //   and if the account is not executable
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |         if !(*program_id == pre.owner
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |             && self.is_writable  // line coverage used to get branch coverage
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |             && !pre.executable)
 | 
					
						
							|  |  |  |             && pre.data != post.data
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         {
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |             if pre.executable {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                 return Err(InstructionError::ExecutableDataModified);
 | 
					
						
							|  |  |  |             } else if self.is_writable {
 | 
					
						
							|  |  |  |                 return Err(InstructionError::ExternalAccountDataModified);
 | 
					
						
							|  |  |  |             } else {
 | 
					
						
							|  |  |  |                 return Err(InstructionError::ReadonlyDataModified);
 | 
					
						
							| 
									
										
										
										
											2019-10-25 21:47:16 -07:00
										 |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         // executable is one-way (false->true) and only the account owner may set it.
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |         if pre.executable != post.executable {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |             if !rent.is_exempt(post.lamports, post.data.len()) {
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |                 return Err(InstructionError::ExecutableAccountNotRentExempt);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |             if !self.is_writable // line coverage used to get branch coverage
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |                 || pre.executable
 | 
					
						
							|  |  |  |                 || *program_id != pre.owner
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |             {
 | 
					
						
							|  |  |  |                 return Err(InstructionError::ExecutableModified);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-22 11:10:04 -07:00
										 |  |  |         // No one modifies rent_epoch (yet).
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |         if pre.rent_epoch != post.rent_epoch {
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |             return Err(InstructionError::RentEpochModified);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         Ok(())
 | 
					
						
							| 
									
										
										
										
											2019-08-26 11:04:20 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     pub fn update(&mut self, account: &Account) {
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |         let mut pre = self.account.borrow_mut();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         pre.lamports = account.lamports;
 | 
					
						
							|  |  |  |         pre.owner = account.owner;
 | 
					
						
							|  |  |  |         if pre.data.len() != account.data.len() {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |             // Only system account can change data size, copy with alloc
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |             pre.data = account.data.clone();
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         } else {
 | 
					
						
							|  |  |  |             // Copy without allocate
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |             pre.data.clone_from_slice(&account.data);
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pub fn key(&self) -> Pubkey {
 | 
					
						
							|  |  |  |         self.key
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pub fn lamports(&self) -> u64 {
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |         self.account.borrow().lamports
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |     pub fn is_zeroed(buf: &[u8]) -> bool {
 | 
					
						
							|  |  |  |         const ZEROS_LEN: usize = 1024;
 | 
					
						
							|  |  |  |         static ZEROS: [u8; ZEROS_LEN] = [0; ZEROS_LEN];
 | 
					
						
							|  |  |  |         let mut chunks = buf.chunks_exact(ZEROS_LEN);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         chunks.all(|chunk| chunk == &ZEROS[..])
 | 
					
						
							|  |  |  |             && chunks.remainder() == &ZEROS[..chunks.remainder().len()]
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-02-18 23:26:22 -07:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:31:19 -07:00
										 |  |  | pub struct ThisComputeMeter {
 | 
					
						
							|  |  |  |     remaining: u64,
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | impl ComputeMeter for ThisComputeMeter {
 | 
					
						
							|  |  |  |     fn consume(&mut self, amount: u64) -> Result<(), InstructionError> {
 | 
					
						
							| 
									
										
										
										
											2020-09-25 11:08:10 -07:00
										 |  |  |         let exceeded = self.remaining < amount;
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:31:19 -07:00
										 |  |  |         self.remaining = self.remaining.saturating_sub(amount);
 | 
					
						
							| 
									
										
										
										
											2020-09-25 11:08:10 -07:00
										 |  |  |         if exceeded {
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:31:19 -07:00
										 |  |  |             return Err(InstructionError::ComputationalBudgetExceeded);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         Ok(())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     fn get_remaining(&self) -> u64 {
 | 
					
						
							|  |  |  |         self.remaining
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2020-10-29 09:57:14 -07:00
										 |  |  | pub struct ThisInvokeContext<'a> {
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  |     program_ids: Vec<Pubkey>,
 | 
					
						
							|  |  |  |     rent: Rent,
 | 
					
						
							|  |  |  |     pre_accounts: Vec<PreAccount>,
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |     account_deps: &'a [(Pubkey, RefCell<Account>)],
 | 
					
						
							| 
									
										
										
										
											2020-10-29 09:57:14 -07:00
										 |  |  |     programs: &'a [(Pubkey, ProcessInstructionWithContext)],
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  |     logger: Rc<RefCell<dyn Logger>>,
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |     bpf_compute_budget: BpfComputeBudget,
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:31:19 -07:00
										 |  |  |     compute_meter: Rc<RefCell<dyn ComputeMeter>>,
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |     executors: Rc<RefCell<Executors>>,
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |     instruction_recorder: Option<InstructionRecorder>,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 14:36:30 -07:00
										 |  |  |     feature_set: Arc<FeatureSet>,
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | }
 | 
					
						
							| 
									
										
										
										
											2020-10-29 09:57:14 -07:00
										 |  |  | impl<'a> ThisInvokeContext<'a> {
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |     #[allow(clippy::too_many_arguments)]
 | 
					
						
							| 
									
										
										
										
											2020-06-03 12:48:19 -07:00
										 |  |  |     pub fn new(
 | 
					
						
							|  |  |  |         program_id: &Pubkey,
 | 
					
						
							|  |  |  |         rent: Rent,
 | 
					
						
							|  |  |  |         pre_accounts: Vec<PreAccount>,
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |         account_deps: &'a [(Pubkey, RefCell<Account>)],
 | 
					
						
							| 
									
										
										
										
											2020-10-29 09:57:14 -07:00
										 |  |  |         programs: &'a [(Pubkey, ProcessInstructionWithContext)],
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  |         log_collector: Option<Rc<LogCollector>>,
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |         bpf_compute_budget: BpfComputeBudget,
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         executors: Rc<RefCell<Executors>>,
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |         instruction_recorder: Option<InstructionRecorder>,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 14:36:30 -07:00
										 |  |  |         feature_set: Arc<FeatureSet>,
 | 
					
						
							| 
									
										
										
										
											2020-06-03 12:48:19 -07:00
										 |  |  |     ) -> Self {
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |         let mut program_ids = Vec::with_capacity(bpf_compute_budget.max_invoke_depth);
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         program_ids.push(*program_id);
 | 
					
						
							|  |  |  |         Self {
 | 
					
						
							|  |  |  |             program_ids,
 | 
					
						
							|  |  |  |             rent,
 | 
					
						
							|  |  |  |             pre_accounts,
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |             account_deps,
 | 
					
						
							| 
									
										
										
										
											2020-06-03 12:48:19 -07:00
										 |  |  |             programs,
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  |             logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |             bpf_compute_budget,
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:31:19 -07:00
										 |  |  |             compute_meter: Rc::new(RefCell::new(ThisComputeMeter {
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |                 remaining: bpf_compute_budget.max_units,
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:31:19 -07:00
										 |  |  |             })),
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |             executors,
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |             instruction_recorder,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 14:36:30 -07:00
										 |  |  |             feature_set,
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2020-10-29 09:57:14 -07:00
										 |  |  | impl<'a> InvokeContext for ThisInvokeContext<'a> {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError> {
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |         if self.program_ids.len() > self.bpf_compute_budget.max_invoke_depth {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |             return Err(InstructionError::CallDepth);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         if self.program_ids.contains(key) && self.program_ids.last() != Some(key) {
 | 
					
						
							|  |  |  |             // Reentrancy not allowed unless caller is calling itself
 | 
					
						
							|  |  |  |             return Err(InstructionError::ReentrancyNotAllowed);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         self.program_ids.push(*key);
 | 
					
						
							|  |  |  |         Ok(())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     fn pop(&mut self) {
 | 
					
						
							|  |  |  |         self.program_ids.pop();
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-11-12 12:44:37 -08:00
										 |  |  |     fn invoke_depth(&self) -> usize {
 | 
					
						
							|  |  |  |         self.program_ids.len()
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     fn verify_and_update(
 | 
					
						
							|  |  |  |         &mut self,
 | 
					
						
							|  |  |  |         message: &Message,
 | 
					
						
							|  |  |  |         instruction: &CompiledInstruction,
 | 
					
						
							|  |  |  |         accounts: &[Rc<RefCell<Account>>],
 | 
					
						
							|  |  |  |     ) -> Result<(), InstructionError> {
 | 
					
						
							|  |  |  |         match self.program_ids.last() {
 | 
					
						
							|  |  |  |             Some(key) => MessageProcessor::verify_and_update(
 | 
					
						
							|  |  |  |                 message,
 | 
					
						
							|  |  |  |                 instruction,
 | 
					
						
							|  |  |  |                 &mut self.pre_accounts,
 | 
					
						
							| 
									
										
										
										
											2020-05-26 01:02:31 -07:00
										 |  |  |                 accounts,
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                 key,
 | 
					
						
							|  |  |  |                 &self.rent,
 | 
					
						
							|  |  |  |             ),
 | 
					
						
							|  |  |  |             None => Err(InstructionError::GenericError), // Should never happen
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-05-08 12:24:36 -07:00
										 |  |  |     fn get_caller(&self) -> Result<&Pubkey, InstructionError> {
 | 
					
						
							|  |  |  |         self.program_ids
 | 
					
						
							|  |  |  |             .last()
 | 
					
						
							|  |  |  |             .ok_or(InstructionError::GenericError)
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-10-28 20:21:50 -07:00
										 |  |  |     fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)] {
 | 
					
						
							| 
									
										
										
										
											2020-10-29 09:57:14 -07:00
										 |  |  |         self.programs
 | 
					
						
							| 
									
										
										
										
											2020-06-03 12:48:19 -07:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  |     fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
 | 
					
						
							|  |  |  |         self.logger.clone()
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |     fn get_bpf_compute_budget(&self) -> &BpfComputeBudget {
 | 
					
						
							|  |  |  |         &self.bpf_compute_budget
 | 
					
						
							| 
									
										
										
										
											2020-08-26 14:48:51 -07:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-08-21 15:31:19 -07:00
										 |  |  |     fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
 | 
					
						
							|  |  |  |         self.compute_meter.clone()
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-10-29 23:43:10 -07:00
										 |  |  |     fn add_executor(&self, pubkey: &Pubkey, executor: Arc<dyn Executor>) {
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         self.executors.borrow_mut().insert(*pubkey, executor);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-10-29 23:43:10 -07:00
										 |  |  |     fn get_executor(&self, pubkey: &Pubkey) -> Option<Arc<dyn Executor>> {
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         self.executors.borrow().get(&pubkey)
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |     fn record_instruction(&self, instruction: &Instruction) {
 | 
					
						
							|  |  |  |         if let Some(recorder) = &self.instruction_recorder {
 | 
					
						
							|  |  |  |             recorder.record_instruction(instruction.clone());
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-09-29 14:36:30 -07:00
										 |  |  |     fn is_feature_active(&self, feature_id: &Pubkey) -> bool {
 | 
					
						
							|  |  |  |         self.feature_set.is_active(feature_id)
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |     fn get_account(&self, pubkey: &Pubkey) -> Option<RefCell<Account>> {
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |         if let Some(account) = self.pre_accounts.iter().find_map(|pre| {
 | 
					
						
							|  |  |  |             if pre.key == *pubkey {
 | 
					
						
							|  |  |  |                 Some(pre.account.clone())
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |             } else {
 | 
					
						
							|  |  |  |                 None
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         }) {
 | 
					
						
							|  |  |  |             return Some(account);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |         self.account_deps.iter().find_map(|(key, account)| {
 | 
					
						
							|  |  |  |             if key == pubkey {
 | 
					
						
							|  |  |  |                 Some(account.clone())
 | 
					
						
							| 
									
										
										
										
											2020-12-18 11:23:00 -08:00
										 |  |  |             } else {
 | 
					
						
							|  |  |  |                 None
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         })
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  | }
 | 
					
						
							|  |  |  | pub struct ThisLogger {
 | 
					
						
							|  |  |  |     log_collector: Option<Rc<LogCollector>>,
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | impl Logger for ThisLogger {
 | 
					
						
							| 
									
										
										
										
											2020-06-06 10:18:28 -07:00
										 |  |  |     fn log_enabled(&self) -> bool {
 | 
					
						
							|  |  |  |         log_enabled!(log::Level::Info) || self.log_collector.is_some()
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-10-29 23:43:10 -07:00
										 |  |  |     fn log(&self, message: &str) {
 | 
					
						
							| 
									
										
										
										
											2020-11-12 12:44:37 -08:00
										 |  |  |         debug!("{}", message);
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  |         if let Some(log_collector) = &self.log_collector {
 | 
					
						
							| 
									
										
										
										
											2020-06-06 10:18:28 -07:00
										 |  |  |             log_collector.log(message);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-29 15:29:52 -07:00
										 |  |  | #[derive(Deserialize, Serialize)]
 | 
					
						
							| 
									
										
										
										
											2019-04-02 09:35:38 -06:00
										 |  |  | pub struct MessageProcessor {
 | 
					
						
							| 
									
										
										
										
											2019-05-30 21:31:35 -07:00
										 |  |  |     #[serde(skip)]
 | 
					
						
							| 
									
										
										
										
											2020-10-28 20:21:50 -07:00
										 |  |  |     programs: Vec<(Pubkey, ProcessInstructionWithContext)>,
 | 
					
						
							| 
									
										
										
										
											2019-05-30 21:31:35 -07:00
										 |  |  |     #[serde(skip)]
 | 
					
						
							| 
									
										
										
										
											2020-04-15 09:41:29 -07:00
										 |  |  |     native_loader: NativeLoader,
 | 
					
						
							| 
									
										
										
										
											2020-07-29 15:29:52 -07:00
										 |  |  | }
 | 
					
						
							| 
									
										
										
										
											2020-08-25 09:49:15 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | impl std::fmt::Debug for MessageProcessor {
 | 
					
						
							|  |  |  |     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 | 
					
						
							|  |  |  |         #[derive(Debug)]
 | 
					
						
							|  |  |  |         struct MessageProcessor<'a> {
 | 
					
						
							|  |  |  |             programs: Vec<String>,
 | 
					
						
							|  |  |  |             native_loader: &'a NativeLoader,
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-10-29 16:17:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // These are just type aliases for work around of Debug-ing above pointers
 | 
					
						
							|  |  |  |         type ErasedProcessInstructionWithContext = fn(
 | 
					
						
							|  |  |  |             &'static Pubkey,
 | 
					
						
							|  |  |  |             &'static [KeyedAccount<'static>],
 | 
					
						
							|  |  |  |             &'static [u8],
 | 
					
						
							|  |  |  |             &'static mut dyn InvokeContext,
 | 
					
						
							|  |  |  |         ) -> Result<(), InstructionError>;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-25 09:49:15 -07:00
										 |  |  |         // rustc doesn't compile due to bug without this work around
 | 
					
						
							|  |  |  |         // https://github.com/rust-lang/rust/issues/50280
 | 
					
						
							|  |  |  |         // https://users.rust-lang.org/t/display-function-pointer/17073/2
 | 
					
						
							|  |  |  |         let processor = MessageProcessor {
 | 
					
						
							|  |  |  |             programs: self
 | 
					
						
							|  |  |  |                 .programs
 | 
					
						
							|  |  |  |                 .iter()
 | 
					
						
							|  |  |  |                 .map(|(pubkey, instruction)| {
 | 
					
						
							| 
									
										
										
										
											2020-10-28 20:21:50 -07:00
										 |  |  |                     let erased_instruction: ErasedProcessInstructionWithContext = *instruction;
 | 
					
						
							| 
									
										
										
										
											2020-08-25 09:49:15 -07:00
										 |  |  |                     format!("{}: {:p}", pubkey, erased_instruction)
 | 
					
						
							|  |  |  |                 })
 | 
					
						
							|  |  |  |                 .collect::<Vec<_>>(),
 | 
					
						
							|  |  |  |             native_loader: &self.native_loader,
 | 
					
						
							|  |  |  |         };
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         write!(f, "{:?}", processor)
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-29 15:29:52 -07:00
										 |  |  | impl Default for MessageProcessor {
 | 
					
						
							|  |  |  |     fn default() -> Self {
 | 
					
						
							|  |  |  |         Self {
 | 
					
						
							|  |  |  |             programs: vec![],
 | 
					
						
							|  |  |  |             native_loader: NativeLoader::default(),
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-03-15 20:48:11 -06:00
										 |  |  | }
 | 
					
						
							| 
									
										
										
										
											2020-04-27 21:05:12 -07:00
										 |  |  | impl Clone for MessageProcessor {
 | 
					
						
							|  |  |  |     fn clone(&self) -> Self {
 | 
					
						
							|  |  |  |         MessageProcessor {
 | 
					
						
							| 
									
										
										
										
											2020-05-19 19:45:30 -07:00
										 |  |  |             programs: self.programs.clone(),
 | 
					
						
							| 
									
										
										
										
											2020-04-15 09:41:29 -07:00
										 |  |  |             native_loader: NativeLoader::default(),
 | 
					
						
							| 
									
										
										
										
											2019-03-16 17:20:09 -06:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2019-03-15 20:48:11 -06:00
										 |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2020-07-06 20:22:23 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | #[cfg(RUSTC_WITH_SPECIALIZATION)]
 | 
					
						
							| 
									
										
										
										
											2020-10-19 21:07:46 -07:00
										 |  |  | impl ::solana_frozen_abi::abi_example::AbiExample for MessageProcessor {
 | 
					
						
							| 
									
										
										
										
											2020-07-06 20:22:23 +09:00
										 |  |  |     fn example() -> Self {
 | 
					
						
							|  |  |  |         // MessageProcessor's fields are #[serde(skip)]-ed and not Serialize
 | 
					
						
							|  |  |  |         // so, just rely on Default anyway.
 | 
					
						
							|  |  |  |         MessageProcessor::default()
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-02 09:35:38 -06:00
										 |  |  | impl MessageProcessor {
 | 
					
						
							| 
									
										
										
										
											2019-07-31 14:28:14 -07:00
										 |  |  |     /// Add a static entrypoint to intercept instructions before the dynamic loader.
 | 
					
						
							| 
									
										
										
										
											2020-10-28 20:21:50 -07:00
										 |  |  |     pub fn add_program(
 | 
					
						
							|  |  |  |         &mut self,
 | 
					
						
							|  |  |  |         program_id: Pubkey,
 | 
					
						
							|  |  |  |         process_instruction: ProcessInstructionWithContext,
 | 
					
						
							|  |  |  |     ) {
 | 
					
						
							| 
									
										
										
										
											2020-05-19 19:45:30 -07:00
										 |  |  |         match self.programs.iter_mut().find(|(key, _)| program_id == *key) {
 | 
					
						
							| 
									
										
										
										
											2020-04-27 21:05:12 -07:00
										 |  |  |             Some((_, processor)) => *processor = process_instruction,
 | 
					
						
							| 
									
										
										
										
											2020-05-19 19:45:30 -07:00
										 |  |  |             None => self.programs.push((program_id, process_instruction)),
 | 
					
						
							| 
									
										
										
										
											2020-04-27 21:05:12 -07:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2019-03-07 13:42:01 -07:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-03-15 20:48:11 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 09:24:57 -07:00
										 |  |  |     pub fn add_loader(
 | 
					
						
							|  |  |  |         &mut self,
 | 
					
						
							|  |  |  |         program_id: Pubkey,
 | 
					
						
							|  |  |  |         process_instruction: ProcessInstructionWithContext,
 | 
					
						
							|  |  |  |     ) {
 | 
					
						
							| 
									
										
										
										
											2020-10-29 14:15:00 -07:00
										 |  |  |         self.add_program(program_id, process_instruction);
 | 
					
						
							| 
									
										
										
										
											2020-05-20 09:24:57 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     /// Create the KeyedAccounts that will be passed to the program
 | 
					
						
							|  |  |  |     fn create_keyed_accounts<'a>(
 | 
					
						
							|  |  |  |         message: &'a Message,
 | 
					
						
							|  |  |  |         instruction: &'a CompiledInstruction,
 | 
					
						
							|  |  |  |         executable_accounts: &'a [(Pubkey, RefCell<Account>)],
 | 
					
						
							|  |  |  |         accounts: &'a [Rc<RefCell<Account>>],
 | 
					
						
							| 
									
										
										
										
											2020-12-13 17:26:34 -08:00
										 |  |  |     ) -> Vec<KeyedAccount<'a>> {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         let mut keyed_accounts = create_keyed_readonly_accounts(&executable_accounts);
 | 
					
						
							| 
									
										
										
										
											2019-04-02 16:02:57 -06:00
										 |  |  |         let mut keyed_accounts2: Vec<_> = instruction
 | 
					
						
							| 
									
										
										
										
											2019-03-07 10:35:28 -07:00
										 |  |  |             .accounts
 | 
					
						
							|  |  |  |             .iter()
 | 
					
						
							|  |  |  |             .map(|&index| {
 | 
					
						
							| 
									
										
										
										
											2020-03-09 22:03:09 -07:00
										 |  |  |                 let is_signer = message.is_signer(index as usize);
 | 
					
						
							| 
									
										
										
										
											2019-03-07 10:35:28 -07:00
										 |  |  |                 let index = index as usize;
 | 
					
						
							| 
									
										
										
										
											2019-03-29 10:05:06 -06:00
										 |  |  |                 let key = &message.account_keys[index];
 | 
					
						
							| 
									
										
										
										
											2020-03-05 16:17:31 -08:00
										 |  |  |                 let account = &accounts[index];
 | 
					
						
							|  |  |  |                 if message.is_writable(index) {
 | 
					
						
							| 
									
										
										
										
											2019-06-27 17:25:10 -04:00
										 |  |  |                     KeyedAccount::new(key, is_signer, account)
 | 
					
						
							|  |  |  |                 } else {
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |                     KeyedAccount::new_readonly(key, is_signer, account)
 | 
					
						
							| 
									
										
										
										
											2019-06-27 17:25:10 -04:00
										 |  |  |                 }
 | 
					
						
							|  |  |  |             })
 | 
					
						
							| 
									
										
										
										
											2019-03-07 10:35:28 -07:00
										 |  |  |             .collect();
 | 
					
						
							| 
									
										
										
										
											2019-03-15 20:48:11 -06:00
										 |  |  |         keyed_accounts.append(&mut keyed_accounts2);
 | 
					
						
							| 
									
										
										
										
											2020-12-13 17:26:34 -08:00
										 |  |  |         keyed_accounts
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Process an instruction
 | 
					
						
							|  |  |  |     /// This method calls the instruction's program entrypoint method
 | 
					
						
							|  |  |  |     fn process_instruction(
 | 
					
						
							|  |  |  |         &self,
 | 
					
						
							| 
									
										
										
										
											2020-05-20 09:24:57 -07:00
										 |  |  |         keyed_accounts: &[KeyedAccount],
 | 
					
						
							|  |  |  |         instruction_data: &[u8],
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         invoke_context: &mut dyn InvokeContext,
 | 
					
						
							|  |  |  |     ) -> Result<(), InstructionError> {
 | 
					
						
							| 
									
										
										
										
											2020-10-12 13:40:04 -07:00
										 |  |  |         if let Some(root_account) = keyed_accounts.iter().next() {
 | 
					
						
							|  |  |  |             if native_loader::check_id(&root_account.owner()?) {
 | 
					
						
							|  |  |  |                 let root_id = root_account.unsigned_key();
 | 
					
						
							|  |  |  |                 for (id, process_instruction) in &self.programs {
 | 
					
						
							|  |  |  |                     if id == root_id {
 | 
					
						
							|  |  |  |                         // Call the builtin program
 | 
					
						
							|  |  |  |                         return process_instruction(
 | 
					
						
							|  |  |  |                             &root_id,
 | 
					
						
							|  |  |  |                             &keyed_accounts[1..],
 | 
					
						
							|  |  |  |                             instruction_data,
 | 
					
						
							| 
									
										
										
										
											2020-10-28 20:21:50 -07:00
										 |  |  |                             invoke_context,
 | 
					
						
							| 
									
										
										
										
											2020-10-12 13:40:04 -07:00
										 |  |  |                         );
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							| 
									
										
										
										
											2020-05-20 09:24:57 -07:00
										 |  |  |                 }
 | 
					
						
							| 
									
										
										
										
											2020-10-12 13:40:04 -07:00
										 |  |  |                 // Call the program via the native loader
 | 
					
						
							|  |  |  |                 return self.native_loader.process_instruction(
 | 
					
						
							|  |  |  |                     &native_loader::id(),
 | 
					
						
							|  |  |  |                     keyed_accounts,
 | 
					
						
							|  |  |  |                     instruction_data,
 | 
					
						
							|  |  |  |                     invoke_context,
 | 
					
						
							|  |  |  |                 );
 | 
					
						
							|  |  |  |             } else {
 | 
					
						
							|  |  |  |                 let owner_id = &root_account.owner()?;
 | 
					
						
							| 
									
										
										
										
											2020-10-29 14:15:00 -07:00
										 |  |  |                 for (id, process_instruction) in &self.programs {
 | 
					
						
							| 
									
										
										
										
											2020-10-12 13:40:04 -07:00
										 |  |  |                     if id == owner_id {
 | 
					
						
							|  |  |  |                         // Call the program via a builtin loader
 | 
					
						
							|  |  |  |                         return process_instruction(
 | 
					
						
							|  |  |  |                             &owner_id,
 | 
					
						
							|  |  |  |                             keyed_accounts,
 | 
					
						
							|  |  |  |                             instruction_data,
 | 
					
						
							|  |  |  |                             invoke_context,
 | 
					
						
							|  |  |  |                         );
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							| 
									
										
										
										
											2020-05-20 09:24:57 -07:00
										 |  |  |                 }
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2020-04-15 09:41:29 -07:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-05-20 09:24:57 -07:00
										 |  |  |         Err(InstructionError::UnsupportedProgramId)
 | 
					
						
							| 
									
										
										
										
											2019-03-15 20:48:11 -06:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-10 18:25:57 -08:00
										 |  |  |     /// Verify instruction against the caller
 | 
					
						
							|  |  |  |     pub fn verify_instruction(
 | 
					
						
							|  |  |  |         keyed_accounts: &[&KeyedAccount],
 | 
					
						
							|  |  |  |         instruction: &Instruction,
 | 
					
						
							|  |  |  |         signers: &[Pubkey],
 | 
					
						
							|  |  |  |     ) -> Result<(), InstructionError> {
 | 
					
						
							|  |  |  |         // Check for privilege escalation
 | 
					
						
							|  |  |  |         for account in instruction.accounts.iter() {
 | 
					
						
							|  |  |  |             let keyed_account = keyed_accounts
 | 
					
						
							|  |  |  |                 .iter()
 | 
					
						
							|  |  |  |                 .find_map(|keyed_account| {
 | 
					
						
							|  |  |  |                     if &account.pubkey == keyed_account.unsigned_key() {
 | 
					
						
							|  |  |  |                         Some(keyed_account)
 | 
					
						
							|  |  |  |                     } else {
 | 
					
						
							|  |  |  |                         None
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							|  |  |  |                 })
 | 
					
						
							|  |  |  |                 .ok_or(InstructionError::MissingAccount)?;
 | 
					
						
							|  |  |  |             // Readonly account cannot become writable
 | 
					
						
							|  |  |  |             if account.is_writable && !keyed_account.is_writable() {
 | 
					
						
							|  |  |  |                 return Err(InstructionError::PrivilegeEscalation);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if account.is_signer && // If message indicates account is signed
 | 
					
						
							|  |  |  |             !( // one of the following needs to be true:
 | 
					
						
							|  |  |  |                 keyed_account.signer_key().is_some() // Signed in the parent instruction
 | 
					
						
							|  |  |  |                 || signers.contains(&account.pubkey) // Signed by the program
 | 
					
						
							|  |  |  |             ) {
 | 
					
						
							|  |  |  |                 return Err(InstructionError::PrivilegeEscalation);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // validate the caller has access to the program account
 | 
					
						
							|  |  |  |         let _ = keyed_accounts
 | 
					
						
							|  |  |  |             .iter()
 | 
					
						
							|  |  |  |             .find_map(|keyed_account| {
 | 
					
						
							|  |  |  |                 if &instruction.program_id == keyed_account.unsigned_key() {
 | 
					
						
							|  |  |  |                     Some(keyed_account)
 | 
					
						
							|  |  |  |                 } else {
 | 
					
						
							|  |  |  |                     None
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							|  |  |  |             })
 | 
					
						
							|  |  |  |             .ok_or(InstructionError::MissingAccount)?;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Ok(())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pub fn create_message(
 | 
					
						
							|  |  |  |         instruction: &Instruction,
 | 
					
						
							|  |  |  |         keyed_accounts: &[&KeyedAccount],
 | 
					
						
							|  |  |  |         signers: &[Pubkey],
 | 
					
						
							| 
									
										
										
										
											2020-12-18 11:23:00 -08:00
										 |  |  |     ) -> Result<(Message, Pubkey), InstructionError> {
 | 
					
						
							| 
									
										
										
										
											2020-12-10 18:25:57 -08:00
										 |  |  |         // Check for privilege escalation
 | 
					
						
							|  |  |  |         for account in instruction.accounts.iter() {
 | 
					
						
							|  |  |  |             let keyed_account = keyed_accounts
 | 
					
						
							|  |  |  |                 .iter()
 | 
					
						
							|  |  |  |                 .find_map(|keyed_account| {
 | 
					
						
							|  |  |  |                     if &account.pubkey == keyed_account.unsigned_key() {
 | 
					
						
							|  |  |  |                         Some(keyed_account)
 | 
					
						
							|  |  |  |                     } else {
 | 
					
						
							|  |  |  |                         None
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							|  |  |  |                 })
 | 
					
						
							|  |  |  |                 .ok_or(InstructionError::MissingAccount)?;
 | 
					
						
							|  |  |  |             // Readonly account cannot become writable
 | 
					
						
							|  |  |  |             if account.is_writable && !keyed_account.is_writable() {
 | 
					
						
							|  |  |  |                 return Err(InstructionError::PrivilegeEscalation);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if account.is_signer && // If message indicates account is signed
 | 
					
						
							|  |  |  |             !( // one of the following needs to be true:
 | 
					
						
							|  |  |  |                 keyed_account.signer_key().is_some() // Signed in the parent instruction
 | 
					
						
							|  |  |  |                 || signers.contains(&account.pubkey) // Signed by the program
 | 
					
						
							|  |  |  |             ) {
 | 
					
						
							|  |  |  |                 return Err(InstructionError::PrivilegeEscalation);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // validate the caller has access to the program account
 | 
					
						
							|  |  |  |         let _ = keyed_accounts
 | 
					
						
							|  |  |  |             .iter()
 | 
					
						
							|  |  |  |             .find_map(|keyed_account| {
 | 
					
						
							|  |  |  |                 if &instruction.program_id == keyed_account.unsigned_key() {
 | 
					
						
							|  |  |  |                     Some(keyed_account)
 | 
					
						
							|  |  |  |                 } else {
 | 
					
						
							|  |  |  |                     None
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							|  |  |  |             })
 | 
					
						
							|  |  |  |             .ok_or(InstructionError::MissingAccount)?;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let message = Message::new(&[instruction.clone()], None);
 | 
					
						
							|  |  |  |         let id = *message
 | 
					
						
							|  |  |  |             .program_id(0)
 | 
					
						
							|  |  |  |             .ok_or(InstructionError::MissingAccount)?;
 | 
					
						
							| 
									
										
										
										
											2020-12-18 11:23:00 -08:00
										 |  |  |         Ok((message, id))
 | 
					
						
							| 
									
										
										
										
											2020-12-10 18:25:57 -08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 15:35:10 -08:00
										 |  |  |     /// Entrypoint for a cross-program invocation from a native program
 | 
					
						
							|  |  |  |     pub fn native_invoke(
 | 
					
						
							|  |  |  |         invoke_context: &mut dyn InvokeContext,
 | 
					
						
							|  |  |  |         instruction: Instruction,
 | 
					
						
							|  |  |  |         keyed_accounts: &[&KeyedAccount],
 | 
					
						
							|  |  |  |         signers_seeds: &[&[&[u8]]],
 | 
					
						
							|  |  |  |     ) -> Result<(), InstructionError> {
 | 
					
						
							|  |  |  |         let caller_program_id = invoke_context.get_caller()?;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Translate and verify caller's data
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let signers = signers_seeds
 | 
					
						
							|  |  |  |             .iter()
 | 
					
						
							|  |  |  |             .map(|seeds| Pubkey::create_program_address(&seeds, caller_program_id))
 | 
					
						
							|  |  |  |             .collect::<Result<Vec<_>, solana_sdk::pubkey::PubkeyError>>()?;
 | 
					
						
							| 
									
										
										
										
											2020-12-18 11:23:00 -08:00
										 |  |  |         let (message, callee_program_id) =
 | 
					
						
							| 
									
										
										
										
											2020-12-14 15:35:10 -08:00
										 |  |  |             Self::create_message(&instruction, &keyed_accounts, &signers)?;
 | 
					
						
							|  |  |  |         let mut accounts = vec![];
 | 
					
						
							|  |  |  |         let mut account_refs = vec![];
 | 
					
						
							|  |  |  |         'root: for account_key in message.account_keys.iter() {
 | 
					
						
							|  |  |  |             for keyed_account in keyed_accounts {
 | 
					
						
							|  |  |  |                 if account_key == keyed_account.unsigned_key() {
 | 
					
						
							|  |  |  |                     accounts.push(Rc::new(keyed_account.account.clone()));
 | 
					
						
							|  |  |  |                     account_refs.push(keyed_account);
 | 
					
						
							|  |  |  |                     continue 'root;
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |             return Err(InstructionError::MissingAccount);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Process instruction
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         invoke_context.record_instruction(&instruction);
 | 
					
						
							| 
									
										
										
										
											2020-12-18 11:23:00 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         let program_account = invoke_context
 | 
					
						
							|  |  |  |             .get_account(&callee_program_id)
 | 
					
						
							|  |  |  |             .ok_or(InstructionError::MissingAccount)?;
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |         if !program_account.borrow().executable {
 | 
					
						
							| 
									
										
										
										
											2020-12-14 15:35:10 -08:00
										 |  |  |             return Err(InstructionError::AccountNotExecutable);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |         let programdata_executable =
 | 
					
						
							|  |  |  |             if program_account.borrow().owner == bpf_loader_upgradeable::id() {
 | 
					
						
							|  |  |  |                 if let UpgradeableLoaderState::Program {
 | 
					
						
							|  |  |  |                     programdata_address,
 | 
					
						
							|  |  |  |                 } = program_account.borrow().state()?
 | 
					
						
							|  |  |  |                 {
 | 
					
						
							|  |  |  |                     if let Some(account) = invoke_context.get_account(&programdata_address) {
 | 
					
						
							|  |  |  |                         Some((programdata_address, account))
 | 
					
						
							|  |  |  |                     } else {
 | 
					
						
							|  |  |  |                         return Err(InstructionError::MissingAccount);
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							| 
									
										
										
										
											2020-12-18 11:23:00 -08:00
										 |  |  |                 } else {
 | 
					
						
							|  |  |  |                     return Err(InstructionError::MissingAccount);
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							|  |  |  |             } else {
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |                 None
 | 
					
						
							|  |  |  |             };
 | 
					
						
							|  |  |  |         let mut executable_accounts = vec![(callee_program_id, program_account)];
 | 
					
						
							| 
									
										
										
										
											2020-12-18 11:23:00 -08:00
										 |  |  |         if let Some(programdata) = programdata_executable {
 | 
					
						
							|  |  |  |             executable_accounts.push(programdata);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-12-14 15:35:10 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         MessageProcessor::process_cross_program_instruction(
 | 
					
						
							|  |  |  |             &message,
 | 
					
						
							|  |  |  |             &executable_accounts,
 | 
					
						
							|  |  |  |             &accounts,
 | 
					
						
							|  |  |  |             invoke_context,
 | 
					
						
							|  |  |  |         )?;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Copy results back to caller
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (i, (account, account_ref)) in accounts.iter().zip(account_refs).enumerate() {
 | 
					
						
							|  |  |  |             let account = account.borrow();
 | 
					
						
							|  |  |  |             if message.is_writable(i) && !account.executable {
 | 
					
						
							|  |  |  |                 account_ref.try_account_ref_mut()?.lamports = account.lamports;
 | 
					
						
							|  |  |  |                 account_ref.try_account_ref_mut()?.owner = account.owner;
 | 
					
						
							|  |  |  |                 if account_ref.data_len()? != account.data.len() && account_ref.data_len()? != 0 {
 | 
					
						
							|  |  |  |                     // Only support for `CreateAccount` at this time.
 | 
					
						
							|  |  |  |                     // Need a way to limit total realloc size across multiple CPI calls
 | 
					
						
							|  |  |  |                     return Err(InstructionError::InvalidRealloc);
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							|  |  |  |                 account_ref.try_account_ref_mut()?.data = account.data.clone();
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Ok(())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     /// Process a cross-program instruction
 | 
					
						
							| 
									
										
										
										
											2020-05-20 09:24:57 -07:00
										 |  |  |     /// This method calls the instruction's program entrypoint function
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     pub fn process_cross_program_instruction(
 | 
					
						
							|  |  |  |         message: &Message,
 | 
					
						
							|  |  |  |         executable_accounts: &[(Pubkey, RefCell<Account>)],
 | 
					
						
							|  |  |  |         accounts: &[Rc<RefCell<Account>>],
 | 
					
						
							|  |  |  |         invoke_context: &mut dyn InvokeContext,
 | 
					
						
							|  |  |  |     ) -> Result<(), InstructionError> {
 | 
					
						
							| 
									
										
										
										
											2020-10-12 13:40:04 -07:00
										 |  |  |         if let Some(instruction) = message.instructions.get(0) {
 | 
					
						
							|  |  |  |             // Verify the calling program hasn't misbehaved
 | 
					
						
							|  |  |  |             invoke_context.verify_and_update(message, instruction, accounts)?;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Construct keyed accounts
 | 
					
						
							|  |  |  |             let keyed_accounts =
 | 
					
						
							| 
									
										
										
										
											2020-12-13 17:26:34 -08:00
										 |  |  |                 Self::create_keyed_accounts(message, instruction, executable_accounts, accounts);
 | 
					
						
							| 
									
										
										
										
											2020-10-12 13:40:04 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // Invoke callee
 | 
					
						
							|  |  |  |             invoke_context.push(instruction.program_id(&message.account_keys))?;
 | 
					
						
							| 
									
										
										
										
											2020-10-30 01:10:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             let mut message_processor = MessageProcessor::default();
 | 
					
						
							|  |  |  |             for (program_id, process_instruction) in invoke_context.get_programs().iter() {
 | 
					
						
							|  |  |  |                 message_processor.add_program(*program_id, *process_instruction);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             let mut result = message_processor.process_instruction(
 | 
					
						
							|  |  |  |                 &keyed_accounts,
 | 
					
						
							|  |  |  |                 &instruction.data,
 | 
					
						
							|  |  |  |                 invoke_context,
 | 
					
						
							|  |  |  |             );
 | 
					
						
							| 
									
										
										
										
											2020-10-12 13:40:04 -07:00
										 |  |  |             if result.is_ok() {
 | 
					
						
							|  |  |  |                 // Verify the called program has not misbehaved
 | 
					
						
							|  |  |  |                 result = invoke_context.verify_and_update(message, instruction, accounts);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |             invoke_context.pop();
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-12 13:40:04 -07:00
										 |  |  |             result
 | 
					
						
							|  |  |  |         } else {
 | 
					
						
							|  |  |  |             // This function is always called with a valid instruction, if that changes return an error
 | 
					
						
							|  |  |  |             Err(InstructionError::GenericError)
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-05 16:17:31 -08:00
										 |  |  |     /// Record the initial state of the accounts so that they can be compared
 | 
					
						
							|  |  |  |     /// after the instruction is processed
 | 
					
						
							|  |  |  |     pub fn create_pre_accounts(
 | 
					
						
							|  |  |  |         message: &Message,
 | 
					
						
							|  |  |  |         instruction: &CompiledInstruction,
 | 
					
						
							|  |  |  |         accounts: &[Rc<RefCell<Account>>],
 | 
					
						
							|  |  |  |     ) -> Vec<PreAccount> {
 | 
					
						
							|  |  |  |         let mut pre_accounts = Vec::with_capacity(accounts.len());
 | 
					
						
							|  |  |  |         {
 | 
					
						
							|  |  |  |             let mut work = |_unique_index: usize, account_index: usize| {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                 let key = &message.account_keys[account_index];
 | 
					
						
							|  |  |  |                 let is_signer = account_index < message.header.num_required_signatures as usize;
 | 
					
						
							| 
									
										
										
										
											2020-03-05 16:17:31 -08:00
										 |  |  |                 let is_writable = message.is_writable(account_index);
 | 
					
						
							|  |  |  |                 let account = accounts[account_index].borrow();
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                 pre_accounts.push(PreAccount::new(key, &account, is_signer, is_writable));
 | 
					
						
							| 
									
										
										
										
											2020-03-05 16:17:31 -08:00
										 |  |  |                 Ok(())
 | 
					
						
							|  |  |  |             };
 | 
					
						
							| 
									
										
										
										
											2020-03-12 09:08:39 -07:00
										 |  |  |             let _ = instruction.visit_each_account(&mut work);
 | 
					
						
							| 
									
										
										
										
											2020-02-21 13:28:35 -08:00
										 |  |  |         }
 | 
					
						
							|  |  |  |         pre_accounts
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Verify there are no outstanding borrows
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |     pub fn verify_account_references(
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         accounts: &[(Pubkey, RefCell<Account>)],
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |     ) -> Result<(), InstructionError> {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         for (_, account) in accounts.iter() {
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |             account
 | 
					
						
							|  |  |  |                 .try_borrow_mut()
 | 
					
						
							|  |  |  |                 .map_err(|_| InstructionError::AccountBorrowOutstanding)?;
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         Ok(())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-21 13:28:35 -08:00
										 |  |  |     /// Verify the results of an instruction
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |     pub fn verify(
 | 
					
						
							| 
									
										
										
										
											2020-02-21 13:28:35 -08:00
										 |  |  |         message: &Message,
 | 
					
						
							|  |  |  |         instruction: &CompiledInstruction,
 | 
					
						
							| 
									
										
										
										
											2020-03-05 16:17:31 -08:00
										 |  |  |         pre_accounts: &[PreAccount],
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         executable_accounts: &[(Pubkey, RefCell<Account>)],
 | 
					
						
							| 
									
										
										
										
											2020-03-05 16:17:31 -08:00
										 |  |  |         accounts: &[Rc<RefCell<Account>>],
 | 
					
						
							| 
									
										
										
										
											2020-05-26 01:02:31 -07:00
										 |  |  |         rent: &Rent,
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |     ) -> Result<(), InstructionError> {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         // Verify all executable accounts have zero outstanding refs
 | 
					
						
							|  |  |  |         Self::verify_account_references(executable_accounts)?;
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Verify the per-account instruction results
 | 
					
						
							|  |  |  |         let (mut pre_sum, mut post_sum) = (0_u128, 0_u128);
 | 
					
						
							| 
									
										
										
										
											2020-03-05 16:17:31 -08:00
										 |  |  |         {
 | 
					
						
							|  |  |  |             let program_id = instruction.program_id(&message.account_keys);
 | 
					
						
							|  |  |  |             let mut work = |unique_index: usize, account_index: usize| {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                 // Verify account has no outstanding references and take one
 | 
					
						
							|  |  |  |                 let account = accounts[account_index]
 | 
					
						
							|  |  |  |                     .try_borrow_mut()
 | 
					
						
							|  |  |  |                     .map_err(|_| InstructionError::AccountBorrowOutstanding)?;
 | 
					
						
							| 
									
										
										
										
											2020-05-26 01:02:31 -07:00
										 |  |  |                 pre_accounts[unique_index].verify(&program_id, rent, &account)?;
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                 pre_sum += u128::from(pre_accounts[unique_index].lamports());
 | 
					
						
							| 
									
										
										
										
											2020-02-21 13:28:35 -08:00
										 |  |  |                 post_sum += u128::from(account.lamports);
 | 
					
						
							| 
									
										
										
										
											2020-03-05 16:17:31 -08:00
										 |  |  |                 Ok(())
 | 
					
						
							|  |  |  |             };
 | 
					
						
							| 
									
										
										
										
											2020-03-12 09:08:39 -07:00
										 |  |  |             instruction.visit_each_account(&mut work)?;
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Verify that the total sum of all the lamports did not change
 | 
					
						
							|  |  |  |         if pre_sum != post_sum {
 | 
					
						
							|  |  |  |             return Err(InstructionError::UnbalancedInstruction);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         Ok(())
 | 
					
						
							| 
									
										
										
										
											2019-11-05 10:57:32 -08:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     /// Verify the results of a cross-program instruction
 | 
					
						
							|  |  |  |     fn verify_and_update(
 | 
					
						
							|  |  |  |         message: &Message,
 | 
					
						
							|  |  |  |         instruction: &CompiledInstruction,
 | 
					
						
							|  |  |  |         pre_accounts: &mut [PreAccount],
 | 
					
						
							| 
									
										
										
										
											2020-05-26 01:02:31 -07:00
										 |  |  |         accounts: &[Rc<RefCell<Account>>],
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         program_id: &Pubkey,
 | 
					
						
							|  |  |  |         rent: &Rent,
 | 
					
						
							|  |  |  |     ) -> Result<(), InstructionError> {
 | 
					
						
							|  |  |  |         // Verify the per-account instruction results
 | 
					
						
							|  |  |  |         let (mut pre_sum, mut post_sum) = (0_u128, 0_u128);
 | 
					
						
							|  |  |  |         let mut work = |_unique_index: usize, account_index: usize| {
 | 
					
						
							| 
									
										
										
										
											2020-11-29 02:06:43 -08:00
										 |  |  |             if account_index < message.account_keys.len() && account_index < accounts.len() {
 | 
					
						
							|  |  |  |                 let key = &message.account_keys[account_index];
 | 
					
						
							|  |  |  |                 let account = &accounts[account_index];
 | 
					
						
							|  |  |  |                 // Find the matching PreAccount
 | 
					
						
							|  |  |  |                 for pre_account in pre_accounts.iter_mut() {
 | 
					
						
							|  |  |  |                     if *key == pre_account.key() {
 | 
					
						
							|  |  |  |                         // Verify account has no outstanding references and take one
 | 
					
						
							|  |  |  |                         let account = account
 | 
					
						
							|  |  |  |                             .try_borrow_mut()
 | 
					
						
							|  |  |  |                             .map_err(|_| InstructionError::AccountBorrowOutstanding)?;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         pre_account.verify(&program_id, &rent, &account)?;
 | 
					
						
							|  |  |  |                         pre_sum += u128::from(pre_account.lamports());
 | 
					
						
							|  |  |  |                         post_sum += u128::from(account.lamports);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         pre_account.update(&account);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         return Ok(());
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                 }
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |             Err(InstructionError::MissingAccount)
 | 
					
						
							|  |  |  |         };
 | 
					
						
							|  |  |  |         instruction.visit_each_account(&mut work)?;
 | 
					
						
							| 
									
										
										
										
											2020-11-29 02:06:43 -08:00
										 |  |  |         work(0, instruction.program_id_index as usize)?;
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Verify that the total sum of all the lamports did not change
 | 
					
						
							|  |  |  |         if pre_sum != post_sum {
 | 
					
						
							|  |  |  |             return Err(InstructionError::UnbalancedInstruction);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         Ok(())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-15 20:48:11 -06:00
										 |  |  |     /// Execute an instruction
 | 
					
						
							|  |  |  |     /// This method calls the instruction's program entrypoint method and verifies that the result of
 | 
					
						
							|  |  |  |     /// the call does not violate the bank's accounting rules.
 | 
					
						
							|  |  |  |     /// The accounts are committed back to the bank only if this function returns Ok(_).
 | 
					
						
							| 
									
										
										
										
											2020-09-20 10:58:12 -07:00
										 |  |  |     #[allow(clippy::too_many_arguments)]
 | 
					
						
							| 
									
										
										
										
											2019-03-15 20:48:11 -06:00
										 |  |  |     fn execute_instruction(
 | 
					
						
							|  |  |  |         &self,
 | 
					
						
							| 
									
										
										
										
											2019-03-29 10:05:06 -06:00
										 |  |  |         message: &Message,
 | 
					
						
							| 
									
										
										
										
											2019-04-02 16:02:57 -06:00
										 |  |  |         instruction: &CompiledInstruction,
 | 
					
						
							| 
									
										
										
										
											2020-01-22 17:54:06 -08:00
										 |  |  |         executable_accounts: &[(Pubkey, RefCell<Account>)],
 | 
					
						
							| 
									
										
										
										
											2020-03-05 16:17:31 -08:00
										 |  |  |         accounts: &[Rc<RefCell<Account>>],
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |         account_deps: &[(Pubkey, RefCell<Account>)],
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |         rent_collector: &RentCollector,
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  |         log_collector: Option<Rc<LogCollector>>,
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         executors: Rc<RefCell<Executors>>,
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |         instruction_recorder: Option<InstructionRecorder>,
 | 
					
						
							| 
									
										
										
										
											2020-09-19 12:17:46 -07:00
										 |  |  |         instruction_index: usize,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 14:36:30 -07:00
										 |  |  |         feature_set: Arc<FeatureSet>,
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |         bpf_compute_budget: BpfComputeBudget,
 | 
					
						
							| 
									
										
										
										
											2019-03-15 20:48:11 -06:00
										 |  |  |     ) -> Result<(), InstructionError> {
 | 
					
						
							| 
									
										
										
										
											2020-09-19 12:17:46 -07:00
										 |  |  |         // Fixup the special instructions key if present
 | 
					
						
							|  |  |  |         // before the account pre-values are taken care of
 | 
					
						
							| 
									
										
										
										
											2020-09-29 14:36:30 -07:00
										 |  |  |         if feature_set.is_active(&instructions_sysvar_enabled::id()) {
 | 
					
						
							| 
									
										
										
										
											2020-09-20 10:58:12 -07:00
										 |  |  |             for (i, key) in message.account_keys.iter().enumerate() {
 | 
					
						
							|  |  |  |                 if solana_sdk::sysvar::instructions::check_id(key) {
 | 
					
						
							|  |  |  |                     let mut mut_account_ref = accounts[i].borrow_mut();
 | 
					
						
							|  |  |  |                     solana_sdk::sysvar::instructions::store_current_index(
 | 
					
						
							|  |  |  |                         &mut mut_account_ref.data,
 | 
					
						
							|  |  |  |                         instruction_index as u16,
 | 
					
						
							|  |  |  |                     );
 | 
					
						
							|  |  |  |                     break;
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							| 
									
										
										
										
											2020-09-19 12:17:46 -07:00
										 |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-05 16:17:31 -08:00
										 |  |  |         let pre_accounts = Self::create_pre_accounts(message, instruction, accounts);
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         let mut invoke_context = ThisInvokeContext::new(
 | 
					
						
							|  |  |  |             instruction.program_id(&message.account_keys),
 | 
					
						
							|  |  |  |             rent_collector.rent,
 | 
					
						
							|  |  |  |             pre_accounts,
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |             account_deps,
 | 
					
						
							| 
									
										
										
										
											2020-10-29 09:57:14 -07:00
										 |  |  |             &self.programs,
 | 
					
						
							| 
									
										
										
										
											2020-06-06 10:18:28 -07:00
										 |  |  |             log_collector,
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |             bpf_compute_budget,
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |             executors,
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |             instruction_recorder,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 14:36:30 -07:00
										 |  |  |             feature_set,
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-05-20 09:24:57 -07:00
										 |  |  |         let keyed_accounts =
 | 
					
						
							| 
									
										
										
										
											2020-12-13 17:26:34 -08:00
										 |  |  |             Self::create_keyed_accounts(message, instruction, executable_accounts, accounts);
 | 
					
						
							| 
									
										
										
										
											2020-05-20 09:24:57 -07:00
										 |  |  |         self.process_instruction(&keyed_accounts, &instruction.data, &mut invoke_context)?;
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         Self::verify(
 | 
					
						
							| 
									
										
										
										
											2020-02-21 13:28:35 -08:00
										 |  |  |             message,
 | 
					
						
							|  |  |  |             instruction,
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |             &invoke_context.pre_accounts,
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |             executable_accounts,
 | 
					
						
							| 
									
										
										
										
											2020-03-05 16:17:31 -08:00
										 |  |  |             accounts,
 | 
					
						
							| 
									
										
										
										
											2020-05-26 01:02:31 -07:00
										 |  |  |             &rent_collector.rent,
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         )?;
 | 
					
						
							| 
									
										
										
										
											2019-03-15 20:48:11 -06:00
										 |  |  |         Ok(())
 | 
					
						
							| 
									
										
										
										
											2019-03-07 10:35:28 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-29 10:05:06 -06:00
										 |  |  |     /// Process a message.
 | 
					
						
							|  |  |  |     /// This method calls each instruction in the message over the set of loaded Accounts
 | 
					
						
							| 
									
										
										
										
											2019-03-15 20:48:11 -06:00
										 |  |  |     /// The accounts are committed back to the bank only if every instruction succeeds
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |     #[allow(clippy::too_many_arguments)]
 | 
					
						
							| 
									
										
										
										
											2019-03-29 10:05:06 -06:00
										 |  |  |     pub fn process_message(
 | 
					
						
							| 
									
										
										
										
											2019-03-15 20:48:11 -06:00
										 |  |  |         &self,
 | 
					
						
							| 
									
										
										
										
											2019-03-29 10:05:06 -06:00
										 |  |  |         message: &Message,
 | 
					
						
							| 
									
										
										
										
											2020-01-22 17:54:06 -08:00
										 |  |  |         loaders: &[Vec<(Pubkey, RefCell<Account>)>],
 | 
					
						
							|  |  |  |         accounts: &[Rc<RefCell<Account>>],
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |         account_deps: &[(Pubkey, RefCell<Account>)],
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |         rent_collector: &RentCollector,
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  |         log_collector: Option<Rc<LogCollector>>,
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         executors: Rc<RefCell<Executors>>,
 | 
					
						
							| 
									
										
										
										
											2020-09-25 20:42:28 +08:00
										 |  |  |         instruction_recorders: Option<&[InstructionRecorder]>,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 14:36:30 -07:00
										 |  |  |         feature_set: Arc<FeatureSet>,
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |         bpf_compute_budget: BpfComputeBudget,
 | 
					
						
							| 
									
										
										
										
											2019-03-15 20:48:11 -06:00
										 |  |  |     ) -> Result<(), TransactionError> {
 | 
					
						
							| 
									
										
										
										
											2019-03-29 10:05:06 -06:00
										 |  |  |         for (instruction_index, instruction) in message.instructions.iter().enumerate() {
 | 
					
						
							| 
									
										
										
										
											2020-09-25 20:42:28 +08:00
										 |  |  |             let instruction_recorder = instruction_recorders
 | 
					
						
							|  |  |  |                 .as_ref()
 | 
					
						
							|  |  |  |                 .map(|recorders| recorders[instruction_index].clone());
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |             self.execute_instruction(
 | 
					
						
							|  |  |  |                 message,
 | 
					
						
							|  |  |  |                 instruction,
 | 
					
						
							| 
									
										
										
										
											2020-06-03 21:16:15 -07:00
										 |  |  |                 &loaders[instruction_index],
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |                 accounts,
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |                 account_deps,
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |                 rent_collector,
 | 
					
						
							| 
									
										
										
										
											2020-06-13 13:20:08 -07:00
										 |  |  |                 log_collector.clone(),
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |                 executors.clone(),
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |                 instruction_recorder,
 | 
					
						
							| 
									
										
										
										
											2020-09-19 12:17:46 -07:00
										 |  |  |                 instruction_index,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 14:36:30 -07:00
										 |  |  |                 feature_set.clone(),
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |                 bpf_compute_budget,
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |             )
 | 
					
						
							|  |  |  |             .map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
 | 
					
						
							| 
									
										
										
										
											2019-03-11 16:35:25 -06:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2019-03-15 20:48:11 -06:00
										 |  |  |         Ok(())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-03-11 16:35:25 -06:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 23:26:22 -07:00
										 |  |  | #[cfg(test)]
 | 
					
						
							|  |  |  | mod tests {
 | 
					
						
							|  |  |  |     use super::*;
 | 
					
						
							| 
									
										
										
										
											2020-01-28 17:03:20 -08:00
										 |  |  |     use solana_sdk::{
 | 
					
						
							|  |  |  |         instruction::{AccountMeta, Instruction, InstructionError},
 | 
					
						
							|  |  |  |         message::Message,
 | 
					
						
							|  |  |  |         native_loader::create_loadable_account,
 | 
					
						
							|  |  |  |     };
 | 
					
						
							| 
									
										
										
										
											2019-02-18 23:26:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_invoke_context() {
 | 
					
						
							|  |  |  |         const MAX_DEPTH: usize = 10;
 | 
					
						
							|  |  |  |         let mut program_ids = vec![];
 | 
					
						
							|  |  |  |         let mut keys = vec![];
 | 
					
						
							|  |  |  |         let mut pre_accounts = vec![];
 | 
					
						
							|  |  |  |         let mut accounts = vec![];
 | 
					
						
							|  |  |  |         for i in 0..MAX_DEPTH {
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |             program_ids.push(solana_sdk::pubkey::new_rand());
 | 
					
						
							|  |  |  |             keys.push(solana_sdk::pubkey::new_rand());
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |             accounts.push(Rc::new(RefCell::new(Account::new(
 | 
					
						
							|  |  |  |                 i as u64,
 | 
					
						
							|  |  |  |                 1,
 | 
					
						
							|  |  |  |                 &program_ids[i],
 | 
					
						
							|  |  |  |             ))));
 | 
					
						
							|  |  |  |             pre_accounts.push(PreAccount::new(
 | 
					
						
							|  |  |  |                 &keys[i],
 | 
					
						
							|  |  |  |                 &accounts[i].borrow(),
 | 
					
						
							|  |  |  |                 false,
 | 
					
						
							|  |  |  |                 true,
 | 
					
						
							|  |  |  |             ))
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-11-29 02:06:43 -08:00
										 |  |  |         let account = Account::new(1, 1, &solana_sdk::pubkey::Pubkey::default());
 | 
					
						
							|  |  |  |         for program_id in program_ids.iter() {
 | 
					
						
							|  |  |  |             pre_accounts.push(PreAccount::new(program_id, &account.clone(), false, true));
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-29 15:29:52 -07:00
										 |  |  |         let mut invoke_context = ThisInvokeContext::new(
 | 
					
						
							|  |  |  |             &program_ids[0],
 | 
					
						
							|  |  |  |             Rent::default(),
 | 
					
						
							|  |  |  |             pre_accounts,
 | 
					
						
							| 
									
										
										
										
											2020-10-29 09:57:14 -07:00
										 |  |  |             &[],
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |             &[],
 | 
					
						
							| 
									
										
										
										
											2020-07-29 15:29:52 -07:00
										 |  |  |             None,
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |             BpfComputeBudget::default(),
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |             Rc::new(RefCell::new(Executors::default())),
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |             None,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 20:18:28 -07:00
										 |  |  |             Arc::new(FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-07-29 15:29:52 -07:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Check call depth increases and has a limit
 | 
					
						
							|  |  |  |         let mut depth_reached = 1;
 | 
					
						
							| 
									
										
										
										
											2020-05-15 17:35:43 +01:00
										 |  |  |         for program_id in program_ids.iter().skip(1) {
 | 
					
						
							|  |  |  |             if Err(InstructionError::CallDepth) == invoke_context.push(program_id) {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                 break;
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |             depth_reached += 1;
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         assert_ne!(depth_reached, 0);
 | 
					
						
							|  |  |  |         assert!(depth_reached < MAX_DEPTH);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Mock each invocation
 | 
					
						
							|  |  |  |         for owned_index in (1..depth_reached).rev() {
 | 
					
						
							|  |  |  |             let not_owned_index = owned_index - 1;
 | 
					
						
							|  |  |  |             let metas = vec![
 | 
					
						
							|  |  |  |                 AccountMeta::new(keys[not_owned_index], false),
 | 
					
						
							|  |  |  |                 AccountMeta::new(keys[owned_index], false),
 | 
					
						
							|  |  |  |             ];
 | 
					
						
							| 
									
										
										
										
											2020-06-24 14:52:38 -06:00
										 |  |  |             let message = Message::new(
 | 
					
						
							| 
									
										
										
										
											2020-05-15 13:23:09 -06:00
										 |  |  |                 &[Instruction::new(program_ids[owned_index], &[0_u8], metas)],
 | 
					
						
							|  |  |  |                 None,
 | 
					
						
							|  |  |  |             );
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // modify account owned by the program
 | 
					
						
							|  |  |  |             accounts[owned_index].borrow_mut().data[0] = (MAX_DEPTH + owned_index) as u8;
 | 
					
						
							| 
									
										
										
										
											2020-12-13 17:26:34 -08:00
										 |  |  |             let mut these_accounts = accounts[not_owned_index..owned_index + 1].to_vec();
 | 
					
						
							| 
									
										
										
										
											2020-11-29 02:06:43 -08:00
										 |  |  |             these_accounts.push(Rc::new(RefCell::new(Account::new(
 | 
					
						
							|  |  |  |                 1,
 | 
					
						
							|  |  |  |                 1,
 | 
					
						
							|  |  |  |                 &solana_sdk::pubkey::Pubkey::default(),
 | 
					
						
							|  |  |  |             ))));
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |             invoke_context
 | 
					
						
							| 
									
										
										
										
											2020-11-29 02:06:43 -08:00
										 |  |  |                 .verify_and_update(&message, &message.instructions[0], &these_accounts)
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                 .unwrap();
 | 
					
						
							|  |  |  |             assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |                 invoke_context.pre_accounts[owned_index]
 | 
					
						
							|  |  |  |                     .account
 | 
					
						
							|  |  |  |                     .borrow()
 | 
					
						
							|  |  |  |                     .data[0],
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                 (MAX_DEPTH + owned_index) as u8
 | 
					
						
							|  |  |  |             );
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // modify account not owned by the program
 | 
					
						
							|  |  |  |             let data = accounts[not_owned_index].borrow_mut().data[0];
 | 
					
						
							|  |  |  |             accounts[not_owned_index].borrow_mut().data[0] = (MAX_DEPTH + not_owned_index) as u8;
 | 
					
						
							|  |  |  |             assert_eq!(
 | 
					
						
							|  |  |  |                 invoke_context.verify_and_update(
 | 
					
						
							|  |  |  |                     &message,
 | 
					
						
							|  |  |  |                     &message.instructions[0],
 | 
					
						
							|  |  |  |                     &accounts[not_owned_index..owned_index + 1],
 | 
					
						
							|  |  |  |                 ),
 | 
					
						
							|  |  |  |                 Err(InstructionError::ExternalAccountDataModified)
 | 
					
						
							|  |  |  |             );
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |             assert_eq!(
 | 
					
						
							|  |  |  |                 invoke_context.pre_accounts[not_owned_index]
 | 
					
						
							|  |  |  |                     .account
 | 
					
						
							|  |  |  |                     .borrow()
 | 
					
						
							|  |  |  |                     .data[0],
 | 
					
						
							|  |  |  |                 data
 | 
					
						
							|  |  |  |             );
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |             accounts[not_owned_index].borrow_mut().data[0] = data;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             invoke_context.pop();
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_is_zeroed() {
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         const ZEROS_LEN: usize = 1024;
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |         let mut buf = [0; ZEROS_LEN];
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         assert_eq!(PreAccount::is_zeroed(&buf), true);
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |         buf[0] = 1;
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         assert_eq!(PreAccount::is_zeroed(&buf), false);
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         let mut buf = [0; ZEROS_LEN - 1];
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         assert_eq!(PreAccount::is_zeroed(&buf), true);
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |         buf[0] = 1;
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         assert_eq!(PreAccount::is_zeroed(&buf), false);
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         let mut buf = [0; ZEROS_LEN + 1];
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         assert_eq!(PreAccount::is_zeroed(&buf), true);
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |         buf[0] = 1;
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         assert_eq!(PreAccount::is_zeroed(&buf), false);
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         let buf = vec![];
 | 
					
						
							| 
									
										
										
										
											2020-02-21 11:30:00 -08:00
										 |  |  |         assert_eq!(PreAccount::is_zeroed(&buf), true);
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 23:26:22 -07:00
										 |  |  |     #[test]
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |     fn test_verify_account_references() {
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:23:14 -07:00
										 |  |  |         let accounts = vec![(
 | 
					
						
							|  |  |  |             solana_sdk::pubkey::new_rand(),
 | 
					
						
							|  |  |  |             RefCell::new(Account::default()),
 | 
					
						
							|  |  |  |         )];
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         assert!(MessageProcessor::verify_account_references(&accounts).is_ok());
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         let mut _borrowed = accounts[0].1.borrow();
 | 
					
						
							| 
									
										
										
										
											2020-01-22 17:54:06 -08:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |             MessageProcessor::verify_account_references(&accounts),
 | 
					
						
							| 
									
										
										
										
											2020-01-22 17:54:06 -08:00
										 |  |  |             Err(InstructionError::AccountBorrowOutstanding)
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-02-18 23:26:22 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-26 01:02:31 -07:00
										 |  |  |     struct Change {
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |         program_id: Pubkey,
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         rent: Rent,
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |         pre: PreAccount,
 | 
					
						
							|  |  |  |         post: Account,
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-05-26 01:02:31 -07:00
										 |  |  |     impl Change {
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |         pub fn new(owner: &Pubkey, program_id: &Pubkey) -> Self {
 | 
					
						
							|  |  |  |             Self {
 | 
					
						
							|  |  |  |                 program_id: *program_id,
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                 rent: Rent::default(),
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |                 pre: PreAccount::new(
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |                     &solana_sdk::pubkey::new_rand(),
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |                     &Account {
 | 
					
						
							|  |  |  |                         owner: *owner,
 | 
					
						
							|  |  |  |                         lamports: std::u64::MAX,
 | 
					
						
							|  |  |  |                         data: vec![],
 | 
					
						
							|  |  |  |                         ..Account::default()
 | 
					
						
							|  |  |  |                     },
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                     false,
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |                     true,
 | 
					
						
							|  |  |  |                 ),
 | 
					
						
							|  |  |  |                 post: Account {
 | 
					
						
							|  |  |  |                     owner: *owner,
 | 
					
						
							|  |  |  |                     lamports: std::u64::MAX,
 | 
					
						
							|  |  |  |                     ..Account::default()
 | 
					
						
							|  |  |  |                 },
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         pub fn read_only(mut self) -> Self {
 | 
					
						
							|  |  |  |             self.pre.is_writable = false;
 | 
					
						
							|  |  |  |             self
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         pub fn executable(mut self, pre: bool, post: bool) -> Self {
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |             self.pre.account.borrow_mut().executable = pre;
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             self.post.executable = post;
 | 
					
						
							|  |  |  |             self
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         pub fn lamports(mut self, pre: u64, post: u64) -> Self {
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |             self.pre.account.borrow_mut().lamports = pre;
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             self.post.lamports = post;
 | 
					
						
							|  |  |  |             self
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         pub fn owner(mut self, post: &Pubkey) -> Self {
 | 
					
						
							|  |  |  |             self.post.owner = *post;
 | 
					
						
							|  |  |  |             self
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         pub fn data(mut self, pre: Vec<u8>, post: Vec<u8>) -> Self {
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |             self.pre.account.borrow_mut().data = pre;
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             self.post.data = post;
 | 
					
						
							|  |  |  |             self
 | 
					
						
							| 
									
										
										
										
											2019-02-22 13:08:54 -07:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |         pub fn rent_epoch(mut self, pre: u64, post: u64) -> Self {
 | 
					
						
							| 
									
										
										
										
											2020-12-23 19:35:09 +00:00
										 |  |  |             self.pre.account.borrow_mut().rent_epoch = pre;
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             self.post.rent_epoch = post;
 | 
					
						
							|  |  |  |             self
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         pub fn verify(&self) -> Result<(), InstructionError> {
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |             self.pre.verify(&self.program_id, &self.rent, &self.post)
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-02-22 13:08:54 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_verify_account_changes_owner() {
 | 
					
						
							| 
									
										
										
										
											2019-02-22 13:08:54 -07:00
										 |  |  |         let system_program_id = system_program::id();
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let alice_program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							|  |  |  |         let mallory_program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2019-02-22 13:08:54 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&system_program_id, &system_program_id)
 | 
					
						
							|  |  |  |                 .owner(&alice_program_id)
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-02-22 13:08:54 -07:00
										 |  |  |             Ok(()),
 | 
					
						
							|  |  |  |             "system program should be able to change the account owner"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&system_program_id, &system_program_id)
 | 
					
						
							|  |  |  |                 .owner(&alice_program_id)
 | 
					
						
							|  |  |  |                 .read_only()
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |             Err(InstructionError::ModifiedProgramId),
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |             "system program should not be able to change the account owner of a read-only account"
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&mallory_program_id, &system_program_id)
 | 
					
						
							|  |  |  |                 .owner(&alice_program_id)
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |             Err(InstructionError::ModifiedProgramId),
 | 
					
						
							|  |  |  |             "system program should not be able to change the account owner of a non-system account"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&mallory_program_id, &mallory_program_id)
 | 
					
						
							|  |  |  |                 .owner(&alice_program_id)
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |             Ok(()),
 | 
					
						
							|  |  |  |             "mallory should be able to change the account owner, if she leaves clear data"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&mallory_program_id, &mallory_program_id)
 | 
					
						
							|  |  |  |                 .owner(&alice_program_id)
 | 
					
						
							|  |  |  |                 .data(vec![42], vec![0])
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |             Ok(()),
 | 
					
						
							|  |  |  |             "mallory should be able to change the account owner, if she leaves clear data"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-12-07 11:37:07 -08:00
										 |  |  |         assert_eq!(
 | 
					
						
							|  |  |  |             Change::new(&mallory_program_id, &mallory_program_id)
 | 
					
						
							|  |  |  |                 .owner(&alice_program_id)
 | 
					
						
							|  |  |  |                 .executable(true, true)
 | 
					
						
							|  |  |  |                 .data(vec![42], vec![0])
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							|  |  |  |             Err(InstructionError::ModifiedProgramId),
 | 
					
						
							|  |  |  |             "mallory should not be able to change the account owner, if the account executable"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&mallory_program_id, &mallory_program_id)
 | 
					
						
							|  |  |  |                 .owner(&alice_program_id)
 | 
					
						
							|  |  |  |                 .data(vec![42], vec![42])
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-03-13 11:46:49 -06:00
										 |  |  |             Err(InstructionError::ModifiedProgramId),
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |             "mallory should not be able to inject data into the alice program"
 | 
					
						
							| 
									
										
										
										
											2019-02-22 13:08:54 -07:00
										 |  |  |         );
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							| 
									
										
										
										
											2019-11-18 15:01:14 -07:00
										 |  |  |     fn test_verify_account_changes_executable() {
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let owner = solana_sdk::pubkey::new_rand();
 | 
					
						
							|  |  |  |         let mallory_program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |         let system_program_id = system_program::id();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |             Change::new(&owner, &system_program_id)
 | 
					
						
							|  |  |  |                 .executable(false, true)
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |             Err(InstructionError::ExecutableModified),
 | 
					
						
							|  |  |  |             "system program can't change executable if system doesn't own the account"
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |             Change::new(&owner, &system_program_id)
 | 
					
						
							|  |  |  |                 .executable(true, true)
 | 
					
						
							|  |  |  |                 .data(vec![1], vec![2])
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2020-03-26 17:10:11 -07:00
										 |  |  |             Err(InstructionError::ExecutableDataModified),
 | 
					
						
							|  |  |  |             "system program can't change executable data if system doesn't own the account"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |             Change::new(&owner, &owner).executable(false, true).verify(),
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |             Ok(()),
 | 
					
						
							| 
									
										
										
										
											2020-03-26 17:10:11 -07:00
										 |  |  |             "owner should be able to change executable"
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |             Change::new(&owner, &owner)
 | 
					
						
							|  |  |  |                 .executable(false, true)
 | 
					
						
							|  |  |  |                 .read_only()
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |             Err(InstructionError::ExecutableModified),
 | 
					
						
							| 
									
										
										
										
											2020-03-26 17:10:11 -07:00
										 |  |  |             "owner can't modify executable of read-only accounts"
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |             Change::new(&owner, &owner).executable(true, false).verify(),
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |             Err(InstructionError::ExecutableModified),
 | 
					
						
							| 
									
										
										
										
											2020-03-26 17:10:11 -07:00
										 |  |  |             "owner program can't reverse executable"
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |             Change::new(&owner, &mallory_program_id)
 | 
					
						
							|  |  |  |                 .executable(false, true)
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |             Err(InstructionError::ExecutableModified),
 | 
					
						
							|  |  |  |             "malicious Mallory should not be able to change the account executable"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-03-26 17:10:11 -07:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |             Change::new(&owner, &owner)
 | 
					
						
							|  |  |  |                 .executable(false, true)
 | 
					
						
							|  |  |  |                 .data(vec![1], vec![2])
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2020-03-26 17:10:11 -07:00
										 |  |  |             Ok(()),
 | 
					
						
							|  |  |  |             "account data can change in the same instruction that sets the bit"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |             Change::new(&owner, &owner)
 | 
					
						
							|  |  |  |                 .executable(true, true)
 | 
					
						
							|  |  |  |                 .data(vec![1], vec![2])
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2020-03-26 17:10:11 -07:00
										 |  |  |             Err(InstructionError::ExecutableDataModified),
 | 
					
						
							|  |  |  |             "owner should not be able to change an account's data once its marked executable"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |         assert_eq!(
 | 
					
						
							|  |  |  |             Change::new(&owner, &owner)
 | 
					
						
							|  |  |  |                 .executable(true, true)
 | 
					
						
							|  |  |  |                 .lamports(1, 2)
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							|  |  |  |             Err(InstructionError::ExecutableLamportChange),
 | 
					
						
							| 
									
										
										
										
											2020-06-17 21:54:52 -06:00
										 |  |  |             "owner should not be able to add lamports once marked executable"
 | 
					
						
							| 
									
										
										
										
											2020-03-27 16:43:25 -07:00
										 |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							|  |  |  |             Change::new(&owner, &owner)
 | 
					
						
							|  |  |  |                 .executable(true, true)
 | 
					
						
							|  |  |  |                 .lamports(1, 2)
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							|  |  |  |             Err(InstructionError::ExecutableLamportChange),
 | 
					
						
							|  |  |  |             "owner should not be able to add lamports once marked executable"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							|  |  |  |             Change::new(&owner, &owner)
 | 
					
						
							|  |  |  |                 .executable(true, true)
 | 
					
						
							|  |  |  |                 .lamports(2, 1)
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							|  |  |  |             Err(InstructionError::ExecutableLamportChange),
 | 
					
						
							|  |  |  |             "owner should not be able to subtract lamports once marked executable"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |         let data = vec![1; 100];
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         let min_lamports = Rent::default().minimum_balance(data.len());
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |         assert_eq!(
 | 
					
						
							|  |  |  |             Change::new(&owner, &owner)
 | 
					
						
							|  |  |  |                 .executable(false, true)
 | 
					
						
							|  |  |  |                 .lamports(0, min_lamports)
 | 
					
						
							|  |  |  |                 .data(data.clone(), data.clone())
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							|  |  |  |             Ok(()),
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							|  |  |  |             Change::new(&owner, &owner)
 | 
					
						
							|  |  |  |                 .executable(false, true)
 | 
					
						
							|  |  |  |                 .lamports(0, min_lamports - 1)
 | 
					
						
							| 
									
										
										
										
											2020-05-15 17:35:43 +01:00
										 |  |  |                 .data(data.clone(), data)
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |                 .verify(),
 | 
					
						
							|  |  |  |             Err(InstructionError::ExecutableAccountNotRentExempt),
 | 
					
						
							|  |  |  |             "owner should not be able to change an account's data once its marked executable"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |     #[test]
 | 
					
						
							| 
									
										
										
										
											2019-11-18 15:01:14 -07:00
										 |  |  |     fn test_verify_account_changes_data_len() {
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let alice_program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&system_program::id(), &system_program::id())
 | 
					
						
							|  |  |  |                 .data(vec![0], vec![0, 0])
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |             Ok(()),
 | 
					
						
							|  |  |  |             "system program should be able to change the data len"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&alice_program_id, &system_program::id())
 | 
					
						
							|  |  |  |             .data(vec![0], vec![0,0])
 | 
					
						
							|  |  |  |             .verify(),
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         Err(InstructionError::AccountDataSizeChanged),
 | 
					
						
							|  |  |  |         "system program should not be able to change the data length of accounts it does not own"
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |         );
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |     #[test]
 | 
					
						
							| 
									
										
										
										
											2019-11-18 15:01:14 -07:00
										 |  |  |     fn test_verify_account_changes_data() {
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let alice_program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							|  |  |  |         let mallory_program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2019-02-22 13:08:54 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&alice_program_id, &alice_program_id)
 | 
					
						
							|  |  |  |                 .data(vec![0], vec![42])
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-07-29 15:29:20 -07:00
										 |  |  |             Ok(()),
 | 
					
						
							|  |  |  |             "alice program should be able to change the data"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-02-22 13:08:54 -07:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&mallory_program_id, &alice_program_id)
 | 
					
						
							|  |  |  |                 .data(vec![0], vec![42])
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-03-14 10:48:27 -06:00
										 |  |  |             Err(InstructionError::ExternalAccountDataModified),
 | 
					
						
							| 
									
										
										
										
											2019-10-25 21:47:16 -07:00
										 |  |  |             "non-owner mallory should not be able to change the account data"
 | 
					
						
							| 
									
										
										
										
											2019-02-22 13:08:54 -07:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&alice_program_id, &alice_program_id)
 | 
					
						
							|  |  |  |                 .data(vec![0], vec![42])
 | 
					
						
							|  |  |  |                 .read_only()
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |             Err(InstructionError::ReadonlyDataModified),
 | 
					
						
							| 
									
										
										
										
											2019-10-25 21:47:16 -07:00
										 |  |  |             "alice isn't allowed to touch a CO account"
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         );
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-26 11:04:20 -07:00
										 |  |  |     #[test]
 | 
					
						
							| 
									
										
										
										
											2019-11-18 15:01:14 -07:00
										 |  |  |     fn test_verify_account_changes_rent_epoch() {
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let alice_program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2019-08-26 11:04:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&alice_program_id, &system_program::id()).verify(),
 | 
					
						
							| 
									
										
										
										
											2019-08-26 11:04:20 -07:00
										 |  |  |             Ok(()),
 | 
					
						
							|  |  |  |             "nothing changed!"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&alice_program_id, &system_program::id())
 | 
					
						
							|  |  |  |                 .rent_epoch(0, 1)
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-08-26 11:04:20 -07:00
										 |  |  |             Err(InstructionError::RentEpochModified),
 | 
					
						
							|  |  |  |             "no one touches rent_epoch"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |     #[test]
 | 
					
						
							| 
									
										
										
										
											2019-11-18 15:01:14 -07:00
										 |  |  |     fn test_verify_account_changes_deduct_lamports_and_reassign_account() {
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let alice_program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							|  |  |  |         let bob_program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // positive test of this capability
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&alice_program_id, &alice_program_id)
 | 
					
						
							|  |  |  |             .owner(&bob_program_id)
 | 
					
						
							|  |  |  |             .lamports(42, 1)
 | 
					
						
							|  |  |  |             .data(vec![42], vec![0])
 | 
					
						
							|  |  |  |             .verify(),
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         Ok(()),
 | 
					
						
							|  |  |  |         "alice should be able to deduct lamports and give the account to bob if the data is zeroed",
 | 
					
						
							|  |  |  |     );
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							| 
									
										
										
										
											2019-11-18 15:01:14 -07:00
										 |  |  |     fn test_verify_account_changes_lamports() {
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let alice_program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&alice_program_id, &system_program::id())
 | 
					
						
							|  |  |  |                 .lamports(42, 0)
 | 
					
						
							|  |  |  |                 .read_only()
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |             Err(InstructionError::ExternalAccountLamportSpend),
 | 
					
						
							|  |  |  |             "debit should fail, even if system program"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&alice_program_id, &alice_program_id)
 | 
					
						
							|  |  |  |                 .lamports(42, 0)
 | 
					
						
							|  |  |  |                 .read_only()
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |             Err(InstructionError::ReadonlyLamportChange),
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |             "debit should fail, even if owning program"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&alice_program_id, &system_program::id())
 | 
					
						
							|  |  |  |                 .lamports(42, 0)
 | 
					
						
							|  |  |  |                 .owner(&system_program::id())
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |             Err(InstructionError::ModifiedProgramId),
 | 
					
						
							|  |  |  |             "system program can't debit the account unless it was the pre.owner"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&system_program::id(), &system_program::id())
 | 
					
						
							|  |  |  |                 .lamports(42, 0)
 | 
					
						
							|  |  |  |                 .owner(&alice_program_id)
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |             Ok(()),
 | 
					
						
							|  |  |  |             "system can spend (and change owner)"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-16 10:47:45 -07:00
										 |  |  |     #[test]
 | 
					
						
							| 
									
										
										
										
											2019-11-18 15:01:14 -07:00
										 |  |  |     fn test_verify_account_changes_data_size_changed() {
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let alice_program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-16 10:47:45 -07:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&alice_program_id, &system_program::id())
 | 
					
						
							|  |  |  |                 .data(vec![0], vec![0, 0])
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |             Err(InstructionError::AccountDataSizeChanged),
 | 
					
						
							|  |  |  |             "system program should not be able to change another program's account data size"
 | 
					
						
							| 
									
										
										
										
											2019-10-16 10:47:45 -07:00
										 |  |  |         );
 | 
					
						
							|  |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&alice_program_id, &alice_program_id)
 | 
					
						
							|  |  |  |                 .data(vec![0], vec![0, 0])
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-10-16 10:47:45 -07:00
										 |  |  |             Err(InstructionError::AccountDataSizeChanged),
 | 
					
						
							|  |  |  |             "non-system programs cannot change their data size"
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-04-18 17:04:13 -07:00
										 |  |  |             Change::new(&system_program::id(), &system_program::id())
 | 
					
						
							|  |  |  |                 .data(vec![0], vec![0, 0])
 | 
					
						
							|  |  |  |                 .verify(),
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |             Ok(()),
 | 
					
						
							| 
									
										
										
										
											2020-06-17 21:54:52 -06:00
										 |  |  |             "system program should be able to change account data size"
 | 
					
						
							| 
									
										
										
										
											2019-10-24 11:06:00 -07:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-10-16 10:47:45 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |     #[test]
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |     fn test_process_message_readonly_handling() {
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         #[derive(Serialize, Deserialize)]
 | 
					
						
							|  |  |  |         enum MockSystemInstruction {
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |             Correct,
 | 
					
						
							|  |  |  |             AttemptCredit { lamports: u64 },
 | 
					
						
							|  |  |  |             AttemptDataChange { data: u8 },
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fn mock_system_process_instruction(
 | 
					
						
							|  |  |  |             _program_id: &Pubkey,
 | 
					
						
							| 
									
										
										
										
											2020-01-22 17:54:06 -08:00
										 |  |  |             keyed_accounts: &[KeyedAccount],
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |             data: &[u8],
 | 
					
						
							| 
									
										
										
										
											2020-10-28 20:21:50 -07:00
										 |  |  |             _invoke_context: &mut dyn InvokeContext,
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         ) -> Result<(), InstructionError> {
 | 
					
						
							|  |  |  |             if let Ok(instruction) = bincode::deserialize(data) {
 | 
					
						
							|  |  |  |                 match instruction {
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |                     MockSystemInstruction::Correct => Ok(()),
 | 
					
						
							|  |  |  |                     MockSystemInstruction::AttemptCredit { lamports } => {
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |                         keyed_accounts[0].account.borrow_mut().lamports -= lamports;
 | 
					
						
							|  |  |  |                         keyed_accounts[1].account.borrow_mut().lamports += lamports;
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |                         Ok(())
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |                     // Change data in a read-only account
 | 
					
						
							|  |  |  |                     MockSystemInstruction::AttemptDataChange { data } => {
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |                         keyed_accounts[1].account.borrow_mut().data = vec![data];
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |                         Ok(())
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							|  |  |  |             } else {
 | 
					
						
							|  |  |  |                 Err(InstructionError::InvalidInstructionData)
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let mock_system_program_id = Pubkey::new(&[2u8; 32]);
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |         let rent_collector = RentCollector::default();
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         let mut message_processor = MessageProcessor::default();
 | 
					
						
							| 
									
										
										
										
											2020-05-19 19:45:30 -07:00
										 |  |  |         message_processor.add_program(mock_system_program_id, mock_system_process_instruction);
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |         let mut accounts: Vec<Rc<RefCell<Account>>> = Vec::new();
 | 
					
						
							|  |  |  |         let account = Account::new_ref(100, 1, &mock_system_program_id);
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         accounts.push(account);
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |         let account = Account::new_ref(0, 1, &mock_system_program_id);
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         accounts.push(account);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |         let mut loaders: Vec<Vec<(Pubkey, RefCell<Account>)>> = Vec::new();
 | 
					
						
							| 
									
										
										
										
											2020-12-11 11:03:31 +09:00
										 |  |  |         let account = RefCell::new(create_loadable_account("mock_system_program", 1));
 | 
					
						
							| 
									
										
										
										
											2019-09-24 07:09:53 -04:00
										 |  |  |         loaders.push(vec![(mock_system_program_id, account)]);
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         let executors = Rc::new(RefCell::new(Executors::default()));
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let from_pubkey = solana_sdk::pubkey::new_rand();
 | 
					
						
							|  |  |  |         let to_pubkey = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         let account_metas = vec![
 | 
					
						
							|  |  |  |             AccountMeta::new(from_pubkey, true),
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |             AccountMeta::new_readonly(to_pubkey, false),
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         ];
 | 
					
						
							| 
									
										
										
										
											2020-06-24 14:52:38 -06:00
										 |  |  |         let message = Message::new(
 | 
					
						
							|  |  |  |             &[Instruction::new(
 | 
					
						
							|  |  |  |                 mock_system_program_id,
 | 
					
						
							|  |  |  |                 &MockSystemInstruction::Correct,
 | 
					
						
							|  |  |  |                 account_metas.clone(),
 | 
					
						
							|  |  |  |             )],
 | 
					
						
							|  |  |  |             Some(&from_pubkey),
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         let result = message_processor.process_message(
 | 
					
						
							|  |  |  |             &message,
 | 
					
						
							|  |  |  |             &loaders,
 | 
					
						
							|  |  |  |             &accounts,
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |             &[],
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |             &rent_collector,
 | 
					
						
							|  |  |  |             None,
 | 
					
						
							|  |  |  |             executors.clone(),
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |             None,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 20:18:28 -07:00
										 |  |  |             Arc::new(FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |             BpfComputeBudget::new(&FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         assert_eq!(result, Ok(()));
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |         assert_eq!(accounts[0].borrow().lamports, 100);
 | 
					
						
							|  |  |  |         assert_eq!(accounts[1].borrow().lamports, 0);
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 14:52:38 -06:00
										 |  |  |         let message = Message::new(
 | 
					
						
							|  |  |  |             &[Instruction::new(
 | 
					
						
							|  |  |  |                 mock_system_program_id,
 | 
					
						
							|  |  |  |                 &MockSystemInstruction::AttemptCredit { lamports: 50 },
 | 
					
						
							|  |  |  |                 account_metas.clone(),
 | 
					
						
							|  |  |  |             )],
 | 
					
						
							|  |  |  |             Some(&from_pubkey),
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         let result = message_processor.process_message(
 | 
					
						
							|  |  |  |             &message,
 | 
					
						
							|  |  |  |             &loaders,
 | 
					
						
							|  |  |  |             &accounts,
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |             &[],
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |             &rent_collector,
 | 
					
						
							|  |  |  |             None,
 | 
					
						
							|  |  |  |             executors.clone(),
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |             None,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 20:18:28 -07:00
										 |  |  |             Arc::new(FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |             BpfComputeBudget::new(&FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         assert_eq!(
 | 
					
						
							|  |  |  |             result,
 | 
					
						
							|  |  |  |             Err(TransactionError::InstructionError(
 | 
					
						
							|  |  |  |                 0,
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |                 InstructionError::ReadonlyLamportChange
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |             ))
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-24 14:52:38 -06:00
										 |  |  |         let message = Message::new(
 | 
					
						
							|  |  |  |             &[Instruction::new(
 | 
					
						
							|  |  |  |                 mock_system_program_id,
 | 
					
						
							|  |  |  |                 &MockSystemInstruction::AttemptDataChange { data: 50 },
 | 
					
						
							|  |  |  |                 account_metas,
 | 
					
						
							|  |  |  |             )],
 | 
					
						
							|  |  |  |             Some(&from_pubkey),
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         let result = message_processor.process_message(
 | 
					
						
							|  |  |  |             &message,
 | 
					
						
							|  |  |  |             &loaders,
 | 
					
						
							|  |  |  |             &accounts,
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |             &[],
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |             &rent_collector,
 | 
					
						
							|  |  |  |             None,
 | 
					
						
							|  |  |  |             executors,
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |             None,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 20:18:28 -07:00
										 |  |  |             Arc::new(FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |             BpfComputeBudget::new(&FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |         assert_eq!(
 | 
					
						
							|  |  |  |             result,
 | 
					
						
							|  |  |  |             Err(TransactionError::InstructionError(
 | 
					
						
							|  |  |  |                 0,
 | 
					
						
							| 
									
										
										
										
											2019-11-05 09:38:35 -07:00
										 |  |  |                 InstructionError::ReadonlyDataModified
 | 
					
						
							| 
									
										
										
										
											2019-06-10 20:50:02 -06:00
										 |  |  |             ))
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-02-22 13:08:54 -07:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_process_message_duplicate_accounts() {
 | 
					
						
							|  |  |  |         #[derive(Serialize, Deserialize)]
 | 
					
						
							|  |  |  |         enum MockSystemInstruction {
 | 
					
						
							|  |  |  |             BorrowFail,
 | 
					
						
							|  |  |  |             MultiBorrowMut,
 | 
					
						
							|  |  |  |             DoWork { lamports: u64, data: u8 },
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fn mock_system_process_instruction(
 | 
					
						
							|  |  |  |             _program_id: &Pubkey,
 | 
					
						
							| 
									
										
										
										
											2020-01-22 17:54:06 -08:00
										 |  |  |             keyed_accounts: &[KeyedAccount],
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |             data: &[u8],
 | 
					
						
							| 
									
										
										
										
											2020-10-28 20:21:50 -07:00
										 |  |  |             _invoke_context: &mut dyn InvokeContext,
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |         ) -> Result<(), InstructionError> {
 | 
					
						
							|  |  |  |             if let Ok(instruction) = bincode::deserialize(data) {
 | 
					
						
							|  |  |  |                 match instruction {
 | 
					
						
							|  |  |  |                     MockSystemInstruction::BorrowFail => {
 | 
					
						
							|  |  |  |                         let from_account = keyed_accounts[0].try_account_ref_mut()?;
 | 
					
						
							|  |  |  |                         let dup_account = keyed_accounts[2].try_account_ref_mut()?;
 | 
					
						
							|  |  |  |                         if from_account.lamports != dup_account.lamports {
 | 
					
						
							|  |  |  |                             return Err(InstructionError::InvalidArgument);
 | 
					
						
							|  |  |  |                         }
 | 
					
						
							|  |  |  |                         Ok(())
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							|  |  |  |                     MockSystemInstruction::MultiBorrowMut => {
 | 
					
						
							|  |  |  |                         let from_lamports = {
 | 
					
						
							|  |  |  |                             let from_account = keyed_accounts[0].try_account_ref_mut()?;
 | 
					
						
							|  |  |  |                             from_account.lamports
 | 
					
						
							|  |  |  |                         };
 | 
					
						
							|  |  |  |                         let dup_lamports = {
 | 
					
						
							|  |  |  |                             let dup_account = keyed_accounts[2].try_account_ref_mut()?;
 | 
					
						
							|  |  |  |                             dup_account.lamports
 | 
					
						
							|  |  |  |                         };
 | 
					
						
							|  |  |  |                         if from_lamports != dup_lamports {
 | 
					
						
							|  |  |  |                             return Err(InstructionError::InvalidArgument);
 | 
					
						
							|  |  |  |                         }
 | 
					
						
							|  |  |  |                         Ok(())
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							|  |  |  |                     MockSystemInstruction::DoWork { lamports, data } => {
 | 
					
						
							|  |  |  |                         {
 | 
					
						
							|  |  |  |                             let mut to_account = keyed_accounts[1].try_account_ref_mut()?;
 | 
					
						
							|  |  |  |                             let mut dup_account = keyed_accounts[2].try_account_ref_mut()?;
 | 
					
						
							|  |  |  |                             dup_account.lamports -= lamports;
 | 
					
						
							|  |  |  |                             to_account.lamports += lamports;
 | 
					
						
							|  |  |  |                             dup_account.data = vec![data];
 | 
					
						
							|  |  |  |                         }
 | 
					
						
							|  |  |  |                         keyed_accounts[0].try_account_ref_mut()?.lamports -= lamports;
 | 
					
						
							|  |  |  |                         keyed_accounts[1].try_account_ref_mut()?.lamports += lamports;
 | 
					
						
							|  |  |  |                         Ok(())
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							|  |  |  |             } else {
 | 
					
						
							|  |  |  |                 Err(InstructionError::InvalidInstructionData)
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let mock_program_id = Pubkey::new(&[2u8; 32]);
 | 
					
						
							| 
									
										
										
										
											2020-03-31 10:07:38 -07:00
										 |  |  |         let rent_collector = RentCollector::default();
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |         let mut message_processor = MessageProcessor::default();
 | 
					
						
							| 
									
										
										
										
											2020-05-19 19:45:30 -07:00
										 |  |  |         message_processor.add_program(mock_program_id, mock_system_process_instruction);
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         let mut accounts: Vec<Rc<RefCell<Account>>> = Vec::new();
 | 
					
						
							|  |  |  |         let account = Account::new_ref(100, 1, &mock_program_id);
 | 
					
						
							|  |  |  |         accounts.push(account);
 | 
					
						
							|  |  |  |         let account = Account::new_ref(0, 1, &mock_program_id);
 | 
					
						
							|  |  |  |         accounts.push(account);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let mut loaders: Vec<Vec<(Pubkey, RefCell<Account>)>> = Vec::new();
 | 
					
						
							| 
									
										
										
										
											2020-12-11 11:03:31 +09:00
										 |  |  |         let account = RefCell::new(create_loadable_account("mock_system_program", 1));
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |         loaders.push(vec![(mock_program_id, account)]);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         let executors = Rc::new(RefCell::new(Executors::default()));
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let from_pubkey = solana_sdk::pubkey::new_rand();
 | 
					
						
							|  |  |  |         let to_pubkey = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2020-05-15 17:35:43 +01:00
										 |  |  |         let dup_pubkey = from_pubkey;
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |         let account_metas = vec![
 | 
					
						
							|  |  |  |             AccountMeta::new(from_pubkey, true),
 | 
					
						
							|  |  |  |             AccountMeta::new(to_pubkey, false),
 | 
					
						
							|  |  |  |             AccountMeta::new(dup_pubkey, false),
 | 
					
						
							|  |  |  |         ];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Try to borrow mut the same account
 | 
					
						
							| 
									
										
										
										
											2020-06-24 14:52:38 -06:00
										 |  |  |         let message = Message::new(
 | 
					
						
							|  |  |  |             &[Instruction::new(
 | 
					
						
							|  |  |  |                 mock_program_id,
 | 
					
						
							|  |  |  |                 &MockSystemInstruction::BorrowFail,
 | 
					
						
							|  |  |  |                 account_metas.clone(),
 | 
					
						
							|  |  |  |             )],
 | 
					
						
							|  |  |  |             Some(&from_pubkey),
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         let result = message_processor.process_message(
 | 
					
						
							|  |  |  |             &message,
 | 
					
						
							|  |  |  |             &loaders,
 | 
					
						
							|  |  |  |             &accounts,
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |             &[],
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |             &rent_collector,
 | 
					
						
							|  |  |  |             None,
 | 
					
						
							|  |  |  |             executors.clone(),
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |             None,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 20:18:28 -07:00
										 |  |  |             Arc::new(FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |             BpfComputeBudget::new(&FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |         assert_eq!(
 | 
					
						
							|  |  |  |             result,
 | 
					
						
							|  |  |  |             Err(TransactionError::InstructionError(
 | 
					
						
							|  |  |  |                 0,
 | 
					
						
							|  |  |  |                 InstructionError::AccountBorrowFailed
 | 
					
						
							|  |  |  |             ))
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Try to borrow mut the same account in a safe way
 | 
					
						
							| 
									
										
										
										
											2020-06-24 14:52:38 -06:00
										 |  |  |         let message = Message::new(
 | 
					
						
							|  |  |  |             &[Instruction::new(
 | 
					
						
							|  |  |  |                 mock_program_id,
 | 
					
						
							|  |  |  |                 &MockSystemInstruction::MultiBorrowMut,
 | 
					
						
							|  |  |  |                 account_metas.clone(),
 | 
					
						
							|  |  |  |             )],
 | 
					
						
							|  |  |  |             Some(&from_pubkey),
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         let result = message_processor.process_message(
 | 
					
						
							|  |  |  |             &message,
 | 
					
						
							|  |  |  |             &loaders,
 | 
					
						
							|  |  |  |             &accounts,
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |             &[],
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |             &rent_collector,
 | 
					
						
							|  |  |  |             None,
 | 
					
						
							|  |  |  |             executors.clone(),
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |             None,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 20:18:28 -07:00
										 |  |  |             Arc::new(FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |             BpfComputeBudget::new(&FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |         assert_eq!(result, Ok(()));
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Do work on the same account but at different location in keyed_accounts[]
 | 
					
						
							| 
									
										
										
										
											2020-06-24 14:52:38 -06:00
										 |  |  |         let message = Message::new(
 | 
					
						
							|  |  |  |             &[Instruction::new(
 | 
					
						
							|  |  |  |                 mock_program_id,
 | 
					
						
							|  |  |  |                 &MockSystemInstruction::DoWork {
 | 
					
						
							|  |  |  |                     lamports: 10,
 | 
					
						
							|  |  |  |                     data: 42,
 | 
					
						
							|  |  |  |                 },
 | 
					
						
							|  |  |  |                 account_metas,
 | 
					
						
							|  |  |  |             )],
 | 
					
						
							|  |  |  |             Some(&from_pubkey),
 | 
					
						
							|  |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         let result = message_processor.process_message(
 | 
					
						
							|  |  |  |             &message,
 | 
					
						
							|  |  |  |             &loaders,
 | 
					
						
							|  |  |  |             &accounts,
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |             &[],
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |             &rent_collector,
 | 
					
						
							|  |  |  |             None,
 | 
					
						
							|  |  |  |             executors,
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |             None,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 20:18:28 -07:00
										 |  |  |             Arc::new(FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |             BpfComputeBudget::new(&FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-01-22 09:11:56 -08:00
										 |  |  |         assert_eq!(result, Ok(()));
 | 
					
						
							|  |  |  |         assert_eq!(accounts[0].borrow().lamports, 80);
 | 
					
						
							|  |  |  |         assert_eq!(accounts[1].borrow().lamports, 20);
 | 
					
						
							|  |  |  |         assert_eq!(accounts[0].borrow().data, vec![42]);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_process_cross_program() {
 | 
					
						
							|  |  |  |         #[derive(Serialize, Deserialize)]
 | 
					
						
							|  |  |  |         enum MockInstruction {
 | 
					
						
							|  |  |  |             NoopSuccess,
 | 
					
						
							|  |  |  |             NoopFail,
 | 
					
						
							|  |  |  |             ModifyOwned,
 | 
					
						
							|  |  |  |             ModifyNotOwned,
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         fn mock_process_instruction(
 | 
					
						
							|  |  |  |             program_id: &Pubkey,
 | 
					
						
							|  |  |  |             keyed_accounts: &[KeyedAccount],
 | 
					
						
							|  |  |  |             data: &[u8],
 | 
					
						
							| 
									
										
										
										
											2020-10-28 20:21:50 -07:00
										 |  |  |             _invoke_context: &mut dyn InvokeContext,
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         ) -> Result<(), InstructionError> {
 | 
					
						
							|  |  |  |             assert_eq!(*program_id, keyed_accounts[0].owner()?);
 | 
					
						
							|  |  |  |             assert_ne!(
 | 
					
						
							| 
									
										
										
										
											2020-05-20 09:24:57 -07:00
										 |  |  |                 keyed_accounts[1].owner()?,
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                 *keyed_accounts[0].unsigned_key()
 | 
					
						
							|  |  |  |             );
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if let Ok(instruction) = bincode::deserialize(data) {
 | 
					
						
							|  |  |  |                 match instruction {
 | 
					
						
							|  |  |  |                     MockInstruction::NoopSuccess => (),
 | 
					
						
							|  |  |  |                     MockInstruction::NoopFail => return Err(InstructionError::GenericError),
 | 
					
						
							|  |  |  |                     MockInstruction::ModifyOwned => {
 | 
					
						
							| 
									
										
										
										
											2020-05-20 09:24:57 -07:00
										 |  |  |                         keyed_accounts[0].try_account_ref_mut()?.data[0] = 1
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                     }
 | 
					
						
							|  |  |  |                     MockInstruction::ModifyNotOwned => {
 | 
					
						
							| 
									
										
										
										
											2020-05-20 09:24:57 -07:00
										 |  |  |                         keyed_accounts[1].try_account_ref_mut()?.data[0] = 1
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                     }
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							|  |  |  |             } else {
 | 
					
						
							|  |  |  |                 return Err(InstructionError::InvalidInstructionData);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |             Ok(())
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let caller_program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							|  |  |  |         let callee_program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2020-05-20 09:24:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         let mut program_account = Account::new(1, 0, &native_loader::id());
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         program_account.executable = true;
 | 
					
						
							| 
									
										
										
										
											2020-11-29 02:06:43 -08:00
										 |  |  |         let executable_preaccount =
 | 
					
						
							|  |  |  |             PreAccount::new(&callee_program_id, &program_account, false, true);
 | 
					
						
							|  |  |  |         let executable_accounts = vec![(callee_program_id, RefCell::new(program_account.clone()))];
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let owned_key = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         let owned_account = Account::new(42, 1, &callee_program_id);
 | 
					
						
							|  |  |  |         let owned_preaccount = PreAccount::new(&owned_key, &owned_account, false, true);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let not_owned_key = solana_sdk::pubkey::new_rand();
 | 
					
						
							|  |  |  |         let not_owned_account = Account::new(84, 1, &solana_sdk::pubkey::new_rand());
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         let not_owned_preaccount = PreAccount::new(¬_owned_key, ¬_owned_account, false, true);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-10 13:02:55 -07:00
										 |  |  |         #[allow(unused_mut)]
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         let mut accounts = vec![
 | 
					
						
							|  |  |  |             Rc::new(RefCell::new(owned_account)),
 | 
					
						
							|  |  |  |             Rc::new(RefCell::new(not_owned_account)),
 | 
					
						
							| 
									
										
										
										
											2020-11-29 02:06:43 -08:00
										 |  |  |             Rc::new(RefCell::new(program_account)),
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         ];
 | 
					
						
							| 
									
										
										
										
											2020-10-30 01:10:13 -07:00
										 |  |  |         let programs: Vec<(_, ProcessInstructionWithContext)> =
 | 
					
						
							|  |  |  |             vec![(callee_program_id, mock_process_instruction)];
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         let mut invoke_context = ThisInvokeContext::new(
 | 
					
						
							|  |  |  |             &caller_program_id,
 | 
					
						
							|  |  |  |             Rent::default(),
 | 
					
						
							| 
									
										
										
										
											2020-11-29 02:06:43 -08:00
										 |  |  |             vec![
 | 
					
						
							|  |  |  |                 owned_preaccount,
 | 
					
						
							|  |  |  |                 not_owned_preaccount,
 | 
					
						
							|  |  |  |                 executable_preaccount,
 | 
					
						
							|  |  |  |             ],
 | 
					
						
							| 
									
										
										
										
											2020-12-22 21:17:18 +00:00
										 |  |  |             &[],
 | 
					
						
							| 
									
										
										
										
											2020-10-30 01:10:13 -07:00
										 |  |  |             programs.as_slice(),
 | 
					
						
							| 
									
										
										
										
											2020-06-06 10:18:28 -07:00
										 |  |  |             None,
 | 
					
						
							| 
									
										
										
										
											2020-10-28 13:16:13 -07:00
										 |  |  |             BpfComputeBudget::default(),
 | 
					
						
							| 
									
										
										
										
											2020-09-14 17:42:37 -07:00
										 |  |  |             Rc::new(RefCell::new(Executors::default())),
 | 
					
						
							| 
									
										
										
										
											2020-09-24 22:36:22 +08:00
										 |  |  |             None,
 | 
					
						
							| 
									
										
										
										
											2020-09-29 20:18:28 -07:00
										 |  |  |             Arc::new(FeatureSet::all_enabled()),
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         );
 | 
					
						
							|  |  |  |         let metas = vec![
 | 
					
						
							|  |  |  |             AccountMeta::new(owned_key, false),
 | 
					
						
							|  |  |  |             AccountMeta::new(not_owned_key, false),
 | 
					
						
							|  |  |  |         ];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // not owned account modified by the caller (before the invoke)
 | 
					
						
							|  |  |  |         accounts[0].borrow_mut().data[0] = 1;
 | 
					
						
							| 
									
										
										
										
											2020-05-15 13:23:09 -06:00
										 |  |  |         let instruction = Instruction::new(
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |             callee_program_id,
 | 
					
						
							|  |  |  |             &MockInstruction::NoopSuccess,
 | 
					
						
							|  |  |  |             metas.clone(),
 | 
					
						
							| 
									
										
										
										
											2020-05-15 13:23:09 -06:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-06-24 14:52:38 -06:00
										 |  |  |         let message = Message::new(&[instruction], None);
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |         assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-10-30 01:10:13 -07:00
										 |  |  |             MessageProcessor::process_cross_program_instruction(
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                 &message,
 | 
					
						
							|  |  |  |                 &executable_accounts,
 | 
					
						
							|  |  |  |                 &accounts,
 | 
					
						
							|  |  |  |                 &mut invoke_context,
 | 
					
						
							|  |  |  |             ),
 | 
					
						
							|  |  |  |             Err(InstructionError::ExternalAccountDataModified)
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |         accounts[0].borrow_mut().data[0] = 0;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let cases = vec![
 | 
					
						
							|  |  |  |             (MockInstruction::NoopSuccess, Ok(())),
 | 
					
						
							|  |  |  |             (
 | 
					
						
							|  |  |  |                 MockInstruction::NoopFail,
 | 
					
						
							|  |  |  |                 Err(InstructionError::GenericError),
 | 
					
						
							|  |  |  |             ),
 | 
					
						
							|  |  |  |             (MockInstruction::ModifyOwned, Ok(())),
 | 
					
						
							|  |  |  |             (
 | 
					
						
							|  |  |  |                 MockInstruction::ModifyNotOwned,
 | 
					
						
							|  |  |  |                 Err(InstructionError::ExternalAccountDataModified),
 | 
					
						
							|  |  |  |             ),
 | 
					
						
							|  |  |  |         ];
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for case in cases {
 | 
					
						
							| 
									
										
										
										
											2020-05-15 13:23:09 -06:00
										 |  |  |             let instruction = Instruction::new(callee_program_id, &case.0, metas.clone());
 | 
					
						
							| 
									
										
										
										
											2020-06-24 14:52:38 -06:00
										 |  |  |             let message = Message::new(&[instruction], None);
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |             assert_eq!(
 | 
					
						
							| 
									
										
										
										
											2020-10-30 01:10:13 -07:00
										 |  |  |                 MessageProcessor::process_cross_program_instruction(
 | 
					
						
							| 
									
										
										
										
											2020-04-28 14:33:56 -07:00
										 |  |  |                     &message,
 | 
					
						
							|  |  |  |                     &executable_accounts,
 | 
					
						
							|  |  |  |                     &accounts,
 | 
					
						
							|  |  |  |                     &mut invoke_context,
 | 
					
						
							|  |  |  |                 ),
 | 
					
						
							|  |  |  |                 case.1
 | 
					
						
							|  |  |  |             );
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2020-09-01 17:48:25 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_debug() {
 | 
					
						
							|  |  |  |         let mut message_processor = MessageProcessor::default();
 | 
					
						
							| 
									
										
										
										
											2020-12-13 17:26:34 -08:00
										 |  |  |         #[allow(clippy::unnecessary_wraps)]
 | 
					
						
							| 
									
										
										
										
											2020-09-01 17:48:25 +09:00
										 |  |  |         fn mock_process_instruction(
 | 
					
						
							|  |  |  |             _program_id: &Pubkey,
 | 
					
						
							|  |  |  |             _keyed_accounts: &[KeyedAccount],
 | 
					
						
							|  |  |  |             _data: &[u8],
 | 
					
						
							| 
									
										
										
										
											2020-10-28 20:21:50 -07:00
										 |  |  |             _invoke_context: &mut dyn InvokeContext,
 | 
					
						
							| 
									
										
										
										
											2020-09-01 17:48:25 +09:00
										 |  |  |         ) -> Result<(), InstructionError> {
 | 
					
						
							|  |  |  |             Ok(())
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-12-13 17:26:34 -08:00
										 |  |  |         #[allow(clippy::unnecessary_wraps)]
 | 
					
						
							| 
									
										
										
										
											2020-09-01 17:48:25 +09:00
										 |  |  |         fn mock_ix_processor(
 | 
					
						
							|  |  |  |             _pubkey: &Pubkey,
 | 
					
						
							|  |  |  |             _ka: &[KeyedAccount],
 | 
					
						
							|  |  |  |             _data: &[u8],
 | 
					
						
							| 
									
										
										
										
											2020-09-29 01:36:46 -07:00
										 |  |  |             _context: &mut dyn InvokeContext,
 | 
					
						
							| 
									
										
										
										
											2020-10-21 01:05:45 +09:00
										 |  |  |         ) -> Result<(), InstructionError> {
 | 
					
						
							| 
									
										
										
										
											2020-09-01 17:48:25 +09:00
										 |  |  |             Ok(())
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-10-19 12:12:08 -07:00
										 |  |  |         let program_id = solana_sdk::pubkey::new_rand();
 | 
					
						
							| 
									
										
										
										
											2020-09-01 17:48:25 +09:00
										 |  |  |         message_processor.add_program(program_id, mock_process_instruction);
 | 
					
						
							|  |  |  |         message_processor.add_loader(program_id, mock_ix_processor);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         assert!(!format!("{:?}", message_processor).is_empty());
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-02-18 23:26:22 -07:00
										 |  |  | }
 |