Skip to content

Commit 2375dd7

Browse files
committed
fix: FindNextKey
1 parent ed246fd commit 2375dd7

File tree

4 files changed

+50
-154
lines changed

4 files changed

+50
-154
lines changed

x/firewood/proof.go

Lines changed: 4 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44
package firewood
55

66
import (
7-
"runtime"
7+
"errors"
88

99
"github.com/ava-labs/firewood-go-ethhash/ffi"
1010

1111
"github.com/ava-labs/avalanchego/ids"
12-
"github.com/ava-labs/avalanchego/utils/maybe"
1312

1413
xsync "github.com/ava-labs/avalanchego/x/sync"
1514
)
@@ -54,84 +53,14 @@ func newRangeProof(proof *ffi.RangeProof) *RangeProof {
5453
}
5554
}
5655

57-
func (r *RangeProof) FindNextKey() (maybe.Maybe[[]byte], error) {
58-
// We can now get the FindNextKey iterator.
59-
nextKeyRange, err := r.ffi.FindNextKey()
60-
if err != nil {
61-
return maybe.Nothing[[]byte](), err
62-
}
63-
64-
// TODO: this panics
65-
startKey := maybe.Some(nextKeyRange.StartKey())
66-
67-
// Done using nextKeyRange
68-
if err := nextKeyRange.Free(); err != nil {
69-
return maybe.Nothing[[]byte](), err
70-
}
71-
72-
return startKey, nil
73-
}
74-
7556
type ChangeProofMarshaler struct{}
7657

7758
func (ChangeProofMarshaler) Marshal(r *ChangeProof) ([]byte, error) {
78-
if r == nil {
79-
return nil, errNilProof
80-
}
81-
if r.proof == nil {
82-
return nil, nil
83-
}
84-
85-
data, err := r.proof.MarshalBinary()
86-
return data, err
59+
return nil, errors.New("not implemented")
8760
}
8861

8962
func (ChangeProofMarshaler) Unmarshal(data []byte) (*ChangeProof, error) {
90-
proof := new(ffi.ChangeProof)
91-
if err := proof.UnmarshalBinary(data); err != nil {
92-
return nil, err
93-
}
94-
return newChangeProof(proof), nil
95-
}
96-
97-
type ChangeProof struct {
98-
proof *ffi.ChangeProof
99-
startRoot ids.ID
100-
endRoot ids.ID
101-
startKey maybe.Maybe[[]byte]
102-
maxLength int
103-
}
104-
105-
// Wrap the ffi proof in our proof type.
106-
func newChangeProof(proof *ffi.ChangeProof) *ChangeProof {
107-
changeProof := &ChangeProof{
108-
proof: proof,
109-
}
110-
111-
// Once this struct is out of scope, free the underlying proof.
112-
runtime.AddCleanup(changeProof, func(ffiProof *ffi.ChangeProof) {
113-
if ffiProof != nil {
114-
_ = ffiProof.Free()
115-
}
116-
}, changeProof.proof)
117-
118-
return changeProof
63+
return nil, errors.New("not implemented")
11964
}
12065

121-
func (c *ChangeProof) FindNextKey() (maybe.Maybe[[]byte], error) {
122-
// We can now get the FindNextKey iterator.
123-
nextKeyRange, err := c.proof.FindNextKey()
124-
if err != nil {
125-
return maybe.Nothing[[]byte](), err
126-
}
127-
128-
// TODO: this panics
129-
startKey := maybe.Some(nextKeyRange.StartKey())
130-
131-
// Done using nextKeyRange
132-
if err := nextKeyRange.Free(); err != nil {
133-
return maybe.Nothing[[]byte](), err
134-
}
135-
136-
return startKey, nil
137-
}
66+
type ChangeProof struct{}

x/firewood/sync_db.go

Lines changed: 42 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package firewood
55

