Files
pallectrum/electrum/plugins
SomberNight 33d394c9d7 ledger: fix scan_devices for certain devices with multiple interfaces
regression from https://github.com/spesmilo/electrum/pull/8041 (4.3.3)

maybe fixes https://github.com/spesmilo/electrum/issues/8293

-----

Testing with a "Ledger Nano S", btc app version 1.6.3.
btchip-python==0.1.32
ledgercomm==1.1.1
ledger-bitcoin==0.1.1

Trying to scan devices hangs/blocks forever on Linux (ubuntu 22.04).

```patch
diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py
index 17c1caca48..ba5ae2e3ee 100644
--- a/electrum/plugins/ledger/ledger.py
+++ b/electrum/plugins/ledger/ledger.py
@@ -306,17 +306,25 @@ class Ledger_Client(HardwareClientBase, ABC):
     @staticmethod
     def construct_new(*args, device: Device, **kwargs) -> 'Ledger_Client':
         """The 'real' constructor, that automatically decides which subclass to use."""
+        _logger.info(f"xxx construct_new(). cp1. {device.path=}. {device=}")
         if LedgerPlugin.is_hw1(device.product_key):
             return Ledger_Client_Legacy_HW1(*args, **kwargs, device=device)
         # for nano S or newer hw, decide which client impl to use based on software/firmware version:
+        _logger.info(f"xxx construct_new(). cp2.")
         hid_device = HID()
         hid_device.path = device.path
+        _logger.info(f"xxx construct_new(). cp3.")
         hid_device.open()
+        _logger.info(f"xxx construct_new(). cp4.")
         transport = ledger_bitcoin.TransportClient('hid', hid=hid_device)
-        cl = ledger_bitcoin.createClient(transport, chain=get_chain())
+        _logger.info(f"xxx construct_new(). cp5.")
+        cl = ledger_bitcoin.createClient(transport, chain=get_chain(), debug=True)
+        _logger.info(f"xxx construct_new(). cp6.")
         if isinstance(cl, ledger_bitcoin.client.NewClient):
+            _logger.info(f"xxx construct_new(). cp7. trying Ledger_Client_New")
             return Ledger_Client_New(hid_device, *args, **kwargs)
         else:
+            _logger.info(f"xxx construct_new(). cp7. trying Ledger_Client_Legacy")
             return Ledger_Client_Legacy(hid_device, *args, **kwargs)

     def __init__(self, *, plugin: HW_PluginBase):
@@ -1416,7 +1424,7 @@ class LedgerPlugin(HW_PluginBase):
         try:
             return Ledger_Client.construct_new(device=device, product_key=device.product_key, plugin=self)
         except Exception as e:
-            self.logger.info(f"cannot connect at {device.path} {e}")
+            self.logger.info(f"cannot connect at {device.path} {e}")  #
         return None

     def setup_device(self, device_info, wizard, purpose):
```

scanning devices freezes... log:
```
  8.94 | I | plugin.DeviceMgr | scanning devices...
  9.18 | D | util.profiler | DeviceMgr.scan_devices 0.2357 sec
  9.18 | I | plugins.ledger.ledger | xxx construct_new(). cp1. device.path=b'0001:0008:00'. device=Device(path=b'0001:0008:00', interface_number=0, id_="b'0001:0008:00',0001,0,0", product_key=(11415, 4117), usage_page=0, transport_ui_string='hid')
  9.18 | I | plugins.ledger.ledger | xxx construct_new(). cp2.
  9.18 | I | plugins.ledger.ledger | xxx construct_new(). cp3.
heyheyhey. cp1. self.path=b'0001:0008:00'
  9.18 | I | plugins.ledger.ledger | xxx construct_new(). cp4.
  9.18 | I | plugins.ledger.ledger | xxx construct_new(). cp5.
=> b001000000
<= 010c426974636f696e205465737405312e362e3301029000
  9.22 | I | plugins.ledger.ledger | xxx construct_new(). cp6.
  9.22 | I | plugins.ledger.ledger | xxx construct_new(). cp7. trying Ledger_Client_Legacy
  9.29 | I | plugin.DeviceMgr | Registering <electrum.plugins.ledger.ledger.Ledger_Client_Legacy object at 0x7f4369e6e380>
 10.33 | I | plugins.ledger.ledger | xxx construct_new(). cp1. device.path=b'0001:0008:01'. device=Device(path=b'0001:0008:01', interface_number=1, id_="b'0001:0008:01',0001,1,0", product_key=(11415, 4117), usage_page=0, transport_ui_string='hid')
 10.33 | I | plugins.ledger.ledger | xxx construct_new(). cp2.
 10.33 | I | plugins.ledger.ledger | xxx construct_new(). cp3.
heyheyhey. cp1. self.path=b'0001:0008:01'
 10.33 | I | plugins.ledger.ledger | xxx construct_new(). cp4.
 10.33 | I | plugins.ledger.ledger | xxx construct_new(). cp5.
=> b001000000
```

in Qt console (before change):
```
>>> lp = plugins.get_plugin("ledger")
>>> plugins.device_manager.scan_devices()
[Device(path=b'0001:000a:00', interface_number=0, id_="b'0001:000a:00',0001,0,0", product_key=(11415, 4117), usage_page=0, transport_ui_string='hid'), Device(path=b'0001:000a:01', interface_number=1, id_="b'0001:000a:01',0001,1,0", product_key=(11415, 4117), usage_page=0, transport_ui_string='hid')]
```
2023-05-02 17:23:07 +00:00
..
2023-04-24 12:58:01 +00:00
2023-04-24 12:58:01 +00:00
2023-04-24 12:58:01 +00:00
2023-04-24 13:00:07 +00:00
2023-04-24 12:58:01 +00:00
2023-04-12 12:21:08 +02:00
2023-04-24 12:58:01 +00:00
2023-04-24 12:58:19 +00:00

Plugin rules:

 * The plugin system of Electrum is designed to allow the development
   of new features without increasing the core code of Electrum.

 * Electrum is written in pure python. if you want to add a feature
   that requires non-python libraries, then it must be submitted as a
   plugin. If the feature you want to add requires communication with
   a remote server (not an Electrum server), then it should be a
   plugin as well. If the feature you want to add introduces new
   dependencies in the code, then it should probably be a plugin.

 * We expect plugin developers to maintain their plugin code. However,
   once a plugin is merged in Electrum, we will have to maintain it
   too, because changes in the Electrum code often require updates in
   the plugin code. Therefore, plugins have to be easy to maintain. If
   we believe that a plugin will create too much maintenance work in
   the future, it will be rejected.

 * Plugins should be compatible with Electrum's conventions. If your
   plugin does not fit with Electrum's architecture, or if we believe
   that it will create too much maintenance work, it will not be
   accepted. In particular, do not duplicate existing Electrum code in
   your plugin.

 * We may decide to remove a plugin after it has been merged in
   Electrum. For this reason, a plugin must be easily removable,
   without putting at risk the user's bitcoins. If we feel that a
   plugin cannot be removed without threatening users who rely on it,
   we will not merge it.