Refactor: CPI Instruction Recording (#22111)
* Unifies all InstructionRecorders of a transaction into one. * Stops explicitly compiling CPI instructions for recording, uses the indices gathered from instruction_accounts instead.
This commit is contained in:
parent
60ddd93d09
commit
cc947cad03
|
@ -1,30 +1,32 @@
|
||||||
use {
|
use {
|
||||||
solana_sdk::{
|
solana_sdk::instruction::CompiledInstruction,
|
||||||
instruction::{CompiledInstruction, Instruction},
|
|
||||||
message::SanitizedMessage,
|
|
||||||
},
|
|
||||||
std::{cell::RefCell, rc::Rc},
|
std::{cell::RefCell, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Records and compiles cross-program invoked instructions
|
/// Records and compiles cross-program invoked instructions
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone)]
|
||||||
pub struct InstructionRecorder {
|
pub struct InstructionRecorder {
|
||||||
inner: Rc<RefCell<Vec<Instruction>>>,
|
records: Vec<Vec<CompiledInstruction>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstructionRecorder {
|
impl InstructionRecorder {
|
||||||
pub fn compile_instructions(
|
pub fn new_ref(instructions_in_message: usize) -> Rc<RefCell<Self>> {
|
||||||
&self,
|
Rc::new(RefCell::new(Self {
|
||||||
message: &SanitizedMessage,
|
records: Vec::with_capacity(instructions_in_message),
|
||||||
) -> Option<Vec<CompiledInstruction>> {
|
}))
|
||||||
self.inner
|
|
||||||
.borrow()
|
|
||||||
.iter()
|
|
||||||
.map(|ix| message.try_compile_instruction(ix))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record_instruction(&self, instruction: Instruction) {
|
pub fn deconstruct(self) -> Vec<Vec<CompiledInstruction>> {
|
||||||
self.inner.borrow_mut().push(instruction);
|
self.records
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn begin_next_recording(&mut self) {
|
||||||
|
self.records.push(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn record_compiled_instruction(&mut self, instruction: CompiledInstruction) {
|
||||||
|
if let Some(records) = self.records.last_mut() {
|
||||||
|
records.push(instruction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use {
|
||||||
remove_native_loader, requestable_heap_size, tx_wide_compute_cap, FeatureSet,
|
remove_native_loader, requestable_heap_size, tx_wide_compute_cap, FeatureSet,
|
||||||
},
|
},
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
|
||||||
keyed_account::{create_keyed_accounts_unified, keyed_account_at_index, KeyedAccount},
|
keyed_account::{create_keyed_accounts_unified, keyed_account_at_index, KeyedAccount},
|
||||||
native_loader,
|
native_loader,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
|
@ -155,7 +155,7 @@ pub struct InvokeContext<'a> {
|
||||||
current_compute_budget: ComputeBudget,
|
current_compute_budget: ComputeBudget,
|
||||||
compute_meter: Rc<RefCell<ComputeMeter>>,
|
compute_meter: Rc<RefCell<ComputeMeter>>,
|
||||||
executors: Rc<RefCell<Executors>>,
|
executors: Rc<RefCell<Executors>>,
|
||||||
pub instruction_recorder: Option<&'a InstructionRecorder>,
|
pub instruction_recorder: Option<Rc<RefCell<InstructionRecorder>>>,
|
||||||
pub feature_set: Arc<FeatureSet>,
|
pub feature_set: Arc<FeatureSet>,
|
||||||
pub timings: ExecuteDetailsTimings,
|
pub timings: ExecuteDetailsTimings,
|
||||||
pub blockhash: Hash,
|
pub blockhash: Hash,
|
||||||
|
@ -173,6 +173,7 @@ impl<'a> InvokeContext<'a> {
|
||||||
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
||||||
compute_budget: ComputeBudget,
|
compute_budget: ComputeBudget,
|
||||||
executors: Rc<RefCell<Executors>>,
|
executors: Rc<RefCell<Executors>>,
|
||||||
|
instruction_recorder: Option<Rc<RefCell<InstructionRecorder>>>,
|
||||||
feature_set: Arc<FeatureSet>,
|
feature_set: Arc<FeatureSet>,
|
||||||
blockhash: Hash,
|
blockhash: Hash,
|
||||||
lamports_per_signature: u64,
|
lamports_per_signature: u64,
|
||||||
|
@ -189,7 +190,7 @@ impl<'a> InvokeContext<'a> {
|
||||||
compute_budget,
|
compute_budget,
|
||||||
compute_meter: ComputeMeter::new_ref(compute_budget.max_units),
|
compute_meter: ComputeMeter::new_ref(compute_budget.max_units),
|
||||||
executors,
|
executors,
|
||||||
instruction_recorder: None,
|
instruction_recorder,
|
||||||
feature_set,
|
feature_set,
|
||||||
timings: ExecuteDetailsTimings::default(),
|
timings: ExecuteDetailsTimings::default(),
|
||||||
blockhash,
|
blockhash,
|
||||||
|
@ -210,6 +211,7 @@ impl<'a> InvokeContext<'a> {
|
||||||
Some(LogCollector::new_ref()),
|
Some(LogCollector::new_ref()),
|
||||||
ComputeBudget::default(),
|
ComputeBudget::default(),
|
||||||
Rc::new(RefCell::new(Executors::default())),
|
Rc::new(RefCell::new(Executors::default())),
|
||||||
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
Hash::default(),
|
Hash::default(),
|
||||||
0,
|
0,
|
||||||
|
@ -493,9 +495,6 @@ impl<'a> InvokeContext<'a> {
|
||||||
prev_account_sizes.push((instruction_account.index, account_length));
|
prev_account_sizes.push((instruction_account.index, account_length));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(instruction_recorder) = &self.instruction_recorder {
|
|
||||||
instruction_recorder.record_instruction(instruction.clone());
|
|
||||||
}
|
|
||||||
self.process_instruction(
|
self.process_instruction(
|
||||||
&instruction.data,
|
&instruction.data,
|
||||||
&instruction_accounts,
|
&instruction_accounts,
|
||||||
|
@ -683,9 +682,32 @@ impl<'a> InvokeContext<'a> {
|
||||||
.unwrap_or_else(native_loader::id);
|
.unwrap_or_else(native_loader::id);
|
||||||
|
|
||||||
let is_lowest_invocation_level = self.invoke_stack.is_empty();
|
let is_lowest_invocation_level = self.invoke_stack.is_empty();
|
||||||
if !is_lowest_invocation_level {
|
if is_lowest_invocation_level {
|
||||||
|
if let Some(instruction_recorder) = &self.instruction_recorder {
|
||||||
|
instruction_recorder.borrow_mut().begin_next_recording();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// Verify the calling program hasn't misbehaved
|
// Verify the calling program hasn't misbehaved
|
||||||
self.verify_and_update(instruction_accounts, caller_write_privileges)?;
|
self.verify_and_update(instruction_accounts, caller_write_privileges)?;
|
||||||
|
|
||||||
|
// Record instruction
|
||||||
|
if let Some(instruction_recorder) = &self.instruction_recorder {
|
||||||
|
let compiled_instruction = CompiledInstruction {
|
||||||
|
program_id_index: self
|
||||||
|
.accounts
|
||||||
|
.iter()
|
||||||
|
.position(|(key, _account)| *key == program_id)
|
||||||
|
.unwrap_or(0) as u8,
|
||||||
|
data: instruction_data.to_vec(),
|
||||||
|
accounts: instruction_accounts
|
||||||
|
.iter()
|
||||||
|
.map(|instruction_account| instruction_account.index as u8)
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
instruction_recorder
|
||||||
|
.borrow_mut()
|
||||||
|
.record_compiled_instruction(compiled_instruction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
|
|
|
@ -273,9 +273,6 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(instruction_recorder) = &invoke_context.instruction_recorder {
|
|
||||||
instruction_recorder.record_instruction(instruction.clone());
|
|
||||||
}
|
|
||||||
invoke_context
|
invoke_context
|
||||||
.process_instruction(
|
.process_instruction(
|
||||||
&instruction.data,
|
&instruction.data,
|
||||||
|
|
|
@ -2382,11 +2382,6 @@ fn call<'a, 'b: 'a>(
|
||||||
*invoke_context,
|
*invoke_context,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Record the instruction
|
|
||||||
if let Some(instruction_recorder) = &invoke_context.instruction_recorder {
|
|
||||||
instruction_recorder.record_instruction(instruction.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process instruction
|
// Process instruction
|
||||||
invoke_context
|
invoke_context
|
||||||
.process_instruction(
|
.process_instruction(
|
||||||
|
|
|
@ -3576,11 +3576,10 @@ impl Bank {
|
||||||
let account_refcells =
|
let account_refcells =
|
||||||
Self::accounts_to_refcells(&mut loaded_transaction.accounts);
|
Self::accounts_to_refcells(&mut loaded_transaction.accounts);
|
||||||
|
|
||||||
let instruction_recorders = if enable_cpi_recording {
|
let instruction_recorder = if enable_cpi_recording {
|
||||||
let ix_count = tx.message().instructions().len();
|
Some(InstructionRecorder::new_ref(
|
||||||
let mut recorders = Vec::with_capacity(ix_count);
|
tx.message().instructions().len(),
|
||||||
recorders.resize_with(ix_count, InstructionRecorder::default);
|
))
|
||||||
Some(recorders)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -3603,7 +3602,7 @@ impl Bank {
|
||||||
self.rent_collector.rent,
|
self.rent_collector.rent,
|
||||||
log_collector.clone(),
|
log_collector.clone(),
|
||||||
executors.clone(),
|
executors.clone(),
|
||||||
instruction_recorders.as_deref(),
|
instruction_recorder.clone(),
|
||||||
feature_set,
|
feature_set,
|
||||||
compute_budget,
|
compute_budget,
|
||||||
&mut timings.details,
|
&mut timings.details,
|
||||||
|
@ -3628,14 +3627,15 @@ impl Bank {
|
||||||
.ok()
|
.ok()
|
||||||
});
|
});
|
||||||
transaction_log_messages.push(log_messages);
|
transaction_log_messages.push(log_messages);
|
||||||
let inner_instruction_list: Option<InnerInstructionsList> =
|
inner_instructions.push(
|
||||||
instruction_recorders.and_then(|instruction_recorders| {
|
instruction_recorder
|
||||||
instruction_recorders
|
.and_then(|instruction_recorder| {
|
||||||
.into_iter()
|
Rc::try_unwrap(instruction_recorder).ok()
|
||||||
.map(|r| r.compile_instructions(tx.message()))
|
})
|
||||||
.collect()
|
.map(|instruction_recorder| {
|
||||||
});
|
instruction_recorder.into_inner().deconstruct()
|
||||||
inner_instructions.push(inner_instruction_list);
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
Self::refcells_to_accounts(
|
Self::refcells_to_accounts(
|
||||||
&mut loaded_transaction.accounts,
|
&mut loaded_transaction.accounts,
|
||||||
|
|
|
@ -58,7 +58,7 @@ impl MessageProcessor {
|
||||||
rent: Rent,
|
rent: Rent,
|
||||||
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
||||||
executors: Rc<RefCell<Executors>>,
|
executors: Rc<RefCell<Executors>>,
|
||||||
instruction_recorders: Option<&[InstructionRecorder]>,
|
instruction_recorder: Option<Rc<RefCell<InstructionRecorder>>>,
|
||||||
feature_set: Arc<FeatureSet>,
|
feature_set: Arc<FeatureSet>,
|
||||||
compute_budget: ComputeBudget,
|
compute_budget: ComputeBudget,
|
||||||
timings: &mut ExecuteDetailsTimings,
|
timings: &mut ExecuteDetailsTimings,
|
||||||
|
@ -74,6 +74,7 @@ impl MessageProcessor {
|
||||||
log_collector,
|
log_collector,
|
||||||
compute_budget,
|
compute_budget,
|
||||||
executors,
|
executors,
|
||||||
|
instruction_recorder,
|
||||||
feature_set,
|
feature_set,
|
||||||
blockhash,
|
blockhash,
|
||||||
lamports_per_signature,
|
lamports_per_signature,
|
||||||
|
@ -109,10 +110,6 @@ impl MessageProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(instruction_recorders) = instruction_recorders {
|
|
||||||
invoke_context.instruction_recorder =
|
|
||||||
Some(&instruction_recorders[instruction_index]);
|
|
||||||
}
|
|
||||||
let instruction_accounts = instruction
|
let instruction_accounts = instruction
|
||||||
.accounts
|
.accounts
|
||||||
.iter()
|
.iter()
|
||||||
|
|
Loading…
Reference in New Issue