What if you could see which DeFi loans are about to collapse — before anyone else? 🔍
LiqScan scans 280,000+ lending positions on Aave V3 every 30 seconds across 5 blockchains (Ethereum, Arbitrum, Base, Polygon & Optimism).
When someone's collateral drops too low, their loan gets liquidated — and whoever executes it earns a bonus. LiqScan shows you exactly which ones are profitable right now, how much you'd make after gas costs, and how to act.
No guessing. No spreadsheets. Just clear opportunities.
🖥️ Try it free for 24 hours — no card needed
→ https://t.co/20Hd6kFySs
Pro plan at 9€/month
#DeFi #Aave #Liquidations #MEV #Web3
Thanks for the insight! That’s a very valid concern, especially regarding compression efficiency and cumulative storage costs.
I wonder whether an adaptive approach could help: keeping periodic full compressed snapshots, while using incremental checkpoints only when their measured compressed size and reconstruction cost justify it.
Would benchmarking this against real FullKV snapshots, including compression ratios, upload costs, and restore times, be useful to determine the break-even point?
After StreamingFast opened several Substreams PRs referencing my previous optimization proposal, I went deeper into the current Substreams / Firehose architecture and found what I believe could be a substantially larger performance opportunity.
SparseFirehose: push Block Index selectivity all the way down to physical storage.
Substreams already knows which historical blocks match a filter through its Block Index / RoaringBitmap infrastructure. But that selectivity can stop above the storage layer: a merged bundle containing a relevant block may still be opened and walked before non-matching blocks are discarded.
In other words:
if the engine already knows a block will never execute, why download and decompress it at all?
The proposal keeps the existing 100-block merged-bundle boundaries, but makes the inside of each bundle independently seekable in small compressed frames:
Block Index → Tier1 sparse planner → skip empty jobs → exact matching blocks → seek table → object-storage Range GET → matching compressed frames only → lazy decode → WASM
I built a reproducible simulation of the current 100-block model vs 4-block seekable frames:
0.1% relevant blocks → 23.95× less block I/O
0.5% → 19.81×
1% → 16.11×
5% → 5.35×
10% → 2.91×
I also tested a deliberately bursty ~1% workload instead of uniformly distributed matches. The reduction was still 12.06×.
These are I/O reductions, not claims of 16× end-to-end Substreams speed. The benchmark I would propose for a real prototype is more demanding:
≥5× end-to-end speedup on ≤1%-selective historical workloads, with ≤5% regression on dense workloads.
A second phase could combine this with BASE / EXTENDED storage lanes, avoiding trace/state payloads when a module only needs standard transaction/log data.
I published the simulation, parameters, raw results and RFC sketch so everything can be reproduced and challenged:
https://t.co/gBWfu58eUc
@streamingfastio@graphprotocol — I’d be very interested to see this tested against real Tier1/Tier2 workloads.
Performance optimization proposal: reducing FullKV checkpoint overhead in Substreams — for @graphprotocol and @streamingfastio
I’ve been studying the FullKV persistence mechanism in Substreams and exploring whether incremental checkpoints could reduce unnecessary serialization and storage operations.
I built an independent prototype, ran local Go benchmarks and tested the approach across thousands of synthetic workloads.
What the investigation actually found:
1. The problem identified in the source code
In the examined Substreams implementation, https://t.co/sFrPvCbCDz obtains a snapshot of the store and serializes its complete contents using MarshalStreamSnapshot.
This means that, for nonempty updates, checkpoint persistence can involve writing the entire state even when only a small fraction of its contents has changed.
For large stateful modules, this creates a potential opportunity to reduce checkpoint I/O.
2. The proposed optimization
Introduce bounded incremental FullKV checkpoints:
→ Record the final changed keys and deletions during state merging.
→ Persist those changes as immutable delta objects referencing an earlier full checkpoint.
→ Reconstruct state through versioned manifests.
→ Periodically compact the accumulated deltas into a new full snapshot.
→ Fall back to full snapshots whenever incremental persistence is unlikely to be beneficial.
The proposal targets checkpoint persistence, not block decoding, WASM execution or the underlying merge computation.
3. Actual benchmark measurements
I implemented an independent Go benchmark that performs real local file writes, including fsync, using synthetic state data.
With a 96 MiB state, eight checkpoint boundaries and three repetitions per change rate, the measured median improvements in write time were:
• 0.1% state churn → 14.77×
• 1% state churn → 12.16×
• 10% state churn → 5.64×
• 50% state churn → 2.01×
• 90% state churn → 1.35×
These figures measure local checkpoint writing, not end-to-end Substreams execution.
4. A critical limitation
Incremental checkpoints are only attractive if identifying modified keys is sufficiently cheap.
When I added the cost of scanning and hashing the entire state as an optimistic proxy for change discovery, the measured median improvement at 1% churn dropped from 12.16× to 1.41×.
At 90% churn, performance fell to 0.78× relative to the full-snapshot baseline.
This is an important finding: incremental persistence is not automatically faster.
Efficient mutation tracking is essential.
5. Additional simulation and correctness testing
The investigation also includes:
• 2,800 synthetic workload scenarios covering 336,000 modeled segments.
• 1,000 randomized checkpoint reconstruction tests.
• Corruption, missing-data, rollback and compaction tests.
• Comparisons between fixed and adaptive checkpoint-selection policies.
In the stochastic model, an adaptive policy using imperfect cost predictions achieved a 1.74× median modeled speedup, while 4.3% of scenarios experienced regressions.
These are simulated outcomes based on assumed workload distributions, not observed production results.
6. What would make this useful for Substreams?
The next step would be an experimental integration into the actual https://t.co/sFrPvCbCDz and FullKV.Load paths.
That implementation would need to validate:
→ Correct behavior across Substreams store update policies.
→ Efficient tracking of mutations without full-state scans.
→ Compatibility with existing checkpoints and recovery mechanisms.
→ Safe publication and garbage collection in object storage.
→ Cold-restoration performance and end-to-end throughput under real workloads.
The existing optimization for completely empty partials must also remain part of the baseline.
📂 Full research repository
https://t.co/pLL2atEdQH
The interesting part is that most primitives already exist:
Block Index knows the exact matching blocks. FileSource already receives filtered block numbers. PR #999 already moves skipping earlier.
So the next question is:
If we already know a block will never execute, why download it at all?
I dug deeper into Substreams/Firehose after the recent PRs inspired by my previous optimization proposal. I think there is a much larger opportunity: push block-index selectivity all the way down to physical storage.
SparseFirehose: Index-Guided Seekable Execution 🧵
@graphprotocol
Combining sparse seeks + BASE-only reads, a ~1%-selective workload could move roughly 80–100× fewer bytes in some cases.
That is not an 80–100× end-to-end speed claim.
A good experimental target would be: ≥5× end-to-end on ≤1% selective historical workloads, with dense workloads within ±5% of today.
Three proposals to make Substreams faster, explained in plain words. Each one attacks a different bottleneck, and each has limits
@streamingfastio@graphprotocol@graphtronauts_c
———
1/ Skip empty chunks
Substreams splits a chain's history into chunks of 1,000 blocks and hands them to many workers in parallel. Many packages only look for rare events, so most chunks hold nothing for the
Today a worker loads its data and compiles the package's code, and only then checks the index that says the chunk is empty.
Like a plumber unloading the whole van before reading the work order. The idea: read the order first.
Potential: compiling alone took 0.15–0.4 s per chunk in my tests, wasted on every empty one.
Limits: it only helps packages that look for rare events, and it saves machine cost more than time. Progress and billing would work as today.
———
2/ Light EVM blocks
Each Ethereum block carries the events apps care about, plus a detailed record of every internal call and state change. Most packages only read the events, but they still download and decode everything.
The idea: a small module strips those internal records first, and a package switches to it by changing one line. StreamingFast already does the same on Solana, where it drops vote transactions.
Like getting only the newspaper section you read.
Measured on real Ethereum, BNB and Polygon blocks: 5.2–5.9x less data and 4.4–5.6x faster for a typical event module, with identical output.
Limits: only 3 sample blocks, not their servers. Packages on newer decoding libraries gain less.
———
3/ Layered stores
Some packages keep running state, called a store: balances, positions, totals. Today, after every chunk, the whole store is saved again, and each save waits for the previous one.
Like photocopying an entire notebook after every chapter, one copy at a time. With a thick notebook, more workers barely help: they all wait for the copier.
StreamingFast's own changelog describes this symptom.
The idea: save only the changes, and merge them in pairs like a tournament bracket. Pairs merge in parallel, and any point in history is rebuilt from at most 14 pieces.
Checked for all 7 store types: identical results in 862,337 random cases.
Potential, from a simulation: a 3.5 GiB store over 10M blocks with 20 workers goes from 26h to 2.3h, and writes 0.37 TB instead of 18.8 TB.
Limits: a model, not a measurement; small stores gain nothing; decimal sums stay as today; months of engine work.
———
Together, 2 and 3 could bring heavy backfills to about 1h in the model; 1 mainly cuts cost.
Prepared with AI assistance; every number is reproducible:
https://t.co/NS7GkSnQOB
https://t.co/nk06he6Nm3
Feedback very welcome.
@Kaushiknew123@base@Kaushiknew123 Finance is better on Base when you can see risk before it hits. 100K+ Aave positions on Base, monitored in real time 👇