Overview
Goldsky provides curated Solana datasets with full historical data, making it easy to build pipelines for blocks, transactions, instructions, and token activity. All datasets are pre-processed and optimized for common use cases.Solana configuration differs from EVM chains:
- Solana uses
start_block(slot number) instead ofstart_at. Omitstart_blockto start from the latest slot. - Use
end_block(not SQLWHEREclauses) to bound a Solana job mode pipeline. in_ordermode is available for Solana sources (not available for EVM)- Batch settings are not available for Solana sources
Quick Start
Get started with Solana data - choose the dataset that fits your use case: For token transfers:solana.blocks- Block data with leader infosolana.transactions- Transaction data with accounts and balancessolana.transactions_with_instructions- Transactions with nested instruction arrayssolana.instructions- Individual instructions (one row per instruction)solana.token_transfers- SPL token transferssolana.native_balances- SOL balance changessolana.token_balances- SPL token balance changessolana.rewards- Records of rewards distributed to validators for securing and validating the Solana network.
Dataset schemas
The tables below list the columns produced by each Solana dataset.List<Struct> columns are nested arrays; see Working with Nested Instructions for query patterns.
solana.blocks (v1.0.0)
Block-level summary, one row per block. SQL transform over the raw source. Primary key: slot.
| Column | Type | Notes |
|---|---|---|
hash | Utf8 | Blockhash. PK is slot |
height | Int64 | blockHeight |
parent_slot | Int64 | parentSlot |
previous_block_hash | Utf8 | previousBlockhash |
skipped | Boolean | Always false |
slot | UInt64 | Slot number. PK |
timestamp | Timestamp | to_timestamp(blockTime) |
transaction_count | Int64 | Number of transactions in the block |
leader | Utf8 | Derived via _gs_solana_get_leader_info |
leader_reward | Int64 | Leader reward lamports |
solana.transactions (v1.0.0)
One row per transaction. SQL transform over the raw source. Primary key: id (sl_transaction_{block_hash}_{index}).
| Column | Type | Notes |
|---|---|---|
id | Utf8 | sl_transaction_{block_hash}_{index}. PK |
index | Int64 | Position within the block |
block_slot | UInt64 | |
block_hash | Utf8 | |
block_timestamp | Timestamp | |
accounts | List<Struct> | Resolved account keys (_gs_solana_get_accounts) |
balance_changes | List<Struct> | Native balance deltas (_gs_solana_get_balance_changes) |
pre_token_balances | List<Struct> | From tx meta |
post_token_balances | List<Struct> | From tx meta |
recent_block_hash | Utf8 | |
signature | Utf8 | First signature |
err | Utf8/Struct | Error object, null on success |
status | Int64 | 1 success / 0 failed |
compute_units_consumed | UInt64 | |
fee | UInt64 | Lamports |
log_messages | List<Utf8> |
solana.instructions (v1.0.0)
One row per (flattened) instruction. solana_transform (transform: instructions). Primary key: id.
| Column | Type | Notes |
|---|---|---|
id | Utf8 | PK |
index | Int64 | Instruction index within the tx |
parent_index | Int64 | Parent instruction index; null if top-level |
signature | Utf8 | |
block_hash | Utf8 | |
block_slot | UInt64 | |
program_id | Utf8 | Invoked program |
data | Utf8 | Base-58 instruction data |
accounts | List<Utf8> | Account keys referenced |
block_timestamp | Int64 | Epoch seconds |
err | Utf8 | null on success |
status | UInt8 | 1 / 0 |
tx_fee | UInt64 | Transaction fee (lamports) |
tx_index | UInt64 | Transaction index within the block |
solana.token_transfers (v1.0.0)
SPL token transfers. Plugin + SQL (transform: token_transfers then SQL reshape). Primary key: id.
| Column | Type | Notes |
|---|---|---|
id | Utf8 | PK |
signature | Utf8 | |
block_slot | UInt64 | |
block_hash | Utf8 | |
block_timestamp | Int64 | Epoch seconds |
from_token_account | Utf8 | |
to_token_account | Utf8 | |
from_owner | Utf8 | |
to_owner | Utf8 | |
token_mint_address | Utf8 | |
amount | UInt64 | Raw (unscaled) amount |
transfer_type | Utf8 | e.g. transfer / mint / burn |
err | Utf8 | |
status | UInt8 | 1 / 0 |
authority | Utf8 | |
mint_authority | Utf8 | |
index | Int64 | |
parent_index | Int64 | |
tx_fee | UInt64 | |
decimals | UInt8 | Mint decimals |
solana.token_transfers (v1.1.0)
Same as v1.0.0 plus two fee columns (for transfers carrying a token fee):
| Column | Type | Notes |
|---|---|---|
| … | all v1.0.0 columns | |
fee_decimals | UInt8 | Fee token decimals |
fee_amount | UInt64 | Raw fee amount |
solana.native_balances (v1.0.0)
Native SOL balance changes, one row per account balance delta. Derived from solana.transactions via SQL. Primary key: id ({block_hash}_NATIVE_{tx_index}_{index}).
| Column | Type | Notes |
|---|---|---|
id | Utf8 | PK |
block_slot | UInt64 | |
block_hash | Utf8 | |
block_timestamp | Timestamp | |
tx_index | Int64 | |
signature | Utf8 | |
account | Utf8 | |
amount_before | Float64 | Lamports / 10^9 (SOL) |
amount_after | Float64 | Lamports / 10^9 (SOL) |
solana.token_balances (v1.0.0)
SPL token balances per (owner, mint) per transaction. Derived from solana.transactions via SQL (pre/post union). Primary key: id ({block_hash}_{tx_index}_{index}).
| Column | Type | Notes |
|---|---|---|
id | Utf8 | PK |
block_slot | UInt64 | |
block_hash | Utf8 | |
block_timestamp | Timestamp | |
tx_index | Int64 | |
signature | Utf8 | |
account | Utf8 | Token account pubkey |
decimals | UInt8 | Mint decimals |
mint | Utf8 | |
owner | Utf8 | |
amount_before | Float64 | uiAmount (human-scaled), 0 if new |
amount_after | Float64 | uiAmount (human-scaled), 0 if closed |
solana.rewards (v1.0.0)
Staking/validator rewards, one row per reward entry. SQL transform over the raw source. Primary key: id (sl_reward_{block_hash}_{index}).
| Column | Type | Notes |
|---|---|---|
id | Utf8 | sl_reward_{block_hash}_{index}. PK |
block_slot | UInt64 | |
block_hash | Utf8 | |
block_timestamp | Int64 | blockTime (epoch seconds) |
pubkey | Utf8 | Reward recipient |
lamports | Int64 | Reward amount (lamports) |
reward_type | Utf8 | rewardType |
commission | UInt8 | Validator commission; nullable |
post_balance | UInt64 | postBalance (lamports) |
solana.transactions_with_instructions (v1.0.0)
One row per transaction with its grouped instructions and token balances inline — the base for dex_swaps. solana_transform (transform: transactions_with_instructions). Primary key: id.
| Column | Type | Notes |
|---|---|---|
id | Utf8 | PK |
index | Int64 | |
signature | Utf8 | |
block_hash | Utf8 | |
block_slot | UInt64 | |
block_timestamp | Int64 | Epoch seconds |
fee | UInt64 | |
status | UInt8 | 1 / 0 |
err | Utf8 | |
accounts | List<Utf8> | |
log_messages | List<Utf8> | |
balance_changes | List<Struct> | {account, before, after} |
pre_token_balances | List<Struct> | {accountIndex, mint, owner, programId, uiTokenAmount} |
post_token_balances | List<Struct> | same struct as above |
compute_units_consumed | UInt64 | |
instructions | List<Struct> | Grouped (nested) instructions |
Starting position
Solana sources usestart_block to specify a starting slot number. This differs from EVM chains which use start_at: latest or start_at: earliest.
To start from the latest slot on Solana, simply omit the
start_block parameter. This is different from EVM chains where you would use start_at: latest.Multiple block ranges
Solana sources accept an optionalblock_ranges field so a single pipeline can process several disjoint slot windows. This is useful for backfilling specific historical ranges without replaying everything in between, or for splitting a large backfill into several sharded pipelines.
Syntax: block_ranges takes a JSON-encoded string (not a YAML list) of [start, end] pairs. Both bounds are inclusive.
- Ranges must be non-empty, non-overlapping, and strictly increasing. The engine panics at startup if these invariants are violated.
- A range’s
startmust be at or after the network’s earliest available block. block_rangestakes precedence overstart_block/end_block. If you set both, the legacy fields are ignored and a warning is logged.- After a checkpoint restore, the engine skips ahead to the next slot that falls inside any remaining range.
job: true to run a bounded backfill that terminates cleanly once every range is processed — the pipeline exits after the epoch covering the final range’s end slot finalizes:
Guide: Track Specific SPL Tokens
Monitor transfers for specific tokens like USDC:Guide: Track Large SOL Balance Changes
Monitor accounts with significant SOL movement:Guide: Decode Program Instructions
Decode Solana program instructions using IDL (Interface Definition Language):Decoding functions:
_gs_decode_instruction_data(idl, data)- Decode instruction data using an IDL_gs_decode_log_message(idl, log_messages)- Decode program log messages using an IDL_gs_fetch_abi(url, 'raw')- Fetch IDL from a URL
Guide: Decode Program Log Messages
Decode Solana program log messages to extract structured event data. This is useful for tracking program events like swaps, liquidations, or other on-chain actions that emit logs.Guide: Analyze Transaction Success Rates
Track transaction patterns and success rates using SQL:Guide: Track Specific Programs
Monitor all instructions for a specific program using SQL:Guide: Multi-Account Monitoring with Dynamic Tables
Track transfers involving specific accounts:Guide: Working with Transactions and Instructions Together
Thetransactions_with_instructions dataset provides a transaction-centric view with all instructions nested in an array. This is ideal when you need both transaction-level data and instruction details without joining separate datasets.
When to Use transactions_with_instructions
Use transactions_with_instructions
- Analyzing multi-instruction transactions - Counting instructions per transaction - Transaction-level aggregations with instruction filtering - Examining instruction sequences within transactions
Use separate datasets
- Simple instruction filtering by program - Individual instruction analysis
- Better SQL performance for instruction-only queries - Joining instructions with other data
Schema Overview
Each row represents one transaction with nested arrays: Transaction fields:id, index, block_slot, block_hash, block_timestamp, accounts, balance_changes, pre_token_balances, post_token_balances, recent_block_hash, signature, err, status, compute_units_consumed, fee, log_messages
Nested instruction array: instructions - Array of instruction structs, each containing:
id,index,parent_index(null for top-level, set for inner instructions),signature,block_slot,block_timestamp,block_hash,tx_fee,tx_indexprogram_id,data,accountsstatus,err
Example: Analyze Multi-Step Swap Transactions
Find transactions with multiple Jupiter swap instructions:Example: Examine Inner Instructions
Analyze transactions with inner instructions (Cross-Program Invocations):Example: Transaction Success Analysis by Program
Analyze transaction success rates grouped by the programs involved:Working with Nested Instructions
To access individual instructions from theinstructions array:
Array indexing (1-based):
Guide: Recreating Solana’s Transaction Counter
Stream every Solana transaction in real-time to power a live counter, similar to theTotal transactions to date counter on Solana’s homepage. This example includes any and all transactions, including failed ones.
Source checkpoints and rewinds
Turbo pipelines use checkpoints to track processing progress. Understanding how checkpoints work helps you avoid unintended rewinds when updating pipeline configurations.How checkpoints work
Checkpoints use a hash of your source configuration (start_block, end_block, and block_ranges) to identify the user’s intent:
- Same hash: The pipeline resumes from the existing checkpoint
- Different hash: The pipeline treats this as a “source change” and rewinds to the new
start_block
Preventing unintended rewinds
A common issue occurs when re-applying a pipeline with a differentstart_block than the currently running configuration. For example:
start_block, the pipeline will rewind:
Best practices
Fetch the current configuration before re-applying
Always check the current pipeline definition before making changes:Using the CLI:Using the UI:
Navigate to your pipeline in the dashboard to view the current configuration.
If you intentionally want to reprocess data from a specific block, changing the
start_block is the correct approach. The rewind behavior is by design to give you control over reprocessing.Filtering by Account or Program
When you only need data for specific accounts or programs, add afilter to your source configuration. This enables fast scan mode, which skips irrelevant slots during backfills by querying an index of which accounts and programs are active in each slot. This can dramatically speed up historical data processing.
We index all accounts and programs referenced in Solana transactions, instructions, and cross-program invocations (CPIs). Program addresses should be specified in the program_ids field, while account addresses, including wallet public keys, Program Derived Addresses (PDAs), and token mint addresses, should be specified in the account_ids field.
Filter syntax
Thefilter parameter is a YAML mapping with two optional fields:
| Field | Description |
|---|---|
account_ids | Comma-separated list of account addresses to filter by |
program_ids | Comma-separated list of program addresses to filter by |
Example: Backfill token balances for specific accounts
Example: Backfill transactions for a specific program
The
filter parameter speeds up backfills only — when processing historical data from a start_block. During real-time processing (when the pipeline has caught up to the chain tip), all slots are processed regardless of the filter.Performance Tips
Choose the right dataset
Choose the right dataset
Use the most specific dataset:
- Token transfers? Use
solana.token_transfers - Balance changes? Use
solana.native_balancesorsolana.token_balances - Transaction-level analysis with instruction details? Use
solana.transactions_with_instructions - Individual instruction analysis? Use
solana.instructions - Transaction metadata only? Use
solana.transactions
Use source filters for backfills
Use source filters for backfills
If you only need data for specific accounts or programs, use the This is much faster than filtering in SQL transforms alone, as it skips entire slots that don’t contain relevant data.
filter parameter on your source to skip irrelevant slots during backfills:Filter early in SQL transforms
Filter early in SQL transforms
Apply filters in SQL as early as possible:
Use appropriate resource sizes
Use appropriate resource sizes
Solana has high throughput. Start with medium or large: