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.

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