Write Lock Contention — Solana's Serialization Curse

The Promise That Sold Me on Solana

When I start building a Solana MEV bot, that is the mental model I carry in: thousands of smart contracts running in parallel, a leader rotating every few hundred milliseconds, transactions settled cheaply enough that a personal developer can actually compete. The official Sealevel writeup leans into exactly that pitch. It contrasts itself with the older single-threaded designs and notes that "EVM and EOS's WASM-based runtimes are all single threaded. That means that one contract at a time modifies the blockchain state," per Solana's Sealevel announcement. The implied promise is the opposite — many contracts, many accounts, all at once.

It takes about a week of running real bots against real pools for that mental model to start cracking. The accounts I actually want to touch — the popular AMM pools, the hot mints, the oracle feeds — turn out to behave less like multilane highways and more like a single checkout line. Not because Solana is broken, but because the very property that makes Sealevel safe also forces serialization the moment two transactions reach for the same writable account. That is write lock contention, and it shapes almost everything about how a small MEV operator like me thinks about strategy, latency, and fees.

What Write Lock Contention Actually Is

Solana's execution model is built on a simple bargain: every transaction must declare, up front, the exact list of accounts it intends to read and write. This is borrowed in spirit from Linux's readv and writev system calls. With that declaration, the runtime can look across a queue of pending transactions and decide which ones touch disjoint state and can run together, versus which ones overlap and must be ordered.

The rule the scheduler applies is deceptively short. A leading infrastructure provider's lifecycle comparison summarizes it cleanly: "Transactions accessing read-only accounts are executed in parallel," while "transactions accessing overlapping writable accounts are serialized and executed sequentially," per its lifecycle comparison with Sui. Read-only on the same account is fine — many transactions can fan out across cores at once. But the instant one of them takes a write lock, every other transaction touching that account, in any mode, has to wait its turn.

This is where the metaphor I prefer comes in. Imagine an interstate with eight lanes wide open in front of me. I look at the on-ramp and feel great about my throughput. Then I check my GPS, and the lane I actually need — the one that touches a popular AMM pool — is a single-file line at a congested service counter. The other seven lanes are real, and they help other people, but they cannot help me, because my transaction has a write on the same account as a thousand other people's transactions.

A developer-facing guide on contention puts it even more bluntly: when one hundred concurrent transactions target the same writable account, the protocol behaves as a "single-threaded queue," with the same source measuring a real DEX AMM account at about an 89% contention level under that load, per HackerNoon's developer guide on write lock contention. That number sticks with me. The accounts that matter most — the ones with real volume — are exactly the ones where parallelism collapses.

How Bad Is It on Mainnet, Really

For a while I assume contention is a theoretical concern that smart engineering has mostly solved. Then I read the empirical analysis on arXiv of transaction conflicts in Ethereum and Solana for parallel execution, published in May 2025, and I have to recalibrate.

The paper takes one thousand non-empty blocks from a recent slice of Solana mainnet and just measures what is actually happening. Per block, the average is around 1,249 transactions, of which about 334 are non-vote. Of those non-vote transactions, only 23 — roughly 6.9% — are fully independent of every other transaction in the block. The other 310, about 92.8%, conflict with at least one neighbor. When the authors zoom out across a longer window of recent blocks, they find average independence has settled near 4%, and they observe that "write-write conflicts compris[e] most contention (~76%)," with per-block write-write conflict counts ranging from 212 all the way up to 17,071.

Compared with Ethereum, the picture is sharper. In the same study, a recent Ethereum block has about 50.6% independent transactions and a longest conflict chain that reaches roughly 18.2% of block size. The Solana block has only about 8.2% independent transactions, with a longest conflict chain that reaches 31% of the block. The authors note that "Solana's design, optimized for high throughput, results in longer chains of conflicts...compared to Ethereum, indicating deeper interdependencies between transactions."

I find that result almost paradoxical at first. The chain marketed on raw parallelism shows deeper interdependence in practice than the chain marketed on sequential clarity. The resolution, once I sit with it, is straightforward. Ethereum's higher fees price out a lot of marginal activity, so each transaction is more independent on average. Solana's near-free fees invite a much denser swarm of bots and retail interaction, and that swarm overwhelmingly converges on the same handful of hot accounts.

Why Throughput Numbers Are Misleading

