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