Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 33 additions & 5 deletions program-runtime/src/instruction_recorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use {
};

/// Records and compiles cross-program invoked instructions
#[derive(Clone, Default)]
#[derive(Clone, Debug, Default, PartialEq)]
pub struct InstructionRecorder {
inner: Rc<RefCell<Vec<Instruction>>>,
inner: Rc<RefCell<Vec<(usize, Instruction)>>>,
}

impl InstructionRecorder {
Expand All @@ -20,11 +20,39 @@ impl InstructionRecorder {
self.inner
.borrow()
.iter()
.map(|ix| message.try_compile_instruction(ix))
.skip(1)
.map(|(_, ix)| message.try_compile_instruction(ix))
.collect()
}

pub fn record_instruction(&self, instruction: Instruction) {
self.inner.borrow_mut().push(instruction);
pub fn record_instruction(&self, stack_height: usize, instruction: Instruction) {
self.inner.borrow_mut().push((stack_height, instruction));
}

pub fn get(&self, index: usize) -> Option<Instruction> {
self.inner
.borrow()
.get(index)
.map(|(_, instruction)| instruction.clone())
}

pub fn find(&self, stack_height: usize, index: usize) -> Option<Instruction> {
let mut current_index = 0;
self.inner
.borrow()
.iter()
.rev()
.skip(1)
.find(|(this_stack_height, _)| {
if stack_height == *this_stack_height {
if index == current_index {
return true;
} else {
current_index = current_index.saturating_add(1);
}
}
false
})
.map(|(_, instruction)| instruction.clone())
}
}
40 changes: 32 additions & 8 deletions program-runtime/src/invoke_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ use {
tx_wide_compute_cap, FeatureSet,
},
hash::Hash,
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
instruction::{
AccountMeta, CompiledInstruction, Instruction, InstructionError,
TRANSACTION_LEVEL_STACK_HEIGHT,
},
keyed_account::{create_keyed_accounts_unified, keyed_account_at_index, KeyedAccount},
message::{Message, SanitizedMessage},
pubkey::Pubkey,
Expand Down Expand Up @@ -201,7 +204,7 @@ pub struct InvokeContext<'a> {
compute_meter: Rc<RefCell<ComputeMeter>>,
accounts_data_meter: AccountsDataMeter,
executors: Rc<RefCell<Executors>>,
pub instruction_recorder: Option<&'a InstructionRecorder>,
pub instruction_trace: Vec<InstructionRecorder>,
pub feature_set: Arc<FeatureSet>,
pub timings: ExecuteDetailsTimings,
pub blockhash: Hash,
Expand Down Expand Up @@ -237,7 +240,7 @@ impl<'a> InvokeContext<'a> {
compute_meter: ComputeMeter::new_ref(compute_budget.max_units),
accounts_data_meter: AccountsDataMeter::new(current_accounts_data_len),
executors,
instruction_recorder: None,
instruction_trace: Vec::new(),
feature_set,
timings: ExecuteDetailsTimings::default(),
blockhash,
Expand Down Expand Up @@ -375,8 +378,8 @@ impl<'a> InvokeContext<'a> {
self.invoke_stack.pop();
}

/// Current depth of the invocation stack
pub fn invoke_depth(&self) -> usize {
/// Current height of the stack
pub fn get_stack_height(&self) -> usize {
self.invoke_stack.len()
}

Expand Down Expand Up @@ -566,9 +569,7 @@ impl<'a> InvokeContext<'a> {
prev_account_sizes.push((account, account_length));
}

if let Some(instruction_recorder) = &self.instruction_recorder {
instruction_recorder.record_instruction(instruction);
}
self.record_instruction(self.get_stack_height(), instruction);

let message = SanitizedMessage::Legacy(message);
self.process_instruction(
Expand Down Expand Up @@ -954,6 +955,29 @@ impl<'a> InvokeContext<'a> {
pub fn get_sysvar_cache(&self) -> &SysvarCache {
&self.sysvar_cache
}

/// Record top-level instruction in the instruction trace
pub fn record_top_level_instruction(&mut self, instruction: Instruction) {
self.instruction_trace.push(InstructionRecorder::default());
self.record_instruction(TRANSACTION_LEVEL_STACK_HEIGHT, instruction);
}

/// Record instruction in the instruction trace
pub fn record_instruction(&mut self, stack_height: usize, instruction: Instruction) {
if let Some(instruction_recorder) = self.instruction_trace.last() {
instruction_recorder.record_instruction(stack_height, instruction)
}
}

/// Get the instruction trace
pub fn get_instruction_trace(&self) -> &[InstructionRecorder] {
&self.instruction_trace
}

/// Get the mutable instruction trace
pub fn get_instruction_trace_mut(&mut self) -> &mut Vec<InstructionRecorder> {
&mut self.instruction_trace
}
}

pub struct MockInvokeContextPreparation {
Expand Down
16 changes: 11 additions & 5 deletions program-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,11 @@ pub fn builtin_process_instruction(

let log_collector = invoke_context.get_log_collector();
let program_id = invoke_context.get_caller()?;
stable_log::program_invoke(&log_collector, program_id, invoke_context.invoke_depth());
stable_log::program_invoke(
&log_collector,
program_id,
invoke_context.get_stack_height(),
);

// Skip the processor account
let keyed_accounts = &invoke_context.get_keyed_accounts()?[1..];
Expand Down Expand Up @@ -246,7 +250,11 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
.map(|(i, _)| message.is_writable(i))
.collect::<Vec<bool>>();

stable_log::program_invoke(&log_collector, &program_id, invoke_context.invoke_depth());
stable_log::program_invoke(
&log_collector,
&program_id,
invoke_context.get_stack_height(),
);

// Convert AccountInfos into Accounts
let mut account_indices = Vec::with_capacity(message.account_keys.len());
Expand Down Expand Up @@ -305,9 +313,7 @@ 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.record_instruction(invoke_context.get_stack_height(), instruction.clone());

let message = SanitizedMessage::Legacy(message);
invoke_context
Expand Down
14 changes: 14 additions & 0 deletions programs/bpf/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions programs/bpf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ members = [
"rust/sanity",
"rust/secp256k1_recover",
"rust/sha",
"rust/sibling_inner_instruction",
"rust/sibling_instruction",
"rust/spoof1",
"rust/spoof1_system",
"rust/sysvar",
Expand Down
2 changes: 2 additions & 0 deletions programs/bpf/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ fn main() {
"sanity",
"secp256k1_recover",
"sha",
"sibling_inner_instruction",
"sibling_instruction",
"spoof1",
"spoof1_system",
"upgradeable",
Expand Down
23 changes: 23 additions & 0 deletions programs/bpf/rust/sibling_inner_instruction/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "solana-bpf-rust-sibling_inner-instructions"
version = "1.9.6"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-bpf-rust-log-data"
edition = "2021"

[dependencies]
solana-program = { path = "../../../../sdk/program", version = "=1.9.6" }

[features]
default = ["program"]
program = []

[lib]
crate-type = ["lib", "cdylib"]

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
69 changes: 69 additions & 0 deletions programs/bpf/rust/sibling_inner_instruction/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//! Example Rust-based BPF program that queries sibling instructions

#![cfg(feature = "program")]

use solana_program::{
account_info::AccountInfo,
entrypoint,
entrypoint::ProgramResult,
instruction::{
get_processed_sibling_instruction, get_stack_height, AccountMeta, Instruction,
TRANSACTION_LEVEL_STACK_HEIGHT,
},
msg,
pubkey::Pubkey,
};

entrypoint!(process_instruction);
fn process_instruction(
_program_id: &Pubkey,
accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
msg!("sibling inner");

// account 0 is mint
// account 1 is noop
// account 2 is invoke_and_return

// Check sibling instructions

let sibling_instruction2 = Instruction::new_with_bytes(
*accounts[2].key,
&[3],
vec![AccountMeta::new_readonly(*accounts[1].key, false)],
);
let sibling_instruction1 = Instruction::new_with_bytes(
*accounts[1].key,
&[2],
vec![
AccountMeta::new_readonly(*accounts[0].key, true),
AccountMeta::new_readonly(*accounts[1].key, false),
],
);
let sibling_instruction0 = Instruction::new_with_bytes(
*accounts[1].key,
&[1],
vec![
AccountMeta::new_readonly(*accounts[1].key, false),
AccountMeta::new_readonly(*accounts[0].key, true),
],
);

assert_eq!(TRANSACTION_LEVEL_STACK_HEIGHT + 1, get_stack_height());
assert_eq!(
get_processed_sibling_instruction(0),
Some(sibling_instruction0)
);
assert_eq!(
get_processed_sibling_instruction(1),
Some(sibling_instruction1)
);
assert_eq!(
get_processed_sibling_instruction(2),
Some(sibling_instruction2)
);
assert_eq!(get_processed_sibling_instruction(3), None);

Ok(())
}
23 changes: 23 additions & 0 deletions programs/bpf/rust/sibling_instruction/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "solana-bpf-rust-sibling-instructions"
version = "1.9.6"
description = "Solana BPF test program written in Rust"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-bpf-rust-log-data"
edition = "2021"

[dependencies]
solana-program = { path = "../../../../sdk/program", version = "=1.9.6" }

[features]
default = ["program"]
program = []

[lib]
crate-type = ["lib", "cdylib"]

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
Loading