Account Lock Analysis
Your PDAs pass collision checks. Great. But under real concurrent load, write locks create invisible bottlenecks that tank your protocol's throughput.
Skaf's Lock Analysis simulates 100 concurrent transactions against your account structure and shows exactly where the serialization happens — before you deploy to mainnet.
collision-free ≠ contention-free
Collision checks verify your PDAs derive unique addresses. But unique addresses don't guarantee performance under load.
Collision Check
"Do any of my PDA seed combinations produce the same on-chain address?"
Checks: address uniqueness, seed overlap, bump validity
Lock Analysis
"When 100 users hit my protocol at once, which accounts become serial bottlenecks?"
Checks: write-lock conflicts, read/write ratio, serialization depth
How Solana account locks work
Solana's runtime processes transactions in parallel by default. But when two transactions touch the same account, the lock system kicks in.
Parallel (no conflict)
PARALLEL> Different accounts = both execute simultaneously. Maximum throughput.
Read sharing (safe)
PARALLEL> Multiple read locks on the same account are allowed. No blocking.
Write conflict (serial)
SERIAL> Two write locks on the same account = forced serial execution. Bottleneck!
Read + Write conflict
SERIAL> Write lock blocks all readers on the same account. Even reads get queued.
Key insight: The more transactions write to the same account, the more they serialize. At 100 concurrent TXs targeting one writable account, your protocol becomes a single-threaded queue.
See it in action
A real DEX AMM account structure — before and after optimization. Toggle to see how sharding transforms the contention profile.
> CRITICAL: amm_pool is a serial bottleneck at 89% contention. 100 concurrent TXs queue behind a single write lock.
Optimization strategies
Lock Analysis doesn't just find problems — it suggests solutions. Here are the four patterns that eliminate most contention.
Account Sharding
One global account handles all writes
Split into N partitioned accounts (e.g., pool_0, pool_1, pool_2)
tick_array → tick_array_0, tick_array_1, tick_array_2
Per-User PDAs
Shared account written by every user TX
Derive unique PDA per user: seeds = ["position", user_wallet]
position → position_<wallet_A>, position_<wallet_B>
Time-based Epochs
Accumulator account updated every TX
Rotate accounts by epoch: seeds = ["stats", epoch_id]
stats → stats_epoch_1, stats_epoch_2
Read-only Separation
Config data mixed with mutable state
Separate read-only config from writable state into different PDAs
pool_config (read-only) + pool_state (writable)
Real-world examples
How common Solana protocol patterns create contention — and how to fix them.
DEX AMM
Single pool account handles all swaps — 89% contention at peak load
> Sharded tick arrays into 3 partitions, separated pool config from state
2.6x throughput improvementLending Protocol
Global reserve account written on every deposit/borrow
> Per-market reserves with epoch-based interest accumulators
3.4x throughput improvementNFT Marketplace
Listing index account grows linearly, every new listing writes to it
> Per-collection listing PDAs with user-scoped escrow accounts
4.3x throughput improvementHow it works
From your PDA design to actionable optimization — in one click.
Design PDAs
Build your account structure in the visual designer with seeds, space, and relationships.
Run Analysis
Click 'Lock Analysis' to simulate 100 concurrent transactions against every account.
Find Bottlenecks
See per-account contention scores, read/write ratios, and serialization depth.
Optimize & Export
Apply sharding suggestions, verify improvement, and export production-ready Anchor code.