I used to quote the headline TPS figures without really thinking about what they imply. The theoretical maximum that gets cited is around 65,000 transactions per second; the realized throughput is somewhere in the range of four to five thousand, per a leading infrastructure provider's comparison with Sui. The gap between those two numbers is the gap between a world without contention and the actual world I am trading in.

That same comparison spells out the underlying cause without flinching: "Solana, by virtue of its single-leader approach and execution fanout which is limited by account contention, does appear to hit some sort of horizontal scaling threshold due to the global single-sharded state model and its leader-centric transaction ingestion per slot." In plain language: the chain has one leader per slot ingesting everything, one global state with no sharding, and execution that fans out only as far as the account graph permits. When the account graph collapses to one account, fanout collapses to one core.

This is why I have stopped treating the headline TPS as anything other than a marketing artifact. The number that matters for any specific strategy is the throughput on the specific writable accounts that strategy touches. For a long-tail SPL transfer between cold wallets, that throughput is basically the network's ceiling. For a swap on the most-traded pool of the day, the throughput is one transaction at a time, dressed up in whatever fee priority the scheduler decides to honor.

The Old Scheduler and Why So Many Transactions Failed

Early on, I make the mistake of pattern-matching contention to gas wars on Ethereum. You raise priority, you win. That intuition does not survive a careful read of how the pre-1.18 banking stage actually works.

A detailed Medium writeup on Solana's transaction scheduler walks through the old design. There were four independent banking threads, each pulling from a priority queue and each trying to take locks on the accounts its candidate transactions need. When the network is calm, that arrangement is fine. When the network is hot — an NFT mint, a viral memecoin, a popular pool getting arbed — the top of every thread's queue fills up with the same high-priority conflicting transactions. The author describes the resulting failure mode crisply: "The top of the queue is often filled with conflicting transactions. Given the entry constraints, this means each thread would attempt to lock 128 conflicting transactions, but fail to lock 127 of them. This resulted in massive inefficiency as the majority of transactions would be skipped over to be retried later."

That is a remarkable image. Each of the four threads tries 128 transactions, wins exactly one of them, and tosses the other 127 back into the queue. Multiply that by every slot during a contention storm and you get the now-familiar reality of transactions sitting in flight for many seconds, eventually expiring, while the user watches the spinner. A leading infrastructure provider's local fee markets analysis puts a concrete number on a contention peak: in April 2024, roughly 75.7% of non-vote transactions reverted, and by December 2024 the revert rate was still about 41.2%. Those are not edge cases. Those are the conditions under which a lot of the protocol's life actually happens.

The Central Scheduler and What v1.18 Actually Fixes

The v1.18 release replaces the four independent banking threads with a single central scheduling thread that owns the priority view across the whole node. The mechanism that does the heavy lifting is a structure called the prio-graph: a lazily-built directed acyclic graph that, as transactions are pushed into it, records read/write dependencies on every account they touch. Conflicting transactions get pulled out of that DAG in time-priority order and assigned to the same worker thread, so the lock takes a single ordered path through the runtime instead of fanning out across four threads and clashing.

A leading infrastructure provider's writeup on the v1.18 update puts it this way: "The prio-graph makes sure that batches prepared for execution are highly likely to succeed without lock conflicts," per the v1.18 explainer. The same source notes that the prior arrangement, in which "four independent threads processing non-vote transactions have their own view of transaction priority within their own threads," inevitably produces "inter-thread locking conflicts and wasted processing time due to unsuccessful lock attempts."

That fix is real, and it matters. What I want to be careful about, though, is what it actually solves. The central scheduler eliminates the worst-case wasted-lock behavior, where 127 out of 128 lock attempts fail. It does not eliminate the underlying truth that two transactions writing to the same account still have to execute sequentially. The serialization is in the runtime semantics, not in the scheduler. The scheduler's job is to avoid wasting CPU cycles trying to do impossible parallelism. The serialization itself is a feature of the chain.

There is a separate observation worth keeping in mind. The same local fee markets analysis quotes Anza engineer Alessandro Decina pointing out that, in 2024, only one of the four non-vote banking threads continued processing past the middle of the block; the other three sat idle. The analysis estimates the network could in principle have processed roughly four times its actual load if those threads had been used. That is a scheduler bug, not a contention problem. It is a useful reminder that some of what I experience as contention on a hot day is actually the scheduler leaving capacity on the floor for unrelated reasons.

The Cost Side: Failed Transactions Burning Blockspace

