---
title: Executing Instructions
description: Learn how to call an instruction from a Solana program in your test
---

## Overview

After deploying a program to LiteSVM, you'll need to execute instructions to
interact with the deployed program.

LiteSVM provides a simple API for creating, sending, and simulating transactions
that is fully compatible with Solana's transaction model.

## Basic Transaction Flow

The typical flow for executing an instruction is:

1. **Create an Instruction** - Define what program to call and with what data
2. **Build a Message** - Combine one or more instructions
3. **Create a Transaction** - Sign the message with required signers
4. **Send or Simulate** - Execute the transaction and handle results

## Creating Instructions

### Basic Instruction Structure

```rust
use solana_instruction::{Instruction, AccountMeta};
use solana_pubkey::Pubkey;

let instruction = Instruction {
    program_id: Pubkey::new_unique(),  // The program to call
    accounts: vec![                     // Accounts the program needs
        AccountMeta::new(account_pubkey, false),        // Writable, not signer
        AccountMeta::new_readonly(readonly_pubkey, false), // Read-only, not signer
        AccountMeta::new(signer_pubkey, true),          // Writable, signer
    ],
    data: vec![0, 1, 2, 3],             // Instruction data (program-specific)
};
```

## Building and Sending Transactions

### Method 1: Basic Transaction

```rust
use litesvm::LiteSVM;
use solana_keypair::Keypair;
use solana_message::Message;
use solana_transaction::Transaction;
use solana_signer::Signer;

let mut svm = LiteSVM::new();
let payer = Keypair::new();

// Airdrop SOL for fees
svm.airdrop(&payer.pubkey(), 1_000_000_000).unwrap();

// Create instruction
let instruction = /* your instruction */;

// Build message with payer
let message = Message::new(&[instruction], Some(&payer.pubkey()));

// Create and sign transaction
let tx = Transaction::new_signed_with_payer(
    &[instruction],                 // Your instructions
    Some(&payer.pubkey()),          // Who pays transaction fees
    &[&payer],                      // All required signers
    svm.latest_blockhash(),         // Recent blockhash
);


// Send transaction
let result = svm.send_transaction(tx);
```

<div className="ml-4 my-2">
  <div className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-1">
    What `new_signed_with_payer` does:
  </div>
  <ul className="space-y-0.5 ml-4 list-disc text-sm text-gray-600 dark:text-gray-400">
    <li>Automatically builds a Message from your instructions</li>
    <li>Automatically signs the transaction with all provided keypairs</li>
    <li>Returns a fully signed, ready-to-send transaction</li>
  </ul>
</div>

### Method 2: Custom Message Transaction

```rust
let payer = Keypair::new();

// Manually construct message
let message = Message::new(&[instruction], Some(&payer.pubkey()));

// Create transaction with signers, message, and blockhash
let tx = Transaction::new(
    &[&payer],
    message,
    svm.latest_blockhash(),
);

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

<div className="ml-4 my-2">
  <div className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-1">
    Use this method when you need control over the `Message` like:
  </div>
  <ul className="space-y-0.5 ml-4 list-disc text-sm text-gray-600 dark:text-gray-400">
    <li>Versioned transactions (v0 with lookup tables)</li>
    <li>Partial/multi-sig workflows</li>
    <li>Durable nonces</li>
    <li>Pre-signature simulation or inspection</li>
    <li>Custom fee payer logic</li>
    <li>Transaction size optimization</li>
  </ul>
</div>

## Versioned Transactions

LiteSVM supports both legacy and versioned transactions:

```rust
use solana_transaction::versioned::VersionedTransaction;
use solana_message::VersionedMessage;

// Legacy transaction (most common)
let legacy_msg = Message::new(&[instruction], Some(&payer.pubkey()));
let versioned_tx = VersionedTransaction::try_new(
    VersionedMessage::Legacy(legacy_msg),
    &[&payer]
).unwrap();

// Send versioned transaction
let result = svm.send_transaction(versioned_tx);
```

## Transaction Results

### Successful Transaction

```rust
match svm.send_transaction(tx) {
    Ok(meta) => {
        println!("Signature: {}", meta.signature);
        println!("Compute units: {}", meta.compute_units_consumed);
        println!("Logs:");
        for log in &meta.logs {
            println!("  {}", log);
        }
    }
    Err(err) => {
        println!("Transaction failed: {:?}", err.err);
        // Logs are still available on failure
        println!("Failure logs: {:?}", err.meta.logs);
    }
}
```

### Transaction Metadata Fields

```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,
}
```

## Simulating Transactions

Simulate transaction lets you test transactions without changing state:

```rust
// Simulate instead of sending
match svm.simulate_transaction(tx) {
    Ok(sim_result) => {
        println!("Simulation successful!");
        println!("Logs: {:?}", sim_result.meta.logs);
        println!("Compute units: {}", sim_result.meta.compute_units_consumed);
    }
    Err(err) => {
        println!("Simulation failed: {:?}", err.err);
    }
}
```

## Error Handling

### Common Transaction Errors

```rust
use solana_transaction_error::TransactionError;
use solana_instruction::error::InstructionError;

match svm.send_transaction(tx) {
    Err(failed_tx) => {
        match failed_tx.err {
            TransactionError::InsufficientFundsForFee => {
                println!("Not enough SOL for fees");
            }
            TransactionError::InvalidProgramForExecution => {
                println!("Program doesn't exist or isn't executable");
            }
            TransactionError::InstructionError(index, err) => {
                println!("Instruction {} failed: {:?}", index, err);
                match err {
                    InstructionError::Custom(code) => {
                        println!("Custom error code: {}", code);
                    }
                    InstructionError::AccountNotFound => {
                        println!("An account doesn't exist");
                    }
                    _ => {}
                }
            }
            TransactionError::BlockhashNotFound => {
                println!("Blockhash expired or invalid");
            }
            _ => println!("Other error: {:?}", failed_tx.err),
        }
    }
    Ok(_) => {}
}
```

## Working with Program Logs

### Accessing Logs

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

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

// Pretty-printed logs (formatted)
println!("{}", result.pretty_logs());
```

### Log Output Example

```
Program 11111111111111111111111111111111 invoke [1]
Program log: Processing instruction
Program 11111111111111111111111111111111 consumed 2000 compute units
Program 11111111111111111111111111111111 success
```

## Compute Budget Configuration

### Setting Global Compute Budget

```rust
use solana_compute_budget::compute_budget::ComputeBudget;

let mut svm = LiteSVM::new()
    .with_compute_budget(ComputeBudget {
        compute_unit_limit: 200_000,
        ..Default::default()
    });
```

### Per-Transaction Compute Budget

```rust
use solana_compute_budget_interface::ComputeBudgetInstruction;

let instructions = vec![
    // Set compute budget for this transaction
    ComputeBudgetInstruction::set_compute_unit_limit(400_000),
    ComputeBudgetInstruction::set_compute_unit_price(1),

    // Your actual instruction
    your_instruction,
];
```

## System Program Instructions

LiteSVM includes system program support:

```rust
use solana_keypair::Keypair;
use solana_signer::Signer;
use solana_system_interface::instruction as system_instruction;
use solana_transaction::Transaction;


// Transfer SOL
let transfer_ix = system_instruction::transfer(
    &alice.pubkey(),
    &bob.pubkey(),
    1_000_000_000, // 1 SOL
);

// Create new account
let create_ix = system_instruction::create_account(
    &payer_pubkey,
    &new_account_pubkey,
    lamports,
    space as u64,
    &owner_program_id,
);
```

## Summary

Executing instructions in LiteSVM follows the standard Solana transaction model:

1. Create `Instruction` objects with program ID, accounts, and data
2. Build a `Transaction` with the instruction and required signers
3. Use `send_transaction()` to execute or `simulate_transaction()` to test
4. Handle results by checking the `TransactionMetadata` or error details

LiteSVM provides instant execution with detailed logs and debugging information,
making it ideal for testing Solana programs efficiently.
