
Solana co-founder: What are the solutions to Solana's state growth?
TechFlow Selected TechFlow Selected

Solana co-founder: What are the solutions to Solana's state growth?
Must manage state and memory within current hardware constraints.
Author: toly, Solana Co-Founder
Translation: Felix, PANews
Approximately one million new accounts are added to Solana every day. The total state now exceeds 500 million, with snapshot sizes around 70GB. While hardware improvements make these figures manageable, the goal of the SVM runtime is to enable access using the cheapest possible hardware. To achieve this, state and memory must be managed within current hardware constraints.
PCI Bandwidth
As of 2024, the latest PCI bandwidth can reach throughput levels between 0.5 Tbps and 1 Tbps—or 64GB to 128GB per second. This may sound substantial, but if a transaction reads/writes 128MB, a PCI bandwidth of 128GB/s would cap the chain's TPS at around 1,000. In practice, most transactions access memory recently loaded and cached in RAM. An ideal design should allow loading 1,000 transactions with 128MB of new state, plus 10,000 or more transactions reading from and writing to existing cached state.
Account Indexing
Creating a new account requires proving that it does not currently exist. This is typically done automatically on each validator, as every validator maintains a complete index of all valid accounts. Even if account data isn't stored locally—only its hash—the index for 500 million accounts would require 32 bytes for the key and 32 bytes for the data hash, totaling 64 bytes per entry, or 32 GB. This alone necessitates separating RAM from disk storage.
Snapshot Size
At certain snapshot sizes, if part of the network experiences hardware failure, the time required to cold-start a new system could extend worst-case restart times. Although improvements in bandwidth and hardware continually shift this boundary—and Solana is not near this limit—the constraint exists at any given moment.
Summary
Memory and disk have different performance characteristics and limitations. If SVM does not distinguish between them, transactions and limits must be priced for the worst-case scenario, thereby capping performance. During transaction execution, all account keys must at minimum be accessible, and the total number of accounts affects RAM and disk PCI bandwidth utilization. Snapshots cannot grow arbitrarily. The ideal solution should:
-
Allow packing more transactions into blocks that don’t consume PCI resources
-
Manage total index size and snapshot size
Chilly, Avocado, LSR. Bad names are often signs of great software design. Engineers from Anza and Firedancer came up with the following solutions.
Chilly
The account runtime cache is deterministically managed across all instances. At a high level, this functions as an LRU (Least Recently Used) cache for accessing state. During block construction and scheduling, this implementation allows easy account checks without requiring locks or iterating through the LRU cache. The cache uses a very simple counter mechanism.
-
Total loaded bytes are tracked as Bank::loaded_bytes:u64
-
Each account is tagged with a current running count, account::load_counter:u64, when used
-
When loading an account, if Bank::loaded_bytes - Account::load_counter > CACHE_SIZE, the account is considered cold, and its size counts against the per-block LOAD_LIMIT
-
New accounts have load_counter set to 0, so all new accounts are initially cold
-
The leader’s scheduler treats LOAD_LIMIT as a watermark, similar to write-lock CU limits
The elegance of this design lies in how naturally it integrates with the current scheduler. Users only need to worry about their priority fees. The scheduler handles fitting transactions below both the LOAD_LIMIT and account write-lock limits into a block like a knapsack problem. Highest-priority transactions can load first and use the LOAD_LIMIT. Once this limit is reached, other transactions can still be included in the block. Thus, validators can maximize caching locality for transactions.
Avocado
Avocado consists of two parts: state compression and index compression. First, replace account data with hashes; then migrate the account index to a Binary Trie / Patricia Trie. New accounts must provide proof they do not exist in the "trie".
State Compression
The general design is as follows:
-
During allocation, each account binds X lamports per byte.
-
If X < current economic floor price, keep the account in memory; otherwise, compress the account
-
Compression is a multi-step process executed over an epoch
-
Account data is replaced with a hash(data)
-
Account keys remain in state
-
Transactions referencing compressed accounts fail
-
Decompression requires uploading data similar to a loader program
-
Decompression cost should equal the cost of allocating a new account
It's estimated that 75% of accounts go unused for over six months and likely will never be accessed again. Compressing them could save 50% of snapshot size.
Index Compression
This is a harder problem. With only state compression, validators still maintain a record of all potentially valid accounts in the system. Creating a new account requires checking this database. The cost to validators for storing this database is high, while the cost to users creating new accounts remains low. Ensuring no new private key conflicts with an existing account is essential.
Binary Trie Mining
-
The Binary Trie is tracked as part of the snapshot
-
Validators who want extra SOL can create a transaction to remove compressed account key-value pairs from state and add them to the Binary Trie
-
Users can reverse this operation during decompression by removing kvs from the Trie (this may require atomic operations during decompression to simplify background compression services)
-
For validators, the Trie root size remains constant regardless of the number of kvs it contains
-
Using ZKPs, each transaction can compress approximately 30 accounts
-
Assuming one such transaction per block, compressing 500 million accounts would take roughly 80 days
The key aspect of this process is that only the validator performing the operation receives a reward—others aren't required to participate. If all validators had to perform this, they'd all need to maintain the current contents of the Binary Trie, meaning the entire state would have to be part of the snapshot. Validators wishing to maintain full state should submit transactions to compress N accounts from the index into the Trie.
New Account Proofs
To create a new account, users must prove it doesn’t exist in the Trie. Validators maintaining full state can generate proofs that an account is absent from the Trie. This places a burden on users, who must always connect to large-state providers to generate such proofs.
Alternatively, users could prove their account was created using a recent PoH hash. The simplest way to support this is:
-
Generate a new PKI
-
Account address = hash(recent PoH hash, PKI::public_key)
Since accounts in the Trie must first undergo state compression—which takes a full epoch—it’s impossible for any account in the Trie to use a recent PoH hash to generate its address.
Other supporting methods include having PKI creation itself provide a proof that the private key was generated via hash(user-secret, recent PoH hash).
LSR
Lightweight Simple Rent, also known as Less Stupid Rent. How should we price the cost of allocating new accounts, ensure old unused accounts eventually get compressed, reduce overall system load, and lower costs for new users?
A rent system must be reintroduced. Rent means accounts in current state pay X dollars/byte/day, just like cloud storage accounts on AWS pay for storage.
Rent Rate Bonding Curve
RentRate = K*(state_size)^N
Regardless of current state size, if it's small, the rate should be low; if approaching snapshot limits, the rate should become very high.
Allocation Minimum Bonding Price
An account must exist for at least one epoch. Allocation brings an account into Hot state. Hot accounts should remain in cache during this period.
New Account bond = Epoch Slots * RentRate * Account::size
A new account must have at least this many lamports in its balance to be created.
Hot Account Burn
lruturnoverrate = average time an account occupies space in the LRU cache, capped at one epoch. This value can be a constant or computed off-chain and reported to SVM as a median stake-weighted constant.
Compression
When (current slot - account::creation_slot) * RentRate * account::size > account::lamports, the account is compressed and all lamports are burned.
This proposed solution should make state inexpensive over time, as unused accounts will eventually deplete their lamports and be compressed. Data overhead decreases, and even index overhead reduces, shrinking the total active state. Reducing state size lowers the super-quadratic cost of allocations.
Join TechFlow official community to stay tuned
Telegram:https://t.me/TechFlowDaily
X (Twitter):https://x.com/TechFlowPost
X (Twitter) EN:https://x.com/BlockFlow_News














