aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2017-02-09 09:28:22 +0800
committerPéter Szilágyi <peterke@gmail.com>2017-02-13 20:00:10 +0800
commitfb1984685562479bfe2b041ae98f901525d1d9d3 (patch)
treed8f8fcc896ae6b6d93292e20a4594ea92c9074e2
parent205ea9580215cca4093dff22ec61222bc3a6ff96 (diff)
downloadgo-tangerine-fb1984685562479bfe2b041ae98f901525d1d9d3.tar.gz
go-tangerine-fb1984685562479bfe2b041ae98f901525d1d9d3.tar.zst
go-tangerine-fb1984685562479bfe2b041ae98f901525d1d9d3.zip
accounts/usbwallet: Ledger teardown on health-check failure
-rw-r--r--accounts/usbwallet/ledger_hub.go8
-rw-r--r--accounts/usbwallet/ledger_wallet.go33
2 files changed, 33 insertions, 8 deletions
diff --git a/accounts/usbwallet/ledger_hub.go b/accounts/usbwallet/ledger_hub.go
index bd397249f..ad5940cd4 100644
--- a/accounts/usbwallet/ledger_hub.go
+++ b/accounts/usbwallet/ledger_hub.go
@@ -130,12 +130,12 @@ func (hub *LedgerHub) refreshWallets() {
url := accounts.URL{Scheme: LedgerScheme, Path: fmt.Sprintf("%03d:%03d", busID>>8, busID&0xff)}
- // Drop wallets while they were in front of the next account
- for len(hub.wallets) > 0 && hub.wallets[0].URL().Cmp(url) < 0 {
+ // Drop wallets in front of the next device or those that failed for some reason
+ for len(hub.wallets) > 0 && (hub.wallets[0].URL().Cmp(url) < 0 || hub.wallets[0].(*ledgerWallet).failed()) {
events = append(events, accounts.WalletEvent{Wallet: hub.wallets[0], Arrive: false})
hub.wallets = hub.wallets[1:]
}
- // If there are no more wallets or the account is before the next, wrap new wallet
+ // If there are no more wallets or the device is before the next, wrap new wallet
if len(hub.wallets) == 0 || hub.wallets[0].URL().Cmp(url) > 0 {
wallet := &ledgerWallet{context: hub.ctx, hardwareID: devID, locationID: busID, url: &url}
@@ -143,7 +143,7 @@ func (hub *LedgerHub) refreshWallets() {
wallets = append(wallets, wallet)
continue
}
- // If the account is the same as the first wallet, keep it
+ // If the device is the same as the first wallet, keep it
if hub.wallets[0].URL().Cmp(url) == 0 {
wallets = append(wallets, hub.wallets[0])
hub.wallets = hub.wallets[1:]
diff --git a/accounts/usbwallet/ledger_wallet.go b/accounts/usbwallet/ledger_wallet.go
index 0481a8990..4f848aebd 100644
--- a/accounts/usbwallet/ledger_wallet.go
+++ b/accounts/usbwallet/ledger_wallet.go
@@ -128,6 +128,15 @@ func (w *ledgerWallet) offline() bool {
return w.version == [3]byte{0, 0, 0}
}
+// failed returns if the USB device wrapped by the wallet failed for some reason.
+// This is used by the device scanner to report failed wallets as departed.
+func (w *ledgerWallet) failed() bool {
+ w.lock.RLock()
+ defer w.lock.RUnlock()
+
+ return w.failure != nil
+}
+
// Open implements accounts.Wallet, attempting to open a USB connection to the
// Ledger hardware wallet. The Ledger does not require a user passphrase so that
// is silently discarded.
@@ -231,6 +240,8 @@ func (w *ledgerWallet) heartbeat() {
w.lock.Lock()
if err := w.resolveVersion(); err == usb.ERROR_IO || err == usb.ERROR_NO_DEVICE {
w.failure = err
+ w.close()
+
fail = err
}
w.lock.Unlock()
@@ -253,15 +264,29 @@ func (w *ledgerWallet) Close() error {
w.lock.Lock()
defer w.lock.Unlock()
- if err := w.device.Close(); err != nil {
+ w.quit = nil
+ if err := w.close(); err != nil {
return err
}
- w.device, w.input, w.output, w.paths, w.quit = nil, nil, nil, nil, nil
- w.version = [3]byte{}
-
return herr // If all went well, return any health-check errors
}
+// close is the internal wallet closer that terminates the USB connection and
+// resets all the fields to their defaults. It assumes the lock is held.
+func (w *ledgerWallet) close() error {
+ // Allow duplicate closes, especially for health-check failures
+ if w.device == nil {
+ return nil
+ }
+ // Close the device, clear everything, then return
+ err := w.device.Close()
+
+ w.device, w.input, w.output = nil, nil, nil
+ w.version, w.paths = [3]byte{}, nil
+
+ return err
+}
+
// Accounts implements accounts.Wallet, returning the list of accounts pinned to
// the Ledger hardware wallet. If self derivation was enabled, the account list
// is periodically expanded based on current chain state.