Advanced· Lesson 1 of 2· 4 min
Anatomy of a Solana transaction
What your wallet actually signs: the message format, the fee maths, the blockhash clock and the compute budget, from bytes to finality.
A transaction is a signed message. The message says which accounts are involved, which programs to call with what arguments, and which recent block it was built against. The signatures over that message come first on the wire. The whole thing must fit in 1,232 bytes — one network packet — and that limit shapes a surprising amount of Solana's design.
The message
| Header | Three counts: how many signatures are required, how many of the signing accounts are read-only, how many of the non-signing accounts are read-only. |
|---|---|
| Account keys | Every account the transaction touches, in one flat list. Instructions refer to accounts by index into it. |
| Recent blockhash | The hash of a recent block. It is both a timestamp and a nonce: the transaction is valid only while that block is recent — about 150 slots, roughly a minute — and can never be replayed after. |
| Instructions | An ordered list. Each names a program by index, the accounts it uses by index, and opaque data bytes that the program decodes itself. |
Because the account list is declared up front, the runtime knows before executing anything which transactions conflict. Non-overlapping transactions run in parallel. That declaration is Solana's parallelism — not an optimisation layered on top.
Instructions are atomic together
One transaction can carry many instructions — create an account, initialize it, transfer into it — and they succeed or fail as a unit. If the third instruction errors, the first two are rolled back and only the fee is charged. That is what lets Solstack bundle “create the recipient's token account, then transfer” without ever leaving a half-finished state.
Fees
- Base fee: 5,000 lamports per signature, fixed. A typical single-signer transaction costs 0.000005 SOL.
- Priority fee: optional. You set a compute-unit price in micro-lamports; the fee is that price times the compute-unit limit. Leaders order transactions by it when blocks are contested.
Separately, any accounts the transaction creates need their rent deposit — refundable, covered in The account model. Your wallet's confirmation shows the total.

- Total fee: 0.00001014 SOL. Two signatures × 5,000 lamports, plus the priority fee.
- Priority fee: 144 lamports, the compute-unit price times the compute-unit limit.
- Compute units used, against the limit the transaction asked for.
- Version 0: a versioned transaction, which is what allows lookup tables.
- Three address lookup tables: how a swap touching dozens of accounts fits in 1,232 bytes.
- The recent blockhash the transaction was built against.
Compute budget
Every instruction runs under a budget of compute units — a measure of work like gas, but capped rather than priced open-endedly. The default is 200,000 CU per instruction, up to 1,400,000 per transaction; exceed it and the transaction fails. Two instructions from the Compute Budget program, SetComputeUnitLimit and SetComputeUnitPrice, adjust the cap and the priority fee. Well-built apps simulate first and request slightly more than the simulation used.

- How the 105,751 compute units split across the four instructions.
- SetComputeUnitLimit: the transaction asks for a 131,387 CU cap instead of the default.
- SetComputeUnitPrice: the priority fee, in micro-lamports per compute unit.
- Create the output token account if it doesn't exist yet. Idempotent, so it's safe to include every time.
- The swap itself. Everything above it is setup.
Versioned transactions and lookup tables
The 1,232-byte cap means a legacy transaction fits roughly 35 accounts. Version 0 transactions add address lookup tables: on-chain accounts holding lists of addresses, so the message can reference an account by a one-byte index instead of 32 bytes. That is how an exchange route touching forty accounts fits in one transaction. Wallets label these “v0”; every current wallet signs them.
Lifecycle
- Build: the app assembles the message with a recent blockhash.
- Simulate: the RPC runs it against current state without committing. Wallets show the simulated balance changes.
- Sign: the wallet produces one Ed25519 signature per required signer.
- Send: the RPC forwards it to the current and upcoming leaders.
- Process → confirm → finalize, as in What is Solana?. If the blockhash expires first, the transaction is dropped and nothing is charged.

- The signature: the transaction's id, 64 bytes in base58. Paste it into any explorer.
- The slot it landed in, and that block's timestamp.
- Result: success, and finalized, the highest commitment level.
- Who signed. The fee payer is listed first; two signers means two 64-byte signatures.
- What the instructions did, decoded: a Jupiter swap that routed through two pools.
Reading a failed one
A transaction that errors still lands on-chain with its logs. The error names the instruction index and a program error code, and the program's logs above it usually say why in words. Transaction Inspector decodes the instructions, balance changes and logs for any signature; Reading a transaction simulation walks through the common failures.
What to remember
- A transaction is signatures plus a message — header, account keys, recent blockhash, instructions — within 1,232 bytes.
- Accounts are declared up front. That is what lets non-conflicting transactions run in parallel.
- Instructions are atomic together: one fails, all roll back, only the fee is paid.
- Fee = 5,000 lamports per signature + optional priority fee (CU price × CU limit). Rent is separate and refundable.
- A blockhash expires after ~150 slots. An expired transaction is dropped for free.