diff options
author | Felix Lange <fjl@twurst.com> | 2016-04-02 00:10:58 +0800 |
---|---|---|
committer | Felix Lange <fjl@twurst.com> | 2016-04-12 21:59:18 +0800 |
commit | 91aaddaeb38ff25118896fb436a938d14636760b (patch) | |
tree | 4cdf271558b1038a83426c4489988fc4a6954851 /cmd | |
parent | ea005a02950513603b7346ef39bc76dc53b82863 (diff) | |
download | dexon-91aaddaeb38ff25118896fb436a938d14636760b.tar.gz dexon-91aaddaeb38ff25118896fb436a938d14636760b.tar.zst dexon-91aaddaeb38ff25118896fb436a938d14636760b.zip |
cmd/geth: add recovery procedure for AmbiguousAddrError
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/geth/accountcmd.go | 37 | ||||
-rw-r--r-- | cmd/geth/accountcmd_test.go | 62 | ||||
-rw-r--r-- | cmd/geth/run_test.go | 10 |
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) |