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 }