github.com/okex/exchain@v1.8.0/libs/tendermint/state/txindex/indexer_service.go (about)

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