-
Notifications
You must be signed in to change notification settings - Fork 990
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PMMR segment creation and validation #3453
Conversation
Quick question that occurred to me reading over the PR description (nice description by the way!) -
Does it potentially make more sense to provide a "starting leaf index" as segment identifier? The current "segment index" is heavily dependent on the "segment size". Clearly you can translate between these easily enough but it may make sense to identify these based on both number of leaves via |
Is the intention to have these segments be self-contained? For pruned MMR (outputs and rangeproofs) do we also provide the bitmap or is the assumption we already have the corresponding bitmap segment? |
(apologies for the barrage of questionable feedback here...) 😄 |
Not at all! I think they highlight some of the subtleties in the PR so it is good that they are discussed explicitly. |
Just posting here for reference -
|
Fixed an edge case: if there is an uneven number of leaves, and the final leaf is spent, we still require it to be present in the final segment. Previously we only checked the bitmap for it and its (non-existent) sibling, which are both 0. This led us to assume they were pruned, but this is not the case. This was actually caught by the pruning test in |
We now support pruned segments. The In order to find the first parent up the path to the peak that is unpruned, the new I've also added a bunch of tests to make sure it behaves as expected for full segments and doesn't affect the partially filled final segment. |
👍 Sounds good - I'm planning to take a closer look at this today. |
This looks good. Want to move it out of Draft status? Just one minor point/question -
Do we need to have |
You are right, we don't really need to return a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're looking good here with this. 👍
What else is outstanding before we can merge?
I'm working on the deser of bitmap segments in this PR, but it probably makes more sense to do that in a separate one. I think we can merge this. |
🎉 |
) * Chunk generation and validation * Rename chunk -> segment * Missed a few * Generate and validate merkle proof * Fix bugs in generation and validation * Add test for unprunable MMR of various sizes * Add missing docs * Remove unused functions * Remove segment error variant on chain error type * Simplify calculation by using a Vec instead of HashMap * Use vectors in segment definition * Compare subtree root during tests * Add test of segments for a prunable mmr * Remove assertion * Only send intermediary hashes for prunable MMRs * Get hash from file directly * Require both leaves if one of them is not pruned * More pruning tests * Add segment (de)serialization * Require sorted vectors in segment deser * Store pos and data separately in segment * Rename log_size -> height * Fix bitmap index in root calculation * Add validation function for output (bitmap) MMRs * Remove left over debug statements * Fix test * Edge case: final segment with uneven number of leaves * Use last_pos instead of segment_last_pos * Simplify pruning in test * Add leaf and hash iterators * Support fully pruned segments * Drop backend before deleting dir in pruned_segment test * Simplify output of first_unpruned_parent
This PR implements a (P)MMR "segment", defined by this WIP RFC. In short, a segment is a set of
2**b
(with variableb
) consecutive leaves along with the necessary data to reconstruct the subtree root and data to verify membership of the subtree in the original MMR (a Merkle proof). In case of a prunable MMR, the segment only contains the unpruned leaves in the segment range and also contains intermediary MMR hashes that are necessary to construct the segment root.Concretely, a segment consist of the following elements:
b
, the 2-log of the size of the number of leaves (before pruning) and a zero-based segment indexidx
[i*2**b, (i+1)*2**b)
), sorted by MMR position in ascending order.Given that a segment contains a number of leaves that is a power of 2, a full segment forms a full subtree in the MMR and as such it has a single root. The final segment possibly has less than
2**b
elements. In this case the peaks in the segment are also peaks in the full MMR and we define its root as these peaks bagged together.Segment creation
A segment is created by looping over all the MMR positions in the segment range. If the position is an unpruned leaf or its subling is an unpruned leaf, add it to the leaf data list. If not, check if its hash is unpruned and add it to the list of hashes. Next, generate the merkle proof by filling a list of hashes with:
Note that this procedure will also behave as expected for the partially filled final segment, since in that case step and 1 and 2 will not produce any hashes and step 3 will give us all the other peaks in the MMR.
Segment verification
Iterate over all the MMR positions in the segment range. If the position is a leaf: check (for prunable MMRs) to see if the element is expected to be there (based on presence of the element or its sibling in the bitmap) and if it is get it from the list of leaves, hash it and store the hash in a list of temporary hashes.
For all other positions: if both children are not present in the list of temporary hashes (i.e. they are both pruned), do nothing. If either or both hashes are present in the list, hash them together and store the new hash in the list of temporary hashes. If only one of the children was present, obtain the hash of the other child from the list of hashes in the segment instead.
After looping through all positions, we are either left with 1 entry (full segment) or multiple entries (partially filled, final segment) in the list of temporary hashes. If there are multiple, bag them together. We are left with the segment root.
Next, verify the proof by attempting to reproduce the MMR root hash: first, hash together with the siblings along the path from the subtree root to its peak in the MMR, then hash it together with the bagged peaks to the right and finally hash it together with the peaks on the left (going right to left). Verification passes if the calculated hash is equal to the MMR root hash.
Open points before merging
In case of a heavily pruned MMR, is this data always sufficient to reconstruct the full pruned MMR? Or would we miss any intermediary hashes?Yes, now that we added support for fully pruned segments.I think we need a function to extract the intermediary and proof hashes for purposes of storing them in the MMR we are buildingTBD in a future PRWould it be more natural to pass in a bitmap indicating the spent or the unspent positions?UnspentIs bitmap/leaf index 0-based (should be a quick check)Yes, it is.