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.

319 lines
7.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. "github.com/tendermint/tendermint/internal/p2p"
  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/privval"
  26. grpcprivval "github.com/tendermint/tendermint/privval/grpc"
  27. privvalproto "github.com/tendermint/tendermint/proto/tendermint/privval"
  28. "github.com/tendermint/tendermint/proxy"
  29. rpcserver "github.com/tendermint/tendermint/rpc/jsonrpc/server"
  30. e2e "github.com/tendermint/tendermint/test/e2e/pkg"
  31. )
  32. var logger = log.MustNewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo, false)
  33. // main is the binary entrypoint.
  34. func main() {
  35. if len(os.Args) != 2 {
  36. fmt.Printf("Usage: %v <configfile>", os.Args[0])
  37. return
  38. }
  39. configFile := ""
  40. if len(os.Args) == 2 {
  41. configFile = os.Args[1]
  42. }
  43. if err := run(configFile); err != nil {
  44. logger.Error(err.Error())
  45. os.Exit(1)
  46. }
  47. }
  48. // run runs the application - basically like main() with error handling.
  49. func run(configFile string) error {
  50. cfg, err := LoadConfig(configFile)
  51. if err != nil {
  52. return err
  53. }
  54. // Start remote signer (must start before node if running builtin).
  55. if cfg.PrivValServer != "" {
  56. if err = startSigner(cfg); err != nil {
  57. return err
  58. }
  59. if cfg.Protocol == "builtin" {
  60. time.Sleep(1 * time.Second)
  61. }
  62. }
  63. // Start app server.
  64. switch cfg.Protocol {
  65. case "socket", "grpc":
  66. err = startApp(cfg)
  67. case "builtin":
  68. switch cfg.Mode {
  69. case string(e2e.ModeLight):
  70. err = startLightNode(cfg)
  71. case string(e2e.ModeSeed):
  72. err = startSeedNode(cfg)
  73. default:
  74. err = startNode(cfg)
  75. }
  76. default:
  77. err = fmt.Errorf("invalid protocol %q", cfg.Protocol)
  78. }
  79. if err != nil {
  80. return err
  81. }
  82. // Apparently there's no way to wait for the server, so we just sleep
  83. for {
  84. time.Sleep(1 * time.Hour)
  85. }
  86. }
  87. // startApp starts the application server, listening for connections from Tendermint.
  88. func startApp(cfg *Config) error {
  89. app, err := NewApplication(cfg)
  90. if err != nil {
  91. return err
  92. }
  93. server, err := server.NewServer(cfg.Listen, cfg.Protocol, app)
  94. if err != nil {
  95. return err
  96. }
  97. err = server.Start()
  98. if err != nil {
  99. return err
  100. }
  101. logger.Info(fmt.Sprintf("Server listening on %v (%v protocol)", cfg.Listen, cfg.Protocol))
  102. return nil
  103. }
  104. // startNode starts a Tendermint node running the application directly. It assumes the Tendermint
  105. // configuration is in $TMHOME/config/tendermint.toml.
  106. //
  107. // FIXME There is no way to simply load the configuration from a file, so we need to pull in Viper.
  108. func startNode(cfg *Config) error {
  109. app, err := NewApplication(cfg)
  110. if err != nil {
  111. return err
  112. }
  113. tmcfg, nodeLogger, err := setupNode()
  114. if err != nil {
  115. return fmt.Errorf("failed to setup config: %w", err)
  116. }
  117. n, err := node.New(tmcfg,
  118. nodeLogger,
  119. proxy.NewLocalClientCreator(app),
  120. nil,
  121. )
  122. if err != nil {
  123. return err
  124. }
  125. return n.Start()
  126. }
  127. func startSeedNode(cfg *Config) error {
  128. tmcfg, nodeLogger, err := setupNode()
  129. if err != nil {
  130. return fmt.Errorf("failed to setup config: %w", err)
  131. }
  132. tmcfg.Mode = config.ModeSeed
  133. n, err := node.New(tmcfg, nodeLogger, nil, nil)
  134. if err != nil {
  135. return err
  136. }
  137. return n.Start()
  138. }
  139. func startLightNode(cfg *Config) error {
  140. tmcfg, nodeLogger, err := setupNode()
  141. if err != nil {
  142. return err
  143. }
  144. dbContext := &config.DBContext{ID: "light", Config: tmcfg}
  145. lightDB, err := config.DefaultDBProvider(dbContext)
  146. if err != nil {
  147. return err
  148. }
  149. providers := rpcEndpoints(tmcfg.P2P.PersistentPeers)
  150. c, err := light.NewHTTPClient(
  151. context.Background(),
  152. cfg.ChainID,
  153. light.TrustOptions{
  154. Period: tmcfg.StateSync.TrustPeriod,
  155. Height: tmcfg.StateSync.TrustHeight,
  156. Hash: tmcfg.StateSync.TrustHashBytes(),
  157. },
  158. providers[0],
  159. providers[1:],
  160. dbs.New(lightDB),
  161. light.Logger(nodeLogger),
  162. )
  163. if err != nil {
  164. return err
  165. }
  166. rpccfg := rpcserver.DefaultConfig()
  167. rpccfg.MaxBodyBytes = tmcfg.RPC.MaxBodyBytes
  168. rpccfg.MaxHeaderBytes = tmcfg.RPC.MaxHeaderBytes
  169. rpccfg.MaxOpenConnections = tmcfg.RPC.MaxOpenConnections
  170. // If necessary adjust global WriteTimeout to ensure it's greater than
  171. // TimeoutBroadcastTxCommit.
  172. // See https://github.com/tendermint/tendermint/issues/3435
  173. if rpccfg.WriteTimeout <= tmcfg.RPC.TimeoutBroadcastTxCommit {
  174. rpccfg.WriteTimeout = tmcfg.RPC.TimeoutBroadcastTxCommit + 1*time.Second
  175. }
  176. p, err := lproxy.NewProxy(c, tmcfg.RPC.ListenAddress, providers[0], rpccfg, nodeLogger,
  177. lrpc.KeyPathFn(lrpc.DefaultMerkleKeyPathFn()))
  178. if err != nil {
  179. return err
  180. }
  181. logger.Info("Starting proxy...", "laddr", tmcfg.RPC.ListenAddress)
  182. if err := p.ListenAndServe(); err != http.ErrServerClosed {
  183. // Error starting or closing listener:
  184. logger.Error("proxy ListenAndServe", "err", err)
  185. }
  186. return nil
  187. }
  188. // startSigner starts a signer server connecting to the given endpoint.
  189. func startSigner(cfg *Config) error {
  190. filePV, err := privval.LoadFilePV(cfg.PrivValKey, cfg.PrivValState)
  191. if err != nil {
  192. return err
  193. }
  194. protocol, address := tmnet.ProtocolAndAddress(cfg.PrivValServer)
  195. var dialFn privval.SocketDialer
  196. switch protocol {
  197. case "tcp":
  198. dialFn = privval.DialTCPFn(address, 3*time.Second, ed25519.GenPrivKey())
  199. case "unix":
  200. dialFn = privval.DialUnixFn(address)
  201. case "grpc":
  202. lis, err := net.Listen("tcp", address)
  203. if err != nil {
  204. return err
  205. }
  206. ss := grpcprivval.NewSignerServer(cfg.ChainID, filePV, logger)
  207. s := grpc.NewServer()
  208. privvalproto.RegisterPrivValidatorAPIServer(s, ss)
  209. go func() { // no need to clean up since we remove docker containers
  210. if err := s.Serve(lis); err != nil {
  211. panic(err)
  212. }
  213. }()
  214. return nil
  215. default:
  216. return fmt.Errorf("invalid privval protocol %q", protocol)
  217. }
  218. endpoint := privval.NewSignerDialerEndpoint(logger, dialFn,
  219. privval.SignerDialerEndpointRetryWaitInterval(1*time.Second),
  220. privval.SignerDialerEndpointConnRetries(100))
  221. err = privval.NewSignerServer(endpoint, cfg.ChainID, filePV).Start()
  222. if err != nil {
  223. return err
  224. }
  225. logger.Info(fmt.Sprintf("Remote signer connecting to %v", cfg.PrivValServer))
  226. return nil
  227. }
  228. func setupNode() (*config.Config, log.Logger, error) {
  229. var tmcfg *config.Config
  230. home := os.Getenv("TMHOME")
  231. if home == "" {
  232. return nil, nil, errors.New("TMHOME not set")
  233. }
  234. viper.AddConfigPath(filepath.Join(home, "config"))
  235. viper.SetConfigName("config")
  236. if err := viper.ReadInConfig(); err != nil {
  237. return nil, nil, err
  238. }
  239. tmcfg = config.DefaultConfig()
  240. if err := viper.Unmarshal(tmcfg); err != nil {
  241. return nil, nil, err
  242. }
  243. tmcfg.SetRoot(home)
  244. if err := tmcfg.ValidateBasic(); err != nil {
  245. return nil, nil, fmt.Errorf("error in config file: %w", err)
  246. }
  247. nodeLogger, err := log.NewDefaultLogger(tmcfg.LogFormat, tmcfg.LogLevel, false)
  248. if err != nil {
  249. return nil, nil, err
  250. }
  251. return tmcfg, nodeLogger.With("module", "main"), nil
  252. }
  253. // rpcEndpoints takes a list of persistent peers and splits them into a list of rpc endpoints
  254. // using 26657 as the port number
  255. func rpcEndpoints(peers string) []string {
  256. arr := strings.Split(peers, ",")
  257. endpoints := make([]string, len(arr))
  258. for i, v := range arr {
  259. addr, err := p2p.ParseNodeAddress(v)
  260. if err != nil {
  261. panic(err)
  262. }
  263. // use RPC port instead
  264. addr.Port = 26657
  265. var rpcEndpoint string
  266. // for ipv6 addresses
  267. if strings.Contains(addr.Hostname, ":") {
  268. rpcEndpoint = "http://[" + addr.Hostname + "]:" + fmt.Sprint(addr.Port)
  269. } else { // for ipv4 addresses
  270. rpcEndpoint = "http://" + addr.Hostname + ":" + fmt.Sprint(addr.Port)
  271. }
  272. endpoints[i] = rpcEndpoint
  273. }
  274. return endpoints
  275. }