aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/geth
diff options
context:
space:
mode:
authorFelix Lange <fjl@twurst.com>2016-04-02 00:10:58 +0800
committerFelix Lange <fjl@twurst.com>2016-04-12 21:59:18 +0800
commit91aaddaeb38ff25118896fb436a938d14636760b (patch)
tree4cdf271558b1038a83426c4489988fc4a6954851 /cmd/geth
parentea005a02950513603b7346ef39bc76dc53b82863 (diff)
downloadgo-tangerine-91aaddaeb38ff25118896fb436a938d14636760b.tar
go-tangerine-91aaddaeb38ff25118896fb436a938d14636760b.tar.gz
go-tangerine-91aaddaeb38ff25118896fb436a938d14636760b.tar.bz2
go-tangerine-91aaddaeb38ff25118896fb436a938d14636760b.tar.lz
go-tangerine-91aaddaeb38ff25118896fb436a938d14636760b.tar.xz
go-tangerine-91aaddaeb38ff25118896fb436a938d14636760b.tar.zst
go-tangerine-91aaddaeb38ff25118896fb436a938d14636760b.zip
cmd/geth: add recovery procedure for AmbiguousAddrError
Diffstat (limited to 'cmd/geth')
-rw-r--r--cmd/geth/accountcmd.go37
-rw-r--r--cmd/geth/accountcmd_test.go62
-rw-r--r--cmd/geth/run_test.go10
3 files changed, 107 insertions, 2 deletions
diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go
index 86175d05f..0bd60d701 100644
--- a/cmd/geth/accountcmd.go
+++ b/cmd/geth/accountcmd.go
@@ -181,10 +181,19 @@ func unlockAccount(ctx *cli.Context, accman *accounts.Manager, address string, i
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)
- if err = accman.Unlock(account, password); err == nil {
+ err = accman.Unlock(account, password)
+ if err == nil {
glog.V(logger.Info).Infof("Unlocked account %x", account.Address)
return account, password
}
+ if err, ok := err.(*accounts.AmbiguousAddrError); ok {
+ glog.V(logger.Info).Infof("Unlocked account %x", account.Address)
+ return ambiguousAddrRecovery(accman, err, password), password
+ }
+ if err != accounts.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)
@@ -221,6 +230,32 @@ func getPassPhrase(prompt string, confirmation bool, i int, passwords []string)
return password
}
+func ambiguousAddrRecovery(am *accounts.Manager, err *accounts.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.File)
+ }
+ fmt.Println("Testing your passphrase against all of them...")
+ var match *accounts.Account
+ for _, a := range err.Matches {
+ if err := am.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.File)
+ 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.File)
+ }
+ }
+ return *match
+}
+
// accountCreate creates a new account into the keystore defined by the CLI flags.
func accountCreate(ctx *cli.Context) {
accman := utils.MakeAccountManager(ctx)
diff --git a/cmd/geth/accountcmd_test.go b/cmd/geth/accountcmd_test.go
index 440a0cb0b..b6abde6d8 100644
--- a/cmd/geth/accountcmd_test.go
+++ b/cmd/geth/accountcmd_test.go
@@ -228,3 +228,65 @@ func TestUnlockFlagPasswordFileWrongPassword(t *testing.T) {
Fatal: Failed to unlock account 0 (could not decrypt key with given passphrase)
`)
}
+
+func TestUnlockFlagAmbiguous(t *testing.T) {
+ store := filepath.Join("..", "..", "accounts", "testdata", "dupes")
+ geth := runGeth(t,
+ "--keystore", store, "--nat", "none", "--nodiscover", "--dev",
+ "--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:
+ {{keypath "1"}}
+ {{keypath "2"}}
+Testing your passphrase against all of them...
+Your passphrase unlocked {{keypath "1"}}
+In order to avoid this warning, you need to remove the following duplicate key files:
+ {{keypath "2"}}
+`)
+ geth.expectExit()
+
+ wantMessages := []string{
+ "Unlocked account f466859ead1932d743d622cb74fc058882e8648a",
+ }
+ for _, m := range wantMessages {
+ if strings.Index(geth.stderrText(), m) == -1 {
+ t.Errorf("stderr text does not contain %q", m)
+ }
+ }
+}
+
+func TestUnlockFlagAmbiguousWrongPassword(t *testing.T) {
+ store := filepath.Join("..", "..", "accounts", "testdata", "dupes")
+ geth := runGeth(t,
+ "--keystore", store, "--nat", "none", "--nodiscover", "--dev",
+ "--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:
+ {{keypath "1"}}
+ {{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/run_test.go b/cmd/geth/run_test.go
index a15d0bf28..a82eb9d68 100644
--- a/cmd/geth/run_test.go
+++ b/cmd/geth/run_test.go
@@ -45,6 +45,7 @@ type testgeth struct {
// template variables for expect
Datadir string
Executable string
+ Func template.FuncMap
removeDatadir bool
cmd *exec.Cmd
@@ -114,6 +115,13 @@ func (tt *testgeth) InputLine(s string) string {
return ""
}
+func (tt *testgeth) setTemplateFunc(name string, fn interface{}) {
+ if tt.Func == nil {
+ tt.Func = make(map[string]interface{})
+ }
+ tt.Func[name] = fn
+}
+
// expect runs its argument as a template, then expects the
// child process to output the result of the template within 5s.
//
@@ -121,7 +129,7 @@ func (tt *testgeth) InputLine(s string) string {
// before matching.
func (tt *testgeth) expect(tplsource string) {
// Generate the expected output by running the template.
- tpl := template.Must(template.New("").Parse(tplsource))
+ tpl := template.Must(template.New("").Funcs(tt.Func).Parse(tplsource))
wantbuf := new(bytes.Buffer)
if err := tpl.Execute(wantbuf, tt); err != nil {
panic(err)