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

     1  // Copyright 2015 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  package main
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"log"
    24  	"math/big"
    25  	"os"
    26  	"path/filepath"
    27  	"runtime"
    28  	"strconv"
    29  	"strings"
    30  
    31  	"errors"
    32  
    33  	"github.com/ethereumproject/ethash"
    34  	"github.com/ethereumproject/go-ethereum/accounts"
    35  	"github.com/ethereumproject/go-ethereum/common"
    36  	"github.com/ethereumproject/go-ethereum/core"
    37  	"github.com/ethereumproject/go-ethereum/core/state"
    38  	"github.com/ethereumproject/go-ethereum/core/types"
    39  	"github.com/ethereumproject/go-ethereum/crypto"
    40  	"github.com/ethereumproject/go-ethereum/eth"
    41  	"github.com/ethereumproject/go-ethereum/ethdb"
    42  	"github.com/ethereumproject/go-ethereum/event"
    43  	"github.com/ethereumproject/go-ethereum/logger"
    44  	"github.com/ethereumproject/go-ethereum/logger/glog"
    45  	"github.com/ethereumproject/go-ethereum/miner"
    46  	"github.com/ethereumproject/go-ethereum/node"
    47  	"github.com/ethereumproject/go-ethereum/p2p/discover"
    48  	"github.com/ethereumproject/go-ethereum/p2p/nat"
    49  	"github.com/ethereumproject/go-ethereum/pow"
    50  	"github.com/ethereumproject/go-ethereum/whisper"
    51  	"gopkg.in/urfave/cli.v1"
    52  )
    53  
    54  func init() {
    55  	cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
    56  
    57  VERSION:
    58     {{.Version}}
    59  
    60  COMMANDS:
    61     {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
    62     {{end}}{{if .Flags}}
    63  GLOBAL OPTIONS:
    64     {{range .Flags}}{{.}}
    65     {{end}}{{end}}
    66  `
    67  
    68  	cli.CommandHelpTemplate = `{{.Name}}{{if .Subcommands}} command{{end}}{{if .Flags}} [command options]{{end}} [arguments...]
    69  {{if .Description}}{{.Description}}
    70  {{end}}{{if .Subcommands}}
    71  SUBCOMMANDS:
    72  	{{range .Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
    73  	{{end}}{{end}}{{if .Flags}}
    74  OPTIONS:
    75  	{{range .Flags}}{{.}}
    76  	{{end}}{{end}}
    77  `
    78  }
    79  
    80  var (
    81  	// Errors.
    82  	ErrInvalidFlag = errors.New("invalid flag or context value")
    83  
    84  	ErrDirectoryStructure = errors.New("error in directory structure")
    85  	ErrStackFail          = errors.New("error in stack protocol")
    86  
    87  	devModeDataDirPath = filepath.Join(os.TempDir(), "/ethereum_dev_mode")
    88  )
    89  
    90  // chainIsMorden allows either
    91  // '--testnet' (legacy), or
    92  // '--chain=morden|testnet'
    93  func chainIsMorden(ctx *cli.Context) bool {
    94  	if ctx.GlobalBool(aliasableName(TestNetFlag.Name, ctx)) {
    95  		return true
    96  	}
    97  	if _, ok := core.ChainIdentitiesMorden[core.GetCacheChainIdentity()]; ok {
    98  		return ok
    99  	}
   100  	if _, ok := core.ChainIdentitiesMorden[ctx.GlobalString(aliasableName(ChainIdentityFlag.Name, ctx))]; ok {
   101  		return ok
   102  	}
   103  	if c := core.GetCacheChainConfig(); c != nil {
   104  		if _, ok := core.ChainIdentitiesMorden[c.Identity]; ok {
   105  			return ok
   106  		}
   107  	}
   108  	return false
   109  }
   110  
   111  // if argument to --chain is a path and is a valid configuration file, copy it to
   112  // identity/chain.json. It will overwrite an existing configuration file with same identity.
   113  // This allows specification of a chain config by filename and subsequently by configured identity as well.
   114  func copyChainConfigFileToChainDataDir(ctx *cli.Context, identity, configFilePath string) error {
   115  	// Ensure directory path exists.
   116  	identityDirPath := common.EnsurePathAbsoluteOrRelativeTo(mustMakeDataDir(ctx), identity)
   117  	if e := os.MkdirAll(identityDirPath, os.ModePerm); e != nil {
   118  		return e
   119  	}
   120  
   121  	// glog.V(logger.Debug).Infof("Copying %v to %v/chain.json", configFilePath, identityDirPath)
   122  	b, e := ioutil.ReadFile(configFilePath)
   123  	if e != nil {
   124  		return e
   125  	}
   126  
   127  	if e := ioutil.WriteFile(filepath.Join(identityDirPath, "chain.json"), b, os.ModePerm); e != nil {
   128  		return e
   129  	}
   130  	return nil
   131  }
   132  
   133  // getChainIdentity parses --chain and --testnet (legacy) flags.
   134  // It will fatal if finds notok value.
   135  // It returns one of valid strings: ["mainnet", "morden", or --chain="flaggedCustom"]
   136  func mustMakeChainIdentity(ctx *cli.Context) (identity string) {
   137  
   138  	if id := core.GetCacheChainIdentity(); id != "" {
   139  		return id
   140  	}
   141  
   142  	if ctx.GlobalIsSet(aliasableName(TestNetFlag.Name, ctx)) && ctx.GlobalIsSet(aliasableName(ChainIdentityFlag.Name, ctx)) {
   143  		glog.Fatalf(`%v: used redundant/conflicting flags: --%v, --%v
   144  		Please use one or the other, but not both.`, ErrInvalidFlag, aliasableName(TestNetFlag.Name, ctx), aliasableName(ChainIdentityFlag.Name, ctx))
   145  		return ""
   146  	}
   147  
   148  	defer func() {
   149  		core.SetCacheChainIdentity(identity)
   150  	}()
   151  
   152  	if chainFlagVal := ctx.GlobalString(aliasableName(ChainIdentityFlag.Name, ctx)); chainFlagVal != "" {
   153  		ctx.GlobalSet(aliasableName(ChainIdentityFlag.Name, ctx), filepath.Clean(chainFlagVal))
   154  	}
   155  
   156  	if chainIsMorden(ctx) {
   157  		// This makes '--testnet', '--chain=testnet', and '--chain=morden' all use the same /morden subdirectory, if --chain isn't specified
   158  		identity = core.DefaultConfigMorden.Identity
   159  		return identity
   160  	}
   161  	// If --chain is in use.
   162  	if chainFlagVal := ctx.GlobalString(aliasableName(ChainIdentityFlag.Name, ctx)); chainFlagVal != "" {
   163  		if core.ChainIdentitiesMain[chainFlagVal] {
   164  			identity = core.DefaultConfigMainnet.Identity
   165  			return identity
   166  		}
   167  		// Check for disallowed values.
   168  		if core.ChainIdentitiesBlacklist[chainFlagVal] {
   169  			glog.Fatalf(`%v: %v: reserved word
   170  					reserved words for --chain flag include: 'chaindata', 'dapp', 'keystore', 'nodekey', 'nodes',
   171  					please use a different identifier`, ErrInvalidFlag, core.ErrInvalidChainID)
   172  			identity = ""
   173  			return identity
   174  		}
   175  
   176  		// Check if passed arg exists as a path to a valid config file.
   177  		if fstat, ferr := os.Stat(filepath.Clean(chainFlagVal)); ferr == nil && !fstat.IsDir() {
   178  			glog.V(logger.Debug).Infof("Found existing file at --%v: %v", aliasableName(ChainIdentityFlag.Name, ctx), chainFlagVal)
   179  			c, configurationError := core.ReadExternalChainConfigFromFile(filepath.Clean(chainFlagVal))
   180  			if configurationError == nil {
   181  				// glog.V(logger.Debug).Infof("OK: Valid chain configuration. Chain identity: %v", c.Identity)
   182  				if e := copyChainConfigFileToChainDataDir(ctx, c.Identity, filepath.Clean(chainFlagVal)); e != nil {
   183  					glog.Fatalf("Could not copy chain configuration: %v", e)
   184  				}
   185  				// In edge case of using a config file for default configuration (decided by 'identity'),
   186  				// set global context and override config file.
   187  				if core.ChainIdentitiesMorden[c.Identity] || core.ChainIdentitiesMain[c.Identity] {
   188  					if e := ctx.Set(aliasableName(ChainIdentityFlag.Name, ctx), c.Identity); e != nil {
   189  						glog.Fatalf("Could not set global context chain identity to morden, error: %v", e)
   190  					}
   191  				}
   192  				identity = c.Identity
   193  				return identity
   194  			}
   195  			glog.Fatalf("Invalid chain config file at --%v: '%v': %v \nAssuming literal identity argument.",
   196  				aliasableName(ChainIdentityFlag.Name, ctx), chainFlagVal, configurationError)
   197  		}
   198  		// glog.V(logger.Debug).Infof("No existing file at --%v: '%v'. Using literal chain identity.", aliasableName(ChainIdentityFlag.Name, ctx), chainFlagVal)
   199  		identity = chainFlagVal
   200  		return identity
   201  	} else if ctx.GlobalIsSet(aliasableName(ChainIdentityFlag.Name, ctx)) {
   202  		glog.Fatalf("%v: %v: chainID empty", ErrInvalidFlag, core.ErrInvalidChainID)
   203  		identity = ""
   204  		return identity
   205  	}
   206  	// If no relevant flag is set, return default mainnet.
   207  	identity = core.DefaultConfigMainnet.Identity
   208  	return identity
   209  }
   210  
   211  // mustMakeChainConfigNameDefaulty gets mainnet or testnet defaults if in use.
   212  // _If a custom net is in use, it echoes the name of the ChainConfigID._
   213  // It is intended to be a human-readable name for a chain configuration.
   214  // - It should only be called in reference to default configuration (name will be configured
   215  // separately through external JSON config otherwise).
   216  func mustMakeChainConfigNameDefaulty(ctx *cli.Context) string {
   217  	if chainIsMorden(ctx) {
   218  		return core.DefaultConfigMorden.Name
   219  	}
   220  	return core.DefaultConfigMainnet.Name
   221  }
   222  
   223  // mustMakeDataDir retrieves the currently requested data directory, terminating
   224  // if none (or the empty string) is specified.
   225  // --> <home>/<EthereumClassic>(defaulty) or --datadir
   226  func mustMakeDataDir(ctx *cli.Context) string {
   227  	if !ctx.GlobalIsSet(aliasableName(DataDirFlag.Name, ctx)) {
   228  		if ctx.GlobalBool(aliasableName(DevModeFlag.Name, ctx)) {
   229  			return devModeDataDirPath
   230  		}
   231  	}
   232  	if path := ctx.GlobalString(aliasableName(DataDirFlag.Name, ctx)); path != "" {
   233  		return path
   234  	}
   235  
   236  	glog.Fatalf("%v: cannot determine data directory, please set manually (--%v)", ErrDirectoryStructure, DataDirFlag.Name)
   237  	return ""
   238  }
   239  
   240  // MustMakeChainDataDir retrieves the currently requested data directory including chain-specific subdirectory.
   241  // A subdir of the datadir is used for each chain configuration ("/mainnet", "/testnet", "/my-custom-net").
   242  // --> <home>/<EthereumClassic>/<mainnet|testnet|custom-net>, per --chain
   243  func MustMakeChainDataDir(ctx *cli.Context) string {
   244  	rp := common.EnsurePathAbsoluteOrRelativeTo(mustMakeDataDir(ctx), mustMakeChainIdentity(ctx))
   245  	if !filepath.IsAbs(rp) {
   246  		af, e := filepath.Abs(rp)
   247  		if e != nil {
   248  			glog.Fatalf("cannot make absolute path for chain data dir: %v: %v", rp, e)
   249  		}
   250  		rp = af
   251  	}
   252  	return rp
   253  }
   254  
   255  // MakeIPCPath creates an IPC path configuration from the set command line flags,
   256  // returning an empty string if IPC was explicitly disabled, or the set path.
   257  func MakeIPCPath(ctx *cli.Context) string {
   258  	if ctx.GlobalBool(aliasableName(IPCDisabledFlag.Name, ctx)) {
   259  		return ""
   260  	}
   261  	return ctx.GlobalString(aliasableName(IPCPathFlag.Name, ctx))
   262  }
   263  
   264  // MakeNodeKey creates a node key from set command line flags, either loading it
   265  // from a file or as a specified hex value. If neither flags were provided, this
   266  // method returns nil and an emphemeral key is to be generated.
   267  func MakeNodeKey(ctx *cli.Context) *ecdsa.PrivateKey {
   268  	var (
   269  		hex  = ctx.GlobalString(aliasableName(NodeKeyHexFlag.Name, ctx))
   270  		file = ctx.GlobalString(aliasableName(NodeKeyFileFlag.Name, ctx))
   271  
   272  		key *ecdsa.PrivateKey
   273  		err error
   274  	)
   275  	switch {
   276  	case file != "" && hex != "":
   277  		log.Fatalf("Options %q and %q are mutually exclusive", aliasableName(NodeKeyFileFlag.Name, ctx), aliasableName(NodeKeyHexFlag.Name, ctx))
   278  
   279  	case file != "":
   280  		f, err := os.Open(file)
   281  		if err != nil {
   282  			log.Fatalf("could not open node key file: %v", err)
   283  		}
   284  		key, err = crypto.LoadECDSA(f)
   285  		if err != nil {
   286  			log.Fatalf("Option %q: %v", aliasableName(NodeKeyFileFlag.Name, ctx), err)
   287  		}
   288  		err = f.Close()
   289  		if err != nil {
   290  			log.Fatalf("could not close node key file: %v", err)
   291  		}
   292  
   293  	case hex != "":
   294  		if key, err = crypto.HexToECDSA(hex); err != nil {
   295  			log.Fatalf("Option %q: %v", aliasableName(NodeKeyHexFlag.Name, ctx), err)
   296  		}
   297  	}
   298  	return key
   299  }
   300  
   301  // MakeBootstrapNodesFromContext creates a list of bootstrap nodes from the command line
   302  // flags, reverting to pre-configured ones if none have been specified.
   303  func MakeBootstrapNodesFromContext(ctx *cli.Context) []*discover.Node {
   304  	// Return pre-configured nodes if none were manually requested
   305  	if !ctx.GlobalIsSet(aliasableName(BootnodesFlag.Name, ctx)) {
   306  
   307  		// --testnet/--chain=morden flag overrides --config flag
   308  		if chainIsMorden(ctx) {
   309  			return core.DefaultConfigMorden.ParsedBootstrap
   310  		}
   311  		return core.DefaultConfigMainnet.ParsedBootstrap
   312  	}
   313  	return core.ParseBootstrapNodeStrings(strings.Split(ctx.GlobalString(aliasableName(BootnodesFlag.Name, ctx)), ","))
   314  }
   315  
   316  // MakeListenAddress creates a TCP listening address string from set command
   317  // line flags.
   318  func MakeListenAddress(ctx *cli.Context) string {
   319  	return fmt.Sprintf(":%d", ctx.GlobalInt(aliasableName(ListenPortFlag.Name, ctx)))
   320  }
   321  
   322  // MakeNAT creates a port mapper from set command line flags.
   323  func MakeNAT(ctx *cli.Context) nat.Interface {
   324  	natif, err := nat.Parse(ctx.GlobalString(aliasableName(NATFlag.Name, ctx)))
   325  	if err != nil {
   326  		log.Fatalf("Option %s: %v", aliasableName(NATFlag.Name, ctx), err)
   327  	}
   328  	return natif
   329  }
   330  
   331  // MakeRPCModules splits input separated by a comma and trims excessive white
   332  // space from the substrings.
   333  func MakeRPCModules(input string) []string {
   334  	result := strings.Split(input, ",")
   335  	for i, r := range result {
   336  		result[i] = strings.TrimSpace(r)
   337  	}
   338  	return result
   339  }
   340  
   341  // MakeHTTPRpcHost creates the HTTP RPC listener interface string from the set
   342  // command line flags, returning empty if the HTTP endpoint is disabled.
   343  func MakeHTTPRpcHost(ctx *cli.Context) string {
   344  	if !ctx.GlobalBool(aliasableName(RPCEnabledFlag.Name, ctx)) {
   345  		return ""
   346  	}
   347  	return ctx.GlobalString(aliasableName(RPCListenAddrFlag.Name, ctx))
   348  }
   349  
   350  // MakeWSRpcHost creates the WebSocket RPC listener interface string from the set
   351  // command line flags, returning empty if the HTTP endpoint is disabled.
   352  func MakeWSRpcHost(ctx *cli.Context) string {
   353  	if !ctx.GlobalBool(aliasableName(WSEnabledFlag.Name, ctx)) {
   354  		return ""
   355  	}
   356  	return ctx.GlobalString(aliasableName(WSListenAddrFlag.Name, ctx))
   357  }
   358  
   359  // MakeDatabaseHandles raises out the number of allowed file handles per process
   360  // for Geth and returns half of the allowance to assign to the database.
   361  func MakeDatabaseHandles() int {
   362  	if err := raiseFdLimit(2048); err != nil {
   363  		glog.V(logger.Warn).Errorf("Failed to raise file descriptor allowance: %v", err)
   364  	}
   365  	limit, err := getFdLimit()
   366  	if err != nil {
   367  		glog.V(logger.Warn).Errorf("Failed to retrieve file descriptor allowance: %v", err)
   368  	}
   369  	if limit > 2048 { // cap database file descriptors even if more is available
   370  		limit = 2048
   371  	}
   372  	return limit / 2 // Leave half for networking and other stuff
   373  }
   374  
   375  // MakeAccountManager creates an account manager from set command line flags.
   376  func MakeAccountManager(ctx *cli.Context) *accounts.Manager {
   377  	// Create the keystore crypto primitive, light if requested
   378  	scryptN := accounts.StandardScryptN
   379  	scryptP := accounts.StandardScryptP
   380  	if ctx.GlobalBool(aliasableName(LightKDFFlag.Name, ctx)) {
   381  		scryptN = accounts.LightScryptN
   382  		scryptP = accounts.LightScryptP
   383  	}
   384  
   385  	datadir := MustMakeChainDataDir(ctx)
   386  
   387  	keydir := filepath.Join(datadir, "keystore")
   388  	if path := ctx.GlobalString(aliasableName(KeyStoreDirFlag.Name, ctx)); path != "" {
   389  		af, e := filepath.Abs(path)
   390  		if e != nil {
   391  			glog.V(logger.Error).Errorf("keydir path could not be made absolute: %v: %v", path, e)
   392  		} else {
   393  			keydir = af
   394  		}
   395  	}
   396  
   397  	m, err := accounts.NewManager(keydir, scryptN, scryptP, ctx.GlobalBool(aliasableName(AccountsIndexFlag.Name, ctx)))
   398  	if err != nil {
   399  		glog.Fatalf("init account manager at %q: %s", keydir, err)
   400  	}
   401  	return m
   402  }
   403  
   404  // MakeAddress converts an account specified directly as a hex encoded string or
   405  // a key index in the key store to an internal account representation.
   406  func MakeAddress(accman *accounts.Manager, account string) (accounts.Account, error) {
   407  	// If the specified account is a valid address, return it
   408  	if common.IsHexAddress(account) {
   409  		return accounts.Account{Address: common.HexToAddress(account)}, nil
   410  	}
   411  	// Otherwise try to interpret the account as a keystore index
   412  	index, err := strconv.Atoi(account)
   413  	if err != nil {
   414  		return accounts.Account{}, fmt.Errorf("invalid account address or index: %q", account)
   415  	}
   416  	return accman.AccountByIndex(index)
   417  }
   418  
   419  // MakeEtherbase retrieves the etherbase either from the directly specified
   420  // command line flags or from the keystore if CLI indexed.
   421  func MakeEtherbase(accman *accounts.Manager, ctx *cli.Context) common.Address {
   422  	accounts := accman.Accounts()
   423  	if !ctx.GlobalIsSet(aliasableName(EtherbaseFlag.Name, ctx)) && len(accounts) == 0 {
   424  		glog.V(logger.Warn).Warnf("No etherbase set and no accounts found as default")
   425  		glog.D(logger.Warn).Warnf("No etherbase set and no accounts found as default")
   426  		return common.Address{}
   427  	}
   428  	etherbase := ctx.GlobalString(aliasableName(EtherbaseFlag.Name, ctx))
   429  	if etherbase == "" {
   430  		return common.Address{}
   431  	}
   432  	// If the specified etherbase is a valid address, return it
   433  	account, err := MakeAddress(accman, etherbase)
   434  	if err != nil {
   435  		log.Fatalf("Option %q: %v", aliasableName(EtherbaseFlag.Name, ctx), err)
   436  	}
   437  	return account.Address
   438  }
   439  
   440  // MakePasswordList reads password lines from the file specified by --password.
   441  func MakePasswordList(ctx *cli.Context) []string {
   442  	path := ctx.GlobalString(aliasableName(PasswordFileFlag.Name, ctx))
   443  	if path == "" {
   444  		return nil
   445  	}
   446  	text, err := ioutil.ReadFile(path)
   447  	if err != nil {
   448  		glog.Fatal("Failed to read password file: ", err)
   449  	}
   450  	lines := strings.Split(string(text), "\n")
   451  	// Sanitise DOS line endings.
   452  	for i := range lines {
   453  		lines[i] = strings.TrimRight(lines[i], "\r")
   454  	}
   455  	return lines
   456  }
   457  
   458  // makeName makes the node name, which can be (in part) customized by the NodeNameFlag
   459  func makeNodeName(version string, ctx *cli.Context) string {
   460  	name := fmt.Sprintf("Geth/%s/%s/%s", version, runtime.GOOS, runtime.Version())
   461  	if identity := ctx.GlobalString(aliasableName(NodeNameFlag.Name, ctx)); len(identity) > 0 {
   462  		name += "/" + identity
   463  	}
   464  	return name
   465  }
   466  
   467  // MakeSystemNode sets up a local node, configures the services to launch and
   468  // assembles the P2P protocol stack.
   469  func MakeSystemNode(version string, ctx *cli.Context) *node.Node {
   470  
   471  	// global settings
   472  
   473  	if ctx.GlobalIsSet(aliasableName(ExtraDataFlag.Name, ctx)) {
   474  		s := ctx.GlobalString(aliasableName(ExtraDataFlag.Name, ctx))
   475  		if len(s) > types.HeaderExtraMax {
   476  			log.Fatalf("%s flag %q exceeds size limit of %d", aliasableName(ExtraDataFlag.Name, ctx), s, types.HeaderExtraMax)
   477  		}
   478  		miner.HeaderExtra = []byte(s)
   479  	}
   480  
   481  	// Makes sufficient configuration from JSON file or DB pending flags.
   482  	// Delegates flag usage.
   483  	config := mustMakeSufficientChainConfig(ctx)
   484  	logChainConfiguration(ctx, config)
   485  
   486  	// Configure the Ethereum service
   487  	ethConf := mustMakeEthConf(ctx, config)
   488  
   489  	// Configure node's service container.
   490  	name := makeNodeName(version, ctx)
   491  	stackConf, shhEnable := mustMakeStackConf(ctx, name, config)
   492  
   493  	// Assemble and return the protocol stack
   494  	stack, err := node.New(stackConf)
   495  	if err != nil {
   496  		glog.Fatalf("%v: failed to create the protocol stack: %v", ErrStackFail, err)
   497  	}
   498  	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
   499  		return eth.New(ctx, ethConf)
   500  	}); err != nil {
   501  		glog.Fatalf("%v: failed to register the Ethereum service: %v", ErrStackFail, err)
   502  	}
   503  	if shhEnable {
   504  		if err := stack.Register(func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil {
   505  			glog.Fatalf("%v: failed to register the Whisper service: %v", ErrStackFail, err)
   506  		}
   507  	}
   508  
   509  	// If --mlog enabled, configure and create mlog dir and file
   510  	if ctx.GlobalString(MLogFlag.Name) != "off" {
   511  		mustRegisterMLogsFromContext(ctx)
   512  	}
   513  
   514  	if ctx.GlobalBool(Unused1.Name) {
   515  		glog.V(logger.Warn).Warnln(fmt.Sprintf("Geth started with --%s flag, which is unused by Geth Classic and can be omitted", Unused1.Name))
   516  	}
   517  
   518  	return stack
   519  }
   520  
   521  // shouldAttemptDirMigration decides based on flags if
   522  // should attempt to migration from old (<=3.3) directory schema to new.
   523  func shouldAttemptDirMigration(ctx *cli.Context) bool {
   524  	if !ctx.GlobalIsSet(aliasableName(DataDirFlag.Name, ctx)) {
   525  		if chainVal := mustMakeChainIdentity(ctx); core.ChainIdentitiesMain[chainVal] || core.ChainIdentitiesMorden[chainVal] {
   526  			return true
   527  		}
   528  	}
   529  	return false
   530  }
   531  
   532  func mustMakeStackConf(ctx *cli.Context, name string, config *core.SufficientChainConfig) (stackConf *node.Config, shhEnable bool) {
   533  	// Configure the node's service container
   534  	stackConf = &node.Config{
   535  		DataDir:         MustMakeChainDataDir(ctx),
   536  		PrivateKey:      MakeNodeKey(ctx),
   537  		Name:            name,
   538  		NoDiscovery:     ctx.GlobalBool(aliasableName(NoDiscoverFlag.Name, ctx)),
   539  		BootstrapNodes:  config.ParsedBootstrap,
   540  		ListenAddr:      MakeListenAddress(ctx),
   541  		NAT:             MakeNAT(ctx),
   542  		MaxPeers:        ctx.GlobalInt(aliasableName(MaxPeersFlag.Name, ctx)),
   543  		MaxPendingPeers: ctx.GlobalInt(aliasableName(MaxPendingPeersFlag.Name, ctx)),
   544  		IPCPath:         MakeIPCPath(ctx),
   545  		HTTPHost:        MakeHTTPRpcHost(ctx),
   546  		HTTPPort:        ctx.GlobalInt(aliasableName(RPCPortFlag.Name, ctx)),
   547  		HTTPCors:        ctx.GlobalString(aliasableName(RPCCORSDomainFlag.Name, ctx)),
   548  		HTTPModules:     MakeRPCModules(ctx.GlobalString(aliasableName(RPCApiFlag.Name, ctx))),
   549  		WSHost:          MakeWSRpcHost(ctx),
   550  		WSPort:          ctx.GlobalInt(aliasableName(WSPortFlag.Name, ctx)),
   551  		WSOrigins:       ctx.GlobalString(aliasableName(WSAllowedOriginsFlag.Name, ctx)),
   552  		WSModules:       MakeRPCModules(ctx.GlobalString(aliasableName(WSApiFlag.Name, ctx))),
   553  	}
   554  
   555  	// Configure the Whisper service
   556  	shhEnable = ctx.GlobalBool(aliasableName(WhisperEnabledFlag.Name, ctx))
   557  
   558  	// Override any default configs in dev mode
   559  	if ctx.GlobalBool(aliasableName(DevModeFlag.Name, ctx)) {
   560  		if !ctx.GlobalIsSet(aliasableName(MaxPeersFlag.Name, ctx)) {
   561  			stackConf.MaxPeers = 0
   562  		}
   563  		// From p2p/server.go:
   564  		// If the port is zero, the operating system will pick a port. The
   565  		// ListenAddr field will be updated with the actual address when
   566  		// the server is started.
   567  		if !ctx.GlobalIsSet(aliasableName(ListenPortFlag.Name, ctx)) {
   568  			stackConf.ListenAddr = ":0"
   569  		}
   570  		if !ctx.GlobalIsSet(aliasableName(WhisperEnabledFlag.Name, ctx)) {
   571  			shhEnable = true
   572  		}
   573  	}
   574  
   575  	return stackConf, shhEnable
   576  }
   577  
   578  func mustMakeEthConf(ctx *cli.Context, sconf *core.SufficientChainConfig) *eth.Config {
   579  
   580  	accman := MakeAccountManager(ctx)
   581  	passwords := MakePasswordList(ctx)
   582  
   583  	accounts := strings.Split(ctx.GlobalString(aliasableName(UnlockedAccountFlag.Name, ctx)), ",")
   584  	for i, account := range accounts {
   585  		if trimmed := strings.TrimSpace(account); trimmed != "" {
   586  			unlockAccount(ctx, accman, trimmed, i, passwords)
   587  		}
   588  	}
   589  
   590  	ethConf := &eth.Config{
   591  		ChainConfig:             sconf.ChainConfig,
   592  		Genesis:                 sconf.Genesis,
   593  		UseAddrTxIndex:          ctx.GlobalBool(aliasableName(AddrTxIndexFlag.Name, ctx)),
   594  		FastSync:                ctx.GlobalBool(aliasableName(FastSyncFlag.Name, ctx)),
   595  		BlockChainVersion:       ctx.GlobalInt(aliasableName(BlockchainVersionFlag.Name, ctx)),
   596  		DatabaseCache:           ctx.GlobalInt(aliasableName(CacheFlag.Name, ctx)),
   597  		DatabaseHandles:         MakeDatabaseHandles(),
   598  		NetworkId:               sconf.Network,
   599  		MaxPeers:                ctx.GlobalInt(aliasableName(MaxPeersFlag.Name, ctx)),
   600  		AccountManager:          accman,
   601  		Etherbase:               MakeEtherbase(accman, ctx),
   602  		MinerThreads:            ctx.GlobalInt(aliasableName(MinerThreadsFlag.Name, ctx)),
   603  		NatSpec:                 ctx.GlobalBool(aliasableName(NatspecEnabledFlag.Name, ctx)),
   604  		DocRoot:                 ctx.GlobalString(aliasableName(DocRootFlag.Name, ctx)),
   605  		GasPrice:                new(big.Int),
   606  		GpoMinGasPrice:          new(big.Int),
   607  		GpoMaxGasPrice:          new(big.Int),
   608  		GpoFullBlockRatio:       ctx.GlobalInt(aliasableName(GpoFullBlockRatioFlag.Name, ctx)),
   609  		GpobaseStepDown:         ctx.GlobalInt(aliasableName(GpobaseStepDownFlag.Name, ctx)),
   610  		GpobaseStepUp:           ctx.GlobalInt(aliasableName(GpobaseStepUpFlag.Name, ctx)),
   611  		GpobaseCorrectionFactor: ctx.GlobalInt(aliasableName(GpobaseCorrectionFactorFlag.Name, ctx)),
   612  		SolcPath:                ctx.GlobalString(aliasableName(SolcPathFlag.Name, ctx)),
   613  		AutoDAG:                 ctx.GlobalBool(aliasableName(AutoDAGFlag.Name, ctx)) || ctx.GlobalBool(aliasableName(MiningEnabledFlag.Name, ctx)),
   614  	}
   615  
   616  	if _, ok := ethConf.GasPrice.SetString(ctx.GlobalString(aliasableName(GasPriceFlag.Name, ctx)), 0); !ok {
   617  		log.Fatalf("malformed %s flag value %q", aliasableName(GasPriceFlag.Name, ctx), ctx.GlobalString(aliasableName(GasPriceFlag.Name, ctx)))
   618  	}
   619  	if _, ok := ethConf.GpoMinGasPrice.SetString(ctx.GlobalString(aliasableName(GpoMinGasPriceFlag.Name, ctx)), 0); !ok {
   620  		log.Fatalf("malformed %s flag value %q", aliasableName(GpoMinGasPriceFlag.Name, ctx), ctx.GlobalString(aliasableName(GpoMinGasPriceFlag.Name, ctx)))
   621  	}
   622  	if _, ok := ethConf.GpoMaxGasPrice.SetString(ctx.GlobalString(aliasableName(GpoMaxGasPriceFlag.Name, ctx)), 0); !ok {
   623  		log.Fatalf("malformed %s flag value %q", aliasableName(GpoMaxGasPriceFlag.Name, ctx), ctx.GlobalString(aliasableName(GpoMaxGasPriceFlag.Name, ctx)))
   624  	}
   625  
   626  	switch sconf.Consensus {
   627  	case "ethash-test":
   628  		ethConf.PowTest = true
   629  	}
   630  
   631  	// Override any default configs in dev mode
   632  	if ctx.GlobalBool(aliasableName(DevModeFlag.Name, ctx)) {
   633  		// Override the Ethereum protocol configs
   634  		if !ctx.GlobalIsSet(aliasableName(GasPriceFlag.Name, ctx)) {
   635  			ethConf.GasPrice = new(big.Int)
   636  		}
   637  	}
   638  
   639  	return ethConf
   640  }
   641  
   642  // mustMakeSufficientChainConfig makes a sufficent chain configuration (id, chainconfig, nodes,...)
   643  // based on --chain or defaults or fails hard.
   644  // - User must provide a full and complete config file if any is specified located at /custom/chain.json
   645  // - Note: Function reads custom config file each time it is called; this could be altered if desired, but I (whilei) felt
   646  // reading a file a couple of times was more efficient than storing a global.
   647  func mustMakeSufficientChainConfig(ctx *cli.Context) *core.SufficientChainConfig {
   648  
   649  	if c := core.GetCacheChainConfig(); c != nil {
   650  		return c
   651  	}
   652  
   653  	config := &core.SufficientChainConfig{}
   654  	defer func() {
   655  		// Allow flags to override external config file.
   656  		if ctx.GlobalBool(aliasableName(DevModeFlag.Name, ctx)) {
   657  			config.Consensus = "ethash-test"
   658  		}
   659  		if ctx.GlobalIsSet(aliasableName(BootnodesFlag.Name, ctx)) {
   660  			config.ParsedBootstrap = MakeBootstrapNodesFromContext(ctx)
   661  			glog.V(logger.Warn).Warnf(`Overwriting external bootnodes configuration with those from --%s flag. Value set from flag: %v`, aliasableName(BootnodesFlag.Name, ctx), config.ParsedBootstrap)
   662  			glog.D(logger.Warn).Warnf(`Overwriting external bootnodes configuration with those from --%s flag. Value set from flag: %v`, aliasableName(BootnodesFlag.Name, ctx), config.ParsedBootstrap)
   663  		}
   664  		if ctx.GlobalIsSet(aliasableName(NetworkIdFlag.Name, ctx)) {
   665  			i := ctx.GlobalInt(aliasableName(NetworkIdFlag.Name, ctx))
   666  			glog.V(logger.Warn).Warnf(`Overwriting external network id configuration with that from --%s flag. Value set from flag: %d`, aliasableName(NetworkIdFlag.Name, ctx), i)
   667  			glog.D(logger.Warn).Warnf(`Overwriting external network id configuration with that from --%s flag. Value set from flag: %d`, aliasableName(NetworkIdFlag.Name, ctx), i)
   668  			if i < 1 {
   669  				glog.Fatalf("Network ID cannot be less than 1. Got: %d", i)
   670  			}
   671  			config.Network = i
   672  		}
   673  		core.SetCacheChainConfig(config)
   674  	}()
   675  
   676  	chainIdentity := mustMakeChainIdentity(ctx)
   677  
   678  	// If chain identity is either of defaults (via config file or flag), use defaults.
   679  	if core.ChainIdentitiesMain[chainIdentity] || core.ChainIdentitiesMorden[chainIdentity] {
   680  		// Initialise chain configuration before handling migrations or setting up node.
   681  		config.Identity = chainIdentity
   682  		config.Name = mustMakeChainConfigNameDefaulty(ctx)
   683  		config.Network = eth.NetworkId // 1, default mainnet
   684  		config.Consensus = "ethash"
   685  		config.Genesis = core.DefaultConfigMainnet.Genesis
   686  		config.ChainConfig = MustMakeChainConfigFromDefaults(ctx).SortForks()
   687  		config.ParsedBootstrap = MakeBootstrapNodesFromContext(ctx)
   688  		if chainIsMorden(ctx) {
   689  			config.Network = 2
   690  			config.Genesis = core.DefaultConfigMorden.Genesis
   691  			state.StartingNonce = state.DefaultTestnetStartingNonce // (2**20)
   692  		}
   693  		return config
   694  	}
   695  
   696  	// Returns surely valid suff chain config.
   697  	chainDir := MustMakeChainDataDir(ctx)
   698  	defaultChainConfigPath := filepath.Join(chainDir, "chain.json")
   699  	if _, de := os.Stat(defaultChainConfigPath); de != nil && os.IsNotExist(de) {
   700  		glog.Fatalf(`%v: %v
   701  		It looks like you haven't set up your custom chain yet...
   702  		Here's a possible workflow for that:
   703  
   704  		$ geth --chain morden dump-chain-config %v/chain.json
   705  		$ sed -i.bak s/morden/%v/ %v/chain.json
   706  		$ vi %v/chain.json # <- make your customizations
   707  		`, core.ErrChainConfigNotFound, defaultChainConfigPath,
   708  			chainDir, chainIdentity, chainDir, chainDir)
   709  	}
   710  	config, err := core.ReadExternalChainConfigFromFile(defaultChainConfigPath)
   711  	if err != nil {
   712  		glog.Fatalf(`invalid external configuration JSON: '%v': %v
   713  		Valid custom configuration JSON file must be named 'chain.json' and be located in respective chain subdir.`, defaultChainConfigPath, err)
   714  	}
   715  
   716  	// Ensure JSON 'id' value matches name of parent chain subdir.
   717  	if config.Identity != chainIdentity {
   718  		glog.Fatalf(`%v: JSON 'id' value in external config file (%v) must match name of parent subdir (%v)`, core.ErrInvalidChainID, config.Identity, chainIdentity)
   719  	}
   720  
   721  	// Set statedb StartingNonce from external config, if specified (is optional)
   722  	if config.State != nil {
   723  		if sn := config.State.StartingNonce; sn != 0 {
   724  			state.StartingNonce = sn
   725  		}
   726  	}
   727  
   728  	return config
   729  }
   730  
   731  func logChainConfiguration(ctx *cli.Context, config *core.SufficientChainConfig) {
   732  	chainIdentity := mustMakeChainIdentity(ctx)
   733  	chainIsCustom := !(core.ChainIdentitiesMain[chainIdentity] || core.ChainIdentitiesMorden[chainIdentity])
   734  
   735  	// File logs.
   736  	// TODO: uglify V logs? provide more detail for debugging? normal users won't see this.
   737  	if chainIsCustom {
   738  		glog.V(logger.Info).Infof("Using custom chain configuration: %s", chainIdentity)
   739  		glog.D(logger.Warn).Infof("Custom chain config: %s", logger.ColorGreen(chainIdentity))
   740  	}
   741  
   742  	glog.V(logger.Info).Info(glog.Separator("-"))
   743  
   744  	glog.V(logger.Info).Infof("Starting Geth Classic %s", ctx.App.Version)
   745  	glog.D(logger.Warn).Infof("Geth Classic version: %s", logger.ColorGreen(ctx.App.Version))
   746  
   747  	glog.V(logger.Info).Infof("Geth is configured to use ETC blockchain: %v", config.Name)
   748  	glog.D(logger.Warn).Infof("Blockchain: %s", logger.ColorGreen(config.Name))
   749  
   750  	chaindataDirName := MustMakeChainDataDir(ctx) + "/chaindata"
   751  	glog.V(logger.Info).Infof("Using chain database at: %s", chaindataDirName)
   752  	glog.D(logger.Warn).Infof("Chain database: %s", logger.ColorGreen(chaindataDirName))
   753  
   754  	glog.V(logger.Info).Infof("%v blockchain upgrades associated with this configuration:", len(config.ChainConfig.Forks))
   755  	glog.D(logger.Warn).Infof("Blockchain upgrades configured: %s", logger.ColorGreen(strconv.Itoa(len(config.ChainConfig.Forks))))
   756  
   757  	for i := range config.ChainConfig.Forks {
   758  		f := fmt.Sprintf(" %7v %v", config.ChainConfig.Forks[i].Block, config.ChainConfig.Forks[i].Name)
   759  		if !config.ChainConfig.Forks[i].RequiredHash.IsEmpty() {
   760  			f += fmt.Sprintf(" (%v)", config.ChainConfig.Forks[i].RequiredHash.Hex())
   761  		}
   762  		glog.V(logger.Info).Infoln(f)
   763  		glog.D(logger.Warn).Infoln(f)
   764  		for _, feat := range config.ChainConfig.Forks[i].Features {
   765  			glog.V(logger.Debug).Infof("    id: %v", feat.ID)
   766  			for k, v := range feat.Options {
   767  				glog.V(logger.Debug).Infof("        %v: %v", k, v)
   768  			}
   769  		}
   770  	}
   771  
   772  	if chainIsCustom {
   773  		sn := strconv.FormatUint(state.StartingNonce, 10)
   774  		glog.V(logger.Info).Infof("State starting nonce: %s", logger.ColorGreen(sn))
   775  		glog.D(logger.Warn).Infof("State starting nonce: %s", logger.ColorGreen(sn))
   776  	}
   777  
   778  	glog.V(logger.Info).Infof("Using %d configured bootnodes", len(config.ParsedBootstrap))
   779  	glog.D(logger.Warn).Infof("Using %d configured bootnodes", len(config.ParsedBootstrap))
   780  
   781  	glog.V(logger.Info).Infof("Use Sputnik EVM: %s", logger.ColorGreen(fmt.Sprintf("%v", core.UseSputnikVM)))
   782  	glog.D(logger.Warn).Infof("Use Sputnik EVM: %s", logger.ColorGreen(fmt.Sprintf("%v", core.UseSputnikVM)))
   783  
   784  	glog.V(logger.Info).Info(glog.Separator("-"))
   785  
   786  	// If unsafe usage, WARNING!
   787  	logIfUnsafeConfiguration(ctx)
   788  }
   789  
   790  // MustMakeChainConfigFromDefaults reads the chain configuration from hardcode.
   791  func MustMakeChainConfigFromDefaults(ctx *cli.Context) *core.ChainConfig {
   792  	c := core.DefaultConfigMainnet.ChainConfig
   793  	if chainIsMorden(ctx) {
   794  		c = core.DefaultConfigMorden.ChainConfig
   795  	}
   796  	return c
   797  }
   798  
   799  // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
   800  func MakeChainDatabase(ctx *cli.Context) ethdb.Database {
   801  	var (
   802  		chaindir = MustMakeChainDataDir(ctx)
   803  		cache    = ctx.GlobalInt(aliasableName(CacheFlag.Name, ctx))
   804  		handles  = MakeDatabaseHandles()
   805  	)
   806  
   807  	chainDb, err := ethdb.NewLDBDatabase(filepath.Join(chaindir, "chaindata"), cache, handles)
   808  	if err != nil {
   809  		glog.Fatal("Could not open database: ", err)
   810  	}
   811  	return chainDb
   812  }
   813  
   814  func MakeIndexDatabase(ctx *cli.Context) ethdb.Database {
   815  	var (
   816  		chaindir = MustMakeChainDataDir(ctx)
   817  		cache    = ctx.GlobalInt(aliasableName(CacheFlag.Name, ctx))
   818  		handles  = MakeDatabaseHandles()
   819  	)
   820  
   821  	indexesDb, err := ethdb.NewLDBDatabase(filepath.Join(chaindir, "indexes"), cache, handles)
   822  	if err != nil {
   823  		glog.Fatal("Could not open database: ", err)
   824  	}
   825  	return indexesDb
   826  }
   827  
   828  // MakeChain creates a chain manager from set command line flags.
   829  func MakeChain(ctx *cli.Context) (chain *core.BlockChain, chainDb ethdb.Database) {
   830  	var err error
   831  	sconf := mustMakeSufficientChainConfig(ctx)
   832  	chainDb = MakeChainDatabase(ctx)
   833  
   834  	pow := pow.PoW(core.FakePow{})
   835  	if !ctx.GlobalBool(aliasableName(FakePoWFlag.Name, ctx)) {
   836  		pow = ethash.New()
   837  	} else {
   838  		glog.V(logger.Info).Infoln("Consensus: fake")
   839  		glog.D(logger.Warn).Warnln("Consensus: fake")
   840  	}
   841  
   842  	chain, err = core.NewBlockChain(chainDb, sconf.ChainConfig, pow, new(event.TypeMux))
   843  	if err != nil {
   844  		glog.Fatal("Could not start chainmanager: ", err)
   845  	}
   846  	return chain, chainDb
   847  }
   848  
   849  // MakeConsolePreloads retrieves the absolute paths for the console JavaScript
   850  // scripts to preload before starting.
   851  func MakeConsolePreloads(ctx *cli.Context) []string {
   852  	// Skip preloading if there's nothing to preload
   853  	if ctx.GlobalString(aliasableName(PreloadJSFlag.Name, ctx)) == "" {
   854  		return nil
   855  	}
   856  	// Otherwise resolve absolute paths and return them
   857  	preloads := []string{}
   858  
   859  	assets := ctx.GlobalString(aliasableName(JSpathFlag.Name, ctx))
   860  	for _, file := range strings.Split(ctx.GlobalString(aliasableName(PreloadJSFlag.Name, ctx)), ",") {
   861  		preloads = append(preloads, common.EnsurePathAbsoluteOrRelativeTo(assets, strings.TrimSpace(file)))
   862  	}
   863  	return preloads
   864  }