Skip to content

SQLite indexer #7017

Open
Open

Description

@LesnyRumcajs

Summary

This feature is needed to get acceptable performance out of several eth_* methods. There's a draft #6720 but some additional considerations might be needed.

Completion Criteria

  • [ ]

Additional Links & Resources

Activity

  1. moved this from New to Ready in Forest Backlog 🌲on May 7, 2026
  2. moved this from Ready to In progress in Forest Backlog 🌲on Jun 2, 2026
  3. LesnyRumcajs commented on Jun 18, 2026

    @LesnyRumcajs
    MemberAuthor

    @hanabi1224 please write down your findings here.

  4. hanabi1224 commented on Jun 24, 2026

    @hanabi1224
    Contributor

    (co-authored by Claude Code)

    Benchmark Results: SQL vs. In-Memory Implementation for eth_getLogs

    I ran load tests using oha (1000 sequential requests, 500-epoch range) against three configurations. Here's a summary of the key metrics:

    Configuration Avg (ms) p50 (ms) p95 (ms) p99 (ms) Req/sec
    main (with cache) 47.88 37.17 106.30 122.87 20.88
    main (no cache) 60.99 66.12 78.25 90.18 16.39
    sql 61.31 58.46 84.40 92.11 16.31

    Findings

    The SQL implementation performs on par with main when the in-memory cache is disabled — both averaging ~61 ms with throughput around 16.3 req/sec. This confirms that the SQL approach does not offer a performance improvement over the existing implementation.

    The main branch with cache enabled significantly outperforms SQL across most percentiles, particularly at the median (p50: 37 ms vs. 58 ms) and throughput (20.9 vs. 16.3 req/sec). It is worth noting that SQL wins slightly at p99 (92 ms vs. 123 ms), suggesting more consistent tail behaviour, but this comes at the cost of a considerably worse median. The cache accelerates repeated data loading for the same tipset and has a modest memory footprint (~100 MiB), so it is doing real work at low cost.

    Conclusion

    Since the SQL implementation merely matches the no-cache baseline without providing any measurable gain, and the existing in-memory cache already delivers substantially better median latency and throughput at negligible memory overhead, I don't think the current approach — a direct translation from Lotus — justifies proceeding further.

    I'd suggest we close this out unless there is a compelling reason to prefer SQL beyond what is already covered by the current implementation.

    Raw oha benchmark result:

    # command
    oha -n 1000 -c 1 -m POST http://localhost:2345/rpc/v1 -H 'Content-Type: application/json' -D eth_getLogs.json
    
    # payload
    

    {
    "method": "eth_getLogs",
    "params": [
    {
    "fromBlock": "0x39e6a8",
    "toBlock": "0x39e6da"
    }
    ],
    "id": 328,
    "jsonrpc": "2.0"
    }

    
    # main
      Success rate: 100.00%30s    40s    50s    60s    70s     ││0.0222  0.0378  0.0535  0.0691  0.0847  0.1004  0.1160    │
      Total:────────47898.2750 ms──────────────────────────────┘└──────────────────────────────────────────────────────────┘
      Slowest:      163.6199 ms
      Fastest:      22.2065 ms
      Average:      47.8814 ms
      Requests/sec: 20.8776
    
      Total data:   1.92 GiB
      Size/request: 1.97 MiB
      Size/sec:     41.14 MiB
    
    Response time histogram:
       22.206 ms [1]   |
       36.348 ms [332] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
       50.489 ms [352] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
       64.631 ms [127] |■■■■■■■■■■■
       78.772 ms [125] |■■■■■■■■■■■
       92.913 ms [11]  |■
      107.055 ms [3]   |
      121.196 ms [37]  |■■■
      135.337 ms [6]   |
      149.479 ms [3]   |
      163.620 ms [3]   |
    
    Response time distribution:
      10.00% in 31.8534 ms
      25.00% in 35.8801 ms
      50.00% in 37.1716 ms
      75.00% in 61.2324 ms
      90.00% in 71.9983 ms
      95.00% in 106.3030 ms
      99.00% in 122.8681 ms
      99.90% in 163.6199 ms
      99.99% in 163.6199 ms
      
    # main - no cache
      Success rate:m100.00%   4m    5m    6m    7m    8m       ││0.0244  0.0382  0.0520  0.0657  0.0795  0.0933  0.1071    │
      Total:────────61008.7898 ms──────────────────────────────┘└──────────────────────────────────────────────────────────┘
      Slowest:      119.6616 ms
      Fastest:      24.3998 ms
      Average:      60.9914 ms
      Requests/sec: 16.3911
    
      Total data:   1.92 GiB
      Size/request: 1.97 MiB
      Size/sec:     32.30 MiB
    
    Response time histogram:
       24.400 ms [1]   |
       33.926 ms [31]  |■■
       43.452 ms [247] |■■■■■■■■■■■■■■■■■■
       52.978 ms [4]   |
       62.505 ms [28]  |■■
       72.031 ms [430] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
       81.557 ms [234] |■■■■■■■■■■■■■■■■■
       91.083 ms [16]  |■
      100.609 ms [3]   |
      110.135 ms [3]   |
      119.662 ms [3]   |
    
    Response time distribution:
      10.00% in 37.8355 ms
      25.00% in 40.1914 ms
      50.00% in 66.1160 ms
      75.00% in 72.4119 ms
      90.00% in 75.6998 ms
      95.00% in 78.2507 ms
      99.00% in 90.1752 ms
      99.90% in 119.6616 ms
      99.99% in 119.6616 ms
      
    # SQL
      Success rate:m100.00%   4m    5m    6m    7m    8m       ││0.0421  0.0531  0.0641  0.0751  0.0861  0.0971  0.1081    │
      Total:────────61328.7609 ms──────────────────────────────┘└──────────────────────────────────────────────────────────┘
      Slowest:      117.0995 ms
      Fastest:      42.0620 ms
      Average:      61.3127 ms
      Requests/sec: 16.3056
    
      Total data:   1.92 GiB
      Size/request: 1.97 MiB
      Size/sec:     32.13 MiB
    
    Response time histogram:
       42.062 ms [1]   |
       49.566 ms [48]  |■■■■
       57.069 ms [341] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
       64.573 ms [361] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
       72.077 ms [74]  |■■■■■■
       79.581 ms [68]  |■■■■■■
       87.084 ms [77]  |■■■■■■
       94.588 ms [23]  |■■
      102.092 ms [3]   |
      109.596 ms [3]   |
      117.099 ms [1]   |
    
    Response time distribution:
      10.00% in 51.2401 ms
      25.00% in 53.1988 ms
      50.00% in 58.4605 ms
      75.00% in 64.3683 ms
      90.00% in 79.9259 ms
      95.00% in 84.4036 ms
      99.00% in 92.1129 ms
      99.90% in 117.0995 ms
      99.99% in 117.0995 ms
    
  5. hanabi1224 commented on Jun 24, 2026

    @hanabi1224
    Contributor

    As discussed, the SQL is intended to be used for a larger range (like 2-month-worth epochs) with a strict filter. Will benchmark that scenario again.

  6. LesnyRumcajs commented on Jun 24, 2026

    @LesnyRumcajs
    MemberAuthor

    Yeah, and the methods affected are not only eth_getLogs but others ~eth.*filter.*

  7. LesnyRumcajs commented on Jun 24, 2026

    @LesnyRumcajs
    MemberAuthor

    All in all, an SQL (or not, it's not set in stone) might have to be used to address expensive calls, for smaller ones we're probably good right now.

    Kind of like std::sort - use different algorithms for different collection sizes :)

  8. removed their assignment
    on Aug 6, 2026
  9. self-assigned this
    on Aug 13, 2026
  10. moved this from In progress to Frozen in Forest Backlog 🌲on Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type: TaskDiscrete task to implement

Type

No type

Fields

Priority

None yet

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions