github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/cmd/geth/accountcmd.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2016 Go Ethereum作者
    10  //此文件是Go以太坊的一部分。
    11  //
    12  //Go以太坊是免费软件:您可以重新发布和/或修改它
    13  //根据GNU通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊的分布希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU通用公共许可证了解更多详细信息。
    21  //
    22  //你应该已经收到一份GNU通用公共许可证的副本
    23  //一起去以太坊吧。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package main
    26  
    27  import (
    28  	"fmt"
    29  	"io/ioutil"
    30  
    31  	"github.com/ethereum/go-ethereum/accounts"
    32  	"github.com/ethereum/go-ethereum/accounts/keystore"
    33  	"github.com/ethereum/go-ethereum/cmd/utils"
    34  	"github.com/ethereum/go-ethereum/console"
    35  	"github.com/ethereum/go-ethereum/crypto"
    36  	"github.com/ethereum/go-ethereum/log"
    37  	"gopkg.in/urfave/cli.v1"
    38  )
    39  
    40  var (
    41  	walletCommand = cli.Command{
    42  		Name:      "wallet",
    43  		Usage:     "Manage Ethereum presale wallets",
    44  		ArgsUsage: "",
    45  		Category:  "ACCOUNT COMMANDS",
    46  		Description: `
    47      geth wallet import /path/to/my/presale.wallet
    48  
    49  will prompt for your password and imports your ether presale account.
    50  It can be used non-interactively with the --password option taking a
    51  passwordfile as argument containing the wallet password in plaintext.`,
    52  		Subcommands: []cli.Command{
    53  			{
    54  
    55  				Name:      "import",
    56  				Usage:     "Import Ethereum presale wallet",
    57  				ArgsUsage: "<keyFile>",
    58  				Action:    utils.MigrateFlags(importWallet),
    59  				Category:  "ACCOUNT COMMANDS",
    60  				Flags: []cli.Flag{
    61  					utils.DataDirFlag,
    62  					utils.KeyStoreDirFlag,
    63  					utils.PasswordFileFlag,
    64  					utils.LightKDFFlag,
    65  				},
    66  				Description: `
    67  	geth wallet [options] /path/to/my/presale.wallet
    68  
    69  will prompt for your password and imports your ether presale account.
    70  It can be used non-interactively with the --password option taking a
    71  passwordfile as argument containing the wallet password in plaintext.`,
    72  			},
    73  		},
    74  	}
    75  
    76  	accountCommand = cli.Command{
    77  		Name:     "account",
    78  		Usage:    "Manage accounts",
    79  		Category: "ACCOUNT COMMANDS",
    80  		Description: `
    81  
    82  Manage accounts, list all existing accounts, import a private key into a new
    83  account, create a new account or update an existing account.
    84  
    85  It supports interactive mode, when you are prompted for password as well as
    86  non-interactive mode where passwords are supplied via a given password file.
    87  Non-interactive mode is only meant for scripted use on test networks or known
    88  safe environments.
    89  
    90  Make sure you remember the password you gave when creating a new account (with
    91  either new or import). Without it you are not able to unlock your account.
    92  
    93  Note that exporting your key in unencrypted format is NOT supported.
    94  
    95  Keys are stored under <DATADIR>/keystore.
    96  It is safe to transfer the entire directory or the individual keys therein
    97  between ethereum nodes by simply copying.
    98  
    99  Make sure you backup your keys regularly.`,
   100  		Subcommands: []cli.Command{
   101  			{
   102  				Name:   "list",
   103  				Usage:  "Print summary of existing accounts",
   104  				Action: utils.MigrateFlags(accountList),
   105  				Flags: []cli.Flag{
   106  					utils.DataDirFlag,
   107  					utils.KeyStoreDirFlag,
   108  				},
   109  				Description: `
   110  Print a short summary of all accounts`,
   111  			},
   112  			{
   113  				Name:   "new",
   114  				Usage:  "Create a new account",
   115  				Action: utils.MigrateFlags(accountCreate),
   116  				Flags: []cli.Flag{
   117  					utils.DataDirFlag,
   118  					utils.KeyStoreDirFlag,
   119  					utils.PasswordFileFlag,
   120  					utils.LightKDFFlag,
   121  				},
   122  				Description: `
   123      geth account new
   124  
   125  Creates a new account and prints the address.
   126  
   127  The account is saved in encrypted format, you are prompted for a passphrase.
   128  
   129  You must remember this passphrase to unlock your account in the future.
   130  
   131  For non-interactive use the passphrase can be specified with the --password flag:
   132  
   133  Note, this is meant to be used for testing only, it is a bad idea to save your
   134  password to file or expose in any other way.
   135  `,
   136  			},
   137  			{
   138  				Name:      "update",
   139  				Usage:     "Update an existing account",
   140  				Action:    utils.MigrateFlags(accountUpdate),
   141  				ArgsUsage: "<address>",
   142  				Flags: []cli.Flag{
   143  					utils.DataDirFlag,
   144  					utils.KeyStoreDirFlag,
   145  					utils.LightKDFFlag,
   146  				},
   147  				Description: `
   148      geth account update <address>
   149  
   150  Update an existing account.
   151  
   152  The account is saved in the newest version in encrypted format, you are prompted
   153  for a passphrase to unlock the account and another to save the updated file.
   154  
   155  This same command can therefore be used to migrate an account of a deprecated
   156  format to the newest format or change the password for an account.
   157  
   158  For non-interactive use the passphrase can be specified with the --password flag:
   159  
   160      geth account update [options] <address>
   161  
   162  Since only one password can be given, only format update can be performed,
   163  changing your password is only possible interactively.
   164  `,
   165  			},
   166  			{
   167  				Name:   "import",
   168  				Usage:  "Import a private key into a new account",
   169  				Action: utils.MigrateFlags(accountImport),
   170  				Flags: []cli.Flag{
   171  					utils.DataDirFlag,
   172  					utils.KeyStoreDirFlag,
   173  					utils.PasswordFileFlag,
   174  					utils.LightKDFFlag,
   175  				},
   176  				ArgsUsage: "<keyFile>",
   177  				Description: `
   178      geth account import <keyfile>
   179  
   180  Imports an unencrypted private key from <keyfile> and creates a new account.
   181  Prints the address.
   182  
   183  The keyfile is assumed to contain an unencrypted private key in hexadecimal format.
   184  
   185  The account is saved in encrypted format, you are prompted for a passphrase.
   186  
   187  You must remember this passphrase to unlock your account in the future.
   188  
   189  For non-interactive use the passphrase can be specified with the -password flag:
   190  
   191      geth account import [options] <keyfile>
   192  
   193  Note:
   194  As you can directly copy your encrypted accounts to another ethereum instance,
   195  this import mechanism is not needed when you transfer an account between
   196  nodes.
   197  `,
   198  			},
   199  		},
   200  	}
   201  )
   202  
   203  func accountList(ctx *cli.Context) error {
   204  	stack, _ := makeConfigNode(ctx)
   205  	var index int
   206  	for _, wallet := range stack.AccountManager().Wallets() {
   207  		for _, account := range wallet.Accounts() {
   208  			fmt.Printf("Account #%d: {%x} %s\n", index, account.Address, &account.URL)
   209  			index++
   210  		}
   211  	}
   212  	return nil
   213  }
   214  
   215  //尝试解锁指定帐户几次。
   216  func unlockAccount(ctx *cli.Context, ks *keystore.KeyStore, address string, i int, passwords []string) (accounts.Account, string) {
   217  	account, err := utils.MakeAddress(ks, address)
   218  	if err != nil {
   219  		utils.Fatalf("Could not list accounts: %v", err)
   220  	}
   221  	for trials := 0; trials < 3; trials++ {
   222  		prompt := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", address, trials+1, 3)
   223  		password := getPassPhrase(prompt, false, i, passwords)
   224  		err = ks.Unlock(account, password)
   225  		if err == nil {
   226  			log.Info("Unlocked account", "address", account.Address.Hex())
   227  			return account, password
   228  		}
   229  		if err, ok := err.(*keystore.AmbiguousAddrError); ok {
   230  			log.Info("Unlocked account", "address", account.Address.Hex())
   231  			return ambiguousAddrRecovery(ks, err, password), password
   232  		}
   233  		if err != keystore.ErrDecrypt {
   234  //如果错误与解密无关,则无需再次提示。
   235  			break
   236  		}
   237  	}
   238  //所有的审判都是为了解锁账户,救市
   239  	utils.Fatalf("Failed to unlock account %s (%v)", address, err)
   240  
   241  	return accounts.Account{}, ""
   242  }
   243  
   244  //getpassphrase检索与帐户关联的密码,或者获取
   245  //从预加载的密码短语列表中,或从用户交互式请求。
   246  func getPassPhrase(prompt string, confirmation bool, i int, passwords []string) string {
   247  //如果提供了密码列表,请从中检索
   248  	if len(passwords) > 0 {
   249  		if i < len(passwords) {
   250  			return passwords[i]
   251  		}
   252  		return passwords[len(passwords)-1]
   253  	}
   254  //否则提示用户输入密码
   255  	if prompt != "" {
   256  		fmt.Println(prompt)
   257  	}
   258  	password, err := console.Stdin.PromptPassword("Passphrase: ")
   259  	if err != nil {
   260  		utils.Fatalf("Failed to read passphrase: %v", err)
   261  	}
   262  	if confirmation {
   263  		confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ")
   264  		if err != nil {
   265  			utils.Fatalf("Failed to read passphrase confirmation: %v", err)
   266  		}
   267  		if password != confirm {
   268  			utils.Fatalf("Passphrases do not match")
   269  		}
   270  	}
   271  	return password
   272  }
   273  
   274  func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrError, auth string) accounts.Account {
   275  	fmt.Printf("Multiple key files exist for address %x:\n", err.Addr)
   276  	for _, a := range err.Matches {
   277  		fmt.Println("  ", a.URL)
   278  	}
   279  	fmt.Println("Testing your passphrase against all of them...")
   280  	var match *accounts.Account
   281  	for _, a := range err.Matches {
   282  		if err := ks.Unlock(a, auth); err == nil {
   283  			match = &a
   284  			break
   285  		}
   286  	}
   287  	if match == nil {
   288  		utils.Fatalf("None of the listed files could be unlocked.")
   289  	}
   290  	fmt.Printf("Your passphrase unlocked %s\n", match.URL)
   291  	fmt.Println("In order to avoid this warning, you need to remove the following duplicate key files:")
   292  	for _, a := range err.Matches {
   293  		if a != *match {
   294  			fmt.Println("  ", a.URL)
   295  		}
   296  	}
   297  	return *match
   298  }
   299  
   300  //accountcreate在cli标志定义的keystore中创建一个新帐户。
   301  func accountCreate(ctx *cli.Context) error {
   302  	cfg := gethConfig{Node: defaultNodeConfig()}
   303  //加载配置文件。
   304  	if file := ctx.GlobalString(configFileFlag.Name); file != "" {
   305  		if err := loadConfig(file, &cfg); err != nil {
   306  			utils.Fatalf("%v", err)
   307  		}
   308  	}
   309  	utils.SetNodeConfig(ctx, &cfg.Node)
   310  	scryptN, scryptP, keydir, err := cfg.Node.AccountConfig()
   311  
   312  	if err != nil {
   313  		utils.Fatalf("Failed to read configuration: %v", err)
   314  	}
   315  
   316  	password := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx))
   317  
   318  	address, err := keystore.StoreKey(keydir, password, scryptN, scryptP)
   319  
   320  	if err != nil {
   321  		utils.Fatalf("Failed to create account: %v", err)
   322  	}
   323  	fmt.Printf("Address: {%x}\n", address)
   324  	return nil
   325  }
   326  
   327  //accountupdate将帐户从以前的格式转换为当前格式
   328  //第一,也提供了改变通行短语的可能性。
   329  func accountUpdate(ctx *cli.Context) error {
   330  	if len(ctx.Args()) == 0 {
   331  		utils.Fatalf("No accounts specified to update")
   332  	}
   333  	stack, _ := makeConfigNode(ctx)
   334  	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
   335  
   336  	for _, addr := range ctx.Args() {
   337  		account, oldPassword := unlockAccount(ctx, ks, addr, 0, nil)
   338  		newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil)
   339  		if err := ks.Update(account, oldPassword, newPassword); err != nil {
   340  			utils.Fatalf("Could not update the account: %v", err)
   341  		}
   342  	}
   343  	return nil
   344  }
   345  
   346  func importWallet(ctx *cli.Context) error {
   347  	keyfile := ctx.Args().First()
   348  	if len(keyfile) == 0 {
   349  		utils.Fatalf("keyfile must be given as argument")
   350  	}
   351  	keyJSON, err := ioutil.ReadFile(keyfile)
   352  	if err != nil {
   353  		utils.Fatalf("Could not read wallet file: %v", err)
   354  	}
   355  
   356  	stack, _ := makeConfigNode(ctx)
   357  	passphrase := getPassPhrase("", false, 0, utils.MakePasswordList(ctx))
   358  
   359  	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
   360  	acct, err := ks.ImportPreSaleKey(keyJSON, passphrase)
   361  	if err != nil {
   362  		utils.Fatalf("%v", err)
   363  	}
   364  	fmt.Printf("Address: {%x}\n", acct.Address)
   365  	return nil
   366  }
   367  
   368  func accountImport(ctx *cli.Context) error {
   369  	keyfile := ctx.Args().First()
   370  	if len(keyfile) == 0 {
   371  		utils.Fatalf("keyfile must be given as argument")
   372  	}
   373  	key, err := crypto.LoadECDSA(keyfile)
   374  	if err != nil {
   375  		utils.Fatalf("Failed to load the private key: %v", err)
   376  	}
   377  	stack, _ := makeConfigNode(ctx)
   378  	passphrase := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx))
   379  
   380  	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
   381  	acct, err := ks.ImportECDSA(key, passphrase)
   382  	if err != nil {
   383  		utils.Fatalf("Could not create the account: %v", err)
   384  	}
   385  	fmt.Printf("Address: {%x}\n", acct.Address)
   386  	return nil
   387  }