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
| Name | Type | Required | Description |
|---|---|---|---|
transaction | string | Yes | Encoded transaction. Does not need valid signatures (unless sigVerify is true). |
encoding | string | No | base58 or base64. Default: base58. |
sigVerify | bool | No | Verify signatures. Default: false. Cannot be used with replaceRecentBlockhash. |
commitment | string | No | State commitment for simulation. Default: finalized. |
replaceRecentBlockhash | bool | No | Swap the blockhash with the latest one. Default: false. |
minContextSlot | number | No | Minimum slot for evaluation. |
accounts | object | No | {addresses: string[], encoding: "base64"} — return post-simulation account data. |
innerInstructions | bool | No | Include 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
}
| Field | Type | Description |
|---|---|---|
err | object or null | null if simulation succeeded, error object if it failed. |
logs | string[] or null | Program log messages from the simulation. |
accounts | array or null | Post-simulation account states (if accounts was requested). |
unitsConsumed | u64 | Compute units consumed during simulation. |
returnData | object or null | Data returned by the program via set_return_data. |
innerInstructions | array or null | Inner (CPI) instructions (if innerInstructions was true). |
Common errors
- Blockhash not found — the transaction’s blockhash has expired. Use
replaceRecentBlockhash: trueto 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
logsfor 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
| Parameter | Type | Required | Description | Default |
|---|---|---|---|---|
transaction | string | Yes | Transaction as a base-58 or base-64 encoded string. The transaction must have a valid blockhash but does not need to be signed. | — |
encoding | string | No | Encoding of the transaction: base58 or base64. | base58 |
sigVerify | bool | No | Verify transaction signatures during simulation. | false |
commitment | string | No | Commitment level for the simulation state. | finalized |
replaceRecentBlockhash | bool | No | Replace the transaction blockhash with the most recent one. | false |
minContextSlot | number | No | Minimum slot at which the simulation can be evaluated. | — |
accounts | object | No | Accounts configuration to return post-simulation state. | — |
innerInstructions | bool | No | Include inner instructions in the simulation result. | false |
Updated: