If you’re coming from Ethereum, Solana’s account model will feel alien. That’s a good thing — it’s one of the main reasons Solana can process transactions in parallel.
Everything is an account
In Solana, everything lives in an account: your wallet balance, program code, program state, even the clock. An account is just a blob of bytes with some metadata:
pub struct Account {
pub lamports: u64, // SOL balance (in lamports)
pub data: Vec<u8>, // arbitrary byte storage
pub owner: Pubkey, // which program "owns" this account
pub executable: bool, // is this a program?
pub rent_epoch: Epoch, // for rent calculations
}
Programs don’t own their state
This is the key insight that confuses everyone at first: Solana programs are stateless. A program’s code is stored in one account, and the data it manages lives in separate accounts.
When you call a program, you pass in the accounts it needs to operate on. The program reads and writes those accounts. It doesn’t have global storage.
This is why Solana transactions include an explicit list of accounts — the runtime uses this to detect parallelism opportunities.
PDAs — Program Derived Addresses
Since programs can’t store state themselves, they create PDA accounts that they control. A PDA is derived deterministically from a program ID and some seeds:
let (pda, bump) = Pubkey::find_program_address(
&[b"user-stats", user.key().as_ref()],
&program_id,
);
The bump ensures the address doesn’t land on the ed25519 curve (so no private key can sign for it). Only the owning program can sign for a PDA.
Why this design wins
The explicit account model means:
- Parallel execution — the runtime sees which accounts a transaction touches and can run non-overlapping transactions simultaneously
- Predictable costs — rent is based on account size, not compute
- Composability — programs can pass accounts between each other cleanly
It takes getting used to, but once it clicks, it’s a surprisingly elegant model.
Comments