8
8
"context"
9
9
"fmt"
10
10
"slices"
11
+ "sync"
11
12
12
13
"golang.org/x/exp/maps"
13
14
"google.golang.org/protobuf/proto"
@@ -31,7 +32,8 @@ type xSyncClient struct {
31
32
db DB
32
33
config * ClientConfig
33
34
tokenSize int
34
- setError func (error )
35
+ err error
36
+ errorOnce sync.Once
35
37
}
36
38
37
39
func NewClient (db DB , config * ClientConfig ) (* xSyncClient , error ) {
@@ -50,8 +52,14 @@ func NewClient(db DB, config *ClientConfig) (*xSyncClient, error) {
50
52
}, nil
51
53
}
52
54
53
- func (c * xSyncClient ) RegisterErrorHandler (handler func (error )) {
54
- c .setError = handler
55
+ func (c * xSyncClient ) Error () error {
56
+ return c .err
57
+ }
58
+
59
+ func (c * xSyncClient ) setError (err error ) {
60
+ c .errorOnce .Do (func () {
61
+ c .err = err
62
+ })
55
63
}
56
64
57
65
func (c * xSyncClient ) Clear () error {
@@ -62,15 +70,15 @@ func (c *xSyncClient) GetMerkleRoot(ctx context.Context) (ids.ID, error) {
62
70
return c .db .GetMerkleRoot (ctx )
63
71
}
64
72
65
- func (c * xSyncClient ) HandleRangeProofResponse (ctx context.Context , request * pb.SyncGetRangeProofRequest , responseBytes []byte , onFinish func (maybe.Maybe [[]byte ])) error {
73
+ func (c * xSyncClient ) HandleRangeProofResponse (ctx context.Context , request * pb.SyncGetRangeProofRequest , responseBytes []byte ) (maybe.Maybe [[]byte ], error ) {
66
74
var rangeProofProto pb.RangeProof
67
75
if err := proto .Unmarshal (responseBytes , & rangeProofProto ); err != nil {
68
- return err
76
+ return maybe . Nothing [[] byte ](), err
69
77
}
70
78
71
79
var rangeProof merkledb.RangeProof
72
80
if err := rangeProof .UnmarshalProto (& rangeProofProto ); err != nil {
73
- return err
81
+ return maybe . Nothing [[] byte ](), err
74
82
}
75
83
76
84
start := maybeBytesToMaybe (request .StartKey )
@@ -86,15 +94,15 @@ func (c *xSyncClient) HandleRangeProofResponse(ctx context.Context, request *pb.
86
94
c .tokenSize ,
87
95
c .config .Hasher ,
88
96
); err != nil {
89
- return err
97
+ return maybe . Nothing [[] byte ](), err
90
98
}
91
99
92
100
largestHandledKey := end
93
101
94
102
// Replace all the key-value pairs in the DB from start to end with values from the response.
95
103
if err := c .db .CommitRangeProof (ctx , start , end , & rangeProof ); err != nil {
96
104
c .setError (err )
97
- return nil
105
+ return maybe . Nothing [[] byte ](), err
98
106
}
99
107
100
108
if len (rangeProof .KeyChanges ) > 0 {
@@ -107,24 +115,22 @@ func (c *xSyncClient) HandleRangeProofResponse(ctx context.Context, request *pb.
107
115
nextKey , err := c .findNextKey (ctx , largestHandledKey .Value (), end , rangeProof .EndProof )
108
116
if err != nil {
109
117
c .setError (err )
110
- return nil
118
+ return maybe . Nothing [[] byte ](), err
111
119
}
112
120
largestHandledKey = nextKey
113
121
}
114
122
115
- onFinish (largestHandledKey )
116
- return nil
123
+ return largestHandledKey , nil
117
124
}
118
125
119
126
func (c * xSyncClient ) HandleChangeProofResponse (
120
127
ctx context.Context ,
121
128
request * pb.SyncGetChangeProofRequest ,
122
129
responseBytes []byte ,
123
- onFinish func (maybe.Maybe [[]byte ]),
124
- ) error {
130
+ ) (maybe.Maybe [[]byte ], error ) {
125
131
var changeProofResp pb.SyncGetChangeProofResponse
126
132
if err := proto .Unmarshal (responseBytes , & changeProofResp ); err != nil {
127
- return err
133
+ return maybe . Nothing [[] byte ](), err
128
134
}
129
135
130
136
startKey := maybeBytesToMaybe (request .StartKey )
@@ -139,21 +145,21 @@ func (c *xSyncClient) HandleChangeProofResponse(
139
145
// The server had enough history to send us a change proof
140
146
var changeProof merkledb.ChangeProof
141
147
if err := changeProof .UnmarshalProto (changeProofResp .ChangeProof ); err != nil {
142
- return err
148
+ return maybe . Nothing [[] byte ](), err
143
149
}
144
150
145
151
// Ensure the response does not contain more than the requested number of leaves
146
152
// and the start and end roots match the requested roots.
147
153
if len (changeProof .KeyChanges ) > int (request .KeyLimit ) {
148
- return fmt .Errorf (
154
+ return maybe . Nothing [[] byte ](), fmt .Errorf (
149
155
"%w: (%d) > %d)" ,
150
156
errTooManyKeys , len (changeProof .KeyChanges ), request .KeyLimit ,
151
157
)
152
158
}
153
159
154
160
endRoot , err := ids .ToID (request .EndRootHash )
155
161
if err != nil {
156
- return err
162
+ return maybe . Nothing [[] byte ](), err
157
163
}
158
164
159
165
if err := c .db .VerifyChangeProof (
@@ -163,15 +169,15 @@ func (c *xSyncClient) HandleChangeProofResponse(
163
169
endKey ,
164
170
endRoot ,
165
171
); err != nil {
166
- return fmt .Errorf ("%w due to %w" , errInvalidChangeProof , err )
172
+ return maybe . Nothing [[] byte ](), fmt .Errorf ("%w due to %w" , errInvalidChangeProof , err )
167
173
}
168
174
169
175
largestHandledKey = endKey
170
176
// if the proof wasn't empty, apply changes to the sync DB
171
177
if len (changeProof .KeyChanges ) > 0 {
172
178
if err := c .db .CommitChangeProof (ctx , & changeProof ); err != nil {
173
179
c .setError (err )
174
- return nil
180
+ return maybe . Nothing [[] byte ](), err
175
181
}
176
182
largestHandledKey = maybe .Some (changeProof .KeyChanges [len (changeProof .KeyChanges )- 1 ].Key )
177
183
}
@@ -180,7 +186,7 @@ func (c *xSyncClient) HandleChangeProofResponse(
180
186
case * pb.SyncGetChangeProofResponse_RangeProof :
181
187
var rangeProof merkledb.RangeProof
182
188
if err := rangeProof .UnmarshalProto (changeProofResp .RangeProof ); err != nil {
183
- return err
189
+ return maybe . Nothing [[] byte ](), err
184
190
}
185
191
186
192
// The server did not have enough history to send us a change proof
@@ -195,22 +201,22 @@ func (c *xSyncClient) HandleChangeProofResponse(
195
201
c .tokenSize ,
196
202
c .config .Hasher ,
197
203
); err != nil {
198
- return err
204
+ return maybe . Nothing [[] byte ](), err
199
205
}
200
206
201
207
largestHandledKey = endKey
202
208
if len (rangeProof .KeyChanges ) > 0 {
203
209
// Add all the key-value pairs we got to the database.
204
210
if err := c .db .CommitRangeProof (ctx , startKey , endKey , & rangeProof ); err != nil {
205
211
c .setError (err )
206
- return nil
212
+ return maybe . Nothing [[] byte ](), err
207
213
}
208
214
largestHandledKey = maybe .Some (rangeProof .KeyChanges [len (rangeProof .KeyChanges )- 1 ].Key )
209
215
}
210
216
endProof = rangeProof .EndProof
211
217
212
218
default :
213
- return fmt .Errorf (
219
+ return maybe . Nothing [[] byte ](), fmt .Errorf (
214
220
"%w: %T" ,
215
221
errUnexpectedChangeProofResponse , changeProofResp ,
216
222
)
@@ -221,12 +227,12 @@ func (c *xSyncClient) HandleChangeProofResponse(
221
227
nextKey , err := c .findNextKey (ctx , largestHandledKey .Value (), endKey , endProof )
222
228
if err != nil {
223
229
c .setError (err )
224
- return nil
230
+ return maybe . Nothing [[] byte ](), err
225
231
}
226
232
largestHandledKey = nextKey
227
233
}
228
- onFinish ( largestHandledKey )
229
- return nil
234
+
235
+ return largestHandledKey , nil
230
236
}
231
237
232
238
// findNextKey returns the start of the key range that should be fetched next
0 commit comments