github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/cmd/geth/accountcmd.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "fmt" 21 "io/ioutil" 22 23 "gopkg.in/urfave/cli.v1" 24 25 "github.com/scroll-tech/go-ethereum/accounts" 26 "github.com/scroll-tech/go-ethereum/accounts/keystore" 27 "github.com/scroll-tech/go-ethereum/cmd/utils" 28 "github.com/scroll-tech/go-ethereum/crypto" 29 "github.com/scroll-tech/go-ethereum/log" 30 ) 31 32 var ( 33 walletCommand = cli.Command{ 34 Name: "wallet", 35 Usage: "Manage Ethereum presale wallets", 36 ArgsUsage: "", 37 Category: "ACCOUNT COMMANDS", 38 Description: ` 39 geth wallet import /path/to/my/presale.wallet 40 41 will prompt for your password and imports your ether presale account. 42 It can be used non-interactively with the --password option taking a 43 passwordfile as argument containing the wallet password in plaintext.`, 44 Subcommands: []cli.Command{ 45 { 46 47 Name: "import", 48 Usage: "Import Ethereum presale wallet", 49 ArgsUsage: "<keyFile>", 50 Action: utils.MigrateFlags(importWallet), 51 Category: "ACCOUNT COMMANDS", 52 Flags: []cli.Flag{ 53 utils.DataDirFlag, 54 utils.KeyStoreDirFlag, 55 utils.PasswordFileFlag, 56 utils.LightKDFFlag, 57 }, 58 Description: ` 59 geth wallet [options] /path/to/my/presale.wallet 60 61 will prompt for your password and imports your ether presale account. 62 It can be used non-interactively with the --password option taking a 63 passwordfile as argument containing the wallet password in plaintext.`, 64 }, 65 }, 66 } 67 68 accountCommand = cli.Command{ 69 Name: "account", 70 Usage: "Manage accounts", 71 Category: "ACCOUNT COMMANDS", 72 Description: ` 73 74 Manage accounts, list all existing accounts, import a private key into a new 75 account, create a new account or update an existing account. 76 77 It supports interactive mode, when you are prompted for password as well as 78 non-interactive mode where passwords are supplied via a given password file. 79 Non-interactive mode is only meant for scripted use on test networks or known 80 safe environments. 81 82 Make sure you remember the password you gave when creating a new account (with 83 either new or import). Without it you are not able to unlock your account. 84 85 Note that exporting your key in unencrypted format is NOT supported. 86 87 Keys are stored under <DATADIR>/keystore. 88 It is safe to transfer the entire directory or the individual keys therein 89 between ethereum nodes by simply copying. 90 91 Make sure you backup your keys regularly.`, 92 Subcommands: []cli.Command{ 93 { 94 Name: "list", 95 Usage: "Print summary of existing accounts", 96 Action: utils.MigrateFlags(accountList), 97 Flags: []cli.Flag{ 98 utils.DataDirFlag, 99 utils.KeyStoreDirFlag, 100 }, 101 Description: ` 102 Print a short summary of all accounts`, 103 }, 104 { 105 Name: "new", 106 Usage: "Create a new account", 107 Action: utils.MigrateFlags(accountCreate), 108 Flags: []cli.Flag{ 109 utils.DataDirFlag, 110 utils.KeyStoreDirFlag, 111 utils.PasswordFileFlag, 112 utils.LightKDFFlag, 113 }, 114 Description: ` 115 geth account new 116 117 Creates a new account and prints the address. 118 119 The account is saved in encrypted format, you are prompted for a password. 120 121 You must remember this password to unlock your account in the future. 122 123 For non-interactive use the password can be specified with the --password flag: 124 125 Note, this is meant to be used for testing only, it is a bad idea to save your 126 password to file or expose in any other way. 127 `, 128 }, 129 { 130 Name: "update", 131 Usage: "Update an existing account", 132 Action: utils.MigrateFlags(accountUpdate), 133 ArgsUsage: "<address>", 134 Flags: []cli.Flag{ 135 utils.DataDirFlag, 136 utils.KeyStoreDirFlag, 137 utils.LightKDFFlag, 138 }, 139 Description: ` 140 geth account update <address> 141 142 Update an existing account. 143 144 The account is saved in the newest version in encrypted format, you are prompted 145 for a password to unlock the account and another to save the updated file. 146 147 This same command can therefore be used to migrate an account of a deprecated 148 format to the newest format or change the password for an account. 149 150 For non-interactive use the password can be specified with the --password flag: 151 152 geth account update [options] <address> 153 154 Since only one password can be given, only format update can be performed, 155 changing your password is only possible interactively. 156 `, 157 }, 158 { 159 Name: "import", 160 Usage: "Import a private key into a new account", 161 Action: utils.MigrateFlags(accountImport), 162 Flags: []cli.Flag{ 163 utils.DataDirFlag, 164 utils.KeyStoreDirFlag, 165 utils.PasswordFileFlag, 166 utils.LightKDFFlag, 167 }, 168 ArgsUsage: "<keyFile>", 169 Description: ` 170 geth account import <keyfile> 171 172 Imports an unencrypted private key from <keyfile> and creates a new account. 173 Prints the address. 174 175 The keyfile is assumed to contain an unencrypted private key in hexadecimal format. 176 177 The account is saved in encrypted format, you are prompted for a password. 178 179 You must remember this password to unlock your account in the future. 180 181 For non-interactive use the password can be specified with the -password flag: 182 183 geth account import [options] <keyfile> 184 185 Note: 186 As you can directly copy your encrypted accounts to another ethereum instance, 187 this import mechanism is not needed when you transfer an account between 188 nodes. 189 `, 190 }, 191 }, 192 } 193 ) 194 195 func accountList(ctx *cli.Context) error { 196 stack, _ := makeConfigNode(ctx) 197 var index int 198 for _, wallet := range stack.AccountManager().Wallets() { 199 for _, account := range wallet.Accounts() { 200 fmt.Printf("Account #%d: {%x} %s\n", index, account.Address, &account.URL) 201 index++ 202 } 203 } 204 return nil 205 } 206 207 // tries unlocking the specified account a few times. 208 func unlockAccount(ks *keystore.KeyStore, address string, i int, passwords []string) (accounts.Account, string) { 209 account, err := utils.MakeAddress(ks, address) 210 if err != nil { 211 utils.Fatalf("Could not list accounts: %v", err) 212 } 213 for trials := 0; trials < 3; trials++ { 214 prompt := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", address, trials+1, 3) 215 password := utils.GetPassPhraseWithList(prompt, false, i, passwords) 216 err = ks.Unlock(account, password) 217 if err == nil { 218 log.Info("Unlocked account", "address", account.Address.Hex()) 219 return account, password 220 } 221 if err, ok := err.(*keystore.AmbiguousAddrError); ok { 222 log.Info("Unlocked account", "address", account.Address.Hex()) 223 return ambiguousAddrRecovery(ks, err, password), password 224 } 225 if err != keystore.ErrDecrypt { 226 // No need to prompt again if the error is not decryption-related. 227 break 228 } 229 } 230 // All trials expended to unlock account, bail out 231 utils.Fatalf("Failed to unlock account %s (%v)", address, err) 232 233 return accounts.Account{}, "" 234 } 235 236 func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrError, auth string) accounts.Account { 237 fmt.Printf("Multiple key files exist for address %x:\n", err.Addr) 238 for _, a := range err.Matches { 239 fmt.Println(" ", a.URL) 240 } 241 fmt.Println("Testing your password against all of them...") 242 var match *accounts.Account 243 for _, a := range err.Matches { 244 if err := ks.Unlock(a, auth); err == nil { 245 match = &a 246 break 247 } 248 } 249 if match == nil { 250 utils.Fatalf("None of the listed files could be unlocked.") 251 } 252 fmt.Printf("Your password unlocked %s\n", match.URL) 253 fmt.Println("In order to avoid this warning, you need to remove the following duplicate key files:") 254 for _, a := range err.Matches { 255 if a != *match { 256 fmt.Println(" ", a.URL) 257 } 258 } 259 return *match 260 } 261 262 // accountCreate creates a new account into the keystore defined by the CLI flags. 263 func accountCreate(ctx *cli.Context) error { 264 cfg := gethConfig{Node: defaultNodeConfig()} 265 // Load config file. 266 if file := ctx.GlobalString(configFileFlag.Name); file != "" { 267 if err := loadConfig(file, &cfg); err != nil { 268 utils.Fatalf("%v", err) 269 } 270 } 271 utils.SetNodeConfig(ctx, &cfg.Node) 272 keydir, err := cfg.Node.KeyDirConfig() 273 if err != nil { 274 utils.Fatalf("Failed to read configuration: %v", err) 275 } 276 scryptN := keystore.StandardScryptN 277 scryptP := keystore.StandardScryptP 278 if cfg.Node.UseLightweightKDF { 279 scryptN = keystore.LightScryptN 280 scryptP = keystore.LightScryptP 281 } 282 283 password := utils.GetPassPhraseWithList("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) 284 285 account, err := keystore.StoreKey(keydir, password, scryptN, scryptP) 286 287 if err != nil { 288 utils.Fatalf("Failed to create account: %v", err) 289 } 290 fmt.Printf("\nYour new key was generated\n\n") 291 fmt.Printf("Public address of the key: %s\n", account.Address.Hex()) 292 fmt.Printf("Path of the secret key file: %s\n\n", account.URL.Path) 293 fmt.Printf("- You can share your public address with anyone. Others need it to interact with you.\n") 294 fmt.Printf("- You must NEVER share the secret key with anyone! The key controls access to your funds!\n") 295 fmt.Printf("- You must BACKUP your key file! Without the key, it's impossible to access account funds!\n") 296 fmt.Printf("- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!\n\n") 297 return nil 298 } 299 300 // accountUpdate transitions an account from a previous format to the current 301 // one, also providing the possibility to change the pass-phrase. 302 func accountUpdate(ctx *cli.Context) error { 303 if len(ctx.Args()) == 0 { 304 utils.Fatalf("No accounts specified to update") 305 } 306 stack, _ := makeConfigNode(ctx) 307 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 308 309 for _, addr := range ctx.Args() { 310 account, oldPassword := unlockAccount(ks, addr, 0, nil) 311 newPassword := utils.GetPassPhraseWithList("Please give a new password. Do not forget this password.", true, 0, nil) 312 if err := ks.Update(account, oldPassword, newPassword); err != nil { 313 utils.Fatalf("Could not update the account: %v", err) 314 } 315 } 316 return nil 317 } 318 319 func importWallet(ctx *cli.Context) error { 320 keyfile := ctx.Args().First() 321 if len(keyfile) == 0 { 322 utils.Fatalf("keyfile must be given as argument") 323 } 324 keyJSON, err := ioutil.ReadFile(keyfile) 325 if err != nil { 326 utils.Fatalf("Could not read wallet file: %v", err) 327 } 328 329 stack, _ := makeConfigNode(ctx) 330 passphrase := utils.GetPassPhraseWithList("", false, 0, utils.MakePasswordList(ctx)) 331 332 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 333 acct, err := ks.ImportPreSaleKey(keyJSON, passphrase) 334 if err != nil { 335 utils.Fatalf("%v", err) 336 } 337 fmt.Printf("Address: {%x}\n", acct.Address) 338 return nil 339 } 340 341 func accountImport(ctx *cli.Context) error { 342 keyfile := ctx.Args().First() 343 if len(keyfile) == 0 { 344 utils.Fatalf("keyfile must be given as argument") 345 } 346 key, err := crypto.LoadECDSA(keyfile) 347 if err != nil { 348 utils.Fatalf("Failed to load the private key: %v", err) 349 } 350 stack, _ := makeConfigNode(ctx) 351 passphrase := utils.GetPassPhraseWithList("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx)) 352 353 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 354 acct, err := ks.ImportECDSA(key, passphrase) 355 if err != nil { 356 utils.Fatalf("Could not create the account: %v", err) 357 } 358 fmt.Printf("Address: {%x}\n", acct.Address) 359 return nil 360 }