From 2c99b23ad71e07778a9b4452cac14b534f5bd93d Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Thu, 20 May 2021 14:00:50 -0700 Subject: [PATCH] Add get_sysvar() helper to sdk --- programs/bpf_loader/src/syscalls.rs | 17 ++++---------- runtime/src/message_processor.rs | 34 +++++++++++++++------------ sdk/src/process_instruction.rs | 36 +++++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 29 deletions(-) diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 31325ed8d..15406fe1e 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -29,7 +29,7 @@ use solana_sdk::{ keccak, keyed_account::KeyedAccount, native_loader, - process_instruction::{stable_log, ComputeMeter, InvokeContext, Logger}, + process_instruction::{self, stable_log, ComputeMeter, InvokeContext, Logger}, pubkey::{Pubkey, PubkeyError, MAX_SEEDS}, rent::Rent, sysvar::{self, fees::Fees, Sysvar, SysvarId}, @@ -957,8 +957,8 @@ fn get_sysvar( memory_mapping: &MemoryMapping, invoke_context: Rc>, ) -> Result> { - let mut invoke_context = invoke_context - .try_borrow_mut() + let invoke_context = invoke_context + .try_borrow() .map_err(|_| SyscallError::InvokeContextBorrowFailed)?; invoke_context.get_compute_meter().consume( @@ -971,15 +971,8 @@ fn get_sysvar( invoke_context.is_feature_active(&enforce_aligned_host_addrs::id()), )?; - let sysvar_data = invoke_context.get_sysvar_data(id).ok_or_else(|| { - ic_msg!(invoke_context, "Unable to get Sysvar {}", id); - SyscallError::InstructionError(InstructionError::UnsupportedSysvar) - })?; - - *var = bincode::deserialize(&sysvar_data).map_err(|e| { - ic_msg!(invoke_context, "Unable to get Sysvar {}: {:?}", id, e); - SyscallError::InstructionError(InstructionError::UnsupportedSysvar) - })?; + *var = process_instruction::get_sysvar::(*invoke_context, id) + .map_err(SyscallError::InstructionError)?; Ok(SUCCESS) } diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 2e5ef6003..037eb0b79 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -266,7 +266,8 @@ pub struct ThisInvokeContext<'a> { pub timings: ExecuteDetailsTimings, account_db: Arc, ancestors: &'a Ancestors, - sysvars: Vec<(Pubkey, Option>>)>, + #[allow(clippy::type_complexity)] + sysvars: RefCell>>)>>, } impl<'a> ThisInvokeContext<'a> { #[allow(clippy::too_many_arguments)] @@ -314,7 +315,7 @@ impl<'a> ThisInvokeContext<'a> { timings: ExecuteDetailsTimings::default(), account_db, ancestors, - sysvars: vec![], + sysvars: RefCell::new(vec![]), }; invoke_context .invoke_stack @@ -509,22 +510,25 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> { self.timings.execute_us += execute_us; self.timings.deserialize_us += deserialize_us; } - fn get_sysvar_data(&mut self, id: &Pubkey) -> Option>> { - // Try share from cache - let mut result = - self.sysvars + fn get_sysvar_data(&self, id: &Pubkey) -> Option>> { + if let Ok(mut sysvars) = self.sysvars.try_borrow_mut() { + // Try share from cache + let mut result = sysvars .iter() .find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None }); - if result.is_none() { - // Load it - result = self - .account_db - .load_with_fixed_root(self.ancestors, id) - .map(|(account, _)| Rc::new(account.data().to_vec())); - // Cache it - self.sysvars.push((*id, result.clone())); + if result.is_none() { + // Load it + result = self + .account_db + .load_with_fixed_root(self.ancestors, id) + .map(|(account, _)| Rc::new(account.data().to_vec())); + // Cache it + sysvars.push((*id, result.clone())); + } + result + } else { + None } - result } } pub struct ThisLogger { diff --git a/sdk/src/process_instruction.rs b/sdk/src/process_instruction.rs index d591c84ac..c97dd9ac5 100644 --- a/sdk/src/process_instruction.rs +++ b/sdk/src/process_instruction.rs @@ -4,6 +4,7 @@ use solana_sdk::{ keyed_account::{create_keyed_accounts_unified, KeyedAccount}, message::Message, pubkey::Pubkey, + sysvar::Sysvar, }; use std::{cell::RefCell, fmt::Debug, rc::Rc, sync::Arc}; @@ -100,7 +101,7 @@ pub trait InvokeContext { deserialize_us: u64, ); /// Get sysvar data - fn get_sysvar_data(&mut self, id: &Pubkey) -> Option>>; + fn get_sysvar_data(&self, id: &Pubkey) -> Option>>; } /// Convenience macro to log a message with an `Rc>` @@ -133,6 +134,21 @@ macro_rules! ic_msg { }; } +pub fn get_sysvar( + invoke_context: &dyn InvokeContext, + id: &Pubkey, +) -> Result { + let sysvar_data = invoke_context.get_sysvar_data(id).ok_or_else(|| { + ic_msg!(invoke_context, "Unable to get sysvar {}", id); + InstructionError::UnsupportedSysvar + })?; + + bincode::deserialize(&sysvar_data).map_err(|err| { + ic_msg!(invoke_context, "Unable to get sysvar {}: {:?}", id, err); + InstructionError::UnsupportedSysvar + }) +} + #[derive(Clone, Copy, Debug, AbiExample)] pub struct BpfComputeBudget { /// Number of compute units that an instruction is allowed. Compute units @@ -338,6 +354,22 @@ impl<'a> MockInvokeContext<'a> { invoke_context } } + +pub fn mock_set_sysvar( + mock_invoke_context: &mut MockInvokeContext, + id: Pubkey, + sysvar: T, +) -> Result<(), InstructionError> { + let mut data = Vec::with_capacity(T::size_of()); + + bincode::serialize_into(&mut data, &sysvar).map_err(|err| { + ic_msg!(mock_invoke_context, "Unable to serialize sysvar: {:?}", err); + InstructionError::GenericError + })?; + mock_invoke_context.sysvars.push((id, Some(Rc::new(data)))); + Ok(()) +} + impl<'a> InvokeContext for MockInvokeContext<'a> { fn push( &mut self, @@ -425,7 +457,7 @@ impl<'a> InvokeContext for MockInvokeContext<'a> { _deserialize_us: u64, ) { } - fn get_sysvar_data(&mut self, id: &Pubkey) -> Option>> { + fn get_sysvar_data(&self, id: &Pubkey) -> Option>> { self.sysvars .iter() .find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None })