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