github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/cmd/geth/main.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // geth is the official command-line client for Ethereum.
    18  package main
    19  
    20  import (
    21  	"fmt"
    22  	"log"
    23  	"math/rand"
    24  	"os"
    25  	"path/filepath"
    26  	"time"
    27  
    28  	"gopkg.in/urfave/cli.v1"
    29  
    30  	"github.com/ethereumproject/benchmark/rtprof"
    31  	"github.com/ethereumproject/go-ethereum/common"
    32  	"github.com/ethereumproject/go-ethereum/console"
    33  	"github.com/ethereumproject/go-ethereum/core"
    34  	"github.com/ethereumproject/go-ethereum/logger"
    35  	"github.com/ethereumproject/go-ethereum/metrics"
    36  )
    37  
    38  // Version is the application revision identifier. It can be set with the linker
    39  // as in: go build -ldflags "-X main.Version="`git describe --tags`
    40  var Version = "source"
    41  
    42  func init() {
    43  	rand.Seed(time.Now().UTC().UnixNano())
    44  	common.SetClientVersion(Version)
    45  }
    46  
    47  var makeDagCommand = cli.Command{
    48  	Action:  makedag,
    49  	Name:    "make-dag",
    50  	Aliases: []string{"makedag"},
    51  	Usage:   "Generate ethash dag (for testing)",
    52  	Description: `
    53  		The makedag command generates an ethash DAG in /tmp/dag.
    54  
    55  		This command exists to support the system testing project.
    56  		Regular users do not need to execute it.
    57  				`,
    58  }
    59  
    60  var gpuInfoCommand = cli.Command{
    61  	Action:  gpuinfo,
    62  	Name:    "gpu-info",
    63  	Aliases: []string{"gpuinfo"},
    64  	Usage:   "GPU info",
    65  	Description: `
    66  	Prints OpenCL device info for all found GPUs.
    67  			`,
    68  }
    69  
    70  var gpuBenchCommand = cli.Command{
    71  	Action:  gpubench,
    72  	Name:    "gpu-bench",
    73  	Aliases: []string{"gpubench"},
    74  	Usage:   "Benchmark GPU",
    75  	Description: `
    76  	Runs quick benchmark on first GPU found.
    77  			`,
    78  }
    79  
    80  var versionCommand = cli.Command{
    81  	Action: version,
    82  	Name:   "version",
    83  	Usage:  "Print ethereum version numbers",
    84  	Description: `
    85  	The output of this command is supposed to be machine-readable.
    86  			`,
    87  }
    88  
    89  var makeMlogDocCommand = cli.Command{
    90  	Action: makeMLogDocumentation,
    91  	Name:   "mdoc",
    92  	Usage:  "Generate mlog documentation",
    93  	Description: `
    94  	Auto-generates documentation for all available mlog lines.
    95  	Use -md switch to toggle markdown output (eg. for wiki).
    96  	Arguments may be used to specify exclusive candidate components;
    97  	so 'geth mdoc -md discover' will generate markdown documentation only
    98  	for the 'discover' component.
    99  			`,
   100  	Flags: []cli.Flag{
   101  		cli.BoolFlag{
   102  			Name:  "md",
   103  			Usage: "Toggle markdown formatting",
   104  		},
   105  	},
   106  }
   107  
   108  func makeCLIApp() (app *cli.App) {
   109  	app = cli.NewApp()
   110  	app.Name = filepath.Base(os.Args[0])
   111  	app.Version = Version
   112  	app.Usage = "the go-ethereum command line interface"
   113  	app.Action = geth
   114  	app.HideVersion = true // we have a command to print the version
   115  
   116  	app.Commands = []cli.Command{
   117  		importCommand,
   118  		exportCommand,
   119  		dumpChainConfigCommand,
   120  		upgradedbCommand,
   121  		dumpCommand,
   122  		rollbackCommand,
   123  		recoverCommand,
   124  		resetCommand,
   125  		monitorCommand,
   126  		accountCommand,
   127  		walletCommand,
   128  		consoleCommand,
   129  		attachCommand,
   130  		javascriptCommand,
   131  		statusCommand,
   132  		apiCommand,
   133  		makeDagCommand,
   134  		gpuInfoCommand,
   135  		gpuBenchCommand,
   136  		versionCommand,
   137  		makeMlogDocCommand,
   138  		buildAddrTxIndexCommand,
   139  	}
   140  
   141  	app.Flags = []cli.Flag{
   142  		PprofFlag,
   143  		PprofIntervalFlag,
   144  		SputnikVMFlag,
   145  		NodeNameFlag,
   146  		UnlockedAccountFlag,
   147  		PasswordFileFlag,
   148  		AccountsIndexFlag,
   149  		BootnodesFlag,
   150  		DataDirFlag,
   151  		DocRootFlag,
   152  		KeyStoreDirFlag,
   153  		ChainIdentityFlag,
   154  		BlockchainVersionFlag,
   155  		FastSyncFlag,
   156  		AddrTxIndexFlag,
   157  		AddrTxIndexAutoBuildFlag,
   158  		CacheFlag,
   159  		LightKDFFlag,
   160  		JSpathFlag,
   161  		ListenPortFlag,
   162  		MaxPeersFlag,
   163  		MaxPendingPeersFlag,
   164  		EtherbaseFlag,
   165  		GasPriceFlag,
   166  		MinerThreadsFlag,
   167  		MiningEnabledFlag,
   168  		MiningGPUFlag,
   169  		AutoDAGFlag,
   170  		TargetGasLimitFlag,
   171  		NATFlag,
   172  		NatspecEnabledFlag,
   173  		NoDiscoverFlag,
   174  		NodeKeyFileFlag,
   175  		NodeKeyHexFlag,
   176  		RPCEnabledFlag,
   177  		RPCListenAddrFlag,
   178  		RPCPortFlag,
   179  		RPCApiFlag,
   180  		WSEnabledFlag,
   181  		WSListenAddrFlag,
   182  		WSPortFlag,
   183  		WSApiFlag,
   184  		WSAllowedOriginsFlag,
   185  		IPCDisabledFlag,
   186  		IPCApiFlag,
   187  		IPCPathFlag,
   188  		ExecFlag,
   189  		PreloadJSFlag,
   190  		WhisperEnabledFlag,
   191  		DevModeFlag,
   192  		TestNetFlag,
   193  		NetworkIdFlag,
   194  		RPCCORSDomainFlag,
   195  		NeckbeardFlag,
   196  		VerbosityFlag,
   197  		DisplayFlag,
   198  		DisplayFormatFlag,
   199  		VModuleFlag,
   200  		LogDirFlag,
   201  		LogMaxSizeFlag,
   202  		LogMinSizeFlag,
   203  		LogMaxTotalSizeFlag,
   204  		LogIntervalFlag,
   205  		LogMaxAgeFlag,
   206  		LogCompressFlag,
   207  		LogStatusFlag,
   208  		MLogFlag,
   209  		MLogDirFlag,
   210  		MLogComponentsFlag,
   211  		BacktraceAtFlag,
   212  		MetricsFlag,
   213  		FakePoWFlag,
   214  		SolcPathFlag,
   215  		GpoMinGasPriceFlag,
   216  		GpoMaxGasPriceFlag,
   217  		GpoFullBlockRatioFlag,
   218  		GpobaseStepDownFlag,
   219  		GpobaseStepUpFlag,
   220  		GpobaseCorrectionFactorFlag,
   221  		ExtraDataFlag,
   222  		Unused1,
   223  	}
   224  
   225  	app.Before = func(ctx *cli.Context) error {
   226  
   227  		// It's a patch.
   228  		// Don't know why urfave/cli isn't catching the unknown command on its own.
   229  		if ctx.Args().Present() {
   230  			commandExists := false
   231  			for _, cmd := range app.Commands {
   232  				if cmd.HasName(ctx.Args().First()) {
   233  					commandExists = true
   234  				}
   235  			}
   236  			if !commandExists {
   237  				if e := cli.ShowCommandHelp(ctx, ctx.Args().First()); e != nil {
   238  					return e
   239  				}
   240  			}
   241  		}
   242  
   243  		// Check for --exec set without console OR attach
   244  		if ctx.IsSet(ExecFlag.Name) {
   245  			// If no command is used, OR command is not one of the valid commands attach/console
   246  			if cmdName := ctx.Args().First(); cmdName == "" || (cmdName != "console" && cmdName != "attach") {
   247  				log.Printf("Error: --%v flag requires use of 'attach' OR 'console' command, command was: '%v'", ExecFlag.Name, cmdName)
   248  				cli.ShowCommandHelp(ctx, consoleCommand.Name)
   249  				cli.ShowCommandHelp(ctx, attachCommand.Name)
   250  				os.Exit(1)
   251  			}
   252  		}
   253  
   254  		if ctx.IsSet(SputnikVMFlag.Name) {
   255  			if core.SputnikVMExists {
   256  				core.UseSputnikVM = "true"
   257  			} else {
   258  				log.Fatal("This version of geth wasn't built to include SputnikVM. To build with SputnikVM, use -tags=sputnikvm following the go build command.")
   259  			}
   260  		}
   261  
   262  		// Check for migrations and handle if conditionals are met.
   263  		if err := handleIfDataDirSchemaMigrations(ctx); err != nil {
   264  			return err
   265  		}
   266  
   267  		if err := setupLogRotation(ctx); err != nil {
   268  			return err
   269  		}
   270  
   271  		// Handle parsing and applying log verbosity, severities, and default configurations from context.
   272  		if err := setupLogging(ctx); err != nil {
   273  			return err
   274  		}
   275  
   276  		// Handle parsing and applying log rotation configs from context.
   277  		if err := setupLogRotation(ctx); err != nil {
   278  			return err
   279  		}
   280  
   281  		if s := ctx.String("metrics"); s != "" {
   282  			go metrics.CollectToFile(s)
   283  		}
   284  
   285  		// (whilei): I use `log` instead of `glog` because git diff tells me:
   286  		// > The output of this command is supposed to be machine-readable.
   287  		gasLimit := ctx.GlobalString(aliasableName(TargetGasLimitFlag.Name, ctx))
   288  		if _, ok := core.TargetGasLimit.SetString(gasLimit, 0); !ok {
   289  			return fmt.Errorf("malformed %s flag value %q", aliasableName(TargetGasLimitFlag.Name, ctx), gasLimit)
   290  		}
   291  
   292  		// Set morden chain by default for dev mode.
   293  		if ctx.GlobalBool(aliasableName(DevModeFlag.Name, ctx)) {
   294  			if !ctx.GlobalIsSet(aliasableName(ChainIdentityFlag.Name, ctx)) {
   295  				if e := ctx.Set(aliasableName(ChainIdentityFlag.Name, ctx), "morden"); e != nil {
   296  					return fmt.Errorf("failed to set chain value: %v", e)
   297  				}
   298  			}
   299  		}
   300  
   301  		if port := ctx.GlobalInt(PprofFlag.Name); port != 0 {
   302  			interval := 5 * time.Second
   303  			if i := ctx.GlobalInt(PprofIntervalFlag.Name); i > 0 {
   304  				interval = time.Duration(i) * time.Second
   305  			}
   306  			rtppf.Start(interval, port)
   307  		}
   308  
   309  		return nil
   310  	}
   311  
   312  	app.After = func(ctx *cli.Context) error {
   313  		rtppf.Stop()
   314  		logger.Flush()
   315  		console.Stdin.Close() // Resets terminal mode.
   316  		return nil
   317  	}
   318  
   319  	app.CommandNotFound = func(c *cli.Context, command string) {
   320  		fmt.Fprintf(c.App.Writer, "Invalid command: %q. Please find `geth` usage below. \n", command)
   321  		cli.ShowAppHelp(c)
   322  		os.Exit(3)
   323  	}
   324  	return app
   325  }
   326  
   327  func main() {
   328  	app := makeCLIApp()
   329  	if err := app.Run(os.Args); err != nil {
   330  		fmt.Fprintln(os.Stderr, err)
   331  		os.Exit(1)
   332  	}
   333  }
   334  
   335  // geth is the main entry point into the system if no special subcommand is ran.
   336  // It creates a default node based on the command line arguments and runs it in
   337  // blocking mode, waiting for it to be shut down.
   338  func geth(ctx *cli.Context) error {
   339  
   340  	n := MakeSystemNode(Version, ctx)
   341  	ethe := startNode(ctx, n)
   342  
   343  	if ctx.GlobalString(LogStatusFlag.Name) != "off" {
   344  		dispatchStatusLogs(ctx, ethe)
   345  	}
   346  	logLoggingConfiguration(ctx)
   347  
   348  	n.Wait()
   349  
   350  	return nil
   351  }