Skip to content
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1d62cda
Add Maybe to end For some Methods
dboehm-avalabs Aug 2, 2023
aa84659
update sync messages
dboehm-avalabs Aug 2, 2023
4124fcd
Update client_test.go
dboehm-avalabs Aug 2, 2023
48100d4
more
dboehm-avalabs Aug 2, 2023
15bbbed
more
dboehm-avalabs Aug 2, 2023
02a6ec7
Update db.go
dboehm-avalabs Aug 2, 2023
4a7d224
fix network client and server
dboehm-avalabs Aug 2, 2023
3d44e2d
lint
dboehm-avalabs Aug 2, 2023
f931491
Merge branch 'dev' into MaybeBounds1
dboehm-avalabs Aug 2, 2023
716d27b
Merge branch 'dev' into MaybeBounds1
dboehm-avalabs Aug 2, 2023
06f7433
improve
dboehm-avalabs Aug 2, 2023
d2c0e6e
Merge branch 'MaybeBounds1' of https://github.com/ava-labs/avalancheg…
dboehm-avalabs Aug 2, 2023
869249c
Update proof_test.go
dboehm-avalabs Aug 2, 2023
c4d3100
Update db.go
dboehm-avalabs Aug 2, 2023
67df793
Update sync_test.go
dboehm-avalabs Aug 3, 2023
a005025
Update sync_test.go
dboehm-avalabs Aug 3, 2023
48f05c0
Update manager.go
dboehm-avalabs Aug 3, 2023
b5ec872
Update manager.go
dboehm-avalabs Aug 3, 2023
2a00683
Update manager.go
dboehm-avalabs Aug 3, 2023
2439323
Update manager.go
dboehm-avalabs Aug 3, 2023
20426dd
Merge branch 'dev' into MaybeBounds1
dboehm-avalabs Aug 3, 2023
9d5290b
merge
dboehm-avalabs Aug 3, 2023
f5be4fc
fix
dboehm-avalabs Aug 3, 2023
8d88e88
remove
dboehm-avalabs Aug 3, 2023
c6f57da
Merge branch 'dev' into MaybeBounds1
Aug 3, 2023
9cefc79
add maybe compare
dboehm-avalabs Aug 4, 2023
f174079
Merge branch 'MaybeBounds1' of https://github.com/ava-labs/avalancheg…
dboehm-avalabs Aug 4, 2023
b2a3bd8
Update maybe.go
dboehm-avalabs Aug 4, 2023
1885715
Merge branch 'dev' into MaybeBounds1
dboehm-avalabs Aug 4, 2023
1838bdc
comment
dboehm-avalabs Aug 7, 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
422 changes: 213 additions & 209 deletions proto/pb/sync/sync.pb.go

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions proto/sync/sync.proto
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ message SyncGetChangeProofRequest {
bytes start_root_hash = 1;
bytes end_root_hash = 2;
bytes start_key = 3;
bytes end_key = 4;
MaybeBytes end_key = 4;
uint32 key_limit = 5;
uint32 bytes_limit = 6;
}
Expand Down Expand Up @@ -96,7 +96,7 @@ message CommitChangeProofRequest {
message SyncGetRangeProofRequest {
bytes root_hash = 1;
bytes start_key = 2;
bytes end_key = 3;
MaybeBytes end_key = 3;
uint32 key_limit = 4;
uint32 bytes_limit = 5;
}
Expand Down
39 changes: 19 additions & 20 deletions x/merkledb/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ type ChangeProofer interface {
// - [proof] is non-empty iff [proof.HadRootsInHistory].
// - All keys in [proof.KeyValues] and [proof.DeletedKeys] are in [start, end].
// If [start] is empty, all keys are considered > [start].
// If [end] is empty, all keys are considered < [end].
// If [end] is nothing, all keys are considered < [end].
// - [proof.KeyValues] and [proof.DeletedKeys] are sorted in order of increasing key.
// - [proof.StartProof] and [proof.EndProof] are well-formed.
// - When the keys in [proof.KeyValues] are added to [db] and the keys in [proof.DeletedKeys]
Expand All @@ -83,7 +83,7 @@ type ChangeProofer interface {
ctx context.Context,
proof *ChangeProof,
start []byte,
end []byte,
end Maybe[[]byte],
Copy link

Choose a reason for hiding this comment

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

Should we also use end Maybe[[]byte] in GetChangeProof above and GetRangeProofAtRoot below for consistency?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Part 2

expectedEndRootID ids.ID,
) error

Expand Down Expand Up @@ -582,20 +582,22 @@ func (db *merkleDB) GetChangeProof(
})
}

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

