github.com/arcology-network/consensus-engine@v1.9.0/state/txindex/indexer_service.go (about)

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