Skip to content

Commit

Permalink
Flattens TransactionContext::instruction_trace.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lichtso committed Aug 12, 2022
1 parent 02a6b7a commit 26b0cf1
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 132 deletions.
36 changes: 12 additions & 24 deletions programs/bpf_loader/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1710,32 +1710,20 @@ declare_syscall!(
result
);

// Reverse iterate through the instruction trace,
// ignoring anything except instructions on the same level
let stack_height = invoke_context.get_stack_height();
let instruction_trace = invoke_context.transaction_context.get_instruction_trace();
let instruction_context = if stack_height == TRANSACTION_LEVEL_STACK_HEIGHT {
// pick one of the top-level instructions
instruction_trace
.len()
.checked_sub(2)
.and_then(|result| result.checked_sub(index as usize))
.and_then(|index| instruction_trace.get(index))
.and_then(|instruction_list| instruction_list.first())
} else {
// Walk the last list of inner instructions
instruction_trace.last().and_then(|inners| {
let mut current_index = 0;
inners.iter().rev().skip(1).find(|instruction_context| {
if stack_height == instruction_context.get_stack_height() {
if index == current_index {
return true;
} else {
current_index = current_index.saturating_add(1);
}
}
false
})
})
};
let mut current_index = 0;
let instruction_context = instruction_trace.iter().rev().find(|instruction_context| {
if instruction_context.get_stack_height() == stack_height {
if index.saturating_add(1) == current_index {
return true;
}
current_index = current_index.saturating_add(1);
}
false
});