// Since we hold [db.commitlock] we must still have sufficient
// history to recreate the trie at [endRootID].
historicalView, err := db.getHistoricalViewForRange(endRootID, start, largestKey)
historicalView, err := db.getHistoricalViewForRange(endRootID, start, largestKey.Value())
if err != nil {
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
}
Expand Down Expand Up @@ -958,10 +960,10 @@ func (db *merkleDB) VerifyChangeProof(
ctx context.Context,
proof *ChangeProof,
start []byte,
end []byte,
end Maybe[[]byte],
expectedEndRootID ids.ID,
) error {
if len(end) > 0 && bytes.Compare(start, end) > 0 {
if end.HasValue() && bytes.Compare(start, end.Value()) > 0 {
return ErrStartAfterEnd
}

Expand All @@ -978,7 +980,7 @@ 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:
Expand All @@ -1004,17 +1006,18 @@ 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
largestPath := Nothing[path]()
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
largestPath = Some(newPath(proof.KeyChanges[len(proof.KeyChanges)-1].Key))
} else if end.HasValue() {
largestPath = Some(newPath(end.Value()))
}
largestPath := newPath(largestKey)

// Make sure the end proof, if given, is well-formed.
if err := verifyProofPath(proof.EndProof, largestPath); err != nil {
if err := verifyProofPath(proof.EndProof, largestPath.Value()); err != nil {
return err
}

Expand Down Expand Up @@ -1074,23 +1077,19 @@ func (db *merkleDB) VerifyChangeProof(
if len(smallestPath) > 0 {
insertChildrenLessThan = Some(smallestPath)
}
insertChildrenGreaterThan := Nothing[path]()
if len(largestPath) > 0 {
insertChildrenGreaterThan = Some(largestPath)
}
if err := addPathInfo(
view,
proof.StartProof,
insertChildrenLessThan,
insertChildrenGreaterThan,
largestPath,
); err != nil {
return err
}
if err := addPathInfo(
view,
proof.EndProof,
insertChildrenLessThan,
insertChildrenGreaterThan,
largestPath,
); err != nil {
return err
}
Expand Down
12 changes: 10 additions & 2 deletions x/merkledb/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -770,10 +770,14 @@ func runRandDBTest(require *require.Assertions, r *rand.Rand, rt randTest) {
}
rangeProof, err := db.GetRangeProofAtRoot(context.Background(), root, step.key, step.value, 100)
require.NoError(err)
end := Nothing[[]byte]()
if len(step.value) > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: should we update the comments on the randStep struct to mention value/key are used differently for getting range/change proofs?

end = Some(step.value)
}
require.NoError(rangeProof.Verify(
context.Background(),
step.key,
step.value,
end,
root,
))
require.LessOrEqual(len(rangeProof.KeyValues), 100)
Expand All @@ -791,11 +795,15 @@ func runRandDBTest(require *require.Assertions, r *rand.Rand, rt randTest) {
require.NoError(err)
changeProofDB, err := getBasicDB()
require.NoError(err)
end := Nothing[[]byte]()
if len(step.value) > 0 {
end = Some(step.value)
}
require.NoError(changeProofDB.VerifyChangeProof(
context.Background(),
changeProof,
step.key,
step.value,
end,
root,
))
require.LessOrEqual(len(changeProof.KeyChanges), 100)
Expand Down
38 changes: 19 additions & 19 deletions x/merkledb/history_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ func Test_History_Simple(t *testing.T) {
require.NoError(err)
require.NotNil(origProof)
origRootID := db.root.id
require.NoError(origProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(origProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))

batch = db.NewBatch()
require.NoError(batch.Put([]byte("key"), []byte("value0")))
require.NoError(batch.Write())
newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), []byte("key3"), 10)
require.NoError(err)
require.NotNil(newProof)
require.NoError(newProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(newProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))

batch = db.NewBatch()
require.NoError(batch.Put([]byte("key1"), []byte("value1")))
Expand All @@ -53,15 +53,15 @@ func Test_History_Simple(t *testing.T) {
newProof, err = db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), []byte("key3"), 10)
require.NoError(err)
require.NotNil(newProof)
require.NoError(newProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(newProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))

batch = db.NewBatch()
require.NoError(batch.Put([]byte("k"), []byte("v")))
require.NoError(batch.Write())
newProof, err = db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), []byte("key3"), 10)
require.NoError(err)
require.NotNil(newProof)
require.NoError(newProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(newProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))

batch = db.NewBatch()
require.NoError(batch.Delete([]byte("k")))
Expand All @@ -77,7 +77,7 @@ func Test_History_Simple(t *testing.T) {
newProof, err = db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), []byte("key3"), 10)
require.NoError(err)
require.NotNil(newProof)
require.NoError(newProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(newProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))
}

func Test_History_Large(t *testing.T) {
Expand Down Expand Up @@ -137,7 +137,7 @@ func Test_History_Large(t *testing.T) {
require.NoError(err)
require.NotNil(proof)

require.NoError(proof.Verify(context.Background(), nil, nil, roots[0]))
require.NoError(proof.Verify(context.Background(), nil, Nothing[[]byte](), roots[0]))
}
}

