github.com/aakash4dev/cometbft@v0.38.2/inspect/inspect.go (about) 1 package inspect 2 3 import ( 4 "context" 5 "errors" 6 "net" 7 "os" 8 9 "github.com/aakash4dev/cometbft/config" 10 "github.com/aakash4dev/cometbft/inspect/rpc" 11 "github.com/aakash4dev/cometbft/libs/log" 12 cmtstrings "github.com/aakash4dev/cometbft/libs/strings" 13 rpccore "github.com/aakash4dev/cometbft/rpc/core" 14 "github.com/aakash4dev/cometbft/state" 15 "github.com/aakash4dev/cometbft/state/indexer" 16 "github.com/aakash4dev/cometbft/state/indexer/block" 17 "github.com/aakash4dev/cometbft/state/txindex" 18 "github.com/aakash4dev/cometbft/store" 19 "github.com/aakash4dev/cometbft/types" 20 21 "golang.org/x/sync/errgroup" 22 ) 23 24 var logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)) 25 26 // Inspector manages an RPC service that exports methods to debug a failed node. 27 // After a node shuts down due to a consensus failure, it will no longer start 28 // up its state cannot easily be inspected. An Inspector value provides a similar interface 29 // to the node, using the underlying CometBFT data stores, without bringing up 30 // any other components. A caller can query the Inspector service to inspect the 31 // persisted state and debug the failure. 32 type Inspector struct { 33 routes rpccore.RoutesMap 34 35 config *config.RPCConfig 36 37 logger log.Logger 38 39 // References to the state store and block store are maintained to enable 40 // the Inspector to safely close them on shutdown. 41 ss state.Store 42 bs state.BlockStore 43 } 44 45 // New returns an Inspector that serves RPC on the specified BlockStore and StateStore. 46 // The Inspector type does not modify the state or block stores. 47 // The sinks are used to enable block and transaction querying via the RPC server. 48 // The caller is responsible for starting and stopping the Inspector service. 49 // 50 //nolint:lll 51 func New( 52 cfg *config.RPCConfig, 53 bs state.BlockStore, 54 ss state.Store, 55 txidx txindex.TxIndexer, 56 blkidx indexer.BlockIndexer, 57 ) *Inspector { 58 routes := rpc.Routes(*cfg, ss, bs, txidx, blkidx, logger) 59 eb := types.NewEventBus() 60 eb.SetLogger(logger.With("module", "events")) 61 return &Inspector{ 62 routes: routes, 63 config: cfg, 64 logger: logger, 65 ss: ss, 66 bs: bs, 67 } 68 } 69 70 // NewFromConfig constructs an Inspector using the values defined in the passed in config. 71 func NewFromConfig(cfg *config.Config) (*Inspector, error) { 72 bsDB, err := config.DefaultDBProvider(&config.DBContext{ID: "blockstore", Config: cfg}) 73 if err != nil { 74 return nil, err 75 } 76 bs := store.NewBlockStore(bsDB) 77 sDB, err := config.DefaultDBProvider(&config.DBContext{ID: "state", Config: cfg}) 78 if err != nil { 79 return nil, err 80 } 81 genDoc, err := types.GenesisDocFromFile(cfg.GenesisFile()) 82 if err != nil { 83 return nil, err 84 } 85 txidx, blkidx, err := block.IndexerFromConfig(cfg, config.DefaultDBProvider, genDoc.ChainID) 86 if err != nil { 87 return nil, err 88 } 89 ss := state.NewStore(sDB, state.StoreOptions{}) 90 return New(cfg.RPC, bs, ss, txidx, blkidx), nil 91 } 92 93 // Run starts the Inspector servers and blocks until the servers shut down. The passed 94 // in context is used to control the lifecycle of the servers. 95 func (ins *Inspector) Run(ctx context.Context) error { 96 defer ins.bs.Close() 97 defer ins.ss.Close() 98 99 return startRPCServers(ctx, ins.config, ins.logger, ins.routes) 100 } 101 102 func startRPCServers(ctx context.Context, cfg *config.RPCConfig, logger log.Logger, routes rpccore.RoutesMap) error { 103 g, tctx := errgroup.WithContext(ctx) 104 listenAddrs := cmtstrings.SplitAndTrimEmpty(cfg.ListenAddress, ",", " ") 105 rh := rpc.Handler(cfg, routes, logger) 106 for _, listenerAddr := range listenAddrs { 107 server := rpc.Server{ 108 Logger: logger, 109 Config: cfg, 110 Handler: rh, 111 Addr: listenerAddr, 112 } 113 if cfg.IsTLSEnabled() { 114 keyFile := cfg.KeyFile() 115 certFile := cfg.CertFile() 116 listenerAddr := listenerAddr 117 g.Go(func() error { 118 logger.Info("RPC HTTPS server starting", "address", listenerAddr, 119 "certfile", certFile, "keyfile", keyFile) 120 err := server.ListenAndServeTLS(tctx, certFile, keyFile) 121 if !errors.Is(err, net.ErrClosed) { 122 return err 123 } 124 logger.Info("RPC HTTPS server stopped", "address", listenerAddr) 125 return nil 126 }) 127 } else { 128 listenerAddr := listenerAddr 129 g.Go(func() error { 130 logger.Info("RPC HTTP server starting", "address", listenerAddr) 131 err := server.ListenAndServe(tctx) 132 if !errors.Is(err, net.ErrClosed) { 133 return err 134 } 135 logger.Info("RPC HTTP server stopped", "address", listenerAddr) 136 return nil 137 }) 138 } 139 } 140 return g.Wait() 141 }