1use solana_account::{Account, AccountSharedData};
2use solana_address::Address;
3use solana_instruction::{Instruction, account_meta::AccountMeta, error::InstructionError};
4use solana_message::inner_instruction::InnerInstructionsList;
5use solana_program_error::ProgramError;
6use solana_signature::Signature;
7use solana_transaction_context::TransactionReturnData;
8use solana_transaction_error::{TransactionError, TransactionResult as Result};
9
10use crate::{error::HPSVMError, format_logs::format_logs};
11
12#[expect(missing_docs)]
13#[derive(Debug, Default, Clone, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct TransactionMetadata {
16 #[cfg_attr(feature = "serde", serde(with = "crate::utils::serde_with_str"))]
17 pub signature: Signature,
18 pub logs: Vec<String>,
19 pub inner_instructions: InnerInstructionsList,
20 pub compute_units_consumed: u64,
21 pub return_data: TransactionReturnData,
22 pub fee: u64,
23 #[cfg_attr(feature = "serde", serde(default))]
24 pub diagnostics: ExecutionDiagnostics,
25}
26
27impl TransactionMetadata {
28 #[expect(missing_docs)]
29 pub fn pretty_logs(&self) -> String {
30 format_logs(&self.logs)
31 }
32}
33
34#[expect(missing_docs)]
36#[derive(Debug, Default, Clone, PartialEq, Eq)]
37#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
38#[non_exhaustive]
39pub struct ExecutionDiagnostics {
40 pub pre_balances: Vec<u64>,
41 pub post_balances: Vec<u64>,
42 pub account_diffs: Vec<AccountDiff>,
43 pub account_source_failures: Vec<AccountSourceFailure>,
44 pub pre_token_balances: Vec<TokenBalance>,
45 pub post_token_balances: Vec<TokenBalance>,
46 pub execution_trace: ExecutionTrace,
47}
48
49#[expect(missing_docs)]
51#[derive(Debug, Clone, PartialEq, Eq)]
52#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
53#[non_exhaustive]
54pub struct AccountSourceFailure {
55 pub pubkey: Address,
56 pub error: String,
57}
58
59#[expect(missing_docs)]
61#[derive(Debug, Clone, PartialEq, Eq)]
62#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
63#[non_exhaustive]
64pub struct AccountDiff {
65 pub address: Address,
66 pub pre: Option<Account>,
67 pub post: Option<Account>,
68}
69
70#[expect(missing_docs)]
72#[derive(Debug, Clone, PartialEq, Eq)]
73#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
74#[non_exhaustive]
75pub struct TokenBalance {
76 pub account_index: usize,
77 pub address: Address,
78 pub mint: Address,
79 pub owner: Address,
80 pub amount: u64,
81 pub decimals: Option<u8>,
82}
83
84#[expect(missing_docs)]
86#[derive(Debug, Default, Clone, PartialEq, Eq)]
87#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
88#[non_exhaustive]
89pub struct ExecutionTrace {
90 pub instructions: Vec<ExecutedInstruction>,
91}
92
93#[expect(missing_docs)]
95#[derive(Debug, Clone, PartialEq, Eq)]
96#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
97#[non_exhaustive]
98pub struct ExecutedInstruction {
99 pub stack_height: u8,
100 pub program_id: Address,
101 pub accounts: Vec<AccountMeta>,
102 pub data: Vec<u8>,
103}
104
105impl ExecutedInstruction {
106 #[must_use]
108 pub fn instruction(&self) -> Instruction {
109 Instruction {
110 program_id: self.program_id,
111 accounts: self.accounts.clone(),
112 data: self.data.clone(),
113 }
114 }
115}
116
117#[must_use = "call HPSVM::commit_transaction to apply this outcome to the VM"]
128#[derive(Debug, PartialEq, Eq)]
129#[cfg_attr(feature = "serde", derive(serde::Serialize))]
130pub struct ExecutionOutcome {
131 pub(crate) meta: TransactionMetadata,
132 pub(crate) post_accounts: Vec<(Address, AccountSharedData)>,
133 pub(crate) status: Result<()>,
134 pub(crate) included: bool,
135 #[cfg_attr(feature = "serde", serde(skip_serializing))]
136 pub(crate) origin_vm_instance_id: u64,
137 #[cfg_attr(feature = "serde", serde(skip_serializing))]
138 pub(crate) origin_state_version: u64,
139 #[cfg_attr(feature = "serde", serde(skip_serializing, skip_deserializing))]
140 pub(crate) fee_payer: Option<Address>,
141}
142
143impl ExecutionOutcome {
144 pub fn meta(&self) -> &TransactionMetadata {
146 &self.meta
147 }
148
149 pub fn post_accounts(&self) -> &[(Address, AccountSharedData)] {
151 &self.post_accounts
152 }
153
154 pub fn status(&self) -> &Result<()> {
157 &self.status
158 }
159
160 pub fn included(&self) -> bool {
162 self.included
163 }
164}
165
166#[expect(missing_docs)]
167#[derive(Debug, Default, Clone, PartialEq, Eq)]
168#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
169pub struct SimulatedTransactionInfo {
170 #[expect(missing_docs)]
171 pub meta: TransactionMetadata,
172 #[expect(missing_docs)]
173 pub post_accounts: Vec<(Address, AccountSharedData)>,
174}
175
176#[expect(missing_docs)]
177#[derive(Debug, Clone, PartialEq, Eq)]
178#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
179pub struct FailedTransactionMetadata {
180 #[expect(missing_docs)]
181 pub err: TransactionError,
182 #[expect(missing_docs)]
183 pub meta: TransactionMetadata,
184}
185
186impl From<ProgramError> for FailedTransactionMetadata {
187 fn from(value: ProgramError) -> Self {
188 Self {
189 err: TransactionError::InstructionError(
190 0,
191 InstructionError::Custom(u64::from(value) as u32),
192 ),
193 meta: Default::default(),
194 }
195 }
196}
197
198#[expect(missing_docs)]
199pub type TransactionResult = std::result::Result<TransactionMetadata, FailedTransactionMetadata>;
200
201pub(crate) struct ExecutionResult {
202 pub(crate) post_accounts: Vec<(Address, AccountSharedData)>,
203 pub(crate) tx_result: Result<()>,
204 pub(crate) signature: Signature,
205 pub(crate) compute_units_consumed: u64,
206 pub(crate) inner_instructions: InnerInstructionsList,
207 pub(crate) return_data: TransactionReturnData,
208 pub(crate) execution_trace: ExecutionTrace,
209 pub(crate) included: bool,
211 pub(crate) fee: u64,
212 pub(crate) fee_payer: Option<Address>,
213 pub(crate) account_source_failures: Vec<AccountSourceFailure>,
214 pub(crate) fatal_error: Option<HPSVMError>,
215}
216
217impl Default for ExecutionResult {
218 fn default() -> Self {
219 Self {
220 post_accounts: Default::default(),
221 tx_result: Err(TransactionError::UnsupportedVersion),
222 signature: Default::default(),
223 compute_units_consumed: Default::default(),
224 inner_instructions: Default::default(),
225 return_data: Default::default(),
226 execution_trace: Default::default(),
227 included: false,
228 fee: 0,
229 fee_payer: None,
230 account_source_failures: Default::default(),
231 fatal_error: None,
232 }
233 }
234}