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.

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