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.

142 lines
4.6 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. eb := eventbus.NewDefault(logger.With("module", "events"))
  41. return &Inspector{
  42. routes: rpc.Routes(*cfg, ss, bs, es, logger),
  43. config: cfg,
  44. logger: logger,
  45. eventBus: eb,
  46. indexerService: indexer.NewService(indexer.ServiceArgs{
  47. Sinks: es,
  48. EventBus: eb,
  49. Logger: logger.With("module", "txindex"),
  50. }),
  51. }
  52. }
  53. // NewFromConfig constructs an Inspector using the values defined in the passed in config.
  54. func NewFromConfig(logger log.Logger, cfg *config.Config) (*Inspector, error) {
  55. bsDB, err := config.DefaultDBProvider(&config.DBContext{ID: "blockstore", Config: cfg})
  56. if err != nil {
  57. return nil, err
  58. }
  59. bs := store.NewBlockStore(bsDB)
  60. sDB, err := config.DefaultDBProvider(&config.DBContext{ID: "state", Config: cfg})
  61. if err != nil {
  62. return nil, err
  63. }
  64. genDoc, err := types.GenesisDocFromFile(cfg.GenesisFile())
  65. if err != nil {
  66. return nil, err
  67. }
  68. sinks, err := sink.EventSinksFromConfig(cfg, config.DefaultDBProvider, genDoc.ChainID)
  69. if err != nil {
  70. return nil, err
  71. }
  72. ss := state.NewStore(sDB)
  73. return New(cfg.RPC, bs, ss, sinks, logger), nil
  74. }
  75. // Run starts the Inspector servers and blocks until the servers shut down. The passed
  76. // in context is used to control the lifecycle of the servers.
  77. func (ins *Inspector) Run(ctx context.Context) error {
  78. err := ins.eventBus.Start(ctx)
  79. if err != nil {
  80. return fmt.Errorf("error starting event bus: %s", err)
  81. }
  82. defer ins.eventBus.Wait()
  83. err = ins.indexerService.Start(ctx)
  84. if err != nil {
  85. return fmt.Errorf("error starting indexer service: %s", err)
  86. }
  87. defer ins.indexerService.Wait()
  88. return startRPCServers(ctx, ins.config, ins.logger, ins.routes)
  89. }
  90. func startRPCServers(ctx context.Context, cfg *config.RPCConfig, logger log.Logger, routes rpccore.RoutesMap) error {
  91. g, tctx := errgroup.WithContext(ctx)
  92. listenAddrs := tmstrings.SplitAndTrimEmpty(cfg.ListenAddress, ",", " ")
  93. rh := rpc.Handler(cfg, routes, logger)
  94. for _, listenerAddr := range listenAddrs {
  95. server := rpc.Server{
  96. Logger: logger,
  97. Config: cfg,
  98. Handler: rh,
  99. Addr: listenerAddr,
  100. }
  101. if cfg.IsTLSEnabled() {
  102. keyFile := cfg.KeyFile()
  103. certFile := cfg.CertFile()
  104. listenerAddr := listenerAddr
  105. g.Go(func() error {
  106. logger.Info("RPC HTTPS server starting", "address", listenerAddr,
  107. "certfile", certFile, "keyfile", keyFile)
  108. err := server.ListenAndServeTLS(tctx, certFile, keyFile)
  109. if !errors.Is(err, net.ErrClosed) {
  110. return err
  111. }
  112. logger.Info("RPC HTTPS server stopped", "address", listenerAddr)
  113. return nil
  114. })
  115. } else {
  116. listenerAddr := listenerAddr
  117. g.Go(func() error {
  118. logger.Info("RPC HTTP server starting", "address", listenerAddr)
  119. err := server.ListenAndServe(tctx)
  120. if !errors.Is(err, net.ErrClosed) {
  121. return err
  122. }
  123. logger.Info("RPC HTTP server stopped", "address", listenerAddr)
  124. return nil
  125. })
  126. }
  127. }
  128. return g.Wait()
  129. }