While attempting to reproducibly build the qml android apk, one of the differences
was due to the "frozenlist" dependency (pulled in by aiohttp) - the compiled C parts
were not deterministic. By setting this env var, we can opt-out [0] of all the C
accelerated parts and just use the pure-python implementation. We are already doing
the same for other aiohttp-related packages anyway.
[0]: c2794cac12/setup.py (L7)
fixes https://github.com/spesmilo/electrum/issues/7780
fixes https://github.com/spesmilo/electrum/issues/7815
Re FIXME in main_window.py, in particular, adb might call `add_transaction` on the same tx multiple times.
In `wallet.on_event_adb_added_tx`, maybe we should propagate `notify_GUI` to `wallet._update_request_statuses_touched_by_tx`.
The issue being fixed here (above TARS reports) can be triggered in multiple ways, e.g.:
- have an already paid receive request, and receive a payment to the same address again
- have an already paid receive request, and *spend from* that address (in which case the history of the address will change, and address_synchronizer will call add_transaction again on the old tx that satisfied the old receive request)
related: 5e0df77df6
kivy 2.1 seemingly became more sensitive to threading issues.
This used to work on kivy 2.0 and older, but 2.1 is complaining.
```
E | lnworker.LNWallet.[default_wallet] | Exception in pay_invoice: TypeError('Cannot create graphics instruction outside the main Kivy thread')
Traceback (most recent call last):
File "...\electrum\util.py", line 1184, in wrapper
return await func(*args, **kwargs)
File "...\electrum\lnworker.py", line 1178, in pay_invoice
util.trigger_callback('payment_succeeded', self.wallet, key)
File "...\electrum\util.py", line 1633, in trigger_callback
callback(*args)
File "...\electrum\gui\kivy\main_window.py", line 309, in on_event_payment_succeeded
self.show_info(_('Payment succeeded') + '\n\n' + description)
File "...\electrum\gui\kivy\main_window.py", line 1105, in show_info
self.show_error(error, icon=f'atlas://{KIVY_GUI_PATH}/theming/atlas/light/important',
File "...\electrum\gui\kivy\main_window.py", line 1097, in show_error
self.show_info_bubble(text=error, icon=icon, width=width,
File "...\electrum\gui\kivy\main_window.py", line 1123, in show_info_bubble
info_bubble = self.info_bubble = Factory.InfoBubble()
File "...\Python310\site-packages\kivy\uix\bubble.py", line 199, in __init__
self._arrow_layout = BoxLayout()
File "...\Python310\site-packages\kivy\uix\boxlayout.py", line 145, in __init__
super(BoxLayout, self).__init__(**kwargs)
File "...\Python310\site-packages\kivy\uix\layout.py", line 76, in __init__
super(Layout, self).__init__(**kwargs)
File "...\Python310\site-packages\kivy\uix\widget.py", line 361, in __init__
self.canvas = Canvas(opacity=self.opacity)
File "kivy\graphics\instructions.pyx", line 608, in kivy.graphics.instructions.Canvas.__init__
File "kivy\graphics\instructions.pyx", line 154, in kivy.graphics.instructions.InstructionGroup.__init__
File "kivy\graphics\instructions.pyx", line 60, in kivy.graphics.instructions.Instruction.__init__
TypeError: Cannot create graphics instruction outside the main Kivy thread
E | gui.kivy.uix.dialogs.crash_reporter.ExceptionHook | exception caught by crash reporter
Traceback (most recent call last):
File "...\electrum\gui\kivy\uix\screens.py", line 419, in pay_thread
fut.result()
File "...\Python310\lib\concurrent\futures\_base.py", line 446, in result
return self.__get_result()
File "...\Python310\lib\concurrent\futures\_base.py", line 391, in __get_result
raise self._exception
File "...\electrum\util.py", line 1184, in wrapper
return await func(*args, **kwargs)
File "...\electrum\lnworker.py", line 1178, in pay_invoice
util.trigger_callback('payment_succeeded', self.wallet, key)
File "...\electrum\util.py", line 1633, in trigger_callback
callback(*args)
File "...\electrum\gui\kivy\main_window.py", line 309, in on_event_payment_succeeded
self.show_info(_('Payment succeeded') + '\n\n' + description)
File "...\electrum\gui\kivy\main_window.py", line 1105, in show_info
self.show_error(error, icon=f'atlas://{KIVY_GUI_PATH}/theming/atlas/light/important',
File "...\electrum\gui\kivy\main_window.py", line 1097, in show_error
self.show_info_bubble(text=error, icon=icon, width=width,
File "...\electrum\gui\kivy\main_window.py", line 1123, in show_info_bubble
info_bubble = self.info_bubble = Factory.InfoBubble()
File "...\Python310\site-packages\kivy\uix\bubble.py", line 199, in __init__
self._arrow_layout = BoxLayout()
File "...\Python310\site-packages\kivy\uix\boxlayout.py", line 145, in __init__
super(BoxLayout, self).__init__(**kwargs)
File "...\Python310\site-packages\kivy\uix\layout.py", line 76, in __init__
super(Layout, self).__init__(**kwargs)
File "...\Python310\site-packages\kivy\uix\widget.py", line 361, in __init__
self.canvas = Canvas(opacity=self.opacity)
File "kivy\graphics\instructions.pyx", line 608, in kivy.graphics.instructions.Canvas.__init__
File "kivy\graphics\instructions.pyx", line 154, in kivy.graphics.instructions.InstructionGroup.__init__
File "kivy\graphics\instructions.pyx", line 60, in kivy.graphics.instructions.Instruction.__init__
TypeError: Cannot create graphics instruction outside the main Kivy thread
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "...\electrum\util.py", line 1128, in run_with_except_hook
run_original(*args2, **kwargs2)
File "...\Python310\lib\threading.py", line 946, in run
self._target(*self._args, **self._kwargs)
File "...\electrum\gui\kivy\uix\screens.py", line 421, in pay_thread
self.app.show_error(repr(e))
File "...\electrum\gui\kivy\main_window.py", line 1097, in show_error
self.show_info_bubble(text=error, icon=icon, width=width,
File "...\electrum\gui\kivy\main_window.py", line 1123, in show_info_bubble
info_bubble = self.info_bubble = Factory.InfoBubble()
File "...\Python310\site-packages\kivy\uix\bubble.py", line 199, in __init__
self._arrow_layout = BoxLayout()
File "...\Python310\site-packages\kivy\uix\boxlayout.py", line 145, in __init__
super(BoxLayout, self).__init__(**kwargs)
File "...\Python310\site-packages\kivy\uix\layout.py", line 76, in __init__
super(Layout, self).__init__(**kwargs)
File "...\Python310\site-packages\kivy\uix\widget.py", line 361, in __init__
self.canvas = Canvas(opacity=self.opacity)
File "kivy\graphics\instructions.pyx", line 608, in kivy.graphics.instructions.Canvas.__init__
File "kivy\graphics\instructions.pyx", line 154, in kivy.graphics.instructions.InstructionGroup.__init__
File "kivy\graphics\instructions.pyx", line 60, in kivy.graphics.instructions.Instruction.__init__
TypeError: Cannot create graphics instruction outside the main Kivy thread
Exception in thread Thread-2 (pay_thread):
Traceback (most recent call last):
File "...\electrum\gui\kivy\uix\screens.py", line 419, in pay_thread
fut.result()
File "...\Python310\lib\concurrent\futures\_base.py", line 446, in result
return self.__get_result()
File "...\Python310\lib\concurrent\futures\_base.py", line 391, in __get_result
raise self._exception
File "...\electrum\util.py", line 1184, in wrapper
return await func(*args, **kwargs)
File "...\electrum\lnworker.py", line 1178, in pay_invoice
util.trigger_callback('payment_succeeded', self.wallet, key)
File "...\electrum\util.py", line 1633, in trigger_callback
callback(*args)
File "...\electrum\gui\kivy\main_window.py", line 309, in on_event_payment_succeeded
self.show_info(_('Payment succeeded') + '\n\n' + description)
File "...\electrum\gui\kivy\main_window.py", line 1105, in show_info
self.show_error(error, icon=f'atlas://{KIVY_GUI_PATH}/theming/atlas/light/important',
File "...\electrum\gui\kivy\main_window.py", line 1097, in show_error
self.show_info_bubble(text=error, icon=icon, width=width,
File "...\electrum\gui\kivy\main_window.py", line 1123, in show_info_bubble
info_bubble = self.info_bubble = Factory.InfoBubble()
File "...\Python310\site-packages\kivy\uix\bubble.py", line 199, in __init__
self._arrow_layout = BoxLayout()
File "...\Python310\site-packages\kivy\uix\boxlayout.py", line 145, in __init__
super(BoxLayout, self).__init__(**kwargs)
File "...\Python310\site-packages\kivy\uix\layout.py", line 76, in __init__
super(Layout, self).__init__(**kwargs)
File "...\Python310\site-packages\kivy\uix\widget.py", line 361, in __init__
self.canvas = Canvas(opacity=self.opacity)
File "kivy\graphics\instructions.pyx", line 608, in kivy.graphics.instructions.Canvas.__init__
File "kivy\graphics\instructions.pyx", line 154, in kivy.graphics.instructions.InstructionGroup.__init__
File "kivy\graphics\instructions.pyx", line 60, in kivy.graphics.instructions.Instruction.__init__
TypeError: Cannot create graphics instruction outside the main Kivy thread
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "...\electrum\util.py", line 1128, in run_with_except_hook
run_original(*args2, **kwargs2)
File "...\Python310\lib\threading.py", line 946, in run
self._target(*self._args, **self._kwargs)
File "...\electrum\gui\kivy\uix\screens.py", line 421, in pay_thread
self.app.show_error(repr(e))
File "...\electrum\gui\kivy\main_window.py", line 1097, in show_error
self.show_info_bubble(text=error, icon=icon, width=width,
File "...\electrum\gui\kivy\main_window.py", line 1123, in show_info_bubble
info_bubble = self.info_bubble = Factory.InfoBubble()
File "...\Python310\site-packages\kivy\uix\bubble.py", line 199, in __init__
self._arrow_layout = BoxLayout()
File "...\Python310\site-packages\kivy\uix\boxlayout.py", line 145, in __init__
super(BoxLayout, self).__init__(**kwargs)
File "...\Python310\site-packages\kivy\uix\layout.py", line 76, in __init__
super(Layout, self).__init__(**kwargs)
File "...\Python310\site-packages\kivy\uix\widget.py", line 361, in __init__
self.canvas = Canvas(opacity=self.opacity)
File "kivy\graphics\instructions.pyx", line 608, in kivy.graphics.instructions.Canvas.__init__
File "kivy\graphics\instructions.pyx", line 154, in kivy.graphics.instructions.InstructionGroup.__init__
File "kivy\graphics\instructions.pyx", line 60, in kivy.graphics.instructions.Instruction.__init__
TypeError: Cannot create graphics instruction outside the main Kivy thread
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "...\Python310\lib\threading.py", line 1009, in _bootstrap_inner
self.run()
File "...\electrum\util.py", line 1130, in run_with_except_hook
sys.excepthook(*sys.exc_info())
File "...\electrum\gui\kivy\uix\dialogs\crash_reporter.py", line 188, in <lambda>
sys.excepthook = lambda exctype, value, tb: self.handle_exception(value)
File "...\electrum\gui\kivy\uix\dialogs\crash_reporter.py", line 199, in handle_exception
e = CrashReporter(self.main_window, *exc_info)
File "...\electrum\gui\kivy\uix\dialogs\crash_reporter.py", line 100, in __init__
Factory.Popup.__init__(self)
File "...\Python310\site-packages\kivy\uix\modalview.py", line 195, in __init__
super(ModalView, self).__init__(**kwargs)
File "...\Python310\site-packages\kivy\uix\anchorlayout.py", line 68, in __init__
super(AnchorLayout, self).__init__(**kwargs)
File "...\Python310\site-packages\kivy\uix\layout.py", line 76, in __init__
super(Layout, self).__init__(**kwargs)
File "...\Python310\site-packages\kivy\uix\widget.py", line 361, in __init__
self.canvas = Canvas(opacity=self.opacity)
File "kivy\graphics\instructions.pyx", line 608, in kivy.graphics.instructions.Canvas.__init__
File "kivy\graphics\instructions.pyx", line 154, in kivy.graphics.instructions.InstructionGroup.__init__
File "kivy\graphics\instructions.pyx", line 60, in kivy.graphics.instructions.Instruction.__init__
TypeError: Cannot create graphics instruction outside the main Kivy thread
```
- in lnurl.py, make request methods async
- in Qt GUI, lnurl network requests no longer block the GUI thread
- but they still do in the kivy GUI
- "lightning address" (LUD-16) support is removed for now as the
email addresses are indistinguishable from openalias email addresses
(both protocols should have added and enforced a prefix, or similar,
to remove this kind of ambiguity -- now we would need to make a
network request just to identify what kind of ID we were given)
- add param to _check_text to toggle if network requests are allowed ("full check")
- every 0.5 sec, if the textedit has no focus, do full check
- on textChanged()
- detect if user copy-pasted by comparing current text against clipboard contents,
if so, do full check
- otherwise, do partial check
- on clicking ButtonsWidget btns (scan qr, paste, read file), do full check
follow-up e1d34300e5
follow-up dc15d59fcf
```
Traceback (most recent call last):
File ".../electrum/gui/qt/main_window.py", line 910, in timer_actions
self.update_wallet()
File ".../electrum/gui/qt/main_window.py", line 1068, in update_wallet
self.update_tabs()
File ".../electrum/gui/qt/main_window.py", line 1075, in update_tabs
self.history_model.refresh('update_tabs')
File ".../electrum/util.py", line 439, in <lambda>
return lambda *args, **kw_args: do_profile(args, kw_args)
File ".../electrum/util.py", line 435, in do_profile
o = func(*args, **kw_args)
File ".../electrum/gui/qt/history_list.py", line 275, in refresh
transactions = wallet.get_full_history(
File ".../electrum/util.py", line 439, in <lambda>
return lambda *args, **kw_args: do_profile(args, kw_args)
File ".../electrum/util.py", line 435, in do_profile
o = func(*args, **kw_args)
File ".../electrum/wallet.py", line 1109, in get_full_history
lightning_history = self.lnworker.get_lightning_history() if self.lnworker and include_lightning else {}
File ".../electrum/lnworker.py", line 839, in get_lightning_history
assert direction == PaymentDirection.FORWARDING
AssertionError
```
follow-up fe74e4b9c9
Just for sanity -- there could be a collision of class names (defined in separate modules).
```
>>> wallet.is_up_to_date.__qualname__
'Abstract_Wallet.is_up_to_date'
>>> wallet.is_up_to_date.__module__
'electrum.wallet'
```
and use that registration in the iterator.
That way, we do not invoke getattr on arbitrary methods, which
could trigger unwanted code execution (for example, if a method
is decorated with @property, getattr will execute its code).
- the detection of self-payments was using the length
of the htlc list, incorrectly categorizing all MPPs.
- the fee for self-payments was not correctly computed.