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.

173 lines
4.3 KiB

  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "time"
  8. "github.com/spf13/viper"
  9. "github.com/tendermint/tendermint/abci/server"
  10. "github.com/tendermint/tendermint/config"
  11. tmflags "github.com/tendermint/tendermint/libs/cli/flags"
  12. "github.com/tendermint/tendermint/libs/log"
  13. tmnet "github.com/tendermint/tendermint/libs/net"
  14. "github.com/tendermint/tendermint/node"
  15. "github.com/tendermint/tendermint/p2p"
  16. "github.com/tendermint/tendermint/privval"
  17. "github.com/tendermint/tendermint/proxy"
  18. )
  19. var logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
  20. // main is the binary entrypoint.
  21. func main() {
  22. if len(os.Args) != 2 {
  23. fmt.Printf("Usage: %v <configfile>", os.Args[0])
  24. return
  25. }
  26. configFile := ""
  27. if len(os.Args) == 2 {
  28. configFile = os.Args[1]
  29. }
  30. if err := run(configFile); err != nil {
  31. logger.Error(err.Error())
  32. os.Exit(1)
  33. }
  34. }
  35. // run runs the application - basically like main() with error handling.
  36. func run(configFile string) error {
  37. cfg, err := LoadConfig(configFile)
  38. if err != nil {
  39. return err
  40. }
  41. switch cfg.Protocol {
  42. case "socket", "grpc":
  43. err = startApp(cfg)
  44. case "builtin":
  45. err = startNode(cfg)
  46. default:
  47. err = fmt.Errorf("invalid protocol %q", cfg.Protocol)
  48. }
  49. if err != nil {
  50. return err
  51. }
  52. // Start remote signer
  53. if cfg.PrivValServer != "" {
  54. if err = startSigner(cfg); err != nil {
  55. return err
  56. }
  57. }
  58. // Apparently there's no way to wait for the server, so we just sleep
  59. for {
  60. time.Sleep(1 * time.Hour)
  61. }
  62. }
  63. // startApp starts the application server, listening for connections from Tendermint.
  64. func startApp(cfg *Config) error {
  65. app, err := NewApplication(cfg)
  66. if err != nil {
  67. return err
  68. }
  69. server, err := server.NewServer(cfg.Listen, cfg.Protocol, app)
  70. if err != nil {
  71. return err
  72. }
  73. err = server.Start()
  74. if err != nil {
  75. return err
  76. }
  77. logger.Info(fmt.Sprintf("Server listening on %v (%v protocol)", cfg.Listen, cfg.Protocol))
  78. return nil
  79. }
  80. // startNode starts a Tendermint node running the application directly. It assumes the Tendermint
  81. // configuration is in $TMHOME/config/tendermint.toml.
  82. //
  83. // FIXME There is no way to simply load the configuration from a file, so we need to pull in Viper.
  84. func startNode(cfg *Config) error {
  85. app, err := NewApplication(cfg)
  86. if err != nil {
  87. return err
  88. }
  89. home := os.Getenv("TMHOME")
  90. if home == "" {
  91. return errors.New("TMHOME not set")
  92. }
  93. viper.AddConfigPath(filepath.Join(home, "config"))
  94. viper.SetConfigName("config")
  95. err = viper.ReadInConfig()
  96. if err != nil {
  97. return err
  98. }
  99. tmcfg := config.DefaultConfig()
  100. err = viper.Unmarshal(tmcfg)
  101. if err != nil {
  102. return err
  103. }
  104. tmcfg.SetRoot(home)
  105. if err = tmcfg.ValidateBasic(); err != nil {
  106. return fmt.Errorf("error in config file: %v", err)
  107. }
  108. if tmcfg.LogFormat == config.LogFormatJSON {
  109. logger = log.NewTMJSONLogger(log.NewSyncWriter(os.Stdout))
  110. }
  111. logger, err = tmflags.ParseLogLevel(tmcfg.LogLevel, logger, config.DefaultLogLevel())
  112. if err != nil {
  113. return err
  114. }
  115. logger = logger.With("module", "main")
  116. nodeKey, err := p2p.LoadOrGenNodeKey(tmcfg.NodeKeyFile())
  117. if err != nil {
  118. return fmt.Errorf("failed to load or gen node key %s: %w", tmcfg.NodeKeyFile(), err)
  119. }
  120. n, err := node.NewNode(tmcfg,
  121. privval.LoadOrGenFilePV(tmcfg.PrivValidatorKeyFile(), tmcfg.PrivValidatorStateFile()),
  122. nodeKey,
  123. proxy.NewLocalClientCreator(app),
  124. node.DefaultGenesisDocProviderFunc(tmcfg),
  125. node.DefaultDBProvider,
  126. node.DefaultMetricsProvider(tmcfg.Instrumentation),
  127. logger,
  128. )
  129. if err != nil {
  130. return err
  131. }
  132. return n.Start()
  133. }
  134. // startSigner starts a signer server connecting to the given endpoint.
  135. func startSigner(cfg *Config) error {
  136. filePV := privval.LoadFilePV(cfg.PrivValKey, cfg.PrivValState)
  137. protocol, address := tmnet.ProtocolAndAddress(cfg.PrivValServer)
  138. var dialFn privval.SocketDialer
  139. switch protocol {
  140. case "tcp":
  141. dialFn = privval.DialTCPFn(address, 3*time.Second, filePV.Key.PrivKey)
  142. case "unix":
  143. dialFn = privval.DialUnixFn(address)
  144. default:
  145. return fmt.Errorf("invalid privval protocol %q", protocol)
  146. }
  147. endpoint := privval.NewSignerDialerEndpoint(logger, dialFn,
  148. privval.SignerDialerEndpointRetryWaitInterval(1*time.Second),
  149. privval.SignerDialerEndpointConnRetries(100))
  150. err := privval.NewSignerServer(endpoint, cfg.ChainID, filePV).Start()
  151. if err != nil {
  152. return err
  153. }
  154. logger.Info(fmt.Sprintf("Remote signer connecting to %v", cfg.PrivValServer))
  155. return nil
  156. }