1
0
Commit Graph

14194 Commits

Author SHA1 Message Date
SomberNight
10b2d705a1 qt chan details dlg: break stats into 2 cols, add local/remote balance 2022-03-21 17:49:08 +01:00
ghost43
14b600bb9d Merge pull request #7721 from SomberNight/202203_build_bump_python
win build: bump python, wine, pyinstaller
2022-03-20 17:25:23 +00:00
SomberNight
b5951adc29 win build: update pyinstaller (from around 4.2 to around 4.10)
see https://github.com/spesmilo/electrum/pull/7721#issuecomment-1072669548

-----

pyinstaller 4.2 failed (during its runtime) to create exes (worked with cpython 3.9.10, but not with cpython 3.9.11):
```
80572 INFO: Processing module hooks...
80573 INFO: Loading module hook 'hook-certifi.py' from 'C:\\python3\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...
80618 INFO: Loading module hook 'hook-cryptography.py' from 'C:\\python3\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...
82879 INFO: Loading module hook 'hook-dns.rdata.py' from 'C:\\python3\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...
84147 INFO: Loading module hook 'hook-mnemonic.py' from 'C:\\python3\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...
84207 INFO: Loading module hook 'hook-pycparser.py' from 'C:\\python3\\lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks'...
84212 INFO: Loading module hook 'hook-usb1.py' from 'C:\\python3\\lib\\site-packages\\usb1\\__pyinstaller'...
84215 INFO: --- libusb1 pyinstaller hook ---
84226 INFO: Added libusb binaries: [('C:\\python3\\lib\\site-packages\\usb1\\libusb-1.0.dll', 'usb1')]
84228 INFO: Loading module hook 'hook-difflib.py' from 'C:\\python3\\lib\\site-packages\\PyInstaller\\hooks'...
84237 INFO: Excluding import of doctest from module difflib
84237 INFO: Loading module hook 'hook-distutils.py' from 'C:\\python3\\lib\\site-packages\\PyInstaller\\hooks'...
Unable to find "C:\python3\Include\pyconfig.h" when adding binary and data files.This would mean your Python installation doesn't
come with proper library files. This usually happens by missing development
package, or unsuitable build parameters of Python installation.
* On Debian/Ubuntu, you would need to install Python development packages
  * apt-get install python3-dev
  * apt-get install python-dev
* If you're building Python by yourself, please rebuild your Python with
`--enable-shared` (or, `--enable-framework` on Darwin)

🗯 ERROR: build-electrum-git failed
```

Looks like this might be fixed in pyinstaller 4.3 (we are using 4.2):
https://github.com/pyinstaller/pyinstaller/pull/5218

-----

While trying to update pyinstaller to have that fix, several issues found with versions 4.3-4.10,
now reported upstream and already fixed:
https://github.com/pyinstaller/pyinstaller/issues/6338
https://github.com/pyinstaller/pyinstaller/issues/6339
https://github.com/pyinstaller/pyinstaller/issues/6686

So the pyinstaller commit pinned here is from the stable "v4" branch, some commits after the 4.10 tag,
which has fixes for the above issues.
2022-03-20 17:28:11 +01:00
SomberNight
0e7b7624fb win build: bump wine 6.0.2->7.0.0.0 to fix installing python
with wine 6.0.2 and 6.0.3, cpython 3.9.11 fails to install (but cpython 3.9.10 worked)
```
010c:err:virtual:virtual_setup_exception stack overflow 1220 bytes in thread 010c addr 0x7bc6713d stack 0x440b3c (0x440000-0x441000-0x640000)
🗯 ERROR: wine msiexec failed for dev.msi
🗯 ERROR: prepare-wine failed
```

-----

