Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
42ad6b6
WIP rewriting and testing range proof invariants
Jun 16, 2023
fbfcac5
WIP rewriting and testing range proof invariants
Jun 16, 2023
675b54e
appease linter
Jun 20, 2023
8146839
Merge remote-tracking branch 'upstream/dev' into merkledb-test-range-…
Jun 20, 2023
5cb9092
fix/remove TODOs
Jun 20, 2023
4f4bf1f
add if branch to prevent nil pointer panic
Jun 20, 2023
0b08de4
fix range proof verification
Jun 20, 2023
60729be
nits
Jun 20, 2023
4e1518e
nits
Jun 20, 2023
5efda97
make range proof invariant test into fuzzing test
Jun 20, 2023
158e5c3
Merge branch 'dev' into merkledb-test-range-proof-invariants
Jun 20, 2023
0ebe0da
Merge branch 'dev' into merkledb-test-range-proof-invariants
Jun 21, 2023
babd9a6
Merge branch 'dev' into merkledb-test-range-proof-invariants
Jun 26, 2023
622199a
nits
Jun 26, 2023
80e67d0
Merge branch 'merkledb-test-range-proof-invariants' of github.com:ava…
Jun 26, 2023
fa67360
comment nits
Jun 26, 2023
7e02d8c
WIP use Maybe for bounds
Jun 26, 2023
e813fc3
WIP use Maybe for bounds
Jun 26, 2023
c469d74
it compiles
Jun 26, 2023
712147d
fix todo
Jun 26, 2023
f1734b1
fix todo
Jun 26, 2023
6804f8c
fix test
Jun 26, 2023
98793ee
nits
Jun 26, 2023
5645e48
nits
Jun 26, 2023
222778f
fix inverted condition
Jun 26, 2023
c4dc815
add proto validation
Jun 26, 2023
02a9ae5
fix test
Jun 26, 2023
b4d7932
fix test and syncWorkHeap.MergeInsert
Jun 26, 2023
42dc875
appease linter
Jun 26, 2023
5cf991b
Merge remote-tracking branch 'upstream/dev' into merkledb-test-range-…
Jun 27, 2023
091f282
add test
Jun 27, 2023
fae5fad
Merge remote-tracking branch 'upstream/dev' into merkledb-test-range-…
Jun 27, 2023
0079566
Merge branch 'merkledb-test-range-proof-invariants' into merkledb-may…
Jun 27, 2023
089e65d
formatting
Jun 27, 2023
4d4cf7d
comments on completeWorkItem
Jun 27, 2023
ecae4aa
nit
Jun 27, 2023
00ce558
fix findNextKey by handling 0 length end proof
Jun 27, 2023
66707f7
add comment
Jun 27, 2023
69a4a0b
appease linter
Jun 27, 2023
7bbe562
comments
Jun 27, 2023
7d2f9c6
comments
Jun 27, 2023
026c6c4
comments
Jun 27, 2023
5f20adf
nits
Jun 27, 2023
6697168
nit
Jun 27, 2023
d3607bc
remove nil check
Jun 27, 2023
4aaae86
remove nil check for range proof requests
Jun 27, 2023
81f01a9
tweak test
Jun 27, 2023
bfa0286
tweak test
Jun 27, 2023
dfa03b6
comment
Jun 27, 2023
f51f79b
add Maybe.String()
Jun 27, 2023
43d797c
appease linter
Jun 27, 2023
937a375
comment
Jun 27, 2023
273c7b4
nits
Jun 27, 2023
de3ad8b
Merge remote-tracking branch 'upstream/dev' into merkledb-maybe-proof…
Jun 28, 2023
d5054d1
Merge remote-tracking branch 'upstream/dev' into merkledb-test-range-…
Jun 28, 2023
b61f9e0
Merge branch 'merkledb-test-range-proof-invariants' into merkledb-may…
Jun 28, 2023
75697fd
nit
Jun 28, 2023
99de404
nit
Jun 28, 2023
d702662
nits
Jun 28, 2023
2a49496
nit
Jun 28, 2023
85230ae
Improve `if` statement readability (#1664)
Jun 28, 2023
47269ee
Merge remote-tracking branch 'upstream/dev' into merkledb-maybe-proof…
Jun 29, 2023
0b45f4e
Merge branch 'merkledb-maybe-proof-bounds' of github.com:ava-labs/ava…
Jun 29, 2023
16c9920
Merge branch 'dev' into merkledb-maybe-proof-bounds
Jun 29, 2023
914dc47
Merge branch 'dev' into merkledb-maybe-proof-bounds
Jun 29, 2023
724d47e
Merge remote-tracking branch 'upstream/dev' into merkledb-maybe-proof…
Jun 30, 2023
4c353e1
Merge branch 'merkledb-maybe-proof-bounds' of github.com:ava-labs/ava…
Jun 30, 2023
a06bd82
Merge remote-tracking branch 'upstream/dev' into merkledb-maybe-proof…
Jun 30, 2023
ea98073
nit
Jun 30, 2023
277f112
Merge remote-tracking branch 'upstream/dev' into merkledb-maybe-proof…
Jun 30, 2023
25911b5
Merge branch 'dev' into merkledb-maybe-proof-bounds
Jun 30, 2023
2f31123
Merge branch 'dev' into merkledb-maybe-proof-bounds
StephenButtolph Jul 12, 2023
961f0b9
fix end > start bound checks
Jul 13, 2023
fa4347f
IsNothing() --> not hasValue for consistency
Jul 13, 2023
e2b3baa
make largestKey a Maybe in VerifyChangeProof
Jul 13, 2023
6b3531d
parameterize midPoint on maybe
Jul 13, 2023
8390771
fix end > start bound checks
Jul 13, 2023
767b929
add comment
Jul 13, 2023
c4d5fbd
make start key in CommitRangeProof a Maybe
Jul 13, 2023
0a8f4e3
add equality function for Maybe[[]byte]
Jul 13, 2023
507a182
Merge remote-tracking branch 'upstream/dev' into merkledb-maybe-proof…
Jul 13, 2023
1533f85
make nextKey in findNextKey a Maybe
Jul 13, 2023
a3453ea
Merge remote-tracking branch 'upstream/dev' into merkledb-maybe-proof…
Jul 14, 2023
57bc445
make verifyKeyValues same as verifyKeyChanges
Jul 14, 2023
7c57683
Merge branch 'dev' into merkledb-maybe-proof-bounds
Jul 14, 2023
3a15f68
Merge remote-tracking branch 'upstream/dev' into merkledb-maybe-proof…
Jul 18, 2023
2591c2b
Merge branch 'merkledb-maybe-proof-bounds' of github.com:ava-labs/ava…
Jul 18, 2023
5bbe098
Merge remote-tracking branch 'upstream/dev' into merkledb-maybe-proof…
Jul 18, 2023
d732bc6
revert errant changes
Jul 18, 2023
d2da07f
unify style for start Maybe[[]byte], end Maybe[[]byte] params
Jul 18, 2023
5c934ca
fix comment
Jul 18, 2023
f708c34
add nil checks
Jul 18, 2023
c9b6bb4
Merge branch 'dev' into merkledb-maybe-proof-bounds
Jul 18, 2023
0129ce9
Merge branch 'dev' into merkledb-maybe-proof-bounds
Jul 20, 2023
2e1270a
Merge remote-tracking branch 'upstream/dev' into merkledb-maybe-proof…
Aug 1, 2023
df42980
Merge branch 'merkledb-maybe-proof-bounds' of github.com:ava-labs/ava…
Aug 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
477 changes: 250 additions & 227 deletions proto/pb/sync/sync.pb.go

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions proto/sync/sync.proto
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ message Proof {
message SyncGetChangeProofRequest {
bytes start_root_hash = 1;
bytes end_root_hash = 2;
bytes start_key = 3;
bytes end_key = 4;
MaybeBytes start_key = 3;
MaybeBytes end_key = 4;
uint32 key_limit = 5;
uint32 bytes_limit = 6;
}
Expand All @@ -70,15 +70,15 @@ message SyncGetChangeProofResponse {
message GetChangeProofRequest {
bytes start_root_hash = 1;
bytes end_root_hash = 2;
bytes start_key = 3;
bytes end_key = 4;
MaybeBytes start_key = 3;
MaybeBytes end_key = 4;
uint32 key_limit = 5;
}

message VerifyChangeProofRequest {
ChangeProof proof = 1;
bytes start_key = 2;
bytes end_key = 3;
MaybeBytes start_key = 2;
MaybeBytes end_key = 3;
bytes expected_root_hash = 4;
}

Expand All @@ -95,16 +95,16 @@ message CommitChangeProofRequest {
// the response. GetRangeProof in the DB service doesn't.
message SyncGetRangeProofRequest {
bytes root_hash = 1;
bytes start_key = 2;
bytes end_key = 3;
MaybeBytes start_key = 2;
MaybeBytes end_key = 3;
uint32 key_limit = 4;
uint32 bytes_limit = 5;
}

message GetRangeProofRequest {
bytes root_hash = 1;
bytes start_key = 2;
bytes end_key = 3;
MaybeBytes start_key = 2;
MaybeBytes end_key = 3;
uint32 key_limit = 4;
}

Expand All @@ -113,7 +113,7 @@ message GetRangeProofResponse {
}

message CommitRangeProofRequest {
bytes start_key = 1;
MaybeBytes start_key = 1;
RangeProof range_proof = 2;
}

Expand Down
88 changes: 47 additions & 41 deletions x/merkledb/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ type ChangeProofer interface {
ctx context.Context,
startRootID ids.ID,
endRootID ids.ID,
start []byte,
end []byte,
start Maybe[[]byte],
end Maybe[[]byte],
maxLength int,
) (*ChangeProof, error)

Expand All @@ -82,8 +82,8 @@ type ChangeProofer interface {
VerifyChangeProof(
ctx context.Context,
proof *ChangeProof,
start []byte,
end []byte,
start Maybe[[]byte],
end Maybe[[]byte],
expectedEndRootID ids.ID,
) error

Expand All @@ -97,14 +97,14 @@ type RangeProofer interface {
GetRangeProofAtRoot(
ctx context.Context,
rootID ids.ID,
start,
end []byte,
start Maybe[[]byte],
end Maybe[[]byte],
maxLength int,
) (*RangeProof, error)

// CommitRangeProof commits the key/value pairs within the [proof] to the db.
// [start] is the smallest key in the range this [proof] covers.
CommitRangeProof(ctx context.Context, start []byte, proof *RangeProof) error
CommitRangeProof(ctx context.Context, start Maybe[[]byte], proof *RangeProof) error
}

type MerkleDB interface {
Expand Down Expand Up @@ -308,7 +308,7 @@ func (db *merkleDB) CommitChangeProof(ctx context.Context, proof *ChangeProof) e
return view.commitToDB(ctx)
}

func (db *merkleDB) CommitRangeProof(ctx context.Context, start []byte, proof *RangeProof) error {
func (db *merkleDB) CommitRangeProof(ctx context.Context, start Maybe[[]byte], proof *RangeProof) error {
db.commitLock.Lock()
defer db.commitLock.Unlock()

Expand Down Expand Up @@ -476,12 +476,13 @@ func (db *merkleDB) getProof(ctx context.Context, key []byte) (*Proof, error) {
return view.getProof(ctx, key)
}

// GetRangeProof returns a proof for the key/value pairs in this trie within the range
// [start, end].
// GetRangeProof returns a proof for the key/value pairs in this trie within the range [start, end].
// If [start] is Nothing, there's no lower bound on the range.
// If [end] is Nothing, there's no upper bound on the range.
func (db *merkleDB) GetRangeProof(
ctx context.Context,
start,
end []byte,
start Maybe[[]byte],
end Maybe[[]byte],
maxLength int,
) (*RangeProof, error) {
db.commitLock.RLock()
Expand All @@ -492,11 +493,13 @@ func (db *merkleDB) GetRangeProof(

// GetRangeProofAtRoot returns a proof for the key/value pairs in this trie within the range
// [start, end] when the root of the trie was [rootID].
// If [start] is Nothing, there's no lower bound on the range.
// If [end] is Nothing, there's no upper bound on the range.
func (db *merkleDB) GetRangeProofAtRoot(
ctx context.Context,
rootID ids.ID,
start,
end []byte,
start Maybe[[]byte],
end Maybe[[]byte],
maxLength int,
) (*RangeProof, error) {
db.commitLock.RLock()
Expand All @@ -509,8 +512,8 @@ func (db *merkleDB) GetRangeProofAtRoot(
func (db *merkleDB) getRangeProofAtRoot(
ctx context.Context,
rootID ids.ID,
start,
end []byte,
start Maybe[[]byte],
end Maybe[[]byte],
maxLength int,
) (*RangeProof, error) {
if db.closed {
Expand All @@ -531,11 +534,11 @@ func (db *merkleDB) GetChangeProof(
ctx context.Context,
startRootID ids.ID,
endRootID ids.ID,
start []byte,
end []byte,
start Maybe[[]byte],
end Maybe[[]byte],
maxLength int,
) (*ChangeProof, error) {
if len(end) > 0 && bytes.Compare(start, end) == 1 {
if start.hasValue && end.hasValue && bytes.Compare(start.value, end.value) > 0 {
return nil, ErrStartAfterEnd
}
if startRootID == endRootID {
Expand Down Expand Up @@ -584,7 +587,7 @@ func (db *merkleDB) GetChangeProof(

largestKey := end
if len(result.KeyChanges) > 0 {
largestKey = result.KeyChanges[len(result.KeyChanges)-1].Key
largestKey = Some(result.KeyChanges[len(result.KeyChanges)-1].Key)
}

// Since we hold [db.commitlock] we must still have sufficient
Expand All @@ -594,16 +597,16 @@ func (db *merkleDB) GetChangeProof(
return nil, err
}

if len(largestKey) > 0 {
endProof, err := historicalView.getProof(ctx, largestKey)
if largestKey.hasValue {
endProof, err := historicalView.getProof(ctx, largestKey.value)
if err != nil {
return nil, err
}
result.EndProof = endProof.Path
}

if len(start) > 0 {
startProof, err := historicalView.getProof(ctx, start)
if start.hasValue {
startProof, err := historicalView.getProof(ctx, start.value)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -957,11 +960,11 @@ func (*merkleDB) CommitToDB(context.Context) error {
func (db *merkleDB) VerifyChangeProof(
ctx context.Context,
proof *ChangeProof,
start []byte,
end []byte,
start Maybe[[]byte],
end Maybe[[]byte],
expectedEndRootID ids.ID,
) error {
if len(end) > 0 && bytes.Compare(start, end) > 0 {
if start.hasValue && end.hasValue && bytes.Compare(start.value, end.value) > 0 {
return ErrStartAfterEnd
}

Expand All @@ -978,10 +981,10 @@ func (db *merkleDB) VerifyChangeProof(
switch {
case proof.Empty():
return ErrNoMerkleProof
case len(end) > 0 && len(proof.EndProof) == 0:
case end.hasValue && len(proof.EndProof) == 0:
// We requested an end proof but didn't get one.
return ErrNoEndProof
case len(start) > 0 && len(proof.StartProof) == 0 && len(proof.EndProof) == 0:
case start.hasValue && len(proof.StartProof) == 0 && len(proof.EndProof) == 0:
// We requested a start proof but didn't get one.
// Note that we also have to check that [proof.EndProof] is empty
// to handle the case that the start proof is empty because all
Expand All @@ -994,7 +997,7 @@ func (db *merkleDB) VerifyChangeProof(
return err
}

smallestPath := newPath(start)
smallestPath := newPath(start.value)
Copy link
Contributor

Choose a reason for hiding this comment

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

TODO: what does this look like when !start.hasValue

Copy link
Author

Choose a reason for hiding this comment

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

It's the empty path, which is what it was before this PR, because of the invariant on value: If [hasValue] is false, [value] is the zero value of type T.


// Make sure the start proof, if given, is well-formed.
if err := verifyProofPath(proof.StartProof, smallestPath); err != nil {
Expand All @@ -1003,15 +1006,16 @@ func (db *merkleDB) VerifyChangeProof(

// Find the greatest key in [proof.KeyChanges]
// Note that [proof.EndProof] is a proof for this key.
// [largestPath] is also used when we add children of proof nodes to [trie] below.
largestKey := end
if len(proof.KeyChanges) > 0 {
// If [proof] has key-value pairs, we should insert children
// greater than [end] to ancestors of the node containing [end]
// so that we get the expected root ID.
largestKey = proof.KeyChanges[len(proof.KeyChanges)-1].Key
largestKey = Some(proof.KeyChanges[len(proof.KeyChanges)-1].Key)
}
largestPath := newPath(largestKey)

// Used when we add children of proof nodes to [trie] below.
largestPath := newPath(largestKey.value)

// Make sure the end proof, if given, is well-formed.
if err := verifyProofPath(proof.EndProof, largestPath); err != nil {
Expand Down Expand Up @@ -1166,11 +1170,13 @@ func (db *merkleDB) initializeRootIfNeeded() (ids.ID, error) {
}

// Returns a view of the trie as it was when it had root [rootID] for keys within range [start, end].
// If [start] is Nothing, there's no lower bound on the range.
// If [end] is Nothing, there's no upper bound on the range.
// Assumes [db.commitLock] is read locked.
func (db *merkleDB) getHistoricalViewForRange(
rootID ids.ID,
start []byte,
end []byte,
start Maybe[[]byte],
end Maybe[[]byte],
) (*trieView, error) {
currentRootID := db.getMerkleRoot()

Expand All @@ -1189,17 +1195,17 @@ func (db *merkleDB) getHistoricalViewForRange(
// Returns all keys in range [start, end] that aren't in [keySet].
// If [start] is nil, then the range has no lower bound.
// If [end] is nil, then the range has no upper bound.
func (db *merkleDB) getKeysNotInSet(start, end []byte, keySet set.Set[string]) ([][]byte, error) {
func (db *merkleDB) getKeysNotInSet(start Maybe[[]byte], end Maybe[[]byte], keySet set.Set[string]) ([][]byte, error) {
db.lock.RLock()
defer db.lock.RUnlock()

it := db.NewIteratorWithStart(start)
it := db.NewIteratorWithStart(start.value)
defer it.Release()

keysNotInSet := make([][]byte, 0, keySet.Len())
for it.Next() {
key := it.Key()
if len(end) != 0 && bytes.Compare(key, end) > 0 {
if !end.IsNothing() && bytes.Compare(key, end.value) > 0 {
break
}
if !keySet.Contains(string(key)) {
Expand Down Expand Up @@ -1314,7 +1320,7 @@ func (db *merkleDB) prepareChangeProofView(proof *ChangeProof) (*trieView, error
// Returns a new view atop [db] with the key/value pairs in [proof.KeyValues] added and
// any existing key-value pairs in the proof's range but not in the proof removed.
// Assumes [db.commitLock] is locked.
func (db *merkleDB) prepareRangeProofView(start []byte, proof *RangeProof) (*trieView, error) {
func (db *merkleDB) prepareRangeProofView(start Maybe[[]byte], proof *RangeProof) (*trieView, error) {
// Don't need to lock [view] because nobody else has a reference to it.
view, err := db.newUntrackedView(len(proof.KeyValues))
if err != nil {
Expand All @@ -1328,9 +1334,9 @@ func (db *merkleDB) prepareRangeProofView(start []byte, proof *RangeProof) (*tri
}
}

var largestKey []byte
largestKey := Nothing[[]byte]()
if len(proof.KeyValues) > 0 {
largestKey = proof.KeyValues[len(proof.KeyValues)-1].Key
largestKey = Some(proof.KeyValues[len(proof.KeyValues)-1].Key)
}
keysToDelete, err := db.getKeysNotInSet(start, largestKey, keys)
if err != nil {
Expand Down
Loading