It does not make sense to count change outputs in our unconfirmed balance,
because our balance will not be negatively affected if the transaction does
not get confirmed.
It is also incorrect to add signed values of get_addr_balance in order to compute
the balance over a domain. For example, this leads to incoming and outgoing
transactions cancelling out in our total unconfirmed balance.
This commit looks at the coins that are spent by a transaction. If those
coins belong to us and are confirmed, we do not count the transaction outputs
in our unconfirmed balance.
As a result, get_balance always returns positive values for unconfirmed balance.
/home/user/wspace/electrum/electrum/gui/qt/locktimeedit.py:145: DeprecationWarning: an integer is required (got type Alignment). Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
painter.drawText(textRect, Qt.AlignRight | Qt.AlignVCenter, "height")
InvoiceList.update() calls hide_if_empty(), which calls setVisible().
setVisible(True) should not be called before the widget is properly parented and put into a layout,
as that results in a blank window flashing up (appearing and disappearing) briefly.
distutils (a module in the python standard library that we use) got deprecated in python 3.10,
and is planned to be removed from the stdlib in python 3.12.
see 9d38120e33/Lib/distutils/__init__.py (L16)
We only use it in the Qt update_checker (for signed version notifications), to compare version numbers.
That is, we only use a very small part of it (only `distutils.version.StrictVersion`).
```
.../electrum/electrum/gui/qt/update_checker.py:7: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives
from distutils.version import StrictVersion
```
Migration advice in PEP-632 suggests ( https://peps.python.org/pep-0632/#migration-advice ):
> `distutils.version` — use the `packaging` package
Note that `packaging` is a 3rd party package, i.e. it would be a new dependency.
Also, it does not provide an identical replacement for `distutils.version.StrictVersion`.
Care needs to be taken when changing the semantics of version numbers...
E.g. `packaging.parse` and `packaging.Version` are less strict than what we currently use.
We have to be careful that old code recognises new electrum version numbers as both valid
and numerically greater than their version.
I think the easiest approach is for us to vendor this small part of distutils.
Re directory structure, this is based on `pip`:
bab5bfce50/src/pip/_vendor
(although the approach here is much more naive ofc)
The Windows build was failing due to the trailing slash in the path:
```
💬 INFO: Pip installing Electrum. This might take a long time if the project folder is large.
Processing c:\electrum
Preparing metadata (setup.py): started
Preparing metadata (setup.py): finished with status 'error'
error: subprocess-exited-with-error
python setup.py egg_info did not run successfully.
exit code: 1
[10 lines of output]
Traceback (most recent call last):
File "<string>", line 2, in <module>
File "<pip-setuptools-caller>", line 34, in <module>
File "C:\electrum\setup.py", line 75, in <module>
find_packages('electrum/', exclude=["tests", "gui.kivy", "gui.kivy.*"])]),
File "C:\python3\lib\site-packages\setuptools\discovery.py", line 103, in find
convert_path(str(where)),
File "C:\python3\lib\site-packages\setuptools\_distutils\util.py", line 130, in convert_path
raise ValueError("path '%s' cannot end with '/'" % pathname)
ValueError: path 'electrum/' cannot end with '/'
```
This is weird because I tested the setuptools.find_packages invocation on Linux, where it
has no issues with the trailing slash, but indeed it looks like on Windows it does.
Not sure why it behaves differently depending on the platform. Anyway, removing.
No change in behaviour as-is.
In the future, if we add a new folder with an __init__.py file, it will get included by default,
whereas in the past it would not.
i.e. this is changing what we manually have to specify from a whitelist to a blacklist.
asyncio.get_event_loop() became deprecated in python3.10. (see https://github.com/python/cpython/issues/83710)
```
.../electrum/electrum/daemon.py:470: DeprecationWarning: There is no current event loop
self.asyncio_loop = asyncio.get_event_loop()
.../electrum/electrum/network.py:276: DeprecationWarning: There is no current event loop
self.asyncio_loop = asyncio.get_event_loop()
```
Also, according to that thread, "set_event_loop() [... is] not deprecated by oversight".
So, we stop using get_event_loop() and set_event_loop() in our own code.
Note that libraries we use (such as the stdlib for python <3.10), might call get_event_loop,
which then relies on us having called set_event_loop e.g. for the GUI thread. To work around
this, a custom event loop policy providing a get_event_loop implementation is used.
Previously, we have been using a single asyncio event loop, created with
util.create_and_start_event_loop, and code in many places got a reference to this loop
using asyncio.get_event_loop().
Now, we still use a single asyncio event loop, but it is now stored as a global in
util._asyncio_event_loop (access with util.get_asyncio_loop()).
I believe these changes also fix https://github.com/spesmilo/electrum/issues/5376
Scenario:
- 2of2 multisig wallet with device1 and device2
- disconnect all devices
- open wallet file
- fail all pairings at wallet-open
- connect device2
- try to sign a tx
At this point Electrum will try to find the device for keystore1 first, and there is only a single unpaired device: device2.
Automatic pairing of keystore1 and device2 will fail, due to device id mismatching compared to what is persisted on disk for keystore1, so the user is prompted for manual selection. The selection dialog is somewhat confusing as it is not clear that the app is asking to select a device for keystore1. Pairing would fail, so the user is expected to cancel the dialog. If they cancel, keystore1 is skipped, and we try to pair for keystore2 now, and device2 will pair with it automatically.
fixes https://github.com/spesmilo/electrum/issues/4199#issuecomment-1112552416
I had a ledger nano S and a ledger nano S plus connected at the same time,
and the "id_"s were colliding resulting in weird behaviour. Multisig was pretty
much not usable with both devices connected simultaneously.
Example dicts returned by `hid.enumerate(0, 0)`:
{'path': b'\\\\?\\hid#vid_2c97&pid_1015&mi_00#a&2a30{REDACTED}&0&0000#{REDACTED_UUID}', 'vendor_id': 11415, 'product_id': 4117, 'serial_number': '0001', 'release_number': 513, 'manufacturer_string': 'Ledger', 'product_string': 'Nano S', 'usage_page': 65440, 'usage': 1, 'interface_number': 0},
{'path': b'\\\\?\\hid#vid_2c97&pid_5011&mi_00#a&28d{REDACTED}&0&0000#{REDACTED_UUID}', 'vendor_id': 11415, 'product_id': 20497, 'serial_number': '0001', 'release_number': 513, 'manufacturer_string': 'Ledger', 'product_string': 'Nano S Plus', 'usage_page': 65440, 'usage': 1, 'interface_number': 0}
see https://github.com/spesmilo/electrum/issues/5376
crash report for electrum 4.2.1:
```
Traceback (most recent call last):
File "/home/user/wspace/electrum/.buildozer/android/platform/build-arm64-v8a/build/python-installs/Electrum/kivy/base.py", line 347, in mainloop
File "/home/user/wspace/electrum/.buildozer/android/platform/build-arm64-v8a/build/python-installs/Electrum/kivy/base.py", line 391, in idle
File "/home/user/wspace/electrum/.buildozer/android/platform/build-arm64-v8a/build/python-installs/Electrum/kivy/base.py", line 342, in dispatch_input
File "/home/user/wspace/electrum/.buildozer/android/platform/build-arm64-v8a/build/python-installs/Electrum/kivy/base.py", line 308, in post_dispatch_input
File "kivy/_event.pyx", line 724, in kivy._event.EventDispatcher.dispatch
File "/home/user/wspace/electrum/.buildozer/android/platform/build-arm64-v8a/build/python-installs/Electrum/kivy/uix/behaviors/button.py", line 179, in on_touch_up
File "kivy/_event.pyx", line 720, in kivy._event.EventDispatcher.dispatch
File "kivy/_event.pyx", line 1263, in kivy._event.EventObservers.dispatch
File "kivy/_event.pyx", line 1147, in kivy._event.EventObservers._dispatch
File "/home/user/wspace/electrum/.buildozer/android/platform/build-arm64-v8a/build/python-installs/Electrum/kivy/lang/builder.py", line 57, in custom_callback
File "<string>", line 42, in <module>
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/gui/kivy/uix/dialogs/wallets.py", line 70, in cb
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/gui/kivy/main_window.py", line 710, in load_wallet_by_name
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/gui/kivy/main_window.py", line 728, in on_open_wallet
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/gui/kivy/main_window.py", line 691, in on_wizard_success
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/wallet.py", line 3267, in __new__
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/wallet.py", line 3111, in __init__
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/wallet.py", line 2904, in __init__
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/wallet.py", line 288, in __init__
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/address_synchronizer.py", line 97, in __init__
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/wallet.py", line 402, in load_and_cleanup
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/address_synchronizer.py", line 106, in load_and_cleanup
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/util.py", line 439, in <lambda>
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/util.py", line 435, in do_profile
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/address_synchronizer.py", line 432, in load_local_history
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/address_synchronizer.py", line 533, in _add_tx_to_local_history
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/address_synchronizer.py", line 548, in _mark_address_history_changed
File "/home/user/wspace/electrum/.buildozer/android/platform/build-arm64-v8a/build/other_builds/python3/arm64-v8a__ndk_target_21/python3/Lib/asyncio/locks.py", line 260, in __init__
File "/home/user/wspace/electrum/.buildozer/android/platform/build-arm64-v8a/build/other_builds/python3/arm64-v8a__ndk_target_21/python3/Lib/asyncio/events.py", line 639, in get_event_loop
RuntimeError: There is no current event loop in thread 'GUI'.
```
see https://github.com/spesmilo/electrum/issues/5376
crash report for electrum 4.2.1:
```
Traceback (most recent call last):
File "/home/user/wspace/electrum/.buildozer/android/platform/build-armeabi-v7a/build/python-installs/Electrum/kivy/base.py", line 347, in mainloop
File "/home/user/wspace/electrum/.buildozer/android/platform/build-armeabi-v7a/build/python-installs/Electrum/kivy/base.py", line 391, in idle
File "/home/user/wspace/electrum/.buildozer/android/platform/build-armeabi-v7a/build/python-installs/Electrum/kivy/base.py", line 342, in dispatch_input
File "/home/user/wspace/electrum/.buildozer/android/platform/build-armeabi-v7a/build/python-installs/Electrum/kivy/base.py", line 308, in post_dispatch_input
File "kivy/_event.pyx", line 724, in kivy._event.EventDispatcher.dispatch
File "/home/user/wspace/electrum/.buildozer/android/platform/build-armeabi-v7a/build/python-installs/Electrum/kivy/uix/behaviors/button.py", line 179, in on_touch_up
File "kivy/_event.pyx", line 720, in kivy._event.EventDispatcher.dispatch
File "kivy/_event.pyx", line 1263, in kivy._event.EventObservers.dispatch
File "kivy/_event.pyx", line 1147, in kivy._event.EventObservers._dispatch
File "/home/user/wspace/electrum/.buildozer/android/platform/build-armeabi-v7a/build/python-installs/Electrum/kivy/lang/builder.py", line 57, in custom_callback
File "<string>", line 39, in <module>
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/gui/kivy/uix/dialogs/settings.py", line 173, in cb
File "kivy/properties.pyx", line 498, in kivy.properties.Property.__set__
File "kivy/properties.pyx", line 545, in kivy.properties.Property.set
File "kivy/properties.pyx", line 600, in kivy.properties.Property.dispatch
File "kivy/_event.pyx", line 1263, in kivy._event.EventObservers.dispatch
File "kivy/_event.pyx", line 1169, in kivy._event.EventObservers._dispatch
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/gui/kivy/main_window.py", line 206, in on_use_gossip
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/network.py", line 368, in start_gossip
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/channel_db.py", line 308, in __init__
File "/home/user/wspace/electrum/.buildozer/android/app/electrum/sql_db.py", line 30, in __init__
File "/home/user/wspace/electrum/.buildozer/android/platform/build-armeabi-v7a/build/other_builds/python3/armeabi-v7a__ndk_target_21/python3/Lib/asyncio/locks.py", line 260, in __init__
File "/home/user/wspace/electrum/.buildozer/android/platform/build-armeabi-v7a/build/other_builds/python3/armeabi-v7a__ndk_target_21/python3/Lib/asyncio/events.py", line 639, in get_event_loop
RuntimeError: There is no current event loop in thread 'GUI'.
```
The call to super was removed in 4efcb53d24 ,
so that LNWallet's taskgroup would not run _maintain_connectivity, AFAICT.
The way it was done meant that "main_loop" itself would not run for LNWallet, only for LNGossip - very confusing.
It is only due to a quirk in the behaviour of TaskGroups that the group "started" at all.