Sign in

Lazy loading

Suggest an edit

In traditional programming, lazy loading means you don't compute or fetch something until someone asks for it. On Solana it's usually not an optimization, but rather the only option. Programs cannot iterate over all accounts ever created. They can only write to the accounts passed into the transaction. And there is no scheduler, so every piece of work needs someone to send a transaction and pay for it.

So whenever your design says "for all holders", "every period", or "when the signers change, update everything", somebody has to send those transactions.

The lazy way (in a good sense): the result is not pushed to every account. Each account stores only what is needed to compute it later, and computes it when someone touches that account. The one who touches it pays for it, and that's the one who wanted the result. Usually this takes two fields: a running total, and a marker of how much of it this account has already seen. The result is the difference.

In a staking pool, the running total is the reward per staked token, kept in the pool account, and the marker is the value of that number at the staker's last claim:

rust
// what every staked token earned since this staker's last claim, times their stake
owed = (pool.reward_per_token - staker.last_reward_per_token) * staker.stake
Lazy loadingOne shared number at the top. Six small accounts below, five of them gray and untouched. One account is touched by a transaction, drawn red, and only that one computes its result from the shared number. Lazy loading shared total untouched untouched untouched computed untouched untouched a transaction touches it

Examples

Squads stale approvals. When signers change, the multisig doesn't walk through all open proposals. It sets one counter to the number of the latest proposal. When a proposal is read, its number is compared to the counter, and a lower number means stale. One comparison, no matter how many proposals there are.

Fragmetric. A transfer hook updates the holder's reward balance at the moment of the transfer. The program runs on that account anyway, so the accounting comes for free.

Helium rewards. The oracle signs the total a device has earned since the beginning, and the device's account stores how much was already paid. Nothing is pushed to a million devices every day. When someone claims, the program pays the difference and moves the marker up to the signed total.

Drift funding. Perp markets charge funding every hour, but the program never walks through the positions. The market stores a running total of funding per unit of position, and each position stores the total it last saw. When a position is touched (a trade, a close, a liquidation), the difference times the size is settled first, and the marker moves to the current total.

Important to remember: lazy means untouched accounts never update. If an action really needs to happen to update something explicitly (liquidations, expiry etc.), you would need a paid executor (like in the untrusted executor pattern) or to rework your design.