Commit 539d8da
perf(rpc): search the block log for a record instead of scanning it
`Context::record_for_hash` asks the block tree for the hash, gets the height
back, and then scanned the block-record log linearly for the matching
`(hash, height)` pair. The height was already in hand and the log is ordered by
height, so the scan was avoidable work proportional to chain length - on the
path under `getblock`, `getblockheader`, `getblockstats`, `getrawtransaction`
with a blockhash, the REST block endpoint, and `gettxoutproof`s explicit-hash
path. `verifychain` calls it once per block it checks, so that RPC was quadratic.
This is a hotter path than the chain-info fold: `getblockchaininfo` is a status
call, `getblockheader` is what a tip-following client polls.
Measured over one fixture in one process, `before_scan` against `after_search`:
10,000 records, hash at tip: 14.59 us -> 37.4 ns 390x
100,000 records, hash at tip: 433.40 us -> 38.5 ns 11,265x
500,000 records, hash at tip: 3.850 ms -> 44.0 ns 87,551x
963,124 records, hash at tip: 6.263 ms -> 42.2 ns 148,548x
963,124 records, hash in middle: 3.448 ms -> 46.9 ns 73,548x
The new arm is flat at 37-47 ns across 96x the records: a binary search is ~20
steps at a mainnet tip. Both lookup positions are reported because measuring one
would flatter the scan - the tip is its worst case, the middle costs it half.
`BlockLog::record_at_height_hash` and `record_at_height` are not new code.
`block_source.rs` already had both, private, over `&[BlockRecord]`; they now live
on `BlockLog` beside the data and the node calls them, so this deletes a
duplicate implementation rather than adding one.
`record_at_height` keeps the direct-index shortcut, accepted only when the record
and its predecessor agree, so a log with gaps or duplicate heights falls through
to the search rather than answering with the wrong record.
Step 2 of `record_for_hash` stays linear on purpose: when the tree has no node
for the hash there is no height, so there is nothing to search on.
Seven mutations, all killed. Two survived the first pass and both were the
fixture's fault: it started at height 0, where the predecessor check can never
matter, and nothing exercised `block_by_height` with no applied tip. See
docs/benchmarks/block-record-lookup.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>1 parent ae689f5 commit 539d8da
5 files changed
Lines changed: 455 additions & 52 deletions
File tree
- crates
- node/src
- rpc
- benches
- src
- docs/benchmarks
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
| 17 | + | |
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
85 | | - | |
| 85 | + | |
86 | 86 | | |
87 | 87 | | |
88 | 88 | | |
| |||
98 | 98 | | |
99 | 99 | | |
100 | 100 | | |
101 | | - | |
| 101 | + | |
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
| |||
138 | 138 | | |
139 | 139 | | |
140 | 140 | | |
141 | | - | |
| 141 | + | |
142 | 142 | | |
143 | 143 | | |
144 | 144 | | |
| |||
298 | 298 | | |
299 | 299 | | |
300 | 300 | | |
301 | | - | |
302 | | - | |
303 | | - | |
304 | | - | |
305 | | - | |
306 | | - | |
307 | | - | |
308 | | - | |
309 | | - | |
310 | | - | |
311 | | - | |
312 | | - | |
313 | | - | |
314 | | - | |
315 | | - | |
316 | | - | |
317 | | - | |
318 | | - | |
319 | | - | |
320 | | - | |
321 | | - | |
322 | | - | |
323 | | - | |
324 | | - | |
325 | | - | |
326 | | - | |
327 | | - | |
328 | | - | |
329 | | - | |
330 | | - | |
331 | | - | |
332 | | - | |
333 | | - | |
334 | | - | |
335 | | - | |
336 | | - | |
337 | | - | |
338 | | - | |
339 | | - | |
340 | | - | |
341 | | - | |
342 | 301 | | |
343 | 302 | | |
344 | 303 | | |
| |||
347 | 306 | | |
348 | 307 | | |
349 | 308 | | |
| 309 | + | |
350 | 310 | | |
351 | 311 | | |
352 | 312 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
0 commit comments