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.

237 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. pval, err := privval.LoadOrGenFilePV(tmcfg.PrivValidatorKeyFile(), tmcfg.PrivValidatorStateFile())
  106. if err != nil {
  107. return err
  108. }
  109. n, err := node.NewNode(tmcfg,
  110. pval,
  111. *nodeKey,
  112. proxy.NewLocalClientCreator(app),
  113. node.DefaultGenesisDocProviderFunc(tmcfg),
  114. node.DefaultDBProvider,
  115. node.DefaultMetricsProvider(tmcfg.Instrumentation),
  116. nodeLogger,
  117. )
  118. if err != nil {
  119. return err
  120. }
  121. return n.Start()
  122. }
  123. // startMaverick starts a Maverick node that runs the application directly. It assumes the Tendermint
  124. // configuration is in $TMHOME/config/tendermint.toml.
  125. func startMaverick(cfg *Config) error {
  126. app, err := NewApplication(cfg)
  127. if err != nil {
  128. return err
  129. }
  130. tmcfg, logger, nodeKey, err := setupNode()
  131. if err != nil {
  132. return fmt.Errorf("failed to setup config: %w", err)
  133. }
  134. misbehaviors := make(map[int64]mcs.Misbehavior, len(cfg.Misbehaviors))
  135. for heightString, misbehaviorString := range cfg.Misbehaviors {
  136. height, _ := strconv.ParseInt(heightString, 10, 64)
  137. misbehaviors[height] = mcs.MisbehaviorList[misbehaviorString]
  138. }
  139. n, err := maverick.NewNode(tmcfg,
  140. maverick.LoadOrGenFilePV(tmcfg.PrivValidatorKeyFile(), tmcfg.PrivValidatorStateFile()),
  141. *nodeKey,
  142. proxy.NewLocalClientCreator(app),
  143. maverick.DefaultGenesisDocProviderFunc(tmcfg),
  144. maverick.DefaultDBProvider,
  145. maverick.DefaultMetricsProvider(tmcfg.Instrumentation),
  146. logger,
  147. misbehaviors,
  148. )
  149. if err != nil {
  150. return err
  151. }
  152. return n.Start()
  153. }
  154. // startSigner starts a signer server connecting to the given endpoint.
  155. func startSigner(cfg *Config) error {
  156. filePV := privval.LoadFilePV(cfg.PrivValKey, cfg.PrivValState)
  157. protocol, address := tmnet.ProtocolAndAddress(cfg.PrivValServer)
  158. var dialFn privval.SocketDialer
  159. switch protocol {
  160. case "tcp":
  161. dialFn = privval.DialTCPFn(address, 3*time.Second, ed25519.GenPrivKey())
  162. case "unix":
  163. dialFn = privval.DialUnixFn(address)
  164. default:
  165. return fmt.Errorf("invalid privval protocol %q", protocol)
  166. }
  167. endpoint := privval.NewSignerDialerEndpoint(logger, dialFn,
  168. privval.SignerDialerEndpointRetryWaitInterval(1*time.Second),
  169. privval.SignerDialerEndpointConnRetries(100))
  170. err := privval.NewSignerServer(endpoint, cfg.ChainID, filePV).Start()
  171. if err != nil {
  172. return err
  173. }
  174. logger.Info(fmt.Sprintf("Remote signer connecting to %v", cfg.PrivValServer))
  175. return nil
  176. }
  177. func setupNode() (*config.Config, log.Logger, *p2p.NodeKey, error) {
  178. var tmcfg *config.Config
  179. home := os.Getenv("TMHOME")
  180. if home == "" {
  181. return nil, nil, nil, errors.New("TMHOME not set")
  182. }
  183. viper.AddConfigPath(filepath.Join(home, "config"))
  184. viper.SetConfigName("config")
  185. err := viper.ReadInConfig()
  186. if err != nil {
  187. return nil, nil, nil, err
  188. }
  189. tmcfg = config.DefaultConfig()
  190. err = viper.Unmarshal(tmcfg)
  191. if err != nil {
  192. return nil, nil, nil, err
  193. }
  194. tmcfg.SetRoot(home)
  195. if err = tmcfg.ValidateBasic(); err != nil {
  196. return nil, nil, nil, fmt.Errorf("error in config file: %w", err)
  197. }
  198. if tmcfg.LogFormat == config.LogFormatJSON {
  199. logger = log.NewTMJSONLogger(log.NewSyncWriter(os.Stdout))
  200. }
  201. nodeLogger, err := tmflags.ParseLogLevel(tmcfg.LogLevel, logger, config.DefaultLogLevel())
  202. if err != nil {
  203. return nil, nil, nil, err
  204. }
  205. nodeLogger = nodeLogger.With("module", "main")
  206. nodeKey, err := p2p.LoadOrGenNodeKey(tmcfg.NodeKeyFile())
  207. if err != nil {
  208. return nil, nil, nil, fmt.Errorf("failed to load or gen node key %s: %w", tmcfg.NodeKeyFile(), err)
  209. }
  210. return tmcfg, nodeLogger, &nodeKey, nil
  211. }