2016-03-17 12:09:18 +00:00
// 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/>.
2023-06-13 15:22:32 +00:00
package geth
2016-03-17 12:09:18 +00:00
import (
"fmt"
2022-05-16 09:59:35 +00:00
"os"
2016-03-17 12:09:18 +00:00
"github.com/ethereum/go-ethereum/accounts"
2017-01-24 09:49:20 +00:00
"github.com/ethereum/go-ethereum/accounts/keystore"
2016-03-17 12:09:18 +00:00
"github.com/ethereum/go-ethereum/cmd/utils"
2016-04-04 23:08:50 +00:00
"github.com/ethereum/go-ethereum/crypto"
2017-02-22 12:10:07 +00:00
"github.com/ethereum/go-ethereum/log"
2022-06-27 16:22:36 +00:00
"github.com/urfave/cli/v2"
2016-03-17 12:09:18 +00:00
)
var (
2022-06-27 16:22:36 +00:00
walletCommand = & cli . Command {
2017-05-23 15:45:26 +00:00
Name : "wallet" ,
Usage : "Manage Ethereum presale wallets" ,
ArgsUsage : "" ,
2016-03-17 12:09:18 +00:00
Description : `
2017-05-23 15:45:26 +00:00
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 . ` ,
2022-06-27 16:22:36 +00:00
Subcommands : [ ] * cli . Command {
2017-05-23 15:45:26 +00:00
{
2016-03-17 12:09:18 +00:00
2017-05-23 15:45:26 +00:00
Name : "import" ,
Usage : "Import Ethereum presale wallet" ,
ArgsUsage : "<keyFile>" ,
2022-06-27 16:22:36 +00:00
Action : importWallet ,
2017-05-23 15:45:26 +00:00
Flags : [ ] cli . Flag {
utils . DataDirFlag ,
utils . KeyStoreDirFlag ,
utils . PasswordFileFlag ,
utils . LightKDFFlag ,
} ,
Description : `
geth wallet [ options ] / path / to / my / presale . wallet
2016-03-17 12:09:18 +00:00
2017-05-23 15:45:26 +00:00
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 . ` ,
} ,
} ,
2016-11-10 11:00:09 +00:00
}
2017-05-23 15:45:26 +00:00
2022-06-27 16:22:36 +00:00
accountCommand = & cli . Command {
Name : "account" ,
Usage : "Manage accounts" ,
2016-03-17 12:09:18 +00:00
Description : `
2017-04-28 10:38:49 +00:00
Manage accounts , list all existing accounts , import a private key into a new
account , create a new account or update an existing account .
2016-03-17 12:09:18 +00:00
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 .
2016-06-08 14:00:18 +00:00
Keys are stored under < DATADIR > / keystore .
2016-03-17 12:09:18 +00:00
It is safe to transfer the entire directory or the individual keys therein
between ethereum nodes by simply copying .
2017-04-28 10:38:49 +00:00
Make sure you backup your keys regularly . ` ,
2022-06-27 16:22:36 +00:00
Subcommands : [ ] * cli . Command {
2016-03-17 12:09:18 +00:00
{
2017-04-28 10:38:49 +00:00
Name : "list" ,
Usage : "Print summary of existing accounts" ,
2022-06-27 16:22:36 +00:00
Action : accountList ,
2017-04-28 10:38:49 +00:00
Flags : [ ] cli . Flag {
utils . DataDirFlag ,
utils . KeyStoreDirFlag ,
} ,
2016-11-10 11:00:09 +00:00
Description : `
2017-04-28 10:38:49 +00:00
Print a short summary of all accounts ` ,
2016-03-17 12:09:18 +00:00
} ,
{
2017-04-28 10:38:49 +00:00
Name : "new" ,
Usage : "Create a new account" ,
2022-06-27 16:22:36 +00:00
Action : accountCreate ,
2017-04-28 10:38:49 +00:00
Flags : [ ] cli . Flag {
utils . DataDirFlag ,
utils . KeyStoreDirFlag ,
utils . PasswordFileFlag ,
utils . LightKDFFlag ,
} ,
2016-03-17 12:09:18 +00:00
Description : `
2016-11-10 11:00:09 +00:00
geth account new
2016-03-17 12:09:18 +00:00
2017-04-28 10:38:49 +00:00
Creates a new account and prints the address .
2016-03-17 12:09:18 +00:00
2019-08-12 09:00:38 +00:00
The account is saved in encrypted format , you are prompted for a password .
2016-03-17 12:09:18 +00:00
2019-08-12 09:00:38 +00:00
You must remember this password to unlock your account in the future .
2016-03-17 12:09:18 +00:00
2019-08-12 09:00:38 +00:00
For non - interactive use the password can be specified with the -- password flag :
2016-03-17 12:09:18 +00:00
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 .
2016-11-10 11:00:09 +00:00
` ,
2016-03-17 12:09:18 +00:00
} ,
{
2016-11-10 11:00:09 +00:00
Name : "update" ,
Usage : "Update an existing account" ,
2022-06-27 16:22:36 +00:00
Action : accountUpdate ,
2016-11-10 11:00:09 +00:00
ArgsUsage : "<address>" ,
2017-04-28 10:38:49 +00:00
Flags : [ ] cli . Flag {
utils . DataDirFlag ,
utils . KeyStoreDirFlag ,
utils . LightKDFFlag ,
} ,
2016-03-17 12:09:18 +00:00
Description : `
2016-11-10 11:00:09 +00:00
geth account update < address >
2016-03-17 12:09:18 +00:00
Update an existing account .
The account is saved in the newest version in encrypted format , you are prompted
2019-08-12 09:00:38 +00:00
for a password to unlock the account and another to save the updated file .
2016-03-17 12:09:18 +00:00
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 .
2019-08-12 09:00:38 +00:00
For non - interactive use the password can be specified with the -- password flag :
2016-03-17 12:09:18 +00:00
2017-04-28 10:38:49 +00:00
geth account update [ options ] < address >
2016-03-17 12:09:18 +00:00
Since only one password can be given , only format update can be performed ,
changing your password is only possible interactively .
2016-11-10 11:00:09 +00:00
` ,
2016-03-17 12:09:18 +00:00
} ,
{
2017-04-28 10:38:49 +00:00
Name : "import" ,
Usage : "Import a private key into a new account" ,
2022-06-27 16:22:36 +00:00
Action : accountImport ,
2017-04-28 10:38:49 +00:00
Flags : [ ] cli . Flag {
utils . DataDirFlag ,
utils . KeyStoreDirFlag ,
utils . PasswordFileFlag ,
utils . LightKDFFlag ,
} ,
2016-11-10 11:00:09 +00:00
ArgsUsage : "<keyFile>" ,
2016-03-17 12:09:18 +00:00
Description : `
2016-11-10 11:00:09 +00:00
geth account import < keyfile >
2016-03-17 12:09:18 +00:00
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 .
2019-08-12 09:00:38 +00:00
The account is saved in encrypted format , you are prompted for a password .
2016-03-17 12:09:18 +00:00
2019-08-12 09:00:38 +00:00
You must remember this password to unlock your account in the future .
2016-03-17 12:09:18 +00:00
2019-08-12 09:00:38 +00:00
For non - interactive use the password can be specified with the - password flag :
2016-03-17 12:09:18 +00:00
2017-04-28 10:38:49 +00:00
geth account import [ options ] < keyfile >
2016-03-17 12:09:18 +00:00
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 .
2016-11-10 11:00:09 +00:00
` ,
2016-03-17 12:09:18 +00:00
} ,
} ,
}
)
2016-06-10 08:23:00 +00:00
func accountList ( ctx * cli . Context ) error {
2017-04-12 14:27:23 +00:00
stack , _ := makeConfigNode ( ctx )
2017-02-07 10:47:34 +00:00
var index int
for _ , wallet := range stack . AccountManager ( ) . Wallets ( ) {
for _ , account := range wallet . Accounts ( ) {
2017-02-08 13:53:02 +00:00
fmt . Printf ( "Account #%d: {%x} %s\n" , index , account . Address , & account . URL )
2017-02-07 10:47:34 +00:00
index ++
}
2016-03-17 12:09:18 +00:00
}
2016-06-10 08:23:00 +00:00
return nil
2016-03-17 12:09:18 +00:00
}
// tries unlocking the specified account a few times.
2019-04-04 11:03:10 +00:00
func unlockAccount ( ks * keystore . KeyStore , address string , i int , passwords [ ] string ) ( accounts . Account , string ) {
2017-01-24 09:49:20 +00:00
account , err := utils . MakeAddress ( ks , address )
2016-03-17 12:09:18 +00:00
if err != nil {
2017-02-22 15:22:50 +00:00
utils . Fatalf ( "Could not list accounts: %v" , err )
2016-03-17 12:09:18 +00:00
}
for trials := 0 ; trials < 3 ; trials ++ {
prompt := fmt . Sprintf ( "Unlocking account %s | Attempt %d/%d" , address , trials + 1 , 3 )
2020-06-30 07:56:40 +00:00
password := utils . GetPassPhraseWithList ( prompt , false , i , passwords )
2017-01-24 09:49:20 +00:00
err = ks . Unlock ( account , password )
2016-04-01 16:10:58 +00:00
if err == nil {
2017-02-22 14:58:00 +00:00
log . Info ( "Unlocked account" , "address" , account . Address . Hex ( ) )
2016-03-17 12:09:18 +00:00
return account , password
}
2017-01-24 09:49:20 +00:00
if err , ok := err . ( * keystore . AmbiguousAddrError ) ; ok {
2017-02-22 14:58:00 +00:00
log . Info ( "Unlocked account" , "address" , account . Address . Hex ( ) )
2017-01-24 09:49:20 +00:00
return ambiguousAddrRecovery ( ks , err , password ) , password
2016-04-01 16:10:58 +00:00
}
2017-01-24 09:49:20 +00:00
if err != keystore . ErrDecrypt {
2016-04-01 16:10:58 +00:00
// No need to prompt again if the error is not decryption-related.
break
}
2016-03-17 12:09:18 +00:00
}
// All trials expended to unlock account, bail out
2017-02-22 15:22:50 +00:00
utils . Fatalf ( "Failed to unlock account %s (%v)" , address , err )
2017-02-22 12:10:07 +00:00
2016-03-03 00:09:16 +00:00
return accounts . Account { } , ""
2016-03-17 12:09:18 +00:00
}
2017-01-24 09:49:20 +00:00
func ambiguousAddrRecovery ( ks * keystore . KeyStore , err * keystore . AmbiguousAddrError , auth string ) accounts . Account {
2016-04-01 16:10:58 +00:00
fmt . Printf ( "Multiple key files exist for address %x:\n" , err . Addr )
for _ , a := range err . Matches {
2017-01-24 09:49:20 +00:00
fmt . Println ( " " , a . URL )
2016-04-01 16:10:58 +00:00
}
2019-08-12 09:00:38 +00:00
fmt . Println ( "Testing your password against all of them..." )
2016-04-01 16:10:58 +00:00
var match * accounts . Account
2022-06-13 14:24:45 +00:00
for i , a := range err . Matches {
if e := ks . Unlock ( a , auth ) ; e == nil {
match = & err . Matches [ i ]
2016-04-01 16:10:58 +00:00
break
}
}
if match == nil {
2017-02-22 15:22:50 +00:00
utils . Fatalf ( "None of the listed files could be unlocked." )
2022-06-13 14:24:45 +00:00
return accounts . Account { }
2016-04-01 16:10:58 +00:00
}
2019-08-12 09:00:38 +00:00
fmt . Printf ( "Your password unlocked %s\n" , match . URL )
2016-04-01 16:10:58 +00:00
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 {
2017-01-24 09:49:20 +00:00
fmt . Println ( " " , a . URL )
2016-04-01 16:10:58 +00:00
}
}
return * match
}
2016-03-17 12:09:18 +00:00
// accountCreate creates a new account into the keystore defined by the CLI flags.
2016-06-10 08:23:00 +00:00
func accountCreate ( ctx * cli . Context ) error {
2017-11-20 16:39:53 +00:00
cfg := gethConfig { Node : defaultNodeConfig ( ) }
// Load config file.
2022-06-27 16:22:36 +00:00
if file := ctx . String ( configFileFlag . Name ) ; file != "" {
2017-11-20 16:39:53 +00:00
if err := loadConfig ( file , & cfg ) ; err != nil {
utils . Fatalf ( "%v" , err )
}
}
utils . SetNodeConfig ( ctx , & cfg . Node )
2021-08-25 20:34:22 +00:00
keydir , err := cfg . Node . KeyDirConfig ( )
2017-11-20 16:39:53 +00:00
if err != nil {
utils . Fatalf ( "Failed to read configuration: %v" , err )
}
2021-08-25 20:34:22 +00:00
scryptN := keystore . StandardScryptN
scryptP := keystore . StandardScryptP
if cfg . Node . UseLightweightKDF {
scryptN = keystore . LightScryptN
scryptP = keystore . LightScryptP
}
2017-11-20 16:39:53 +00:00
2020-06-30 07:56:40 +00:00
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 ) )
2016-03-17 12:09:18 +00:00
2019-05-07 12:49:51 +00:00
account , err := keystore . StoreKey ( keydir , password , scryptN , scryptP )
2017-11-20 16:39:53 +00:00
2016-03-17 12:09:18 +00:00
if err != nil {
2017-02-22 15:22:50 +00:00
utils . Fatalf ( "Failed to create account: %v" , err )
2016-03-17 12:09:18 +00:00
}
2019-05-07 12:49:51 +00:00
fmt . Printf ( "\nYour new key was generated\n\n" )
fmt . Printf ( "Public address of the key: %s\n" , account . Address . Hex ( ) )
fmt . Printf ( "Path of the secret key file: %s\n\n" , account . URL . Path )
fmt . Printf ( "- You can share your public address with anyone. Others need it to interact with you.\n" )
fmt . Printf ( "- You must NEVER share the secret key with anyone! The key controls access to your funds!\n" )
fmt . Printf ( "- You must BACKUP your key file! Without the key, it's impossible to access account funds!\n" )
fmt . Printf ( "- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!\n\n" )
2016-06-10 08:23:00 +00:00
return nil
2016-03-17 12:09:18 +00:00
}
// accountUpdate transitions an account from a previous format to the current
// one, also providing the possibility to change the pass-phrase.
2016-06-10 08:23:00 +00:00
func accountUpdate ( ctx * cli . Context ) error {
2022-06-27 16:22:36 +00:00
if ctx . Args ( ) . Len ( ) == 0 {
2017-02-22 15:22:50 +00:00
utils . Fatalf ( "No accounts specified to update" )
2016-03-17 12:09:18 +00:00
}
2017-04-12 14:27:23 +00:00
stack , _ := makeConfigNode ( ctx )
2023-04-03 09:08:06 +00:00
backends := stack . AccountManager ( ) . Backends ( keystore . KeyStoreType )
if len ( backends ) == 0 {
utils . Fatalf ( "Keystore is not available" )
}
ks := backends [ 0 ] . ( * keystore . KeyStore )
2017-01-24 09:49:20 +00:00
2022-06-27 16:22:36 +00:00
for _ , addr := range ctx . Args ( ) . Slice ( ) {
2019-04-04 11:03:10 +00:00
account , oldPassword := unlockAccount ( ks , addr , 0 , nil )
2020-06-30 07:56:40 +00:00
newPassword := utils . GetPassPhraseWithList ( "Please give a new password. Do not forget this password." , true , 0 , nil )
2017-04-28 10:38:49 +00:00
if err := ks . Update ( account , oldPassword , newPassword ) ; err != nil {
utils . Fatalf ( "Could not update the account: %v" , err )
}
2016-03-17 12:09:18 +00:00
}
2016-06-10 08:23:00 +00:00
return nil
2016-03-17 12:09:18 +00:00
}
2016-06-10 08:23:00 +00:00
func importWallet ( ctx * cli . Context ) error {
2022-06-27 16:22:36 +00:00
if ctx . Args ( ) . Len ( ) != 1 {
utils . Fatalf ( "keyfile must be given as the only argument" )
2016-03-17 12:09:18 +00:00
}
2022-06-27 16:22:36 +00:00
keyfile := ctx . Args ( ) . First ( )
2022-05-16 09:59:35 +00:00
keyJSON , err := os . ReadFile ( keyfile )
2016-03-17 12:09:18 +00:00
if err != nil {
2017-02-22 15:22:50 +00:00
utils . Fatalf ( "Could not read wallet file: %v" , err )
2016-03-17 12:09:18 +00:00
}
2017-04-12 14:27:23 +00:00
stack , _ := makeConfigNode ( ctx )
2020-06-30 07:56:40 +00:00
passphrase := utils . GetPassPhraseWithList ( "" , false , 0 , utils . MakePasswordList ( ctx ) )
2017-01-24 09:49:20 +00:00
2023-04-03 09:08:06 +00:00
backends := stack . AccountManager ( ) . Backends ( keystore . KeyStoreType )
if len ( backends ) == 0 {
utils . Fatalf ( "Keystore is not available" )
}
ks := backends [ 0 ] . ( * keystore . KeyStore )
2018-05-09 07:38:03 +00:00
acct , err := ks . ImportPreSaleKey ( keyJSON , passphrase )
2016-03-17 12:09:18 +00:00
if err != nil {
2017-02-22 15:22:50 +00:00
utils . Fatalf ( "%v" , err )
2016-03-17 12:09:18 +00:00
}
2016-03-03 00:15:42 +00:00
fmt . Printf ( "Address: {%x}\n" , acct . Address )
2016-06-10 08:23:00 +00:00
return nil
2016-03-17 12:09:18 +00:00
}
2016-06-10 08:23:00 +00:00
func accountImport ( ctx * cli . Context ) error {
2022-06-27 16:22:36 +00:00
if ctx . Args ( ) . Len ( ) != 1 {
utils . Fatalf ( "keyfile must be given as the only argument" )
2016-03-17 12:09:18 +00:00
}
2022-06-27 16:22:36 +00:00
keyfile := ctx . Args ( ) . First ( )
2016-04-04 23:08:50 +00:00
key , err := crypto . LoadECDSA ( keyfile )
if err != nil {
2017-02-22 15:22:50 +00:00
utils . Fatalf ( "Failed to load the private key: %v" , err )
2016-04-04 23:08:50 +00:00
}
2017-04-12 14:27:23 +00:00
stack , _ := makeConfigNode ( ctx )
2020-06-30 07:56:40 +00:00
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 ) )
2017-01-24 09:49:20 +00:00
2023-04-03 09:08:06 +00:00
backends := stack . AccountManager ( ) . Backends ( keystore . KeyStoreType )
if len ( backends ) == 0 {
utils . Fatalf ( "Keystore is not available" )
}
ks := backends [ 0 ] . ( * keystore . KeyStore )
2017-01-24 09:49:20 +00:00
acct , err := ks . ImportECDSA ( key , passphrase )
2016-03-17 12:09:18 +00:00
if err != nil {
2017-02-22 15:22:50 +00:00
utils . Fatalf ( "Could not create the account: %v" , err )
2016-03-17 12:09:18 +00:00
}
2016-03-03 00:15:42 +00:00
fmt . Printf ( "Address: {%x}\n" , acct . Address )
2016-06-10 08:23:00 +00:00
return nil
2016-03-17 12:09:18 +00:00
}