6. Programs, SVM, and development
A Solana program is not a server waiting for HTTP requests. It is deterministic logic invoked by instructions and given explicit accounts. This chapter turns the architecture into a development workflow.
What the runtime gives a program
Section titled “What the runtime gives a program”Conceptually, a handler receives:
program idordered account inputsinstruction data bytesThe program parses the instruction, validates every account, applies business rules, updates permitted state, and may invoke other programs. Execution is metered and deterministic.
Programs compile to Solana bytecode and run under the Solana runtime. The term SVM describes this execution environment and programming model. Performance depends on code, compute, account access, scheduler behavior, and validator implementation, not on a label alone.
Start from an instruction specification
Section titled “Start from an instruction specification”Before writing Rust, specify the state transition:
Instruction: UpdateProfile(name)Signer: authorityWritable: profile PDARead-only: system/clock inputs only if requiredChecks: profile PDA matches ["profile", authority] profile owner is this program stored authority equals signer name byte length <= 64Effect: profile.name becomes nameErrors: wrong authority, wrong PDA, invalid data, name too longThis document becomes the basis for implementation, tests, client generation, and review.
Native Rust flow
Section titled “Native Rust flow”A native program commonly follows this shape:
pub fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], data: &[u8],) -> ProgramResult { let instruction = MyInstruction::unpack(data)?; match instruction { MyInstruction::UpdateProfile { name } => { process_update_profile(program_id, accounts, name) } }}The real work is not the match. The real work is validating account addresses, owners, signers, writable privileges, data shape, authority, bounds, and arithmetic.
Anchor adds conventions
Section titled “Anchor adds conventions”Anchor provides account serialization, instruction dispatch, IDL generation, error conventions, and declarative account constraints.
#[derive(Accounts)]pub struct UpdateProfile<'info> { #[account( mut, seeds = [b"profile", authority.key().as_ref()], bump, has_one = authority )] pub profile: Account<'info, Profile>,
pub authority: Signer<'info>,}Read each constraint as a security claim. mut permits change, seeds checks the PDA namespace, and has_one connects stored authority to the signer account.
Native Rust or Anchor?
Section titled “Native Rust or Anchor?”Choose Anchor for common application development, typed clients, and a productive constraint system. Choose lower-level Rust when you need explicit control, specialized interfaces, or deeper runtime work. A strong developer understands the underlying account model regardless of framework.
Organize by invariants
Section titled “Organize by invariants”programs/profile/src/├── lib.rs├── state.rs├── errors.rs└── instructions/ ├── initialize.rs ├── update.rs └── close.rsKeep state definitions and instruction-specific validation readable. As the program grows, a single large handler hides security boundaries.
Test the attacks, not only the happy path
Section titled “Test the attacks, not only the happy path”A useful testing ladder is:
Pure unit tests
Section titled “Pure unit tests”Test parsing, serialization, arithmetic, rounding, and bounded input rules.
Local program tests
Section titled “Local program tests”Test complete instructions against an isolated validator or test environment.
Adversarial tests
Section titled “Adversarial tests”Attempt:
- wrong owner program;
- correct signer but wrong authority;
- fake PDA or bump;
- duplicate account aliasing;
- repeated initialization;
- overflow or underflow;
- fake token mint;
- wrong CPI program;
- unauthorized close;
- stale oracle data.
Devnet integration
Section titled “Devnet integration”Test wallet approval, RPC behavior, transaction confirmation, and deployment configuration with disposable assets.
Deployment is a trust decision
Section titled “Deployment is a trust decision”An upgradeable program has an upgrade authority under the applicable loader model. If one laptop key controls that authority, users are trusting one laptop.
Production questions include:
- Who can upgrade?
- Is authority held by a multisig or governance process?
- Are upgrades delayed or announced?
- Can users verify deployed code against source?
- Is there an incident and rollback process?
- Can authority eventually be revoked if immutability is intended?
Use separate identities for development, deployment, treasury, minting, and emergency operations.
Security checklist
Section titled “Security checklist”Before production:
- validate every account and exact external program ID;
- verify PDA seeds, owners, types, and authorities;
- use checked arithmetic and document rounding;
- bound variable-length data;
- minimize writable accounts;
- secure initialization, migration, and close paths;
- define duplicate and replay behavior;
- verify oracle freshness and confidence;
- pin dependencies and review changes;
- measure compute and contention;
- obtain independent review for valuable assets.
A development path that teaches the architecture
Section titled “A development path that teaches the architecture”- Build a counter on a local validator.
- Replace one global counter with one PDA per user.
- Add an authority and close instruction.
- Write tests for wrong signer, wrong PDA, and repeated initialization.
- Add a TypeScript client that separates read, build, sign, submit, and confirm stages.
- Deploy to Devnet and inspect every account in an explorer.
- Only then add token CPI or external data.
Check your understanding
Section titled “Check your understanding”Explain why this statement is dangerous:
“The account signed, so the account is allowed to update the profile.”
The signer may be valid but unrelated to the stored profile authority. Authorization requires the relationship, not merely a signature.
Next, apply the model to the most common on-chain assets in Tokens, NFTs, and DeFi.