You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
4.8 KiB

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