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

package main
import (
"fmt"
"os"
"path/filepath"
"github.com/spf13/cobra"
"github.com/spf13/viper"
cmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
"github.com/tendermint/tendermint/cmd/tendermint/commands/debug"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/libs/cli"
tmflags "github.com/tendermint/tendermint/libs/cli/flags"
"github.com/tendermint/tendermint/libs/log"
tmos "github.com/tendermint/tendermint/libs/os"
tmrand "github.com/tendermint/tendermint/libs/rand"
"github.com/tendermint/tendermint/p2p"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
cs "github.com/tendermint/tendermint/test/maverick/consensus"
nd "github.com/tendermint/tendermint/test/maverick/node"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
)
var (
config = cfg.DefaultConfig()
logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
misbehaviorFlag = ""
)
func init() {
registerFlagsRootCmd(RootCmd)
}
func registerFlagsRootCmd(command *cobra.Command) {
command.PersistentFlags().String("log_level", config.LogLevel, "Log level")
}
func ParseConfig() (*cfg.Config, error) {
conf := cfg.DefaultConfig()
err := viper.Unmarshal(conf)
if err != nil {
return nil, err
}
conf.SetRoot(conf.RootDir)
cfg.EnsureRoot(conf.RootDir)
if err = conf.ValidateBasic(); err != nil {
return nil, fmt.Errorf("error in config file: %v", err)
}
return conf, err
}
// RootCmd is the root command for Tendermint core.
var RootCmd = &cobra.Command{
Use: "maverick",
Short: "Tendermint Maverick Node",
Long: "Tendermint Maverick Node for testing with faulty consensus misbehaviors in a testnet. Contains " +
"all the functionality of a normal node but custom misbehaviors can be injected when running the node " +
"through a flag. See maverick node --help for how the misbehavior flag is constructured",
PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) {
fmt.Printf("use: %v, args: %v", cmd.Use, cmd.Args)
config, err = ParseConfig()
if err != nil {
return err
}
if config.LogFormat == cfg.LogFormatJSON {
logger = log.NewTMJSONLogger(log.NewSyncWriter(os.Stdout))
}
logger, err = tmflags.ParseLogLevel(config.LogLevel, logger, cfg.DefaultLogLevel())
if err != nil {
return err
}
if viper.GetBool(cli.TraceFlag) {
logger = log.NewTracingLogger(logger)
}
logger = logger.With("module", "main")
return nil
},
}
func main() {
rootCmd := RootCmd
rootCmd.AddCommand(
ListMisbehaviorCmd,
cmd.GenValidatorCmd,
InitFilesCmd,
cmd.ProbeUpnpCmd,
cmd.ReplayCmd,
cmd.ReplayConsoleCmd,
cmd.ResetAllCmd,
cmd.ResetPrivValidatorCmd,
cmd.ShowValidatorCmd,
cmd.ShowNodeIDCmd,
cmd.GenNodeKeyCmd,
cmd.VersionCmd,
debug.DebugCmd,
cli.NewCompletionCmd(rootCmd, true),
)
nodeCmd := &cobra.Command{
Use: "node",
Short: "Run the maverick node",
RunE: func(command *cobra.Command, args []string) error {
return startNode(config, logger, misbehaviorFlag)
},
}
cmd.AddNodeFlags(nodeCmd)
// Create & start node
rootCmd.AddCommand(nodeCmd)
// add special flag for misbehaviors
nodeCmd.Flags().StringVar(
&misbehaviorFlag,
"misbehaviors",
"",
"Select the misbehaviors of the node (comma-separated, no spaces in between): \n"+
"e.g. --misbehaviors double-prevote,3\n"+
"You can also have multiple misbehaviors: e.g. double-prevote,3,no-vote,5")
cmd := cli.PrepareBaseCmd(rootCmd, "TM", os.ExpandEnv(filepath.Join("$HOME", cfg.DefaultTendermintDir)))
if err := cmd.Execute(); err != nil {
panic(err)
}
}
func startNode(config *cfg.Config, logger log.Logger, misbehaviorFlag string) error {
misbehaviors, err := nd.ParseMisbehaviors(misbehaviorFlag)
if err != nil {
return err
}
node, err := nd.DefaultNewNode(config, logger, misbehaviors)
if err != nil {
return fmt.Errorf("failed to create node: %w", err)
}
if err := node.Start(); err != nil {
return fmt.Errorf("failed to start node: %w", err)
}
logger.Info("Started node", "nodeInfo", node.Switch().NodeInfo())
// Stop upon receiving SIGTERM or CTRL-C.
tmos.TrapSignal(logger, func() {
if node.IsRunning() {
if err := node.Stop(); err != nil {
logger.Error("unable to stop the node", "error", err)
}
}
})
// Run forever.
select {}
}
var keyType string
var InitFilesCmd = &cobra.Command{
Use: "init",
Short: "Initialize Tendermint",
RunE: initFiles,
}
func init() {
InitFilesCmd.Flags().StringVar(&keyType, "key", types.ABCIPubKeyTypeEd25519,
"Key type to generate privval file with. Options: ed25519, secp256k1")
}
func initFiles(cmd *cobra.Command, args []string) error {
return initFilesWithConfig(config)
}
func initFilesWithConfig(config *cfg.Config) error {
// private validator
privValKeyFile := config.PrivValidatorKeyFile()
privValStateFile := config.PrivValidatorStateFile()
var pv *nd.FilePV
if tmos.FileExists(privValKeyFile) {
pv = nd.LoadFilePV(privValKeyFile, privValStateFile)
logger.Info("Found private validator", "keyFile", privValKeyFile,
"stateFile", privValStateFile)
} else {
pv = nd.GenFilePV(privValKeyFile, privValStateFile)
pv.Save()
logger.Info("Generated private validator", "keyFile", privValKeyFile,
"stateFile", privValStateFile)
}
nodeKeyFile := config.NodeKeyFile()
if tmos.FileExists(nodeKeyFile) {
logger.Info("Found node key", "path", nodeKeyFile)
} else {
if _, err := p2p.LoadOrGenNodeKey(nodeKeyFile); err != nil {
return err
}
logger.Info("Generated node key", "path", nodeKeyFile)
}
// genesis file
genFile := config.GenesisFile()
if tmos.FileExists(genFile) {
logger.Info("Found genesis file", "path", genFile)
} else {
genDoc := types.GenesisDoc{
ChainID: fmt.Sprintf("test-chain-%v", tmrand.Str(6)),
GenesisTime: tmtime.Now(),
ConsensusParams: types.DefaultConsensusParams(),
}
if keyType == "secp256k1" {
genDoc.ConsensusParams.Validator = tmproto.ValidatorParams{
PubKeyTypes: []string{types.ABCIPubKeyTypeSecp256k1},
}
}
pubKey, err := pv.GetPubKey()
if err != nil {
return fmt.Errorf("can't get pubkey: %w", err)
}
genDoc.Validators = []types.GenesisValidator{{
Address: pubKey.Address(),
PubKey: pubKey,
Power: 10,
}}
if err := genDoc.SaveAs(genFile); err != nil {
return err
}
logger.Info("Generated genesis file", "path", genFile)
}
return nil
}
var ListMisbehaviorCmd = &cobra.Command{
Use: "misbehaviors",
Short: "Lists possible misbehaviors",
RunE: listMisbehaviors,
}
func listMisbehaviors(cmd *cobra.Command, args []string) error {
str := "Currently registered misbehaviors: \n"
for key := range cs.MisbehaviorList {
str += fmt.Sprintf("- %s\n", key)
}
fmt.Println(str)
return nil
}