github.com/badrootd/nibiru-cometbft@v0.37.5-0.20240307173500-2a75559eee9b/cmd/cometbft/commands/reindex_event.go (about) 1 package commands 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 8 "github.com/spf13/cobra" 9 10 dbm "github.com/badrootd/nibiru-db" 11 12 abcitypes "github.com/badrootd/nibiru-cometbft/abci/types" 13 cmtcfg "github.com/badrootd/nibiru-cometbft/config" 14 "github.com/badrootd/nibiru-cometbft/libs/progressbar" 15 "github.com/badrootd/nibiru-cometbft/state" 16 "github.com/badrootd/nibiru-cometbft/state/indexer" 17 blockidxkv "github.com/badrootd/nibiru-cometbft/state/indexer/block/kv" 18 "github.com/badrootd/nibiru-cometbft/state/indexer/sink/psql" 19 "github.com/badrootd/nibiru-cometbft/state/txindex" 20 "github.com/badrootd/nibiru-cometbft/state/txindex/kv" 21 "github.com/badrootd/nibiru-cometbft/types" 22 ) 23 24 const ( 25 reindexFailed = "event re-index failed: " 26 ) 27 28 var ( 29 ErrHeightNotAvailable = errors.New("height is not available") 30 ErrInvalidRequest = errors.New("invalid request") 31 ) 32 33 // ReIndexEventCmd constructs a command to re-index events in a block height interval. 34 var ReIndexEventCmd = &cobra.Command{ 35 Use: "reindex-event", 36 Aliases: []string{"reindex_event"}, 37 Short: "reindex events to the event store backends", 38 Long: ` 39 reindex-event is an offline tooling to re-index block and tx events to the eventsinks, 40 you can run this command when the event store backend dropped/disconnected or you want to 41 replace the backend. The default start-height is 0, meaning the tooling will start 42 reindex from the base block height(inclusive); and the default end-height is 0, meaning 43 the tooling will reindex until the latest block height(inclusive). User can omit 44 either or both arguments. 45 46 Note: This operation requires ABCI Responses. Do not set DiscardABCIResponses to true if you 47 want to use this command. 48 `, 49 Example: ` 50 cometbft reindex-event 51 cometbft reindex-event --start-height 2 52 cometbft reindex-event --end-height 10 53 cometbft reindex-event --start-height 2 --end-height 10 54 `, 55 Run: func(cmd *cobra.Command, args []string) { 56 bs, ss, err := loadStateAndBlockStore(config) 57 if err != nil { 58 fmt.Println(reindexFailed, err) 59 return 60 } 61 62 if err := checkValidHeight(bs); err != nil { 63 fmt.Println(reindexFailed, err) 64 return 65 } 66 67 bi, ti, err := loadEventSinks(config) 68 if err != nil { 69 fmt.Println(reindexFailed, err) 70 return 71 } 72 73 riArgs := eventReIndexArgs{ 74 startHeight: startHeight, 75 endHeight: endHeight, 76 blockIndexer: bi, 77 txIndexer: ti, 78 blockStore: bs, 79 stateStore: ss, 80 } 81 if err := eventReIndex(cmd, riArgs); err != nil { 82 panic(fmt.Errorf("%s: %w", reindexFailed, err)) 83 } 84 85 fmt.Println("event re-index finished") 86 }, 87 } 88 89 var ( 90 startHeight int64 91 endHeight int64 92 ) 93 94 func init() { 95 ReIndexEventCmd.Flags().Int64Var(&startHeight, "start-height", 0, "the block height would like to start for re-index") 96 ReIndexEventCmd.Flags().Int64Var(&endHeight, "end-height", 0, "the block height would like to finish for re-index") 97 } 98 99 func loadEventSinks(cfg *cmtcfg.Config) (indexer.BlockIndexer, txindex.TxIndexer, error) { 100 switch strings.ToLower(cfg.TxIndex.Indexer) { 101 case "null": 102 return nil, nil, errors.New("found null event sink, please check the tx-index section in the config.toml") 103 case "psql": 104 conn := cfg.TxIndex.PsqlConn 105 if conn == "" { 106 return nil, nil, errors.New("the psql connection settings cannot be empty") 107 } 108 es, err := psql.NewEventSink(conn, cfg.ChainID()) 109 if err != nil { 110 return nil, nil, err 111 } 112 return es.BlockIndexer(), es.TxIndexer(), nil 113 case "kv": 114 store, err := dbm.NewDB("tx_index", dbm.BackendType(cfg.DBBackend), cfg.DBDir()) 115 if err != nil { 116 return nil, nil, err 117 } 118 119 txIndexer := kv.NewTxIndex(store) 120 blockIndexer := blockidxkv.New(dbm.NewPrefixDB(store, []byte("block_events"))) 121 return blockIndexer, txIndexer, nil 122 default: 123 return nil, nil, fmt.Errorf("unsupported event sink type: %s", cfg.TxIndex.Indexer) 124 } 125 } 126 127 type eventReIndexArgs struct { 128 startHeight int64 129 endHeight int64 130 blockIndexer indexer.BlockIndexer 131 txIndexer txindex.TxIndexer 132 blockStore state.BlockStore 133 stateStore state.Store 134 } 135 136 func eventReIndex(cmd *cobra.Command, args eventReIndexArgs) error { 137 var bar progressbar.Bar 138 bar.NewOption(args.startHeight-1, args.endHeight) 139 140 fmt.Println("start re-indexing events:") 141 defer bar.Finish() 142 for i := args.startHeight; i <= args.endHeight; i++ { 143 select { 144 case <-cmd.Context().Done(): 145 return fmt.Errorf("event re-index terminated at height %d: %w", i, cmd.Context().Err()) 146 default: 147 b := args.blockStore.LoadBlock(i) 148 if b == nil { 149 return fmt.Errorf("not able to load block at height %d from the blockstore", i) 150 } 151 152 r, err := args.stateStore.LoadABCIResponses(i) 153 if err != nil { 154 return fmt.Errorf("not able to load ABCI Response at height %d from the statestore", i) 155 } 156 157 e := types.EventDataNewBlockHeader{ 158 Header: b.Header, 159 NumTxs: int64(len(b.Txs)), 160 ResultBeginBlock: *r.BeginBlock, 161 ResultEndBlock: *r.EndBlock, 162 } 163 164 var batch *txindex.Batch 165 if e.NumTxs > 0 { 166 batch = txindex.NewBatch(e.NumTxs) 167 168 for i := range b.Data.Txs { 169 tr := abcitypes.TxResult{ 170 Height: b.Height, 171 Index: uint32(i), 172 Tx: b.Data.Txs[i], 173 Result: *(r.DeliverTxs[i]), 174 } 175 176 if err = batch.Add(&tr); err != nil { 177 return fmt.Errorf("adding tx to batch: %w", err) 178 } 179 } 180 181 if err := args.txIndexer.AddBatch(batch); err != nil { 182 return fmt.Errorf("tx event re-index at height %d failed: %w", i, err) 183 } 184 } 185 186 if err := args.blockIndexer.Index(e); err != nil { 187 return fmt.Errorf("block event re-index at height %d failed: %w", i, err) 188 } 189 } 190 191 bar.Play(i) 192 } 193 194 return nil 195 } 196 197 func checkValidHeight(bs state.BlockStore) error { 198 base := bs.Base() 199 200 if startHeight == 0 { 201 startHeight = base 202 fmt.Printf("set the start block height to the base height of the blockstore %d \n", base) 203 } 204 205 if startHeight < base { 206 return fmt.Errorf("%s (requested start height: %d, base height: %d)", 207 ErrHeightNotAvailable, startHeight, base) 208 } 209 210 height := bs.Height() 211 212 if startHeight > height { 213 return fmt.Errorf( 214 "%s (requested start height: %d, store height: %d)", ErrHeightNotAvailable, startHeight, height) 215 } 216 217 if endHeight == 0 || endHeight > height { 218 endHeight = height 219 fmt.Printf("set the end block height to the latest height of the blockstore %d \n", height) 220 } 221 222 if endHeight < base { 223 return fmt.Errorf( 224 "%s (requested end height: %d, base height: %d)", ErrHeightNotAvailable, endHeight, base) 225 } 226 227 if endHeight < startHeight { 228 return fmt.Errorf( 229 "%s (requested the end height: %d is less than the start height: %d)", 230 ErrInvalidRequest, startHeight, endHeight) 231 } 232 233 return nil 234 }