if let Some(instruction_context) = instruction_context {
let ProcessedSiblingInstruction {
Expand Down
93 changes: 47 additions & 46 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ use {
hash::{extend_and_hash, hashv, Hash},
incinerator,
inflation::Inflation,
instruction::CompiledInstruction,
instruction::{CompiledInstruction, TRANSACTION_LEVEL_STACK_HEIGHT},
lamports::LamportsError,
message::{AccountKeys, SanitizedMessage},
native_loader,
Expand All @@ -144,7 +144,7 @@ use {
TransactionVerificationMode, VersionedTransaction,
},
transaction_context::{
ExecutionRecord, InstructionTrace, TransactionAccount, TransactionContext,
ExecutionRecord, InstructionContext, TransactionAccount, TransactionContext,
TransactionReturnData,
},
},
Expand Down Expand Up @@ -744,40 +744,45 @@ pub type InnerInstructions = Vec<CompiledInstruction>;
/// a transaction
pub type InnerInstructionsList = Vec<InnerInstructions>;

/// Convert from an InstructionTrace to InnerInstructionsList
/// Convert from an &[InstructionContext] to InnerInstructionsList
pub fn inner_instructions_list_from_instruction_trace(
instruction_trace: &InstructionTrace,
instruction_trace: &[InstructionContext],
) -> InnerInstructionsList {
instruction_trace
.iter()
.map(|inner_instructions_trace| {
inner_instructions_trace
.iter()
.skip(1)
.map(|instruction_context| {
CompiledInstruction::new_from_raw_parts(
instruction_context
.get_index_of_program_account_in_transaction(
instruction_context
.get_number_of_program_accounts()
.saturating_sub(1),
)
.unwrap_or_default() as u8,
instruction_context.get_instruction_data().to_vec(),
(0..instruction_context.get_number_of_instruction_accounts())
.map(|instruction_account_index| {
instruction_context
.get_index_of_instruction_account_in_transaction(
instruction_account_index,
)
.unwrap_or_default() as u8
})
.collect(),
)
})
.collect()
})
.collect()
debug_assert!(instruction_trace
.first()
.map(|instruction_context| instruction_context.get_stack_height()
== TRANSACTION_LEVEL_STACK_HEIGHT)
.unwrap_or(true));
let mut outer_instructions = Vec::new();
for instruction_context in instruction_trace.iter() {
if instruction_context.get_stack_height() == TRANSACTION_LEVEL_STACK_HEIGHT {
outer_instructions.push(Vec::new());
} else {
outer_instructions
.last_mut()
.unwrap()
.push(CompiledInstruction::new_from_raw_parts(
instruction_context
.get_index_of_program_account_in_transaction(
instruction_context
.get_number_of_program_accounts()
.saturating_sub(1),
)
.unwrap_or_default() as u8,
instruction_context.get_instruction_data().to_vec(),
(0..instruction_context.get_number_of_instruction_accounts())
.map(|instruction_account_index| {
instruction_context
.get_index_of_instruction_account_in_transaction(
instruction_account_index,
)
.unwrap_or_default() as u8
})
.collect(),
));
}
}
outer_instructions
}

/// A list of log messages emitted during a transaction
Expand Down Expand Up @@ -18892,25 +18897,21 @@ pub(crate) mod tests {
#[test]
fn test_inner_instructions_list_from_instruction_trace() {
let instruction_trace = vec![
vec![
InstructionContext::new(0, 0, &[], &[], &[1]),
InstructionContext::new(1, 0, &[], &[], &[2]),
],
vec![],
vec![
InstructionContext::new(0, 0, &[], &[], &[3]),
InstructionContext::new(1, 0, &[], &[], &[4]),
InstructionContext::new(2, 0, &[], &[], &[5]),
InstructionContext::new(1, 0, &[], &[], &[6]),
],
InstructionContext::new(0, 0, &[], &[], &[0]),
InstructionContext::new(1, 0, &[], &[], &[1]),
InstructionContext::new(0, 0, &[], &[], &[2]),
InstructionContext::new(0, 0, &[], &[], &[3]),
InstructionContext::new(1, 0, &[], &[], &[4]),
InstructionContext::new(2, 0, &[], &[], &[5]),
InstructionContext::new(1, 0, &[], &[], &[6]),
];

let inner_instructions = inner_instructions_list_from_instruction_trace(&instruction_trace);

assert_eq!(
inner_instructions,
vec![
vec![CompiledInstruction::new_from_raw_parts(0, vec![2], vec![])],
vec![CompiledInstruction::new_from_raw_parts(0, vec![1], vec![])],
vec![],
vec![
CompiledInstruction::new_from_raw_parts(0, vec![4], vec![]),
Expand Down
96 changes: 34 additions & 62 deletions sdk/src/transaction_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ pub struct TransactionContext {
account_touched_flags: RefCell<Pin<Box<[bool]>>>,
instruction_context_capacity: usize,
instruction_stack: Vec<usize>,
number_of_instructions_at_transaction_level: usize,
instruction_trace: InstructionTrace,
_number_of_instructions_at_transaction_level: usize,
instruction_trace: Vec<InstructionContext>,
return_data: TransactionReturnData,
accounts_resize_delta: RefCell<i64>,
rent: Option<Rent>,
Expand All @@ -75,8 +75,9 @@ impl TransactionContext {
account_touched_flags: RefCell::new(Pin::new(account_touched_flags.into_boxed_slice())),
instruction_context_capacity,
instruction_stack: Vec::with_capacity(instruction_context_capacity),
number_of_instructions_at_transaction_level,
instruction_trace: Vec::with_capacity(number_of_instructions_at_transaction_level),
_number_of_instructions_at_transaction_level:
number_of_instructions_at_transaction_level,
instruction_trace: Vec::new(),
return_data: TransactionReturnData::default(),
accounts_resize_delta: RefCell::new(0),
rent,
Expand Down Expand Up @@ -144,22 +145,13 @@ impl TransactionContext {
&self,
level: usize,
) -> Result<&InstructionContext, InstructionError> {
let top_level_index = *self
let index_in_trace = *self
.instruction_stack
.first()
.get(level)
.ok_or(InstructionError::CallDepth)?;
let cpi_index = if level == 0 {
0
} else {
*self
.instruction_stack
.get(level)
.ok_or(InstructionError::CallDepth)?
};
let instruction_context = self
.instruction_trace
.get(top_level_index)
.and_then(|instruction_trace| instruction_trace.get(cpi_index))
.get(index_in_trace)
.ok_or(InstructionError::CallDepth)?;
debug_assert_eq!(instruction_context.nesting_level, level);
Ok(instruction_context)
Expand Down Expand Up @@ -192,50 +184,33 @@ impl TransactionContext {
instruction_accounts: &[InstructionAccount],
instruction_data: &[u8],
) -> Result<(), InstructionError> {
if !self.instruction_stack.is_empty()
&& self.is_early_verification_of_account_modifications_enabled()
{
let caller_instruction_context = self.get_current_instruction_context()?;
let original_caller_instruction_accounts_lamport_sum =
caller_instruction_context.instruction_accounts_lamport_sum;
let current_caller_instruction_accounts_lamport_sum = self
.instruction_accounts_lamport_sum(
&caller_instruction_context.instruction_accounts,
)?;
if original_caller_instruction_accounts_lamport_sum
!= current_caller_instruction_accounts_lamport_sum
{
return Err(InstructionError::UnbalancedInstruction);
}
}
let callee_instruction_accounts_lamport_sum =
self.instruction_accounts_lamport_sum(instruction_accounts)?;
let index_in_trace = if self.instruction_stack.is_empty() {
debug_assert!(
self.instruction_trace.len() < self.number_of_instructions_at_transaction_level
);
let instruction_context = InstructionContext {
nesting_level: self.instruction_stack.len(),
instruction_accounts_lamport_sum: callee_instruction_accounts_lamport_sum,
program_accounts: program_accounts.to_vec(),
instruction_accounts: instruction_accounts.to_vec(),
instruction_data: instruction_data.to_vec(),
};
self.instruction_trace.push(vec![instruction_context]);
self.instruction_trace.len().saturating_sub(1)
} else {
if self.is_early_verification_of_account_modifications_enabled() {
let caller_instruction_context = self.get_current_instruction_context()?;
let original_caller_instruction_accounts_lamport_sum =
caller_instruction_context.instruction_accounts_lamport_sum;
let current_caller_instruction_accounts_lamport_sum = self
.instruction_accounts_lamport_sum(
&caller_instruction_context.instruction_accounts,
)?;
if original_caller_instruction_accounts_lamport_sum
!= current_caller_instruction_accounts_lamport_sum
{
return Err(InstructionError::UnbalancedInstruction);
}
}
if let Some(instruction_trace) = self.instruction_trace.last_mut() {
let instruction_context = InstructionContext {
nesting_level: self.instruction_stack.len(),
instruction_accounts_lamport_sum: callee_instruction_accounts_lamport_sum,
program_accounts: program_accounts.to_vec(),
instruction_accounts: instruction_accounts.to_vec(),
instruction_data: instruction_data.to_vec(),
};
instruction_trace.push(instruction_context);
instruction_trace.len().saturating_sub(1)
} else {
return Err(InstructionError::CallDepth);
}
let instruction_context = InstructionContext {
nesting_level: self.instruction_stack.len(),
instruction_accounts_lamport_sum: callee_instruction_accounts_lamport_sum,
program_accounts: program_accounts.to_vec(),
instruction_accounts: instruction_accounts.to_vec(),
instruction_data: instruction_data.to_vec(),
};
let index_in_trace = self.instruction_trace.len();
self.instruction_trace.push(instruction_context);
if self.instruction_stack.len() >= self.instruction_context_capacity {
return Err(InstructionError::CallDepth);
}
Expand Down Expand Up @@ -294,7 +269,7 @@ impl TransactionContext {
}

/// Returns instruction trace
pub fn get_instruction_trace(&self) -> &InstructionTrace {
pub fn get_instruction_trace(&self) -> &[InstructionContext] {
&self.instruction_trace
}

Expand Down Expand Up @@ -340,9 +315,6 @@ pub struct TransactionReturnData {
pub data: Vec<u8>,
}

/// List of (stack height, instruction) for each top-level instruction
pub type InstructionTrace = Vec<Vec<InstructionContext>>;

/// Loaded instruction shared between runtime and programs.
///
/// This context is valid for the entire duration of a (possibly cross program) instruction being processed.
Expand Down Expand Up @@ -912,7 +884,7 @@ impl<'a> BorrowedAccount<'a> {
/// Everything that needs to be recorded from a TransactionContext after execution
pub struct ExecutionRecord {
pub accounts: Vec<TransactionAccount>,
pub instruction_trace: InstructionTrace,
pub instruction_trace: Vec<InstructionContext>,
pub return_data: TransactionReturnData,
pub changed_account_count: u64,
pub total_size_of_all_accounts: u64,
Expand Down

0 comments on commit 26b0cf1

Please sign in to comment.