Tempo Mainnet is now live on Chainstack! Get Tempo RPC endpoint for free!    Learn more
  • Pricing
  • Docs

Solana: Architecture, Account Model and Transactions

Created Nov 7, 2025 Updated Jan 20, 2026

The Solana account model is the foundation of how data, balances, and program state are stored and modified across the network.

In Solana, everything comes down to accounts.
Every token balance, user record, and piece of program data lives inside one. The programs themselves are stateless — they only read and modify the information that accounts provide. Once you see this, the whole design of Solana becomes much clearer.

You’ll learn how Program-Derived Addresses (PDAs) let programs securely control deterministic accounts without private keys, how ownership and access flags prevent unauthorized modifications, and why rent and rent exemption keep the network’s storage model sustainable.

This article takes a closer look at what an account really is. We’ll break down its structure, ownership, and how Program-Derived Addresses (PDAs) help create secure, predictable account addresses without private keys. You’ll also see how the different types of accounts — from system to program state — fit together in Solana’s architecture.

What makes an account the basic unit of state on Solana

The most important thing to understand about Solana is that unlike most blockchains where “contracts” hold their own state internally, Solana separates code and data completely.
Programs (smart contracts) are pure logic, they don’t own persistent storage.
Instead, all persistent data lives in accounts, which are on-chain data containers managed by the runtime.

Yh5baeaaaaalaaaaaabaaeaaaibraa7 logo

Scheme from https://solana.com/docs/core/accounts#account-address

Every instruction that runs on Solana explicitly lists which accounts it wants to read or write.
The runtime enforces access rules:

  • Only the account’s owner program can modify its data.
  • Only the account’s signer (or a PDA acting as signer, PDA will be explained in next section) can authorize transfers or ownership changes.

This strict separation achieves two things:

  1. Parallelism: since programs operate only on the accounts listed in the transaction, Solana can execute unrelated transactions concurrently.
  2. Security and clarity: a program cannot accidentally modify global state; it must be given explicit permission to touch each account.

In short, accounts are the atomic unit of state on Solana.
If Ethereum’s equivalent is a contract with internal storage slots, Solana’s model externalizes that: each “slot” becomes its own addressable account on-chain.

Everything you interact with: users, tokens, pools, NFTs, even the Solana runtime itself is built on top of these accounts.

What is Program derived address (PDA)

Solana doesn’t allow programs to hold private keys.
Yet, sometimes your program needs an address it can own and control deterministically, for example, a vault to store user deposits, or a metadata account tied to a specific mint.
That’s exactly what Program-Derived Addresses (PDAs) provide.

PDA is a special kind of account address that is:

  • Deterministically derived from a set of seeds and a program ID
  • Guaranteed not to collide with any address that has a valid Ed25519 private key.

Because PDAs don’t correspond to real keypairs, they cannot be signed using a private key.
Instead, the Solana runtime lets the owning program “sign” on behalf of that PDA during an instruction but only if the PDA was derived with the program’s own ID.

How PDAs are generated

A PDA is derived like that with the help of solana-sdk on Rust:

Pubkey::find_program_address(seeds: &[&[u8]], program_id: &Pubkey)

This function tries different “bump” values: It iterates bump values by starting at 255 and decrementing by 1 until a valid PDA is found that is not on the Ed25519 curve (i.e., cannot have a private key).
This results a unique PDA is created for the combination of:

  • program_id
  • and the seeds array.

Example:

let (vault_pda, bump) =
Pubkey::find_program_address(&[b"my_vault", user.key().as_ref()], &program_id);

Now vault_pda will always be the same for this user and program no need to store it anywhere.

Yh5baeaaaaalaaaaaabaaeaaaibraa7 logo

Scheme from https://solana.com/docs/core/pda

How PDAs “sign”

When your program makes a cross-program invocation (CPI) (Don’t worry, it will be covered in later chapters; now we only want to understand the sign effect) that needs the PDA to act as a signer, for example, to transfer tokens from a PDA’s account, you use the function invoke_signed() and pass the same seeds and bump used to derive the PDA.

Why PDAs matter

PDAs are at the heart of how complex Solana programs structure state.
They let you:

  • Create per-user or per-pool state accounts deterministically (like ["profile", user] or ["pool", token_a, token_b]).
  • Build vaults or treasuries controlled solely by your program.
  • Prevent arbitrary users from hijacking your storage addresses.
  • Avoid having to store mapping data on-chain (you can recompute addresses instead).

They are what make Solana’s stateless programs practical, safe, and composable.

Account Types

On Solana, every account falls into one of two main categories:

  • Program accounts: contain executable code.
  • Data accounts: hold information but do not execute code.

This structure means that a program’s logic (the code) and its state (the data) live in separate accounts.

Program accounts

A program account holds the compiled bytecode that defines what a Solana program does.

Key properties:

  • Executable: true
  • Owner: always the BPF Loader
  • Data: contains the actual program code

Program accounts don’t store any user data or variables.
When a transaction calls a program, Solana loads this executable account into memory and runs its code.

