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.

165 lines
4.9 KiB

  1. package commands
  2. import (
  3. "bytes"
  4. "crypto/sha256"
  5. "fmt"
  6. "io"
  7. "os"
  8. "github.com/spf13/cobra"
  9. cfg "github.com/tendermint/tendermint/config"
  10. tmos "github.com/tendermint/tendermint/libs/os"
  11. )
  12. var (
  13. genesisHash []byte
  14. )
  15. // AddNodeFlags exposes some common configuration options on the command-line
  16. // These are exposed for convenience of commands embedding a tendermint node
  17. func AddNodeFlags(cmd *cobra.Command) {
  18. // bind flags
  19. cmd.Flags().String("moniker", config.Moniker, "node name")
  20. // mode flags
  21. cmd.Flags().String("mode", config.Mode, "node mode (full | validator | seed)")
  22. // priv val flags
  23. cmd.Flags().String(
  24. "priv-validator-laddr",
  25. config.PrivValidator.ListenAddr,
  26. "socket address to listen on for connections from external priv-validator process")
  27. // node flags
  28. cmd.Flags().Bool("fast-sync", config.FastSyncMode, "fast blockchain syncing")
  29. cmd.Flags().BytesHexVar(
  30. &genesisHash,
  31. "genesis-hash",
  32. []byte{},
  33. "optional SHA-256 hash of the genesis file")
  34. cmd.Flags().Int64("consensus.double-sign-check-height", config.Consensus.DoubleSignCheckHeight,
  35. "how many blocks to look back to check existence of the node's "+
  36. "consensus votes before joining consensus")
  37. // abci flags
  38. cmd.Flags().String(
  39. "proxy-app",
  40. config.ProxyApp,
  41. "proxy app address, or one of: 'kvstore',"+
  42. " 'persistent_kvstore',"+
  43. " 'counter',"+
  44. " 'counter_serial' or 'noop' for local testing.")
  45. cmd.Flags().String("abci", config.ABCI, "specify abci transport (socket | grpc)")
  46. // rpc flags
  47. cmd.Flags().String("rpc.laddr", config.RPC.ListenAddress, "RPC listen address. Port required")
  48. cmd.Flags().String(
  49. "rpc.grpc-laddr",
  50. config.RPC.GRPCListenAddress,
  51. "GRPC listen address (BroadcastTx only). Port required")
  52. cmd.Flags().Bool("rpc.unsafe", config.RPC.Unsafe, "enabled unsafe rpc methods")
  53. cmd.Flags().String("rpc.pprof-laddr", config.RPC.PprofListenAddress, "pprof listen address (https://golang.org/pkg/net/http/pprof)")
  54. // p2p flags
  55. cmd.Flags().String(
  56. "p2p.laddr",
  57. config.P2P.ListenAddress,
  58. "node listen address. (0.0.0.0:0 means any interface, any port)")
  59. cmd.Flags().String("p2p.seeds", config.P2P.Seeds, "comma-delimited ID@host:port seed nodes")
  60. cmd.Flags().String("p2p.persistent-peers", config.P2P.PersistentPeers, "comma-delimited ID@host:port persistent peers")
  61. cmd.Flags().String("p2p.unconditional-peer-ids",
  62. config.P2P.UnconditionalPeerIDs, "comma-delimited IDs of unconditional peers")
  63. cmd.Flags().Bool("p2p.upnp", config.P2P.UPNP, "enable/disable UPNP port forwarding")
  64. cmd.Flags().Bool("p2p.pex", config.P2P.PexReactor, "enable/disable Peer-Exchange")
  65. cmd.Flags().String("p2p.private-peer-ids", config.P2P.PrivatePeerIDs, "comma-delimited private peer IDs")
  66. // consensus flags
  67. cmd.Flags().Bool(
  68. "consensus.create-empty-blocks",
  69. config.Consensus.CreateEmptyBlocks,
  70. "set this to false to only produce blocks when there are txs or when the AppHash changes")
  71. cmd.Flags().String(
  72. "consensus.create-empty-blocks-interval",
  73. config.Consensus.CreateEmptyBlocksInterval.String(),
  74. "the possible interval between empty blocks")
  75. // db flags
  76. cmd.Flags().String(
  77. "db-backend",
  78. config.DBBackend,
  79. "database backend: goleveldb | cleveldb | boltdb | rocksdb | badgerdb")
  80. cmd.Flags().String(
  81. "db-dir",
  82. config.DBPath,
  83. "database directory")
  84. }
  85. // NewRunNodeCmd returns the command that allows the CLI to start a node.
  86. // It can be used with a custom PrivValidator and in-process ABCI application.
  87. func NewRunNodeCmd(nodeProvider cfg.ServiceProvider) *cobra.Command {
  88. cmd := &cobra.Command{
  89. Use: "start",
  90. Aliases: []string{"node", "run"},
  91. Short: "Run the tendermint node",
  92. RunE: func(cmd *cobra.Command, args []string) error {
  93. if err := checkGenesisHash(config); err != nil {
  94. return err
  95. }
  96. n, err := nodeProvider(config, logger)
  97. if err != nil {
  98. return fmt.Errorf("failed to create node: %w", err)
  99. }
  100. if err := n.Start(); err != nil {
  101. return fmt.Errorf("failed to start node: %w", err)
  102. }
  103. logger.Info("started node", "node", n.String())
  104. // Stop upon receiving SIGTERM or CTRL-C.
  105. tmos.TrapSignal(logger, func() {
  106. if n.IsRunning() {
  107. if err := n.Stop(); err != nil {
  108. logger.Error("unable to stop the node", "error", err)
  109. }
  110. }
  111. })
  112. // Run forever.
  113. select {}
  114. },
  115. }
  116. AddNodeFlags(cmd)
  117. return cmd
  118. }
  119. func checkGenesisHash(config *cfg.Config) error {
  120. if len(genesisHash) == 0 || config.Genesis == "" {
  121. return nil
  122. }
  123. // Calculate SHA-256 hash of the genesis file.
  124. f, err := os.Open(config.GenesisFile())
  125. if err != nil {
  126. return fmt.Errorf("can't open genesis file: %w", err)
  127. }
  128. defer f.Close()
  129. h := sha256.New()
  130. if _, err := io.Copy(h, f); err != nil {
  131. return fmt.Errorf("error when hashing genesis file: %w", err)
  132. }
  133. actualHash := h.Sum(nil)
  134. // Compare with the flag.
  135. if !bytes.Equal(genesisHash, actualHash) {
  136. return fmt.Errorf(
  137. "--genesis_hash=%X does not match %s hash: %X",
  138. genesisHash, config.GenesisFile(), actualHash)
  139. }
  140. return nil
  141. }