Expand Down Expand Up @@ -233,7 +233,7 @@ func Test_History_Trigger_History_Queue_Looping(t *testing.T) {
require.NoError(origProof.Verify(
context.Background(),
[]byte("k"),
[]byte("key3"),
Some([]byte("key3")),
origRootID,
))

Expand All @@ -249,7 +249,7 @@ func Test_History_Trigger_History_Queue_Looping(t *testing.T) {
require.NoError(newProof.Verify(
context.Background(),
[]byte("k"),
[]byte("key3"),
Some([]byte("key3")),
origRootID,
))

Expand Down Expand Up @@ -332,7 +332,7 @@ func Test_History_RepeatedRoot(t *testing.T) {
require.NoError(err)
require.NotNil(origProof)
origRootID := db.root.id
require.NoError(origProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(origProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))

batch = db.NewBatch()
require.NoError(batch.Put([]byte("key1"), []byte("other")))
Expand All @@ -342,7 +342,7 @@ func Test_History_RepeatedRoot(t *testing.T) {
newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), []byte("key3"), 10)
require.NoError(err)
require.NotNil(newProof)
require.NoError(newProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(newProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))

// revert state to be the same as in orig proof
batch = db.NewBatch()
Expand All @@ -354,7 +354,7 @@ func Test_History_RepeatedRoot(t *testing.T) {
newProof, err = db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), []byte("key3"), 10)
require.NoError(err)
require.NotNil(newProof)
require.NoError(newProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(newProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))
}

func Test_History_ExcessDeletes(t *testing.T) {
Expand All @@ -374,7 +374,7 @@ func Test_History_ExcessDeletes(t *testing.T) {
require.NoError(err)
require.NotNil(origProof)
origRootID := db.root.id
require.NoError(origProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(origProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))

batch = db.NewBatch()
require.NoError(batch.Delete([]byte("key1")))
Expand All @@ -386,7 +386,7 @@ func Test_History_ExcessDeletes(t *testing.T) {
newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), []byte("key3"), 10)
require.NoError(err)
require.NotNil(newProof)
require.NoError(newProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(newProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))
}

func Test_History_DontIncludeAllNodes(t *testing.T) {
Expand All @@ -406,15 +406,15 @@ func Test_History_DontIncludeAllNodes(t *testing.T) {
require.NoError(err)
require.NotNil(origProof)
origRootID := db.root.id
require.NoError(origProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(origProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))

batch = db.NewBatch()
require.NoError(batch.Put([]byte("z"), []byte("z")))
require.NoError(batch.Write())
newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), []byte("key3"), 10)
require.NoError(err)
require.NotNil(newProof)
require.NoError(newProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(newProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))
}

func Test_History_Branching2Nodes(t *testing.T) {
Expand All @@ -434,15 +434,15 @@ func Test_History_Branching2Nodes(t *testing.T) {
require.NoError(err)
require.NotNil(origProof)
origRootID := db.root.id
require.NoError(origProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(origProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))

batch = db.NewBatch()
require.NoError(batch.Put([]byte("k"), []byte("v")))
require.NoError(batch.Write())
newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), []byte("key3"), 10)
require.NoError(err)
require.NotNil(newProof)
require.NoError(newProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(newProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))
}

func Test_History_Branching3Nodes(t *testing.T) {
Expand All @@ -462,15 +462,15 @@ func Test_History_Branching3Nodes(t *testing.T) {
require.NoError(err)
require.NotNil(origProof)
origRootID := db.root.id
require.NoError(origProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(origProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))

batch = db.NewBatch()
require.NoError(batch.Put([]byte("key321"), []byte("value321")))
require.NoError(batch.Write())
newProof, err := db.GetRangeProofAtRoot(context.Background(), origRootID, []byte("k"), []byte("key3"), 10)
require.NoError(err)
require.NotNil(newProof)
require.NoError(newProof.Verify(context.Background(), []byte("k"), []byte("key3"), origRootID))
require.NoError(newProof.Verify(context.Background(), []byte("k"), Some([]byte("key3")), origRootID))
}

func Test_History_MaxLength(t *testing.T) {
Expand Down
29 changes: 27 additions & 2 deletions x/merkledb/maybe.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

package merkledb

import "golang.org/x/exp/slices"
import (
"bytes"

"golang.org/x/exp/slices"
)

// Maybe T = Some T | Nothing.
// A data wrapper that allows values to be something [Some T] or nothing [Nothing].
Expand All @@ -29,11 +33,16 @@ func Nothing[T any]() Maybe[T] {
return Maybe[T]{}
}

// Returns true iff [m] has a value.
// Returns false iff [m] has a value.
func (m Maybe[T]) IsNothing() bool {
return !m.hasValue
}

// Returns true iff [m] has a value.
func (m Maybe[T]) HasValue() bool {
return m.hasValue
}

// Returns the value of [m].
func (m Maybe[T]) Value() T {
return m.value
Expand All @@ -45,3 +54,19 @@ func Clone(m Maybe[[]byte]) Maybe[[]byte] {
}
return Some(slices.Clone(m.value))
}

// MaybeBytesEquals returns true iff [a] and [b] are equal.
func MaybeBytesEquals(a, b Maybe[[]byte]) bool {
aNothing := a.IsNothing()
bNothing := b.IsNothing()

if aNothing {
return bNothing
}

if bNothing {
return false
}

return bytes.Equal(a.Value(), b.Value())
}
2 changes: 1 addition & 1 deletion x/merkledb/mock_db.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading