github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/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 "io/ioutil" 23 _ "net/http/pprof" 24 "os" 25 "path/filepath" 26 "runtime" 27 "strconv" 28 "strings" 29 "time" 30 31 "github.com/codegangsta/cli" 32 "github.com/ethereum/ethash" 33 "github.com/ethereum/go-ethereum/accounts" 34 "github.com/ethereum/go-ethereum/cmd/utils" 35 "github.com/ethereum/go-ethereum/common" 36 "github.com/ethereum/go-ethereum/core" 37 "github.com/ethereum/go-ethereum/core/types" 38 "github.com/ethereum/go-ethereum/eth" 39 "github.com/ethereum/go-ethereum/ethdb" 40 "github.com/ethereum/go-ethereum/logger" 41 "github.com/ethereum/go-ethereum/logger/glog" 42 "github.com/ethereum/go-ethereum/metrics" 43 "github.com/ethereum/go-ethereum/params" 44 "github.com/ethereum/go-ethereum/rlp" 45 "github.com/ethereum/go-ethereum/rpc/codec" 46 "github.com/ethereum/go-ethereum/rpc/comms" 47 ) 48 49 const ( 50 ClientIdentifier = "Geth" 51 Version = "1.1.3" 52 VersionMajor = 1 53 VersionMinor = 1 54 VersionPatch = 3 55 ) 56 57 var ( 58 gitCommit string // set via linker flagg 59 nodeNameVersion string 60 app *cli.App 61 ) 62 63 func init() { 64 if gitCommit == "" { 65 nodeNameVersion = Version 66 } else { 67 nodeNameVersion = Version + "-" + gitCommit[:8] 68 } 69 70 app = utils.NewApp(Version, "the go-ethereum command line interface") 71 app.Action = run 72 app.HideVersion = true // we have a command to print the version 73 app.Commands = []cli.Command{ 74 { 75 Action: blockRecovery, 76 Name: "recover", 77 Usage: "attempts to recover a corrupted database by setting a new block by number or hash. See help recover.", 78 Description: ` 79 The recover commands will attempt to read out the last 80 block based on that. 81 82 recover #number recovers by number 83 recover <hex> recovers by hash 84 `, 85 }, 86 blocktestCommand, 87 importCommand, 88 exportCommand, 89 upgradedbCommand, 90 removedbCommand, 91 dumpCommand, 92 monitorCommand, 93 { 94 Action: makedag, 95 Name: "makedag", 96 Usage: "generate ethash dag (for testing)", 97 Description: ` 98 The makedag command generates an ethash DAG in /tmp/dag. 99 100 This command exists to support the system testing project. 101 Regular users do not need to execute it. 102 `, 103 }, 104 { 105 Action: version, 106 Name: "version", 107 Usage: "print ethereum version numbers", 108 Description: ` 109 The output of this command is supposed to be machine-readable. 110 `, 111 }, 112 113 { 114 Name: "wallet", 115 Usage: "ethereum presale wallet", 116 Subcommands: []cli.Command{ 117 { 118 Action: importWallet, 119 Name: "import", 120 Usage: "import ethereum presale wallet", 121 }, 122 }, 123 Description: ` 124 125 get wallet import /path/to/my/presale.wallet 126 127 will prompt for your password and imports your ether presale account. 128 It can be used non-interactively with the --password option taking a 129 passwordfile as argument containing the wallet password in plaintext. 130 131 `}, 132 { 133 Action: accountList, 134 Name: "account", 135 Usage: "manage accounts", 136 Description: ` 137 138 Manage accounts lets you create new accounts, list all existing accounts, 139 import a private key into a new account. 140 141 ' help' shows a list of subcommands or help for one subcommand. 142 143 It supports interactive mode, when you are prompted for password as well as 144 non-interactive mode where passwords are supplied via a given password file. 145 Non-interactive mode is only meant for scripted use on test networks or known 146 safe environments. 147 148 Make sure you remember the password you gave when creating a new account (with 149 either new or import). Without it you are not able to unlock your account. 150 151 Note that exporting your key in unencrypted format is NOT supported. 152 153 Keys are stored under <DATADIR>/keys. 154 It is safe to transfer the entire directory or the individual keys therein 155 between ethereum nodes by simply copying. 156 Make sure you backup your keys regularly. 157 158 In order to use your account to send transactions, you need to unlock them using the 159 '--unlock' option. The argument is a comma 160 161 And finally. DO NOT FORGET YOUR PASSWORD. 162 `, 163 Subcommands: []cli.Command{ 164 { 165 Action: accountList, 166 Name: "list", 167 Usage: "print account addresses", 168 }, 169 { 170 Action: accountCreate, 171 Name: "new", 172 Usage: "create a new account", 173 Description: ` 174 175 ethereum account new 176 177 Creates a new account. Prints the address. 178 179 The account is saved in encrypted format, you are prompted for a passphrase. 180 181 You must remember this passphrase to unlock your account in the future. 182 183 For non-interactive use the passphrase can be specified with the --password flag: 184 185 ethereum --password <passwordfile> account new 186 187 Note, this is meant to be used for testing only, it is a bad idea to save your 188 password to file or expose in any other way. 189 `, 190 }, 191 { 192 Action: accountUpdate, 193 Name: "update", 194 Usage: "update an existing account", 195 Description: ` 196 197 ethereum account update <address> 198 199 Update an existing account. 200 201 The account is saved in the newest version in encrypted format, you are prompted 202 for a passphrase to unlock the account and another to save the updated file. 203 204 This same command can therefore be used to migrate an account of a deprecated 205 format to the newest format or change the password for an account. 206 207 For non-interactive use the passphrase can be specified with the --password flag: 208 209 ethereum --password <passwordfile> account new 210 211 Since only one password can be given, only format update can be performed, 212 changing your password is only possible interactively. 213 214 Note that account update has the a side effect that the order of your accounts 215 changes. 216 `, 217 }, 218 { 219 Action: accountImport, 220 Name: "import", 221 Usage: "import a private key into a new account", 222 Description: ` 223 224 ethereum account import <keyfile> 225 226 Imports an unencrypted private key from <keyfile> and creates a new account. 227 Prints the address. 228 229 The keyfile is assumed to contain an unencrypted private key in hexadecimal format. 230 231 The account is saved in encrypted format, you are prompted for a passphrase. 232 233 You must remember this passphrase to unlock your account in the future. 234 235 For non-interactive use the passphrase can be specified with the -password flag: 236 237 ethereum --password <passwordfile> account import <keyfile> 238 239 Note: 240 As you can directly copy your encrypted accounts to another ethereum instance, 241 this import mechanism is not needed when you transfer an account between 242 nodes. 243 `, 244 }, 245 }, 246 }, 247 { 248 Action: console, 249 Name: "console", 250 Usage: `Geth Console: interactive JavaScript environment`, 251 Description: ` 252 The Geth console is an interactive shell for the JavaScript runtime environment 253 which exposes a node admin interface as well as the Ðapp JavaScript API. 254 See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console 255 `}, 256 { 257 Action: attach, 258 Name: "attach", 259 Usage: `Geth Console: interactive JavaScript environment (connect to node)`, 260 Description: ` 261 The Geth console is an interactive shell for the JavaScript runtime environment 262 which exposes a node admin interface as well as the Ðapp JavaScript API. 263 See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console. 264 This command allows to open a console on a running geth node. 265 `, 266 }, 267 { 268 Action: execJSFiles, 269 Name: "js", 270 Usage: `executes the given JavaScript files in the Geth JavaScript VM`, 271 Description: ` 272 The JavaScript VM exposes a node admin interface as well as the Ðapp 273 JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console 274 `, 275 }, 276 } 277 app.Flags = []cli.Flag{ 278 utils.IdentityFlag, 279 utils.UnlockedAccountFlag, 280 utils.PasswordFileFlag, 281 utils.GenesisFileFlag, 282 utils.BootnodesFlag, 283 utils.DataDirFlag, 284 utils.BlockchainVersionFlag, 285 utils.OlympicFlag, 286 utils.CacheFlag, 287 utils.JSpathFlag, 288 utils.ListenPortFlag, 289 utils.MaxPeersFlag, 290 utils.MaxPendingPeersFlag, 291 utils.EtherbaseFlag, 292 utils.GasPriceFlag, 293 utils.MinerThreadsFlag, 294 utils.MiningEnabledFlag, 295 utils.AutoDAGFlag, 296 utils.NATFlag, 297 utils.NatspecEnabledFlag, 298 utils.NoDiscoverFlag, 299 utils.NodeKeyFileFlag, 300 utils.NodeKeyHexFlag, 301 utils.RPCEnabledFlag, 302 utils.RPCListenAddrFlag, 303 utils.RPCPortFlag, 304 utils.RpcApiFlag, 305 utils.IPCDisabledFlag, 306 utils.IPCApiFlag, 307 utils.IPCPathFlag, 308 utils.ExecFlag, 309 utils.WhisperEnabledFlag, 310 utils.VMDebugFlag, 311 utils.VMForceJitFlag, 312 utils.VMJitCacheFlag, 313 utils.VMEnableJitFlag, 314 utils.NetworkIdFlag, 315 utils.RPCCORSDomainFlag, 316 utils.VerbosityFlag, 317 utils.BacktraceAtFlag, 318 utils.LogToStdErrFlag, 319 utils.LogVModuleFlag, 320 utils.LogFileFlag, 321 utils.LogJSONFlag, 322 utils.PProfEanbledFlag, 323 utils.PProfPortFlag, 324 utils.MetricsEnabledFlag, 325 utils.SolcPathFlag, 326 utils.GpoMinGasPriceFlag, 327 utils.GpoMaxGasPriceFlag, 328 utils.GpoFullBlockRatioFlag, 329 utils.GpobaseStepDownFlag, 330 utils.GpobaseStepUpFlag, 331 utils.GpobaseCorrectionFactorFlag, 332 } 333 app.Before = func(ctx *cli.Context) error { 334 utils.SetupLogger(ctx) 335 utils.SetupVM(ctx) 336 if ctx.GlobalBool(utils.PProfEanbledFlag.Name) { 337 utils.StartPProf(ctx) 338 } 339 return nil 340 } 341 // Start system runtime metrics collection 342 go metrics.CollectProcessMetrics(3 * time.Second) 343 } 344 345 func main() { 346 runtime.GOMAXPROCS(runtime.NumCPU()) 347 defer logger.Flush() 348 if err := app.Run(os.Args); err != nil { 349 fmt.Fprintln(os.Stderr, err) 350 os.Exit(1) 351 } 352 } 353 354 func makeDefaultExtra() []byte { 355 var clientInfo = struct { 356 Version uint 357 Name string 358 GoVersion string 359 Os string 360 }{uint(VersionMajor<<16 | VersionMinor<<8 | VersionPatch), ClientIdentifier, runtime.Version(), runtime.GOOS} 361 extra, err := rlp.EncodeToBytes(clientInfo) 362 if err != nil { 363 glog.V(logger.Warn).Infoln("error setting canonical miner information:", err) 364 } 365 366 if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() { 367 glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize) 368 glog.V(logger.Debug).Infof("extra: %x\n", extra) 369 return nil 370 } 371 372 return extra 373 } 374 375 func run(ctx *cli.Context) { 376 utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) 377 if ctx.GlobalBool(utils.OlympicFlag.Name) { 378 utils.InitOlympic() 379 } 380 381 cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) 382 cfg.ExtraData = makeDefaultExtra() 383 384 ethereum, err := eth.New(cfg) 385 if err != nil { 386 utils.Fatalf("%v", err) 387 } 388 389 startEth(ctx, ethereum) 390 // this blocks the thread 391 ethereum.WaitForShutdown() 392 } 393 394 func attach(ctx *cli.Context) { 395 utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) 396 397 var client comms.EthereumClient 398 var err error 399 if ctx.Args().Present() { 400 client, err = comms.ClientFromEndpoint(ctx.Args().First(), codec.JSON) 401 } else { 402 cfg := comms.IpcConfig{ 403 Endpoint: ctx.GlobalString(utils.IPCPathFlag.Name), 404 } 405 client, err = comms.NewIpcClient(cfg, codec.JSON) 406 } 407 408 if err != nil { 409 utils.Fatalf("Unable to attach to geth node - %v", err) 410 } 411 412 repl := newLightweightJSRE( 413 ctx.GlobalString(utils.JSpathFlag.Name), 414 client, 415 true, 416 ) 417 418 if ctx.GlobalString(utils.ExecFlag.Name) != "" { 419 repl.batch(ctx.GlobalString(utils.ExecFlag.Name)) 420 } else { 421 repl.welcome() 422 repl.interactive() 423 } 424 } 425 426 func console(ctx *cli.Context) { 427 utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) 428 429 cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) 430 ethereum, err := eth.New(cfg) 431 if err != nil { 432 utils.Fatalf("%v", err) 433 } 434 435 client := comms.NewInProcClient(codec.JSON) 436 437 startEth(ctx, ethereum) 438 repl := newJSRE( 439 ethereum, 440 ctx.GlobalString(utils.JSpathFlag.Name), 441 ctx.GlobalString(utils.RPCCORSDomainFlag.Name), 442 client, 443 true, 444 nil, 445 ) 446 447 if ctx.GlobalString(utils.ExecFlag.Name) != "" { 448 repl.batch(ctx.GlobalString(utils.ExecFlag.Name)) 449 } else { 450 repl.welcome() 451 repl.interactive() 452 } 453 454 ethereum.Stop() 455 ethereum.WaitForShutdown() 456 } 457 458 func execJSFiles(ctx *cli.Context) { 459 utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) 460 461 cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) 462 ethereum, err := eth.New(cfg) 463 if err != nil { 464 utils.Fatalf("%v", err) 465 } 466 467 client := comms.NewInProcClient(codec.JSON) 468 startEth(ctx, ethereum) 469 repl := newJSRE( 470 ethereum, 471 ctx.GlobalString(utils.JSpathFlag.Name), 472 ctx.GlobalString(utils.RPCCORSDomainFlag.Name), 473 client, 474 false, 475 nil, 476 ) 477 for _, file := range ctx.Args() { 478 repl.exec(file) 479 } 480 481 ethereum.Stop() 482 ethereum.WaitForShutdown() 483 } 484 485 func unlockAccount(ctx *cli.Context, am *accounts.Manager, addr string, i int) (addrHex, auth string) { 486 utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) 487 488 var err error 489 addrHex, err = utils.ParamToAddress(addr, am) 490 if err == nil { 491 // Attempt to unlock the account 3 times 492 attempts := 3 493 for tries := 0; tries < attempts; tries++ { 494 msg := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", addr, tries+1, attempts) 495 auth = getPassPhrase(ctx, msg, false, i) 496 err = am.Unlock(common.HexToAddress(addrHex), auth) 497 if err == nil { 498 break 499 } 500 } 501 } 502 503 if err != nil { 504 utils.Fatalf("Unlock account failed '%v'", err) 505 } 506 fmt.Printf("Account '%s' unlocked.\n", addr) 507 return 508 } 509 510 func blockRecovery(ctx *cli.Context) { 511 utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) 512 513 arg := ctx.Args().First() 514 if len(ctx.Args()) < 1 && len(arg) > 0 { 515 glog.Fatal("recover requires block number or hash") 516 } 517 518 cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) 519 utils.CheckLegalese(cfg.DataDir) 520 521 blockDb, err := ethdb.NewLDBDatabase(filepath.Join(cfg.DataDir, "blockchain"), cfg.DatabaseCache) 522 if err != nil { 523 glog.Fatalln("could not open db:", err) 524 } 525 526 var block *types.Block 527 if arg[0] == '#' { 528 block = core.GetBlockByNumber(blockDb, common.String2Big(arg[1:]).Uint64()) 529 } else { 530 block = core.GetBlockByHash(blockDb, common.HexToHash(arg)) 531 } 532 533 if block == nil { 534 glog.Fatalln("block not found. Recovery failed") 535 } 536 537 err = core.WriteHead(blockDb, block) 538 if err != nil { 539 glog.Fatalln("block write err", err) 540 } 541 glog.Infof("Recovery succesful. New HEAD %x\n", block.Hash()) 542 } 543 544 func startEth(ctx *cli.Context, eth *eth.Ethereum) { 545 // Start Ethereum itself 546 utils.StartEthereum(eth) 547 548 am := eth.AccountManager() 549 account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) 550 accounts := strings.Split(account, " ") 551 for i, account := range accounts { 552 if len(account) > 0 { 553 if account == "primary" { 554 utils.Fatalf("the 'primary' keyword is deprecated. You can use integer indexes, but the indexes are not permanent, they can change if you add external keys, export your keys or copy your keystore to another node.") 555 } 556 unlockAccount(ctx, am, account, i) 557 } 558 } 559 // Start auxiliary services if enabled. 560 if !ctx.GlobalBool(utils.IPCDisabledFlag.Name) { 561 if err := utils.StartIPC(eth, ctx); err != nil { 562 utils.Fatalf("Error string IPC: %v", err) 563 } 564 } 565 if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { 566 if err := utils.StartRPC(eth, ctx); err != nil { 567 utils.Fatalf("Error starting RPC: %v", err) 568 } 569 } 570 if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { 571 if err := eth.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name)); err != nil { 572 utils.Fatalf("%v", err) 573 } 574 } 575 } 576 577 func accountList(ctx *cli.Context) { 578 utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) 579 580 am := utils.MakeAccountManager(ctx) 581 accts, err := am.Accounts() 582 if err != nil { 583 utils.Fatalf("Could not list accounts: %v", err) 584 } 585 for i, acct := range accts { 586 fmt.Printf("Account #%d: %x\n", i, acct) 587 } 588 } 589 590 func getPassPhrase(ctx *cli.Context, desc string, confirmation bool, i int) (passphrase string) { 591 passfile := ctx.GlobalString(utils.PasswordFileFlag.Name) 592 if len(passfile) == 0 { 593 fmt.Println(desc) 594 auth, err := utils.PromptPassword("Passphrase: ", true) 595 if err != nil { 596 utils.Fatalf("%v", err) 597 } 598 if confirmation { 599 confirm, err := utils.PromptPassword("Repeat Passphrase: ", false) 600 if err != nil { 601 utils.Fatalf("%v", err) 602 } 603 if auth != confirm { 604 utils.Fatalf("Passphrases did not match.") 605 } 606 } 607 passphrase = auth 608 609 } else { 610 passbytes, err := ioutil.ReadFile(passfile) 611 if err != nil { 612 utils.Fatalf("Unable to read password file '%s': %v", passfile, err) 613 } 614 // this is backwards compatible if the same password unlocks several accounts 615 // it also has the consequence that trailing newlines will not count as part 616 // of the password, so --password <(echo -n 'pass') will now work without -n 617 passphrases := strings.Split(string(passbytes), "\n") 618 if i >= len(passphrases) { 619 passphrase = passphrases[len(passphrases)-1] 620 } else { 621 passphrase = passphrases[i] 622 } 623 } 624 return 625 } 626 627 func accountCreate(ctx *cli.Context) { 628 utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) 629 630 am := utils.MakeAccountManager(ctx) 631 passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0) 632 acct, err := am.NewAccount(passphrase) 633 if err != nil { 634 utils.Fatalf("Could not create the account: %v", err) 635 } 636 fmt.Printf("Address: %x\n", acct) 637 } 638 639 func accountUpdate(ctx *cli.Context) { 640 utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) 641 642 am := utils.MakeAccountManager(ctx) 643 arg := ctx.Args().First() 644 if len(arg) == 0 { 645 utils.Fatalf("account address or index must be given as argument") 646 } 647 648 addr, authFrom := unlockAccount(ctx, am, arg, 0) 649 authTo := getPassPhrase(ctx, "Please give a new password. Do not forget this password.", true, 0) 650 err := am.Update(common.HexToAddress(addr), authFrom, authTo) 651 if err != nil { 652 utils.Fatalf("Could not update the account: %v", err) 653 } 654 } 655 656 func importWallet(ctx *cli.Context) { 657 utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) 658 659 keyfile := ctx.Args().First() 660 if len(keyfile) == 0 { 661 utils.Fatalf("keyfile must be given as argument") 662 } 663 keyJson, err := ioutil.ReadFile(keyfile) 664 if err != nil { 665 utils.Fatalf("Could not read wallet file: %v", err) 666 } 667 668 am := utils.MakeAccountManager(ctx) 669 passphrase := getPassPhrase(ctx, "", false, 0) 670 671 acct, err := am.ImportPreSaleKey(keyJson, passphrase) 672 if err != nil { 673 utils.Fatalf("Could not create the account: %v", err) 674 } 675 fmt.Printf("Address: %x\n", acct) 676 } 677 678 func accountImport(ctx *cli.Context) { 679 utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) 680 681 keyfile := ctx.Args().First() 682 if len(keyfile) == 0 { 683 utils.Fatalf("keyfile must be given as argument") 684 } 685 am := utils.MakeAccountManager(ctx) 686 passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0) 687 acct, err := am.Import(keyfile, passphrase) 688 if err != nil { 689 utils.Fatalf("Could not create the account: %v", err) 690 } 691 fmt.Printf("Address: %x\n", acct) 692 } 693 694 func makedag(ctx *cli.Context) { 695 utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) 696 697 args := ctx.Args() 698 wrongArgs := func() { 699 utils.Fatalf(`Usage: geth makedag <block number> <outputdir>`) 700 } 701 switch { 702 case len(args) == 2: 703 blockNum, err := strconv.ParseUint(args[0], 0, 64) 704 dir := args[1] 705 if err != nil { 706 wrongArgs() 707 } else { 708 dir = filepath.Clean(dir) 709 // seems to require a trailing slash 710 if !strings.HasSuffix(dir, "/") { 711 dir = dir + "/" 712 } 713 _, err = ioutil.ReadDir(dir) 714 if err != nil { 715 utils.Fatalf("Can't find dir") 716 } 717 fmt.Println("making DAG, this could take awhile...") 718 ethash.MakeDAG(blockNum, dir) 719 } 720 default: 721 wrongArgs() 722 } 723 } 724 725 func version(c *cli.Context) { 726 fmt.Println(ClientIdentifier) 727 fmt.Println("Version:", Version) 728 if gitCommit != "" { 729 fmt.Println("Git Commit:", gitCommit) 730 } 731 fmt.Println("Protocol Versions:", eth.ProtocolVersions) 732 fmt.Println("Network Id:", c.GlobalInt(utils.NetworkIdFlag.Name)) 733 fmt.Println("Go Version:", runtime.Version()) 734 fmt.Println("OS:", runtime.GOOS) 735 fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH")) 736 fmt.Printf("GOROOT=%s\n", runtime.GOROOT()) 737 }