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.

383 lines
9.8 KiB

  1. package main
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "net"
  7. "net/http"
  8. "os"
  9. "path/filepath"
  10. "strings"
  11. "time"
  12. "github.com/spf13/viper"
  13. "google.golang.org/grpc"
  14. "github.com/tendermint/tendermint/abci/server"
  15. "github.com/tendermint/tendermint/config"
  16. "github.com/tendermint/tendermint/crypto/ed25519"
  17. tmflags "github.com/tendermint/tendermint/libs/cli/flags"
  18. "github.com/tendermint/tendermint/libs/log"
  19. tmnet "github.com/tendermint/tendermint/libs/net"
  20. "github.com/tendermint/tendermint/light"
  21. lproxy "github.com/tendermint/tendermint/light/proxy"
  22. lrpc "github.com/tendermint/tendermint/light/rpc"
  23. dbs "github.com/tendermint/tendermint/light/store/db"
  24. "github.com/tendermint/tendermint/node"
  25. "github.com/tendermint/tendermint/p2p"
  26. "github.com/tendermint/tendermint/privval"
  27. grpcprivval "github.com/tendermint/tendermint/privval/grpc"
  28. privvalproto "github.com/tendermint/tendermint/proto/tendermint/privval"
  29. "github.com/tendermint/tendermint/proxy"
  30. rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server"
  31. e2e "github.com/tendermint/tendermint/test/e2e/pkg"
  32. )
  33. var logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
  34. // main is the binary entrypoint.
  35. func main() {
  36. if len(os.Args) != 2 {
  37. fmt.Printf("Usage: %v <configfile>", os.Args[0])
  38. return
  39. }
  40. configFile := ""
  41. if len(os.Args) == 2 {
  42. configFile = os.Args[1]
  43. }
  44. if err := run(configFile); err != nil {
  45. logger.Error(err.Error())
  46. os.Exit(1)
  47. }
  48. }
  49. // run runs the application - basically like main() with error handling.
  50. func run(configFile string) error {
  51. cfg, err := LoadConfig(configFile)
  52. if err != nil {
  53. return err
  54. }
  55. // Start remote signer (must start before node if running builtin).
  56. if cfg.PrivValServer != "" {
  57. if err = startSigner(cfg); err != nil {
  58. return err
  59. }
  60. if cfg.Protocol == "builtin" {
  61. time.Sleep(1 * time.Second)
  62. }
  63. }
  64. // Start app server.
  65. switch cfg.Protocol {
  66. case "socket", "grpc":
  67. err = startApp(cfg)
  68. case "builtin":
  69. switch cfg.Mode {
  70. case string(e2e.ModeLight):
  71. err = startLightNode(cfg)
  72. case string(e2e.ModeSeed):
  73. err = startSeedNode(cfg)
  74. default:
  75. err = startNode(cfg)
  76. }
  77. // FIXME: Temporarily remove maverick until it is redesigned
  78. // if len(cfg.Misbehaviors) == 0 {
  79. // err = startMaverick(cfg)
  80. // }
  81. default:
  82. err = fmt.Errorf("invalid protocol %q", cfg.Protocol)
  83. }
  84. if err != nil {
  85. return err
  86. }
  87. // Apparently there's no way to wait for the server, so we just sleep
  88. for {
  89. time.Sleep(1 * time.Hour)
  90. }
  91. }
  92. // startApp starts the application server, listening for connections from Tendermint.
  93. func startApp(cfg *Config) error {
  94. app, err := NewApplication(cfg)
  95. if err != nil {
  96. return err
  97. }
  98. server, err := server.NewServer(cfg.Listen, cfg.Protocol, app)
  99. if err != nil {
  100. return err
  101. }
  102. err = server.Start()
  103. if err != nil {
  104. return err
  105. }
  106. logger.Info(fmt.Sprintf("Server listening on %v (%v protocol)", cfg.Listen, cfg.Protocol))
  107. return nil
  108. }
  109. // startNode starts a Tendermint node running the application directly. It assumes the Tendermint
  110. // configuration is in $TMHOME/config/tendermint.toml.
  111. //
  112. // FIXME There is no way to simply load the configuration from a file, so we need to pull in Viper.
  113. func startNode(cfg *Config) error {
  114. app, err := NewApplication(cfg)
  115. if err != nil {
  116. return err
  117. }
  118. tmcfg, nodeLogger, nodeKey, err := setupNode()
  119. if err != nil {
  120. return fmt.Errorf("failed to setup config: %w", err)
  121. }
  122. pval, err := privval.LoadOrGenFilePV(tmcfg.PrivValidatorKeyFile(), tmcfg.PrivValidatorStateFile())
  123. if err != nil {
  124. return err
  125. }
  126. n, err := node.NewNode(tmcfg,
  127. pval,
  128. *nodeKey,
  129. proxy.NewLocalClientCreator(app),
  130. node.DefaultGenesisDocProviderFunc(tmcfg),
  131. node.DefaultDBProvider,
  132. node.DefaultMetricsProvider(tmcfg.Instrumentation),
  133. nodeLogger,
  134. )
  135. if err != nil {
  136. return err
  137. }
  138. return n.Start()
  139. }
  140. func startSeedNode(cfg *Config) error {
  141. tmcfg, nodeLogger, nodeKey, err := setupNode()
  142. if err != nil {
  143. return fmt.Errorf("failed to setup config: %w", err)
  144. }
  145. n, err := node.NewSeedNode(
  146. tmcfg,
  147. *nodeKey,
  148. node.DefaultGenesisDocProviderFunc(tmcfg),
  149. nodeLogger,
  150. )
  151. if err != nil {
  152. return err
  153. }
  154. return n.Start()
  155. }
  156. func startLightNode(cfg *Config) error {
  157. tmcfg, nodeLogger, _, err := setupNode()
  158. if err != nil {
  159. return err
  160. }
  161. dbContext := &node.DBContext{ID: "light", Config: tmcfg}
  162. lightDB, err := node.DefaultDBProvider(dbContext)
  163. if err != nil {
  164. return err
  165. }
  166. providers := rpcEndpoints(tmcfg.P2P.PersistentPeers)
  167. c, err := light.NewHTTPClient(
  168. context.Background(),
  169. cfg.ChainID,
  170. light.TrustOptions{
  171. Period: tmcfg.StateSync.TrustPeriod,
  172. Height: tmcfg.StateSync.TrustHeight,
  173. Hash: tmcfg.StateSync.TrustHashBytes(),
  174. },
  175. providers[0],
  176. providers[1:],
  177. dbs.New(lightDB),
  178. light.Logger(nodeLogger),
  179. )
  180. if err != nil {
  181. return err
  182. }
  183. rpccfg := rpcserver.DefaultConfig()
  184. rpccfg.MaxBodyBytes = tmcfg.RPC.MaxBodyBytes
  185. rpccfg.MaxHeaderBytes = tmcfg.RPC.MaxHeaderBytes
  186. rpccfg.MaxOpenConnections = tmcfg.RPC.MaxOpenConnections
  187. // If necessary adjust global WriteTimeout to ensure it's greater than
  188. // TimeoutBroadcastTxCommit.
  189. // See https://github.com/tendermint/tendermint/issues/3435
  190. if rpccfg.WriteTimeout <= tmcfg.RPC.TimeoutBroadcastTxCommit {
  191. rpccfg.WriteTimeout = tmcfg.RPC.TimeoutBroadcastTxCommit + 1*time.Second
  192. }
  193. p, err := lproxy.NewProxy(c, tmcfg.RPC.ListenAddress, providers[0], rpccfg, nodeLogger,
  194. lrpc.KeyPathFn(lrpc.DefaultMerkleKeyPathFn()))
  195. if err != nil {
  196. return err
  197. }
  198. logger.Info("Starting proxy...", "laddr", tmcfg.RPC.ListenAddress)
  199. if err := p.ListenAndServe(); err != http.ErrServerClosed {
  200. // Error starting or closing listener:
  201. logger.Error("proxy ListenAndServe", "err", err)
  202. }
  203. return nil
  204. }
  205. // FIXME: Temporarily disconnected maverick until it is redesigned
  206. // startMaverick starts a Maverick node that runs the application directly. It assumes the Tendermint
  207. // configuration is in $TMHOME/config/tendermint.toml.
  208. // func startMaverick(cfg *Config) error {
  209. // app, err := NewApplication(cfg)
  210. // if err != nil {
  211. // return err
  212. // }
  213. // tmcfg, logger, nodeKey, err := setupNode()
  214. // if err != nil {
  215. // return fmt.Errorf("failed to setup config: %w", err)
  216. // }
  217. // misbehaviors := make(map[int64]mcs.Misbehavior, len(cfg.Misbehaviors))
  218. // for heightString, misbehaviorString := range cfg.Misbehaviors {
  219. // height, _ := strconv.ParseInt(heightString, 10, 64)
  220. // misbehaviors[height] = mcs.MisbehaviorList[misbehaviorString]
  221. // }
  222. // n, err := maverick.NewNode(tmcfg,
  223. // maverick.LoadOrGenFilePV(tmcfg.PrivValidatorKeyFile(), tmcfg.PrivValidatorStateFile()),
  224. // *nodeKey,
  225. // proxy.NewLocalClientCreator(app),
  226. // maverick.DefaultGenesisDocProviderFunc(tmcfg),
  227. // maverick.DefaultDBProvider,
  228. // maverick.DefaultMetricsProvider(tmcfg.Instrumentation),
  229. // logger,
  230. // misbehaviors,
  231. // )
  232. // if err != nil {
  233. // return err
  234. // }
  235. // return n.Start()
  236. // }
  237. // startSigner starts a signer server connecting to the given endpoint.
  238. func startSigner(cfg *Config) error {
  239. filePV, err := privval.LoadFilePV(cfg.PrivValKey, cfg.PrivValState)
  240. if err != nil {
  241. return err
  242. }
  243. protocol, address := tmnet.ProtocolAndAddress(cfg.PrivValServer)
  244. var dialFn privval.SocketDialer
  245. switch protocol {
  246. case "tcp":
  247. dialFn = privval.DialTCPFn(address, 3*time.Second, ed25519.GenPrivKey())
  248. case "unix":
  249. dialFn = privval.DialUnixFn(address)
  250. case "grpc":
  251. lis, err := net.Listen("tcp", address)
  252. if err != nil {
  253. return err
  254. }
  255. ss := grpcprivval.NewSignerServer(cfg.ChainID, filePV, logger)
  256. s := grpc.NewServer()
  257. privvalproto.RegisterPrivValidatorAPIServer(s, ss)
  258. go func() { // no need to clean up since we remove docker containers
  259. if err := s.Serve(lis); err != nil {
  260. panic(err)
  261. }
  262. }()
  263. return nil
  264. default:
  265. return fmt.Errorf("invalid privval protocol %q", protocol)
  266. }
  267. endpoint := privval.NewSignerDialerEndpoint(logger, dialFn,
  268. privval.SignerDialerEndpointRetryWaitInterval(1*time.Second),
  269. privval.SignerDialerEndpointConnRetries(100))
  270. err = privval.NewSignerServer(endpoint, cfg.ChainID, filePV).Start()
  271. if err != nil {
  272. return err
  273. }
  274. logger.Info(fmt.Sprintf("Remote signer connecting to %v", cfg.PrivValServer))
  275. return nil
  276. }
  277. func setupNode() (*config.Config, log.Logger, *p2p.NodeKey, error) {
  278. var tmcfg *config.Config
  279. home := os.Getenv("TMHOME")
  280. if home == "" {
  281. return nil, nil, nil, errors.New("TMHOME not set")
  282. }
  283. viper.AddConfigPath(filepath.Join(home, "config"))
  284. viper.SetConfigName("config")
  285. if err := viper.ReadInConfig(); err != nil {
  286. return nil, nil, nil, err
  287. }
  288. tmcfg = config.DefaultConfig()
  289. if err := viper.Unmarshal(tmcfg); err != nil {
  290. return nil, nil, nil, err
  291. }
  292. tmcfg.SetRoot(home)
  293. if err := tmcfg.ValidateBasic(); err != nil {
  294. return nil, nil, nil, fmt.Errorf("error in config file: %w", err)
  295. }
  296. if tmcfg.LogFormat == config.LogFormatJSON {
  297. logger = log.NewTMJSONLogger(log.NewSyncWriter(os.Stdout))
  298. }
  299. nodeLogger, err := tmflags.ParseLogLevel(tmcfg.LogLevel, logger, config.DefaultLogLevel)
  300. if err != nil {
  301. return nil, nil, nil, err
  302. }
  303. nodeLogger = nodeLogger.With("module", "main")
  304. nodeKey, err := p2p.LoadOrGenNodeKey(tmcfg.NodeKeyFile())
  305. if err != nil {
  306. return nil, nil, nil, fmt.Errorf("failed to load or gen node key %s: %w", tmcfg.NodeKeyFile(), err)
  307. }
  308. return tmcfg, nodeLogger, &nodeKey, nil
  309. }
  310. // rpcEndpoints takes a list of persistent peers and splits them into a list of rpc endpoints
  311. // using 26657 as the port number
  312. func rpcEndpoints(peers string) []string {
  313. arr := strings.Split(peers, ",")
  314. endpoints := make([]string, len(arr))
  315. for i, v := range arr {
  316. addr, err := p2p.ParseNodeAddress(v)
  317. if err != nil {
  318. panic(err)
  319. }
  320. // use RPC port instead
  321. addr.Port = 26657
  322. var rpcEndpoint string
  323. // for ipv6 addresses
  324. if strings.Contains(addr.Hostname, ":") {
  325. rpcEndpoint = "http://[" + addr.Hostname + "]:" + fmt.Sprint(addr.Port)
  326. } else { // for ipv4 addresses
  327. rpcEndpoint = "http://" + addr.Hostname + ":" + fmt.Sprint(addr.Port)
  328. }
  329. endpoints[i] = rpcEndpoint
  330. }
  331. return endpoints
  332. }