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.

237 lines
6.3 KiB

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "github.com/spf13/cobra"
  7. "github.com/spf13/viper"
  8. cmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
  9. "github.com/tendermint/tendermint/cmd/tendermint/commands/debug"
  10. cfg "github.com/tendermint/tendermint/config"
  11. "github.com/tendermint/tendermint/libs/cli"
  12. tmflags "github.com/tendermint/tendermint/libs/cli/flags"
  13. "github.com/tendermint/tendermint/libs/log"
  14. tmos "github.com/tendermint/tendermint/libs/os"
  15. tmrand "github.com/tendermint/tendermint/libs/rand"
  16. "github.com/tendermint/tendermint/p2p"
  17. cs "github.com/tendermint/tendermint/test/maverick/consensus"
  18. nd "github.com/tendermint/tendermint/test/maverick/node"
  19. "github.com/tendermint/tendermint/types"
  20. tmtime "github.com/tendermint/tendermint/types/time"
  21. )
  22. var (
  23. config = cfg.DefaultConfig()
  24. logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
  25. misbehaviorFlag = ""
  26. )
  27. func init() {
  28. registerFlagsRootCmd(RootCmd)
  29. }
  30. func registerFlagsRootCmd(command *cobra.Command) {
  31. command.PersistentFlags().String("log_level", config.LogLevel, "Log level")
  32. }
  33. func ParseConfig() (*cfg.Config, error) {
  34. conf := cfg.DefaultConfig()
  35. err := viper.Unmarshal(conf)
  36. if err != nil {
  37. return nil, err
  38. }
  39. conf.SetRoot(conf.RootDir)
  40. cfg.EnsureRoot(conf.RootDir)
  41. if err = conf.ValidateBasic(); err != nil {
  42. return nil, fmt.Errorf("error in config file: %v", err)
  43. }
  44. return conf, err
  45. }
  46. // RootCmd is the root command for Tendermint core.
  47. var RootCmd = &cobra.Command{
  48. Use: "maverick",
  49. Short: "Tendermint Maverick Node",
  50. Long: "Tendermint Maverick Node for testing with faulty consensus misbehaviors in a testnet. Contains " +
  51. "all the functionality of a normal node but custom misbehaviors can be injected when running the node " +
  52. "through a flag. See maverick node --help for how the misbehavior flag is constructured",
  53. PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) {
  54. fmt.Printf("use: %v, args: %v", cmd.Use, cmd.Args)
  55. config, err = ParseConfig()
  56. if err != nil {
  57. return err
  58. }
  59. if config.LogFormat == cfg.LogFormatJSON {
  60. logger = log.NewTMJSONLogger(log.NewSyncWriter(os.Stdout))
  61. }
  62. logger, err = tmflags.ParseLogLevel(config.LogLevel, logger, cfg.DefaultLogLevel())
  63. if err != nil {
  64. return err
  65. }
  66. if viper.GetBool(cli.TraceFlag) {
  67. logger = log.NewTracingLogger(logger)
  68. }
  69. logger = logger.With("module", "main")
  70. return nil
  71. },
  72. }
  73. func main() {
  74. rootCmd := RootCmd
  75. rootCmd.AddCommand(
  76. ListMisbehaviorCmd,
  77. cmd.GenValidatorCmd,
  78. InitFilesCmd,
  79. cmd.ProbeUpnpCmd,
  80. cmd.ReplayCmd,
  81. cmd.ReplayConsoleCmd,
  82. cmd.ResetAllCmd,
  83. cmd.ResetPrivValidatorCmd,
  84. cmd.ShowValidatorCmd,
  85. cmd.ShowNodeIDCmd,
  86. cmd.GenNodeKeyCmd,
  87. cmd.VersionCmd,
  88. debug.DebugCmd,
  89. cli.NewCompletionCmd(rootCmd, true),
  90. )
  91. nodeCmd := &cobra.Command{
  92. Use: "node",
  93. Short: "Run the maverick node",
  94. RunE: func(command *cobra.Command, args []string) error {
  95. return startNode(config, logger, misbehaviorFlag)
  96. },
  97. }
  98. cmd.AddNodeFlags(nodeCmd)
  99. // Create & start node
  100. rootCmd.AddCommand(nodeCmd)
  101. // add special flag for misbehaviors
  102. nodeCmd.Flags().StringVar(
  103. &misbehaviorFlag,
  104. "misbehaviors",
  105. "",
  106. "Select the misbehaviors of the node (comma-separated, no spaces in between): \n"+
  107. "e.g. --misbehaviors double-prevote,3\n"+
  108. "You can also have multiple misbehaviors: e.g. double-prevote,3,no-vote,5")
  109. cmd := cli.PrepareBaseCmd(rootCmd, "TM", os.ExpandEnv(filepath.Join("$HOME", cfg.DefaultTendermintDir)))
  110. if err := cmd.Execute(); err != nil {
  111. panic(err)
  112. }
  113. }
  114. func startNode(config *cfg.Config, logger log.Logger, misbehaviorFlag string) error {
  115. misbehaviors, err := nd.ParseMisbehaviors(misbehaviorFlag)
  116. if err != nil {
  117. return err
  118. }
  119. node, err := nd.DefaultNewNode(config, logger, misbehaviors)
  120. if err != nil {
  121. return fmt.Errorf("failed to create node: %w", err)
  122. }
  123. if err := node.Start(); err != nil {
  124. return fmt.Errorf("failed to start node: %w", err)
  125. }
  126. logger.Info("Started node", "nodeInfo", node.Switch().NodeInfo())
  127. // Stop upon receiving SIGTERM or CTRL-C.
  128. tmos.TrapSignal(logger, func() {
  129. if node.IsRunning() {
  130. if err := node.Stop(); err != nil {
  131. logger.Error("unable to stop the node", "error", err)
  132. }
  133. }
  134. })
  135. // Run forever.
  136. select {}
  137. }
  138. var InitFilesCmd = &cobra.Command{
  139. Use: "init",
  140. Short: "Initialize Tendermint",
  141. RunE: initFiles,
  142. }
  143. func initFiles(cmd *cobra.Command, args []string) error {
  144. return initFilesWithConfig(config)
  145. }
  146. func initFilesWithConfig(config *cfg.Config) error {
  147. // private validator
  148. privValKeyFile := config.PrivValidatorKeyFile()
  149. privValStateFile := config.PrivValidatorStateFile()
  150. var pv *nd.FilePV
  151. if tmos.FileExists(privValKeyFile) {
  152. pv = nd.LoadFilePV(privValKeyFile, privValStateFile)
  153. logger.Info("Found private validator", "keyFile", privValKeyFile,
  154. "stateFile", privValStateFile)
  155. } else {
  156. pv = nd.GenFilePV(privValKeyFile, privValStateFile)
  157. pv.Save()
  158. logger.Info("Generated private validator", "keyFile", privValKeyFile,
  159. "stateFile", privValStateFile)
  160. }
  161. nodeKeyFile := config.NodeKeyFile()
  162. if tmos.FileExists(nodeKeyFile) {
  163. logger.Info("Found node key", "path", nodeKeyFile)
  164. } else {
  165. if _, err := p2p.LoadOrGenNodeKey(nodeKeyFile); err != nil {
  166. return err
  167. }
  168. logger.Info("Generated node key", "path", nodeKeyFile)
  169. }
  170. // genesis file
  171. genFile := config.GenesisFile()
  172. if tmos.FileExists(genFile) {
  173. logger.Info("Found genesis file", "path", genFile)
  174. } else {
  175. genDoc := types.GenesisDoc{
  176. ChainID: fmt.Sprintf("test-chain-%v", tmrand.Str(6)),
  177. GenesisTime: tmtime.Now(),
  178. ConsensusParams: types.DefaultConsensusParams(),
  179. }
  180. pubKey, err := pv.GetPubKey()
  181. if err != nil {
  182. return fmt.Errorf("can't get pubkey: %w", err)
  183. }
  184. genDoc.Validators = []types.GenesisValidator{{
  185. Address: pubKey.Address(),
  186. PubKey: pubKey,
  187. Power: 10,
  188. }}
  189. if err := genDoc.SaveAs(genFile); err != nil {
  190. return err
  191. }
  192. logger.Info("Generated genesis file", "path", genFile)
  193. }
  194. return nil
  195. }
  196. var ListMisbehaviorCmd = &cobra.Command{
  197. Use: "misbehaviors",
  198. Short: "Lists possible misbehaviors",
  199. RunE: listMisbehaviors,
  200. }
  201. func listMisbehaviors(cmd *cobra.Command, args []string) error {
  202. str := "Currently registered misbehaviors: \n"
  203. for key := range cs.MisbehaviorList {
  204. str += fmt.Sprintf("- %s\n", key)
  205. }
  206. fmt.Println(str)
  207. return nil
  208. }