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.

260 lines
6.7 KiB

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