Skip to content

merkledb -- rewrite and test range proof invariants; fix proof generation/veriifcation bugs #1629

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

Merged
merged 22 commits into from
Jun 28, 2023

Conversation

danlaine
Copy link

@danlaine danlaine commented Jun 16, 2023

Why this should be merged

Yay code quality and testing

How this works

  • Rewrites range proof invariant for clarity
  • Adds test for range proof invariants
  • Fixes bug when generating/verifying a range proof whose greatest key has length 0

How this was tested

New UT

@danlaine danlaine added bug Something isn't working DO NOT MERGE This PR must not be merged in its current state merkledb labels Jun 16, 2023
@danlaine danlaine requested a review from darioush as a code owner June 16, 2023 20:23
@danlaine danlaine self-assigned this Jun 16, 2023
@danlaine danlaine requested a review from dboehm-avalabs as a code owner June 16, 2023 20:23
@@ -300,12 +305,12 @@ func (proof *RangeProof) Verify(
return err
}

largestkey := end
largestKey := end
Copy link
Author

Choose a reason for hiding this comment

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

nit to use camelCase

@@ -167,6 +167,7 @@ func (proof *Proof) Verify(ctx context.Context, expectedRootID ids.ID) error {
return ErrProofValueDoesntMatch
}

// Don't bother locking [view] -- nobody else has a reference to it.
Copy link
Author

Choose a reason for hiding this comment

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

Moved from below since it makes more sense to be here

// Empty if the request for this range proof gave no upper bound
// on the range to fetch, unless this proof contains no [KeyValues]
// and [StartProof] is empty.
// If no upper range bound was given, [KeyValues] is empty,
Copy link
Author

Choose a reason for hiding this comment

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

Rewritten to make the invariants more clear

Comment on lines +763 to +764
insertChildrenLessThan Maybe[path],
insertChildrenGreaterThan Maybe[path],
Copy link
Author

@danlaine danlaine Jun 20, 2023

Choose a reason for hiding this comment

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

Now uses a Maybe to properly handle the case where we're verifying a proof that contains only the root. Namely, suppose that we had a range proof for range [nil, [0]] where the only key-value pair in the proof is for the root, but the database resulting in the proof has more key-value pairs. In RangeProof.Verify we set largestPath to the empty path and called addPathInfo with startPath and endPath both the empty root. This causes hasLowerBound and hasUpperBound in addPathInfo to be false, and we did not add children greater than the root (the empty path), resulting in proof verification failing.

In other words, we need to use a Maybe to disambiguate between the case where the largest key in the proof is at the root and the case where we shouldn't add any proof node children on the "right" side.

Comment on lines +442 to +458
var (
endProof *Proof
err error
)
if len(result.KeyValues) > 0 {
end = result.KeyValues[len(result.KeyValues)-1].Key
}

if len(end) > 0 {
endProof, err := t.getProof(ctx, end)
greatestKey := result.KeyValues[len(result.KeyValues)-1].Key
endProof, err = t.getProof(ctx, greatestKey)
if err != nil {
return nil, err
}
} else if len(end) > 0 {
endProof, err = t.getProof(ctx, end)
if err != nil {
return nil, err
}
}
if endProof != nil {
Copy link
Author

Choose a reason for hiding this comment

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

The old code could violate a RangeProof.EndProof invariant. Namely, if KeyValues contained only the root, we would not set result.EndProof.

@danlaine danlaine removed the DO NOT MERGE This PR must not be merged in its current state label Jun 20, 2023
@danlaine danlaine changed the title Rewrite and testing range proof invariants merkledb -- rewrite and test range proof invariants; fix proof generation/veriifcation bugs Jun 20, 2023
x/merkledb/db.go Outdated
Comment on lines 1066 to 1067
// For all the nodes along the edges of the proof, insert children
// < [insertChildrenLessThan] and > [insertChildrenGreaterThan]
Copy link
Contributor

Choose a reason for hiding this comment

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

During the hackathon I found this comment super confusing.... specifically the < and >.

Suggested change
// For all the nodes along the edges of the proof, insert children
// < [insertChildrenLessThan] and > [insertChildrenGreaterThan]
// For all the nodes along the edges of the proof, insert the children whose
// keys are less than [insertChildrenLessThan] or whose keys are greater
// than [insertChildrenGreaterThan]

Comment on lines +1070 to +1072
if len(smallestPath) > 0 {
insertChildrenLessThan = Some(smallestPath)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems pretty suspicious... Should start and end be Maybe types being passed into this function?

Copy link
Author

Choose a reason for hiding this comment

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

done in #1657

if err != nil {
return nil, err
}
} else if len(end) > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like this could would be a lot easier to understand if we just passed start, end Maybe[[]byte] rather than doing this len([]byte) > 0 stuff

Copy link
Author

Choose a reason for hiding this comment

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

done in #1657

@patrick-ogrady
Copy link
Contributor

patrick-ogrady commented Jun 28, 2023

Running on HyperSDK sync tests: ava-labs/hypersdk#227

It passed.

@StephenButtolph StephenButtolph merged commit 99a5f5a into dev Jun 28, 2023
@StephenButtolph StephenButtolph deleted the merkledb-test-range-proof-invariants branch June 28, 2023 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working merkledb
Projects
No open projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants