Skip to content

Conversation

@jewei1997
Copy link
Contributor

@jewei1997 jewei1997 commented Feb 11, 2026

Summary

This PR adds a parquet-based receipt storage backend with DuckDB for efficient range queries on logs, enabling fast eth_getLogs queries across block ranges.

  • Add parquet backend option (Backend: "parquet" in config)
  • Parquet files rotate every 500 blocks
  • DuckDB queries across closed parquet files for efficient log filtering
  • WAL for crash recovery of in-progress parquet files
  • Pruning of old parquet files based on KeepRecent config
  • Build tag support: use -tags duckdb to enable parquet backend

The parquet backend supports the new FilterLogs range query API introduced in #2788, enabling efficient cross-block log queries without falling back to per-receipt fetching.

Dependencies

Test plan

  • Receipt store unit tests pass (without duckdb tag)
  • Parquet store tests pass with -tags duckdb
  • Integration testing with full node using parquet backend

@github-actions
Copy link

github-actions bot commented Feb 11, 2026

The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedFeb 12, 2026, 10:08 PM

@codecov
Copy link

codecov bot commented Feb 11, 2026

Codecov Report

❌ Patch coverage is 71.16858% with 301 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.28%. Comparing base (9ccd5ca) to head (0a355b7).

Files with missing lines Patch % Lines
sei-db/ledger_db/parquet/store.go 66.44% 56 Missing and 43 partials ⚠️
sei-db/ledger_db/receipt/parquet_store.go 65.53% 62 Missing and 29 partials ⚠️
sei-db/ledger_db/parquet/reader.go 73.26% 48 Missing and 25 partials ⚠️
sei-db/ledger_db/receipt/receipt_cache.go 79.54% 10 Missing and 8 partials ⚠️
sei-db/ledger_db/parquet/wal.go 75.38% 8 Missing and 8 partials ⚠️
sei-db/ledger_db/receipt/cached_receipt_store.go 95.91% 1 Missing and 1 partial ⚠️
sei-db/ledger_db/receipt/receipt_store.go 80.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2861      +/-   ##
==========================================
+ Coverage   57.16%   57.28%   +0.12%     
==========================================
  Files        2091     2095       +4     
  Lines      171145   172176    +1031     
==========================================
+ Hits        97827    98627     +800     
- Misses      64609    64722     +113     
- Partials     8709     8827     +118     
Flag Coverage Δ
sei-chain 52.78% <71.16%> (+0.16%) ⬆️
sei-cosmos 48.12% <ø> (-0.02%) ⬇️
sei-db 68.72% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
evmrpc/filter.go 69.07% <ø> (+0.43%) ⬆️
sei-db/ledger_db/receipt/cached_receipt_store.go 92.30% <95.91%> (+3.26%) ⬆️
sei-db/ledger_db/receipt/receipt_store.go 76.96% <80.00%> (+7.37%) ⬆️
sei-db/ledger_db/parquet/wal.go 75.38% <75.38%> (ø)
sei-db/ledger_db/receipt/receipt_cache.go 81.11% <79.54%> (-2.81%) ⬇️
sei-db/ledger_db/parquet/reader.go 73.26% <73.26%> (ø)
sei-db/ledger_db/receipt/parquet_store.go 65.53% <65.53%> (ø)
sei-db/ledger_db/parquet/store.go 66.44% <66.44%> (ø)

... and 29 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment on lines +230 to +240
for blockNum, logs := range chunk.logs {
if blockNum < fromBlock || blockNum > toBlock {
continue
}
for _, lg := range logs {
if matchLog(lg, crit) {
logCopy := *lg
result = append(result, &logCopy)
}
}
}

Check warning

Code scanning / CodeQL

Iteration over map Warning

Iteration over map may be a possible source of non-determinism
"database/sql"
"fmt"
"path/filepath"
"runtime"

Check notice

Code scanning / CodeQL

Sensitive package import Note

Certain system packages contain functions which may be a possible source of non-determinism
Comment on lines 310 to 332
go func() {
for {
latestVersion := s.latestVersion.Load()
pruneBeforeBlock := latestVersion - s.config.KeepRecent
if pruneBeforeBlock > 0 {
pruned := s.pruneOldFiles(uint64(pruneBeforeBlock))
if pruned > 0 && s.log != nil {
s.log.Info(fmt.Sprintf("Pruned %d parquet file pairs older than block %d", pruned, pruneBeforeBlock))
}
}

// Add jitter to avoid thundering herd
jitter := time.Duration(float64(pruneIntervalSeconds)*0.5) * time.Second
sleepDuration := time.Duration(pruneIntervalSeconds)*time.Second + jitter

select {
case <-s.pruneStop:
return
case <-time.After(sleepDuration):
// Continue to next iteration
}
}
}()

Check notice

Code scanning / CodeQL

Spawning a Go routine Note

Spawning a Go routine may be a possible source of non-determinism
}

// Add random jitter (up to 50% of base interval) to avoid thundering herd
jitter := time.Duration(rand.Float64()*float64(pruneIntervalSeconds)*0.5) * time.Second

Check notice

Code scanning / CodeQL

Floating point arithmetic Note

Floating point arithmetic operations are not associative and a possible source of non-determinism
}

// Add random jitter (up to 50% of base interval) to avoid thundering herd
jitter := time.Duration(rand.Float64()*float64(pruneIntervalSeconds)*0.5) * time.Second

Check notice

Code scanning / CodeQL

Floating point arithmetic Note

Floating point arithmetic operations are not associative and a possible source of non-determinism
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants