A protocol engineer’s analysis of state representation, parallel execution, and the tradeoffs that don’t make it into the pitch deck.
The account-vs-UTXO debate is usually framed as developer ergonomics: mutable objects and method calls versus functional purity and immutable outputs. That framing buries the lede. The state model is the concurrency model. It determines how the runtime schedules execution, where contention surfaces, which classes of bug are reachable versus merely avoidable, and how lean a node’s working set stays after years of operation. Parallelism, MEV surface, L2 sequencer complexity, and state growth are all downstream of this one decision.
What follows is an analysis from the runtime’s perspective — including the points where the UTXO model’s advantages stop being free.
An account-model chain maintains a single authenticated key-value store. On Ethereum that’s a Merkle-Patricia Trie keyed by keccak256(address), with each leaf holding (nonce, balance, storageRoot, codeHash). Contract storage is a second trie nested under storageRoot, keyed by keccak256(slot).
Execution is read-modify-write against this structure. The EVM resolves a SLOAD, mutates registers, and commits via SSTORE. Two properties fall out of this and drive everything later:
A UTXO ledger has no accounts, no balances, and no in-place mutation. State is exactly the set of Unspent Transaction Outputs. A transaction is a pure transition: it names a set of existing outputs to consume and defines a set of new outputs to create.
tx : {UTXO_in} → {UTXO_out} where every UTXO_in is removed from the set
and every UTXO_out is appended exactly once
Each output carries a globally unique identifier id = H(txid ‖ output_index) and can be consumed at most once. The lineage of consumptions and creations forms a DAG. There is no "balance to update," only prior state destroyed and new state minted. This is the same invariant Rust enforces at compile time — single ownership, single consumption, no shared mutable state — lifted to the ledger.
The practical consequence is that a transaction must name its exact inputs by hash before broadcast. That requirement is the source of nearly every other property in this article — good and bad.
This is the most misunderstood part of the comparison, so be precise about it: parallel execution requires knowing the read/write set before you run the transaction. The account model and the UTXO model differ in when and how that set becomes known — not in some inherent capacity for concurrency.
The EVM cannot know a transaction’s footprint a priori, so parallel EVM runtimes use Optimistic Concurrency Control. Block-STM (Aptos, and the approach several parallel-EVM efforts adopt) speculatively executes transactions in parallel, records read/write sets, and validates after the fact. On a detected conflict — two transactions writing the same DEX reserve slot — it aborts the dependent transaction and re-executes. Under low contention this is close to linear speedup. Under a hot slot (a popular pool, an NFT mint) it degrades toward sequential plus the wasted cost of aborted attempts and re-validation passes. The contention didn’t disappear; it moved into CPU thrash.
It’s worth killing a common oversimplification: account models are not intrinsically un-parallelizable. Solana’s Sealevel parallelizes by requiring every transaction to declare its account access list (read-only vs. writable) up front; the scheduler then runs transactions with disjoint writable sets concurrently, no speculation needed. Sui does the same with its object model — transactions touching only owned objects skip consensus ordering entirely and parallelize trivially, while shared objects fall back to sequenced execution. Both are account/object models that bought parallelism by adopting the UTXO discipline of declaring your footprint. The lesson generalizes: the win was never “UTXO,” it was “declare your state access.”
In a UTXO chain that declaration is mandatory and unforgeable — the inputs are the footprint. Two transactions conflict iff their input sets intersect, which is a set-membership check against consumed-output hashes (amortized O(1) per input via a hash set; scheduling N transactions is O(total inputs)). Disjoint input sets are conflict-free by construction, with no speculation and no rollback path to maintain. The scheduler gets a hard guarantee instead of a hopeful one.
That’s the genuine, defensible advantage: deterministic conflict detection with zero abort machinery. Keep it in mind for the next section, where the same mechanism becomes a liability.
A bare UTXO pairs a value with a spending predicate (typically a signature check). It has no persistent memory and can’t enforce invariants across transactions. The Extended UTXO (eUTXO) model — formalized in the IOG/Cardano research line and used in spirit by object/UTXO hybrids like Fuel — adds programmable, local state to each output via three components:
Spending an output runs the validator over its local context:
validate(Datum, Redeemer, ScriptContext) → Bool
ScriptContext exposes the whole transaction — all inputs, all outputs, validity interval, signatories — so the script can constrain what the resulting transaction must look like. There is no global state read.
In the account model, an AMM pool’s reserves (x, y) live in shared storage slots that every swap mutates in place. In eUTXO, the entire pool is one UTXO whose datum holds (x, y). A swap:
The old pool UTXO is destroyed and a new one with the updated datum is minted, atomically. Multi-step protocols are built by threading the datum through a chain of consume/create steps — state machines on a graph, never a global trie lookup. Note the inversion: the validator verifies a state transition the caller already computed; it doesn’t produce one.
This is the section the optimistic version of this article leaves out, and it’s the one that matters most if you’re choosing an architecture to ship on.
Re-read the AMM example with the scheduler from §2 in mind. The entire pool is a single UTXO. A UTXO can be consumed exactly once. Therefore only one swap against that pool can land per block. Every other swap in the mempool named the same input; the moment one of them is included, the rest reference an output that no longer exists and are invalid by construction.
The property that made disjoint transactions trivially parallel makes contended transactions strictly serial — and worse than the EVM here, because there’s no “queue behind the current state” semantics, just instant invalidation. On a popular pool this is a throughput cliff, not a gentle degradation. This is not theoretical: it’s exactly why production Cardano DEXs (Minswap, SundaeSwap, and others) run batcher / off-chain aggregation layers. Users submit orders as their own UTXOs; a batcher collects them and folds them into the pool UTXO sequentially, one fold per block. You get back throughput, but you’ve reintroduced a privileged off-chain actor that orders and includes flow — which is precisely an MEV role (see §6).
The architectural escape hatches, and their costs:
The honest framing: eUTXO gives you free parallelism on uncontended state and a hard serialization wall on contended state. The account/STM model gives you speculative parallelism that degrades continuously under contention. Neither is strictly better; they fail differently, and you should pick the failure mode that matches your workload’s contention profile.
This is eUTXO’s cleanest and most underrated win, and it survives the §4 critique intact.
In the account model, a transaction is evaluated at execution time. The user signs against state S; the world mutates S → S' while the transaction sits in the mempool; the transaction executes against S', fails its slippage check, reverts — and the user still pays gas for the cycles burned reaching the revert.
eUTXO transactions are evaluated at construction time. Inputs, outputs, and the resulting datum are fully specified before broadcast, so the on-chain client is a verifier, not a compute engine. It checks two things: do the named inputs still exist in the unspent set, and does each validator return True. If your targeted pool UTXO was consumed by someone else first, your transaction doesn't revert — it's structurally invalid and is dropped at the validation gate, before any script runs. You don't pay for failed computation. (Cardano's two-phase model is the practical embodiment: phase-1 checks structure/balance for free; phase-2 runs scripts, and only a phase-2 script failure forfeits posted collateral.)
For rollups this is a real simplification, not a slogan. An EVM sequencer must execute the full state transition to compute the post-state root before it can commit a block. A UTXO-based sequencer’s core job reduces to verifying input disjointness and signatures/scripts — the expensive transition computation was already done by the client that built the transaction. The heavy compute is pushed to the edge, and the L1→L2 derivation pipeline gets leaner and easier to make deterministic and fault-provable. The flip side is that wallet/client tooling must now do real work (UTXO selection, datum construction, fee balancing), which is where the eUTXO developer-experience complaints legitimately come from.
Reentrancy exists in the account model because a contract can make an external call before committing its own state update, leaving a stale intermediate state for the callee to exploit. The defense is disciplined sequencing (checks-effects-interactions) and reentrancy guards — i.e., a coding practice you can forget.
In eUTXO there is no intermediate state to re-enter. State transition is atomic destruction-and-creation: the instant a transaction is validated, its input UTXO is consumed and gone; the updated UTXO does not exist until the transaction’s outputs are appended at the end. There is no point in the lifecycle where a contract holds a half-updated balance on the ledger that another execution context could observe and exploit. The vulnerability class isn’t mitigated — it’s structurally unrepresentable.
The account model serializes an account’s transactions with an incrementing nonce, which couples otherwise-independent transactions: a stuck tx at nonce 5 blocks nonce 6. eUTXO needs no nonces — each output’s unique id = H(txid ‖ index) is consumed exactly once, so a rebroadcast fails because its inputs are gone. A wallet can fan out hundreds of independent transactions over disjoint UTXOs in parallel with no sequence head-of-line blocking. (The cost: you must manage a UTXO set and avoid accidentally double-spending your own outputs across concurrent transactions — a real client-side concern for high-frequency systems.)
This is where the original needs correcting. MEV is extractable value from ordering and inclusion, and eUTXO has both. Whoever lands their transaction first against a contended UTXO (a pool, an oracle, an auction) wins; everyone else is invalidated. Block producers still choose ordering. And as §4 showed, the standard eUTXO scaling pattern introduces batchers/solvers who explicitly order user flow — a textbook MEV-extraction position. eUTXO changes the shape of MEV (front-running becomes “your input got consumed first” rather than “your trade executed at a worse price”) and removes the specific failure of paying gas for a doomed revert, but it does not remove the economic incentive or the producer’s ordering power. Claiming otherwise is the kind of thing a reviewer who’s run a Cardano batcher will catch immediately.
EVM state monotonically inflates: dead contracts, abandoned tokens, and dust persist in the active trie because the structure is interconnected and reachability is hard to reason about. State-expiry proposals have stalled for years for exactly this reason, and node operators eat the cost in RAM and NVMe provisioning.
The UTXO model prunes by construction. The active validation state is only the unspent set; a consumed output is removed and never consulted again to validate future transactions. The working set stays lean without a state-rent mechanism. Two caveats keep this honest: (1) the UTXO set itself can still grow if outputs are created faster than consumed — which is why Cardano enforces a min-ADA-per-UTXO to price storage and discourage dust, and (2) pruning the active set doesn’t eliminate the historical chain data a new node must process to sync. The advantage is real but it’s about working-set size, not total data.
Reduce it to contention profile and execution semantics, not ideology:
The account model optimized for the developer’s mental model first. The UTXO model optimizes for the runtime’s guarantees first and pushes complexity to the client. As throughput and determinism requirements rise, that trade keeps looking better — provided you go in knowing exactly where the serialization wall is, rather than discovering it in production.
Follow me on X.
The Memory Model Is the Architecture: Account vs. eUTXO was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.


