// Package main defines a validator client, a critical actor in Ethereum which manages // a keystore of private keys, connects to a beacon node to receive assignments, // and submits blocks/attestations as needed. package main import ( "fmt" "os" "path/filepath" "runtime" runtimeDebug "runtime/debug" joonix "github.com/joonix/log" accountcommands "github.com/prysmaticlabs/prysm/cmd/validator/accounts" dbcommands "github.com/prysmaticlabs/prysm/cmd/validator/db" "github.com/prysmaticlabs/prysm/cmd/validator/flags" slashingprotectioncommands "github.com/prysmaticlabs/prysm/cmd/validator/slashing-protection" walletcommands "github.com/prysmaticlabs/prysm/cmd/validator/wallet" "github.com/prysmaticlabs/prysm/shared/cmd" "github.com/prysmaticlabs/prysm/shared/debug" "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/fileutil" "github.com/prysmaticlabs/prysm/shared/journald" "github.com/prysmaticlabs/prysm/shared/logutil" _ "github.com/prysmaticlabs/prysm/shared/maxprocs" "github.com/prysmaticlabs/prysm/shared/tos" "github.com/prysmaticlabs/prysm/shared/version" "github.com/prysmaticlabs/prysm/validator/node" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" prefixed "github.com/x-cray/logrus-prefixed-formatter" ) func startNode(ctx *cli.Context) error { // verify if ToS accepted if err := tos.VerifyTosAcceptedOrPrompt(ctx); err != nil { return err } validatorClient, err := node.NewValidatorClient(ctx) if err != nil { return err } validatorClient.Start() return nil } var appFlags = []cli.Flag{ flags.BeaconRPCProviderFlag, flags.BeaconRPCGatewayProviderFlag, flags.CertFlag, flags.GraffitiFlag, flags.DisablePenaltyRewardLogFlag, flags.InteropStartIndex, flags.InteropNumValidators, flags.EnableRPCFlag, flags.RPCHost, flags.RPCPort, flags.GRPCGatewayPort, flags.GRPCGatewayHost, flags.GrpcRetriesFlag, flags.GrpcRetryDelayFlag, flags.GrpcHeadersFlag, flags.GPRCGatewayCorsDomain, flags.DisableAccountMetricsFlag, cmd.MonitoringHostFlag, flags.MonitoringPortFlag, cmd.DisableMonitoringFlag, flags.SlasherRPCProviderFlag, flags.SlasherCertFlag, flags.WalletPasswordFileFlag, flags.WalletDirFlag, flags.EnableWebFlag, flags.GraffitiFileFlag, flags.EnableDutyCountDown, cmd.BackupWebhookOutputDir, cmd.EnableBackupWebhookFlag, cmd.MinimalConfigFlag, cmd.E2EConfigFlag, cmd.VerbosityFlag, cmd.DataDirFlag, cmd.ClearDB, cmd.ForceClearDB, cmd.EnableTracingFlag, cmd.TracingProcessNameFlag, cmd.TracingEndpointFlag, cmd.TraceSampleFractionFlag, cmd.LogFormat, cmd.LogFileName, cmd.ConfigFileFlag, cmd.ChainConfigFileFlag, cmd.GrpcMaxCallRecvMsgSizeFlag, cmd.BoltMMapInitialSizeFlag, debug.PProfFlag, debug.PProfAddrFlag, debug.PProfPortFlag, debug.MemProfileRateFlag, debug.CPUProfileFlag, debug.TraceFlag, debug.BlockProfileRateFlag, debug.MutexProfileFractionFlag, cmd.AcceptTosFlag, } func init() { appFlags = cmd.WrapFlags(append(appFlags, featureconfig.ValidatorFlags...)) } func main() { app := cli.App{} app.Name = "validator" app.Usage = `launches an Ethereum validator client that interacts with a beacon chain, starts proposer and attester services, p2p connections, and more` app.Version = version.Version() app.Action = startNode app.Commands = []*cli.Command{ walletcommands.Commands, accountcommands.Commands, slashingprotectioncommands.Commands, dbcommands.Commands, } app.Flags = appFlags app.Before = func(ctx *cli.Context) error { // Load flags from config file, if specified. if err := cmd.LoadFlagsFromConfig(ctx, app.Flags); err != nil { return err } format := ctx.String(cmd.LogFormat.Name) switch format { case "text": formatter := new(prefixed.TextFormatter) formatter.TimestampFormat = "2006-01-02 15:04:05" formatter.FullTimestamp = true // If persistent log files are written - we disable the log messages coloring because // the colors are ANSI codes and seen as Gibberish in the log files. formatter.DisableColors = ctx.String(cmd.LogFileName.Name) != "" logrus.SetFormatter(formatter) case "fluentd": f := joonix.NewFormatter() if err := joonix.DisableTimestampFormat(f); err != nil { panic(err) } logrus.SetFormatter(f) case "json": logrus.SetFormatter(&logrus.JSONFormatter{}) case "journald": if err := journald.Enable(); err != nil { return err } default: return fmt.Errorf("unknown log format %s", format) } logFileName := ctx.String(cmd.LogFileName.Name) if logFileName != "" { if err := logutil.ConfigurePersistentLogging(logFileName); err != nil { log.WithError(err).Error("Failed to configuring logging to disk.") } } // Fix data dir for Windows users. outdatedDataDir := filepath.Join(fileutil.HomeDir(), "AppData", "Roaming", "Eth2Validators") currentDataDir := flags.DefaultValidatorDir() if err := cmd.FixDefaultDataDir(outdatedDataDir, currentDataDir); err != nil { log.WithError(err).Error("Cannot update data directory") } runtime.GOMAXPROCS(runtime.NumCPU()) if err := debug.Setup(ctx); err != nil { return err } return cmd.ValidateNoArgs(ctx) } app.After = func(ctx *cli.Context) error { debug.Exit(ctx) return nil } defer func() { if x := recover(); x != nil { log.Errorf("Runtime panic: %v\n%v", x, string(runtimeDebug.Stack())) panic(x) } }() if err := app.Run(os.Args); err != nil { log.Error(err.Error()) } }