The keystore logic would need to be significantly changed to nicely
interoperate with StoredDict/json_db logic.
(just see KeyStore.__init__() and KeyStore.dump())
For now we exempt the keystore from the recursive StoredDict conversion, as
it is a smaller change that is also easier to review for correctness.
fixes#6066fixes#6401
also reverts 2d3c2eeea9 (which was an even hackier workaround for #6066)
If the Bridge is unavailable, on my machine it takes 2 seconds to timeout.
i.e. call_bridge("enumerate") and BridgeTransport.enumerate() both take 2 seconds each.
With this change, if the Bridge is unavailable, DeviceMgr.scan_devices() takes 4 seconds less.
In below log, with 6 different hw devices connected, scan time was originally ~7.5 seconds;
with this change it became ~3.5 seconds.
Now the time is dominated by WebUsbTransport.enumerate(), called by Trezor,
KeepKey, SafeT, ~1.1 seconds each.
-----
I | plugin.DeviceMgr | scan_devices() entered. 1598666278.6756
I | plugin.DeviceMgr | scan_devices(). _scan_devices_with_hid() DONE. 1598666278.7583
I | plugin.DeviceMgr | scan_devices(). starting custom enumeration loop. 1598666278.7593
I | plugin.DeviceMgr | scan_devices(). custom enumeration iter DONE, for <bound method SafeTPlugin.enumerate of <electrum.plugins.safe_t.qt.Plugin object at 0x000001F60060A730>>. 1598666279.9345
I | plugins.trezor.qt.Plugin | trezor custom enumeration entered. 1598666279.9345
I | plugins.trezor.qt.Plugin | trezor custom enumeration. call_bridge('enumerate') DONE. 1598666281.9385
>> trezorlib enumerating <class 'trezorlib.transport.bridge.BridgeTransport'> DONE at 1598666283.9500.
>> trezorlib enumerating <class 'trezorlib.transport.webusb.WebUsbTransport'> DONE at 1598666285.0427.
>> trezorlib enumerating <class 'trezorlib.transport.hid.HidTransport'> DONE at 1598666285.1198.
>> trezorlib enumerating <class 'trezorlib.transport.udp.UdpTransport'> DONE at 1598666285.1237.
I | plugins.trezor.qt.Plugin | trezor custom enumeration. trezorlib.transport.enumerate_devices() DONE. 1598666285.1257
I | plugin.DeviceMgr | scan_devices(). custom enumeration iter DONE, for <bound method TrezorPlugin.enumerate of <electrum.plugins.trezor.qt.Plugin object at 0x000001F60C16F4C0>>. 1598666285.1257
I | plugin.DeviceMgr | scan_devices(). custom enumeration iter DONE, for <bound method KeepKeyPlugin.enumerate of <electrum.plugins.keepkey.qt.Plugin object at 0x000001F60BADF130>>. 1598666286.2251
I | plugin.DeviceMgr | scan_devices(). custom enumeration iter DONE, for <bound method ColdcardPlugin.detect_simulator of <electrum.plugins.coldcard.qt.Plugin object at 0x000001F60BAA5AC0>>. 1598666286.2251
I | plugin.DeviceMgr | scan_devices(). custom enumeration loop DONE. 1598666286.2251
I | plugin.DeviceMgr | scan_devices(). find out what was disconnected DONE. 1598666286.2251
I | plugin.DeviceMgr | scan_devices(). Unpair disconnected devices DONE. 1598666286.2251
Instead of single mpk_text widget for each ks and changing the contents
when switching, create an mpk_text widget for each ks and switch between those.
This allows putting the "show xpub on device" button inside mpk_text.
Without it, if you have say a 1-of-2 multisig with two BitBox02s, you
would run into trouble if the first keystore would try to match to the
wrong inserted BitBox02 (wrong order, or the first one is not
inserted, etc. ).
With the soft device id, the device manager can figure it on its own
which keystore belongs to which connected bb02.
ServerProxy does not seem to be thread-safe.
For e.g. a 2of3 multisig wallet, which would send two messages,
one msg would get sent but the other might error out. See trace:
E | plugins.cosigner_pool.qt.Plugin | on_failure
Traceback (most recent call last):
File "...\electrum\electrum\gui\qt\util.py", line 832, in run
result = task.task()
File "...\electrum\electrum\plugins\cosigner_pool\qt.py", line 199, in <lambda>
task = lambda: server.put(_hash, message)
File "...\Python38\lib\xmlrpc\client.py", line 1109, in __call__
return self.__send(self.__name, args)
File "...\Python38\lib\xmlrpc\client.py", line 1450, in __request
response = self.__transport.request(
File "...\Python38\lib\xmlrpc\client.py", line 1153, in request
return self.single_request(host, handler, request_body, verbose)
File "...\Python38\lib\xmlrpc\client.py", line 1165, in single_request
http_conn = self.send_request(host, handler, request_body, verbose)
File "...\Python38\lib\xmlrpc\client.py", line 1271, in send_request
connection.putrequest("POST", handler, skip_accept_encoding=True)
File "...\Python38\lib\http\client.py", line 1088, in putrequest
raise CannotSendRequest(self.__state)
http.client.CannotSendRequest: Request-sent
- for symmetry with other plugins
- and because this is a superset. txin.utxo gets populated from the wallet db (or network);
but the wallet db does not import txs from txin.utxo (so if a psbt already had an
unknown tx there, it will not get imported)
Inform the user that they need to upgrade if their firmware version is
out of date.
The previous `check_device_firmware_version()` was dead code, and the
bb02 function called inside also does not exist.
This commit adds support for the BitBox02 hardware wallet.
It supports both single and multisig for the electrum gui wallet.
To use the plugin a local installation of the BitBox02 python library is
required. It can be found on PiPy under the name 'bitbox02' and can be
installed from the bitbox02-firmware repository in the py/bitbox02
directory.
All communication to and from the BitBox02 is noise encrypted, the keys
required for this are stored in the wallet config file under the
bitbox02 key.
The BitBox02 registers a multisig configuration before allowing
transaction signing. This multisig configuration includes the threshold,
cosigner xpubs, keypath, a variable to indicate for mainnet and testnet,
and a name that the user can choose during configuration registration.
The user is asked to register the multisig configuration either during
address verification or during transaction signing.
The check the xpub of the BitBox02 for other hardware wallets, a button
is added in the wallet info dialog.
The wallet encryption key is fetched in a separate api call, requiring a
slightly tweaked override version of the wallet encryption password.