The most striking single statistic I keep returning to comes from the SIMD-110 proposal on exponential fees for write-locked accounts. The proposal authors write that "almost half of the Compute Units (CUs) in a block are allocated to failed transactions, leading to undesirable scenario where large portion of compute powers primarily serving failed DeFi arbitrage transactions."

For me, sitting on the other side of that statistic as one of the people sending those transactions, it lands awkwardly. The MEV economy on Solana is, in part, an economy of optimistic submission. Bots send transactions that they expect might fail because the cost of trying is so low and the cost of missing a winning opportunity is comparatively high. When you sum that behavior across many bots, you get the blockspace pattern the proposal describes: a substantial fraction of the chain's compute capacity is spent on transactions that never settle anything.

The same fee market analysis breaks the responsibility down by activity tier. Retail users sending one to five transactions per day saw a 1.4% revert rate; moderately active users in the six-to-fifty range saw 4.6%; the highly active tier above ten thousand transactions per day saw 66.7%; and bots above one hundred thousand transactions per day accounted for 95.2% of all reverts. That last number is hard to look away from. The contention problem, in revealed-preference terms, is a bot problem, and I am one of the bots.

Why Write Locks Are Honest About a Hard Problem

There is a particular passage in the bundle locking writeup from Eclipse Labs that I think every Solana developer should sit with. It describes the three conflict patterns the runtime cares about — write/write, write/read, read/write — and then makes the point as plainly as it can be made: "Any presence of a write means you cannot run them in parallel." The runtime is honest. It does not pretend you can squeeze parallelism out of conflicting writes. It tells you, before you submit, that you cannot.

That honesty is what makes Solana's model different from optimistic concurrency designs where transactions speculatively execute in parallel and then abort if they conflict. Sealevel's account-declaration discipline trades flexibility for predictability. You know, before execution, whether a batch can run together or must serialize. The cost is the rigidity I have been complaining about. The benefit is a runtime that does not waste cycles speculating and rolling back.

From a market structure perspective, this design choice is most visible in the way AMMs dominate decentralized trading on the chain. A Sino Global Capital writeup on DEX and AMM dynamics on Solana observes that "most trading volume on the Solana chain is actually facilitated by Automated Market Makers (AMMs) rather than Central Limit Order Books (CLOBs)," and adds that "the dominance of AMMs on Solana is rooted in limitations of blockchain performance." That phrasing is diplomatic. The blunter version is that a CLOB needs to write to far more accounts per matched trade than an AMM does, and write lock contention punishes the architectures that need more writes. AMMs win on Solana not because they are technically superior, but because they fit the contention budget the runtime imposes.

Local Fee Markets, the Theory and the Reality

The official answer to contention, at least at the price-mechanism level, is the local fee market. The idea is intuitive enough: transactions that contend with hot writable accounts should pay more, while transactions that touch cold accounts should pay less. That is exactly the kind of micro-targeting you would not get from an Ethereum-style global base fee, which charges every transaction the same regardless of which storage slots it touches.

A leading infrastructure provider's local fee markets analysis quotes Ben Coverston, co-founder of Temporal, from December 2023: "Local fee markets are a lie." That is provocative, but not nihilistic. The same article walks through the data and shows where the mechanism does work, where it does not, and what the actual fee distributions look like on chain. In November 2024, the analysis reports an average non-vote fee above 0.0003 SOL with a median around 0.00000861 SOL — the average is roughly 35 times the median, which tells you almost everything about how skewed contention-driven fee spending really is. A small minority of transactions targeting a small minority of accounts are paying nearly all the fees.

This is consistent with what I see from my own perch. Most of the time, the chain feels free, the way Solana's marketing suggests. But on the specific accounts I care about during the specific moments I care about, fees spike sharply and predictably, and the cost of competing is not the median fee but the tip of the distribution.

Why SIMD-110 Was Closed

The SIMD-110 proposal would have layered an exponential, EMA-driven surcharge on top of the priority fee for accounts whose utilization exceeded a 25% threshold of the per-account limit. Anatoly Yakovenko summarized the policy lever as "1% per block increase puts the worst case on a tx to 4.4x" over a 150-slot window, and argued that "if txs take too long to get through the pipeline, prioritization is not effective...we need to force sender to stop economically," per SIMD-110.

The proposal was eventually closed without being merged, and the reasons illustrate how genuinely hard the contention problem is to price. Reviewers raised several objections. One asked whether the v1.18 scheduler improvements should be allowed to land first, and the contention costs re-measured against the new baseline. Another worried that legitimate developers — not just spam bots — would be priced out. A third raised the most economically interesting concern: account sybiling. If a developer can rotate canonical state across many addresses to evade the surcharge, the fee just creates a complexity tax on honest builders while the spam continues. A fourth pointed out that the LRU cache structure required to track per-account EMAs would add real cost to leader performance, especially for transactions referencing the maximum number of accounts.

None of those objections are silly. They reflect the reality that the contention problem is not a simple coordination failure where the right fee curve solves it. It is a structural property of single-leader, single-sharded execution, and any price-based fix risks introducing new gameable surface area without removing the underlying scarcity.

What Contention Means for an Individual Bot Operator

For me personally, the practical implications of all this rearrange themselves over the months I keep at this. A few of the lessons stick.

The first is that latency to the leader matters far less in isolation than I initially think. If a hundred bots are racing to lock the same pool account, being a few milliseconds earlier into the priority queue is helpful, but the dominant variable is whether your transaction wins the lock at all. The scheduler, post-v1.18, is making that decision based on a priority score that incorporates fees and compute units. Tip-priority competition through Jito-style bundles is one path; on-chain priority fees are another; neither is a substitute for picking targets where the contention is shallow enough that winning is plausible.

The second is that picking the right account graph is half the engineering problem. The most lucrative pools are often the most contended, and the most contended pools have the lowest probability of landing per attempt. There is real edge in looking for opportunities where the writable account graph is small and the contention is shallow, even if the headline opportunity size is smaller. A consistent win on a less-fashionable pool can outperform a streak of losses on the hottest pool of the week.

The third, and the one I keep relearning, is that the chain's design intends for me to lose most of my races. When 95.2% of all reverts are produced by bots and roughly half of every block's compute is allocated to failed transactions, the equilibrium that produces those numbers is one in which optimistic submission by bots is the dominant strategy and most of those bots lose most of their attempts. The chain is not malfunctioning when my transaction reverts. It is functioning exactly as the contention model says it should. The serialization curse is not a bug; it is the price of the deterministic, composable global state that draws me to Solana in the first place.

What This Means Going Forward

The central scheduler in v1.18 makes the contention story less wasteful, but it does not change the underlying physics. Two transactions writing to the same account still have to wait for each other, and that account is still the choke point of any strategy that touches it. The improvements that would change that physics — sharding, optimistic concurrency, smaller per-account scope — are not on the near-term roadmap, and several of them would compromise the composability that makes the chain attractive to begin with.

What is changing, slowly, is the economic layer around contention. Fee mechanisms keep getting more nuanced. Searchers keep getting better at simulating outcomes before they submit, which trims the volume of pure-noise submissions. Wallet UX keeps getting better at hiding the revert noise from end users. The chain's center of gravity moves toward applications that fit the contention model and away from applications that fight it. CLOBs continue to lose to AMMs not because their developers are less talented but because the runtime keeps quietly punishing the design that needs more writes per match.

For me, the long-term takeaway is that the strategies most likely to age well are the ones that respect the serialization curse rather than try to outrun it. Build for the account graph that exists. Pay attention to where the conflicts actually live. Treat the headline TPS as marketing and the empirical independence rate as truth. Accept that most attempts will lose, price every attempt accordingly, and let the chain be the chain.

Key Takeaways

  • Solana's parallelism is real, but it is bounded by account contention: any write lock forces every other access to that account, in any mode, to serialize.
  • Recent empirical data from arXiv shows roughly 92.8% of non-vote transactions in a typical block conflict with at least one neighbor, with average independence around 4% and write-write conflicts accounting for about 76% of contention.
  • v1.18's central scheduler eliminates the worst wasted-lock behavior of the four-thread design but does not change the fact that conflicting writes must execute sequentially.
  • About half of every block's compute units have been spent on failed transactions, with bots responsible for the overwhelming share of reverts during contention peaks.
  • The strategies that survive on Solana are the ones that respect the serialization curse — picking shallow account graphs, accepting most attempts will lose, and treating headline TPS as marketing rather than reality.

Disclaimer

This article is for informational and educational purposes only and does not constitute financial, investment, legal, or professional advice. Content is produced independently and supported by advertising revenue. While we strive for accuracy, this article may contain unintentional errors or outdated information. Readers should independently verify all facts and data before making decisions. Company names and trademarks are referenced for analysis purposes under fair use principles. Always consult qualified professionals before making financial or legal decisions.