Solana
Solana is the main production blockchain that isn't an EVM chain, and its architecture differs from Ethereum at the most basic level: programs hold no state. Code and data are entirely separate. A program is a stateless deployed binary; all data lives in accounts that the caller must name explicitly in every transaction.
That constraint sounds like a burden and is actually the design's core insight. Because every transaction declares up front which accounts it will read and write, the runtime knows exactly which transactions conflict — and can execute all the non-conflicting ones in parallel. Ethereum's EVM is single-threaded because a transaction's storage access isn't known until it runs. Solana's is parallel because it is.
The costs are equally real: mandatory upfront declaration of accounts makes composability harder, the mental model takes longer to learn, and the network has a history of outages that EVM chains have not had.
TL;DR
- Programs are stateless. All data lives in separate accounts that transactions must declare.
- Every instruction lists its accounts and whether each is writable and a signer — this is what enables parallelism.
- Sealevel executes non-conflicting transactions in parallel; Proof of History provides a verifiable clock.
- PDAs (Program Derived Addresses) are deterministic addresses a program can sign for — the equivalent of contract-owned state.
- Accounts pay rent as a refundable minimum balance; close an account to get it back.
- Programs are Rust; Anchor is the framework that removes most of the boilerplate and adds safety checks.
- Fees are fractions of a cent and blocks are ~400 ms; the tradeoff is heavier validator hardware and fewer validators.
- Programs are upgradeable by default — a security consideration EVM developers don't have.
Quick Example
A counter program in Anchor — the standard shape of Solana code:
The #[derive(Accounts)] struct is where most of the security lives. It's a declarative specification of what each account must be — the right type, the right owner, the right PDA seeds, a signer or not — and Anchor rejects the transaction before your logic runs if any of it doesn't hold.
Core Concepts
The accounts model
Every account has:
Only an account's owner program may modify its data. That's the entire authorization primitive, and it's checked by the runtime rather than by your code.
Transactions declare their accounts
Every instruction carries an explicit account list with per-account flags: writable or read-only, signer or not. The runtime uses this to schedule:
This is why the declaration requirement exists, and it's the fundamental difference from the EVM. It also means a program cannot decide mid-execution to touch an account the caller didn't list — which rules out some dynamic patterns that are trivial in Solidity.
Program Derived Addresses
A PDA is an address derived from a program ID plus seeds, deliberately chosen to lie off the ed25519 curve so no private key exists for it. The program can sign for it, which is how a program owns and controls state and assets.
PDAs serve the role of mappings in Solidity: balances[user] becomes a PDA seeded by the user's key. The difference is that the client must derive and pass the address, since the transaction has to declare it.
Rent
An account must hold a minimum SOL balance proportional to its size, or it can be reclaimed. Above the threshold, an account is rent-exempt and persists indefinitely.
The deposit is fully refundable — closing an account returns the lamports. This is a genuinely good design: storage is a refundable deposit rather than a permanent cost, which creates an incentive to clean up that Ethereum lacks. Getting space wrong is a common bug: too small and writes fail, too large and you lock up SOL unnecessarily.
Fees and compute
Solana meters compute units rather than charging per operation like gas, and the base fee doesn't scale with computation. Priority fees exist for local fee markets — congestion on one hot account doesn't raise fees network-wide, which is a meaningful improvement over a global fee market.
Proof of History and consensus
Proof of History is a verifiable delay function producing a cryptographic timestamp sequence — a clock validators agree on without communicating. It isn't a consensus mechanism; it's an ordering primitive that lets Tower BFT (the actual proof-of-stake consensus) skip much of the messaging normally needed to agree on time. This is what enables ~400 ms slots.
Solana vs. Ethereum
The honest summary: Solana optimizes for throughput and cost at the price of validator decentralization and a history of liveness failures. Ethereum optimizes for the ability of ordinary hardware to validate, and pushes throughput to rollups. Both are defensible positions, and which matters depends entirely on the application — a consumer app with high transaction volume and a DeFi protocol securing billions have genuinely different requirements.
For a developer, the practical consideration is that EVM skills transfer to dozens of chains, while Solana skills transfer to Solana. That's an argument for learning EVM first and Solana when you have a reason.
Building on Solana
The toolchain
Anchor is close to mandatory for new work. Raw Solana programs require manual account deserialization and manual validation of every ownership and signer condition — precisely the checks that, when omitted, cause exploits.
Client interaction
Commitment levels
Use confirmed for UI responsiveness and finalized before doing anything irreversible off-chain. Displaying processed as success will occasionally show users a transaction that then disappears.
Best Practices
Use Anchor, and use its constraints
has_one, seeds, bump, constraint, and the typed Account<'info, T> wrapper are your access control. Every check you move from imperative code into the #[derive(Accounts)] struct is a check that runs before your logic and can't be forgotten in a new code path.
Validate account ownership explicitly when not using Anchor
The most common Solana exploit class is a missing owner or signer check — a program that reads an account the caller supplied without verifying it's the account it expects. Anchor does this for you; raw programs must do it themselves, on every account, every time.
Derive PDAs with canonical bumps and store them
find_program_address returns the canonical bump. Store it in the account and use bump = stored.bump on subsequent instructions rather than re-deriving, which saves compute and prevents a class of bump-seed attacks where a non-canonical bump yields a different valid PDA.
Size accounts correctly and close them when done
Use InitSpace to compute size rather than counting bytes by hand. Close accounts you no longer need — close = recipient returns the rent deposit, which users notice and appreciate.
Use checked arithmetic
Rust in release mode wraps on overflow rather than panicking. Use checked_add, checked_sub, and checked_mul with explicit errors, or enable overflow-checks = true in the release profile. Silent wraparound in a financial program is exactly as bad as it sounds.
Keep instructions within the compute budget
The default is 200,000 CU. Request more explicitly when needed (up to 1.4M), and be aware that heavy loops, large deserializations, and many cross-program invocations consume it quickly. Profile with solana logs before assuming an instruction fits.
Have a plan for the upgrade authority
Programs are upgradeable by default and the upgrade authority can replace the code entirely. Put it behind a multisig (Squads) for anything holding value, and either publish a timelock or document the intent to eventually set it to None — which makes the program immutable and is the closest analogue to an EVM deployment.
Handle transaction size limits
A transaction is capped at 1,232 bytes, which constrains how many accounts you can reference. Address Lookup Tables (versioned transactions) compress account references and are how complex DeFi routes fit at all.
Common Mistakes
Missing a signer or owner check
Unchecked arithmetic
Getting account space wrong
Using processed commitment for anything that matters
Assuming an account is the type you expect
Leaving the upgrade authority on a hot key
FAQ
Should I learn Solana or EVM first?
EVM, in most cases. Solidity skills apply to Ethereum, every L2, and dozens of other chains, and the ecosystem of tooling, libraries, and audit expertise is far larger. Learn Solana when you have a concrete reason — an application needing very high throughput and sub-cent fees, or a project already in that ecosystem. Knowing both is genuinely valuable, since the account model teaches a different way to think about on-chain state.
Is Rust required?
For writing programs, effectively yes — Anchor and the whole ecosystem are Rust, and the alternatives (C, Zig via the SBF target) have little support. For frontend and client work, no: TypeScript with @solana/web3.js and the Anchor client covers it, and that's where most application development happens. See Rust.
How bad are the outages?
Solana has had multiple full network halts, mostly in 2021–2022, generally caused by resource exhaustion from bot-driven transaction floods, and each required a coordinated validator restart. Stability has improved substantially with fee market changes, QUIC transport, and stake-weighted quality of service, and there have been long stretches without incident. It remains a real difference from Ethereum, which has never halted, and it's a legitimate factor when deciding what to build where.
Why is it so much cheaper than Ethereum?
Higher throughput from parallel execution, plus a fee model that isn't a global auction for scarce block space. The cost is on validators: running one requires fast NVMe storage, many cores, and substantial bandwidth, which limits how many independent operators participate. That is precisely the tradeoff Ethereum declines to make at L1 and pushes to rollups instead.
What are Address Lookup Tables?
A way to reference accounts by a one-byte index into an on-chain table instead of a full 32-byte public key, introduced with versioned transactions. Since transactions are capped at 1,232 bytes, complex operations touching many accounts — a multi-hop DEX route, for instance — simply don't fit without them.
How do tokens work compared to ERC-20?
Very differently. There is no per-token contract: one SPL Token Program handles all tokens, each token has a mint account defining supply and decimals, and each holder has a separate token account per mint (usually an Associated Token Account derived from the owner and mint). This means transfers touch three accounts rather than one contract's mapping — and it means every token behaves identically, which eliminates the non-standard-ERC20 problems that plague EVM development.
Related Topics
- Blockchain Fundamentals — Consensus, finality, and the trilemma
- Ethereum & the EVM — The architecture Solana is contrasted against
- Solidity — The EVM contract model, for comparison
- Smart Contract Security — Vulnerability classes that apply here too
- Rust — The language of Solana programs
- Web3 Frontends — Client patterns, largely transferable
- Layer 2 Scaling — Ethereum's alternative answer to throughput