btw, related note:
After changing the Dockerfile, building the docker image from cache failed. Setting ELECBUILD_NOCACHE=1 fixed it:
```
E: Could not configure 'libc6:i386'.
E: Could not perform immediate configuration on 'libgcc-s1:i386'. Please see man 5 apt.conf under APT::Immediate-Configure for details. (2)

$ ELECBUILD_NOCACHE=1 ./contrib/build-wine/build.sh
```
2022-03-20 17:15:58 +01:00
SomberNight
185d54de63 win build: bump python 3.9.10->3.9.11 2022-03-20 17:15:54 +01:00
SomberNight
e00c998df3 transaction: TxInput.witness_elements() to return [] if not segwit
Previously it would raise:
```
>>> import electrum
>>> tx = electrum.transaction.tx_from_any("0200000001d945b6b076ad7858f7a2227374a42ada71582b1d558fde9ece4bf6c9395c67ca000000006a473044022034867c61623a147dbe7e8541da1086ec8691d4f39181deeba4be70559e26734d02205c0288c96ae6950a0687c0d8c06f9cd343362e6a174cd4c66cfc2abd2278aed801210330fb51ac7b556a599a05c2b8670e79008406e4c0b7e46d4a522ad01804f25dbbfdffffff02389d0700000000001976a9146d687bece6d502519ce5317e25f48da60a52ca8f88ac20a1070000000000220020a948d7fa6abbb97e31779ae54383012b413d53821c7fd394900f6b443c61deeee82a1800")
>>> tx.inputs()[0].witness_elements()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/wspace/electrum/electrum/transaction.py", line 257, in witness_elements
    vds.write(self.witness)
  File "/home/user/wspace/electrum/electrum/transaction.py", line 279, in write
    assert isinstance(_bytes, (bytes, bytearray))
AssertionError
```
2022-03-20 16:55:36 +01:00
SomberNight
3e42f2f33d kivy: fix cpfp dialog: qt not available on android
(and the imports are unused.)

fixes https://github.com/spesmilo/electrum/issues/7723
2022-03-19 00:02:54 +01:00
SomberNight
1bb7ef92e7 binaries: bump python 3.9.10->3.9.11; and for android 3.8.12->3.8.13
This is bumping the python versions bundled inside our binaries.
For macOS and AppImage, from 3.9.10 to 3.9.11.
For Android, from 3.8.12 to 3.8.13.