Data accounts

Data accounts store all persistent data your program uses, such as user profiles, vaults, liquidity pools, and token mints.
They are owned by a specific program, and only that program can modify them.

Common subtypes:

Program state accounts

Custom accounts that keep your program’s on-chain data, such as:

  • a liquidity pool
  • a user’s staking position
  • configuration or settings data

Main properties:

  • Address: often a Program-Derived Address (PDA) to ensure secure, deterministic ownership
  • Owner: your program’s public key
  • Executable: false
  • Rent: must hold enough lamports to stay rent-exempt (explained later)

System accounts

These are accounts controlled by the System Program.
They include:

  • Wallet accounts holding SOL and able to sign transactions.
  • Temporary or uninitialized accounts before assignment to a program.
  • Upgrade or admin accounts, usually simple keypairs with control privileges.

System accounts form the foundation of Solana’s runtime.
They can send SOL, pay rent, and be reassigned to different program owners.

Sysvar accounts

Sysvar accounts are read-only accounts provided by Solana itself.
They give programs access to internal blockchain data — for example, block times, slot numbers, or rent rates.

Instead of adding this data to every transaction, Solana offers it through predefined Sysvar accounts.
More information can be found in the official Solana documentation.

How Solana enforces ownership, rent, and access

Now that we’ve seen the different types of accounts, it’s important to understand how Solana controls who can read, write, or move lamports and how it ensures the network stays economically stable through rent.

Ownership

Every account has an owner field a public key that identifies the program authorized to modify its data.

  • Only the owning program can change an account’s data bytes.
  • The System Program can change an account’s owner (using assign) or Lamport balance (using transfer).
  • User wallets are just system accounts whose owner is the System Program.
  • When your custom program creates an account, it sets itself as the owner, making it the only program that can write to that account’s data.

Example:

account.owner = <your program id>

means that only your program can modify this account’s internal data field no other program can. This strict owner–writer rule prevents accidental or malicious modification of another program’s state.

Access Control (Signers and Writable Flags)

On Solana, every transaction must clearly list all the accounts it will use before execution.
For each account, two important flags are defined:

  • Writable: whether the program can change the account’s data or lamports (SOL balance).
  • Signer: whether the account must sign the transaction to authorize it.

This system ensures strong access control.
Only accounts marked as writable can be modified during execution — for example, updating a user’s balance or changing program state. Accounts marked as read-only can be viewed but not altered.

Similarly, signer accounts are those that prove permission to perform an action. In most cases, this means a user’s wallet or a Program Derived Address (PDA) that signs through invoke_signed. Without the correct signature, the transaction will fail.

A key rule is that programs cannot read or modify any account that wasn’t explicitly included in the instruction’s context. This prevents unauthorized access and ensures predictable behavior.

Because Solana knows in advance which accounts each instruction will touch, it can safely execute many transactions at the same time — as long as they do not try to write to the same accounts.
This explicit access model is what enables Solana’s high parallel performance and throughput.

Rent and Rent Exemption

Every account must pay rent, which is a small cost to occupy on-chain storage. However, most programs make accounts rent-exempt by depositing enough lamports upfront.

The rent-exempt minimum depends on:

  • the account’s data size (number of bytes), and
  • the current rent rate (available via the SysvarRent account).

Key points:

  • If an account’s lamports drop below the rent-exempt threshold, the runtime can reclaim it.
  • Rent-exempt accounts never lose lamports or get purged.
  • Programs typically calculate rent like this:
let rent = Rent::get()?;
let lamports = rent.minimum_balance(space);

This one-time deposit covers storage costs permanently, keeping the account active without future rent deductions.

Read the full article from Andrey Obruchkov on Substack

Learn more about Solana architecture from our articles

Reliable Solana RPC infrastructure

Getting started with Solana on Chainstack is fast and straightforward. Developers can deploy a reliable Solana node within seconds through an intuitive Console — no complex setup or hardware management required. 

Chainstack provides low-latency Solana RPC access and real-time gRPC data streaming via Yellowstone Geyser Plugin, ensuring seamless connectivity for building, testing, and scaling DeFi, analytics, and trading applications. With Solana low-latency endpoints powered by global infrastructure, you can achieve lightning-fast response times and consistent performance across regions. 

Start for free, connect your app to a reliable Solana RPC endpoint, and experience how easy it is to build and scale on Solana with Chainstack – one of the best RPC providers.

SHARE THIS ARTICLE
andrey_o

Andrey Obruchkov

Senior Software Engineer and blockchain specialist with hands-on experience building across EVM, Solana, Bitcoin, Cosmos, Aptos, and Sui ecosystems from smart contracts and DeFi infrastructure to cross-chain integrations and developer tooling.

Customer Stories

Aleph One

Operate smarter and more efficiently with seamless integration of decentralized applications.

Trava.Finance

Reliable and high-performance infrastructure across multiple blockchain networks.

Blank

Achieving operational excellence with infrastructure made for full privacy functionality.