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.

141 lines
4.6 KiB

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