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.

171 lines
4.1 KiB

  1. package node
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "time"
  8. "github.com/tendermint/tendermint/config"
  9. "github.com/tendermint/tendermint/internal/p2p"
  10. "github.com/tendermint/tendermint/internal/p2p/pex"
  11. sm "github.com/tendermint/tendermint/internal/state"
  12. "github.com/tendermint/tendermint/libs/log"
  13. "github.com/tendermint/tendermint/libs/service"
  14. "github.com/tendermint/tendermint/libs/strings"
  15. tmtime "github.com/tendermint/tendermint/libs/time"
  16. "github.com/tendermint/tendermint/types"
  17. )
  18. type seedNodeImpl struct {
  19. service.BaseService
  20. logger log.Logger
  21. // config
  22. config *config.Config
  23. genesisDoc *types.GenesisDoc // initial validator set
  24. // network
  25. peerManager *p2p.PeerManager
  26. router *p2p.Router
  27. nodeInfo types.NodeInfo
  28. nodeKey types.NodeKey // our node privkey
  29. isListening bool
  30. // services
  31. pexReactor service.Service // for exchanging peer addresses
  32. shutdownOps closer
  33. }
  34. // makeSeedNode returns a new seed node, containing only p2p, pex reactor
  35. func makeSeedNode(
  36. ctx context.Context,
  37. cfg *config.Config,
  38. dbProvider config.DBProvider,
  39. nodeKey types.NodeKey,
  40. genesisDocProvider genesisDocProvider,
  41. logger log.Logger,
  42. ) (service.Service, error) {
  43. if !cfg.P2P.PexReactor {
  44. return nil, errors.New("cannot run seed nodes with PEX disabled")
  45. }
  46. genDoc, err := genesisDocProvider()
  47. if err != nil {
  48. return nil, err
  49. }
  50. state, err := sm.MakeGenesisState(genDoc)
  51. if err != nil {
  52. return nil, err
  53. }
  54. nodeInfo, err := makeSeedNodeInfo(cfg, nodeKey, genDoc, state)
  55. if err != nil {
  56. return nil, err
  57. }
  58. // Setup Transport and Switch.
  59. p2pMetrics := p2p.PrometheusMetrics(cfg.Instrumentation.Namespace, "chain_id", genDoc.ChainID)
  60. peerManager, closer, err := createPeerManager(cfg, dbProvider, nodeKey.ID)
  61. if err != nil {
  62. return nil, combineCloseError(
  63. fmt.Errorf("failed to create peer manager: %w", err),
  64. closer)
  65. }
  66. router, err := createRouter(ctx, logger, p2pMetrics, nodeInfo, nodeKey,
  67. peerManager, cfg, nil)
  68. if err != nil {
  69. return nil, combineCloseError(
  70. fmt.Errorf("failed to create router: %w", err),
  71. closer)
  72. }
  73. pexReactor, err := pex.NewReactor(ctx, logger, peerManager, router.OpenChannel, peerManager.Subscribe(ctx))
  74. if err != nil {
  75. return nil, combineCloseError(err, closer)
  76. }
  77. node := &seedNodeImpl{
  78. config: cfg,
  79. logger: logger,
  80. genesisDoc: genDoc,
  81. nodeInfo: nodeInfo,
  82. nodeKey: nodeKey,
  83. peerManager: peerManager,
  84. router: router,
  85. shutdownOps: closer,
  86. pexReactor: pexReactor,
  87. }
  88. node.BaseService = *service.NewBaseService(logger, "SeedNode", node)
  89. return node, nil
  90. }
  91. // OnStart starts the Seed Node. It implements service.Service.
  92. func (n *seedNodeImpl) OnStart(ctx context.Context) error {
  93. if n.config.RPC.PprofListenAddress != "" {
  94. rpcCtx, rpcCancel := context.WithCancel(ctx)
  95. srv := &http.Server{Addr: n.config.RPC.PprofListenAddress, Handler: nil}
  96. go func() {
  97. select {
  98. case <-ctx.Done():
  99. sctx, scancel := context.WithTimeout(context.Background(), time.Second)
  100. defer scancel()
  101. _ = srv.Shutdown(sctx)
  102. case <-rpcCtx.Done():
  103. }
  104. }()
  105. go func() {
  106. n.logger.Info("Starting pprof server", "laddr", n.config.RPC.PprofListenAddress)
  107. if err := srv.ListenAndServe(); err != nil {
  108. n.logger.Error("pprof server error", "err", err)
  109. rpcCancel()
  110. }
  111. }()
  112. }
  113. now := tmtime.Now()
  114. genTime := n.genesisDoc.GenesisTime
  115. if genTime.After(now) {
  116. n.logger.Info("Genesis time is in the future. Sleeping until then...", "genTime", genTime)
  117. time.Sleep(genTime.Sub(now))
  118. }
  119. // Start the transport.
  120. if err := n.router.Start(ctx); err != nil {
  121. return err
  122. }
  123. n.isListening = true
  124. if n.config.P2P.PexReactor {
  125. if err := n.pexReactor.Start(ctx); err != nil {
  126. return err
  127. }
  128. }
  129. return nil
  130. }
  131. // OnStop stops the Seed Node. It implements service.Service.
  132. func (n *seedNodeImpl) OnStop() {
  133. n.logger.Info("Stopping Node")
  134. n.pexReactor.Wait()
  135. n.router.Wait()
  136. n.isListening = false
  137. if err := n.shutdownOps(); err != nil {
  138. if strings.TrimSpace(err.Error()) != "" {
  139. n.logger.Error("problem shutting down additional services", "err", err)
  140. }
  141. }
  142. }