@@ -17,13 +17,14 @@ import (
17
17
"github.com/filecoin-project/go-address"
18
18
amt4 "github.com/filecoin-project/go-amt-ipld/v4"
19
19
"github.com/filecoin-project/go-state-types/abi"
20
- "github.com/filecoin-project/lotus/chain/types"
21
20
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
21
+
22
+ "github.com/filecoin-project/lotus/chain/types"
22
23
)
23
24
24
25
var (
25
- ErrMaxResultsReached = fmt . Errorf ("filter matches too many events, try a more restricted filter" )
26
- ErrRangeInFuture = fmt . Errorf ("range end is in the future" )
26
+ ErrMaxResultsReached = xerrors . New ("filter matches too many events, try a more restricted filter" )
27
+ ErrRangeInFuture = xerrors . New ("range end is in the future" )
27
28
)
28
29
29
30
const maxLookBackForWait = 120 // one hour of tipsets
@@ -238,101 +239,135 @@ func loadExecutedMessages(ctx context.Context, cs ChainStore, recomputeTipSetSta
238
239
return ems , nil
239
240
}
240
241
241
- // checkRangeIndexedStatus verifies if a range of heights is indexed.
242
- // It checks for the existence of non-null rounds at the range boundaries.
243
- func (si * SqliteIndexer ) checkRangeIndexedStatus (ctx context.Context , f * EventFilter ) error {
244
- minHeight := f .MinHeight
245
- maxHeight := f .MaxHeight
242
+ // checkFilterTipsetsIndexed verifies if a tipset, or a range of tipsets, specified by a given
243
+ // filter is indexed. It checks for the existence of non-null rounds at the range boundaries.
244
+ func (si * SqliteIndexer ) checkFilterTipsetsIndexed (ctx context.Context , f * EventFilter ) error {
245
+ // Three cases to consider:
246
+ // 1. Specific tipset is provided
247
+ // 2. Single tipset is specified by the height range (min=max)
248
+ // 3. Range of tipsets is specified by the height range (min!=max)
249
+ // We'll handle the first two cases here and the third case in checkRangeIndexedStatus
250
+
251
+ var tipsetKeyCid []byte
252
+ var err error
253
+
254
+ switch {
255
+ case f .TipsetCid != cid .Undef :
256
+ tipsetKeyCid = f .TipsetCid .Bytes ()
257
+ case f .MinHeight >= 0 && f .MinHeight == f .MaxHeight :
258
+ tipsetKeyCid , err = si .getTipsetKeyCidByHeight (ctx , f .MinHeight )
259
+ if err != nil {
260
+ if err == ErrNotFound {
261
+ // this means that this is a null round and there exist no events for this epoch
262
+ return nil
263
+ }
264
+ return xerrors .Errorf ("failed to get tipset key cid by height: %w" , err )
265
+ }
266
+ default :
267
+ return si .checkRangeIndexedStatus (ctx , f .MinHeight , f .MaxHeight )
268
+ }
269
+
270
+ // If we couldn't determine a specific tipset, return ErrNotFound
271
+ if tipsetKeyCid == nil {
272
+ return ErrNotFound
273
+ }
274
+
275
+ // Check if the determined tipset is indexed
276
+ if exists , err := si .isTipsetIndexed (ctx , tipsetKeyCid ); err != nil {
277
+ return xerrors .Errorf ("failed to check if tipset is indexed: %w" , err )
278
+ } else if exists {
279
+ return nil // Tipset is indexed
280
+ }
281
+
282
+ return ErrNotFound // Tipset is not indexed
283
+ }
284
+
285
+ // checkRangeIndexedStatus verifies if a range of tipsets specified by the given height range is
286
+ // indexed. It checks for the existence of non-null rounds at the range boundaries.
287
+ func (si * SqliteIndexer ) checkRangeIndexedStatus (ctx context.Context , minHeight abi.ChainEpoch , maxHeight abi.ChainEpoch ) error {
288
+ head := si .cs .GetHeaviestTipSet ()
289
+ if minHeight > head .Height () || maxHeight > head .Height () {
290
+ return ErrRangeInFuture
291
+ }
246
292
247
293
// Find the first non-null round in the range
248
- startCid , err := si .findFirstNonNullRound (ctx , & minHeight , maxHeight )
294
+ startCid , startHeight , err := si .findFirstNonNullRound (ctx , minHeight , maxHeight )
249
295
if err != nil {
250
296
return xerrors .Errorf ("failed to find first non-null round: %w" , err )
251
297
}
252
-
253
298
// If all rounds are null, consider the range valid
254
299
if startCid == nil {
255
300
return nil
256
301
}
257
302
258
303
// Find the last non-null round in the range
259
- endCid , err := si .findLastNonNullRound (ctx , & maxHeight , minHeight )
304
+ endCid , endHeight , err := si .findLastNonNullRound (ctx , maxHeight , minHeight )
260
305
if err != nil {
261
- if errors .Is (err , ErrRangeInFuture ) {
262
- return xerrors .Errorf ("range end is in the future: %w" , err )
263
- }
264
306
return xerrors .Errorf ("failed to find last non-null round: %w" , err )
265
307
}
266
-
267
308
// If all rounds are null, consider the range valid
268
309
if endCid == nil {
269
- return nil
310
+ return xerrors . Errorf ( "unexpected error finding last non-null round: all rounds are null but start round is not (%d to %d)" , minHeight , maxHeight )
270
311
}
271
312
272
- // Check indexing for start and end tipsets
273
- if err := si .checkTipsetByKeyCid (ctx , startCid , minHeight ); err != nil {
313
+ // Check indexing status for start and end tipsets
314
+ if err := si .checkTipsetIndexedStatus (ctx , startCid , startHeight ); err != nil {
274
315
return err
275
316
}
276
-
277
- if err := si .checkTipsetByKeyCid (ctx , endCid , maxHeight ); err != nil {
317
+ if err := si .checkTipsetIndexedStatus (ctx , endCid , endHeight ); err != nil {
278
318
return err
279
319
}
320
+ // Assume (not necessarily correctly, but likely) that all tipsets within the range are indexed
280
321
281
322
return nil
282
323
}
283
324
284
- // checkTipsetByKeyCid checks if a tipset identified by its key CID is indexed.
285
- func (si * SqliteIndexer ) checkTipsetByKeyCid (ctx context.Context , tipsetKeyCid []byte , height abi.ChainEpoch ) error {
325
+ func (si * SqliteIndexer ) checkTipsetIndexedStatus (ctx context.Context , tipsetKeyCid []byte , height abi.ChainEpoch ) error {
286
326
exists , err := si .isTipsetIndexed (ctx , tipsetKeyCid )
287
327
if err != nil {
288
- return xerrors .Errorf ("failed to check if tipset at height %d is indexed: %w" , height , err )
328
+ return xerrors .Errorf ("failed to check if tipset at epoch %d is indexed: %w" , height , err )
329
+ } else if exists {
330
+ return nil // has been indexed
289
331
}
290
-
291
- if exists {
292
- return nil // null round
293
- }
294
-
295
- return ErrNotFound // tipset is not indexed
332
+ return ErrNotFound
296
333
}
297
334
298
- // findFirstNonNullRound finds the first non-null round starting from minHeight up to maxHeight
299
- func (si * SqliteIndexer ) findFirstNonNullRound (ctx context.Context , minHeight * abi.ChainEpoch , maxHeight abi.ChainEpoch ) ([]byte , error ) {
300
- for height := * minHeight ; height <= maxHeight ; height ++ {
335
+ // findFirstNonNullRound finds the first non-null round starting from minHeight up to maxHeight.
336
+ // It updates the minHeight to the found height and returns the tipset key CID.
337
+ func (si * SqliteIndexer ) findFirstNonNullRound (ctx context.Context , minHeight abi.ChainEpoch , maxHeight abi.ChainEpoch ) ([]byte , abi.ChainEpoch , error ) {
338
+ for height := minHeight ; height <= maxHeight ; height ++ {
301
339
cid , err := si .getTipsetKeyCidByHeight (ctx , height )
302
- if err = = nil {
303
- * minHeight = height // Update the minHeight to the found height
304
- return cid , nil
305
- }
306
- if ! errors . Is ( err , ErrNotFound ) {
307
- return nil , xerrors . Errorf ( "failed to get tipset key cid for height %d: %w" , height , err )
340
+ if err ! = nil {
341
+ if ! errors . Is ( err , ErrNotFound ) {
342
+ return nil , 0 , xerrors . Errorf ( "failed to get tipset key cid for height %d: %w" , height , err )
343
+ }
344
+ // else null round, keep searching
345
+ continue
308
346
}
347
+ minHeight = height // Update the minHeight to the found height
348
+ return cid , minHeight , nil
309
349
}
310
-
311
- return nil , nil
350
+ // All rounds are null
351
+ return nil , 0 , nil
312
352
}
313
353
314
354
// findLastNonNullRound finds the last non-null round starting from maxHeight down to minHeight
315
- func (si * SqliteIndexer ) findLastNonNullRound (ctx context.Context , maxHeight * abi.ChainEpoch , minHeight abi.ChainEpoch ) ([]byte , error ) {
316
- head := si .cs .GetHeaviestTipSet ()
317
- if head == nil || * maxHeight > head .Height () {
318
- return nil , ErrRangeInFuture
319
- }
320
-
321
- for height := * maxHeight ; height >= minHeight ; height -- {
355
+ func (si * SqliteIndexer ) findLastNonNullRound (ctx context.Context , maxHeight abi.ChainEpoch , minHeight abi.ChainEpoch ) ([]byte , abi.ChainEpoch , error ) {
356
+ for height := maxHeight ; height >= minHeight ; height -- {
322
357
cid , err := si .getTipsetKeyCidByHeight (ctx , height )
323
358
if err == nil {
324
- * maxHeight = height // Update the maxHeight to the found height
325
- return cid , nil
359
+ maxHeight = height // Update the maxHeight to the found height
360
+ return cid , maxHeight , nil
326
361
}
327
362
if ! errors .Is (err , ErrNotFound ) {
328
- return nil , xerrors .Errorf ("failed to get tipset key cid for height %d: %w" , height , err )
363
+ return nil , 0 , xerrors .Errorf ("failed to get tipset key cid for height %d: %w" , height , err )
329
364
}
330
365
}
331
366
332
- return nil , nil
367
+ return nil , 0 , nil
333
368
}
334
369
335
- // getTipsetKeyCidByHeight retrieves the tipset key CID for a given height.
370
+ // getTipsetKeyCidByHeight retrieves the tipset key CID for a given height from the ChainStore
336
371
func (si * SqliteIndexer ) getTipsetKeyCidByHeight (ctx context.Context , height abi.ChainEpoch ) ([]byte , error ) {
337
372
ts , err := si .cs .GetTipsetByHeight (ctx , height , nil , false )
338
373
if err != nil {
@@ -504,15 +539,15 @@ func (si *SqliteIndexer) GetEventsForFilter(ctx context.Context, f *EventFilter)
504
539
if height > 0 {
505
540
head := si .cs .GetHeaviestTipSet ()
506
541
if head == nil {
507
- return nil , errors .New ("failed to get head: head is nil" )
542
+ return nil , xerrors .New ("failed to get head: head is nil" )
508
543
}
509
544
headHeight := head .Height ()
510
545
maxLookBackHeight := headHeight - maxLookBackForWait
511
546
512
547
// if the height is old enough, we'll assume the index is caught up to it and not bother
513
548
// waiting for it to be indexed
514
549
if height <= maxLookBackHeight {
515
- return nil , si .checkRangeIndexedStatus (ctx , f )
550
+ return nil , si .checkFilterTipsetsIndexed (ctx , f )
516
551
}
517
552
}
518
553
@@ -526,7 +561,7 @@ func (si *SqliteIndexer) GetEventsForFilter(ctx context.Context, f *EventFilter)
526
561
}
527
562
528
563
if len (ces ) == 0 {
529
- return nil , si .checkRangeIndexedStatus (ctx , f )
564
+ return nil , si .checkFilterTipsetsIndexed (ctx , f )
530
565
}
531
566
}
532
567
0 commit comments