Format
A Thru transaction consists of the following components:Transaction Header (v1)
The transaction header contains critical metadata and parameters:Account Addresses
At the end of and after the header, the transaction contains arrays of account addresses that will be accessed during execution. The account addresses are organized in a specific order:- The fee payer account is always listed first in the transaction. This is also
header field
fee_payer_pubkey. - The program account is always listed second in the transaction. This is
header field
program_pubkey. - The writable accounts array follows, containing all accounts that the program may modify.
- The read-only accounts array comes last, containing all accounts that the program may read but not modify.
The account indices in a Thru transaction are always assigned as follows:
- The fee payer account is at index 0 (corresponding to
fee_payer_pubkeyin the header). - The program account is at index 1 (corresponding to
program_pubkeyin the header). - Writable and read-only accounts follow at subsequent indices.
Instruction Data
Following the account addresses is the instruction data section. This contains the raw data that will be passed to the program during execution. The size of this data is specified in the header’sinstr_data_sz field.
Optional State Proof
For fee payer accounts that are being created or decompressed from a compressed state, an optional state proof may be included at the end of the transaction. This proof validates the account’s existence or non-existence in the state tree.Complete Transaction Data Layout
The following shows the complete binary layout of a Thru transaction:Field Descriptions
The following table describes each field in the transaction structure:| Field | Offset | Size | Type | Description |
|---|---|---|---|---|
| Transaction Header | ||||
fee_payer_signature | 0-63 | 64 bytes | Ed25519 signature | Cryptographic signature from the fee payer authorizing the transaction |
transaction_version | 64 | 1 byte | uint8 | Transaction format version, must be 0x01 |
flags | 65 | 1 byte | uint8 | Transaction flags (bit 0: has fee payer proof, bits 1-7: reserved) |
readwrite_accounts_cnt | 66-67 | 2 bytes | uint16 | Number of accounts that can be modified by the program |
readonly_accounts_cnt | 68-69 | 2 bytes | uint16 | Number of accounts that can only be read by the program |
instr_data_sz | 70-71 | 2 bytes | uint16 | Size in bytes of the instruction data section |
req_compute_units | 72-75 | 4 bytes | uint32 | Maximum compute units the transaction may consume |
req_state_units | 76-77 | 2 bytes | uint16 | Maximum state units the transaction may consume |
req_memory_units | 78-79 | 2 bytes | uint16 | Maximum memory units the transaction may consume |
fee | 80-87 | 8 bytes | uint64 | Transaction fee in native tokens |
nonce | 88-95 | 8 bytes | uint64 | Transaction nonce, must match fee payer’s current nonce |
start_slot | 96-103 | 8 bytes | uint64 | Earliest slot when transaction becomes valid |
expiry_after | 104-107 | 4 bytes | uint32 | Number of slots after start_slot when transaction expires |
padding_0 | 108-111 | 4 bytes | uint32 | Reserved padding, must be zero |
fee_payer_pubkey | 112-143 | 32 bytes | Ed25519 pubkey | Public key of the account paying transaction fees |
program_pubkey | 144-175 | 32 bytes | Ed25519 pubkey | Public key of the program to execute |
| Account Addresses | ||||
readwrite_accounts | 176+ | 32×N bytes | Ed25519 pubkey[] | Array of writable account addresses (sorted ascending) |
readonly_accounts | Variable | 32×M bytes | Ed25519 pubkey[] | Array of read-only account addresses (sorted ascending) |
| Instruction Data | ||||
instruction_data | Variable | Variable | uint8[] | Raw data passed to the program during execution |
| Optional State Proof | ||||
type_slot | Variable | 8 bytes | uint64 | Proof type (bits 62-63) and slot number (bits 0-61) |
path_bitset | Variable | 32 bytes | uint8[32] | Bitset indicating which indices have sibling hashes |
proof_body | Variable | Variable | uint8[] | Variable proof data based on type and path_bitset |
| Optional Account Metadata | ||||
magic | Variable | 2 bytes | uint16 | Magic number identifying account metadata (0xC7A3) |
version | Variable | 1 byte | uint8 | Account metadata version (0x00) |
flags | Variable | 1 byte | uint8 | Account flags (program, privileged, compressed, etc.) |
data_sz | Variable | 4 bytes | uint32 | Size of account data in bytes |
seq | Variable | 8 bytes | uint64 | Account state modification counter |
owner | Variable | 32 bytes | Ed25519 pubkey | Public key of the program that owns this account |
balance | Variable | 8 bytes | uint64 | Account balance in native tokens |
nonce | Variable | 8 bytes | uint64 | Account nonce for transaction ordering |
Transaction Flags
The flags field at byte offset 65 controls optional transaction features. Currently, only one flag is defined:| Flag | Bit Position | Value | Description |
|---|---|---|---|
TN_TXN_FLAG_HAS_FEE_PAYER_PROOF | 0 | 0x01 | Indicates that the transaction includes a state proof for the fee payer account. When this flag is set, a state proof must be included at the end of the transaction after the instruction data. |
Limitations
The Thru blockchain enforces several limits on transaction structure and size:- The maximum transaction size is 32KiB.
- Each transaction can reference at most 1024 accounts.
- All account addresses must be exactly 32 bytes in length.
Validity Criteria
A valid transaction is one which is includable in to the chain. That is to say, a block is considered itself unincludable if it contains an invalid transaction. A transaction must meet the following criteria to be considered valid.Format Validation
- The transaction size must not exceed the maximum transmission unit (MTU) of 32KiB.
- The transaction version must be exactly
0x01. - All fields in the transaction header must be properly formatted and aligned.
- The account arrays must contain the correct number of accounts as specified in the header.
- The total number of accounts referenced must not exceed 1024.
Signature Verification
- The fee payer’s Ed25519 signature must be cryptographically valid.
- The signature must cover the entire transaction body, excluding the signature itself.
Account List Verification
- No duplicate accounts are allowed anywhere in the transaction.
- Writable accounts must be sorted in ascending lexicographic order.
- Read-only accounts must be sorted in ascending lexicographic order.