Skip to content

Commit 65c9ee1

Browse files
author
lukacan
committed
🐛 Add transaction return data
1 parent 2815fd2 commit 65c9ee1

8 files changed

Lines changed: 135 additions & 18 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ incremented upon a breaking change and the patch version will be incremented for
1818
- add more stake program related methods ([441](https://github.com/Ackee-Blockchain/trident/pull/441))
1919
- add remove functionality to AddressStorage ([442](https://github.com/Ackee-Blockchain/trident/pull/442))
2020
- add support for exit code mode ([454](https://github.com/Ackee-Blockchain/trident/pull/454))
21+
- add support for return data ([456](https://github.com/Ackee-Blockchain/trident/pull/456))
2122

2223
**Removed**
2324

crates/fuzz/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ pub mod fuzzing {
5959

6060
/// Trident
6161
pub use super::trident::flow_executor::FlowExecutor;
62+
pub use super::trident::transaction_result::TransactionResult;
63+
pub use super::trident::transaction_result::TransactionReturnData;
6264
pub use super::trident::Trident;
6365
pub use trident_fuzz_metrics::TridentFuzzingData;
6466

crates/fuzz/src/trident/client.rs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use trident_svm::prelude::TridentTransactionProcessingResult;
77
use trident_svm::processor::InstructionError;
88

99
use crate::trident::transaction_result::TransactionResult;
10+
use crate::trident::transaction_result::TransactionReturnData;
1011
use crate::trident::Trident;
1112
use crate::AccountDiscriminator;
1213

@@ -408,16 +409,41 @@ impl Trident {
408409
Ok(result) => match result {
409410
trident_svm::prelude::solana_svm::transaction_processing_result::ProcessedTransaction::Executed(executed_transaction) => match &executed_transaction.execution_details.status {
410411
Ok(_) => {
412+
let transaction_return_data = executed_transaction
413+
.execution_details
414+
.return_data
415+
.clone()
416+
.map(|return_data| TransactionReturnData {
417+
program_id: return_data.program_id,
418+
data: return_data.data,
419+
});
411420
// Record successful execution
412421
if fuzzing_metrics.is_ok() && log_as.is_some() {
413422
if let Some(log_as) = log_as {
414423
self.fuzzing_data
415424
.add_successful_transaction(log_as);
416425
}
417426
}
418-
TransactionResult::new(Ok(()), executed_transaction.execution_details.log_messages.clone().unwrap_or_default(), transaction_timestamp)
427+
TransactionResult::new(
428+
Ok(()),
429+
executed_transaction
430+
.execution_details
431+
.log_messages
432+
.clone()
433+
.unwrap_or_default(),
434+
transaction_timestamp,
435+
transaction_return_data,
436+
)
419437
},
420438
Err(transaction_error) => {
439+
let transaction_return_data = executed_transaction
440+
.execution_details
441+
.return_data
442+
.clone()
443+
.map(|return_data| TransactionReturnData {
444+
program_id: return_data.program_id,
445+
data: return_data.data,
446+
});
421447
if let TransactionError::InstructionError(_error_code, instruction_error) =
422448
&transaction_error
423449
{
@@ -476,12 +502,23 @@ impl Trident {
476502
);
477503
}
478504
}
479-
TransactionResult::new(Err(transaction_error.clone()), executed_transaction.execution_details.log_messages.clone().unwrap_or_default(), transaction_timestamp)
505+
TransactionResult::new(
506+
Err(transaction_error.clone()),
507+
executed_transaction
508+
.execution_details
509+
.log_messages
510+
.clone()
511+
.unwrap_or_default(),
512+
transaction_timestamp,
513+
transaction_return_data,
514+
)
480515
},
481516
},
482517
trident_svm::prelude::solana_svm::transaction_processing_result::ProcessedTransaction::FeesOnly(_) => todo!(),
483518
},
484-
Err(transaction_error) => TransactionResult::new(Err(transaction_error.clone()), vec![], transaction_timestamp),
519+
Err(transaction_error) => {
520+
TransactionResult::new(Err(transaction_error.clone()), vec![], transaction_timestamp, None)
521+
}
485522
}
486523
}
487524
}

crates/fuzz/src/trident/transaction_result.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1+
use solana_sdk::pubkey::Pubkey;
12
use solana_sdk::transaction::TransactionError;
23
use trident_svm::processor::InstructionError;
34

5+
/// Return data emitted by a Solana program during transaction execution.
6+
#[derive(Clone, Debug, PartialEq, Eq)]
7+
pub struct TransactionReturnData {
8+
pub program_id: Pubkey,
9+
pub data: Vec<u8>,
10+
}
11+
412
/// Result of a transaction execution containing both the result and logs
513
///
614
/// This struct encapsulates the outcome of executing a transaction,
@@ -10,6 +18,7 @@ pub struct TransactionResult {
1018
transaction_result: solana_sdk::transaction::Result<()>,
1119
transaction_logs: Vec<String>,
1220
transaction_timestamp: u64,
21+
transaction_return_data: Option<TransactionReturnData>,
1322
}
1423

1524
impl TransactionResult {
@@ -22,11 +31,13 @@ impl TransactionResult {
2231
transaction_result: solana_sdk::transaction::Result<()>,
2332
transaction_logs: Vec<String>,
2433
transaction_timestamp: u64,
34+
transaction_return_data: Option<TransactionReturnData>,
2535
) -> Self {
2636
Self {
2737
transaction_result,
2838
transaction_logs,
2939
transaction_timestamp,
40+
transaction_return_data,
3041
}
3142
}
3243

@@ -118,4 +129,16 @@ impl TransactionResult {
118129
pub fn get_transaction_timestamp(&self) -> u64 {
119130
self.transaction_timestamp
120131
}
132+
133+
/// Returns the raw return data emitted during transaction execution.
134+
///
135+
/// When a program calls `set_return_data`, Solana stores the emitting program ID
136+
/// together with the returned bytes. This accessor exposes that data to Trident users.
137+
///
138+
/// # Returns
139+
///
140+
/// `Some(&TransactionReturnData)` if a program returned data, `None` otherwise.
141+
pub fn get_return_data(&self) -> Option<&TransactionReturnData> {
142+
self.transaction_return_data.as_ref()
143+
}
121144
}

documentation/docs/trident-api/transaction-result/index.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# TransactionResult
22

3-
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.
3+
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.
44

55
## Overview
66

@@ -10,6 +10,7 @@ The `TransactionResult` struct encapsulates the outcome of executing a transacti
1010
- Log messages generated during execution
1111
- Custom program error codes
1212
- Transaction timestamp
13+
- Return data emitted by the executed program
1314

1415
## Core Methods
1516

@@ -118,6 +119,23 @@ pub fn get_transaction_timestamp(&self) -> u64
118119

119120
---
120121

122+
### `get_return_data`
123+
124+
Returns the raw Solana return data for the transaction, if any program emitted it via `set_return_data`.
125+
126+
```rust
127+
pub fn get_return_data(&self) -> Option<&TransactionReturnData>
128+
```
129+
130+
**Returns:**
131+
132+
- `Some(&TransactionReturnData)` - If a program emitted return data during execution
133+
- `None` - If no return data was set
134+
135+
**Description:** The returned value contains the emitting `program_id` and the raw returned `data` bytes.
136+
137+
---
138+
121139
## Example Usage
122140

123141
### Basic Transaction Verification

examples/hello_world/programs/hello_world/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ declare_id!("FtevoQoDMv6ZB3N9Lix5Tbjs8EVuNL8vDSqG9kzaZPit");
66
pub mod hello_world {
77
use super::*;
88

9-
pub fn initialize_fn(ctx: Context<InitializeContext>, input: u8) -> Result<()> {
9+
pub fn initialize_fn(ctx: Context<InitializeContext>, input: u8) -> Result<u8> {
1010
msg!(
1111
"Hello World address: {}",
1212
ctx.accounts.hello_world_account.key()
@@ -21,7 +21,7 @@ pub mod hello_world {
2121
let timestamp = Clock::get()?.unix_timestamp;
2222
hello_world_store.timestamp = timestamp as u64;
2323

24-
Ok(())
24+
Ok(5)
2525
}
2626
}
2727

examples/hello_world/trident-tests/Cargo.lock

Lines changed: 43 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/hello_world/trident-tests/fuzz_0/test_fuzz.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ impl FuzzTest {
8888
assert!(hello_world_account.input == input);
8989
assert!(hello_world_account.timestamp == res.get_transaction_timestamp());
9090
}
91+
92+
let returned_value = res.get_return_data().unwrap();
93+
94+
assert!(returned_value.program_id.eq(&hello_world::program_id()));
95+
assert!(returned_value.data.eq(&[5]));
9196
}
9297
}
9398

0 commit comments

Comments
 (0)