Add get_sysvar() helper to sdk
This commit is contained in:
parent
45552d271a
commit
2c99b23ad7
|
@ -29,7 +29,7 @@ use solana_sdk::{
|
||||||
keccak,
|
keccak,
|
||||||
keyed_account::KeyedAccount,
|
keyed_account::KeyedAccount,
|
||||||
native_loader,
|
native_loader,
|
||||||
process_instruction::{stable_log, ComputeMeter, InvokeContext, Logger},
|
process_instruction::{self, stable_log, ComputeMeter, InvokeContext, Logger},
|
||||||
pubkey::{Pubkey, PubkeyError, MAX_SEEDS},
|
pubkey::{Pubkey, PubkeyError, MAX_SEEDS},
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
sysvar::{self, fees::Fees, Sysvar, SysvarId},
|
sysvar::{self, fees::Fees, Sysvar, SysvarId},
|
||||||
|
@ -957,8 +957,8 @@ fn get_sysvar<T: std::fmt::Debug + Sysvar + SysvarId>(
|
||||||
memory_mapping: &MemoryMapping,
|
memory_mapping: &MemoryMapping,
|
||||||
invoke_context: Rc<RefCell<&mut dyn InvokeContext>>,
|
invoke_context: Rc<RefCell<&mut dyn InvokeContext>>,
|
||||||
) -> Result<u64, EbpfError<BpfError>> {
|
) -> Result<u64, EbpfError<BpfError>> {
|
||||||
let mut invoke_context = invoke_context
|
let invoke_context = invoke_context
|
||||||
.try_borrow_mut()
|
.try_borrow()
|
||||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed)?;
|
.map_err(|_| SyscallError::InvokeContextBorrowFailed)?;
|
||||||
|
|
||||||
invoke_context.get_compute_meter().consume(
|
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()),
|
invoke_context.is_feature_active(&enforce_aligned_host_addrs::id()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let sysvar_data = invoke_context.get_sysvar_data(id).ok_or_else(|| {
|
*var = process_instruction::get_sysvar::<T>(*invoke_context, id)
|
||||||
ic_msg!(invoke_context, "Unable to get Sysvar {}", id);
|
.map_err(SyscallError::InstructionError)?;
|
||||||
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)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(SUCCESS)
|
Ok(SUCCESS)
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,7 +266,8 @@ pub struct ThisInvokeContext<'a> {
|
||||||
pub timings: ExecuteDetailsTimings,
|
pub timings: ExecuteDetailsTimings,
|
||||||
account_db: Arc<Accounts>,
|
account_db: Arc<Accounts>,
|
||||||
ancestors: &'a Ancestors,
|
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> {
|
impl<'a> ThisInvokeContext<'a> {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
@ -314,7 +315,7 @@ impl<'a> ThisInvokeContext<'a> {
|
||||||
timings: ExecuteDetailsTimings::default(),
|
timings: ExecuteDetailsTimings::default(),
|
||||||
account_db,
|
account_db,
|
||||||
ancestors,
|
ancestors,
|
||||||
sysvars: vec![],
|
sysvars: RefCell::new(vec![]),
|
||||||
};
|
};
|
||||||
invoke_context
|
invoke_context
|
||||||
.invoke_stack
|
.invoke_stack
|
||||||
|
@ -509,22 +510,25 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
||||||
self.timings.execute_us += execute_us;
|
self.timings.execute_us += execute_us;
|
||||||
self.timings.deserialize_us += deserialize_us;
|
self.timings.deserialize_us += deserialize_us;
|
||||||
}
|
}
|
||||||
fn get_sysvar_data(&mut self, id: &Pubkey) -> Option<Rc<Vec<u8>>> {
|
fn get_sysvar_data(&self, id: &Pubkey) -> Option<Rc<Vec<u8>>> {
|
||||||
// Try share from cache
|
if let Ok(mut sysvars) = self.sysvars.try_borrow_mut() {
|
||||||
let mut result =
|
// Try share from cache
|
||||||
self.sysvars
|
let mut result = sysvars
|
||||||
.iter()
|
.iter()
|
||||||
.find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None });
|
.find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None });
|
||||||
if result.is_none() {
|
if result.is_none() {
|
||||||
// Load it
|
// Load it
|
||||||
result = self
|
result = self
|
||||||
.account_db
|
.account_db
|
||||||
.load_with_fixed_root(self.ancestors, id)
|
.load_with_fixed_root(self.ancestors, id)
|
||||||
.map(|(account, _)| Rc::new(account.data().to_vec()));
|
.map(|(account, _)| Rc::new(account.data().to_vec()));
|
||||||
// Cache it
|
// Cache it
|
||||||
self.sysvars.push((*id, result.clone()));
|
sysvars.push((*id, result.clone()));
|
||||||
|
}
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub struct ThisLogger {
|
pub struct ThisLogger {
|
||||||
|
|
|
@ -4,6 +4,7 @@ use solana_sdk::{
|
||||||
keyed_account::{create_keyed_accounts_unified, KeyedAccount},
|
keyed_account::{create_keyed_accounts_unified, KeyedAccount},
|
||||||
message::Message,
|
message::Message,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
|
sysvar::Sysvar,
|
||||||
};
|
};
|
||||||
use std::{cell::RefCell, fmt::Debug, rc::Rc, sync::Arc};
|
use std::{cell::RefCell, fmt::Debug, rc::Rc, sync::Arc};
|
||||||
|
|
||||||
|
@ -100,7 +101,7 @@ pub trait InvokeContext {
|
||||||
deserialize_us: u64,
|
deserialize_us: u64,
|
||||||
);
|
);
|
||||||
/// Get sysvar data
|
/// 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>>`
|
/// 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)]
|
#[derive(Clone, Copy, Debug, AbiExample)]
|
||||||
pub struct BpfComputeBudget {
|
pub struct BpfComputeBudget {
|
||||||
/// Number of compute units that an instruction is allowed. Compute units
|
/// Number of compute units that an instruction is allowed. Compute units
|
||||||
|
@ -338,6 +354,22 @@ impl<'a> MockInvokeContext<'a> {
|
||||||
invoke_context
|
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> {
|
impl<'a> InvokeContext for MockInvokeContext<'a> {
|
||||||
fn push(
|
fn push(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -425,7 +457,7 @@ impl<'a> InvokeContext for MockInvokeContext<'a> {
|
||||||
_deserialize_us: u64,
|
_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
|
self.sysvars
|
||||||
.iter()
|
.iter()
|
||||||
.find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None })
|
.find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None })
|
||||||
|
|
Loading…
Reference in New Issue