From 65c9ee1214c8a53be0f2a2716eccff0303816224 Mon Sep 17 00:00:00 2001 From: lukacan Date: Tue, 10 Mar 2026 17:15:40 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Add=20transaction=20return=20dat?= =?UTF-8?q?a?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + crates/fuzz/src/lib.rs | 2 + crates/fuzz/src/trident/client.rs | 43 ++++++++++++++- crates/fuzz/src/trident/transaction_result.rs | 23 ++++++++ .../trident-api/transaction-result/index.md | 20 ++++++- .../programs/hello_world/src/lib.rs | 4 +- examples/hello_world/trident-tests/Cargo.lock | 55 +++++++++++++++---- .../trident-tests/fuzz_0/test_fuzz.rs | 5 ++ 8 files changed, 135 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 886835185..58c9fbd29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ incremented upon a breaking change and the patch version will be incremented for - add more stake program related methods ([441](https://github.com/Ackee-Blockchain/trident/pull/441)) - add remove functionality to AddressStorage ([442](https://github.com/Ackee-Blockchain/trident/pull/442)) - add support for exit code mode ([454](https://github.com/Ackee-Blockchain/trident/pull/454)) +- add support for return data ([456](https://github.com/Ackee-Blockchain/trident/pull/456)) **Removed** diff --git a/crates/fuzz/src/lib.rs b/crates/fuzz/src/lib.rs index a1bbe5695..7b1fe454a 100644 --- a/crates/fuzz/src/lib.rs +++ b/crates/fuzz/src/lib.rs @@ -59,6 +59,8 @@ pub mod fuzzing { /// Trident pub use super::trident::flow_executor::FlowExecutor; + pub use super::trident::transaction_result::TransactionResult; + pub use super::trident::transaction_result::TransactionReturnData; pub use super::trident::Trident; pub use trident_fuzz_metrics::TridentFuzzingData; diff --git a/crates/fuzz/src/trident/client.rs b/crates/fuzz/src/trident/client.rs index 4107a9273..26ccd807f 100644 --- a/crates/fuzz/src/trident/client.rs +++ b/crates/fuzz/src/trident/client.rs @@ -7,6 +7,7 @@ use trident_svm::prelude::TridentTransactionProcessingResult; use trident_svm::processor::InstructionError; use crate::trident::transaction_result::TransactionResult; +use crate::trident::transaction_result::TransactionReturnData; use crate::trident::Trident; use crate::AccountDiscriminator; @@ -408,6 +409,14 @@ impl Trident { Ok(result) => match result { trident_svm::prelude::solana_svm::transaction_processing_result::ProcessedTransaction::Executed(executed_transaction) => match &executed_transaction.execution_details.status { Ok(_) => { + let transaction_return_data = executed_transaction + .execution_details + .return_data + .clone() + .map(|return_data| TransactionReturnData { + program_id: return_data.program_id, + data: return_data.data, + }); // Record successful execution if fuzzing_metrics.is_ok() && log_as.is_some() { if let Some(log_as) = log_as { @@ -415,9 +424,26 @@ impl Trident { .add_successful_transaction(log_as); } } - TransactionResult::new(Ok(()), executed_transaction.execution_details.log_messages.clone().unwrap_or_default(), transaction_timestamp) + TransactionResult::new( + Ok(()), + executed_transaction + .execution_details + .log_messages + .clone() + .unwrap_or_default(), + transaction_timestamp, + transaction_return_data, + ) }, Err(transaction_error) => { + let transaction_return_data = executed_transaction + .execution_details + .return_data + .clone() + .map(|return_data| TransactionReturnData { + program_id: return_data.program_id, + data: return_data.data, + }); if let TransactionError::InstructionError(_error_code, instruction_error) = &transaction_error { @@ -476,12 +502,23 @@ impl Trident { ); } } - TransactionResult::new(Err(transaction_error.clone()), executed_transaction.execution_details.log_messages.clone().unwrap_or_default(), transaction_timestamp) + TransactionResult::new( + Err(transaction_error.clone()), + executed_transaction + .execution_details + .log_messages + .clone() + .unwrap_or_default(), + transaction_timestamp, + transaction_return_data, + ) }, }, trident_svm::prelude::solana_svm::transaction_processing_result::ProcessedTransaction::FeesOnly(_) => todo!(), }, - Err(transaction_error) => TransactionResult::new(Err(transaction_error.clone()), vec![], transaction_timestamp), + Err(transaction_error) => { + TransactionResult::new(Err(transaction_error.clone()), vec![], transaction_timestamp, None) + } } } } diff --git a/crates/fuzz/src/trident/transaction_result.rs b/crates/fuzz/src/trident/transaction_result.rs index acbc05a0b..b162289b0 100644 --- a/crates/fuzz/src/trident/transaction_result.rs +++ b/crates/fuzz/src/trident/transaction_result.rs @@ -1,6 +1,14 @@ +use solana_sdk::pubkey::Pubkey; use solana_sdk::transaction::TransactionError; use trident_svm::processor::InstructionError; +/// Return data emitted by a Solana program during transaction execution. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TransactionReturnData { + pub program_id: Pubkey, + pub data: Vec, +} + /// Result of a transaction execution containing both the result and logs /// /// This struct encapsulates the outcome of executing a transaction, @@ -10,6 +18,7 @@ pub struct TransactionResult { transaction_result: solana_sdk::transaction::Result<()>, transaction_logs: Vec, transaction_timestamp: u64, + transaction_return_data: Option, } impl TransactionResult { @@ -22,11 +31,13 @@ impl TransactionResult { transaction_result: solana_sdk::transaction::Result<()>, transaction_logs: Vec, transaction_timestamp: u64, + transaction_return_data: Option, ) -> Self { Self { transaction_result, transaction_logs, transaction_timestamp, + transaction_return_data, } } @@ -118,4 +129,16 @@ impl TransactionResult { pub fn get_transaction_timestamp(&self) -> u64 { self.transaction_timestamp } + + /// Returns the raw return data emitted during transaction execution. + /// + /// When a program calls `set_return_data`, Solana stores the emitting program ID + /// together with the returned bytes. This accessor exposes that data to Trident users. + /// + /// # Returns + /// + /// `Some(&TransactionReturnData)` if a program returned data, `None` otherwise. + pub fn get_return_data(&self) -> Option<&TransactionReturnData> { + self.transaction_return_data.as_ref() + } } diff --git a/documentation/docs/trident-api/transaction-result/index.md b/documentation/docs/trident-api/transaction-result/index.md index 39e3bbbeb..2e158f8a9 100644 --- a/documentation/docs/trident-api/transaction-result/index.md +++ b/documentation/docs/trident-api/transaction-result/index.md @@ -1,6 +1,6 @@ # TransactionResult -The `TransactionResult` struct encapsulates the outcome of executing a transaction in the Trident fuzzing environment. It provides methods to inspect transaction success/failure status, access logs, and extract error information. +The `TransactionResult` struct encapsulates the outcome of executing a transaction in the Trident fuzzing environment. It provides methods to inspect transaction success/failure status, access logs, extract error information, and read Solana return data. ## Overview @@ -10,6 +10,7 @@ The `TransactionResult` struct encapsulates the outcome of executing a transacti - Log messages generated during execution - Custom program error codes - Transaction timestamp +- Return data emitted by the executed program ## Core Methods @@ -118,6 +119,23 @@ pub fn get_transaction_timestamp(&self) -> u64 --- +### `get_return_data` + +Returns the raw Solana return data for the transaction, if any program emitted it via `set_return_data`. + +```rust +pub fn get_return_data(&self) -> Option<&TransactionReturnData> +``` + +**Returns:** + +- `Some(&TransactionReturnData)` - If a program emitted return data during execution +- `None` - If no return data was set + +**Description:** The returned value contains the emitting `program_id` and the raw returned `data` bytes. + +--- + ## Example Usage ### Basic Transaction Verification diff --git a/examples/hello_world/programs/hello_world/src/lib.rs b/examples/hello_world/programs/hello_world/src/lib.rs index 0d30f5ef1..0fee5141c 100644 --- a/examples/hello_world/programs/hello_world/src/lib.rs +++ b/examples/hello_world/programs/hello_world/src/lib.rs @@ -6,7 +6,7 @@ declare_id!("FtevoQoDMv6ZB3N9Lix5Tbjs8EVuNL8vDSqG9kzaZPit"); pub mod hello_world { use super::*; - pub fn initialize_fn(ctx: Context, input: u8) -> Result<()> { + pub fn initialize_fn(ctx: Context, input: u8) -> Result { msg!( "Hello World address: {}", ctx.accounts.hello_world_account.key() @@ -21,7 +21,7 @@ pub mod hello_world { let timestamp = Clock::get()?.unix_timestamp; hello_world_store.timestamp = timestamp as u64; - Ok(()) + Ok(5) } } diff --git a/examples/hello_world/trident-tests/Cargo.lock b/examples/hello_world/trident-tests/Cargo.lock index c850d6429..5c7d5ab92 100644 --- a/examples/hello_world/trident-tests/Cargo.lock +++ b/examples/hello_world/trident-tests/Cargo.lock @@ -3059,7 +3059,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.2", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.4", "tower", "tower-http", "tower-service", @@ -3079,7 +3079,7 @@ dependencies = [ "anyhow", "async-trait", "http 1.4.0", - "reqwest 0.12.24", + "reqwest 0.12.28", "serde", "thiserror 1.0.69", "tower-service", @@ -4950,7 +4950,7 @@ dependencies = [ "futures", "indicatif", "log", - "reqwest 0.12.24", + "reqwest 0.12.28", "reqwest-middleware", "semver", "serde", @@ -4985,7 +4985,7 @@ checksum = "2dbc138685c79d88a766a8fd825057a74ea7a21e1dd7f8de275ada899540fff7" dependencies = [ "anyhow", "jsonrpc-core", - "reqwest 0.12.24", + "reqwest 0.12.28", "reqwest-middleware", "serde", "serde_derive", @@ -6738,7 +6738,7 @@ dependencies = [ [[package]] name = "trident-config" -version = "0.12.0" +version = "0.13.0-rc.2" dependencies = [ "anyhow", "base64 0.22.1", @@ -6758,7 +6758,7 @@ dependencies = [ [[package]] name = "trident-derive-flow-executor" -version = "0.12.0" +version = "0.13.0-rc.2" dependencies = [ "proc-macro2", "quote", @@ -6768,7 +6768,7 @@ dependencies = [ [[package]] name = "trident-derive-fuzz-test-methods" -version = "0.12.0" +version = "0.13.0-rc.2" dependencies = [ "proc-macro2", "quote", @@ -6778,8 +6778,9 @@ dependencies = [ [[package]] name = "trident-fuzz" -version = "0.12.0" +version = "0.13.0-rc.2" dependencies = [ + "bincode", "borsh 1.6.0", "getrandom 0.3.4", "hex", @@ -6789,6 +6790,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "sha2 0.10.9", + "solana-loader-v3-interface", "solana-sdk", "solana-stake-interface", "solana-vote-interface", @@ -6809,7 +6811,7 @@ dependencies = [ [[package]] name = "trident-fuzz-metrics" -version = "0.12.0" +version = "0.13.0-rc.2" dependencies = [ "hex", "prettytable", @@ -6821,8 +6823,9 @@ dependencies = [ [[package]] name = "trident-svm" -version = "0.2.0" -source = "git+https://github.com/Ackee-Blockchain/trident-svm?branch=remove-programs-db#8a3033619a7e7e3275a8ab895b78c54bd808d28e" +version = "0.3.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e850c21b2c402bb75c2feca8468a1a7da8c263e8cf8831cdcfaeaa8415387a" dependencies = [ "bincode", "log", @@ -6860,7 +6863,7 @@ dependencies = [ [[package]] name = "trident-syn" -version = "0.12.0" +version = "0.13.0-rc.2" dependencies = [ "petgraph", "proc-macro2", @@ -7658,3 +7661,31 @@ name = "zmij" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d6085d62852e35540689d1f97ad663e3971fc19cf5eceab364d62c646ea167" + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/examples/hello_world/trident-tests/fuzz_0/test_fuzz.rs b/examples/hello_world/trident-tests/fuzz_0/test_fuzz.rs index 0cc3680af..c083061fc 100644 --- a/examples/hello_world/trident-tests/fuzz_0/test_fuzz.rs +++ b/examples/hello_world/trident-tests/fuzz_0/test_fuzz.rs @@ -88,6 +88,11 @@ impl FuzzTest { assert!(hello_world_account.input == input); assert!(hello_world_account.timestamp == res.get_transaction_timestamp()); } + + let returned_value = res.get_return_data().unwrap(); + + assert!(returned_value.program_id.eq(&hello_world::program_id())); + assert!(returned_value.data.eq(&[5])); } }