Add get_sysvar() helper to sdk
This commit is contained in:
		
				
					committed by
					
						![mergify[bot]](/avatar/e3df20cd7a67969c41a65f03bea54961?size=40) mergify[bot]
						mergify[bot]
					
				
			
			
				
	
			
			
			
						parent
						
							45552d271a
						
					
				
				
					commit
					2c99b23ad7
				
			| @@ -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<T: std::fmt::Debug + Sysvar + SysvarId>( | ||||
|     memory_mapping: &MemoryMapping, | ||||
|     invoke_context: Rc<RefCell<&mut dyn InvokeContext>>, | ||||
| ) -> Result<u64, EbpfError<BpfError>> { | ||||
|     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<T: std::fmt::Debug + Sysvar + SysvarId>( | ||||
|         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::<T>(*invoke_context, id) | ||||
|         .map_err(SyscallError::InstructionError)?; | ||||
|  | ||||
|     Ok(SUCCESS) | ||||
| } | ||||
|   | ||||
| @@ -266,7 +266,8 @@ pub struct ThisInvokeContext<'a> { | ||||
|     pub timings: ExecuteDetailsTimings, | ||||
|     account_db: Arc<Accounts>, | ||||
|     ancestors: &'a Ancestors, | ||||
|     sysvars: Vec<(Pubkey, Option<Rc<Vec<u8>>>)>, | ||||
|     #[allow(clippy::type_complexity)] | ||||
|     sysvars: RefCell<Vec<(Pubkey, Option<Rc<Vec<u8>>>)>>, | ||||
| } | ||||
| 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<Rc<Vec<u8>>> { | ||||
|         // Try share from cache | ||||
|         let mut result = | ||||
|             self.sysvars | ||||
|     fn get_sysvar_data(&self, id: &Pubkey) -> Option<Rc<Vec<u8>>> { | ||||
|         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 { | ||||
|   | ||||
| @@ -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<Rc<Vec<u8>>>; | ||||
|     fn get_sysvar_data(&self, id: &Pubkey) -> Option<Rc<Vec<u8>>>; | ||||
| } | ||||
|  | ||||
| /// Convenience macro to log a message with an `Rc<RefCell<dyn Logger>>` | ||||
| @@ -133,6 +134,21 @@ macro_rules! ic_msg { | ||||
|     }; | ||||
| } | ||||
|  | ||||
| pub fn get_sysvar<T: Sysvar>( | ||||
|     invoke_context: &dyn InvokeContext, | ||||
|     id: &Pubkey, | ||||
| ) -> Result<T, InstructionError> { | ||||
|     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<T: 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<Rc<Vec<u8>>> { | ||||
|     fn get_sysvar_data(&self, id: &Pubkey) -> Option<Rc<Vec<u8>>> { | ||||
|         self.sysvars | ||||
|             .iter() | ||||
|             .find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None }) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user