Cleanup: InvokeContext accessors (#21574)

* Removes blockhash accessors from InvokeContext.

* Removes lamports_per_signature accessors from InvokeContext.

* Removes return_data accessors from InvokeContext.

* Removes feature_set accessor from InvokeContext.

* Removes instruction_recorders and instruction_index accessors from InvokeContext.

* Moves get_sysvars() into InvokeContext.

* Removes compute_meter parameter from InvokeContext::new().

* Removes InvokeContext::new_mock_with_sysvars_and_features().

* Removes InvokeContext::update_timing().
This commit is contained in:
Alexander Meißner
2021-12-03 12:15:22 +01:00
committed by GitHub
parent dab0e8fdc7
commit a9d5ef2055
14 changed files with 314 additions and 343 deletions

View File

@ -131,24 +131,23 @@ impl<'a> StackFrame<'a> {
}
pub struct InvokeContext<'a> {
instruction_index: usize,
invoke_stack: Vec<StackFrame<'a>>,
rent: Rent,
pre_accounts: Vec<PreAccount>,
accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
builtin_programs: &'a [BuiltinProgram],
sysvars: &'a [(Pubkey, Vec<u8>)],
pub sysvars: &'a [(Pubkey, Vec<u8>)],
log_collector: Option<Rc<RefCell<LogCollector>>>,
compute_budget: ComputeBudget,
current_compute_budget: ComputeBudget,
compute_meter: Rc<RefCell<ComputeMeter>>,
executors: Rc<RefCell<Executors>>,
instruction_recorders: Option<&'a [InstructionRecorder]>,
feature_set: Arc<FeatureSet>,
pub instruction_recorder: Option<&'a InstructionRecorder>,
pub feature_set: Arc<FeatureSet>,
pub timings: ExecuteDetailsTimings,
blockhash: Hash,
lamports_per_signature: u64,
return_data: (Pubkey, Vec<u8>),
pub blockhash: Hash,
pub lamports_per_signature: u64,
pub return_data: (Pubkey, Vec<u8>),
}
impl<'a> InvokeContext<'a> {
@ -160,15 +159,12 @@ impl<'a> InvokeContext<'a> {
sysvars: &'a [(Pubkey, Vec<u8>)],
log_collector: Option<Rc<RefCell<LogCollector>>>,
compute_budget: ComputeBudget,
compute_meter: Rc<RefCell<ComputeMeter>>,
executors: Rc<RefCell<Executors>>,
instruction_recorders: Option<&'a [InstructionRecorder]>,
feature_set: Arc<FeatureSet>,
blockhash: Hash,
lamports_per_signature: u64,
) -> Self {
Self {
instruction_index: 0,
invoke_stack: Vec::with_capacity(compute_budget.max_invoke_depth),
rent,
pre_accounts: Vec::new(),
@ -178,9 +174,9 @@ impl<'a> InvokeContext<'a> {
log_collector,
current_compute_budget: compute_budget,
compute_budget,
compute_meter,
compute_meter: ComputeMeter::new_ref(compute_budget.max_units),
executors,
instruction_recorders,
instruction_recorder: None,
feature_set,
timings: ExecuteDetailsTimings::default(),
blockhash,
@ -189,40 +185,24 @@ impl<'a> InvokeContext<'a> {
}
}
pub fn new_mock_with_sysvars_and_features(
pub fn new_mock(
accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
builtin_programs: &'a [BuiltinProgram],
sysvars: &'a [(Pubkey, Vec<u8>)],
feature_set: Arc<FeatureSet>,
) -> Self {
Self::new(
Rent::default(),
accounts,
builtin_programs,
sysvars,
&[],
Some(LogCollector::new_ref()),
ComputeBudget::default(),
ComputeMeter::new_ref(std::i64::MAX as u64),
Rc::new(RefCell::new(Executors::default())),
None,
feature_set,
Arc::new(FeatureSet::all_enabled()),
Hash::default(),
0,
)
}
pub fn new_mock(
accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
builtin_programs: &'a [BuiltinProgram],
) -> Self {
Self::new_mock_with_sysvars_and_features(
accounts,
builtin_programs,
&[],
Arc::new(FeatureSet::all_enabled()),
)
}
/// Push a stack frame onto the invocation stack
pub fn push(
&mut self,
@ -240,15 +220,15 @@ impl<'a> InvokeContext<'a> {
.map(|index_of_program_id| &self.accounts[*index_of_program_id].0);
if self.invoke_stack.is_empty() {
let mut compute_budget = self.compute_budget;
if !self.is_feature_active(&tx_wide_compute_cap::id())
&& self.is_feature_active(&neon_evm_compute_budget::id())
if !self.feature_set.is_active(&tx_wide_compute_cap::id())
&& self.feature_set.is_active(&neon_evm_compute_budget::id())
&& program_id == Some(&crate::neon_evm_program::id())
{
// Bump the compute budget for neon_evm
compute_budget.max_units = compute_budget.max_units.max(500_000);
}
if !self.is_feature_active(&requestable_heap_size::id())
&& self.is_feature_active(&neon_evm_compute_budget::id())
if !self.feature_set.is_active(&requestable_heap_size::id())
&& self.feature_set.is_active(&neon_evm_compute_budget::id())
&& program_id == Some(&crate::neon_evm_program::id())
{
// Bump the compute budget for neon_evm
@ -342,8 +322,10 @@ impl<'a> InvokeContext<'a> {
program_indices: &[usize],
) -> Result<(), InstructionError> {
let program_id = instruction.program_id(&message.account_keys);
let demote_program_write_locks = self.is_feature_active(&demote_program_write_locks::id());
let do_support_realloc = self.is_feature_active(&do_support_realloc::id());
let demote_program_write_locks = self
.feature_set
.is_active(&demote_program_write_locks::id());
let do_support_realloc = self.feature_set.is_active(&do_support_realloc::id());
// Verify all executable accounts have zero outstanding refs
for account_index in program_indices.iter() {
@ -501,7 +483,9 @@ impl<'a> InvokeContext<'a> {
prev_account_sizes.push((account, account_length));
}
self.record_instruction(&instruction);
if let Some(instruction_recorder) = &self.instruction_recorder {
instruction_recorder.record_instruction(instruction);
}
self.process_cross_program_instruction(
&message,
&program_indices,
@ -510,7 +494,7 @@ impl<'a> InvokeContext<'a> {
)?;
// Verify the called program has not misbehaved
let do_support_realloc = self.is_feature_active(&do_support_realloc::id());
let do_support_realloc = self.feature_set.is_active(&do_support_realloc::id());
for (account, prev_size) in prev_account_sizes.iter() {
if !do_support_realloc && *prev_size != account.borrow().data().len() && *prev_size != 0
{
@ -657,12 +641,13 @@ impl<'a> InvokeContext<'a> {
// Verify the calling program hasn't misbehaved
self.verify_and_update(instruction, account_indices, caller_write_privileges)?;
self.set_return_data(Vec::new())?;
self.return_data = (*self.get_caller()?, Vec::new());
self.push(message, instruction, program_indices, Some(account_indices))?;
let result = self.process_instruction(&instruction.data).and_then(|_| {
// Verify the called program has not misbehaved
let demote_program_write_locks =
self.is_feature_active(&demote_program_write_locks::id());
let demote_program_write_locks = self
.feature_set
.is_active(&demote_program_write_locks::id());
let write_privileges: Vec<bool> = (0..message.account_keys.len())
.map(|i| message.is_writable(i, demote_program_write_locks))
.collect();
@ -692,7 +677,7 @@ impl<'a> InvokeContext<'a> {
);
}
}
if !self.is_feature_active(&remove_native_loader::id()) {
if !self.feature_set.is_active(&remove_native_loader::id()) {
let native_loader = NativeLoader::default();
// Call the program via the native loader
return native_loader.process_instruction(0, instruction_data, self);
@ -733,7 +718,7 @@ impl<'a> InvokeContext<'a> {
note = "To be removed together with remove_native_loader"
)]
pub fn remove_first_keyed_account(&mut self) -> Result<(), InstructionError> {
if !self.is_feature_active(&remove_native_loader::id()) {
if !self.feature_set.is_active(&remove_native_loader::id()) {
let stack_frame = &mut self
.invoke_stack
.last_mut()
@ -786,23 +771,6 @@ impl<'a> InvokeContext<'a> {
self.executors.borrow().get(pubkey)
}
/// Set which instruction in the message is currently being recorded
pub fn set_instruction_index(&mut self, instruction_index: usize) {
self.instruction_index = instruction_index;
}
/// Record invoked instruction
pub fn record_instruction(&self, instruction: &Instruction) {
if let Some(instruction_recorders) = &self.instruction_recorders {
instruction_recorders[self.instruction_index].record_instruction(instruction.clone());
}
}
/// Get the bank's active feature set
pub fn is_feature_active(&self, feature_id: &Pubkey) -> bool {
self.feature_set.is_active(feature_id)
}
/// Find an account_index and account by its key
pub fn get_account(&self, pubkey: &Pubkey) -> Option<(usize, Rc<RefCell<AccountSharedData>>)> {
for (index, (key, account)) in self.accounts.iter().enumerate().rev() {
@ -813,82 +781,27 @@ impl<'a> InvokeContext<'a> {
None
}
/// Update timing
pub fn update_timing(
&mut self,
serialize_us: u64,
create_vm_us: u64,
execute_us: u64,
deserialize_us: u64,
) {
self.timings.serialize_us = self.timings.serialize_us.saturating_add(serialize_us);
self.timings.create_vm_us = self.timings.create_vm_us.saturating_add(create_vm_us);
self.timings.execute_us = self.timings.execute_us.saturating_add(execute_us);
self.timings.deserialize_us = self.timings.deserialize_us.saturating_add(deserialize_us);
}
/// Get cached sysvars
pub fn get_sysvars(&self) -> &[(Pubkey, Vec<u8>)] {
self.sysvars
}
/// Get this invocation's compute budget
pub fn get_compute_budget(&self) -> &ComputeBudget {
&self.current_compute_budget
}
/// Set this invocation's blockhash
pub fn set_blockhash(&mut self, hash: Hash) {
self.blockhash = hash;
/// Get the value of a sysvar by its id
pub fn get_sysvar<T: Sysvar>(&self, id: &Pubkey) -> Result<T, InstructionError> {
self.sysvars
.iter()
.find_map(|(key, data)| {
if id == key {
bincode::deserialize(data).ok()
} else {
None
}
})
.ok_or_else(|| {
ic_msg!(self, "Unable to get sysvar {}", id);
InstructionError::UnsupportedSysvar
})
}
/// Get this invocation's blockhash
pub fn get_blockhash(&self) -> &Hash {
&self.blockhash
}
/// Set this invocation's lamports_per_signature value
pub fn set_lamports_per_signature(&mut self, lamports_per_signature: u64) {
self.lamports_per_signature = lamports_per_signature;
}
/// Get this invocation's lamports_per_signature value
pub fn get_lamports_per_signature(&self) -> u64 {
self.lamports_per_signature
}
/// Set the return data
pub fn set_return_data(&mut self, data: Vec<u8>) -> Result<(), InstructionError> {
self.return_data = (*self.get_caller()?, data);
Ok(())
}
/// Get the return data
pub fn get_return_data(&self) -> (Pubkey, &[u8]) {
(self.return_data.0, &self.return_data.1)
}
}
// This method which has a generic parameter is outside of the InvokeContext,
// because the InvokeContext is a dyn Trait.
pub fn get_sysvar<T: Sysvar>(
invoke_context: &InvokeContext,
id: &Pubkey,
) -> Result<T, InstructionError> {
invoke_context
.get_sysvars()
.iter()
.find_map(|(key, data)| {
if id == key {
bincode::deserialize(data).ok()
} else {
None
}
})
.ok_or_else(|| {
ic_msg!(invoke_context, "Unable to get sysvar {}", id);
InstructionError::UnsupportedSysvar
})
}
pub struct MockInvokeContextPreparation {
@ -1300,8 +1213,9 @@ mod tests {
.unwrap();
// not owned account modified by the caller (before the invoke)
let demote_program_write_locks =
invoke_context.is_feature_active(&demote_program_write_locks::id());
let demote_program_write_locks = invoke_context
.feature_set
.is_active(&demote_program_write_locks::id());
let caller_write_privileges = message
.account_keys
.iter()
@ -1509,12 +1423,8 @@ mod tests {
let mut feature_set = FeatureSet::all_enabled();
feature_set.deactivate(&tx_wide_compute_cap::id());
feature_set.deactivate(&requestable_heap_size::id());
let mut invoke_context = InvokeContext::new_mock_with_sysvars_and_features(
&accounts,
&[],
&[],
Arc::new(feature_set),
);
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
invoke_context.feature_set = Arc::new(feature_set);
invoke_context
.push(&noop_message, &noop_message.instructions[0], &[0], None)