@@ -17,13 +17,14 @@ import (
1717 "github.com/filecoin-project/go-address"
1818 amt4 "github.com/filecoin-project/go-amt-ipld/v4"
1919 "github.com/filecoin-project/go-state-types/abi"
20- "github.com/filecoin-project/lotus/chain/types"
2120 blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
21+
22+ "github.com/filecoin-project/lotus/chain/types"
2223)
2324
2425var (
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" )
2728)
2829
2930const maxLookBackForWait = 120 // one hour of tipsets
@@ -238,101 +239,135 @@ func loadExecutedMessages(ctx context.Context, cs ChainStore, recomputeTipSetSta
238239 return ems , nil
239240}
240241
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+ }
246292
247293 // 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 )
249295 if err != nil {
250296 return xerrors .Errorf ("failed to find first non-null round: %w" , err )
251297 }
252-
253298 // If all rounds are null, consider the range valid
254299 if startCid == nil {
255300 return nil
256301 }
257302
258303 // 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 )
260305 if err != nil {
261- if errors .Is (err , ErrRangeInFuture ) {
262- return xerrors .Errorf ("range end is in the future: %w" , err )
263- }
264306 return xerrors .Errorf ("failed to find last non-null round: %w" , err )
265307 }
266-
267308 // If all rounds are null, consider the range valid
268309 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 )
270311 }
271312
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 {
274315 return err
275316 }
276-
277- if err := si .checkTipsetByKeyCid (ctx , endCid , maxHeight ); err != nil {
317+ if err := si .checkTipsetIndexedStatus (ctx , endCid , endHeight ); err != nil {
278318 return err
279319 }
320+ // Assume (not necessarily correctly, but likely) that all tipsets within the range are indexed
280321
281322 return nil
282323}
283324
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 {
286326 exists , err := si .isTipsetIndexed (ctx , tipsetKeyCid )
287327 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
289331 }
290-
291- if exists {
292- return nil // null round
293- }
294-
295- return ErrNotFound // tipset is not indexed
332+ return ErrNotFound
296333}
297334
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 ++ {
301339 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
308346 }
347+ minHeight = height // Update the minHeight to the found height
348+ return cid , minHeight , nil
309349 }
310-
311- return nil , nil
350+ // All rounds are null
351+ return nil , 0 , nil
312352}
313353
314354// 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 -- {
322357 cid , err := si .getTipsetKeyCidByHeight (ctx , height )
323358 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
326361 }
327362 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 )
329364 }
330365 }
331366
332- return nil , nil
367+ return nil , 0 , nil
333368}
334369
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
336371func (si * SqliteIndexer ) getTipsetKeyCidByHeight (ctx context.Context , height abi.ChainEpoch ) ([]byte , error ) {
337372 ts , err := si .cs .GetTipsetByHeight (ctx , height , nil , false )
338373 if err != nil {
@@ -504,15 +539,15 @@ func (si *SqliteIndexer) GetEventsForFilter(ctx context.Context, f *EventFilter)
504539 if height > 0 {
505540 head := si .cs .GetHeaviestTipSet ()
506541 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" )
508543 }
509544 headHeight := head .Height ()
510545 maxLookBackHeight := headHeight - maxLookBackForWait
511546
512547 // if the height is old enough, we'll assume the index is caught up to it and not bother
513548 // waiting for it to be indexed
514549 if height <= maxLookBackHeight {
515- return nil , si .checkRangeIndexedStatus (ctx , f )
550+ return nil , si .checkFilterTipsetsIndexed (ctx , f )
516551 }
517552 }
518553
@@ -526,7 +561,7 @@ func (si *SqliteIndexer) GetEventsForFilter(ctx context.Context, f *EventFilter)
526561 }
527562
528563 if len (ces ) == 0 {
529- return nil , si .checkRangeIndexedStatus (ctx , f )
564+ return nil , si .checkFilterTipsetsIndexed (ctx , f )
530565 }
531566 }
532567
0 commit comments