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.

156 lines
4.6 KiB

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