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 := ð.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 }