Wavelength / Ark stack · regtest, never reset · bottleneck snapshot

Wavelength Growth Bench

One operator (lumosd, postgres) and ten clients (waved, lwwallet on sqlite) on a regtest chain that advances at mainnet pace: 18 blocks per 3-hour epoch, mined only by the harness. Every epoch runs 30 random client-to-client OOR payments (25–100k sat) and a wallet-realistic refresh of whatever is due (near batch expiry or deep OOR lineage), on top of everything prior epochs created. The question is not how fast the stack is on a clean network, but what the same payments and rounds cost once the operator's round history, indexer and mailbox have real volume in them.

Load cases

Time to complete each case

Wall clock per case, measured separately. Because state is never reset, an upward slope is the cost of accumulated history rather than run-to-run noise. The refresh number includes the harness-mined confirmation, so its floor is set by the round protocol, not the daemons.

Payments

OOR send latency

Per-payment time from submitting the send to the OOR session reaching its terminal state, across the 30 sends of the epoch. Sends run ten at a time (every client sends at once), so the spread between the median and the slowest send is the contention signal.

Rounds

Refresh round completion

Per-client time from queueing a refresh to that client's round reaching a terminal state. From epoch 14 the policy is wallet-realistic: a client refreshes only vtxos within 300 blocks of batch expiry or with an OOR chain depth of 6+ (a lineage that keeps growing eventually exceeds the operator's 25k vB cap and stops being spendable over OOR). Clients with nothing due skip; skips and fee-quote rejections ("insufficient_residual") count in the epoch detail as their own buckets, not as failures, and are excluded from the percentiles. Epochs 1-13 refreshed every client's whole fleet every epoch, which is why their round times and fee drain run far hotter. Epochs where every client skips are left out of the timings: nothing was due, so there is no round to time.

Capital

Deployed against user capital

Three views of the system's money. Deployed is the operator ledger's deployed_capital: every sat locked in unexpired on-chain batch outputs, including the operator's own refresh liquidity and fully-forfeited history the sweeper has not reclaimed yet. User spendable is the sum of all ten clients' confirmed offchain balances. Live vtxo value is the operator indexer's total for live vtxos, an independent measurement that should track user spendable exactly. The gap between deployed and the other two is capital the operator has committed beyond what users can spend; batch expiry (1008 blocks after a round confirms) is when the sweeper starts winning it back.

Capital efficiency

Sats locked per sat of user capital

Locked capital divided by user-owned capital. The numerator is only what sits in unexpired batch outputs and cannot be moved by the operator: value locked in previous rounds (forfeited but co-locked under the tree covenant until that batch's 1008-block expiry) plus the current rounds backing live vtxos. The operator's idle wallet is not in it. The denominator is everything users own, spendable or in flight (the indexer's live vtxo value). Every refresh re-locks fresh capital while the forfeited batch waits out its expiry, so the ratio climbs between sweeps and falls when the sweeper reclaims expired batches; a ratio that only ever climbs means reclamation is not keeping up.

Capital conservation

Where every sat is

Every sat enters through a known boarding deposit, so the books can be closed exactly. Against the operator's own indexer and ledger the identity deposited = live + in-flight + expired + fees holds to the sat in every epoch of this series, so the conservation residual is flat zero: the protocol loses nothing. What does go wrong is visibility. Invisible to owners is value the operator holds live that no client counts, because a dropped incoming transfer leaves the recipient unaware it was ever paid; those sats are unspendable by their owner until a seed-restore rescan finds them. Swept from owners is value in batches that expired before being refreshed, which the sweeper reclaims permanently. Client balances cannot close these books themselves: a vtxo locked in a queued refresh is counted in both a client's confirmed balance and its pending-out.

Reading a flat line here. All three series sitting on one value is the healthy result, not a missing chart: in this series they are pinned at zero for every epoch.

Operator storage

Operator database

Total size postgres reports for the lumos database. Postgres carries a fixed multi-megabyte catalog baseline: read the slope, not the offset. The largest tables behind this number are in the snapshot.

Storage growth

Storage added per epoch

Marginal cost of one epoch's work: the operator's postgres growth against the summed sqlite growth of all ten clients (main files plus WAL). Flat means the cost per unit of work is holding; a rising line means each epoch stores more than the last for the same 30 payments and one round.

Client storage

Client databases

Summed sqlite footprint of all ten clients, and wb-client01 alone as the representative client (clients are symmetric by construction). Includes each database's WAL, so a stalled checkpoint shows up here as growth the main file never sees.

Memory · operator

lumosd memory

Resident set sampled once after the epoch's cases finish, so it is where memory settles rather than a peak during the run. The high water mark is memory.peak from the container's cgroup: it cannot be reset without root, so it only ever rises, and a mark that keeps climbing epoch after epoch is the leak signal.

Memory · client

wb-client01 memory

Same measurements on the observed client. One client stands for all ten: they run the same binary against the same operator with the same workload shape.

Runtime

Goroutines

Live goroutine count on the operator and the observed client at the end of each epoch. A count that grows with the series and never settles is a leaked-goroutine signal; growth proportional to load that returns to a floor is normal.

Every epoch, as measured