Skip to content

fix(kv-store): iterate LMDBMultiMap ranges past a numeric key 0 - #376

Merged
rkarabut merged 2 commits into
mainfrom
rk/fix-a2186-multimap-slot-zero
Oct 2, 2026
Merged

rkarabut merged 2 commits into
mainfrom
rk/fix-a2186-multimap-slot-zero

Conversation

@rkarabut

@rkarabut rkarabut commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

LMDBMultiMap.entriesAsync treated a numeric key 0 as an absent bound or a decode failure. A valid key 0 is falsey, so a range scan that reached key 0 stopped at the first key. Once a node stored a slot-0 proposal index, cleanup stopped deleting old indices.

Mirror LMDBMap: compare bounds with !== undefined and break only when deserializeKey returns false.

Fixes A-2186

LMDBMultiMap.entriesAsync treated a numeric key 0 as an absent bound or a decode
failure: it built range bounds with range?.start/range?.end truthiness and broke
iteration on !deserializedKey. A valid key 0 is falsey, so a range scan that
reached key 0 stopped at the first key. The p2p attestation pool's slot-keyed
proposal-index cleanup (deleteOlderThan) iterates these numeric multimaps, so once
a node stored a slot-0 proposal index, cleanup stopped deleting old indexes and
stale p2p state grew unbounded by finalized-block cleanup. Mirror LMDBMap: compare
bounds with !== undefined and break only when deserializeKey returns false.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[High risk] Fixes key-value store range iteration for numeric zero keys.

The implementation appears sound, but the explicit repository transaction requirement should be satisfied before merging.

Fix All in Claude CodeFindings

  1. P2 Temporary stores are left behind ▶
  2. P2 Zero-bound regression remains untested ▶
  3. P2 Related operations lack a transaction ▶

Summary

This PR changes LMDBMultiMap range iteration to retain numeric zero as a bound and as a decoded key, and adds two regression tests.

  • The implementation follows the existing LMDBMap pattern.
  • The tests need store teardown, more discriminating bound coverage, and transaction wrapping to meet the repository requirement.

Reviews (1) · Last reviewed commit: "fix(kv-store): iterate LMDBMultiMap rang..."

// (used by the p2p attestation pool's slot-keyed proposal-index cleanup) must include and iterate
// past it; otherwise cleanup that starts at slot 0 stops at the first key and old indexes leak.
it('iterates entries past a numeric key 0', async () => {
const store = await openTmpStore('test-numeric-entries');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Temporary stores are left behind Both new tests open temporary LMDB stores but never delete them. Each store creates a directory, and cleanup runs through store.delete(), so test runs leave database files behind. Add teardown for both stores.

Fix in Claude Code

await map.set(1, 'b');
await map.set(2, 'c');

const keys = await toArray(map.keysAsync({ start: 0 }));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Zero-bound regression remains untested With only keys 0, 1, and 2, this forward scan returns the same result whether start: 0 is honored or ignored. Neither new test checks end: 0, so both bound changes could regress without failing these tests. Add cases that distinguish an explicit zero bound from an absent one.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

Comment on lines +15 to +19
await map.set(0, 'a');
await map.set(1, 'b');
await map.set(2, 'c');

const keys = (await toArray(map.entriesAsync())).map(([key]) => key);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Related operations lack a transaction Both new tests perform related writes and a range read without store.transactionAsync(). The repository requires related AztecAsyncKVStore reads and writes to be wrapped in a transaction for atomicity. Please satisfy that requirement in both tests before merging.

Context Used: yarn-project/CLAUDE.md (source)

Fix in Claude Code

- add a discriminating end:0 case: end is exclusive, so an honored zero bound
  returns [], while the pre-fix code reads 0 as falsey, drops the bound, and
  returns all keys - so this assertion fails when the zero bound regresses
  (start:0 forward cannot distinguish an honored bound from an absent one with
  non-negative keys, so it is not a regression guard on its own)
- wrap the related writes and range reads in store.transactionAsync for atomicity
- delete both temp stores in a finally block so the tests do not leak LMDB dirs
@rkarabut
rkarabut merged commit e77cd49 into main Oct 2, 2026
6 checks passed
@rkarabut
rkarabut deleted the rk/fix-a2186-multimap-slot-zero branch October 2, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants