Transactions and Instructions
On Solana, we send transactions to interact with the network. Transactions include one or more instructions that specify operations to be processed. The execution logic for instructions are stored on programs deployed to the Solana network, where each program defines its own set of instructions.
Below are key details about how transactions are processed:
- If a transaction includes multiple instructions, the instructions execute in the order they are added to the transaction
- Transactions are "atomic" - either all instructions process successfully, or the entire transaction fails and no changes are made.
For simplicity, a transaction can be thought of as a request to process one or multiple instructions.
Transaction Simplified
Think of a transaction like an envelope containing forms. Each form is an instruction that tells the network what we are requesting to do. When you send the transaction, it's like mailing the envelope to get the forms processed.
Key Points
-
Solana transactions include instructions that are requests to invoke programs on the network.
-
Transactions are atomic - if any instruction fails, the entire transaction fails and no changes occur.
-
Instructions on a transaction are processed in sequential order.
-
The maximum size of a transaction is 1232 bytes.
-
Each instruction requires 3 pieces of information:
- The address of the program to invoke
- The accounts the instruction will read from or write to
- Any additional data required by the instruction (e.g. function arguments)
Basic Example
Below is a diagram representing a transaction with a single instruction to transfer SOL from a sender to a receiver.
On Solana, accounts we refer to as "wallets" are owned by the System Program. Only the program owner can modify an account's data, so transferring SOL requires sending a transaction to invoke the System Program.
SOL Transfer
The sender account must sign (is_signer
) the transaction to authorize
deducting its lamport balance. Both sender and recipient accounts need to be
marked as writable (is_writable
) since the lamport balances on these accounts
will change.
Once the transaction is sent, the System Program is invoked to process the transfer instruction. The System Program then updates the lamport balances of both the sender and recipient accounts accordingly.
SOL Transfer Process
Transfer SOL
Here is a Solana Playground
example of how to build a SOL transfer instruction using the
SystemProgram.transfer
method:
Run the example by using the run
command in the Playground terminal or
clicking the "Run" button.
Ensure your Playground wallet has devnet SOL. Get devnet SOL from the Solana Faucet.
In the sections below, we'll walk through the details of transactions and instructions.
Transaction
A Solana transaction consists of:
- Signatures: An array of signatures included on the transaction.
- Message: List of instructions to be processed atomically.
Transaction Format
The structure of a transaction message consists of:
- Message Header: Specifies the number of signer and read-only account.
- Account Addresses: An array of account addresses required by the instructions on the transaction.
- Recent Blockhash: Acts as a timestamp for the transaction.
- Instructions: An array of instructions to be executed.
Transaction Message
Transaction Size
Solana transactions are limited to 1232 bytes. This limit comes from the IPv6 MTU size of 1280 bytes, minus 48 bytes for network headers (40 bytes IPv6 + 8 bytes fragment header).
A transaction's total size (signatures and message) must stay under this limit and consists of:
- Signatures: 64 bytes each
- Message: Header (3 bytes), account keys (32 bytes each), recent blockhash (32 bytes), and instructions
Transaction Format
Message Header
The message header uses three bytes to define account privileges:
- Required signatures and message version (eg. legacy vs v0)
- Number of read-only signed accounts
- Number of read-only unsigned accounts
Message Header
Compact-Array Format
A compact array in a transaction message refers to an array serialized in the following format:
- The array length (encoded as compact-u16)
- The array items listed one after another
Compact array format
This format is used to encode the lengths of the Account Addresses and Instructions arrays in transaction messages.
Array of Account Addresses
A transaction message contains an array of account addresses required by its instructions. The array begins with a compact-u16 number indicating how many addresses it contains. The addresses are then ordered based on their privileges, which is determined by the message header.
- Accounts that are writable and signers
- Accounts that are read-only and signers
- Accounts that are writable and not signers
- Accounts that are read-only and not signers
Compact array of account addresses
Recent Blockhash
Every transaction requires a recent blockhash that serves two purposes:
- Acts as a timestamp
- Prevents duplicate transactions
A blockhash expires after 150 blocks (about 1 minute assuming 400ms block times), after which the transaction cannot be processed.
You can use the getLatestBlockhash
RPC
method to get the current blockhash and last block height at which the blockhash
will be valid. Here is an example on
Solana Playground.
Array of Instructions
A transaction message contains an array of instructions in the CompiledInstruction type. Instructions are converted to this type when added to a transaction.
Like the account addresses array in the message, it starts with a compact-u16 length followed by the instruction data. Each instruction contains:
- Program ID Index: An u8 index that points to the program's address in the account addresses array. This specifies the program that will process the instruction.
- Account Indexes: An array of u8 indexes that point to the account addresses required for this instruction.
- Instruction Data: A byte array specifying which instruction to invoke on the program and any additional data required by the instruction (eg. function arguments).
Compact array of Instructions
Example Transaction Structure
Below is an example transaction including a single SOL transfer instruction. The transaction's components include:
-
header
: Specifies read/write and signer privileges for addresses in theaccountKeys
array -
accountKeys
: Array of all account addresses used in the transaction's instructions -
recentBlockhash
: Blockhash used to timestamp the transaction -
instructions
: Array of instructions to execute. Eachaccount
andprogramIdIndex
in an instruction references theaccountKeys
array by index. -
signatures
: Array including signatures for all accounts required as signers by the instructions on the transaction. A signature is created by signing the transaction message using the corresponding private key for an account.
Instruction
An instruction on a deployed program can be thought of as a public function that can be called by anyone using the Solana network.
Invoking a program's instruction requires providing three key pieces of information:
- Program ID: The program being invoked to execute the instruction
- Accounts: List of accounts the instruction requires
- Instruction Data: Byte array specifying the instruction on the program to invoke and any function arguments required by the instruction
Transaction Instruction
AccountMeta
Each account required by an instruction must be provided as an AccountMeta that contains:
pubkey
: Account's addressis_signer
: Whether the account must sign the transactionis_writable
: Whether the instruction will modify the account's data
AccountMeta
By specifying up front which accounts an instruction will read from or write to, transactions that do not modify the same accounts can be processed in parallel.
Example Instruction Structure
Below is a simple example showing the structure of a SOL transfer instruction:
keys
: Includes theAccountMeta
for each account required by an instruction.programId
: The address of the program which contains the execution logic for the instruction invoked.data
: The instruction data for the instruction as a buffer of bytes
Expanded Example
The details for building program instructions are often abstracted away by client libraries. However, if one is not available, you can always fall back to manually building the instruction.
Transfer SOL
Here is a Solana Playground example of how to manually build a SOL transfer instruction.
Under the hood, the
simple example using the
SystemProgram.transfer
method is functionally equivalent to the more verbose
example below. The SystemProgram.transfer
method simply abstracts away the
details of creating the instruction data buffer and AccountMeta
for each
account required by the instruction.
The snippets in the two tabs below are functionally equivalent.
Last updated on