github.com/KYVENetwork/cometbft/v38@v38.0.3/state/txindex/indexer_service.go (about)

     1  package txindex
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/KYVENetwork/cometbft/v38/libs/service"
     7  	"github.com/KYVENetwork/cometbft/v38/state/indexer"
     8  	"github.com/KYVENetwork/cometbft/v38/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  	blockSub, err := is.eventBus.SubscribeUnbuffered(
    48  		context.Background(),
    49  		subscriber,
    50  		types.EventQueryNewBlockEvents)
    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  			select {
    63  			case <-blockSub.Canceled():
    64  				return
    65  			case msg := <-blockSub.Out():
    66  				eventNewBlockEvents := msg.Data().(types.EventDataNewBlockEvents)
    67  				height := eventNewBlockEvents.Height
    68  				numTxs := eventNewBlockEvents.NumTxs
    69  
    70  				batch := NewBatch(numTxs)
    71  
    72  				for i := int64(0); i < numTxs; i++ {
    73  					msg2 := <-txsSub.Out()
    74  					txResult := msg2.Data().(types.EventDataTx).TxResult
    75  
    76  					if err = batch.Add(&txResult); err != nil {
    77  						is.Logger.Error(
    78  							"failed to add tx to batch",
    79  							"height", height,
    80  							"index", txResult.Index,
    81  							"err", err,
    82  						)
    83  
    84  						if is.terminateOnError {
    85  							if err := is.Stop(); err != nil {
    86  								is.Logger.Error("failed to stop", "err", err)
    87  							}
    88  							return
    89  						}
    90  					}
    91  				}
    92  
    93  				if err := is.blockIdxr.Index(eventNewBlockEvents); err != nil {
    94  					is.Logger.Error("failed to index block", "height", height, "err", err)
    95  					if is.terminateOnError {
    96  						if err := is.Stop(); err != nil {
    97  							is.Logger.Error("failed to stop", "err", err)
    98  						}
    99  						return
   100  					}
   101  				} else {
   102  					is.Logger.Info("indexed block events", "height", height)
   103  				}
   104  
   105  				if err = is.txIdxr.AddBatch(batch); err != nil {
   106  					is.Logger.Error("failed to index block txs", "height", height, "err", err)
   107  					if is.terminateOnError {
   108  						if err := is.Stop(); err != nil {
   109  							is.Logger.Error("failed to stop", "err", err)
   110  						}
   111  						return
   112  					}
   113  				} else {
   114  					is.Logger.Debug("indexed transactions", "height", height, "num_txs", numTxs)
   115  				}
   116  			}
   117  		}
   118  	}()
   119  	return nil
   120  }
   121  
   122  // OnStop implements service.Service by unsubscribing from all transactions.
   123  func (is *IndexerService) OnStop() {
   124  	if is.eventBus.IsRunning() {
   125  		_ = is.eventBus.UnsubscribeAll(context.Background(), subscriber)
   126  	}
   127  }