// Copyright 2014 The go-ethereum Authors // This file is part of go-ethereum. // // go-ethereum is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // go-ethereum is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see . // geth is the official command-line client for Ethereum. package main import ( "encoding/hex" "fmt" "io/ioutil" "os" "path/filepath" "runtime" "strconv" "strings" "time" "github.com/ethereum/ethash" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/console" "github.com/ethereum/go-ethereum/contracts/release" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p/discover" "gopkg.in/urfave/cli.v1" ) const ( clientIdentifier = "geth" // Client identifier to advertise over the network ) var ( // Git SHA1 commit hash of the release (set via linker flags) gitCommit = "" // Ethereum address of the Geth release oracle. relOracle = common.HexToAddress("0xfa7b9770ca4cb04296cac84f37736d4041251cdf") // The app that holds all commands and flags. app = utils.NewApp(gitCommit, "the go-ethereum command line interface") ) func init() { // Initialize the CLI app and start Geth app.Action = geth app.HideVersion = true // we have a command to print the version app.Commands = []cli.Command{ importCommand, exportCommand, upgradedbCommand, removedbCommand, dumpCommand, monitorCommand, accountCommand, walletCommand, consoleCommand, attachCommand, javascriptCommand, { Action: makedag, Name: "makedag", Usage: "generate ethash dag (for testing)", Description: ` The makedag command generates an ethash DAG in /tmp/dag. This command exists to support the system testing project. Regular users do not need to execute it. `, }, { Action: version, Name: "version", Usage: "print ethereum version numbers", Description: ` The output of this command is supposed to be machine-readable. `, }, { Action: initGenesis, Name: "init", Usage: "bootstraps and initialises a new genesis block (JSON)", Description: ` The init command initialises a new genesis block and definition for the network. This is a destructive action and changes the network in which you will be participating. `, }, { Action: license, Name: "license", Usage: "displays geth's license information", }, } app.Flags = []cli.Flag{ utils.IdentityFlag, utils.UnlockedAccountFlag, utils.PasswordFileFlag, utils.BootnodesFlag, utils.DataDirFlag, utils.KeyStoreDirFlag, utils.OlympicFlag, utils.FastSyncFlag, utils.LightModeFlag, utils.NoDefSrvFlag, utils.LightServFlag, utils.LightPeersFlag, utils.LightKDFFlag, utils.CacheFlag, utils.TrieCacheGenFlag, utils.JSpathFlag, utils.ListenPortFlag, utils.MaxPeersFlag, utils.MaxPendingPeersFlag, utils.EtherbaseFlag, utils.GasPriceFlag, utils.SupportDAOFork, utils.OpposeDAOFork, utils.MinerThreadsFlag, utils.MiningEnabledFlag, utils.AutoDAGFlag, utils.TargetGasLimitFlag, utils.NATFlag, utils.NatspecEnabledFlag, utils.NoDiscoverFlag, utils.NodeKeyFileFlag, utils.NodeKeyHexFlag, utils.RPCEnabledFlag, utils.RPCListenAddrFlag, utils.RPCPortFlag, utils.RPCApiFlag, utils.WSEnabledFlag, utils.WSListenAddrFlag, utils.WSPortFlag, utils.WSApiFlag, utils.WSAllowedOriginsFlag, utils.IPCDisabledFlag, utils.IPCApiFlag, utils.IPCPathFlag, utils.ExecFlag, utils.PreloadJSFlag, utils.WhisperEnabledFlag, utils.DevModeFlag, utils.TestNetFlag, utils.VMForceJitFlag, utils.VMJitCacheFlag, utils.VMEnableJitFlag, utils.NetworkIdFlag, utils.RPCCORSDomainFlag, utils.MetricsEnabledFlag, utils.FakePoWFlag, utils.SolcPathFlag, utils.GpoMinGasPriceFlag, utils.GpoMaxGasPriceFlag, utils.GpoFullBlockRatioFlag, utils.GpobaseStepDownFlag, utils.GpobaseStepUpFlag, utils.GpobaseCorrectionFactorFlag, utils.ExtraDataFlag, } app.Flags = append(app.Flags, debug.Flags...) app.Before = func(ctx *cli.Context) error { runtime.GOMAXPROCS(runtime.NumCPU()) if err := debug.Setup(ctx); err != nil { return err } // Start system runtime metrics collection go metrics.CollectProcessMetrics(3 * time.Second) // This should be the only place where reporting is enabled // because it is not intended to run while testing. // In addition to this check, bad block reports are sent only // for chains with the main network genesis block and network id 1. eth.EnableBadBlockReporting = true utils.SetupNetwork(ctx) return nil } app.After = func(ctx *cli.Context) error { logger.Flush() debug.Exit() console.Stdin.Close() // Resets terminal mode. return nil } } func main() { if err := app.Run(os.Args); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } // geth is the main entry point into the system if no special subcommand is ran. // It creates a default node based on the command line arguments and runs it in // blocking mode, waiting for it to be shut down. func geth(ctx *cli.Context) error { node := makeFullNode(ctx) startNode(ctx, node) node.Wait() return nil } // initGenesis will initialise the given JSON format genesis file and writes it as // the zero'd block (i.e. genesis) or will fail hard if it can't succeed. func initGenesis(ctx *cli.Context) error { genesisPath := ctx.Args().First() if len(genesisPath) == 0 { utils.Fatalf("must supply path to genesis JSON file") } if ctx.GlobalBool(utils.TestNetFlag.Name) { state.StartingNonce = 1048576 // (2**20) } stack := makeFullNode(ctx) chaindb := utils.MakeChainDatabase(ctx, stack) genesisFile, err := os.Open(genesisPath) if err != nil { utils.Fatalf("failed to read genesis file: %v", err) } block, err := core.WriteGenesisBlock(chaindb, genesisFile) if err != nil { utils.Fatalf("failed to write genesis block: %v", err) } glog.V(logger.Info).Infof("successfully wrote genesis block and/or chain rule set: %x", block.Hash()) return nil } func makeFullNode(ctx *cli.Context) *node.Node { stack := utils.MakeNode(ctx, clientIdentifier, gitCommit) utils.RegisterEthService(ctx, stack, utils.MakeDefaultExtraData(clientIdentifier)) // Whisper must be explicitly enabled, but is auto-enabled in --dev mode. shhEnabled := ctx.GlobalBool(utils.WhisperEnabledFlag.Name) shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DevModeFlag.Name) if shhEnabled || shhAutoEnabled { utils.RegisterShhService(stack) } // Add the release oracle service so it boots along with node. if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { config := release.Config{ Oracle: relOracle, Major: uint32(utils.VersionMajor), Minor: uint32(utils.VersionMinor), Patch: uint32(utils.VersionPatch), } commit, _ := hex.DecodeString(gitCommit) copy(config.Commit[:], commit) return release.NewReleaseService(ctx, config) }); err != nil { utils.Fatalf("Failed to register the Geth release oracle service: %v", err) } return stack } // startNode boots up the system node and all registered protocols, after which // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the // miner. func startNode(ctx *cli.Context, stack *node.Node) { // Start up the node itself utils.StartNode(stack) if ctx.GlobalBool(utils.LightModeFlag.Name) && !ctx.GlobalBool(utils.NoDefSrvFlag.Name) { // add default light server; test phase only addPeer := func(url string) { node, err := discover.ParseNode(url) if err == nil { stack.Server().AddPeer(node) } } if ctx.GlobalBool(utils.TestNetFlag.Name) { // TestNet (John Gerryts @phonikg) addPeer("enode://d72af45ba9b60851a8077a4eb07700484b585e5f2e55024e0c93b7ec7d114f2e3fa3c8f3a3358f89da00a609f5a062415deb857ada863b8cdad02b0b0bc90da3@50.112.52.169:30301") } else { if ctx.GlobalBool(utils.OpposeDAOFork.Name) { // Classic (Azure) addPeer("enode://fc3d7b57e5d317946bf421411632ec98d5ffcbf94548cd7bc10088e4fef176670f8ec70280d301a9d0b22fe498203f62b323da15b3acc18b02a1fee2a06b7d3f@40.118.3.223:30305") } else { // MainNet (Azure) addPeer("enode://feaf206a308a669a789be45f4dadcb351246051727f12415ad69e44f8080daf0569c10fe1d9944d245dd1f3e1c89cedda8ce03d7e3d5ed8975a35cad4b4f7ec1@40.118.3.223:30303") // MainNet (John Gerryts @phonikg) addPeer("enode://02b80f0d47c7c157c069d0584067a284cdf188b9267666234b872e70d936a803ad20ea27f78ef1fd6425ae4b7108907e1875adbca96b038004114ac4d1e529a3@50.112.52.169:30300") } } } // Unlock any account specifically requested accman := stack.AccountManager() passwords := utils.MakePasswordList(ctx) accounts := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",") for i, account := range accounts { if trimmed := strings.TrimSpace(account); trimmed != "" { unlockAccount(ctx, accman, trimmed, i, passwords) } } // Start auxiliary services if enabled if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { var ethereum *eth.Ethereum if err := stack.Service(ðereum); err != nil { utils.Fatalf("ethereum service not running: %v", err) } if err := ethereum.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name)); err != nil { utils.Fatalf("Failed to start mining: %v", err) } } } func makedag(ctx *cli.Context) error { args := ctx.Args() wrongArgs := func() { utils.Fatalf(`Usage: geth makedag `) } switch { case len(args) == 2: blockNum, err := strconv.ParseUint(args[0], 0, 64) dir := args[1] if err != nil { wrongArgs() } else { dir = filepath.Clean(dir) // seems to require a trailing slash if !strings.HasSuffix(dir, "/") { dir = dir + "/" } _, err = ioutil.ReadDir(dir) if err != nil { utils.Fatalf("Can't find dir") } fmt.Println("making DAG, this could take awhile...") ethash.MakeDAG(blockNum, dir) } default: wrongArgs() } return nil } func version(c *cli.Context) error { fmt.Println(strings.Title(clientIdentifier)) fmt.Println("Version:", utils.Version) if gitCommit != "" { fmt.Println("Git Commit:", gitCommit) } fmt.Println("Protocol Versions:", eth.ProtocolVersions) fmt.Println("Network Id:", c.GlobalInt(utils.NetworkIdFlag.Name)) fmt.Println("Go Version:", runtime.Version()) fmt.Println("OS:", runtime.GOOS) fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH")) fmt.Printf("GOROOT=%s\n", runtime.GOROOT()) return nil } func license(c *cli.Context) error { fmt.Println(`Geth is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Geth is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with geth. If not, see . `) return nil }