diff options
author | Wei-Ning Huang <w@dexon.org> | 2018-10-24 18:59:48 +0800 |
---|---|---|
committer | Wei-Ning Huang <w@dexon.org> | 2019-04-09 21:32:51 +0800 |
commit | 832edda709e2d6414e417e8e561b9cc83f8f09bb (patch) | |
tree | d797fb233f3fb6758b69d2550440cfad40765e5d /cmd/geth | |
parent | d8b0b71610758cc7d218a012f27071937efff60e (diff) | |
download | go-tangerine-832edda709e2d6414e417e8e561b9cc83f8f09bb.tar go-tangerine-832edda709e2d6414e417e8e561b9cc83f8f09bb.tar.gz go-tangerine-832edda709e2d6414e417e8e561b9cc83f8f09bb.tar.bz2 go-tangerine-832edda709e2d6414e417e8e561b9cc83f8f09bb.tar.lz go-tangerine-832edda709e2d6414e417e8e561b9cc83f8f09bb.tar.xz go-tangerine-832edda709e2d6414e417e8e561b9cc83f8f09bb.tar.zst go-tangerine-832edda709e2d6414e417e8e561b9cc83f8f09bb.zip |
Rename geth -> gdex and fix Dockerfile
Diffstat (limited to 'cmd/geth')
-rw-r--r-- | cmd/geth/accountcmd.go | 379 | ||||
-rw-r--r-- | cmd/geth/accountcmd_test.go | 296 | ||||
-rw-r--r-- | cmd/geth/bugcmd.go | 113 | ||||
-rw-r--r-- | cmd/geth/chaincmd.go | 471 | ||||
-rw-r--r-- | cmd/geth/config.go | 210 | ||||
-rw-r--r-- | cmd/geth/consolecmd.go | 218 | ||||
-rw-r--r-- | cmd/geth/consolecmd_test.go | 163 | ||||
-rw-r--r-- | cmd/geth/dao_test.go | 152 | ||||
-rw-r--r-- | cmd/geth/genesis_test.go | 110 | ||||
-rw-r--r-- | cmd/geth/main.go | 373 | ||||
-rw-r--r-- | cmd/geth/misccmd.go | 139 | ||||
-rw-r--r-- | cmd/geth/monitorcmd.go | 351 | ||||
-rw-r--r-- | cmd/geth/run_test.go | 98 | ||||
-rw-r--r-- | cmd/geth/testdata/empty.js | 1 | ||||
-rw-r--r-- | cmd/geth/testdata/guswallet.json | 6 | ||||
-rw-r--r-- | cmd/geth/testdata/passwords.txt | 3 | ||||
-rw-r--r-- | cmd/geth/testdata/wrong-passwords.txt | 3 | ||||
-rw-r--r-- | cmd/geth/usage.go | 360 |
18 files changed, 0 insertions, 3446 deletions
diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go deleted file mode 100644 index bf6d9140d..000000000 --- a/cmd/geth/accountcmd.go +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -package main - -import ( - "fmt" - "io/ioutil" - - "github.com/dexon-foundation/dexon/accounts" - "github.com/dexon-foundation/dexon/accounts/keystore" - "github.com/dexon-foundation/dexon/cmd/utils" - "github.com/dexon-foundation/dexon/console" - "github.com/dexon-foundation/dexon/crypto" - "github.com/dexon-foundation/dexon/log" - "gopkg.in/urfave/cli.v1" -) - -var ( - walletCommand = cli.Command{ - Name: "wallet", - Usage: "Manage Ethereum presale wallets", - ArgsUsage: "", - Category: "ACCOUNT COMMANDS", - Description: ` - geth wallet import /path/to/my/presale.wallet - -will prompt for your password and imports your ether presale account. -It can be used non-interactively with the --password option taking a -passwordfile as argument containing the wallet password in plaintext.`, - Subcommands: []cli.Command{ - { - - Name: "import", - Usage: "Import Ethereum presale wallet", - ArgsUsage: "<keyFile>", - Action: utils.MigrateFlags(importWallet), - Category: "ACCOUNT COMMANDS", - Flags: []cli.Flag{ - utils.DataDirFlag, - utils.KeyStoreDirFlag, - utils.PasswordFileFlag, - utils.LightKDFFlag, - }, - Description: ` - geth wallet [options] /path/to/my/presale.wallet - -will prompt for your password and imports your ether presale account. -It can be used non-interactively with the --password option taking a -passwordfile as argument containing the wallet password in plaintext.`, - }, - }, - } - - accountCommand = cli.Command{ - Name: "account", - Usage: "Manage accounts", - Category: "ACCOUNT COMMANDS", - Description: ` - -Manage accounts, list all existing accounts, import a private key into a new -account, create a new account or update an existing account. - -It supports interactive mode, when you are prompted for password as well as -non-interactive mode where passwords are supplied via a given password file. -Non-interactive mode is only meant for scripted use on test networks or known -safe environments. - -Make sure you remember the password you gave when creating a new account (with -either new or import). Without it you are not able to unlock your account. - -Note that exporting your key in unencrypted format is NOT supported. - -Keys are stored under <DATADIR>/keystore. -It is safe to transfer the entire directory or the individual keys therein -between ethereum nodes by simply copying. - -Make sure you backup your keys regularly.`, - Subcommands: []cli.Command{ - { - Name: "list", - Usage: "Print summary of existing accounts", - Action: utils.MigrateFlags(accountList), - Flags: []cli.Flag{ - utils.DataDirFlag, - utils.KeyStoreDirFlag, - }, - Description: ` -Print a short summary of all accounts`, - }, - { - Name: "new", - Usage: "Create a new account", - Action: utils.MigrateFlags(accountCreate), - Flags: []cli.Flag{ - utils.DataDirFlag, - utils.KeyStoreDirFlag, - utils.PasswordFileFlag, - utils.LightKDFFlag, - }, - Description: ` - geth account new - -Creates a new account and prints the address. - -The account is saved in encrypted format, you are prompted for a passphrase. - -You must remember this passphrase to unlock your account in the future. - -For non-interactive use the passphrase can be specified with the --password flag: - -Note, this is meant to be used for testing only, it is a bad idea to save your -password to file or expose in any other way. -`, - }, - { - Name: "update", - Usage: "Update an existing account", - Action: utils.MigrateFlags(accountUpdate), - ArgsUsage: "<address>", - Flags: []cli.Flag{ - utils.DataDirFlag, - utils.KeyStoreDirFlag, - utils.LightKDFFlag, - }, - Description: ` - geth account update <address> - -Update an existing account. - -The account is saved in the newest version in encrypted format, you are prompted -for a passphrase to unlock the account and another to save the updated file. - -This same command can therefore be used to migrate an account of a deprecated -format to the newest format or change the password for an account. - -For non-interactive use the passphrase can be specified with the --password flag: - - geth account update [options] <address> - -Since only one password can be given, only format update can be performed, -changing your password is only possible interactively. -`, - }, - { - Name: "import", - Usage: "Import a private key into a new account", - Action: utils.MigrateFlags(accountImport), - Flags: []cli.Flag{ - utils.DataDirFlag, - utils.KeyStoreDirFlag, - utils.PasswordFileFlag, - utils.LightKDFFlag, - }, - ArgsUsage: "<keyFile>", - Description: ` - geth account import <keyfile> - -Imports an unencrypted private key from <keyfile> and creates a new account. -Prints the address. - -The keyfile is assumed to contain an unencrypted private key in hexadecimal format. - -The account is saved in encrypted format, you are prompted for a passphrase. - -You must remember this passphrase to unlock your account in the future. - -For non-interactive use the passphrase can be specified with the -password flag: - - geth account import [options] <keyfile> - -Note: -As you can directly copy your encrypted accounts to another ethereum instance, -this import mechanism is not needed when you transfer an account between -nodes. -`, - }, - }, - } -) - -func accountList(ctx *cli.Context) error { - stack, _ := makeConfigNode(ctx) - var index int - for _, wallet := range stack.AccountManager().Wallets() { - for _, account := range wallet.Accounts() { - fmt.Printf("Account #%d: {%x} %s\n", index, account.Address, &account.URL) - index++ - } - } - return nil -} - -// tries unlocking the specified account a few times. -func unlockAccount(ctx *cli.Context, ks *keystore.KeyStore, address string, i int, passwords []string) (accounts.Account, string) { - account, err := utils.MakeAddress(ks, address) - if err != nil { - utils.Fatalf("Could not list accounts: %v", err) - } - for trials := 0; trials < 3; trials++ { - prompt := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", address, trials+1, 3) - password := getPassPhrase(prompt, false, i, passwords) - err = ks.Unlock(account, password) - if err == nil { - log.Info("Unlocked account", "address", account.Address.Hex()) - return account, password - } - if err, ok := err.(*keystore.AmbiguousAddrError); ok { - log.Info("Unlocked account", "address", account.Address.Hex()) - return ambiguousAddrRecovery(ks, err, password), password - } - if err != keystore.ErrDecrypt { - // No need to prompt again if the error is not decryption-related. - break - } - } - // All trials expended to unlock account, bail out - utils.Fatalf("Failed to unlock account %s (%v)", address, err) - - return accounts.Account{}, "" -} - -// getPassPhrase retrieves the password associated with an account, either fetched -// from a list of preloaded passphrases, or requested interactively from the user. -func getPassPhrase(prompt string, confirmation bool, i int, passwords []string) string { - // If a list of passwords was supplied, retrieve from them - if len(passwords) > 0 { - if i < len(passwords) { - return passwords[i] - } - return passwords[len(passwords)-1] - } - // Otherwise prompt the user for the password - if prompt != "" { - fmt.Println(prompt) - } - password, err := console.Stdin.PromptPassword("Passphrase: ") - if err != nil { - utils.Fatalf("Failed to read passphrase: %v", err) - } - if confirmation { - confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ") - if err != nil { - utils.Fatalf("Failed to read passphrase confirmation: %v", err) - } - if password != confirm { - utils.Fatalf("Passphrases do not match") - } - } - return password -} - -func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrError, auth string) accounts.Account { - fmt.Printf("Multiple key files exist for address %x:\n", err.Addr) - for _, a := range err.Matches { - fmt.Println(" ", a.URL) - } - fmt.Println("Testing your passphrase against all of them...") - var match *accounts.Account - for _, a := range err.Matches { - if err := ks.Unlock(a, auth); err == nil { - match = &a - break - } - } - if match == nil { - utils.Fatalf("None of the listed files could be unlocked.") - } - fmt.Printf("Your passphrase unlocked %s\n", match.URL) - fmt.Println("In order to avoid this warning, you need to remove the following duplicate key files:") - for _, a := range err.Matches { - if a != *match { - fmt.Println(" ", a.URL) - } - } - return *match -} - -// accountCreate creates a new account into the keystore defined by the CLI flags. -func accountCreate(ctx *cli.Context) error { - cfg := gethConfig{Node: defaultNodeConfig()} - // Load config file. - if file := ctx.GlobalString(configFileFlag.Name); file != "" { - if err := loadConfig(file, &cfg); err != nil { - utils.Fatalf("%v", err) - } - } - utils.SetNodeConfig(ctx, &cfg.Node) - scryptN, scryptP, keydir, err := cfg.Node.AccountConfig() - - if err != nil { - utils.Fatalf("Failed to read configuration: %v", err) - } - - password := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) - - address, err := keystore.StoreKey(keydir, password, scryptN, scryptP) - - if err != nil { - utils.Fatalf("Failed to create account: %v", err) - } - fmt.Printf("Address: {%x}\n", address) - return nil -} - -// accountUpdate transitions an account from a previous format to the current -// one, also providing the possibility to change the pass-phrase. -func accountUpdate(ctx *cli.Context) error { - if len(ctx.Args()) == 0 { - utils.Fatalf("No accounts specified to update") - } - stack, _ := makeConfigNode(ctx) - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) - - for _, addr := range ctx.Args() { - account, oldPassword := unlockAccount(ctx, ks, addr, 0, nil) - newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil) - if err := ks.Update(account, oldPassword, newPassword); err != nil { - utils.Fatalf("Could not update the account: %v", err) - } - } - return nil -} - -func importWallet(ctx *cli.Context) error { - keyfile := ctx.Args().First() - if len(keyfile) == 0 { - utils.Fatalf("keyfile must be given as argument") - } - keyJSON, err := ioutil.ReadFile(keyfile) - if err != nil { - utils.Fatalf("Could not read wallet file: %v", err) - } - - stack, _ := makeConfigNode(ctx) - passphrase := getPassPhrase("", false, 0, utils.MakePasswordList(ctx)) - - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) - acct, err := ks.ImportPreSaleKey(keyJSON, passphrase) - if err != nil { - utils.Fatalf("%v", err) - } - fmt.Printf("Address: {%x}\n", acct.Address) - return nil -} - -func accountImport(ctx *cli.Context) error { - keyfile := ctx.Args().First() - if len(keyfile) == 0 { - utils.Fatalf("keyfile must be given as argument") - } - key, err := crypto.LoadECDSA(keyfile) - if err != nil { - utils.Fatalf("Failed to load the private key: %v", err) - } - stack, _ := makeConfigNode(ctx) - passphrase := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) - - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) - acct, err := ks.ImportECDSA(key, passphrase) - if err != nil { - utils.Fatalf("Could not create the account: %v", err) - } - fmt.Printf("Address: {%x}\n", acct.Address) - return nil -} diff --git a/cmd/geth/accountcmd_test.go b/cmd/geth/accountcmd_test.go deleted file mode 100644 index c9983a219..000000000 --- a/cmd/geth/accountcmd_test.go +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -package main - -import ( - "io/ioutil" - "path/filepath" - "runtime" - "strings" - "testing" - - "github.com/cespare/cp" -) - -// These tests are 'smoke tests' for the account related -// subcommands and flags. -// -// For most tests, the test files from package accounts -// are copied into a temporary keystore directory. - -func tmpDatadirWithKeystore(t *testing.T) string { - datadir := tmpdir(t) - keystore := filepath.Join(datadir, "keystore") - source := filepath.Join("..", "..", "accounts", "keystore", "testdata", "keystore") - if err := cp.CopyAll(keystore, source); err != nil { - t.Fatal(err) - } - return datadir -} - -func TestAccountListEmpty(t *testing.T) { - geth := runGeth(t, "account", "list") - geth.ExpectExit() -} - -func TestAccountList(t *testing.T) { - datadir := tmpDatadirWithKeystore(t) - geth := runGeth(t, "account", "list", "--datadir", datadir) - defer geth.ExpectExit() - if runtime.GOOS == "windows" { - geth.Expect(` -Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}\keystore\UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8 -Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}\keystore\aaa -Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}\keystore\zzz -`) - } else { - geth.Expect(` -Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}/keystore/UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8 -Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}/keystore/aaa -Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/keystore/zzz -`) - } -} - -func TestAccountNew(t *testing.T) { - geth := runGeth(t, "account", "new", "--lightkdf") - defer geth.ExpectExit() - geth.Expect(` -Your new account is locked with a password. Please give a password. Do not forget this password. -!! Unsupported terminal, password will be echoed. -Passphrase: {{.InputLine "foobar"}} -Repeat passphrase: {{.InputLine "foobar"}} -`) - geth.ExpectRegexp(`Address: \{[0-9a-f]{40}\}\n`) -} - -func TestAccountNewBadRepeat(t *testing.T) { - geth := runGeth(t, "account", "new", "--lightkdf") - defer geth.ExpectExit() - geth.Expect(` -Your new account is locked with a password. Please give a password. Do not forget this password. -!! Unsupported terminal, password will be echoed. -Passphrase: {{.InputLine "something"}} -Repeat passphrase: {{.InputLine "something else"}} -Fatal: Passphrases do not match -`) -} - -func TestAccountUpdate(t *testing.T) { - datadir := tmpDatadirWithKeystore(t) - geth := runGeth(t, "account", "update", - "--datadir", datadir, "--lightkdf", - "f466859ead1932d743d622cb74fc058882e8648a") - defer geth.ExpectExit() - geth.Expect(` -Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 -!! Unsupported terminal, password will be echoed. -Passphrase: {{.InputLine "foobar"}} -Please give a new password. Do not forget this password. -Passphrase: {{.InputLine "foobar2"}} -Repeat passphrase: {{.InputLine "foobar2"}} -`) -} - -func TestWalletImport(t *testing.T) { - geth := runGeth(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json") - defer geth.ExpectExit() - geth.Expect(` -!! Unsupported terminal, password will be echoed. -Passphrase: {{.InputLine "foo"}} -Address: {d4584b5f6229b7be90727b0fc8c6b91bb427821f} -`) - - files, err := ioutil.ReadDir(filepath.Join(geth.Datadir, "keystore")) - if len(files) != 1 { - t.Errorf("expected one key file in keystore directory, found %d files (error: %v)", len(files), err) - } -} - -func TestWalletImportBadPassword(t *testing.T) { - geth := runGeth(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json") - defer geth.ExpectExit() - geth.Expect(` -!! Unsupported terminal, password will be echoed. -Passphrase: {{.InputLine "wrong"}} -Fatal: could not decrypt key with given passphrase -`) -} - -func TestUnlockFlag(t *testing.T) { - datadir := tmpDatadirWithKeystore(t) - geth := runGeth(t, - "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0", - "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", - "js", "testdata/empty.js") - geth.Expect(` -Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 -!! Unsupported terminal, password will be echoed. -Passphrase: {{.InputLine "foobar"}} -`) - geth.ExpectExit() - - wantMessages := []string{ - "Unlocked account", - "=0xf466859eAD1932D743d622CB74FC058882E8648A", - } - for _, m := range wantMessages { - if !strings.Contains(geth.StderrText(), m) { - t.Errorf("stderr text does not contain %q", m) - } - } -} - -func TestUnlockFlagWrongPassword(t *testing.T) { - datadir := tmpDatadirWithKeystore(t) - geth := runGeth(t, - "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0", - "--unlock", "f466859ead1932d743d622cb74fc058882e8648a") - defer geth.ExpectExit() - geth.Expect(` -Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 -!! Unsupported terminal, password will be echoed. -Passphrase: {{.InputLine "wrong1"}} -Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 2/3 -Passphrase: {{.InputLine "wrong2"}} -Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 3/3 -Passphrase: {{.InputLine "wrong3"}} -Fatal: Failed to unlock account f466859ead1932d743d622cb74fc058882e8648a (could not decrypt key with given passphrase) -`) -} - -// https://github.com/dexon-foundation/dexon/issues/1785 -func TestUnlockFlagMultiIndex(t *testing.T) { - datadir := tmpDatadirWithKeystore(t) - geth := runGeth(t, - "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0", - "--unlock", "0,2", - "js", "testdata/empty.js") - geth.Expect(` -Unlocking account 0 | Attempt 1/3 -!! Unsupported terminal, password will be echoed. -Passphrase: {{.InputLine "foobar"}} -Unlocking account 2 | Attempt 1/3 -Passphrase: {{.InputLine "foobar"}} -`) - geth.ExpectExit() - - wantMessages := []string{ - "Unlocked account", - "=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", - "=0x289d485D9771714CCe91D3393D764E1311907ACc", - } - for _, m := range wantMessages { - if !strings.Contains(geth.StderrText(), m) { - t.Errorf("stderr text does not contain %q", m) - } - } -} - -func TestUnlockFlagPasswordFile(t *testing.T) { - datadir := tmpDatadirWithKeystore(t) - geth := runGeth(t, - "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0", - "--password", "testdata/passwords.txt", "--unlock", "0,2", - "js", "testdata/empty.js") - geth.ExpectExit() - - wantMessages := []string{ - "Unlocked account", - "=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", - "=0x289d485D9771714CCe91D3393D764E1311907ACc", - } - for _, m := range wantMessages { - if !strings.Contains(geth.StderrText(), m) { - t.Errorf("stderr text does not contain %q", m) - } - } -} - -func TestUnlockFlagPasswordFileWrongPassword(t *testing.T) { - datadir := tmpDatadirWithKeystore(t) - geth := runGeth(t, - "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0", - "--password", "testdata/wrong-passwords.txt", "--unlock", "0,2") - defer geth.ExpectExit() - geth.Expect(` -Fatal: Failed to unlock account 0 (could not decrypt key with given passphrase) -`) -} - -func TestUnlockFlagAmbiguous(t *testing.T) { - store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes") - geth := runGeth(t, - "--keystore", store, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0", - "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", - "js", "testdata/empty.js") - defer geth.ExpectExit() - - // Helper for the expect template, returns absolute keystore path. - geth.SetTemplateFunc("keypath", func(file string) string { - abs, _ := filepath.Abs(filepath.Join(store, file)) - return abs - }) - geth.Expect(` -Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 -!! Unsupported terminal, password will be echoed. -Passphrase: {{.InputLine "foobar"}} -Multiple key files exist for address f466859ead1932d743d622cb74fc058882e8648a: - keystore://{{keypath "1"}} - keystore://{{keypath "2"}} -Testing your passphrase against all of them... -Your passphrase unlocked keystore://{{keypath "1"}} -In order to avoid this warning, you need to remove the following duplicate key files: - keystore://{{keypath "2"}} -`) - geth.ExpectExit() - - wantMessages := []string{ - "Unlocked account", - "=0xf466859eAD1932D743d622CB74FC058882E8648A", - } - for _, m := range wantMessages { - if !strings.Contains(geth.StderrText(), m) { - t.Errorf("stderr text does not contain %q", m) - } - } -} - -func TestUnlockFlagAmbiguousWrongPassword(t *testing.T) { - store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes") - geth := runGeth(t, - "--keystore", store, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0", - "--unlock", "f466859ead1932d743d622cb74fc058882e8648a") - defer geth.ExpectExit() - - // Helper for the expect template, returns absolute keystore path. - geth.SetTemplateFunc("keypath", func(file string) string { - abs, _ := filepath.Abs(filepath.Join(store, file)) - return abs - }) - geth.Expect(` -Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 -!! Unsupported terminal, password will be echoed. -Passphrase: {{.InputLine "wrong"}} -Multiple key files exist for address f466859ead1932d743d622cb74fc058882e8648a: - keystore://{{keypath "1"}} - keystore://{{keypath "2"}} -Testing your passphrase against all of them... -Fatal: None of the listed files could be unlocked. -`) - geth.ExpectExit() -} diff --git a/cmd/geth/bugcmd.go b/cmd/geth/bugcmd.go deleted file mode 100644 index bb33a0af4..000000000 --- a/cmd/geth/bugcmd.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -package main - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "net/url" - "os/exec" - "runtime" - "strings" - - "github.com/dexon-foundation/dexon/cmd/internal/browser" - "github.com/dexon-foundation/dexon/params" - - "github.com/dexon-foundation/dexon/cmd/utils" - cli "gopkg.in/urfave/cli.v1" -) - -var bugCommand = cli.Command{ - Action: utils.MigrateFlags(reportBug), - Name: "bug", - Usage: "opens a window to report a bug on the geth repo", - ArgsUsage: " ", - Category: "MISCELLANEOUS COMMANDS", -} - -const issueURL = "https://github.com/dexon-foundation/dexon/issues/new" - -// reportBug reports a bug by opening a new URL to the go-ethereum GH issue -// tracker and setting default values as the issue body. -func reportBug(ctx *cli.Context) error { - // execute template and write contents to buff - var buff bytes.Buffer - - fmt.Fprintln(&buff, "#### System information") - fmt.Fprintln(&buff) - fmt.Fprintln(&buff, "Version:", params.VersionWithMeta) - fmt.Fprintln(&buff, "Go Version:", runtime.Version()) - fmt.Fprintln(&buff, "OS:", runtime.GOOS) - printOSDetails(&buff) - fmt.Fprintln(&buff, header) - - // open a new GH issue - if !browser.Open(issueURL + "?body=" + url.QueryEscape(buff.String())) { - fmt.Printf("Please file a new issue at %s using this template:\n\n%s", issueURL, buff.String()) - } - return nil -} - -// copied from the Go source. Copyright 2017 The Go Authors -func printOSDetails(w io.Writer) { - switch runtime.GOOS { - case "darwin": - printCmdOut(w, "uname -v: ", "uname", "-v") - printCmdOut(w, "", "sw_vers") - case "linux": - printCmdOut(w, "uname -sr: ", "uname", "-sr") - printCmdOut(w, "", "lsb_release", "-a") - case "openbsd", "netbsd", "freebsd", "dragonfly": - printCmdOut(w, "uname -v: ", "uname", "-v") - case "solaris": - out, err := ioutil.ReadFile("/etc/release") - if err == nil { - fmt.Fprintf(w, "/etc/release: %s\n", out) - } else { - fmt.Printf("failed to read /etc/release: %v\n", err) - } - } -} - -// printCmdOut prints the output of running the given command. -// It ignores failures; 'go bug' is best effort. -// -// copied from the Go source. Copyright 2017 The Go Authors -func printCmdOut(w io.Writer, prefix, path string, args ...string) { - cmd := exec.Command(path, args...) - out, err := cmd.Output() - if err != nil { - fmt.Printf("%s %s: %v\n", path, strings.Join(args, " "), err) - return - } - fmt.Fprintf(w, "%s%s\n", prefix, bytes.TrimSpace(out)) -} - -const header = ` -#### Expected behaviour - - -#### Actual behaviour - - -#### Steps to reproduce the behaviour - - -#### Backtrace -` diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go deleted file mode 100644 index ce4216a94..000000000 --- a/cmd/geth/chaincmd.go +++ /dev/null @@ -1,471 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -package main - -import ( - "encoding/json" - "fmt" - "os" - "runtime" - "strconv" - "sync/atomic" - "time" - - "github.com/dexon-foundation/dexon/cmd/utils" - "github.com/dexon-foundation/dexon/common" - "github.com/dexon-foundation/dexon/console" - "github.com/dexon-foundation/dexon/core" - "github.com/dexon-foundation/dexon/core/state" - "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/eth/downloader" - "github.com/dexon-foundation/dexon/ethdb" - "github.com/dexon-foundation/dexon/event" - "github.com/dexon-foundation/dexon/log" - "github.com/dexon-foundation/dexon/trie" - "github.com/syndtr/goleveldb/leveldb/util" - "gopkg.in/urfave/cli.v1" -) - -var ( - initCommand = cli.Command{ - Action: utils.MigrateFlags(initGenesis), - Name: "init", - Usage: "Bootstrap and initialize a new genesis block", - ArgsUsage: "<genesisPath>", - Flags: []cli.Flag{ - utils.DataDirFlag, - }, - Category: "BLOCKCHAIN COMMANDS", - Description: ` -The init command initializes a new genesis block and definition for the network. -This is a destructive action and changes the network in which you will be -participating. - -It expects the genesis file as argument.`, - } - importCommand = cli.Command{ - Action: utils.MigrateFlags(importChain), - Name: "import", - Usage: "Import a blockchain file", - ArgsUsage: "<filename> (<filename 2> ... <filename N>) ", - Flags: []cli.Flag{ - utils.DataDirFlag, - utils.CacheFlag, - utils.SyncModeFlag, - utils.GCModeFlag, - utils.CacheDatabaseFlag, - utils.CacheGCFlag, - }, - Category: "BLOCKCHAIN COMMANDS", - Description: ` -The import command imports blocks from an RLP-encoded form. The form can be one file -with several RLP-encoded blocks, or several files can be used. - -If only one file is used, import error will result in failure. If several files are used, -processing will proceed even if an individual RLP-file import failure occurs.`, - } - exportCommand = cli.Command{ - Action: utils.MigrateFlags(exportChain), - Name: "export", - Usage: "Export blockchain into file", - ArgsUsage: "<filename> [<blockNumFirst> <blockNumLast>]", - Flags: []cli.Flag{ - utils.DataDirFlag, - utils.CacheFlag, - utils.SyncModeFlag, - }, - Category: "BLOCKCHAIN COMMANDS", - Description: ` -Requires a first argument of the file to write to. -Optional second and third arguments control the first and -last block to write. In this mode, the file will be appended -if already existing. If the file ends with .gz, the output will -be gzipped.`, - } - importPreimagesCommand = cli.Command{ - Action: utils.MigrateFlags(importPreimages), - Name: "import-preimages", - Usage: "Import the preimage database from an RLP stream", - ArgsUsage: "<datafile>", - Flags: []cli.Flag{ - utils.DataDirFlag, - utils.CacheFlag, - utils.SyncModeFlag, - }, - Category: "BLOCKCHAIN COMMANDS", - Description: ` - The import-preimages command imports hash preimages from an RLP encoded stream.`, - } - exportPreimagesCommand = cli.Command{ - Action: utils.MigrateFlags(exportPreimages), - Name: "export-preimages", - Usage: "Export the preimage database into an RLP stream", - ArgsUsage: "<dumpfile>", - Flags: []cli.Flag{ - utils.DataDirFlag, - utils.CacheFlag, - utils.SyncModeFlag, - }, - Category: "BLOCKCHAIN COMMANDS", - Description: ` -The export-preimages command export hash preimages to an RLP encoded stream`, - } - copydbCommand = cli.Command{ - Action: utils.MigrateFlags(copyDb), - Name: "copydb", - Usage: "Create a local chain from a target chaindata folder", - ArgsUsage: "<sourceChaindataDir>", - Flags: []cli.Flag{ - utils.DataDirFlag, - utils.CacheFlag, - utils.SyncModeFlag, - utils.FakePoWFlag, - utils.TestnetFlag, - }, - Category: "BLOCKCHAIN COMMANDS", - Description: ` -The first argument must be the directory containing the blockchain to download from`, - } - removedbCommand = cli.Command{ - Action: utils.MigrateFlags(removeDB), - Name: "removedb", - Usage: "Remove blockchain and state databases", - ArgsUsage: " ", - Flags: []cli.Flag{ - utils.DataDirFlag, - }, - Category: "BLOCKCHAIN COMMANDS", - Description: ` -Remove blockchain and state databases`, - } - dumpCommand = cli.Command{ - Action: utils.MigrateFlags(dump), - Name: "dump", - Usage: "Dump a specific block from storage", - ArgsUsage: "[<blockHash> | <blockNum>]...", - Flags: []cli.Flag{ - utils.DataDirFlag, - utils.CacheFlag, - utils.SyncModeFlag, - }, - Category: "BLOCKCHAIN COMMANDS", - Description: ` -The arguments are interpreted as block numbers or hashes. -Use "ethereum dump 0" to dump the genesis block.`, - } -) - -// initGenesis will initialise the given JSON format genesis file and writes it as -// the zero'd block (i.e. genesis) or will fail hard if it can't succeed. -func initGenesis(ctx *cli.Context) error { - // Make sure we have a valid genesis JSON - genesisPath := ctx.Args().First() - if len(genesisPath) == 0 { - utils.Fatalf("Must supply path to genesis JSON file") - } - file, err := os.Open(genesisPath) - if err != nil { - utils.Fatalf("Failed to read genesis file: %v", err) - } - defer file.Close() - - genesis := new(core.Genesis) - if err := json.NewDecoder(file).Decode(genesis); err != nil { - utils.Fatalf("invalid genesis file: %v", err) - } - // Open an initialise both full and light databases - stack := makeFullNode(ctx) - for _, name := range []string{"chaindata", "lightchaindata"} { - chaindb, err := stack.OpenDatabase(name, 0, 0) - if err != nil { - utils.Fatalf("Failed to open database: %v", err) - } - _, hash, err := core.SetupGenesisBlock(chaindb, genesis) - if err != nil { - utils.Fatalf("Failed to write genesis block: %v", err) - } - log.Info("Successfully wrote genesis state", "database", name, "hash", hash) - } - return nil -} - -func importChain(ctx *cli.Context) error { - if len(ctx.Args()) < 1 { - utils.Fatalf("This command requires an argument.") - } - stack := makeFullNode(ctx) - chain, chainDb := utils.MakeChain(ctx, stack) - defer chainDb.Close() - - // Start periodically gathering memory profiles - var peakMemAlloc, peakMemSys uint64 - go func() { - stats := new(runtime.MemStats) - for { - runtime.ReadMemStats(stats) - if atomic.LoadUint64(&peakMemAlloc) < stats.Alloc { - atomic.StoreUint64(&peakMemAlloc, stats.Alloc) - } - if atomic.LoadUint64(&peakMemSys) < stats.Sys { - atomic.StoreUint64(&peakMemSys, stats.Sys) - } - time.Sleep(5 * time.Second) - } - }() - // Import the chain - start := time.Now() - - if len(ctx.Args()) == 1 { - if err := utils.ImportChain(chain, ctx.Args().First()); err != nil { - log.Error("Import error", "err", err) - } - } else { - for _, arg := range ctx.Args() { - if err := utils.ImportChain(chain, arg); err != nil { - log.Error("Import error", "file", arg, "err", err) - } - } - } - chain.Stop() - fmt.Printf("Import done in %v.\n\n", time.Since(start)) - - // Output pre-compaction stats mostly to see the import trashing - db := chainDb.(*ethdb.LDBDatabase) - - stats, err := db.LDB().GetProperty("leveldb.stats") - if err != nil { - utils.Fatalf("Failed to read database stats: %v", err) - } - fmt.Println(stats) - - ioStats, err := db.LDB().GetProperty("leveldb.iostats") - if err != nil { - utils.Fatalf("Failed to read database iostats: %v", err) - } - fmt.Println(ioStats) - - fmt.Printf("Trie cache misses: %d\n", trie.CacheMisses()) - fmt.Printf("Trie cache unloads: %d\n\n", trie.CacheUnloads()) - - // Print the memory statistics used by the importing - mem := new(runtime.MemStats) - runtime.ReadMemStats(mem) - - fmt.Printf("Object memory: %.3f MB current, %.3f MB peak\n", float64(mem.Alloc)/1024/1024, float64(atomic.LoadUint64(&peakMemAlloc))/1024/1024) - fmt.Printf("System memory: %.3f MB current, %.3f MB peak\n", float64(mem.Sys)/1024/1024, float64(atomic.LoadUint64(&peakMemSys))/1024/1024) - fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000) - fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs)) - - if ctx.GlobalIsSet(utils.NoCompactionFlag.Name) { - return nil - } - - // Compact the entire database to more accurately measure disk io and print the stats - start = time.Now() - fmt.Println("Compacting entire database...") - if err = db.LDB().CompactRange(util.Range{}); err != nil { - utils.Fatalf("Compaction failed: %v", err) - } - fmt.Printf("Compaction done in %v.\n\n", time.Since(start)) - - stats, err = db.LDB().GetProperty("leveldb.stats") - if err != nil { - utils.Fatalf("Failed to read database stats: %v", err) - } - fmt.Println(stats) - - ioStats, err = db.LDB().GetProperty("leveldb.iostats") - if err != nil { - utils.Fatalf("Failed to read database iostats: %v", err) - } - fmt.Println(ioStats) - - return nil -} - -func exportChain(ctx *cli.Context) error { - if len(ctx.Args()) < 1 { - utils.Fatalf("This command requires an argument.") - } - stack := makeFullNode(ctx) - chain, _ := utils.MakeChain(ctx, stack) - start := time.Now() - - var err error - fp := ctx.Args().First() - if len(ctx.Args()) < 3 { - err = utils.ExportChain(chain, fp) - } else { - // This can be improved to allow for numbers larger than 9223372036854775807 - first, ferr := strconv.ParseInt(ctx.Args().Get(1), 10, 64) - last, lerr := strconv.ParseInt(ctx.Args().Get(2), 10, 64) - if ferr != nil || lerr != nil { - utils.Fatalf("Export error in parsing parameters: block number not an integer\n") - } - if first < 0 || last < 0 { - utils.Fatalf("Export error: block number must be greater than 0\n") - } - err = utils.ExportAppendChain(chain, fp, uint64(first), uint64(last)) - } - - if err != nil { - utils.Fatalf("Export error: %v\n", err) - } - fmt.Printf("Export done in %v\n", time.Since(start)) - return nil -} - -// importPreimages imports preimage data from the specified file. -func importPreimages(ctx *cli.Context) error { - if len(ctx.Args()) < 1 { - utils.Fatalf("This command requires an argument.") - } - stack := makeFullNode(ctx) - diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase) - - start := time.Now() - if err := utils.ImportPreimages(diskdb, ctx.Args().First()); err != nil { - utils.Fatalf("Import error: %v\n", err) - } - fmt.Printf("Import done in %v\n", time.Since(start)) - return nil -} - -// exportPreimages dumps the preimage data to specified json file in streaming way. -func exportPreimages(ctx *cli.Context) error { - if len(ctx.Args()) < 1 { - utils.Fatalf("This command requires an argument.") - } - stack := makeFullNode(ctx) - diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase) - - start := time.Now() - if err := utils.ExportPreimages(diskdb, ctx.Args().First()); err != nil { - utils.Fatalf("Export error: %v\n", err) - } - fmt.Printf("Export done in %v\n", time.Since(start)) - return nil -} - -func copyDb(ctx *cli.Context) error { - // Ensure we have a source chain directory to copy - if len(ctx.Args()) != 1 { - utils.Fatalf("Source chaindata directory path argument missing") - } - // Initialize a new chain for the running node to sync into - stack := makeFullNode(ctx) - chain, chainDb := utils.MakeChain(ctx, stack) - - syncmode := *utils.GlobalTextMarshaler(ctx, utils.SyncModeFlag.Name).(*downloader.SyncMode) - dl := downloader.New(syncmode, chainDb, new(event.TypeMux), chain, nil, nil) - - // Create a source peer to satisfy downloader requests from - db, err := ethdb.NewLDBDatabase(ctx.Args().First(), ctx.GlobalInt(utils.CacheFlag.Name), 256) - if err != nil { - return err - } - hc, err := core.NewHeaderChain(db, chain.Config(), chain.Engine(), func() bool { return false }) - if err != nil { - return err - } - peer := downloader.NewFakePeer("local", db, hc, dl) - if err = dl.RegisterPeer("local", 63, peer); err != nil { - return err - } - // Synchronise with the simulated peer - start := time.Now() - - currentHeader := hc.CurrentHeader() - if err = dl.Synchronise("local", currentHeader.Hash(), hc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64()), syncmode); err != nil { - return err - } - for dl.Synchronising() { - time.Sleep(10 * time.Millisecond) - } - fmt.Printf("Database copy done in %v\n", time.Since(start)) - - // Compact the entire database to remove any sync overhead - start = time.Now() - fmt.Println("Compacting entire database...") - if err = chainDb.(*ethdb.LDBDatabase).LDB().CompactRange(util.Range{}); err != nil { - utils.Fatalf("Compaction failed: %v", err) - } - fmt.Printf("Compaction done in %v.\n\n", time.Since(start)) - - return nil -} - -func removeDB(ctx *cli.Context) error { - stack, _ := makeConfigNode(ctx) - - for _, name := range []string{"chaindata", "lightchaindata"} { - // Ensure the database exists in the first place - logger := log.New("database", name) - - dbdir := stack.ResolvePath(name) - if !common.FileExist(dbdir) { - logger.Info("Database doesn't exist, skipping", "path", dbdir) - continue - } - // Confirm removal and execute - fmt.Println(dbdir) - confirm, err := console.Stdin.PromptConfirm("Remove this database?") - switch { - case err != nil: - utils.Fatalf("%v", err) - case !confirm: - logger.Warn("Database deletion aborted") - default: - start := time.Now() - os.RemoveAll(dbdir) - logger.Info("Database successfully deleted", "elapsed", common.PrettyDuration(time.Since(start))) - } - } - return nil -} - -func dump(ctx *cli.Context) error { - stack := makeFullNode(ctx) - chain, chainDb := utils.MakeChain(ctx, stack) - for _, arg := range ctx.Args() { - var block *types.Block - if hashish(arg) { - block = chain.GetBlockByHash(common.HexToHash(arg)) - } else { - num, _ := strconv.Atoi(arg) - block = chain.GetBlockByNumber(uint64(num)) - } - if block == nil { - fmt.Println("{}") - utils.Fatalf("block not found") - } else { - state, err := state.New(block.Root(), state.NewDatabase(chainDb)) - if err != nil { - utils.Fatalf("could not create new state: %v", err) - } - fmt.Printf("%s\n", state.Dump()) - } - } - chainDb.Close() - return nil -} - -// hashish returns true for strings that look like hashes. -func hashish(x string) bool { - _, err := strconv.Atoi(x) - return err != nil -} diff --git a/cmd/geth/config.go b/cmd/geth/config.go deleted file mode 100644 index d4363c0b4..000000000 --- a/cmd/geth/config.go +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -package main - -import ( - "bufio" - "errors" - "fmt" - "os" - "reflect" - "unicode" - - cli "gopkg.in/urfave/cli.v1" - - "github.com/dexon-foundation/dexon/cmd/utils" - "github.com/dexon-foundation/dexon/dashboard" - "github.com/dexon-foundation/dexon/dex" - "github.com/dexon-foundation/dexon/node" - "github.com/dexon-foundation/dexon/params" - whisper "github.com/dexon-foundation/dexon/whisper/whisperv6" - "github.com/naoina/toml" -) - -var ( - dumpConfigCommand = cli.Command{ - Action: utils.MigrateFlags(dumpConfig), - Name: "dumpconfig", - Usage: "Show configuration values", - ArgsUsage: "", - Flags: append(append(nodeFlags, rpcFlags...), whisperFlags...), - Category: "MISCELLANEOUS COMMANDS", - Description: `The dumpconfig command shows configuration values.`, - } - - configFileFlag = cli.StringFlag{ - Name: "config", - Usage: "TOML configuration file", - } -) - -// These settings ensure that TOML keys use the same names as Go struct fields. -var tomlSettings = toml.Config{ - NormFieldName: func(rt reflect.Type, key string) string { - return key - }, - FieldToKey: func(rt reflect.Type, field string) string { - return field - }, - MissingField: func(rt reflect.Type, field string) error { - link := "" - if unicode.IsUpper(rune(rt.Name()[0])) && rt.PkgPath() != "main" { - link = fmt.Sprintf(", see https://godoc.org/%s#%s for available fields", rt.PkgPath(), rt.Name()) - } - return fmt.Errorf("field '%s' is not defined in %s%s", field, rt.String(), link) - }, -} - -type ethstatsConfig struct { - URL string `toml:",omitempty"` -} - -type gethConfig struct { - Dex dex.Config - Shh whisper.Config - Node node.Config - Ethstats ethstatsConfig - Dashboard dashboard.Config -} - -func loadConfig(file string, cfg *gethConfig) error { - f, err := os.Open(file) - if err != nil { - return err - } - defer f.Close() - - err = tomlSettings.NewDecoder(bufio.NewReader(f)).Decode(cfg) - // Add file name to errors that have a line number. - if _, ok := err.(*toml.LineError); ok { - err = errors.New(file + ", " + err.Error()) - } - return err -} - -func defaultNodeConfig() node.Config { - cfg := node.DefaultConfig - cfg.Name = clientIdentifier - cfg.Version = params.VersionWithCommit(gitCommit) - cfg.HTTPModules = append(cfg.HTTPModules, "eth", "shh") - cfg.WSModules = append(cfg.WSModules, "eth", "shh") - cfg.IPCPath = "geth.ipc" - return cfg -} - -func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { - // Load defaults. - cfg := gethConfig{ - Dex: dex.DefaultConfig, - Shh: whisper.DefaultConfig, - Node: defaultNodeConfig(), - Dashboard: dashboard.DefaultConfig, - } - - // Load config file. - if file := ctx.GlobalString(configFileFlag.Name); file != "" { - if err := loadConfig(file, &cfg); err != nil { - utils.Fatalf("%v", err) - } - } - - // Apply flags. - utils.SetNodeConfig(ctx, &cfg.Node) - stack, err := node.New(&cfg.Node) - if err != nil { - utils.Fatalf("Failed to create the protocol stack: %v", err) - } - utils.SetDexConfig(ctx, stack, &cfg.Dex) - if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) { - cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name) - } - - utils.SetShhConfig(ctx, stack, &cfg.Shh) - utils.SetDashboardConfig(ctx, &cfg.Dashboard) - - return stack, cfg -} - -// enableWhisper returns true in case one of the whisper flags is set. -func enableWhisper(ctx *cli.Context) bool { - for _, flag := range whisperFlags { - if ctx.GlobalIsSet(flag.GetName()) { - return true - } - } - return false -} - -func makeFullNode(ctx *cli.Context) *node.Node { - stack, cfg := makeConfigNode(ctx) - - utils.RegisterDexService(stack, &cfg.Dex) - - if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) { - utils.RegisterDashboardService(stack, &cfg.Dashboard, gitCommit) - } - // Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode - shhEnabled := enableWhisper(ctx) - shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DeveloperFlag.Name) - if shhEnabled || shhAutoEnabled { - if ctx.GlobalIsSet(utils.WhisperMaxMessageSizeFlag.Name) { - cfg.Shh.MaxMessageSize = uint32(ctx.Int(utils.WhisperMaxMessageSizeFlag.Name)) - } - if ctx.GlobalIsSet(utils.WhisperMinPOWFlag.Name) { - cfg.Shh.MinimumAcceptedPOW = ctx.Float64(utils.WhisperMinPOWFlag.Name) - } - if ctx.GlobalIsSet(utils.WhisperRestrictConnectionBetweenLightClientsFlag.Name) { - cfg.Shh.RestrictConnectionBetweenLightClients = true - } - utils.RegisterShhService(stack, &cfg.Shh) - } - - // Add the Ethereum Stats daemon if requested. - if cfg.Ethstats.URL != "" { - utils.RegisterEthStatsService(stack, cfg.Ethstats.URL) - } - return stack -} - -// dumpConfig is the dumpconfig command. -func dumpConfig(ctx *cli.Context) error { - _, cfg := makeConfigNode(ctx) - comment := "" - - if cfg.Dex.Genesis != nil { - cfg.Dex.Genesis = nil - comment += "# Note: this config doesn't contain the genesis block.\n\n" - } - - out, err := tomlSettings.Marshal(&cfg) - if err != nil { - return err - } - - dump := os.Stdout - if ctx.NArg() > 0 { - dump, err = os.OpenFile(ctx.Args().Get(0), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) - if err != nil { - return err - } - defer dump.Close() - } - dump.WriteString(comment) - dump.Write(out) - - return nil -} diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go deleted file mode 100644 index 339919c8d..000000000 --- a/cmd/geth/consolecmd.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -package main - -import ( - "fmt" - "os" - "os/signal" - "path/filepath" - "strings" - "syscall" - - "github.com/dexon-foundation/dexon/cmd/utils" - "github.com/dexon-foundation/dexon/console" - "github.com/dexon-foundation/dexon/node" - "github.com/dexon-foundation/dexon/rpc" - "gopkg.in/urfave/cli.v1" -) - -var ( - consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag} - - consoleCommand = cli.Command{ - Action: utils.MigrateFlags(localConsole), - Name: "console", - Usage: "Start an interactive JavaScript environment", - Flags: append(append(append(nodeFlags, rpcFlags...), consoleFlags...), whisperFlags...), - Category: "CONSOLE COMMANDS", - Description: ` -The Geth console is an interactive shell for the JavaScript runtime environment -which exposes a node admin interface as well as the Ðapp JavaScript API. -See https://github.com/dexon-foundation/dexon/wiki/JavaScript-Console.`, - } - - attachCommand = cli.Command{ - Action: utils.MigrateFlags(remoteConsole), - Name: "attach", - Usage: "Start an interactive JavaScript environment (connect to node)", - ArgsUsage: "[endpoint]", - Flags: append(consoleFlags, utils.DataDirFlag), - Category: "CONSOLE COMMANDS", - Description: ` -The Geth console is an interactive shell for the JavaScript runtime environment -which exposes a node admin interface as well as the Ðapp JavaScript API. -See https://github.com/dexon-foundation/dexon/wiki/JavaScript-Console. -This command allows to open a console on a running geth node.`, - } - - javascriptCommand = cli.Command{ - Action: utils.MigrateFlags(ephemeralConsole), - Name: "js", - Usage: "Execute the specified JavaScript files", - ArgsUsage: "<jsfile> [jsfile...]", - Flags: append(nodeFlags, consoleFlags...), - Category: "CONSOLE COMMANDS", - Description: ` -The JavaScript VM exposes a node admin interface as well as the Ðapp -JavaScript API. See https://github.com/dexon-foundation/dexon/wiki/JavaScript-Console`, - } -) - -// localConsole starts a new geth node, attaching a JavaScript console to it at the -// same time. -func localConsole(ctx *cli.Context) error { - // Create and start the node based on the CLI flags - node := makeFullNode(ctx) - startNode(ctx, node) - defer node.Stop() - - // Attach to the newly started node and start the JavaScript console - client, err := node.Attach() - if err != nil { - utils.Fatalf("Failed to attach to the inproc geth: %v", err) - } - config := console.Config{ - DataDir: utils.MakeDataDir(ctx), - DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), - Client: client, - Preload: utils.MakeConsolePreloads(ctx), - } - - console, err := console.New(config) - if err != nil { - utils.Fatalf("Failed to start the JavaScript console: %v", err) - } - defer console.Stop(false) - - // If only a short execution was requested, evaluate and return - if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { - console.Evaluate(script) - return nil - } - // Otherwise print the welcome screen and enter interactive mode - console.Welcome() - console.Interactive() - - return nil -} - -// remoteConsole will connect to a remote geth instance, attaching a JavaScript -// console to it. -func remoteConsole(ctx *cli.Context) error { - // Attach to a remotely running geth instance and start the JavaScript console - endpoint := ctx.Args().First() - if endpoint == "" { - path := node.DefaultDataDir() - if ctx.GlobalIsSet(utils.DataDirFlag.Name) { - path = ctx.GlobalString(utils.DataDirFlag.Name) - } - if path != "" { - if ctx.GlobalBool(utils.TestnetFlag.Name) { - path = filepath.Join(path, "testnet") - } - } - endpoint = fmt.Sprintf("%s/geth.ipc", path) - } - client, err := dialRPC(endpoint) - if err != nil { - utils.Fatalf("Unable to attach to remote geth: %v", err) - } - config := console.Config{ - DataDir: utils.MakeDataDir(ctx), - DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), - Client: client, - Preload: utils.MakeConsolePreloads(ctx), - } - - console, err := console.New(config) - if err != nil { - utils.Fatalf("Failed to start the JavaScript console: %v", err) - } - defer console.Stop(false) - - if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { - console.Evaluate(script) - return nil - } - - // Otherwise print the welcome screen and enter interactive mode - console.Welcome() - console.Interactive() - - return nil -} - -// dialRPC returns a RPC client which connects to the given endpoint. -// The check for empty endpoint implements the defaulting logic -// for "geth attach" and "geth monitor" with no argument. -func dialRPC(endpoint string) (*rpc.Client, error) { - if endpoint == "" { - endpoint = node.DefaultIPCEndpoint(clientIdentifier) - } else if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") { - // Backwards compatibility with geth < 1.5 which required - // these prefixes. - endpoint = endpoint[4:] - } - return rpc.Dial(endpoint) -} - -// ephemeralConsole starts a new geth node, attaches an ephemeral JavaScript -// console to it, executes each of the files specified as arguments and tears -// everything down. -func ephemeralConsole(ctx *cli.Context) error { - // Create and start the node based on the CLI flags - node := makeFullNode(ctx) - startNode(ctx, node) - defer node.Stop() - - // Attach to the newly started node and start the JavaScript console - client, err := node.Attach() - if err != nil { - utils.Fatalf("Failed to attach to the inproc geth: %v", err) - } - config := console.Config{ - DataDir: utils.MakeDataDir(ctx), - DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), - Client: client, - Preload: utils.MakeConsolePreloads(ctx), - } - - console, err := console.New(config) - if err != nil { - utils.Fatalf("Failed to start the JavaScript console: %v", err) - } - defer console.Stop(false) - - // Evaluate each of the specified JavaScript files - for _, file := range ctx.Args() { - if err = console.Execute(file); err != nil { - utils.Fatalf("Failed to execute %s: %v", file, err) - } - } - // Wait for pending callbacks, but stop for Ctrl-C. - abort := make(chan os.Signal, 1) - signal.Notify(abort, syscall.SIGINT, syscall.SIGTERM) - - go func() { - <-abort - os.Exit(0) - }() - console.Stop(true) - - return nil -} diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go deleted file mode 100644 index 1e3363c0d..000000000 --- a/cmd/geth/consolecmd_test.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -package main - -import ( - "crypto/rand" - "math/big" - "os" - "path/filepath" - "runtime" - "strconv" - "strings" - "testing" - "time" - - "github.com/dexon-foundation/dexon/params" -) - -const ( - ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0" - httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0" -) - -// Tests that a node embedded within a console can be started up properly and -// then terminated by closing the input stream. -func TestConsoleWelcome(t *testing.T) { - coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" - - // Start a geth console, make sure it's cleaned up and terminate the console - geth := runGeth(t, - "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", - "--etherbase", coinbase, "--shh", - "console") - - // Gather all the infos the welcome message needs to contain - geth.SetTemplateFunc("goos", func() string { return runtime.GOOS }) - geth.SetTemplateFunc("goarch", func() string { return runtime.GOARCH }) - geth.SetTemplateFunc("gover", runtime.Version) - geth.SetTemplateFunc("gethver", func() string { return params.VersionWithMeta }) - geth.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) }) - geth.SetTemplateFunc("apis", func() string { return ipcAPIs }) - - // Verify the actual welcome message to the required template - geth.Expect(` -Welcome to the Geth JavaScript console! - -instance: Geth/v{{gethver}}/{{goos}}-{{goarch}}/{{gover}} -coinbase: {{.Etherbase}} -at block: 0 ({{niltime}}) - datadir: {{.Datadir}} - modules: {{apis}} - -> {{.InputLine "exit"}} -`) - geth.ExpectExit() -} - -// Tests that a console can be attached to a running node via various means. -func TestIPCAttachWelcome(t *testing.T) { - // Configure the instance for IPC attachement - coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" - var ipc string - if runtime.GOOS == "windows" { - ipc = `\\.\pipe\geth` + strconv.Itoa(trulyRandInt(100000, 999999)) - } else { - ws := tmpdir(t) - defer os.RemoveAll(ws) - ipc = filepath.Join(ws, "geth.ipc") - } - // Note: we need --shh because testAttachWelcome checks for default - // list of ipc modules and shh is included there. - geth := runGeth(t, - "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", - "--etherbase", coinbase, "--shh", "--ipcpath", ipc) - - time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open - testAttachWelcome(t, geth, "ipc:"+ipc, ipcAPIs) - - geth.Interrupt() - geth.ExpectExit() -} - -func TestHTTPAttachWelcome(t *testing.T) { - coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" - port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P - geth := runGeth(t, - "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", - "--etherbase", coinbase, "--rpc", "--rpcport", port) - - time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open - testAttachWelcome(t, geth, "http://localhost:"+port, httpAPIs) - - geth.Interrupt() - geth.ExpectExit() -} - -func TestWSAttachWelcome(t *testing.T) { - coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" - port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P - - geth := runGeth(t, - "--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", - "--etherbase", coinbase, "--ws", "--wsport", port) - - time.Sleep(2 * time.Second) // Simple way to wait for the RPC endpoint to open - testAttachWelcome(t, geth, "ws://localhost:"+port, httpAPIs) - - geth.Interrupt() - geth.ExpectExit() -} - -func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) { - // Attach to a running geth note and terminate immediately - attach := runGeth(t, "attach", endpoint) - defer attach.ExpectExit() - attach.CloseStdin() - - // Gather all the infos the welcome message needs to contain - attach.SetTemplateFunc("goos", func() string { return runtime.GOOS }) - attach.SetTemplateFunc("goarch", func() string { return runtime.GOARCH }) - attach.SetTemplateFunc("gover", runtime.Version) - attach.SetTemplateFunc("gethver", func() string { return params.VersionWithMeta }) - attach.SetTemplateFunc("etherbase", func() string { return geth.Etherbase }) - attach.SetTemplateFunc("niltime", func() string { return time.Unix(0, 0).Format(time.RFC1123) }) - attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") }) - attach.SetTemplateFunc("datadir", func() string { return geth.Datadir }) - attach.SetTemplateFunc("apis", func() string { return apis }) - - // Verify the actual welcome message to the required template - attach.Expect(` -Welcome to the Geth JavaScript console! - -instance: Geth/v{{gethver}}/{{goos}}-{{goarch}}/{{gover}} -coinbase: {{etherbase}} -at block: 0 ({{niltime}}){{if ipc}} - datadir: {{datadir}}{{end}} - modules: {{apis}} - -> {{.InputLine "exit" }} -`) - attach.ExpectExit() -} - -// trulyRandInt generates a crypto random integer used by the console tests to -// not clash network ports with other tests running cocurrently. -func trulyRandInt(lo, hi int) int { - num, _ := rand.Int(rand.Reader, big.NewInt(int64(hi-lo))) - return int(num.Int64()) + lo -} diff --git a/cmd/geth/dao_test.go b/cmd/geth/dao_test.go deleted file mode 100644 index b4aefe9dd..000000000 --- a/cmd/geth/dao_test.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -package main - -import ( - "io/ioutil" - "math/big" - "os" - "path/filepath" - "testing" - - "github.com/dexon-foundation/dexon/common" - "github.com/dexon-foundation/dexon/core/rawdb" - "github.com/dexon-foundation/dexon/ethdb" - "github.com/dexon-foundation/dexon/params" -) - -// Genesis block for nodes which don't care about the DAO fork (i.e. not configured) -var daoOldGenesis = `{ - "alloc" : {}, - "coinbase" : "0x0000000000000000000000000000000000000000", - "difficulty" : "0x20000", - "extraData" : "", - "gasLimit" : "0x2fefd8", - "nonce" : "0x0000000000000042", - "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp" : "0x00", - "config" : {} -}` - -// Genesis block for nodes which actively oppose the DAO fork -var daoNoForkGenesis = `{ - "alloc" : {}, - "coinbase" : "0x0000000000000000000000000000000000000000", - "difficulty" : "0x20000", - "extraData" : "", - "gasLimit" : "0x2fefd8", - "nonce" : "0x0000000000000042", - "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp" : "0x00", - "config" : { - "daoForkBlock" : 314, - "daoForkSupport" : false - } -}` - -// Genesis block for nodes which actively support the DAO fork -var daoProForkGenesis = `{ - "alloc" : {}, - "coinbase" : "0x0000000000000000000000000000000000000000", - "difficulty" : "0x20000", - "extraData" : "", - "gasLimit" : "0x2fefd8", - "nonce" : "0x0000000000000042", - "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp" : "0x00", - "config" : { - "daoForkBlock" : 314, - "daoForkSupport" : true - } -}` - -var daoGenesisHash = common.HexToHash("5e1fc79cb4ffa4739177b5408045cd5d51c6cf766133f23f7cd72ee1f8d790e0") -var daoGenesisForkBlock = big.NewInt(314) - -// TestDAOForkBlockNewChain tests that the DAO hard-fork number and the nodes support/opposition is correctly -// set in the database after various initialization procedures and invocations. -func TestDAOForkBlockNewChain(t *testing.T) { - for i, arg := range []struct { - genesis string - expectBlock *big.Int - expectVote bool - }{ - // Test DAO Default Mainnet - {"", params.MainnetChainConfig.DAOForkBlock, true}, - // test DAO Init Old Privnet - {daoOldGenesis, nil, false}, - // test DAO Default No Fork Privnet - {daoNoForkGenesis, daoGenesisForkBlock, false}, - // test DAO Default Pro Fork Privnet - {daoProForkGenesis, daoGenesisForkBlock, true}, - } { - testDAOForkBlockNewChain(t, i, arg.genesis, arg.expectBlock, arg.expectVote) - } -} - -func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBlock *big.Int, expectVote bool) { - // Create a temporary data directory to use and inspect later - datadir := tmpdir(t) - defer os.RemoveAll(datadir) - - // Start a Geth instance with the requested flags set and immediately terminate - if genesis != "" { - json := filepath.Join(datadir, "genesis.json") - if err := ioutil.WriteFile(json, []byte(genesis), 0600); err != nil { - t.Fatalf("test %d: failed to write genesis file: %v", test, err) - } - runGeth(t, "--datadir", datadir, "init", json).WaitExit() - } else { - // Force chain initialization - args := []string{"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--ipcdisable", "--datadir", datadir} - geth := runGeth(t, append(args, []string{"--exec", "2+2", "console"}...)...) - geth.WaitExit() - } - // Retrieve the DAO config flag from the database - path := filepath.Join(datadir, "geth", "chaindata") - db, err := ethdb.NewLDBDatabase(path, 0, 0) - if err != nil { - t.Fatalf("test %d: failed to open test database: %v", test, err) - } - defer db.Close() - - genesisHash := common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") - if genesis != "" { - genesisHash = daoGenesisHash - } - config := rawdb.ReadChainConfig(db, genesisHash) - if config == nil { - t.Errorf("test %d: failed to retrieve chain config: %v", test, err) - return // we want to return here, the other checks can't make it past this point (nil panic). - } - // Validate the DAO hard-fork block number against the expected value - if config.DAOForkBlock == nil { - if expectBlock != nil { - t.Errorf("test %d: dao hard-fork block mismatch: have nil, want %v", test, expectBlock) - } - } else if expectBlock == nil { - t.Errorf("test %d: dao hard-fork block mismatch: have %v, want nil", test, config.DAOForkBlock) - } else if config.DAOForkBlock.Cmp(expectBlock) != 0 { - t.Errorf("test %d: dao hard-fork block mismatch: have %v, want %v", test, config.DAOForkBlock, expectBlock) - } - if config.DAOForkSupport != expectVote { - t.Errorf("test %d: dao hard-fork support mismatch: have %v, want %v", test, config.DAOForkSupport, expectVote) - } -} diff --git a/cmd/geth/genesis_test.go b/cmd/geth/genesis_test.go deleted file mode 100644 index e75b542cb..000000000 --- a/cmd/geth/genesis_test.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -package main - -import ( - "io/ioutil" - "os" - "path/filepath" - "testing" -) - -var customGenesisTests = []struct { - genesis string - query string - result string -}{ - // Plain genesis file without anything extra - { - genesis: `{ - "alloc" : {}, - "coinbase" : "0x0000000000000000000000000000000000000000", - "difficulty" : "0x20000", - "extraData" : "", - "gasLimit" : "0x2fefd8", - "nonce" : "0x0000000000000042", - "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp" : "0x00" - }`, - query: "eth.getBlock(0).nonce", - result: "0x0000000000000042", - }, - // Genesis file with an empty chain configuration (ensure missing fields work) - { - genesis: `{ - "alloc" : {}, - "coinbase" : "0x0000000000000000000000000000000000000000", - "difficulty" : "0x20000", - "extraData" : "", - "gasLimit" : "0x2fefd8", - "nonce" : "0x0000000000000042", - "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp" : "0x00", - "config" : {} - }`, - query: "eth.getBlock(0).nonce", - result: "0x0000000000000042", - }, - // Genesis file with specific chain configurations - { - genesis: `{ - "alloc" : {}, - "coinbase" : "0x0000000000000000000000000000000000000000", - "difficulty" : "0x20000", - "extraData" : "", - "gasLimit" : "0x2fefd8", - "nonce" : "0x0000000000000042", - "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp" : "0x00", - "config" : { - "homesteadBlock" : 314, - "daoForkBlock" : 141, - "daoForkSupport" : true - } - }`, - query: "eth.getBlock(0).nonce", - result: "0x0000000000000042", - }, -} - -// Tests that initializing Geth with a custom genesis block and chain definitions -// work properly. -func TestCustomGenesis(t *testing.T) { - for i, tt := range customGenesisTests { - // Create a temporary data directory to use and inspect later - datadir := tmpdir(t) - defer os.RemoveAll(datadir) - - // Initialize the data directory with the custom genesis block - json := filepath.Join(datadir, "genesis.json") - if err := ioutil.WriteFile(json, []byte(tt.genesis), 0600); err != nil { - t.Fatalf("test %d: failed to write genesis file: %v", i, err) - } - runGeth(t, "--datadir", datadir, "init", json).WaitExit() - - // Query the custom genesis block - geth := runGeth(t, - "--datadir", datadir, "--maxpeers", "0", "--port", "0", - "--nodiscover", "--nat", "none", "--ipcdisable", - "--exec", tt.query, "console") - geth.ExpectRegexp(tt.result) - geth.ExpectExit() - } -} diff --git a/cmd/geth/main.go b/cmd/geth/main.go deleted file mode 100644 index 05f5c45b6..000000000 --- a/cmd/geth/main.go +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright 2014 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -// geth is the official command-line client for Ethereum. -package main - -import ( - "fmt" - "math" - "os" - godebug "runtime/debug" - "sort" - "strconv" - "strings" - "time" - - "github.com/dexon-foundation/dexon/accounts" - "github.com/dexon-foundation/dexon/accounts/keystore" - "github.com/dexon-foundation/dexon/cmd/utils" - "github.com/dexon-foundation/dexon/console" - "github.com/dexon-foundation/dexon/dex" - "github.com/dexon-foundation/dexon/eth" - "github.com/dexon-foundation/dexon/ethclient" - "github.com/dexon-foundation/dexon/internal/debug" - "github.com/dexon-foundation/dexon/log" - "github.com/dexon-foundation/dexon/metrics" - "github.com/dexon-foundation/dexon/node" - "github.com/elastic/gosigar" - cli "gopkg.in/urfave/cli.v1" -) - -const ( - clientIdentifier = "geth" // Client identifier to advertise over the network -) - -var ( - // Git SHA1 commit hash of the release (set via linker flags) - gitCommit = "" - // The app that holds all commands and flags. - app = utils.NewApp(gitCommit, "the go-ethereum command line interface") - // flags that configure the node - nodeFlags = []cli.Flag{ - utils.IdentityFlag, - utils.UnlockedAccountFlag, - utils.PasswordFileFlag, - utils.BootnodesFlag, - utils.BootnodesV4Flag, - utils.BootnodesV5Flag, - utils.DataDirFlag, - utils.KeyStoreDirFlag, - utils.NoUSBFlag, - utils.DashboardEnabledFlag, - utils.DashboardAddrFlag, - utils.DashboardPortFlag, - utils.DashboardRefreshFlag, - utils.EthashCacheDirFlag, - utils.EthashCachesInMemoryFlag, - utils.EthashCachesOnDiskFlag, - utils.EthashDatasetDirFlag, - utils.EthashDatasetsInMemoryFlag, - utils.EthashDatasetsOnDiskFlag, - utils.TxPoolLocalsFlag, - utils.TxPoolNoLocalsFlag, - utils.TxPoolJournalFlag, - utils.TxPoolRejournalFlag, - utils.TxPoolPriceLimitFlag, - utils.TxPoolPriceBumpFlag, - utils.TxPoolAccountSlotsFlag, - utils.TxPoolGlobalSlotsFlag, - utils.TxPoolAccountQueueFlag, - utils.TxPoolGlobalQueueFlag, - utils.TxPoolLifetimeFlag, - utils.SyncModeFlag, - utils.GCModeFlag, - utils.LightServFlag, - utils.LightPeersFlag, - utils.LightKDFFlag, - utils.WhitelistFlag, - utils.CacheFlag, - utils.CacheDatabaseFlag, - utils.CacheTrieFlag, - utils.CacheGCFlag, - utils.TrieCacheGenFlag, - utils.ListenPortFlag, - utils.MaxPeersFlag, - utils.MaxPendingPeersFlag, - utils.ProposingEnabledFlag, - utils.MiningEnabledFlag, - utils.MinerThreadsFlag, - utils.MinerLegacyThreadsFlag, - utils.MinerNotifyFlag, - utils.MinerGasTargetFlag, - utils.MinerLegacyGasTargetFlag, - utils.MinerGasLimitFlag, - utils.MinerGasPriceFlag, - utils.MinerLegacyGasPriceFlag, - utils.MinerEtherbaseFlag, - utils.MinerLegacyEtherbaseFlag, - utils.MinerExtraDataFlag, - utils.MinerLegacyExtraDataFlag, - utils.MinerRecommitIntervalFlag, - utils.MinerNoVerfiyFlag, - utils.NATFlag, - utils.NoDiscoverFlag, - utils.DiscoveryV5Flag, - utils.NetrestrictFlag, - utils.NodeKeyFileFlag, - utils.NodeKeyHexFlag, - utils.DeveloperFlag, - utils.DeveloperPeriodFlag, - utils.TestnetFlag, - utils.VMEnableDebugFlag, - utils.NetworkIdFlag, - utils.ConstantinopleOverrideFlag, - utils.RPCCORSDomainFlag, - utils.RPCVirtualHostsFlag, - utils.EthStatsURLFlag, - utils.MetricsEnabledFlag, - utils.FakePoWFlag, - utils.NoCompactionFlag, - utils.GpoBlocksFlag, - utils.GpoPercentileFlag, - utils.EWASMInterpreterFlag, - utils.EVMInterpreterFlag, - configFileFlag, - } - - rpcFlags = []cli.Flag{ - utils.RPCEnabledFlag, - utils.RPCListenAddrFlag, - utils.RPCPortFlag, - utils.RPCApiFlag, - utils.WSEnabledFlag, - utils.WSListenAddrFlag, - utils.WSPortFlag, - utils.WSApiFlag, - utils.WSAllowedOriginsFlag, - utils.IPCDisabledFlag, - utils.IPCPathFlag, - utils.RPCGlobalGasCap, - } - - whisperFlags = []cli.Flag{ - utils.WhisperEnabledFlag, - utils.WhisperMaxMessageSizeFlag, - utils.WhisperMinPOWFlag, - utils.WhisperRestrictConnectionBetweenLightClientsFlag, - } - - metricsFlags = []cli.Flag{ - utils.MetricsEnableInfluxDBFlag, - utils.MetricsInfluxDBEndpointFlag, - utils.MetricsInfluxDBDatabaseFlag, - utils.MetricsInfluxDBUsernameFlag, - utils.MetricsInfluxDBPasswordFlag, - utils.MetricsInfluxDBTagsFlag, - } -) - -func init() { - // Initialize the CLI app and start Geth - app.Action = geth - app.HideVersion = true // we have a command to print the version - app.Copyright = "Copyright 2013-2018 The go-ethereum Authors" - app.Commands = []cli.Command{ - // See chaincmd.go: - initCommand, - importCommand, - exportCommand, - importPreimagesCommand, - exportPreimagesCommand, - copydbCommand, - removedbCommand, - dumpCommand, - // See monitorcmd.go: - monitorCommand, - // See accountcmd.go: - accountCommand, - walletCommand, - // See consolecmd.go: - consoleCommand, - attachCommand, - javascriptCommand, - // See misccmd.go: - makecacheCommand, - makedagCommand, - versionCommand, - bugCommand, - licenseCommand, - // See config.go - dumpConfigCommand, - } - sort.Sort(cli.CommandsByName(app.Commands)) - - app.Flags = append(app.Flags, nodeFlags...) - app.Flags = append(app.Flags, rpcFlags...) - app.Flags = append(app.Flags, consoleFlags...) - app.Flags = append(app.Flags, debug.Flags...) - app.Flags = append(app.Flags, whisperFlags...) - app.Flags = append(app.Flags, metricsFlags...) - - app.Before = func(ctx *cli.Context) error { - logdir := "" - if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) { - logdir = (&node.Config{DataDir: utils.MakeDataDir(ctx)}).ResolvePath("logs") - } - if err := debug.Setup(ctx, logdir); err != nil { - return err - } - // Cap the cache allowance and tune the garbage collector - var mem gosigar.Mem - if err := mem.Get(); err == nil { - allowance := int(mem.Total / 1024 / 1024 / 3) - if cache := ctx.GlobalInt(utils.CacheFlag.Name); cache > allowance { - log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance) - ctx.GlobalSet(utils.CacheFlag.Name, strconv.Itoa(allowance)) - } - } - // Ensure Go's GC ignores the database cache for trigger percentage - cache := ctx.GlobalInt(utils.CacheFlag.Name) - gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024))) - - log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc)) - godebug.SetGCPercent(int(gogc)) - - // Start metrics export if enabled - utils.SetupMetrics(ctx) - - // Start system runtime metrics collection - go metrics.CollectProcessMetrics(3 * time.Second) - - return nil - } - - app.After = func(ctx *cli.Context) error { - debug.Exit() - console.Stdin.Close() // Resets terminal mode. - return nil - } -} - -func main() { - if err := app.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -// geth is the main entry point into the system if no special subcommand is ran. -// It creates a default node based on the command line arguments and runs it in -// blocking mode, waiting for it to be shut down. -func geth(ctx *cli.Context) error { - if args := ctx.Args(); len(args) > 0 { - return fmt.Errorf("invalid command: %q", args[0]) - } - node := makeFullNode(ctx) - startNode(ctx, node) - node.Wait() - return nil -} - -// startNode boots up the system node and all registered protocols, after which -// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the -// miner. -func startNode(ctx *cli.Context, stack *node.Node) { - debug.Memsize.Add("node", stack) - - // Start up the node itself - utils.StartNode(stack) - - // Unlock any account specifically requested - ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) - - passwords := utils.MakePasswordList(ctx) - unlocks := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",") - for i, account := range unlocks { - if trimmed := strings.TrimSpace(account); trimmed != "" { - unlockAccount(ctx, ks, trimmed, i, passwords) - } - } - // Register wallet event handlers to open and auto-derive wallets - events := make(chan accounts.WalletEvent, 16) - stack.AccountManager().Subscribe(events) - - go func() { - // Create a chain state reader for self-derivation - rpcClient, err := stack.Attach() - if err != nil { - utils.Fatalf("Failed to attach to self: %v", err) - } - stateReader := ethclient.NewClient(rpcClient) - - // Open any wallets already attached - for _, wallet := range stack.AccountManager().Wallets() { - if err := wallet.Open(""); err != nil { - log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err) - } - } - // Listen for wallet event till termination - for event := range events { - switch event.Kind { - case accounts.WalletArrived: - if err := event.Wallet.Open(""); err != nil { - log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err) - } - case accounts.WalletOpened: - status, _ := event.Wallet.Status() - log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status) - - derivationPath := accounts.DefaultBaseDerivationPath - if event.Wallet.URL().Scheme == "ledger" { - derivationPath = accounts.DefaultLedgerBaseDerivationPath - } - event.Wallet.SelfDerive(derivationPath, stateReader) - - case accounts.WalletDropped: - log.Info("Old wallet dropped", "url", event.Wallet.URL()) - event.Wallet.Close() - } - } - }() - // Start auxiliary services if enabled - if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) { - // Mining only makes sense if a full Ethereum node is running - if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { - utils.Fatalf("Light clients do not support mining") - } - var ethereum *eth.Ethereum - if err := stack.Service(ðereum); err != nil { - utils.Fatalf("Ethereum service not running: %v", err) - } - // Set the gas price to the limits from the CLI and start mining - gasprice := utils.GlobalBig(ctx, utils.MinerLegacyGasPriceFlag.Name) - if ctx.IsSet(utils.MinerGasPriceFlag.Name) { - gasprice = utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name) - } - ethereum.TxPool().SetGasPrice(gasprice) - - threads := ctx.GlobalInt(utils.MinerLegacyThreadsFlag.Name) - if ctx.GlobalIsSet(utils.MinerThreadsFlag.Name) { - threads = ctx.GlobalInt(utils.MinerThreadsFlag.Name) - } - if err := ethereum.StartMining(threads); err != nil { - utils.Fatalf("Failed to start mining: %v", err) - } - } - - if ctx.GlobalBool(utils.ProposingEnabledFlag.Name) { - if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { - utils.Fatalf("Light clients do not support proposing") - } - var dexon *dex.Dexon - if err := stack.Service(&dexon); err != nil { - utils.Fatalf("Dexon service not running: %v", err) - } - if err := dexon.StartProposing(); err != nil { - utils.Fatalf("Failed to string proposing: %v", err) - } - } -} diff --git a/cmd/geth/misccmd.go b/cmd/geth/misccmd.go deleted file mode 100644 index b90567154..000000000 --- a/cmd/geth/misccmd.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -package main - -import ( - "fmt" - "os" - "runtime" - "strconv" - "strings" - - "github.com/dexon-foundation/dexon/cmd/utils" - "github.com/dexon-foundation/dexon/consensus/ethash" - "github.com/dexon-foundation/dexon/eth" - "github.com/dexon-foundation/dexon/params" - "gopkg.in/urfave/cli.v1" -) - -var ( - makecacheCommand = cli.Command{ - Action: utils.MigrateFlags(makecache), - Name: "makecache", - Usage: "Generate ethash verification cache (for testing)", - ArgsUsage: "<blockNum> <outputDir>", - Category: "MISCELLANEOUS COMMANDS", - Description: ` -The makecache command generates an ethash cache in <outputDir>. - -This command exists to support the system testing project. -Regular users do not need to execute it. -`, - } - makedagCommand = cli.Command{ - Action: utils.MigrateFlags(makedag), - Name: "makedag", - Usage: "Generate ethash mining DAG (for testing)", - ArgsUsage: "<blockNum> <outputDir>", - Category: "MISCELLANEOUS COMMANDS", - Description: ` -The makedag command generates an ethash DAG in <outputDir>. - -This command exists to support the system testing project. -Regular users do not need to execute it. -`, - } - versionCommand = cli.Command{ - Action: utils.MigrateFlags(version), - Name: "version", - Usage: "Print version numbers", - ArgsUsage: " ", - Category: "MISCELLANEOUS COMMANDS", - Description: ` -The output of this command is supposed to be machine-readable. -`, - } - licenseCommand = cli.Command{ - Action: utils.MigrateFlags(license), - Name: "license", - Usage: "Display license information", - ArgsUsage: " ", - Category: "MISCELLANEOUS COMMANDS", - } -) - -// makecache generates an ethash verification cache into the provided folder. -func makecache(ctx *cli.Context) error { - args := ctx.Args() - if len(args) != 2 { - utils.Fatalf(`Usage: geth makecache <block number> <outputdir>`) - } - block, err := strconv.ParseUint(args[0], 0, 64) - if err != nil { - utils.Fatalf("Invalid block number: %v", err) - } - ethash.MakeCache(block, args[1]) - - return nil -} - -// makedag generates an ethash mining DAG into the provided folder. -func makedag(ctx *cli.Context) error { - args := ctx.Args() - if len(args) != 2 { - utils.Fatalf(`Usage: geth makedag <block number> <outputdir>`) - } - block, err := strconv.ParseUint(args[0], 0, 64) - if err != nil { - utils.Fatalf("Invalid block number: %v", err) - } - ethash.MakeDataset(block, args[1]) - - return nil -} - -func version(ctx *cli.Context) error { - fmt.Println(strings.Title(clientIdentifier)) - fmt.Println("Version:", params.VersionWithMeta) - if gitCommit != "" { - fmt.Println("Git Commit:", gitCommit) - } - fmt.Println("Architecture:", runtime.GOARCH) - fmt.Println("Protocol Versions:", eth.ProtocolVersions) - fmt.Println("Network Id:", eth.DefaultConfig.NetworkId) - fmt.Println("Go Version:", runtime.Version()) - fmt.Println("Operating System:", runtime.GOOS) - fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH")) - fmt.Printf("GOROOT=%s\n", runtime.GOROOT()) - return nil -} - -func license(_ *cli.Context) error { - fmt.Println(`Geth is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Geth is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with geth. If not, see <http://www.gnu.org/licenses/>.`) - return nil -} diff --git a/cmd/geth/monitorcmd.go b/cmd/geth/monitorcmd.go deleted file mode 100644 index 668401028..000000000 --- a/cmd/geth/monitorcmd.go +++ /dev/null @@ -1,351 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -package main - -import ( - "fmt" - "math" - "reflect" - "runtime" - "sort" - "strings" - "time" - - "github.com/dexon-foundation/dexon/cmd/utils" - "github.com/dexon-foundation/dexon/node" - "github.com/dexon-foundation/dexon/rpc" - "github.com/gizak/termui" - "gopkg.in/urfave/cli.v1" -) - -var ( - monitorCommandAttachFlag = cli.StringFlag{ - Name: "attach", - Value: node.DefaultIPCEndpoint(clientIdentifier), - Usage: "API endpoint to attach to", - } - monitorCommandRowsFlag = cli.IntFlag{ - Name: "rows", - Value: 5, - Usage: "Maximum rows in the chart grid", - } - monitorCommandRefreshFlag = cli.IntFlag{ - Name: "refresh", - Value: 3, - Usage: "Refresh interval in seconds", - } - monitorCommand = cli.Command{ - Action: utils.MigrateFlags(monitor), // keep track of migration progress - Name: "monitor", - Usage: "Monitor and visualize node metrics", - ArgsUsage: " ", - Category: "MONITOR COMMANDS", - Description: ` -The Geth monitor is a tool to collect and visualize various internal metrics -gathered by the node, supporting different chart types as well as the capacity -to display multiple metrics simultaneously. -`, - Flags: []cli.Flag{ - monitorCommandAttachFlag, - monitorCommandRowsFlag, - monitorCommandRefreshFlag, - }, - } -) - -// monitor starts a terminal UI based monitoring tool for the requested metrics. -func monitor(ctx *cli.Context) error { - var ( - client *rpc.Client - err error - ) - // Attach to an Ethereum node over IPC or RPC - endpoint := ctx.String(monitorCommandAttachFlag.Name) - if client, err = dialRPC(endpoint); err != nil { - utils.Fatalf("Unable to attach to geth node: %v", err) - } - defer client.Close() - - // Retrieve all the available metrics and resolve the user pattens - metrics, err := retrieveMetrics(client) - if err != nil { - utils.Fatalf("Failed to retrieve system metrics: %v", err) - } - monitored := resolveMetrics(metrics, ctx.Args()) - if len(monitored) == 0 { - list := expandMetrics(metrics, "") - sort.Strings(list) - - if len(list) > 0 { - utils.Fatalf("No metrics specified.\n\nAvailable:\n - %s", strings.Join(list, "\n - ")) - } else { - utils.Fatalf("No metrics collected by geth (--%s).\n", utils.MetricsEnabledFlag.Name) - } - } - sort.Strings(monitored) - if cols := len(monitored) / ctx.Int(monitorCommandRowsFlag.Name); cols > 6 { - utils.Fatalf("Requested metrics (%d) spans more that 6 columns:\n - %s", len(monitored), strings.Join(monitored, "\n - ")) - } - // Create and configure the chart UI defaults - if err := termui.Init(); err != nil { - utils.Fatalf("Unable to initialize terminal UI: %v", err) - } - defer termui.Close() - - rows := len(monitored) - if max := ctx.Int(monitorCommandRowsFlag.Name); rows > max { - rows = max - } - cols := (len(monitored) + rows - 1) / rows - for i := 0; i < rows; i++ { - termui.Body.AddRows(termui.NewRow()) - } - // Create each individual data chart - footer := termui.NewPar("") - footer.Block.Border = true - footer.Height = 3 - - charts := make([]*termui.LineChart, len(monitored)) - units := make([]int, len(monitored)) - data := make([][]float64, len(monitored)) - for i := 0; i < len(monitored); i++ { - charts[i] = createChart((termui.TermHeight() - footer.Height) / rows) - row := termui.Body.Rows[i%rows] - row.Cols = append(row.Cols, termui.NewCol(12/cols, 0, charts[i])) - } - termui.Body.AddRows(termui.NewRow(termui.NewCol(12, 0, footer))) - - refreshCharts(client, monitored, data, units, charts, ctx, footer) - termui.Body.Align() - termui.Render(termui.Body) - - // Watch for various system events, and periodically refresh the charts - termui.Handle("/sys/kbd/C-c", func(termui.Event) { - termui.StopLoop() - }) - termui.Handle("/sys/wnd/resize", func(termui.Event) { - termui.Body.Width = termui.TermWidth() - for _, chart := range charts { - chart.Height = (termui.TermHeight() - footer.Height) / rows - } - termui.Body.Align() - termui.Render(termui.Body) - }) - go func() { - tick := time.NewTicker(time.Duration(ctx.Int(monitorCommandRefreshFlag.Name)) * time.Second) - for range tick.C { - if refreshCharts(client, monitored, data, units, charts, ctx, footer) { - termui.Body.Align() - } - termui.Render(termui.Body) - } - }() - termui.Loop() - return nil -} - -// retrieveMetrics contacts the attached geth node and retrieves the entire set -// of collected system metrics. -func retrieveMetrics(client *rpc.Client) (map[string]interface{}, error) { - var metrics map[string]interface{} - err := client.Call(&metrics, "debug_metrics", true) - return metrics, err -} - -// resolveMetrics takes a list of input metric patterns, and resolves each to one -// or more canonical metric names. -func resolveMetrics(metrics map[string]interface{}, patterns []string) []string { - res := []string{} - for _, pattern := range patterns { - res = append(res, resolveMetric(metrics, pattern, "")...) - } - return res -} - -// resolveMetrics takes a single of input metric pattern, and resolves it to one -// or more canonical metric names. -func resolveMetric(metrics map[string]interface{}, pattern string, path string) []string { - results := []string{} - - // If a nested metric was requested, recurse optionally branching (via comma) - parts := strings.SplitN(pattern, "/", 2) - if len(parts) > 1 { - for _, variation := range strings.Split(parts[0], ",") { - submetrics, ok := metrics[variation].(map[string]interface{}) - if !ok { - utils.Fatalf("Failed to retrieve system metrics: %s", path+variation) - return nil - } - results = append(results, resolveMetric(submetrics, parts[1], path+variation+"/")...) - } - return results - } - // Depending what the last link is, return or expand - for _, variation := range strings.Split(pattern, ",") { - switch metric := metrics[variation].(type) { - case float64: - // Final metric value found, return as singleton - results = append(results, path+variation) - - case map[string]interface{}: - results = append(results, expandMetrics(metric, path+variation+"/")...) - - default: - utils.Fatalf("Metric pattern resolved to unexpected type: %v", reflect.TypeOf(metric)) - return nil - } - } - return results -} - -// expandMetrics expands the entire tree of metrics into a flat list of paths. -func expandMetrics(metrics map[string]interface{}, path string) []string { - // Iterate over all fields and expand individually - list := []string{} - for name, metric := range metrics { - switch metric := metric.(type) { - case float64: - // Final metric value found, append to list - list = append(list, path+name) - - case map[string]interface{}: - // Tree of metrics found, expand recursively - list = append(list, expandMetrics(metric, path+name+"/")...) - - default: - utils.Fatalf("Metric pattern %s resolved to unexpected type: %v", path+name, reflect.TypeOf(metric)) - return nil - } - } - return list -} - -// fetchMetric iterates over the metrics map and retrieves a specific one. -func fetchMetric(metrics map[string]interface{}, metric string) float64 { - parts := strings.Split(metric, "/") - for _, part := range parts[:len(parts)-1] { - var found bool - metrics, found = metrics[part].(map[string]interface{}) - if !found { - return 0 - } - } - if v, ok := metrics[parts[len(parts)-1]].(float64); ok { - return v - } - return 0 -} - -// refreshCharts retrieves a next batch of metrics, and inserts all the new -// values into the active datasets and charts -func refreshCharts(client *rpc.Client, metrics []string, data [][]float64, units []int, charts []*termui.LineChart, ctx *cli.Context, footer *termui.Par) (realign bool) { - values, err := retrieveMetrics(client) - for i, metric := range metrics { - if len(data) < 512 { - data[i] = append([]float64{fetchMetric(values, metric)}, data[i]...) - } else { - data[i] = append([]float64{fetchMetric(values, metric)}, data[i][:len(data[i])-1]...) - } - if updateChart(metric, data[i], &units[i], charts[i], err) { - realign = true - } - } - updateFooter(ctx, err, footer) - return -} - -// updateChart inserts a dataset into a line chart, scaling appropriately as to -// not display weird labels, also updating the chart label accordingly. -func updateChart(metric string, data []float64, base *int, chart *termui.LineChart, err error) (realign bool) { - dataUnits := []string{"", "K", "M", "G", "T", "E"} - timeUnits := []string{"ns", "µs", "ms", "s", "ks", "ms"} - colors := []termui.Attribute{termui.ColorBlue, termui.ColorCyan, termui.ColorGreen, termui.ColorYellow, termui.ColorRed, termui.ColorRed} - - // Extract only part of the data that's actually visible - if chart.Width*2 < len(data) { - data = data[:chart.Width*2] - } - // Find the maximum value and scale under 1K - high := 0.0 - if len(data) > 0 { - high = data[0] - for _, value := range data[1:] { - high = math.Max(high, value) - } - } - unit, scale := 0, 1.0 - for high >= 1000 && unit+1 < len(dataUnits) { - high, unit, scale = high/1000, unit+1, scale*1000 - } - // If the unit changes, re-create the chart (hack to set max height...) - if unit != *base { - realign, *base, *chart = true, unit, *createChart(chart.Height) - } - // Update the chart's data points with the scaled values - if cap(chart.Data) < len(data) { - chart.Data = make([]float64, len(data)) - } - chart.Data = chart.Data[:len(data)] - for i, value := range data { - chart.Data[i] = value / scale - } - // Update the chart's label with the scale units - units := dataUnits - if strings.Contains(metric, "/Percentiles/") || strings.Contains(metric, "/pauses/") || strings.Contains(metric, "/time/") { - units = timeUnits - } - chart.BorderLabel = metric - if len(units[unit]) > 0 { - chart.BorderLabel += " [" + units[unit] + "]" - } - chart.LineColor = colors[unit] | termui.AttrBold - if err != nil { - chart.LineColor = termui.ColorRed | termui.AttrBold - } - return -} - -// createChart creates an empty line chart with the default configs. -func createChart(height int) *termui.LineChart { - chart := termui.NewLineChart() - if runtime.GOOS == "windows" { - chart.Mode = "dot" - } - chart.DataLabels = []string{""} - chart.Height = height - chart.AxesColor = termui.ColorWhite - chart.PaddingBottom = -2 - - chart.BorderLabelFg = chart.BorderFg | termui.AttrBold - chart.BorderFg = chart.BorderBg - - return chart -} - -// updateFooter updates the footer contents based on any encountered errors. -func updateFooter(ctx *cli.Context, err error, footer *termui.Par) { - // Generate the basic footer - refresh := time.Duration(ctx.Int(monitorCommandRefreshFlag.Name)) * time.Second - footer.Text = fmt.Sprintf("Press Ctrl+C to quit. Refresh interval: %v.", refresh) - footer.TextFgColor = termui.ThemeAttr("par.fg") | termui.AttrBold - - // Append any encountered errors - if err != nil { - footer.Text = fmt.Sprintf("Error: %v.", err) - footer.TextFgColor = termui.ColorRed | termui.AttrBold - } -} diff --git a/cmd/geth/run_test.go b/cmd/geth/run_test.go deleted file mode 100644 index c5bd7e6fc..000000000 --- a/cmd/geth/run_test.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -package main - -import ( - "fmt" - "io/ioutil" - "os" - "testing" - - "github.com/dexon-foundation/dexon/internal/cmdtest" - "github.com/docker/docker/pkg/reexec" -) - -func tmpdir(t *testing.T) string { - dir, err := ioutil.TempDir("", "geth-test") - if err != nil { - t.Fatal(err) - } - return dir -} - -type testgeth struct { - *cmdtest.TestCmd - - // template variables for expect - Datadir string - Etherbase string -} - -func init() { - // Run the app if we've been exec'd as "geth-test" in runGeth. - reexec.Register("geth-test", func() { - if err := app.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - os.Exit(0) - }) -} - -func TestMain(m *testing.M) { - // check if we have been reexec'd - if reexec.Init() { - return - } - os.Exit(m.Run()) -} - -// spawns geth with the given command line args. If the args don't set --datadir, the -// child g gets a temporary data directory. -func runGeth(t *testing.T, args ...string) *testgeth { - tt := &testgeth{} - tt.TestCmd = cmdtest.NewTestCmd(t, tt) - for i, arg := range args { - switch { - case arg == "-datadir" || arg == "--datadir": - if i < len(args)-1 { - tt.Datadir = args[i+1] - } - case arg == "-etherbase" || arg == "--etherbase": - if i < len(args)-1 { - tt.Etherbase = args[i+1] - } - } - } - if tt.Datadir == "" { - tt.Datadir = tmpdir(t) - tt.Cleanup = func() { os.RemoveAll(tt.Datadir) } - args = append([]string{"-datadir", tt.Datadir}, args...) - // Remove the temporary datadir if something fails below. - defer func() { - if t.Failed() { - tt.Cleanup() - } - }() - } - - // Boot "geth". This actually runs the test binary but the TestMain - // function will prevent any tests from running. - tt.Run("geth-test", args...) - - return tt -} diff --git a/cmd/geth/testdata/empty.js b/cmd/geth/testdata/empty.js deleted file mode 100644 index 8b1378917..000000000 --- a/cmd/geth/testdata/empty.js +++ /dev/null @@ -1 +0,0 @@ - diff --git a/cmd/geth/testdata/guswallet.json b/cmd/geth/testdata/guswallet.json deleted file mode 100644 index e8ea4f332..000000000 --- a/cmd/geth/testdata/guswallet.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "encseed": "26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba", - "ethaddr": "d4584b5f6229b7be90727b0fc8c6b91bb427821f", - "email": "gustav.simonsson@gmail.com", - "btcaddr": "1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx" -} diff --git a/cmd/geth/testdata/passwords.txt b/cmd/geth/testdata/passwords.txt deleted file mode 100644 index 96f98c7f4..000000000 --- a/cmd/geth/testdata/passwords.txt +++ /dev/null @@ -1,3 +0,0 @@ -foobar -foobar -foobar diff --git a/cmd/geth/testdata/wrong-passwords.txt b/cmd/geth/testdata/wrong-passwords.txt deleted file mode 100644 index 7d1e338bb..000000000 --- a/cmd/geth/testdata/wrong-passwords.txt +++ /dev/null @@ -1,3 +0,0 @@ -wrong -wrong -wrong diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go deleted file mode 100644 index fb14a9bbd..000000000 --- a/cmd/geth/usage.go +++ /dev/null @@ -1,360 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. - -// Contains the geth command usage template and generator. - -package main - -import ( - "io" - "sort" - - "strings" - - "github.com/dexon-foundation/dexon/cmd/utils" - "github.com/dexon-foundation/dexon/internal/debug" - cli "gopkg.in/urfave/cli.v1" -) - -// AppHelpTemplate is the test template for the default, global app help topic. -var AppHelpTemplate = `NAME: - {{.App.Name}} - {{.App.Usage}} - - Copyright 2013-2018 The go-ethereum Authors - -USAGE: - {{.App.HelpName}} [options]{{if .App.Commands}} command [command options]{{end}} {{if .App.ArgsUsage}}{{.App.ArgsUsage}}{{else}}[arguments...]{{end}} - {{if .App.Version}} -VERSION: - {{.App.Version}} - {{end}}{{if len .App.Authors}} -AUTHOR(S): - {{range .App.Authors}}{{ . }}{{end}} - {{end}}{{if .App.Commands}} -COMMANDS: - {{range .App.Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} - {{end}}{{end}}{{if .FlagGroups}} -{{range .FlagGroups}}{{.Name}} OPTIONS: - {{range .Flags}}{{.}} - {{end}} -{{end}}{{end}}{{if .App.Copyright }} -COPYRIGHT: - {{.App.Copyright}} - {{end}} -` - -// flagGroup is a collection of flags belonging to a single topic. -type flagGroup struct { - Name string - Flags []cli.Flag -} - -// AppHelpFlagGroups is the application flags, grouped by functionality. -var AppHelpFlagGroups = []flagGroup{ - { - Name: "ETHEREUM", - Flags: []cli.Flag{ - configFileFlag, - utils.DataDirFlag, - utils.KeyStoreDirFlag, - utils.NoUSBFlag, - utils.NetworkIdFlag, - utils.TestnetFlag, - utils.SyncModeFlag, - utils.GCModeFlag, - utils.EthStatsURLFlag, - utils.IdentityFlag, - utils.LightServFlag, - utils.LightPeersFlag, - utils.LightKDFFlag, - utils.WhitelistFlag, - }, - }, - { - Name: "DEVELOPER CHAIN", - Flags: []cli.Flag{ - utils.DeveloperFlag, - utils.DeveloperPeriodFlag, - }, - }, - { - Name: "ETHASH", - Flags: []cli.Flag{ - utils.EthashCacheDirFlag, - utils.EthashCachesInMemoryFlag, - utils.EthashCachesOnDiskFlag, - utils.EthashDatasetDirFlag, - utils.EthashDatasetsInMemoryFlag, - utils.EthashDatasetsOnDiskFlag, - }, - }, - //{ - // Name: "DASHBOARD", - // Flags: []cli.Flag{ - // utils.DashboardEnabledFlag, - // utils.DashboardAddrFlag, - // utils.DashboardPortFlag, - // utils.DashboardRefreshFlag, - // utils.DashboardAssetsFlag, - // }, - //}, - { - Name: "TRANSACTION POOL", - Flags: []cli.Flag{ - utils.TxPoolLocalsFlag, - utils.TxPoolNoLocalsFlag, - utils.TxPoolJournalFlag, - utils.TxPoolRejournalFlag, - utils.TxPoolPriceLimitFlag, - utils.TxPoolPriceBumpFlag, - utils.TxPoolAccountSlotsFlag, - utils.TxPoolGlobalSlotsFlag, - utils.TxPoolAccountQueueFlag, - utils.TxPoolGlobalQueueFlag, - utils.TxPoolLifetimeFlag, - }, - }, - { - Name: "PERFORMANCE TUNING", - Flags: []cli.Flag{ - utils.CacheFlag, - utils.CacheDatabaseFlag, - utils.CacheTrieFlag, - utils.CacheGCFlag, - utils.TrieCacheGenFlag, - }, - }, - { - Name: "ACCOUNT", - Flags: []cli.Flag{ - utils.UnlockedAccountFlag, - utils.PasswordFileFlag, - }, - }, - { - Name: "API AND CONSOLE", - Flags: []cli.Flag{ - utils.RPCEnabledFlag, - utils.RPCListenAddrFlag, - utils.RPCPortFlag, - utils.RPCApiFlag, - utils.RPCGlobalGasCap, - utils.WSEnabledFlag, - utils.WSListenAddrFlag, - utils.WSPortFlag, - utils.WSApiFlag, - utils.WSAllowedOriginsFlag, - utils.IPCDisabledFlag, - utils.IPCPathFlag, - utils.RPCCORSDomainFlag, - utils.RPCVirtualHostsFlag, - utils.JSpathFlag, - utils.ExecFlag, - utils.PreloadJSFlag, - }, - }, - { - Name: "NETWORKING", - Flags: []cli.Flag{ - utils.BootnodesFlag, - utils.BootnodesV4Flag, - utils.BootnodesV5Flag, - utils.ListenPortFlag, - utils.MaxPeersFlag, - utils.MaxPendingPeersFlag, - utils.NATFlag, - utils.NoDiscoverFlag, - utils.DiscoveryV5Flag, - utils.NetrestrictFlag, - utils.NodeKeyFileFlag, - utils.NodeKeyHexFlag, - }, - }, - { - Name: "PROPOSER", - Flags: []cli.Flag{ - utils.ProposingEnabledFlag, - }, - }, - { - Name: "MINER", - Flags: []cli.Flag{ - utils.MiningEnabledFlag, - utils.MinerThreadsFlag, - utils.MinerNotifyFlag, - utils.MinerGasPriceFlag, - utils.MinerGasTargetFlag, - utils.MinerGasLimitFlag, - utils.MinerEtherbaseFlag, - utils.MinerExtraDataFlag, - utils.MinerRecommitIntervalFlag, - utils.MinerNoVerfiyFlag, - }, - }, - { - Name: "GAS PRICE ORACLE", - Flags: []cli.Flag{ - utils.GpoBlocksFlag, - utils.GpoPercentileFlag, - }, - }, - { - Name: "VIRTUAL MACHINE", - Flags: []cli.Flag{ - utils.VMEnableDebugFlag, - utils.EVMInterpreterFlag, - utils.EWASMInterpreterFlag, - }, - }, - { - Name: "LOGGING AND DEBUGGING", - Flags: append([]cli.Flag{ - utils.FakePoWFlag, - utils.NoCompactionFlag, - }, debug.Flags...), - }, - { - Name: "METRICS AND STATS", - Flags: []cli.Flag{ - utils.MetricsEnabledFlag, - utils.MetricsEnableInfluxDBFlag, - utils.MetricsInfluxDBEndpointFlag, - utils.MetricsInfluxDBDatabaseFlag, - utils.MetricsInfluxDBUsernameFlag, - utils.MetricsInfluxDBPasswordFlag, - utils.MetricsInfluxDBTagsFlag, - }, - }, - { - Name: "WHISPER (EXPERIMENTAL)", - Flags: whisperFlags, - }, - { - Name: "DEPRECATED", - Flags: []cli.Flag{ - utils.MinerLegacyThreadsFlag, - utils.MinerLegacyGasTargetFlag, - utils.MinerLegacyGasPriceFlag, - utils.MinerLegacyEtherbaseFlag, - utils.MinerLegacyExtraDataFlag, - }, - }, - { - Name: "MISC", - }, -} - -// byCategory sorts an array of flagGroup by Name in the order -// defined in AppHelpFlagGroups. -type byCategory []flagGroup - -func (a byCategory) Len() int { return len(a) } -func (a byCategory) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byCategory) Less(i, j int) bool { - iCat, jCat := a[i].Name, a[j].Name - iIdx, jIdx := len(AppHelpFlagGroups), len(AppHelpFlagGroups) // ensure non categorized flags come last - - for i, group := range AppHelpFlagGroups { - if iCat == group.Name { - iIdx = i - } - if jCat == group.Name { - jIdx = i - } - } - - return iIdx < jIdx -} - -func flagCategory(flag cli.Flag) string { - for _, category := range AppHelpFlagGroups { - for _, flg := range category.Flags { - if flg.GetName() == flag.GetName() { - return category.Name - } - } - } - return "MISC" -} - -func init() { - // Override the default app help template - cli.AppHelpTemplate = AppHelpTemplate - - // Define a one shot struct to pass to the usage template - type helpData struct { - App interface{} - FlagGroups []flagGroup - } - - // Override the default app help printer, but only for the global app help - originalHelpPrinter := cli.HelpPrinter - cli.HelpPrinter = func(w io.Writer, tmpl string, data interface{}) { - if tmpl == AppHelpTemplate { - // Iterate over all the flags and add any uncategorized ones - categorized := make(map[string]struct{}) - for _, group := range AppHelpFlagGroups { - for _, flag := range group.Flags { - categorized[flag.String()] = struct{}{} - } - } - uncategorized := []cli.Flag{} - for _, flag := range data.(*cli.App).Flags { - if _, ok := categorized[flag.String()]; !ok { - if strings.HasPrefix(flag.GetName(), "dashboard") { - continue - } - uncategorized = append(uncategorized, flag) - } - } - if len(uncategorized) > 0 { - // Append all ungategorized options to the misc group - miscs := len(AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags) - AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags = append(AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags, uncategorized...) - - // Make sure they are removed afterwards - defer func() { - AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags = AppHelpFlagGroups[len(AppHelpFlagGroups)-1].Flags[:miscs] - }() - } - // Render out custom usage screen - originalHelpPrinter(w, tmpl, helpData{data, AppHelpFlagGroups}) - } else if tmpl == utils.CommandHelpTemplate { - // Iterate over all command specific flags and categorize them - categorized := make(map[string][]cli.Flag) - for _, flag := range data.(cli.Command).Flags { - if _, ok := categorized[flag.String()]; !ok { - categorized[flagCategory(flag)] = append(categorized[flagCategory(flag)], flag) - } - } - - // sort to get a stable ordering - sorted := make([]flagGroup, 0, len(categorized)) - for cat, flgs := range categorized { - sorted = append(sorted, flagGroup{cat, flgs}) - } - sort.Sort(byCategory(sorted)) - - // add sorted array to data and render with default printer - originalHelpPrinter(w, tmpl, map[string]interface{}{ - "cmd": data, - "categorizedFlags": sorted, - }) - } else { - originalHelpPrinter(w, tmpl, data) - } - } -} |