---
title: Transactions
description: Methods for handling transactions
---

## send_transaction

```rust
pub fn send_transaction(&mut self, tx: impl Into<VersionedTransaction>) -> Result<TransactionMetadata, FailedTransactionMetadata>
```

Execute transaction and modify state.

```rust
let tx = Transaction::new_signed_with_payer(
    &[instruction],
    Some(&payer.pubkey()),
    &[&payer],
    svm.latest_blockhash(),
);

match svm.send_transaction(tx) {
    Ok(meta) => {
        println!("Success! Signature: {}", meta.signature);
        println!("Compute units: {}", meta.compute_units_consumed);
        println!("Fee: {} lamports", meta.fee);
    }
    Err(e) => {
        println!("Failed: {:?}", e.err);
        println!("Logs: {:?}", e.meta.logs);
    }
}
```

## simulate_transaction

```rust
pub fn simulate_transaction(&self, tx: impl Into<VersionedTransaction>) -> Result<SimulatedTransactionInfo, FailedTransactionMetadata>
```

Simulate transaction without modifying state.

Returns `SimulatedTransactionInfo` which contains:

- `meta`: Transaction metadata (logs, compute units, signature, etc.)
- `post_accounts`: Account states after simulation

```rust
// State before simulation
let balance_before = svm.get_balance(&pubkey).unwrap_or(0);

// Simulate transaction
let result = svm.simulate_transaction(tx.clone());

// State unchanged
assert_eq!(svm.get_balance(&pubkey).unwrap_or(0), balance_before);

// Check simulation result
if let Ok(sim_info) = result {
    println!("Would succeed");
    println!("Compute units: {}", sim_info.meta.compute_units_consumed);

    // Can inspect post_accounts to see what would change
    for (pubkey, account) in sim_info.post_accounts {
        println!("Account {} would have {} lamports", pubkey, account.lamports());
    }

    // Safe to send
    svm.send_transaction(tx).unwrap();
}
```

## When to Use Simulation

Use `simulate_transaction()` to:

- Test transaction validity without modifying state
- Check compute unit consumption
- Verify transaction logs without commitment
- Test error handling paths

```rust
// Test if transaction would succeed
let result = svm.simulate_transaction(tx.clone());

match result {
    Ok(sim_info) => {
        println!("Would succeed");
        println!("Compute units: {}", sim_info.meta.compute_units_consumed);

        // Now execute for real
        svm.send_transaction(tx).unwrap();
    }
    Err(e) => {
        println!("Would fail: {:?}", e.err);
        // Don't send transaction
    }
}
```

## Testing Error Cases

```rust
// Simulate expected failure
let result = svm.simulate_transaction(invalid_tx);
assert!(result.is_err());

match result.unwrap_err().err {
    TransactionError::InsufficientFundsForFee => {
        println!("Expected error occurred");
    }
    _ => panic!("Unexpected error"),
}
```

## State Remains Unchanged

```rust
let balance_before = svm.get_balance(&pubkey).unwrap_or(0);

// Simulate multiple times
for _ in 0..10 {
    svm.simulate_transaction(tx.clone()).unwrap();
}

// Balance unchanged
assert_eq!(svm.get_balance(&pubkey).unwrap_or(0), balance_before);
```

## Transaction Metadata

`send_transaction()` returns `TransactionMetadata` directly, while
`simulate_transaction()` returns `SimulatedTransactionInfo` which contains
`meta: TransactionMetadata`:

```rust
pub struct TransactionMetadata {
    pub signature: Signature,
    pub logs: Vec<String>,
    pub inner_instructions: InnerInstructionsList,
    pub compute_units_consumed: u64,
    pub return_data: TransactionReturnData,
    pub fee: u64,
}
```

### Accessing Transaction Data

```rust
let result = svm.send_transaction(tx).unwrap();

// Signature
println!("Signature: {}", result.signature);

// Logs
for log in &result.logs {
    println!("{}", log);
}

// Compute units
println!("CU consumed: {}", result.compute_units_consumed);

// Return data
if let Some(data) = result.return_data.data {
    println!("Program returned: {:?}", data);
}

// Inner instructions (CPIs)
for inner in &result.inner_instructions {
    println!("CPI: {:?}", inner);
}

// Transaction fee paid by fee payer
println!("Fee paid: {} lamports", result.fee);
```

## get_transaction

```rust
pub fn get_transaction(&self, signature: &Signature) -> Option<&TransactionResult>
```

Where
`TransactionResult = Result<TransactionMetadata, FailedTransactionMetadata>`.

Query transaction from history. Requires `with_transaction_history()` to be set.

```rust
let mut svm = LiteSVM::default()
    .with_transaction_history(100);

let result = svm.send_transaction(tx).unwrap();
let signature = result.signature;

// Query later
if let Some(tx_result) = svm.get_transaction(&signature) {
    match tx_result {
        Ok(meta) => println!("Found: {:?}", meta),
        Err(e) => println!("Failed: {:?}", e.err),
    }
}
```

## latest_blockhash

```rust
pub fn latest_blockhash(&self) -> Hash
```

Get current blockhash for transactions.

```rust
let blockhash = svm.latest_blockhash();

let tx = Transaction::new_signed_with_payer(
    &[instruction],
    Some(&payer.pubkey()),
    &[&payer],
    blockhash,
);
```

## expire_blockhash

```rust
pub fn expire_blockhash(&mut self)
```

Force current blockhash to expire.

```rust
let old_hash = svm.latest_blockhash();
svm.expire_blockhash();
let new_hash = svm.latest_blockhash();

assert_ne!(old_hash, new_hash);

// Transactions with old_hash will now fail
```

## Common Patterns

### Validate Before Executing

```rust
// Simulate first to check validity
if svm.simulate_transaction(tx.clone()).is_ok() {
    // Execute if simulation passes
    svm.send_transaction(tx).unwrap();
} else {
    println!("Transaction would fail, skipping execution");
}
```

### Track Compute Units

```rust
let result = svm.send_transaction(tx).unwrap();

// Assert within budget
assert!(
    result.compute_units_consumed < 100_000,
    "Transaction used too many compute units: {}",
    result.compute_units_consumed
);
```

### Check Transaction Logs

```rust
let result = svm.send_transaction(tx).unwrap();

// Check for specific log messages
assert!(result.logs.iter().any(|log|
    log.contains("Transfer successful")
));
```
