Research · Solana
The account model: ownership, storage and PDAs
Last reviewed 2026-09-21Source: Solana account documentationMechanism described as deployed; limits quoted from the runtime constants.
Five fields, one shape
An account is Solana's fundamental unit of state. Every account, whether it holds a wallet balance, a token mint, a program's data or the program's own bytecode, has the same five fields. There is no separate object type for a token or a program; the difference is carried by the fields themselves, principally the owner and the executable flag.
The address is a 32-byte value, displayed as a base58 string. It is either an Ed25519 public key, which has a corresponding private key, or a program derived address, which does not. The distinction matters because it decides who can sign for the account, and it is the basis of the PDA mechanism described below.
| Field | Type | Role and rule |
|---|---|---|
lamports | u64 | Balance in lamports. The owner may debit it; any program may credit it. |
data | byte vector | Account state or program bytecode. Writable only by the owner. |
owner | Pubkey | The program with write access. Reassignable only when the data is zeroed. |
executable | bool | True for a program account, false for a data account. |
rent_epoch | Epoch | Deprecated. Set to u64::MAX for accounts meeting the storage deposit. |
Last reviewed 2026-09-21Source: Solana — Account Structure
Ownership decides who may change what
The owner field is the program that governs the account's state transitions. Only the owner may modify the account's data, and only the owner may deduct lamports from it. Any program may add lamports to any account, and any program may read any account. Those four rules are the whole of the permission model, and most of the account model's behaviour follows from them.
The asymmetry between crediting and debiting is deliberate. Because anyone can add lamports but only the owner can remove them, a program cannot drain an account it does not own, but it can always fund one. That makes it safe to send value to an address without the recipient having to cooperate, which is what allows a first transfer to a new address to create the account.
Ownership is assigned once. The System Program is the only program that can assign an account's owner, and it can only do so while the account's data is zeroed. A program that wants to take ownership of a new account does so by asking the System Program to create the account with that program as owner, then initialising the data itself. Once data has been written, the owner cannot be changed without first clearing it.
Program accounts are owned by their loader. When a program is deployed, the account holding its bytecode is owned by one of the loader programs rather than by the program itself, and the runtime checks that a program invoked by an instruction is owned by a valid loader before executing it. A program that is not owned by a loader cannot be executed.
The storage deposit, and why rent is a misnomer
Storing data on-chain costs the network something, and Solana makes the account holder pay for it. Every account must hold a minimum lamport balance proportional to the size of its data. The runtime and the RPC methods call this the rent-exempt minimum, but the name is a legacy: ongoing rent collection is disabled, and the balance is better understood as a refundable storage deposit.
The deposit is refundable because it is not spent. It sits in the account's lamport balance, and when the account is closed — its balance reduced to exactly zero — the full amount is recovered. What the holder gives up is the use of that capital while the account exists, not the capital itself. The formula the runtime uses is documented as a function of the account's size, and the constants behind it are published rather than hidden.
The rule is enforced on every balance reduction. A transaction that would leave an account below its minimum without closing it fails, and the only permitted way to go below the minimum is to go to exactly zero. That is why closing an account is a distinct operation rather than simply spending its balance down. Accounts that reach zero are removed from the network by garbage collection, though their transaction history remains visible.
The rent_epoch field is a remnant of the earlier design. It once tracked when an account would next have lamports deducted to pay for its storage. With ongoing collection disabled, it is set to the maximum value for accounts that meet the deposit, and it carries no operational meaning today.
Program derived addresses
A program often needs an address it controls without holding a private key — a per-user account, a vault, a mint authority. A program derived address is how it gets one. A PDA is derived deterministically from the program's own ID and a set of seeds, so the same program and the same seeds always produce the same address.
The derivation is designed to produce an address that is not a valid point on the Ed25519 curve. Because it is off-curve, no private key exists for it, and no external party can produce a signature for it. Only the program whose ID was used in the derivation can authorise operations on the PDA, and it does so through the runtime's invoke_signed mechanism during a cross-program invocation rather than by presenting a signature.
The derivation hashes the seeds, the program ID and a fixed string together, then checks whether the result lies on the curve. If it does, the derivation fails and a different bump seed is tried. The bump is a single byte appended as the final seed, and the canonical bump is the first value that produces an off-curve address. Programs are expected to use the canonical bump: using a non-canonical one creates a second valid address for the same seeds, which is a known source of vulnerabilities.
Deriving a PDA computes an address; it does not create an account. The account must be created separately, typically by a cross-program invocation to the System Program that allocates the space and assigns ownership. Until that happens, the address exists only as a derivation, not as on-chain state.
| Limit | Value | Constant |
|---|---|---|
| Maximum seeds per derivation | 16 | MAX_SEEDS |
| Maximum length per seed | 32 bytes | MAX_SEED_LEN |
| Bump range | 0–255 (one byte) | Appended as the final seed |
| Maximum PDA signers per cross-program invocation | 16 | MAX_SIGNERS |
Last reviewed 2026-09-21Source: Solana — Program Derived Addresses
What the model implies
The account model is the reason the Sealevel runtime can schedule transactions in parallel. Because every account has a single owner and a transaction declares which accounts it will write, the runtime can tell whether two transactions conflict without executing either. A model in which a contract held its own internal state would not expose that information at the transaction level.
It also explains why storage is priced the way it is. Because the deposit is proportional to data size and refundable on close, a program that stores a large amount of state imposes a real capital cost on whoever funds it. That cost is the reason state compression exists: it stores a hash of the data rather than the data itself, which reduces the deposit dramatically. The state compression page covers that trade-off.
Sources and references
The account structure, the ownership rules, the storage deposit and the PDA derivation are taken from the project's own documentation. The mechanism is presented as deployed; the limits quoted are the runtime constants named in the sources.
- The account structure and its fields. Solana, Account Structure: defines the five fields, the ownership rules, the storage deposit and the deprecated rent epoch.
- Account types and the System Program. Solana, Account Types: distinguishes program accounts, data accounts, system accounts and sysvars, and describes how a data account is created and initialised.
- Program derived addresses. Solana, Program Derived Addresses: covers the derivation, the off-curve requirement, the canonical bump and the seed and signer limits.
- Account loading and validation. Solana, Account Runtime: describes how accounts are loaded before execution and the validations the runtime performs on the fee payer and program accounts.
Related reading
- Research HubEvery dataset on the site, with methodology and provenance.
- Altcoin ResearchAltcoins measured against Bitcoin: design intent, consensus, execution, scaling and market structure.
- The ETH-BTC Correlation RecordHow the correlation is measured, how it behaves across windows, and where it breaks down.
- The ETH/BTC RatioWhat the ratio measures, how to read its trend, and why it is not a forecast.
- ETH During Bitcoin Bull PhasesAssociation within a common market factor, and what co-movement cannot establish.
- ETH During Bitcoin Bear PhasesDrawdown depth and duration compared over identical windows, and the limits of the comparison.