Skip to content

trie/bintrie: fix grouped InternalNode serialization path mismatch#569

Merged
gballet merged 2 commits intogballet:binary-tree-with-pagesfrom
CPerezz:fix/stemnode-group-path-mismatch
Mar 10, 2026
Merged

trie/bintrie: fix grouped InternalNode serialization path mismatch#569
gballet merged 2 commits intogballet:binary-tree-with-pagesfrom
CPerezz:fix/stemnode-group-path-mismatch

Conversation

@CPerezz
Copy link
Copy Markdown
Collaborator

@CPerezz CPerezz commented Feb 25, 2026

When a StemNode appears at an intermediate depth within a grouped InternalNode, collectChildGroups stored it at its actual depth path (e.g., [0,0] for depth 2), but serializeSubtree projected its hash to the group leaf boundary using stem key bits. After deserialization, the HashedNode ended up at the projected depth, causing lookup path mismatches and "missing trie node" errors.

Two fixes:

  1. serializeSubtree: use stem key bits (not all-left) to project StemNodes to their correct bitmap leaf position
  2. collectChildGroups: extend the storage path to match the projected leaf position using the same stem-bit extension

This ensures the storage path matches the lookup path generated by keyToPath in InsertValuesAtStem/GetValuesAtStem after deserialization.

Fixes missing trie node errors for groupDepth values 1-3 with large state databases.


Review updates:

  • Trimmed PR to only the serialization fix (removed unrelated slow-block metrics commit)
  • Added comment explaining why groupDepth byte is serialized (sparse bottom layer)
  • Made HashedNode handling explicit with named type switch case

@CPerezz CPerezz requested a review from gballet as a code owner February 25, 2026 22:49
@gballet gballet force-pushed the binary-tree-with-pages branch from 95a6188 to 2ffd285 Compare March 6, 2026 18:58
Copy link
Copy Markdown
Owner

@gballet gballet left a comment

Choose a reason for hiding this comment

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

leaving some comments ahead of your cleanup. The PR name should be changed, imo, as it seems to concern InternalNodes and not StemNodes, iiuc.

Comment thread trie/bintrie/trie.go
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

this shouldn't happen, and so I recommend either returning an error or panicking, because this is a criticial flaw if that happens.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed — this should be a hard error. However, this code is from the base branch (binary-tree-with-pages), not from this PR's fix. I've trimmed this PR to only the serialization path fix. Happy to open a separate PR for the groupDepth validation if you'd like.

Comment thread triedb/database.go
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

same here, it should panic because whatever situation brought this turn of events should be immediately flagged

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Same as above — this is base branch code. Removed from this PR's scope. Can address in a follow-up.

Comment thread trie/bintrie/binary_node.go
Comment thread trie/bintrie/binary_node.go
serializeSubtree(n.left, remainingDepth-1, leftPos, bitmap, hashes)
serializeSubtree(n.right, remainingDepth-1, rightPos, bitmap, hashes)
serializeSubtree(n.left, remainingDepth-1, leftPos, absoluteDepth+1, bitmap, hashes)
serializeSubtree(n.right, remainingDepth-1, rightPos, absoluteDepth+1, bitmap, hashes)
case Empty:
// Empty subtree: all positions in this subtree are empty (bits already 0)
return
default:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

aren't you handling HashedNode ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

You're right that HashedNode was implicit. Refactored the default case into an explicit type switch: *StemNode extends using stem key bits, and the fallback (HashedNode/unknown) extends all-left via position << remainingDepth. The all-left extension is correct for HashedNode because we don't have key bits to follow — it matches the all-zero path that resolveNode would take.

@CPerezz CPerezz force-pushed the fix/stemnode-group-path-mismatch branch from 371cb9e to 3f9bb49 Compare March 10, 2026 13:50
@CPerezz CPerezz changed the title trie/bintrie: fix StemNode storage path mismatch in grouped serialization trie/bintrie: fix grouped InternalNode serialization path mismatch Mar 10, 2026
CPerezz added 2 commits March 10, 2026 14:52
…tion

When a StemNode appears at an intermediate depth within a grouped
InternalNode, collectChildGroups stored it at its actual depth path
(e.g., [0,0] for depth 2), but serializeSubtree projected its hash
to the group leaf boundary using stem key bits. After deserialization,
the HashedNode ended up at the projected depth, causing lookup path
mismatches and "missing trie node" errors.

Two fixes:
1. serializeSubtree: use stem key bits (not all-left) to project
   StemNodes to their correct bitmap leaf position
2. collectChildGroups: extend the storage path to match the projected
   leaf position using the same stem-bit extension

This ensures the storage path matches the lookup path generated by
keyToPath in InsertValuesAtStem/GetValuesAtStem after deserialization.

Fixes missing trie node errors for groupDepth values 1-3 with large
state databases.
- Add comment explaining why groupDepth byte is serialized (sparse
  bottom layer makes bitmap size variable)
- Make HashedNode handling explicit with named type switch case
  instead of hiding it in the if/else fallthrough
@CPerezz CPerezz force-pushed the fix/stemnode-group-path-mismatch branch from 3f9bb49 to ada64c9 Compare March 10, 2026 13:52
@gballet gballet merged commit c596e50 into gballet:binary-tree-with-pages Mar 10, 2026
1 check passed
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