in-solana by Supanode

simulateTransaction — Solana RPC Method

simulateTransaction executes a transaction against the current ledger state without broadcasting it to the network. It returns execution logs, compute units consumed, account state changes, and any errors — making it essential for testing transactions before submission.

Parameters

NameTypeRequiredDescription
transactionstringYesEncoded transaction. Does not need valid signatures (unless sigVerify is true).
encodingstringNobase58 or base64. Default: base58.
sigVerifyboolNoVerify signatures. Default: false. Cannot be used with replaceRecentBlockhash.
commitmentstringNoState commitment for simulation. Default: finalized.
replaceRecentBlockhashboolNoSwap the blockhash with the latest one. Default: false.
minContextSlotnumberNoMinimum slot for evaluation.
accountsobjectNo{addresses: string[], encoding: "base64"} — return post-simulation account data.
innerInstructionsboolNoInclude inner (CPI) instructions. Default: false.

Request

curl -X POST https://api.mainnet-beta.solana.com \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "simulateTransaction",
    "params": [
      "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEDArczbMia1tLmq7zz4DinMNN0pJ1JtLdqIJPUw3YrGCzYAMHBsgN27lcgB6H2WQvFgyZuJYHa46puOQo9yQ8CVQbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCp20C7Wj6s1Nf1S/4xzT2Pk18YRmTR47YRnqJMhQnDjFalAEBAgABDAIAAACAlpgAAAAAAAM=",
      {"encoding": "base64", "replaceRecentBlockhash": true}
    ]
  }'

TypeScript (@solana/kit)

import { createSolanaRpc, getBase64EncodedWireTransaction } from "@solana/kit";

const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");

const encodedTransaction = getBase64EncodedWireTransaction(transaction);

const simulation = await rpc
  .simulateTransaction(encodedTransaction, {
    encoding: "base64",
    replaceRecentBlockhash: true,
  })
  .send();

if (simulation.value.err) {
  console.error("Simulation failed:", simulation.value.err);
  console.log("Logs:", simulation.value.logs);
} else {
  console.log(`CU consumed: ${simulation.value.unitsConsumed}`);
}

Response

{
  "jsonrpc": "2.0",
  "result": {
    "context": { "slot": 341200000, "apiVersion": "2.2.4" },
    "value": {
      "err": null,
      "logs": [
        "Program 11111111111111111111111111111111 invoke [1]",
        "Program 11111111111111111111111111111111 success"
      ],
      "accounts": null,
      "unitsConsumed": 150,
      "returnData": null,
      "innerInstructions": null
    }
  },
  "id": 1
}
FieldTypeDescription
errobject or nullnull if simulation succeeded, error object if it failed.
logsstring[] or nullProgram log messages from the simulation.
accountsarray or nullPost-simulation account states (if accounts was requested).
unitsConsumedu64Compute units consumed during simulation.
returnDataobject or nullData returned by the program via set_return_data.
innerInstructionsarray or nullInner (CPI) instructions (if innerInstructions was true).

Common errors

  • Blockhash not found — the transaction’s blockhash has expired. Use replaceRecentBlockhash: true to bypass this.
  • Account not found — one of the accounts referenced in the transaction does not exist.
  • Insufficient funds — the fee payer lacks enough SOL.
  • Program error — the program returned an error during execution. Check logs for details.

Performance

Simulation runs the transaction against the node’s current state without writing to the ledger. It is heavier than a simple read but much cheaper than landing a failed transaction. Use base64 encoding for better performance.

FAQ

Do I need to sign the transaction for simulation? No. By default, signature verification is skipped (sigVerify: false). This lets you simulate before signing. Set sigVerify: true to also verify signatures.

What is replaceRecentBlockhash? When true, the node replaces the transaction’s blockhash with the most recent one, so you can simulate without worrying about blockhash expiry. Cannot be combined with sigVerify.

How do I estimate compute units? Run simulateTransaction and read unitsConsumed. Add a safety margin (10-20%) and use this as your compute unit limit in the transaction’s setComputeUnitLimit instruction.

Can simulation pass but the real transaction fail? Yes. Ledger state changes between simulation and execution. Another transaction may alter account balances, close an account, or change program state. Simulation is a best-effort preview, not a guarantee.

How do I read post-simulation account state? Pass accounts: {addresses: ["pubkey1", "pubkey2"], encoding: "base64"} to get the account data as it would be after the transaction executes.

Parameters

ParameterTypeRequiredDescriptionDefault
transactionstringYesTransaction as a base-58 or base-64 encoded string. The transaction must have a valid blockhash but does not need to be signed.—
encodingstringNoEncoding of the transaction: base58 or base64.base58
sigVerifyboolNoVerify transaction signatures during simulation.false
commitmentstringNoCommitment level for the simulation state.finalized
replaceRecentBlockhashboolNoReplace the transaction blockhash with the most recent one.false
minContextSlotnumberNoMinimum slot at which the simulation can be evaluated.—
accountsobjectNoAccounts configuration to return post-simulation state.—
innerInstructionsboolNoInclude inner instructions in the simulation result.false

Updated: