github.com/badrootd/celestia-core@v0.0.0-20240305091328-aa4207a4b25d/state/txindex/indexer_service.go (about)

     1  package txindex
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/badrootd/celestia-core/libs/service"
     7  	"github.com/badrootd/celestia-core/state/indexer"
     8  	"github.com/badrootd/celestia-core/types"
     9  )
    10  
    11  // XXX/TODO: These types should be moved to the indexer package.
    12  
    13  const (
    14  	subscriber = "IndexerService"
    15  )
    16  
    17  // IndexerService connects event bus, transaction and block indexers together in
    18  // order to index transactions and blocks coming from the event bus.
    19  type IndexerService struct {
    20  	service.BaseService
    21  
    22  	txIdxr           TxIndexer
    23  	blockIdxr        indexer.BlockIndexer
    24  	eventBus         *types.EventBus
    25  	terminateOnError bool
    26  }
    27  
    28  // NewIndexerService returns a new service instance.
    29  func NewIndexerService(
    30  	txIdxr TxIndexer,
    31  	blockIdxr indexer.BlockIndexer,
    32  	eventBus *types.EventBus,
    33  	terminateOnError bool,
    34  ) *IndexerService {
    35  
    36  	is := &IndexerService{txIdxr: txIdxr, blockIdxr: blockIdxr, eventBus: eventBus, terminateOnError: terminateOnError}
    37  	is.BaseService = *service.NewBaseService(nil, "IndexerService", is)
    38  	return is
    39  }
    40  
    41  // OnStart implements service.Service by subscribing for all transactions
    42  // and indexing them by events.
    43  func (is *IndexerService) OnStart() error {
    44  	// Use SubscribeUnbuffered here to ensure both subscriptions does not get
    45  	// canceled due to not pulling messages fast enough. Cause this might
    46  	// sometimes happen when there are no other subscribers.
    47  	blockHeadersSub, err := is.eventBus.SubscribeUnbuffered(
    48  		context.Background(),
    49  		subscriber,
    50  		types.EventQueryNewBlockHeader)
    51  	if err != nil {
    52  		return err
    53  	}
    54  
    55  	txsSub, err := is.eventBus.SubscribeUnbuffered(context.Background(), subscriber, types.EventQueryTx)
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	go func() {
    61  		for {
    62  			msg := <-blockHeadersSub.Out()
    63  			eventDataHeader := msg.Data().(types.EventDataNewBlockHeader)
    64  			height := eventDataHeader.Header.Height
    65  			batch := NewBatch(eventDataHeader.NumTxs)
    66  
    67  			for i := int64(0); i < eventDataHeader.NumTxs; i++ {
    68  				msg2 := <-txsSub.Out()
    69  				txResult := msg2.Data().(types.EventDataTx).TxResult
    70  
    71  				if err = batch.Add(&txResult); err != nil {
    72  					is.Logger.Error(
    73  						"failed to add tx to batch",
    74  						"height", height,
    75  						"index", txResult.Index,
    76  						"err", err,
    77  					)
    78  
    79  					if is.terminateOnError {
    80  						if err := is.Stop(); err != nil {
    81  							is.Logger.Error("failed to stop", "err", err)
    82  						}
    83  						return
    84  					}
    85  				}
    86  			}
    87  
    88  			if err := is.blockIdxr.Index(eventDataHeader); err != nil {
    89  				is.Logger.Error("failed to index block", "height", height, "err", err)
    90  				if is.terminateOnError {
    91  					if err := is.Stop(); err != nil {
    92  						is.Logger.Error("failed to stop", "err", err)
    93  					}
    94  					return
    95  				}
    96  			} else {
    97  				is.Logger.Info("indexed block exents", "height", height)
    98  			}
    99  
   100  			if err = is.txIdxr.AddBatch(batch); err != nil {
   101  				is.Logger.Error("failed to index block txs", "height", height, "err", err)
   102  				if is.terminateOnError {
   103  					if err := is.Stop(); err != nil {
   104  						is.Logger.Error("failed to stop", "err", err)
   105  					}
   106  					return
   107  				}
   108  			} else {
   109  				is.Logger.Debug("indexed transactions", "height", height, "num_txs", eventDataHeader.NumTxs)
   110  			}
   111  		}
   112  	}()
   113  	return nil
   114  }
   115  
   116  // OnStop implements service.Service by unsubscribing from all transactions.
   117  func (is *IndexerService) OnStop() {
   118  	if is.eventBus.IsRunning() {
   119  		_ = is.eventBus.UnsubscribeAll(context.Background(), subscriber)
   120  	}
   121  }