Part Revision: The Runtime You Built
You started this part with an empty Rust crate and a single hard question — the same one that drives the whole book: how do you build one global state machine that runs at hardware speed without falling apart? You now have an answer you can compile. solmini is a working runtime whose parallel output is byte-for-byte identical to its sequential output, and every line of it exists because one earlier line forced it into being.
This page does not add code. It retells the build as a single chain of consequences, so the pieces stop feeling like five separate modules and start feeling like one machine. Then it does the honest bookkeeping: what we simplified, what real Solana adds on top, and how the toy programs you wrote map onto real Anchor. If you want to reread a step, each section links back to the page that built it.
The build order was a chain of forced moves
Section titled “The build order was a chain of forced moves”Look back at the overview and you will see we never chose features from a menu. Each component was the only move left once the previous one landed. Here is the whole chain in one breath:
run at hardware speed │ (one CPU runs one tx at a time — a hard ceiling) ▼ use every core → run transactions in PARALLEL │ (but two txs on two cores must not touch the same state) ▼ footprints must be known BEFORE execution │ (the code can't tell you; it's what you're trying to run) ▼ state must live in NAMED EXTERNAL ACCOUNTS, programs STATELESS │ (so a transaction can point at exactly what it touches) ▼ a SCHEDULER can now batch non-conflicting transactions │ (and it needs a global order that survives no network vote) ▼ PROOF OF HISTORY — a clock that is a proof of elapsed work │ ▼ RUNTIME: run batches in parallel, commit on success, roll back on failure │ (checked against a sequential baseline that must match exactly) ▼ one global state machine, at hardware speed, that does not fall apartRead top to bottom, that is the argument of the entire part. Let me walk each link, because the dependencies are the lesson.
The throughput problem is the seed
Section titled “The throughput problem is the seed”The Throughput Problem built no code on purpose. It established the ceiling: a chain that executes one transaction at a time is bounded by a single core, and no amount of faster hardware per core escapes that — you have to use more cores at once. That is the pressure that makes everything after it necessary. If you were content with serialized execution, you could stop reading; the account model, the scheduler, and even Proof of History would all be over-engineering. Every later component is a defense of one goal: keep all the cores busy without ever letting two of them corrupt the same state.
Proof of History gives a verifiable order
Section titled “Proof of History gives a verifiable order”Proof of History built the poh module — Poh, Entry, and verify — from a single idea: feed a hash back into itself, h = sha256(h), and the number of iterations becomes a count of real elapsed work. You cannot skip ahead, because SHA-256 is pre-image resistant; you cannot fake a future state without doing every hash in between. To stamp an event into time, you mix it in — one hash of sha256(state || event) — and every later hash now depends on it, so its position in the chain is sealed.
The asymmetry is the whole trick, and it is exactly the shape the throughput problem demanded: the chain is sequential to build (a clock ticking once per hash) but embarrassingly parallel to verify (each Entry pins its own ending hash, so a verifier hands segment i..i+1 to a different core). A global order that no one had to vote on, and that anyone can check on all their cores at once. This is Bitcoin’s hash chain from earlier in the book, repurposed: there it made history expensive to rewrite; here it makes ordering provable without messages.
Accounts make footprints declarable
Section titled “Accounts make footprints declarable”Accounts and Stateless Programs built account and program, and this is the structural pivot of the part. The scheduler needs to know a transaction’s footprint before running it — but the footprint can’t come from the code, because the code is the thing being run. So state has to move out of the code. That is the entire justification for the account model:
Ethereum Solana / solmini ──────── ───────────────── contract = code + its storage program = code only (stateless) account = data + lamports (owned by a program)A Program in solmini is a zero-sized unit struct — it holds no state at all — with one method:
fn process(&self, accounts: &mut [Account], data: &[u8]) -> Result<()>All mutable state lives in Accounts (a balance, a data buffer, an owner) that a transaction names through its accounts list. Because state is external and named, a transaction can honestly declare “I will read A and write B” up front — the one thing an Ethereum contract, with its state hidden inside it, cannot cleanly do. The accounts-vs-storage split you met earlier in the book (accounts vs UTXO, where does state live?) reappears here as the precondition for parallelism.
The scheduler exploits the declared footprints
Section titled “The scheduler exploits the declared footprints”The Account-Locks Scheduler built schedule and conflicts. Now that every transaction declares its footprint, the runtime can finally use those declarations. The conflict rule is one line of intent: two transactions conflict when they share an account and at least one writes it. Read–read on the same account is not a conflict, which is what lets many transactions read shared config in the same batch.
txs (submission order): t0 t1 t2 t3 t4 accounts they write: A B A C B
batch 0 (parallel): t0[A] t1[B] t3[C] ← all disjoint, run together batch 1 (parallel): t2[A] t4[B] ← each waited on an earlier writerschedule layers each transaction into the earliest batch strictly after every earlier transaction it conflicts with — batch(i) = 1 + max{ batch(j) : j < i and conflicts(i, j) }. That single rule buys two guarantees at once: within a batch nothing conflicts (a conflicting pair would have been split across batches), and conflicting transactions keep submission order (a later writer always lands in a strictly later batch, so it observes the earlier writes). The declared footprint from the previous page is the raw material; the scheduler is what turns it into safe parallelism.
The runtime executes it safely
Section titled “The runtime executes it safely”Assembling the Runtime built the Runtime — the account database, the program registry, and both execution paths. Each transaction runs against a private clone of its accounts (its working_set); rayon hands each element of a conflict-free batch a disjoint &mut, and because the batch is conflict-free, no two threads can ever reach the same writable account. Writes are committed back to the database only if the transaction succeeded, so a failed transaction rolls back for free — its clone is simply discarded. That is why the overdraft test leaves both balances untouched.
And crucially, the runtime keeps run_sequential — the obvious, one-at-a-time baseline — alongside run_parallel. The integration tests run both and assert the final account state is identical. The parallel path is only trustworthy because a dumber, correct path exists to disagree with it. That is the “without falling apart” half of the book’s question made mechanical: speed you can’t verify against a baseline is speed you can’t trust.
The one idea underneath everything: shared XOR mutable
Section titled “The one idea underneath everything: shared XOR mutable”If you keep only one sentence from this part, keep this one: shared XOR mutable, lifted from Rust variables to accounts. In ordinary Rust, the borrow checker enforces a rule on references — you may have any number of shared reads or exactly one exclusive write, never both at once. solmini takes that exact rule and applies it to on-chain state: any number of transactions may read an account at once, but a write to an account must have it exclusively.
What makes this the spine of the part is that the same rule is enforced at two different levels working together:
- At the scheduler level,
conflictsis shared-XOR-mutable stated over accounts: a shared read is fine, but a write demands exclusivity, so a conflicting pair is pushed into separate batches. This is the rule chosen by the runtime designer. - At the type-system level, once a batch is conflict-free, rayon’s
par_iter_mutgives each transaction a disjoint&mut [Account], and theProgram: Send + Syncbound lets the immutable program code be shared across threads. The compiler now proves no two threads alias a writable account. The data race that “run these on threads” would invite in C is unrepresentable.
Rust variables solmini accounts ────────────── ──────────────── &T (many readers) ─► readonly AccountMeta, many per batch &mut T (one writer) ─► writable AccountMeta, exclusive per batch borrow checker ─► scheduler (conflicts) + rayon's &mut + Send/SyncThis is what “fearless parallelism at scale” actually means: the scheduler decides what is safe to run together, and the type system proves the decision was honored. Neither alone is enough — a correct scheduler with an unsafe execution engine could still race, and a safe engine with no scheduler could only ever run one transaction at a time. Together they are the whole answer to running at hardware speed without falling apart.
What we simplified, and what real Solana adds
Section titled “What we simplified, and what real Solana adds”solmini is deliberately the smallest thing that is still correct. Every simplification was called out as we went; here they are in one place, next to what a real validator does instead. Knowing exactly where the map ends is what lets you trust the parts inside it.
| We built | We simplified | Real Solana adds |
|---|---|---|
Pubkey::from_seed("alice") | keys are SHA-256 of a label | ed25519 keypairs, and per-transaction signature verification |
Poh hash chain | a plain iterated sha256 | the same chain, but studied as a VDF-like construction, plus ticks driving slots and leaders |
schedule conflict scan | an O(n²) all-pairs scan | per-account read/write locks (the same idea, without the quadratic cost) |
one in-memory HashMap DB | one process, no network | gossip, Turbine block propagation, and an accounts DB on disk |
| a single validator | no consensus | Tower BFT voting to agree which chain is canonical |
compute_per_tx knob | a hash-burning stand-in for CPU cost | real compute-unit metering, fees, and rent |
Two of these deserve a second look, because they are where beginners most often over-claim what the toy proves.
PoH is a clock, not a consensus. We built the ordering (a verifiable proof that events happened in a sequence) but not the voting that turns one node’s clock into a whole network’s agreement. solmini is a single validator that never disagrees with itself, so it needs the clock but not the vote. Real Solana pairs PoH with Tower BFT: PoH says when, consensus says which chain is real. Our hash chain is also honestly a hash chain, not a true VDF — a real verifiable delay function is designed so that verification is asymptotically cheaper than production, whereas our verify does the same number of hashes the producer did. We keep it linear for clarity and lean on the per-Entry checkpoints for the parallel-verification story.
The scheduler’s O(n²) scan is the honest version of per-account locks. Our conflicts compares every pair of transactions, which is fine for a demo batch and catastrophic for tens of thousands of transactions a slot. Real Solana never builds the all-pairs comparison; it takes read/write locks on each account and lets a transaction proceed the moment its accounts are free. But the decision those locks encode — shared reads coexist, a write is exclusive — is exactly the layering rule you built. The data structure is different; the invariant is identical.
Under the hood — from solmini programs to real Anchor
Section titled “Under the hood — from solmini programs to real Anchor”The process signature you wrote is not a toy shape that Anchor discards — it is the shape Anchor generates code around. When you write your first real on-chain program, the mapping is one-to-one:
solmini real Anchor ─────── ─────────── fn process(accounts, data) ─► your #[program] module's instruction handler &mut [Account] ─► the Context<'_>'s #[derive(Accounts)] struct Account.data buffer ─► an #[account] struct, (de)serialized for you Account.owner ─► the program id that owns the account AccountMeta { is_writable } ─► #[account(mut)] vs a read-only account declared accounts list ─► the accounts you pass in the instructionCounterState { count: u64 }, which solmini hand-serializes into a data buffer with serde_json, is precisely an Anchor #[account] struct — Anchor just generates the (de)serialization glue with Borsh instead. TransferProgram is the System program’s transfer. And the discipline that felt like extra ceremony in solmini — you must list every account a transaction touches, and mark which are writable — is not ceremony at all. It is the single constraint the whole runtime is built on, and Anchor makes you honor it because Solana’s scheduler depends on it exactly the way yours does. You did not learn a simplified model that you now have to unlearn; you learned the real model with the networking and cryptography peeled away.
Closing the loop
Section titled “Closing the loop”Return to the question the book keeps asking: how do you build one global state machine that runs at hardware speed without falling apart? You can now answer it as a chain, not a slogan.
One global state machine is the account database — one named, external store of state that every program reads and writes. At hardware speed is the scheduler plus rayon: declared footprints let non-conflicting transactions fill every core, and the sequential path proves the fast path didn’t cheat. Without falling apart is shared-XOR-mutable enforced twice over — the scheduler chooses safe batches, the type system proves it, and clone-then-commit gives rollback for free. And a global order everyone agrees on without stopping to vote is Proof of History, the verifiable clock stitched from Bitcoin’s own hash-chain idea.
Each earlier part set up a piece of this. Bitcoin’s hash chain became the clock. The accounts-vs-UTXO question — where does state live? — became the reason programs are stateless and accounts are external. Rust’s borrow checker, which you learned to fear and then trust, became the mechanism that makes parallel execution unable to race. This part is where those threads braid into one runtime you can read end to end.
solmini is small, but it is not a cartoon. Strip a real validator of its network, its consensus, and its cryptography, and what remains is exactly this: an ordered clock, external state, and safe parallelism. Those three are the architectural core Solana bet its throughput on — and you built them.
Check your understanding
Section titled “Check your understanding”- Retrace the build order as a chain of forced moves: starting from “run at hardware speed,” name each consequence in order and the component it forced into existence.
- State the “shared XOR mutable” idea, and name the two levels at which
solminienforces it. Why is neither level sufficient on its own? solminibuilds Proof of History but has “no consensus.” What is the difference between the clock and the vote, and why can a single-validator toy get away with only the clock?- Give three honest simplifications
solminimakes and, for each, what real Solana does instead. For the scheduler specifically, why is theO(n²)scan the same idea as per-account locks? - Map the
solminiprocesssignature onto a real Anchor program: what do&mut [Account], thedatabuffer, and a writableAccountMetaeach become?
Show answers
- run at hardware speed → use every core → run transactions in parallel; parallel execution forces footprints known in advance → the account model (state in named external accounts, stateless programs) so a transaction can declare what it touches; declared footprints enable the scheduler (batch non-conflicting transactions); the need for a global order without a network vote forces Proof of History; and the whole thing is assembled into the runtime that runs batches in parallel, commits on success, and rolls back on failure — checked against a sequential baseline.
- Shared XOR mutable: any number of transactions may read an account at once, but a write must have it exclusively (Rust’s borrow rule lifted from variables to accounts). Level one is the scheduler —
conflictssplits a writer from anything else touching that account, so batches are conflict-free. Level two is the type system — rayon’spar_iter_muthands out disjoint&mut [Account]andProgram: Send + Syncshares the immutable code, so the compiler proves no two threads alias a writable account. Neither alone suffices: a correct scheduler with an unsafe engine could still race, and a safe engine with no scheduler could only run one transaction at a time. - The clock (PoH) is a verifiable proof that events happened in a particular order and that real work elapsed between them. The vote (Tower BFT) is how a whole network agrees on which chain is canonical when nodes might disagree.
solminiis a single process that never disagrees with itself, so it needs an ordering but never needs to reconcile competing views — hence the clock without the vote. - Examples: keys are SHA-256 of a label vs real ed25519 keypairs with signature verification; one in-memory
HashMapand no network vs gossip, block propagation, and an on-disk accounts DB; no consensus vs Tower BFT; the hash chain vs a true VDF; thecompute_per_txknob vs real compute metering, fees, and rent. The scheduler’sO(n²)scan is the same idea as per-account locks because both encode one invariant — shared reads coexist, a write is exclusive; real Solana just takes locks on each account instead of comparing every pair, avoiding the quadratic cost while enforcing the identical rule. &mut [Account]becomes theContext’s#[derive(Accounts)]struct; theAccount.databuffer becomes an#[account]struct that Anchor (de)serializes for you (Borsh rather thansolmini’sserde_json); a writableAccountMetabecomes an#[account(mut)]account. Theprocessfunction itself is your#[program]module’s instruction handler, and the declared accounts list is the accounts you pass in the instruction.