66
import (
7+
"bytes"
78
"context"
89
"errors"
910
"sync"
@@ -39,39 +40,30 @@ func (db *syncDB) GetMerkleRoot(context.Context) (ids.ID, error) {
3940
return ids.ID(root), nil
4041
}
4142

42-
// TODO: implement
43-
func (db *syncDB) CommitChangeProof(_ context.Context, end maybe.Maybe[[]byte], proof *ChangeProof) (nextKey maybe.Maybe[[]byte], err error) {
44-
// Set up cleanup.
45-
var nextKeyRange *ffi.NextKeyRange
46-
defer func() {
47-
// If we got a nextKeyRange, free it too.
48-
if nextKeyRange != nil {
49-
err = errors.Join(err, nextKeyRange.Free())
50-
}
51-
}()
52-
53-
// Verify and commit the proof in a single step (TODO: separate these steps).
54-
// CommitRangeProof will verify the proof as part of committing it.
55-
db.lock.Lock()
56-
defer db.lock.Unlock()
57-
newRoot, err := db.fw.VerifyAndCommitChangeProof(proof.proof, ffi.Hash(proof.startRoot), ffi.Hash(proof.endRoot), proof.startKey, end, uint32(proof.maxLength))
43+
// GetRangeProof returns a range proof for x/sync between [start, end].
44+
func (db *syncDB) GetRangeProofAtRoot(_ context.Context, rootID ids.ID, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], maxLength int) (*RangeProof, error) {
45+
proof, err := db.fw.RangeProof(ffi.Hash(rootID), start, end, uint32(maxLength))
5846
if err != nil {
59-
return maybe.Nothing[[]byte](), err
47+
return nil, err
6048
}
6149

62-
// TODO: This case should be handled by `FindNextKey`.
63-
if ids.ID(newRoot) == proof.endRoot {
64-
return maybe.Nothing[[]byte](), nil
50+
return newRangeProof(proof), nil
51+
}
52+
53+
// VerifyRangeProof ensures the range proof matches the expected parameters.
54+
func (db *syncDB) VerifyRangeProof(_ context.Context, proof *RangeProof, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], expectedEndRootID ids.ID, maxLength int) error {
55+
if proof.ffi == nil {
56+
return errNilProof
6557
}
6658

67-
return proof.FindNextKey()
59+
proof.root = expectedEndRootID
60+
proof.maxLength = maxLength
61+
62+
return proof.ffi.Verify(ffi.Hash(expectedEndRootID), start, end, uint32(maxLength))
6863
}
6964

7065
// Commit the range proof to the database.
71-
// TODO: This should only commit the range proof, not verify it.
72-
// This will be resolved once the Firewood supports that.
73-
// This is the last call to the proof, so it and any resources should be freed.
74-
func (db *syncDB) CommitRangeProof(_ context.Context, start, end maybe.Maybe[[]byte], proof *RangeProof) (nextKey maybe.Maybe[[]byte], err error) {
66+
func (db *syncDB) CommitRangeProof(_ context.Context, start, end maybe.Maybe[[]byte], proof *RangeProof) (maybe.Maybe[[]byte], error) {
7567
// Verify and commit the proof in a single step (TODO: separate these steps).
7668
// CommitRangeProof will verify the proof as part of committing it.
7769
db.lock.Lock()
@@ -86,69 +78,44 @@ func (db *syncDB) CommitRangeProof(_ context.Context, start, end maybe.Maybe[[]b
8678
return maybe.Nothing[[]byte](), nil
8779
}
8880

89-
return proof.FindNextKey()
90-
}
91-
92-
// TODO: implement
93-
func (db *syncDB) GetChangeProof(_ context.Context, startRootID ids.ID, endRootID ids.ID, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], maxLength int) (*ChangeProof, error) {
94-
proof, err := db.fw.ChangeProof(ffi.Hash(startRootID), ffi.Hash(endRootID), start, end, uint32(maxLength))
95-
if err != nil {
96-
return nil, err
81+
// We can now get the FindNextKey iterator.
82+
nextKeyRange, err := proof.ffi.FindNextKey()
83+
if err != nil || nextKeyRange == nil {
84+
// Indicates the range is complete.
85+
return maybe.Nothing[[]byte](), err
9786
}
9887

99-
return newChangeProof(proof), nil
100-
}
88+
byteSlice := nextKeyRange.StartKey()
89+
newSlice := make([]byte, len(byteSlice))
90+
copy(newSlice, byteSlice)
10191

102-
// Get the range proof between [start, end].
103-
// The returned proof must be freed when no longer needed.
104-
// Since this method is only called prior to marshalling the proof for sending over the
105-
// network, the proof will be freed when marshalled.
106-
func (db *syncDB) GetRangeProofAtRoot(_ context.Context, rootID ids.ID, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], maxLength int) (*RangeProof, error) {
107-
proof, err := db.fw.RangeProof(ffi.Hash(rootID), start, end, uint32(maxLength))
108-
if err != nil {
109-
return nil, err
92+
// Done using nextKeyRange
93+
if err := nextKeyRange.Free(); err != nil {
94+
return maybe.Nothing[[]byte](), err
11095
}
11196

112-
return newRangeProof(proof), nil
113-
}
114-
115-
// TODO: implement
116-
// Right now, we verify the proof as part of committing it, making this function a no-op.
117-
// We must only pass the necessary data to CommitChangeProof so it can verify the proof.
118-
//
119-
//nolint:revive
120-
func (db *syncDB) VerifyChangeProof(_ context.Context, proof *ChangeProof, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], expectedEndRootID ids.ID, maxLength int) error {
121-
if proof.proof == nil {
122-
return errNilProof
97+
if start.HasValue() && bytes.Equal(newSlice, start.Value()) {
98+
// There is no next key.
99+
return maybe.Nothing[[]byte](), nil
123100
}
124101

125-
// TODO: once firewood can verify separately from committing, do that here.
126-
// For now, pass any necessary data to be done in CommitChangeProof.
127-
// Namely, the start root, end root, and max length.
128-
proof.startRoot = expectedEndRootID
129-
proof.endRoot = expectedEndRootID
130-
proof.maxLength = maxLength
131-
return nil
102+
return maybe.Some(newSlice), nil
132103
}
133104

134-
// TODO: implement
135-
// Right now, we verify the proof as part of committing it, making this function a no-op.
136-
// We must only pass the necessary data to CommitRangeProof so it can verify the proof.
137-
func (db *syncDB) VerifyRangeProof(_ context.Context, proof *RangeProof, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], expectedEndRootID ids.ID, maxLength int) error {
138-
if proof.ffi == nil {
139-
return errNilProof
140-
}
105+
func (db *syncDB) GetChangeProof(_ context.Context, startRootID ids.ID, endRootID ids.ID, start maybe.Maybe[[]byte], end maybe.Maybe[[]byte], maxLength int) (*ChangeProof, error) {
106+
return nil, errors.New("change proofs are not implemented")
107+
}
141108

142-
proof.root = expectedEndRootID
143-
proof.maxLength = maxLength
109+
func (db *syncDB) VerifyChangeProof(context.Context, *ChangeProof, maybe.Maybe[[]byte], maybe.Maybe[[]byte], ids.ID, int) error {
110+
return errors.New("change proofs are not implemented")
111+
}
144112

145-
return proof.ffi.Verify(ffi.Hash(expectedEndRootID), start, end, uint32(maxLength))
113+
func (db *syncDB) CommitChangeProof(context.Context, maybe.Maybe[[]byte], *ChangeProof) (maybe.Maybe[[]byte], error) {
114+
return maybe.Nothing[[]byte](), errors.New("change proofs are not implemented")
146115
}
147116

148-
// TODO: implement
149-
// No error is returned to ensure some tests pass.
150-
//
151-
//nolint:revive
117+
// Clear the database.
118+
// TODO: implement this method. It is left nil to allow empty DBs to be used in tests.
152119
func (db *syncDB) Clear() error {
153120
return nil
154121
}

x/firewood/sync_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ var (
2828
)
2929

3030
func Test_Firewood_Sync(t *testing.T) {
31-
tests := []int{0, 1, 100, 1_000, 100_000}
31+
tests := []int{0, 1, 1_000, 100_000}
3232
for _, numKeys := range tests {
3333
t.Run(fmt.Sprintf("numKeys=%d", numKeys), func(t *testing.T) {
3434
require := require.New(t)
@@ -89,7 +89,7 @@ func generateDB(t *testing.T, numKeys int, seed int64) *syncDB {
8989
r = rand.New(rand.NewSource(seed)) // #nosec G404
9090
keys = make([][]byte, numKeys)
9191
vals = make([][]byte, numKeys)
92-
minLength = 0
92+
minLength = 1
9393
maxLength = 64
9494
)
9595
t.Logf("generating %d random keys/values with seed %d", numKeys, seed)

x/sync/manager.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,8 +512,8 @@ func (m *Manager[R, _]) handleRangeProofResponse(
512512
if err := m.db.VerifyRangeProof(
513513
ctx,
514514
rangeProof,
515-
protoutils.ProtoToMaybe(request.StartKey),
516-
protoutils.ProtoToMaybe(request.EndKey),
515+
work.start,
516+
work.end,
517517
root,
518518
int(request.KeyLimit),
519519
); err != nil {

0 commit comments

Comments
 (0)