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 }