Skip to content

Conversation

@rkuris
Copy link
Member

@rkuris rkuris commented Apr 12, 2025

This is part 2 of 3 for change proofs, and contains the bulk of the work. The remaining changes involve calling these methods from the API to resolve #443.

Generates BatchOp operations representing the differences between two merkle tries, with an optional start key. Sub-tries with identical hashes are skipped.

The two main structures are DiffMerkleKeyValueStreams which manages the dual trie iteration and holds the pending values, and DiffIteratorState which keeps track of which values are saved because they haven't been matched to the other trie yet.

Algorithm:

  1. Iterates through both trees simultaneously from optional start key
  2. Compares keys lexicographically to determine operation type
  3. Generate Put operations for additions/modifications
  4. Generate Delete operations for removals
  5. Saves out-of-order values in iterator state for next iteration
  6. Optimizes by skipping subtrees with matching hashes (when possible)

@rkuris rkuris force-pushed the rkuris/change-proofs branch 2 times, most recently from c2035b5 to 7a1242e Compare April 16, 2025 21:11
@rkuris rkuris force-pushed the rkuris/change-proofs branch from 3961602 to 9c8aab4 Compare June 7, 2025 17:15
@rkuris rkuris changed the title Framework for change proofs feat(diff): Framework for change proofs Jun 7, 2025
@rkuris rkuris self-assigned this Jun 7, 2025
@rkuris rkuris linked an issue Jun 7, 2025 that may be closed by this pull request
@rkuris rkuris force-pushed the rkuris/change-proofs branch from 9c8aab4 to 05fb244 Compare June 7, 2025 17:52
@rkuris rkuris requested a review from alarso16 June 7, 2025 17:52
@rkuris rkuris marked this pull request as ready for review June 7, 2025 17:53
@rkuris rkuris requested a review from aaronbuchwald as a code owner June 7, 2025 17:53
@rkuris rkuris removed a link to an issue Jun 7, 2025
@rkuris rkuris added the enhancement New feature or request label Jun 7, 2025
@rkuris rkuris added this to the libevm integration milestone Jun 7, 2025
@rkuris rkuris force-pushed the rkuris/change-proofs branch from 0f0f65b to 6595ba7 Compare June 9, 2025 20:25
@rkuris rkuris marked this pull request as draft June 9, 2025 23:31
rkuris added 2 commits June 10, 2025 15:41
Unoptimized version for reference, with some tests
Generates BatchOp operations representing the differences between two
merkle tries, with an optional start key. Sub-tries with identical
hashes are skipped.

The two main structures are DiffMerkleKeyValueStreams which manages the
dual trie iteration and holds the pending values, and DiffIteratorState
which keeps track of which values are saved because they haven't been
matched to the other trie yet.

Algorithm:
1. Iterates through both trees simultaneously from optional start key
2. Compares keys lexicographically to determine operation type
3. Generate Put operations for additions/modifications
4. Generate Delete operations for removals
5. Saves out-of-order values in iterator state for next iteration
6. Optimizes by skipping subtrees with matching hashes (when possible)

Testing:
There are basic tests and a fuzz test. If the test fails, instructions
on how to rerun it with the correct seed are provided in the error
output. This follows the same pattern as the merkle fuzz tests.
@rkuris rkuris force-pushed the rkuris/change-proofs branch 2 times, most recently from 78dffbb to 10dbdf1 Compare June 10, 2025 22:56
@rkuris rkuris marked this pull request as ready for review June 10, 2025 22:57
@rkuris rkuris force-pushed the rkuris/change-proofs branch from 10dbdf1 to 27698b4 Compare June 10, 2025 23:01
Took a slightly different approach, since the previous diff didn't
use the optimized node iterator, and didn't even check for it.

Other changes:
 - Renamed children_have_same_hash() to child_identical()
 - Added documentation around more complicated functions
 - Added additional tests to verify that fewer nodes are read when
   diffing tries with hashes already computed
 - Installed a test metrics recorder so metrics can be checked at
   runtime

Note that if we add additional tests that want to use this metrics
recorder, we would need to put this into a utility method and save it in
case some other test initializes the metrics.
@rkuris rkuris force-pushed the rkuris/change-proofs branch from 27698b4 to 3a4032d Compare June 11, 2025 05:16
Comment on lines 51 to 58
impl fmt::Debug for VisitedPairState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("VisitedPairState")
.field("children_iter_left", &"<iterator>")
.field("children_iter_right", &"<iterator>")
.finish()
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We can use derivative to clean up these manually implemented Debugs.

@rkuris
Copy link
Member Author

rkuris commented Jun 11, 2025

Group review comments:

  • Can eliminate the boilerplate code for the debug implementations with a crate @demosdemon knows about
  • Should better document each of the types, especially around understanding how you get in the state. Diagram?
  • The giant match statement is too hard cognitively to see the algorithm, so let's add more helper methods on DiffIterationState

@rkuris rkuris marked this pull request as draft June 12, 2025 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Change proof support

2 participants