Transactions

To interact with the Solana network, you must send a transaction. You can think of a transaction as an envelope that holds several forms. Each form is an instruction that tells the network what to do. Sending the transaction is like mailing the envelope so the forms can be processed.

The example below shows a simplified version of two transactions. When the first transaction is processed, it will execute a single instruction. When the second transaction is processed, it will execute three instructions in sequential order: first instruction 1, followed by instruction 2, followed by instruction 3.

Transactions are atomic: If a single instruction fails, the entire transaction will fail and no changes will occur.

A simplified diagram showing two transactionsA simplified diagram showing two transactions

A Transaction consists of the following information:

  • signatures: An array of signatures
  • message: Transaction information, including the list of instructions to be processed
Transaction
pub struct Transaction {
#[wasm_bindgen(skip)]
#[serde(with = "short_vec")]
pub signatures: Vec<Signature>,
#[wasm_bindgen(skip)]
pub message: Message,
}

Diagram showing the two parts of a transactionDiagram showing the two parts of a transaction

Transactions have a total size limit of 1232 bytes. This limit includes both the signatures array and the message struct.

This limit comes from the IPv6 Maximum Transmission Unit (MTU) size of 1280 bytes, minus 48 bytes for network headers (40 bytes IPv6 + 8 bytes header).

Diagram showing the transaction format and size limitsDiagram showing the transaction format and size limits

Signatures

The transaction's signatures array contains Signature structs. Each Signature is 64 bytes and is created by signing the transaction's Message with the account's private key. A signature must be provided for each signer account included on any of the transaction's instructions.

The first signature belongs to the account that will pay the transaction's base fee and is the transaction signature. The transaction signature can be used to look up the transaction's details on the network.

Message

The transaction's message is a Message struct that contains the following information:

  • header: The message header
  • account_keys: An array of account addresses required by the transaction's instructions
  • recent_blockhash: A blockhash that acts as a timestamp for the transaction
  • instructions: An array of instructions

To save space, the transaction does not store permissions for each account individually. Instead, account permissions are determined using the header and account_keys.

Message
pub struct Message {
/// The message header, identifying signed and read-only `account_keys`.
pub header: MessageHeader,
/// All the account keys used by this transaction.
#[serde(with = "short_vec")]
pub account_keys: Vec<Pubkey>,
/// The id of a recent ledger entry.
pub recent_blockhash: Hash,
/// Programs that will be executed in sequence and committed in
/// one atomic transaction if all succeed.
#[serde(with = "short_vec")]
pub instructions: Vec<CompiledInstruction>,
}

The message's header is a MessageHeader struct. It contains the following information:

  • num_required_signatures: The total number of signatures required by the transaction
  • num_readonly_signed_accounts: The total number of read-only accounts that require signatures
  • num_readonly_unsigned_accounts: The total number of read-only accounts that don't require signatures
MessageHeader
pub struct MessageHeader {
/// The number of signatures required for this message to be considered
/// valid. The signers of those signatures must match the first
/// `num_required_signatures` of [`Message::account_keys`].
pub num_required_signatures: u8,
/// The last `num_readonly_signed_accounts` of the signed keys are read-only
/// accounts.
pub num_readonly_signed_accounts: u8,
/// The last `num_readonly_unsigned_accounts` of the unsigned keys are
/// read-only accounts.
pub num_readonly_unsigned_accounts: u8,
}

Diagram showing the three parts of the message headerDiagram showing the three parts of the message header

Account addresses

The message's account_keys is an array of account addresses, sent in compact array format. The array's prefix indicates its length. Each item in the array is a public key, pointing to an account used by its instructions. The accounts_keys array must be complete, and strictly ordered, as follows:

  1. Signer + Writable
  2. Signer + Read-only
  3. Not signer + Writable
  4. Not signer + Read-only

Strict ordering allows the account_keys array to be combined with the information in the message's header to determine the permissions for each account.

Diagram showing the order of the account addresses arrayDiagram showing the order of the account addresses array

Recent blockhash

The message's recent_blockhash is a hash value that acts as a transaction timestamp and prevents duplicate transactions. A blockhash expires after 150 blocks. (Equivalent to one minute—assuming each block is 400ms.) After the block expires, the transaction is expired and cannot be processed.

The getLatestBlockhash RPC method allows you to get the current blockhash and last block height at which the blockhash will be valid.

Instructions

The message's instructions is an array of all the instructions to be processed, sent in compact array format. The array's prefix indicates its length. Each item in the array is a CompiledInstruction struct and includes the following information:

  1. program_id_index: An index pointing to an address in the account_keys array. This value indicates the address of the program that processes the instruction.
  2. accounts: An array of indices pointing to addresses in the account_keys array. Each index points to the address of an account required for this instruction.
  3. data: A byte array specifying which instruction to invoke on the program. It also includes any additional data required by the instruction. (For example, function arguments)
CompiledInstruction
pub struct CompiledInstruction {
/// Index into the transaction keys array indicating the program account that executes this instruction.
pub program_id_index: u8,
/// Ordered indices into the transaction keys array indicating which accounts to pass to the program.
#[serde(with = "short_vec")]
pub accounts: Vec<u8>,
/// The program input data.
#[serde(with = "short_vec")]
pub data: Vec<u8>,
}

Compact array of InstructionsCompact array of Instructions

Example transaction structure

The following example shows the structure of a transaction that contains a single SOL transfer instruction.

import {
createSolanaRpc,
generateKeyPairSigner,
lamports,
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstructions,
pipe,
signTransactionMessageWithSigners,
getCompiledTransactionMessageDecoder
} from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
const rpc = createSolanaRpc("http://localhost:8899");
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
// Generate sender and recipient keypairs
const sender = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
// Define the amount to transfer
const LAMPORTS_PER_SOL = 1_000_000_000n;
const transferAmount = lamports(LAMPORTS_PER_SOL / 100n); // 0.01 SOL
// Create a transfer instruction for transferring SOL from sender to recipient
const transferInstruction = getTransferSolInstruction({
source: sender,
destination: recipient.address,
amount: transferAmount
});
// Create transaction message
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(sender, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => appendTransactionMessageInstructions([transferInstruction], tx)
);
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
// Decode the messageBytes
const compiledTransactionMessage =
getCompiledTransactionMessageDecoder().decode(signedTransaction.messageBytes);
console.log(JSON.stringify(compiledTransactionMessage, null, 2));
Console
Click to execute the code.

The code below shows the output from the previous code snippets. The format differs between SDKs, but notice that each instruction contains the same required information.

{
"version": 0,
"header": {
"numSignerAccounts": 1,
"numReadonlySignerAccounts": 0,
"numReadonlyNonSignerAccounts": 1
},
"staticAccounts": [
"HoCy8p5xxDDYTYWEbQZasEjVNM5rxvidx8AfyqA4ywBa",
"5T388jBjovy7d8mQ3emHxMDTbUF8b7nWvAnSiP3EAdFL",
"11111111111111111111111111111111"
],
"lifetimeToken": "EGCWPUEXhqHJWYBfDirq3mHZb4qDpATmYqBZMBy9TBC1",
"instructions": [
{
"programAddressIndex": 2,
"accountIndices": [0, 1],
"data": {
"0": 2,
"1": 0,
"2": 0,
"3": 0,
"4": 128,
"5": 150,
"6": 152,
"7": 0,
"8": 0,
"9": 0,
"10": 0,
"11": 0
}
}
]
}

After a transaction is submitted, you can retrieve its details using the transaction signature and the getTransaction RPC method. The response will have a structure similar to the following snippet.

You can also find the transaction using Solana Explorer.

Transaction Data
{
"blockTime": 1745196488,
"meta": {
"computeUnitsConsumed": 150,
"err": null,
"fee": 5000,
"innerInstructions": [],
"loadedAddresses": {
"readonly": [],
"writable": []
},
"logMessages": [
"Program 11111111111111111111111111111111 invoke [1]",
"Program 11111111111111111111111111111111 success"
],
"postBalances": [989995000, 10000000, 1],
"postTokenBalances": [],
"preBalances": [1000000000, 0, 1],
"preTokenBalances": [],
"rewards": [],
"status": {
"Ok": null
}
},
"slot": 13049,
"transaction": {
"message": {
"header": {
"numReadonlySignedAccounts": 0,
"numReadonlyUnsignedAccounts": 1,
"numRequiredSignatures": 1
},
"accountKeys": [
"8PLdpLxkuv9Nt8w3XcGXvNa663LXDjSrSNon4EK7QSjQ",
"7GLg7bqgLBv1HVWXKgWAm6YoPf1LoWnyWGABbgk487Ma",
"11111111111111111111111111111111"
],
"recentBlockhash": "7ZCxc2SDhzV2bYgEQqdxTpweYJkpwshVSDtXuY7uPtjf",
"instructions": [
{
"accounts": [0, 1],
"data": "3Bxs4NN8M2Yn4TLb",
"programIdIndex": 2,
"stackHeight": null
}
],
"indexToProgramIds": {}
},
"signatures": [
"3jUKrQp1UGq5ih6FTDUUt2kkqUfoG2o4kY5T1DoVHK2tXXDLdxJSXzuJGY4JPoRivgbi45U2bc7LZfMa6C4R3szX"
]
},
"version": "legacy"
}

Is this page helpful?

सामग्री तालिका

पृष्ठ संपादित करें

द्वारा प्रबंधित

© 2025 सोलाना फाउंडेशन। सर्वाधिकार सुरक्षित।
Transactions | Solana