Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

Commit

Permalink
Record inner instruction stack height
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarry committed Oct 17, 2022
1 parent c9e0337 commit 546b579
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 35 deletions.
17 changes: 13 additions & 4 deletions ledger/src/blockstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4394,7 +4394,7 @@ pub mod tests {
rand::{seq::SliceRandom, thread_rng},
solana_account_decoder::parse_token::UiTokenAmount,
solana_entry::entry::{next_entry, next_entry_mut},
solana_runtime::bank::{Bank, RewardType},
solana_runtime::bank::{Bank, InnerInstruction, RewardType},
solana_sdk::{
hash::{self, hash, Hash},
instruction::CompiledInstruction,
Expand Down Expand Up @@ -6838,7 +6838,10 @@ pub mod tests {
let post_balances_vec = vec![3, 2, 1];
let inner_instructions_vec = vec![InnerInstructions {
index: 0,
instructions: vec![CompiledInstruction::new(1, &(), vec![0])],
instructions: vec![InnerInstruction {
instruction: CompiledInstruction::new(1, &(), vec![0]),
stack_height: Some(2),
}],
}];
let log_messages_vec = vec![String::from("Test message\n")];
let pre_token_balances_vec = vec![];
Expand Down Expand Up @@ -7570,7 +7573,10 @@ pub mod tests {
}
let inner_instructions = Some(vec![InnerInstructions {
index: 0,
instructions: vec![CompiledInstruction::new(1, &(), vec![0])],
instructions: vec![InnerInstruction {
instruction: CompiledInstruction::new(1, &(), vec![0]),
stack_height: Some(2),
}],
}]);
let log_messages = Some(vec![String::from("Test message\n")]);
let pre_token_balances = Some(vec![]);
Expand Down Expand Up @@ -7687,7 +7693,10 @@ pub mod tests {
}
let inner_instructions = Some(vec![InnerInstructions {
index: 0,
instructions: vec![CompiledInstruction::new(1, &(), vec![0])],
instructions: vec![InnerInstruction {
instruction: CompiledInstruction::new(1, &(), vec![0]),
stack_height: Some(2),
}],
}]);
let log_messages = Some(vec![String::from("Test message\n")]);
let pre_token_balances = Some(vec![]);
Expand Down
1 change: 1 addition & 0 deletions rpc-client/src/mock_sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ impl RpcSender for MockSender {
program_id_index: 2,
accounts: vec![0, 1],
data: "3Bxs49DitAvXtoDR".to_string(),
stack_height: None,
}],
address_table_lookups: None,
})
Expand Down
10 changes: 8 additions & 2 deletions rpc/src/transaction_status_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use {
},
solana_runtime::bank::{DurableNonceFee, TransactionExecutionDetails},
solana_transaction_status::{
extract_and_fmt_memos, InnerInstructions, Reward, TransactionStatusMeta,
extract_and_fmt_memos, InnerInstruction, InnerInstructions, Reward, TransactionStatusMeta,
},
std::{
sync::{
Expand Down Expand Up @@ -128,7 +128,13 @@ impl TransactionStatusService {
.enumerate()
.map(|(index, instructions)| InnerInstructions {
index: index as u8,
instructions,
instructions: instructions
.into_iter()
.map(|info| InnerInstruction {
instruction: info.instruction,
stack_height: info.stack_height,
})
.collect(),
})
.filter(|i| !i.instructions.is_empty())
.collect()
Expand Down
43 changes: 35 additions & 8 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,16 @@ pub type TransactionBalances = Vec<Vec<u64>>;

/// An ordered list of compiled instructions that were invoked during a
/// transaction instruction
pub type InnerInstructions = Vec<CompiledInstruction>;
pub type InnerInstructions = Vec<InnerInstruction>;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct InnerInstruction {
pub instruction: CompiledInstruction,
/// Invocation stack height of this instruction. Instruction stack height
/// starts at 1 for transaction instructions. This field is set to `None`
/// for transactions that were processed prior to stack height tracking.
pub stack_height: Option<u32>,
}

/// A list of compiled instructions that were invoked during each instruction of
/// a transaction
Expand All @@ -510,10 +519,12 @@ pub fn inner_instructions_list_from_instruction_trace(
if let Ok(instruction_context) =
transaction_context.get_instruction_context_at_index_in_trace(index_in_trace)
{
if instruction_context.get_stack_height() == TRANSACTION_LEVEL_STACK_HEIGHT {
let stack_height = instruction_context.get_stack_height();
if stack_height == TRANSACTION_LEVEL_STACK_HEIGHT {
outer_instructions.push(Vec::new());
} else if let Some(inner_instructions) = outer_instructions.last_mut() {
inner_instructions.push(CompiledInstruction::new_from_raw_parts(
let stack_height = u32::try_from(stack_height).unwrap_or(u32::MAX);
let instruction = CompiledInstruction::new_from_raw_parts(
instruction_context
.get_index_of_program_account_in_transaction(
instruction_context
Expand All @@ -531,7 +542,11 @@ pub fn inner_instructions_list_from_instruction_trace(
.unwrap_or_default() as u8
})
.collect(),
));
);
inner_instructions.push(InnerInstruction {
instruction,
stack_height: Some(stack_height),
});
} else {
debug_assert!(false);
}
Expand Down Expand Up @@ -18466,12 +18481,24 @@ pub(crate) mod tests {
assert_eq!(
inner_instructions,
vec![
vec![CompiledInstruction::new_from_raw_parts(0, vec![1], vec![])],
vec![InnerInstruction {
instruction: CompiledInstruction::new_from_raw_parts(0, vec![1], vec![]),
stack_height: Some(2),
}],
vec![],
vec![
CompiledInstruction::new_from_raw_parts(0, vec![4], vec![]),
CompiledInstruction::new_from_raw_parts(0, vec![5], vec![]),
CompiledInstruction::new_from_raw_parts(0, vec![6], vec![])
InnerInstruction {
instruction: CompiledInstruction::new_from_raw_parts(0, vec![4], vec![]),
stack_height: Some(2),
},
InnerInstruction {
instruction: CompiledInstruction::new_from_raw_parts(0, vec![5], vec![]),
stack_height: Some(3),
},
InnerInstruction {
instruction: CompiledInstruction::new_from_raw_parts(0, vec![6], vec![]),
stack_height: Some(2),
},
]
]
);
Expand Down
13 changes: 12 additions & 1 deletion storage-proto/proto/confirmed_block.proto
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,18 @@ message TransactionError {

message InnerInstructions {
uint32 index = 1;
repeated CompiledInstruction instructions = 2;
repeated InnerInstruction instructions = 2;
}

message InnerInstruction {
uint32 program_id_index = 1;
bytes accounts = 2;
bytes data = 3;

// Invocation stack height of an inner instruction.
// Available since Solana v1.14.6
// Set to `None` for txs executed on earlier versions.
optional uint32 stack_height = 4;
}

message CompiledInstruction {
Expand Down
30 changes: 27 additions & 3 deletions storage-proto/src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ use {
transaction_context::TransactionReturnData,
},
solana_transaction_status::{
ConfirmedBlock, InnerInstructions, Reward, RewardType, TransactionByAddrInfo,
TransactionStatusMeta, TransactionTokenBalance, TransactionWithStatusMeta,
VersionedConfirmedBlock, VersionedTransactionWithStatusMeta,
ConfirmedBlock, InnerInstruction, InnerInstructions, Reward, RewardType,
TransactionByAddrInfo, TransactionStatusMeta, TransactionTokenBalance,
TransactionWithStatusMeta, VersionedConfirmedBlock, VersionedTransactionWithStatusMeta,
},
std::{
convert::{TryFrom, TryInto},
Expand Down Expand Up @@ -647,6 +647,30 @@ impl From<generated::CompiledInstruction> for CompiledInstruction {
}
}

impl From<InnerInstruction> for generated::InnerInstruction {
fn from(value: InnerInstruction) -> Self {
Self {
program_id_index: value.instruction.program_id_index as u32,
accounts: value.instruction.accounts,
data: value.instruction.data,
stack_height: value.stack_height,
}
}
}

impl From<generated::InnerInstruction> for InnerInstruction {
fn from(value: generated::InnerInstruction) -> Self {
Self {
instruction: CompiledInstruction {
program_id_index: value.program_id_index as u8,
accounts: value.accounts,
data: value.data,
},
stack_height: value.stack_height,
}
}
}

impl TryFrom<tx_by_addr::TransactionError> for TransactionError {
type Error = &'static str;

Expand Down
70 changes: 56 additions & 14 deletions transaction-status/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,17 @@ pub enum UiInstruction {
}

impl UiInstruction {
fn parse(instruction: &CompiledInstruction, account_keys: &AccountKeys) -> Self {
fn parse(
instruction: &CompiledInstruction,
account_keys: &AccountKeys,
stack_height: Option<u32>,
) -> Self {
let program_id = &account_keys[instruction.program_id_index as usize];
if let Ok(parsed_instruction) = parse(program_id, instruction, account_keys) {
if let Ok(parsed_instruction) = parse(program_id, instruction, account_keys, stack_height) {
UiInstruction::Parsed(UiParsedInstruction::Parsed(parsed_instruction))
} else {
UiInstruction::Parsed(UiParsedInstruction::PartiallyDecoded(
UiPartiallyDecodedInstruction::from(instruction, account_keys),
UiPartiallyDecodedInstruction::from(instruction, account_keys, stack_height),
))
}
}
Expand All @@ -165,14 +169,16 @@ pub struct UiCompiledInstruction {
pub program_id_index: u8,
pub accounts: Vec<u8>,
pub data: String,
pub stack_height: Option<u32>,
}

impl From<&CompiledInstruction> for UiCompiledInstruction {
fn from(instruction: &CompiledInstruction) -> Self {
impl UiCompiledInstruction {
fn from(instruction: &CompiledInstruction, stack_height: Option<u32>) -> Self {
Self {
program_id_index: instruction.program_id_index,
accounts: instruction.accounts.clone(),
data: bs58::encode(instruction.data.clone()).into_string(),
data: bs58::encode(&instruction.data).into_string(),
stack_height,
}
}
}
Expand All @@ -184,10 +190,15 @@ pub struct UiPartiallyDecodedInstruction {
pub program_id: String,
pub accounts: Vec<String>,
pub data: String,
pub stack_height: Option<u32>,
}

impl UiPartiallyDecodedInstruction {
fn from(instruction: &CompiledInstruction, account_keys: &AccountKeys) -> Self {
fn from(
instruction: &CompiledInstruction,
account_keys: &AccountKeys,
stack_height: Option<u32>,
) -> Self {
Self {
program_id: account_keys[instruction.program_id_index as usize].to_string(),
accounts: instruction
Expand All @@ -196,6 +207,7 @@ impl UiPartiallyDecodedInstruction {
.map(|&i| account_keys[i as usize].to_string())
.collect(),
data: bs58::encode(instruction.data.clone()).into_string(),
stack_height,
}
}
}
Expand All @@ -205,7 +217,15 @@ pub struct InnerInstructions {
/// Transaction instruction index
pub index: u8,
/// List of inner instructions
pub instructions: Vec<CompiledInstruction>,
pub instructions: Vec<InnerInstruction>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct InnerInstruction {
/// Compiled instruction
pub instruction: CompiledInstruction,
/// Invocation stack height of the instruction,
pub stack_height: Option<u32>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
Expand All @@ -224,7 +244,14 @@ impl UiInnerInstructions {
instructions: inner_instructions
.instructions
.iter()
.map(|ix| UiInstruction::parse(ix, account_keys))
.map(
|InnerInstruction {
instruction: ix,
stack_height,
}| {
UiInstruction::parse(ix, account_keys, *stack_height)
},
)
.collect(),
}
}
Expand All @@ -237,7 +264,14 @@ impl From<InnerInstructions> for UiInnerInstructions {
instructions: inner_instructions
.instructions
.iter()
.map(|ix| UiInstruction::Compiled(ix.into()))
.map(
|InnerInstruction {
instruction: ix,
stack_height,
}| {
UiInstruction::Compiled(UiCompiledInstruction::from(ix, *stack_height))
},
)
.collect(),
}
}
Expand Down Expand Up @@ -1091,7 +1125,7 @@ impl Encodable for Message {
instructions: self
.instructions
.iter()
.map(|instruction| UiInstruction::parse(instruction, &account_keys))
.map(|instruction| UiInstruction::parse(instruction, &account_keys, None))
.collect(),
address_table_lookups: None,
})
Expand All @@ -1100,7 +1134,11 @@ impl Encodable for Message {
header: self.header,
account_keys: self.account_keys.iter().map(ToString::to_string).collect(),
recent_blockhash: self.recent_blockhash.to_string(),
instructions: self.instructions.iter().map(Into::into).collect(),
instructions: self
.instructions
.iter()
.map(|ix| UiCompiledInstruction::from(ix, None))
.collect(),
address_table_lookups: None,
})
}
Expand All @@ -1123,7 +1161,7 @@ impl EncodableWithMeta for v0::Message {
instructions: self
.instructions
.iter()
.map(|instruction| UiInstruction::parse(instruction, &account_keys))
.map(|instruction| UiInstruction::parse(instruction, &account_keys, None))
.collect(),
address_table_lookups: Some(
self.address_table_lookups.iter().map(Into::into).collect(),
Expand All @@ -1138,7 +1176,11 @@ impl EncodableWithMeta for v0::Message {
header: self.header,
account_keys: self.account_keys.iter().map(ToString::to_string).collect(),
recent_blockhash: self.recent_blockhash.to_string(),
instructions: self.instructions.iter().map(Into::into).collect(),
instructions: self
.instructions
.iter()
.map(|ix| UiCompiledInstruction::from(ix, None))
.collect(),
address_table_lookups: Some(
self.address_table_lookups.iter().map(Into::into).collect(),
),
Expand Down
Loading

0 comments on commit 546b579

Please sign in to comment.