Sealevel Runtime Key Points
Sealevel is Solana's parallel runtime for on-chain programs: it schedules work from declared account access, meters compute, and keeps program logic separate from durable state.
This page is the conceptual map for Programs & Sealevel Runtime - executable bytecode, the SVM entrypoint, account locks, concurrency, compute budgets, and loaders on Agave 4.1.1.
Summary
- Solana programs are stateless executables; Sealevel runs them against accounts the transaction listed up front, locking those accounts so non-overlapping work can proceed in parallel.
- Insight: Almost every design choice - PDAs, instruction shape, CU limits, upgrades - follows from how the runtime locks accounts and meters compute, not from how you would store data inside a contract.
- Key Concepts: executable program account, sBPF / SVM, entrypoint, AccountMeta, read/write locks, compute units (CU), upgradeable loader / ProgramData.
- When to Use This Model: Designing state layouts, reasoning about throughput under contention, debugging missing accounts or CU failures, or teaching Solana execution to sequential-runtime teammates.
- Limitations/Trade-offs: Parallelism is not automatic - a shared writable account serializes work, and every heavy path costs CU inside a finite transaction budget.
- Related Topics: Programs Basics, The SVM & sBPF, Sealevel Parallel Execution, Account Locks & Conflicts, Compute Units & Budgets, Stateless Programs.
Foundations
A program on Solana is an executable account: its data is bytecode the runtime is allowed to run, not application records you mutate instruction by instruction.
Durable state lives in other accounts the program owns (or may read). The binary does not embed a growing database of users, balances, or mappings.
You write logic in Rust (or another supported language), compile to sBPF (Solana BPF), and deploy the shared object for validators to load.
The SVM (Solana Virtual Machine) on Agave validators runs that sBPF, enforces ownership rules, meters compute, and services syscalls.
An instruction names a program ID, a list of accounts, and an opaque instruction-data byte slice.
The program's entrypoint is the single function the runtime calls for every instruction to that program.
In native form, the entrypoint receives roughly program_id, a slice of AccountInfo values, and the instruction data. Anchor's #[program] macro generates that entrypoint and dispatches on an 8-byte discriminator to your handlers.
Every instruction must declare AccountMeta for each account the runtime will touch: public key, is_signer, and is_writable.
Those flags are lock requests Sealevel uses before any bytecode runs, not optional client-side hints.
Mechanics & Interactions
Execution starts outside your program: a transaction is assembled with one or more instructions, each listing program ID, accounts, and data, then signed and submitted with a recent blockhash.
The runtime validates signatures, fee payer balance, and that every account appearing in any instruction is present in the transaction's account list with consistent meta flags.
Before scheduling, Sealevel derives locks from those metas: a writable account needs an exclusive write lock; a readonly account needs a shared read lock.
Multiple transactions may hold read locks on the same account concurrently.
A write lock excludes other writers and readers on that same account for the duration of the conflicting work.
That rule produces the core scheduling behavior: transactions whose locked account sets do not conflict can run in parallel; write-write and write-read overlaps must serialize.
Account keys:
A = Alice position PDA (writable in Alice's txs)
B = Bob position PDA (writable in Bob's txs)
G = Global vault (writable when anyone touches it)
C = Config (readonly in both designs)
Disjoint locks - may run concurrently:
Tx1: write(A), read(C)
Tx2: write(B), read(C)
-> locks: A exclusive, B exclusive, C shared -> no conflict
Overlapping locks - must serialize:
Tx3: write(G), write(A), read(C)
Tx4: write(G), write(B), read(C)
-> both need exclusive G -> Tx3 and Tx4 cannot run in parallel
Inside a scheduled transaction, instructions run in order; within an instruction the SVM loads the program, calls the entrypoint, and passes only the accounts that instruction listed.
Your handler may read account data, write only accounts it owns (and that were marked writable), transfer lamports under the usual rules, and issue CPIs to other programs - but every account a CPI needs must already be in the transaction's declared set.
While the entrypoint runs, the runtime meters compute units (CU). Syscalls, logging, deserialization, and arithmetic all draw from a transaction-level budget.
On modern Solana (including Agave 4.1.1), the default transaction compute budget is about 1,400,000 CU unless a Compute Budget instruction raises (or lowers) the limit within protocol caps.
If any path exceeds the remaining budget, the transaction fails and state changes from that transaction do not commit.
CU measures allowed work; priority fees influence inclusion under load - related knobs, different jobs.
After success, account updates commit under the locks already held; failed transactions release locks without applying those writes.
Upgrades sit beside execution, not inside app state. With the BPF Upgradeable Loader, the program ID account points at a ProgramData account that holds bytecode.
An upgrade authority (if set) can deploy a new .so into ProgramData; clearing that authority freezes the loader upgrade path.
Because programs are stateless, upgrades swap logic without migrating storage out of the binary - data accounts remain, so new code must stay layout-compatible or ship an explicit migration.
Advanced Considerations & Applications
The highest-leverage design decision under Sealevel is what you mark writable.
A single global writable account - a "mutex" config, one shared ledger, one global counter every user must touch - forces every contending transaction into a single file, no matter how efficient the sBPF is.
Sharding state so each user (or each order, position, or session) has its own PDA keeps most transactions on disjoint keys so the scheduler can run them together.
| Design | Writable accounts per user action | Parallelism under load | When it fits | Cost of getting it wrong |
|---|---|---|---|---|
| Per-user / per-entity PDAs | Usually that user's PDA (+ token accounts as needed) | High - different users rarely lock the same keys | User profiles, positions, inventories, sessions | Slightly more accounts to pass and create |
| Sharded tables (many PDAs by shard key) | One shard PDA among many | High if load spreads across shards | High-throughput indexes, order books, queues | Hot shard keys still serialize that slice of traffic |
| Global config (readonly in hot path) | None for config if only read | Readers share the config lock | Parameters, fee rates, feature flags | Marking config writable on every tx kills parallelism |
| Global mutex account (always writable) | The same global account for everyone | Low - essentially sequential on that key | Rare admin ops, true global invariants that must serialize | Throughput ceiling equals one writer at a time |
| Hybrid: hot path sharded, cold path global | User PDA on hot path; global only on admin/settle | Hot path scales; admin path serializes intentionally | Markets that settle against a shared vault on a schedule | Accidentally putting the vault on the hot path |
Prefer readonly whenever you do not mutate: a shared config PDA marked readonly lets many transactions hold concurrent read locks.
Keep writable sets minimal and predictable so clients can build account lists and so the lock graph stays sparse.
Watch CU the same way you watch locks: large account deserialization, verbose msg! logging, and unbounded loops burn budget and can push ordinary paths toward the default ~1,400,000 CU ceiling.
Request a higher limit with a Compute Budget instruction when simulation shows you need it; still optimize the hot path so you are not paying priority fee for waste.
Think about loaders in production: retain upgrade authority only while you need it, use verifiable builds, and treat ProgramData upgrades as a change-control process - authority compromise is a full code-rewrite risk.
When testing on Agave 4.1.1-aligned stacks (CLI 3.0.10, Anchor 0.32.1, LiteSVM 0.6.x, Surfpool 0.12.0), exercise CU and contended-account cases before mainnet traffic does.
Common Misconceptions
- "Programs hold application state like EVM contracts." Programs hold executable bytecode; application state lives in separate accounts the program owns - see Stateless Programs.
- "Sealevel parallelizes every transaction automatically." Only transactions with non-conflicting lock sets run together; shared writable accounts force serialization.
- "If two transactions only read the same account, they must wait." Multiple readers may share a read lock; conflicts appear when at least one side needs a write lock on the same key.
- "The program can pull any account it wants at runtime." Every account must appear in the transaction's declared list with correct signer/writable flags before execution starts.
- "Exceeding compute only fails one instruction." Compute is metered against the transaction budget; exhaustion fails the transaction and rolls back its effects.
- "Default CU is unlimited until I set a budget." There is a default per-transaction ceiling (about 1,400,000 CU on modern Solana); you may request a different limit within protocol bounds via Compute Budget instructions.
- "is_writable is optional if my code only writes sometimes." The meta flags define locks and authorization for writes; under-declaring writable or missing accounts fails at runtime or prevents intended mutations.
- "Upgrading the program rewrites user account data." The upgradeable loader swaps bytecode in ProgramData; existing data accounts stay as-is unless you ship migration logic.
- "CPI lets me discover callee accounts dynamically without listing them." CPI still requires every needed account to have been provided in the outer transaction's account list.
- "One big account is simpler and just as fast." It may be simpler to code, but it becomes a global mutex under Sealevel and caps throughput at one writer at a time.
FAQs
What exactly is a Solana program under Sealevel?
An executable account whose data is sBPF bytecode the SVM can run. It is invoked by instructions that name its program ID and pass accounts plus instruction data.
Where does my app state live if the program is stateless?
In data accounts owned by your program (often PDAs). The program reads and writes those accounts when they are passed in and marked appropriately.
What does the entrypoint receive?
The program ID, a slice of account infos for the accounts listed on the instruction, and the instruction data bytes. Frameworks like Anchor 0.32.1 generate this entrypoint and dispatch to typed handlers.
Why must clients declare is_signer and is_writable?
Those AccountMeta flags tell the runtime who authorized the transaction and which accounts need exclusive write locks versus shared read locks. Wrong flags cause failures or missing write privileges.
When can two transactions run at the same time?
When their required locks do not conflict - typically when they touch disjoint writable sets and any shared accounts are readonly for all concurrent readers. See Sealevel Parallel Execution.
What lock conflicts force serialization?
Write-write on the same account, and write-read on the same account. Two pure readers of the same account do not need to serialize with each other. Details in Account Locks & Conflicts.
What is the default compute budget I should assume?
On modern Solana including Agave 4.1.1, plan around a default transaction compute budget of about 1,400,000 CU unless Compute Budget instructions set a different limit within protocol bounds.
What happens if my instruction uses too many compute units?
The transaction fails with a compute-budget error and does not commit state changes from that transaction. Simulate, measure logs (consumed), and either optimize or request a higher limit. See Compute Units & Budgets.
How do Rust, sBPF, and the SVM relate?
You compile Rust to sBPF with the Solana/Agave toolchain (cargo build-sbf / Anchor build). Validators execute that bytecode in the SVM under Sealevel's scheduling and metering rules. See The SVM & sBPF.
How do upgradeable programs work?
The BPF Upgradeable Loader keeps a program account that points at ProgramData holding the bytecode. An upgrade authority can deploy new bytecode; removing the authority freezes that upgrade path.
Does upgrading change my PDA addresses?
No. PDA addresses derive from program ID and seeds. The program ID stays the same across upgrades of the same deployed program; only the bytecode in ProgramData changes.
How should I design accounts for maximum parallelism?
Give each independent actor or entity its own writable account (commonly a PDA), keep global accounts readonly on hot paths, and avoid a single writable account every user must touch.
Can I mutate an account my program does not own?
No for arbitrary data writes - only the owner program may modify an account's data. Other programs interact via CPI into the owner (for example SPL Token) with the correct accounts and signers.
Do CPIs get a separate compute budget?
CPIs consume CU from the same transaction budget. Nested calls still draw from the shared pool; deep or heavy CPI stacks need budgeting and simulation.
How does this model change under Alpenglow or other consensus work?
Confirmation latency may change, but the program mental model - declared accounts, locks, stateless executables, CU metering - remains Sealevel as described here.
Related
- Programs Basics - what a program is and how it is invoked
- The SVM & sBPF - compilation target and virtual machine
- Sealevel Parallel Execution - scheduling non-conflicting transactions
- Account Locks & Conflicts - read/write lock rules in detail
- Compute Units & Budgets - metering, limits, and optimization
- Stateless Programs - why logic and state stay separated
- The Program Entrypoint - entrypoint, accounts slice, instruction data
- Program Loaders & Upgradeability - upgradeable loader and ProgramData
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.