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.

232 lines
6.0 KiB

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