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.

177 lines
4.4 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. // Start remote signer (must start before node if running builtin).
  42. if cfg.PrivValServer != "" {
  43. if err = startSigner(cfg); err != nil {
  44. return err
  45. }
  46. if cfg.Protocol == "builtin" {
  47. time.Sleep(1 * time.Second)
  48. }
  49. }
  50. // Start app server.
  51. switch cfg.Protocol {
  52. case "socket", "grpc":
  53. err = startApp(cfg)
  54. case "builtin":
  55. err = startNode(cfg)
  56. default:
  57. err = fmt.Errorf("invalid protocol %q", cfg.Protocol)
  58. }
  59. if err != nil {
  60. return err
  61. }
  62. // Apparently there's no way to wait for the server, so we just sleep
  63. for {
  64. time.Sleep(1 * time.Hour)
  65. }
  66. }
  67. // startApp starts the application server, listening for connections from Tendermint.
  68. func startApp(cfg *Config) error {
  69. app, err := NewApplication(cfg)
  70. if err != nil {
  71. return err
  72. }
  73. server, err := server.NewServer(cfg.Listen, cfg.Protocol, app)
  74. if err != nil {
  75. return err
  76. }
  77. err = server.Start()
  78. if err != nil {
  79. return err
  80. }
  81. logger.Info(fmt.Sprintf("Server listening on %v (%v protocol)", cfg.Listen, cfg.Protocol))
  82. return nil
  83. }
  84. // startNode starts a Tendermint node running the application directly. It assumes the Tendermint
  85. // configuration is in $TMHOME/config/tendermint.toml.
  86. //
  87. // FIXME There is no way to simply load the configuration from a file, so we need to pull in Viper.
  88. func startNode(cfg *Config) error {
  89. app, err := NewApplication(cfg)
  90. if err != nil {
  91. return err
  92. }
  93. home := os.Getenv("TMHOME")
  94. if home == "" {
  95. return errors.New("TMHOME not set")
  96. }
  97. viper.AddConfigPath(filepath.Join(home, "config"))
  98. viper.SetConfigName("config")
  99. err = viper.ReadInConfig()
  100. if err != nil {
  101. return err
  102. }
  103. tmcfg := config.DefaultConfig()
  104. err = viper.Unmarshal(tmcfg)
  105. if err != nil {
  106. return err
  107. }
  108. tmcfg.SetRoot(home)
  109. if err = tmcfg.ValidateBasic(); err != nil {
  110. return fmt.Errorf("error in config file: %v", err)
  111. }
  112. if tmcfg.LogFormat == config.LogFormatJSON {
  113. logger = log.NewTMJSONLogger(log.NewSyncWriter(os.Stdout))
  114. }
  115. logger, err = tmflags.ParseLogLevel(tmcfg.LogLevel, logger, config.DefaultLogLevel())
  116. if err != nil {
  117. return err
  118. }
  119. logger = logger.With("module", "main")
  120. nodeKey, err := p2p.LoadOrGenNodeKey(tmcfg.NodeKeyFile())
  121. if err != nil {
  122. return fmt.Errorf("failed to load or gen node key %s: %w", tmcfg.NodeKeyFile(), err)
  123. }
  124. n, err := node.NewNode(tmcfg,
  125. privval.LoadOrGenFilePV(tmcfg.PrivValidatorKeyFile(), tmcfg.PrivValidatorStateFile()),
  126. nodeKey,
  127. proxy.NewLocalClientCreator(app),
  128. node.DefaultGenesisDocProviderFunc(tmcfg),
  129. node.DefaultDBProvider,
  130. node.DefaultMetricsProvider(tmcfg.Instrumentation),
  131. logger,
  132. )
  133. if err != nil {
  134. return err
  135. }
  136. return n.Start()
  137. }
  138. // startSigner starts a signer server connecting to the given endpoint.
  139. func startSigner(cfg *Config) error {
  140. filePV := privval.LoadFilePV(cfg.PrivValKey, cfg.PrivValState)
  141. protocol, address := tmnet.ProtocolAndAddress(cfg.PrivValServer)
  142. var dialFn privval.SocketDialer
  143. switch protocol {
  144. case "tcp":
  145. dialFn = privval.DialTCPFn(address, 3*time.Second, filePV.Key.PrivKey)
  146. case "unix":
  147. dialFn = privval.DialUnixFn(address)
  148. default:
  149. return fmt.Errorf("invalid privval protocol %q", protocol)
  150. }
  151. endpoint := privval.NewSignerDialerEndpoint(logger, dialFn,
  152. privval.SignerDialerEndpointRetryWaitInterval(1*time.Second),
  153. privval.SignerDialerEndpointConnRetries(100))
  154. err := privval.NewSignerServer(endpoint, cfg.ChainID, filePV).Start()
  155. if err != nil {
  156. return err
  157. }
  158. logger.Info(fmt.Sprintf("Remote signer connecting to %v", cfg.PrivValServer))
  159. return nil
  160. }