Windows is left untouched as I am having issues with the wine build when using 3.9.11.
(see https://github.com/spesmilo/electrum/pull/7721#issuecomment-1071901116 )
2022-03-18 16:21:24 +01:00
ThomasV
e8ec65a907 Merge pull request #7720 from SomberNight/202203_lnpeer_error_msg
lnpeer: some rework of error/warning message handling
2022-03-18 08:10:13 +01:00
SomberNight
a92dede490 lnpeer: some rework of error/warning message handling
- rm the `_get_channel_ids` abstraction as each of its usages needs subtle differences.
  Some code duplication is preferable in this case.
- raise exceptions in `wait_for_message`, so that callers such as the GUI can show user-feedback
- on_error/on_warning were dropping messages with temp_chan_ids if they were not stored in
  `temp_id_to_id` - which was only done once the mapping was known (so the normal chan_id was known).
  To fix this, we now store temp_chan_ids into `temp_id_to_id` early.
- `schedule_force_closing` only works if the chan_id is already in `channels`

related:
https://github.com/spesmilo/electrum/pull/7645 (and related commits)

-----

example before commit:
```
D/P | lnpeer.Peer.[LNWallet, 03933884aa-3b53e4ab] | Sending OPEN_CHANNEL
D/P | lnpeer.Peer.[LNWallet, 03933884aa-3b53e4ab] | Received ERROR
I/P | lnpeer.Peer.[LNWallet, 03933884aa-3b53e4ab] | remote peer sent error [DO NOT TRUST THIS MESSAGE]: invalid funding_satoshis=10000 sat (min=400000 sat max=1500000000 sat)

E | gui.qt.main_window.[test_segwit_2] | Could not open channel
Traceback (most recent call last):
  File "...\electrum\electrum\util.py", line 1160, in wrapper
    return await func(*args, **kwargs)
  File "...\electrum\electrum\lnpeer.py", line 661, in wrapper
    return await func(self, *args, **kwargs)
  File "...\electrum\electrum\lnpeer.py", line 742, in channel_establishment_flow
    payload = await self.wait_for_message('accept_channel', temp_channel_id)  #
  File "...\electrum\electrum\lnpeer.py", line 315, in wait_for_message
    name, payload = await asyncio.wait_for(q.get(), LN_P2P_NETWORK_TIMEOUT)
  File "...\Python39\lib\asyncio\tasks.py", line 468, in wait_for
    await waiter
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "...\Python39\lib\asyncio\tasks.py", line 492, in wait_for
    fut.result()
asyncio.exceptions.CancelledError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "...\electrum\electrum\gui\qt\util.py", line 914, in run
    result = task.task()
  File "...\electrum\electrum\gui\qt\main_window.py", line 1875, in task
    return self.wallet.lnworker.open_channel(
  File "...\electrum\electrum\lnworker.py", line 1075, in open_channel
    chan, funding_tx = fut.result()
  File "...\Python39\lib\concurrent\futures\_base.py", line 445, in result
    return self.__get_result()
  File "...\Python39\lib\concurrent\futures\_base.py", line 390, in __get_result
    raise self._exception
  File "...\electrum\electrum\util.py", line 1160, in wrapper
    return await func(*args, **kwargs)
  File "...\electrum\electrum\lnworker.py", line 1006, in _open_channel_coroutine
    chan, funding_tx = await asyncio.wait_for(coro, LN_P2P_NETWORK_TIMEOUT)
  File "...\Python39\lib\asyncio\tasks.py", line 494, in wait_for
    raise exceptions.TimeoutError() from exc
asyncio.exceptions.TimeoutError
```

example after commit:
```
D/P | lnpeer.Peer.[LNWallet, 03933884aa-ff3a866f] | Sending OPEN_CHANNEL
D/P | lnpeer.Peer.[LNWallet, 03933884aa-ff3a866f] | Received ERROR
I/P | lnpeer.Peer.[LNWallet, 03933884aa-ff3a866f] | remote peer sent error [DO NOT TRUST THIS MESSAGE]: invalid funding_satoshis=10000 sat (min=400000 sat max=1500000000 sat). chan_id=124ca21fa6aa2993430ad71f465f0d44731ef87f7478e4b31327e4459b5a3988
E | lnworker.LNWallet.[test_segwit_2] | Exception in _open_channel_coroutine: GracefulDisconnect('remote peer sent error [DO NOT TRUST THIS MESSAGE]: invalid funding_satoshis=10000 sat (min=400000 sat max=1500000000 sat)')
Traceback (most recent call last):
  File "...\electrum\electrum\util.py", line 1160, in wrapper
    return await func(*args, **kwargs)
  File "...\electrum\electrum\lnworker.py", line 1006, in _open_channel_coroutine
    chan, funding_tx = await asyncio.wait_for(coro, LN_P2P_NETWORK_TIMEOUT)
  File "...\Python39\lib\asyncio\tasks.py", line 481, in wait_for
    return fut.result()
  File "...\electrum\electrum\lnpeer.py", line 673, in wrapper
    return await func(self, *args, **kwargs)
  File "...\electrum\electrum\lnpeer.py", line 755, in channel_establishment_flow
    payload = await self.wait_for_message('accept_channel', temp_channel_id)
  File "...\electrum\electrum\lnpeer.py", line 326, in wait_for_message
    raise GracefulDisconnect(
electrum.interface.GracefulDisconnect: remote peer sent error [DO NOT TRUST THIS MESSAGE]: invalid funding_satoshis=10000 sat (min=400000 sat max=1500000000 sat)
I/P | lnpeer.Peer.[LNWallet, 03933884aa-ff3a866f] | Disconnecting: GracefulDisconnect()
```
2022-03-17 17:52:38 +01:00
ThomasV
0212b4339d Merge pull request #7718 from SomberNight/202203_doc_add_cosigner
contrib/add_cosigner: document usage process
2022-03-17 06:26:33 +01:00
SomberNight
1a8a0fc159 contrib/add_cosigner: document usage process 2022-03-16 21:31:59 +01:00
SomberNight
f082a84033 contrib/upload: fix file permissions on the sftp server, and chmod +x 2022-03-16 17:56:38 +01:00
SomberNight
fc8d14889d update gitignore: .buildozer is now a symlink, not a folder 2022-03-16 17:54:23 +01:00
ThomasV
eb8ab74698 fix date in release notes 4.2.0 2022-03-16 13:58:32 +01:00
SomberNight
978677700c fix prev 2022-03-16 13:34:15 +01:00
SomberNight
dcf194952b android build: update openssl 2022-03-16 13:24:03 +01:00
SomberNight
d154e368f1 wallet: fix clear_requests and clear_invoices
these are StoredDicts, subdicts in wallet_db.data, so reassigning the name does not work
2022-03-16 12:51:03 +01:00
gruve-p
1aa831c7d9 appimage: update libssl-dev libssl1.0.0 openssl (#7715) 2022-03-15 23:45:49 +00:00
SomberNight
7cd14e4ef4 android build: (reprod) exclude frozenlist-*.dist-info from apk
```
$ cat d
29,30c29,32
< 527b99c5fa20d43ab49302f6b4b1a9a671ac04601f5f471f254ae2f97cb31e17  ./META-INF/MANIFEST.MF
< 0a2887e3041a3eaeef6e0f1dbf65fcc527bf0c878728b0e9d4b783b855f3e64c  ./assets/private.mp3
---
> d18d1d9f4933952f93b32091b0a002cdb9ed94fdecc20b22d605cf8143a02d92  ./META-INF/CERT.RSA
> ec2ca24868f69427162c0dc2f3a3390e6165dec7b3202c65928ae77939316392  ./META-INF/CERT.SF
> 7a94368993707d82a328cf7625450e6868f450ecf73474574048ff70a707f4ce  ./META-INF/MANIFEST.MF
> 84c86813d93d4e74a7f199da8b925d36d89608eee37031a88f61a833ab30e6dd  ./assets/private.mp3
1672c1674
< 10666a3ae7e2080120165b2b0edbbe2eb8e7b679dac7de18dffde0e6f786fd08  ./assets/private_mp3/packages/frozenlist-1.3.0.dist-info/RECORD
---
> 803d20545cf39ade4d9b803034f0fd2002478ffdcc2056852621ae2c42e37d0d  ./assets/private_mp3/packages/frozenlist-1.3.0.dist-info/RECORD
```
2022-03-15 20:05:44 +01:00
SomberNight
2c5eb26ff0 contrib/release.sh: fix some paths re android apk 2022-03-15 20:00:43 +01:00
SomberNight
f9b07d15af macos build: brew now requires xcode cli tools (not full xcode)
Which means we need *both* xcode cli tools and full xcode.
Document this weirdness, including the exact paths they should be at.

excerpt from terminal when running make_osx:
```
Warning: You are using macOS 10.14.
We (and Apple) do not provide support for this old version.
You will encounter build failures with some formulae.
Please create pull requests instead of asking for help on Homebrew's GitHub,
Twitter or any other official channels. You are responsible for resolving
any issues you experience while you are running this
old version.

==> Downloading https://ftp.gnu.org/gnu/coreutils/coreutils-9.0.tar.xz
Already downloaded: /Users/vagrant/Library/Caches/Homebrew/downloads/5744bb33344b6180adca9d909a87e830d55982a1b3229c61e9dc0e35cfacbf25--coreutils-9.0.tar.xz
Error: Xcode alone is not sufficient on Mojave.
Install the Command Line Tools for Xcode 11.3.1 from:
  https://developer.apple.com/download/all/
```
2022-03-15 19:59:56 +01:00
ThomasV
d10203f88e update submodule 2022-03-15 15:26:57 +01:00
SomberNight
f94f142605 prepare release 4.2.0 2022-03-15 15:06:28 +01:00
SomberNight
15643b7951 qt init: make sure wallet file parsing errors are shown in gui
Some exceptions were just killing the gui silently and not even logged.

E.g.:
```
E | gui.qt.ElectrumGui | error loading wallet (or creating window for it)
Traceback (most recent call last):
  File "/opt/electrum/electrum/gui/qt/__init__.py", line 433, in main
    if not self.start_new_window(path, self.config.get('url'), app_is_starting=True):
  File "/opt/electrum/electrum/gui/qt/__init__.py", line 307, in wrapper
    return func(self, *args, **kwargs)
  File "/opt/electrum/electrum/gui/qt/__init__.py", line 332, in start_new_window
    wallet = self._start_wizard_to_select_or_create_wallet(path)
  File "/opt/electrum/electrum/gui/qt/__init__.py", line 377, in _start_wizard_to_select_or_create_wallet
    db = WalletDB(storage.read(), manual_upgrades=False)
  File "/opt/electrum/electrum/wallet_db.py", line 73, in __init__
    self.load_data(raw)
  File "/opt/electrum/electrum/wallet_db.py", line 104, in load_data
    self._after_upgrade_tasks()
  File "/opt/electrum/electrum/wallet_db.py", line 202, in _after_upgrade_tasks
    self._load_transactions()
  File "/opt/electrum/electrum/util.py", line 439, in <lambda>
    return lambda *args, **kw_args: do_profile(args, kw_args)
  File "/opt/electrum/electrum/util.py", line 435, in do_profile
    o = func(*args, **kw_args)
  File "/opt/electrum/electrum/wallet_db.py", line 1310, in _load_transactions
    self.data = StoredDict(self.data, self, [])
  File "/opt/electrum/electrum/json_db.py", line 79, in __init__
    self.__setitem__(k, v)
  File "/opt/electrum/electrum/json_db.py", line 44, in wrapper
    return func(self, *args, **kwargs)
  File "/opt/electrum/electrum/json_db.py", line 97, in __setitem__
    v = self.db._convert_dict(self.path, key, v)
  File "/opt/electrum/electrum/wallet_db.py", line 1361, in _convert_dict
    v = dict((k, SwapData(**x)) for k, x in v.items())
```
2022-03-15 14:23:30 +01:00
SomberNight
3771553a2c crash reporter: if disabled via config, make sure EEQueue is flushed
If the user had `config.get("show_crash_reporter")==False`, they would
never get to see excs collected via `send_exception_to_crash_reporter(exc)`.

E.g.:
```
E | gui.qt.ElectrumGui | error loading wallet (or creating window for it)
Traceback (most recent call last):
  File "/opt/electrum/electrum/gui/qt/__init__.py", line 433, in main
    if not self.start_new_window(path, self.config.get('url'), app_is_starting=True):
  File "/opt/electrum/electrum/gui/qt/__init__.py", line 307, in wrapper
    return func(self, *args, **kwargs)
  File "/opt/electrum/electrum/gui/qt/__init__.py", line 332, in start_new_window
    wallet = self._start_wizard_to_select_or_create_wallet(path)
  File "/opt/electrum/electrum/gui/qt/__init__.py", line 377, in _start_wizard_to_select_or_create_wallet
    db = WalletDB(storage.read(), manual_upgrades=False)
  File "/opt/electrum/electrum/wallet_db.py", line 73, in __init__
    self.load_data(raw)
  File "/opt/electrum/electrum/wallet_db.py", line 104, in load_data
    self._after_upgrade_tasks()
  File "/opt/electrum/electrum/wallet_db.py", line 202, in _after_upgrade_tasks
    self._load_transactions()
  File "/opt/electrum/electrum/util.py", line 439, in <lambda>
    return lambda *args, **kw_args: do_profile(args, kw_args)
  File "/opt/electrum/electrum/util.py", line 435, in do_profile
    o = func(*args, **kw_args)
  File "/opt/electrum/electrum/wallet_db.py", line 1310, in _load_transactions
    self.data = StoredDict(self.data, self, [])
  File "/opt/electrum/electrum/json_db.py", line 79, in __init__
    self.__setitem__(k, v)
  File "/opt/electrum/electrum/json_db.py", line 44, in wrapper
    return func(self, *args, **kwargs)
  File "/opt/electrum/electrum/json_db.py", line 97, in __setitem__
    v = self.db._convert_dict(self.path, key, v)
  File "/opt/electrum/electrum/wallet_db.py", line 1361, in _convert_dict
    v = dict((k, SwapData(**x)) for k, x in v.items())
```
2022-03-15 13:39:33 +01:00
ThomasV
05119b0d2c lnpeer: fix shutdown: do not broadcast dummy tx 2022-03-15 09:15:48 +01:00
SomberNight
1c297d6049 android build: add Qt/QML build-time dependencies
related 78b51b3f43 (r826140909)
2022-03-14 21:36:27 +01:00
SomberNight
338637973f frozen deps: update bitbox02 and coldcard libs 2022-03-14 17:32:04 +01:00
SomberNight
b1b17029f1 android build: bump targetSdkVersion to 30
This is the new minimum the google play store requires.

note: the newer android command-line tools use a tiny bit different paths,
hence the `mv "${ANDROID_SDK_HOME}/cmdline-tools" "${ANDROID_SDK_HOME}/tools"` rename
see https://github.com/kivy/python-for-android/issues/2540
2022-03-14 16:50:10 +01:00
SomberNight
841a701acf kivy: show error when failing to save wallet file backup
related: https://github.com/spesmilo/electrum/issues/6774#issuecomment-856098099
2022-03-14 16:45:07 +01:00
nvk
12832a3199 Improved COLDCARD icons PNG+SVG (#7709) 2022-03-11 19:30:44 +00:00
SomberNight
c8dd68bd63 DeviceMgr.select_device: add some log lines
related https://github.com/spesmilo/electrum/issues/5759#issuecomment-1060093399
2022-03-11 15:49:30 +01:00
SomberNight
d7c02c4f7f network.switch_to_interface: catch 'task group terminated'
closes https://github.com/spesmilo/electrum/issues/7677
see https://github.com/spesmilo/electrum/issues/7677#issuecomment-1065170369
2022-03-11 15:39:03 +01:00
scgbckbone
67c386c39a change coldcard icons to be more consistent with the other vendors (#7708)
Co-authored-by: avirgovi <avirgovi@cisco.com>
2022-03-11 13:20:46 +00:00
SomberNight
e454a06e80 electrum-env script: don't pull in "pip install --user" pkgs
apt-get/pacman installed stuff such as PyQt5 are nice to detect
(instead of installing it via pip inside the venv), however
it is probably better to isolate the venv from the ~global pip.
2022-03-11 14:17:38 +01:00
ThomasV
a65b97d25c lnpeer: raise GracefulDisconnect in wait_for_message 2022-03-10 14:56:46 +01:00
ThomasV
b4a3622bc3 Merge pull request #7703 from spesmilo/buildozer_qml
Add Qt5/QML building framework to contrib/android:
2022-03-10 14:43:27 +01:00
ThomasV
00902a40d7 lnpeer: favor schedule_force_closing wrapper 2022-03-09 15:53:53 +01:00
ThomasV
da16b11159 minor: simplification 2022-03-09 15:46:42 +01:00
ThomasV
61eebb2b77 lnpeer: no need to raise GracefulDisconnect twice 2022-03-09 13:48:11 +01:00
ThomasV
47917d9e6c lnpeer: factorize on_warning/on_error code 2022-03-09 13:40:44 +01:00
bitromortac
3915045067 lnpeer: warnings for shutdown and open_channel 2022-03-09 13:40:44 +01:00
bitromortac
e2b1f6c6d5 lnutil: exceptions for LN protocol errors/warnings
The exceptions are meant to be raised in places where the BOLTs require
the sending of warning or error messages. They are necessary to handle
protocol failures occuring helper functions that check constraints.
2022-03-09 13:40:44 +01:00
bitromortac
9e800172ec lnpeer: send/handle error and warning messages
* adds methods for sending protocol errors/warnings
* handling of warning messages
2022-03-09 13:40:44 +01:00
bitromortac
7d8f943150 lnwire: understand warning messages 2022-03-09 13:40:44 +01:00
ThomasV
78b51b3f43 update cirrus make_apk command 2022-03-09 10:45:51 +01:00
ThomasV
d91a4da557 Add Qt5/QML building framework to contrib/android:
- update requirements file for building PyQt5
 - use separate .buildozer directories for qml and Kivy
 - add GUI and ARCH parameters to android/build.sh
2022-03-08 17:21:31 +01:00
ThomasV
6667a79f10 modern shutdown:
- clarify TODOs
 - add tests for shutdown with modern negotiation
2022-03-08 11:57:19 +01:00
ThomasV
0b203f0b94 lnpeer: refactor fee negotiation in _shutdown
- the fee negotiation is split into smaller functions, reducing the scope of variables.
  - the while loop logic is condensed in a few lines, so it is easier to understand termination conditions.
  - removed code that was never executed
2022-03-08 11:55:40 +01:00