Skip to content

commitment: add TrieReader — stateless read-only Patricia trie navigation#20287

Merged
awskii merged 7 commits intomainfrom
awskii/trie-reader
Apr 11, 2026
Merged

commitment: add TrieReader — stateless read-only Patricia trie navigation#20287
awskii merged 7 commits intomainfrom
awskii/trie-reader

Conversation

@awskii
Copy link
Copy Markdown
Member

@awskii awskii commented Apr 2, 2026

Summary

Adds TrieReader — a lightweight, stateless read-only navigator for the Patricia trie. Each Lookup call starts from the root and descends independently without any mutable grid state.

Motivation

HexPatriciaHashed carries ~200KB of mutable grid state (grid[64][16]cell, touchMap, afterMap, etc.) designed for update processing. For read-only path queries (proofs, witnesses, integrity checks, tooling) this is unnecessary.

Design

type TrieReader struct {
    ctx           PatriciaContext
    accountKeyLen int16
    keccak        keccak.KeccakState
    hashBuf       [length.Hash]byte
}

func NewTrieReader(ctx PatriciaContext, accountKeyLen int) *TrieReader
func (tr *TrieReader) Lookup(hashedKey []byte) (cell, bool, error)
  • Stateless: no grid, no activeRows. Each call allocates only a small nibble prefix buffer
  • Direct descent: calls ctx.Branch(compact(prefix)) at each level, parses cells from branch data
  • deriveHashedKeys: reconstructs hashed nibble extensions from plain keys (accountAddr/storageAddr) via keccak — the same step unfoldBranchNode does. This is critical for navigating past leaf cells into storage sub-tries
  • Storage support: account cells with hash + more key to consume continue into the storage sub-trie at depth 64+
  • Nibble validation: rejects invalid nibbles (> 0x0f) with a clear error

Exported cell accessors

func (c *cell) AccountAddrLen() int
func (c *cell) StorageAddrLen() int
func (c *cell) HashLen() int
func (c *cell) GetAccountAddr() []byte
func (c *cell) GetStorageAddr() []byte
func (c *cell) CellHash() []byte
func (c *cell) Extension() []byte

Tests

Test What it verifies
TestTrieReader_RoundTripWithHPH 7 accounts + 3 storage keys through real HexPatriciaHashed.Process → TrieReader lookup
TestTrieReader_RoundTripWithHPH_ManyAccounts 100 accounts, all 100 found
TestTrieReader_IntegrationWithRealData (db/state) 200 accounts + 100 storage via full domain/aggregator/snapshot stack
9 mock unit tests Account/storage hits, misses, extensions, multi-level descent, error propagation

Files

  • execution/commitment/trie_reader.go — implementation + cell accessors
  • execution/commitment/trie_reader_test.go — 12 tests (mock + HPH round-trip)
  • db/state/trie_reader_integration_test.go — full-stack integration test
  • execution/commitment/commitmentdb/commitment_context.goNewTrieContextRo for read-only branch access

Related

awskii added 3 commits April 1, 2026 18:23
Implement TrieReader in execution/commitment/ that navigates the Patricia
trie by hashed key without any mutable grid state. Each Lookup call starts
from the root and descends independently via PatriciaContext.Branch().

Includes parseCellAt for single-cell extraction from branch data, and
comprehensive tests covering hits, misses, extensions, and multi-level descent.
- Remove unused accountKeyLen field from TrieReader (dead code)
- Fix redundant depth bounds check: change > to >= to avoid unnecessary
  Branch() call when key is fully consumed
- Remove duplicate depth >= len(hashedKey) check that became dead code
- Add test for Branch() error propagation
- Add test for empty/nil hashedKey edge case
@awskii awskii linked an issue Apr 10, 2026 that may be closed by this pull request
14 tasks
@awskii awskii marked this pull request as ready for review April 10, 2026 12:19
@AskAlexSharov AskAlexSharov requested a review from Copilot April 10, 2026 12:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Introduces a new lightweight TrieReader in execution/commitment to support stateless, read-only navigation of the existing Patricia trie encoding via PatriciaContext.Branch, avoiding the large mutable HexPatriciaHashed grid state.

Changes:

  • Added TrieReader with Lookup(hashedKey []byte) that descends from the root by compact-prefix branch reads and per-nibble cell parsing.
  • Added unit tests covering hits/misses, extension traversal, multi-level descent, and error propagation with a mock PatriciaContext.
  • Added an implementation plan document under completed/.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
execution/commitment/trie_reader.go New stateless trie lookup implementation using branch reads + cell parsing.
execution/commitment/trie_reader_test.go New unit tests for TrieReader behavior across common paths and failure modes.
completed/plan.md Design/implementation plan for TrieReader and its intended algorithm.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +93 to +99
afterMap := binary.BigEndian.Uint16(branchData[2:4])
cellData := branchData[4:]
nibble := int(hashedKey[depth])

if afterMap&(uint16(1)<<nibble) == 0 {
return c, false, nil
}
Comment thread execution/commitment/trie_reader.go Outdated
Comment thread completed/plan.md Outdated
Comment on lines +135 to +142
func TestTrieReader_AccountLookupHit(t *testing.T) {
t.Parallel()

// Build a simple single-level trie:
// Root branch has nibble 0xa pointing to an account leaf.
ctx := newTrieReaderTestCtx()
addr := bytes.Repeat([]byte{0xAB}, 20)

…tests

TrieReader could not read actual commitment data because it was missing
the deriveHashedKeys call that HexPatriciaHashed.unfoldBranchNode uses
to reconstruct hashed nibble paths from plain keys stored in branch data.

Key changes:
- TrieReader now calls deriveHashedKeys on parsed cells (keccak hashing
  plain accountAddr/storageAddr to recover the full hashed extension)
- Fixed storage lookups: account cells with hash at depth < 64 continue
  into the storage sub-trie instead of returning prematurely
- Added exported cell accessor methods for external callers
- NewTrieReader takes accountKeyLen parameter
- All mock tests updated to use hash-consistent data
- Added TestTrieReader_RoundTripWithHPH: verifies accounts + storage
  lookups against real HexPatriciaHashed.Process output
- Added TestTrieReader_RoundTripWithHPH_ManyAccounts: 100 accounts
- Fixed db/state integration test: 200/200 accounts, 100/100 storage
- Added NewTrieContextRo to commitmentdb for read-only branch access
@awskii awskii requested a review from sudeepdino008 as a code owner April 10, 2026 17:33
awskii added 3 commits April 10, 2026 19:52
…deBranch refactor

Update TrieReader and tests for API changes from main:
- HexNibblesToCompactBytes → nibbles.HexToCompact
- EncodeBranch callback → *[16]cellEncodeData array
…ation

- Remove completed/plan.md (obsolete, pseudocode mismatched implementation)
- Add nibble bounds check in Lookup (validates hashedKey[depth] <= 0x0f)
- parseCellAt errors already include depth+nibble context from prior commit
@awskii awskii added this pull request to the merge queue Apr 11, 2026
Merged via the queue into main with commit d84a312 Apr 11, 2026
35 checks passed
@awskii awskii deleted the awskii/trie-reader branch April 11, 2026 11:15
@awskii awskii removed a link to an issue Apr 14, 2026
14 tasks
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.

3 participants