4. Accounts and state
Consensus gives validators one accepted history. What does that history contain? Primarily, changes to accounts. Account design is the center of Solana application architecture.
An account is a typed box only because your program says so
Section titled “An account is a typed box only because your program says so”At runtime, account data is bytes. A program and its client agree that those bytes represent a profile, market, order, or configuration.
Conceptually, an account contains:
struct Account { lamports: u64, data: Vec<u8>, owner: Pubkey, executable: bool, rent_epoch: u64,}Read each field as a question
Section titled “Read each field as a question”lamports: how much native balance is attached?
Section titled “lamports: how much native balance is attached?”Lamports can represent ordinary SOL holdings and fund the minimum balance associated with storing account data.
data: what bytes are stored?
Section titled “data: what bytes are stored?”The owning program interprets these bytes according to a serialization format and version.
owner: which program may change the data?
Section titled “owner: which program may change the data?”The runtime enforces owner-based rules. This owner is a program address, not necessarily the person who controls an application action.
executable: is this account program code?
Section titled “executable: is this account program code?”Executable accounts represent programs rather than ordinary mutable application records.
rent_epoch: what storage-accounting metadata exists?
Section titled “rent_epoch: what storage-accounting metadata exists?”Treat this as a runtime field. Do not build application logic on assumptions that are not guaranteed by current documentation.
Build a profile account
Section titled “Build a profile account”Suppose a program stores one profile per wallet.
Profile PDA version: 1 authority: Alice public key display_name: "Alice" created_slot: 123456The PDA is derived from ['profile', Alice public key]. Alice can find the profile without a registry, and the program can verify the derivation.
To update the profile safely, the program checks:
- the profile address matches the expected PDA;
- the profile is owned by the Profile Program;
- the bytes represent the expected account type and version;
- the stored authority equals Alice’s signer address;
- the new name fits allocated space;
- the profile is writable.
Missing one check may allow account substitution or unauthorized updates.
Account types you will meet
Section titled “Account types you will meet”- A system account commonly holds SOL and may correspond to a wallet public key.
- A data account stores application state.
- A program account contains executable code.
- A sysvar exposes selected cluster information to programs.
- A mint account describes a token.
- A token account records a balance for one mint.
- A stake account stores staking state.
The word “account” therefore does not mean “user login.” It means an addressable piece of on-chain state.
Owner, authority, signer, payer
Section titled “Owner, authority, signer, payer”| Term | The question it answers |
|---|---|
| Owner program | Which program may modify base account data? |
| Authority | Which address does the application trust for an action? |
| Signer | Which required private-key authorization is present? |
| Fee payer | Which signer pays the transaction fee? |
| Writable | May this transaction modify the account? |
Space must be planned
Section titled “Space must be planned”On-chain data is not an unlimited JSON document. Allocate space for fixed fields and bounded variable fields.
space = discriminator + version + fixed fields + bounded contentAvoid unbounded vectors and strings. If data grows indefinitely, consider pages, one PDA per record, bounded queues, or off-chain content with an on-chain integrity reference.
Fetch the current minimum balance for the exact account size rather than hard-coding it.
Serialization and migrations
Section titled “Serialization and migrations”A durable account should identify its type and version. A simple layout might be:
[discriminator][version][authority][application fields]Deployed data can outlive one program release. Plan how version 1 becomes version 2:
- retain backward-compatible readers;
- add bounded optional fields;
- reallocate with correct authority and funding;
- or create a new account and migrate safely.
Account design controls parallelism
Section titled “Account design controls parallelism”The runtime locks writable accounts during transaction execution.
Alice update -> writes AliceProfileBob update -> writes BobProfileThese operations do not conflict. If every update also writes one global counter, that counter becomes a shared lock and reduces concurrency.
A useful design rule is:
Keep shared configuration read-only on common paths, and partition mutable state when application invariants allow it.
Partitioning is not free. It can complicate queries and atomic cross-record operations. Design from actual read/write patterns, not from a slogan.
Closing an account
Section titled “Closing an account”An application may allow unused accounts to be closed and remaining lamports returned. A safe close instruction validates the authority and destination, invalidates the old state, and prevents unsafe reuse.
Cleanup is not an afterthought. An unauthorized close path can be as damaging as an unauthorized transfer.
Account validation checklist
Section titled “Account validation checklist”Before trusting an account, ask:
- Is the address expected?
- Is the owner program expected?
- Is the account the expected type and version?
- Is the PDA derivation correct?
- Is the required authority the actual signer?
- Are mint and token authority fields correct?
- Is writability necessary?
- Could two inputs point to the same account unexpectedly?
- Is the account initialized, active, and large enough?
Check your understanding
Section titled “Check your understanding”Draw a box for a Profile Program and two boxes for AliceProfile and BobProfile. Put logic in the program box and state in the profile boxes. Then explain why the two updates can run concurrently.
Next, learn how a transaction carries those account boxes into program execution in Transactions and runtime.