Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

yg-privacyenhanced.py error: jmclient.storage.StorageError: Read-only storage cannot be saved. #673

Closed
github12101 opened this issue Aug 20, 2020 · 17 comments
Labels

Comments

@github12101
Copy link

Today I've noticed error in YG terminal output. After this error, YG continued to operate and log continued to populate with debug and info messages.

2020-08-20 13:51:53,349 [DEBUG]  >>privmsg on darkscience: nick=JXXX cmd=pubkey msg=8XXX
2020-08-20 13:52:02,337 [DEBUG]  mix depths that have enough = {0: XXX}
2020-08-20 13:52:02,338 [INFO]  filling offer, mixdepth=0, amount=2XXX
2020-08-20 13:52:02,893 [INFO]  sending output to address=3XXX
Unhandled Error
Traceback (most recent call last):
  File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/protocols/amp.py", line 1041, in _commandReceived
    deferred = self.dispatchCommand(box)
  File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/protocols/amp.py", line 1099, in dispatchCommand
    return maybeDeferred(responder, box)
  File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/internet/defer.py", line 151, in maybeDeferred
    result = f(*args, **kw)
  File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/protocols/amp.py", line 1186, in doit
    return maybeDeferred(aCallable, **kw).addCallback(
--- <exception caught here> ---
  File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/internet/defer.py", line 654, in _runCallbacks
    current.result = callback(current.result, *args, **kw)
  File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/protocols/amp.py", line 1169, in checkKnownErrors
    key = error.trap(*command.allErrors)
  File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/python/failure.py", line 460, in trap
    self.raiseException()
  File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/python/failure.py", line 488, in raiseException
    raise self.value.with_traceback(self.tb)
  File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/internet/defer.py", line 151, in maybeDeferred
    result = f(*args, **kw)
  File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/client_protocol.py", line 242, in on_JM_AUTH_RECEIVED
    commitment, revelation, amount, kphex)
  File "/home/nv01/joinmarket-clientserver/jmbase/jmbase/support.py", line 280, in func_wrapper
    return func(inst, *newargs, **kwargs)
  File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/maker.py", line 105, in on_auth_received
    self.wallet_service.save_wallet()
  File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/wallet_service.py", line 769, in save_wallet
    self.wallet.save()
  File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/wallet.py", line 1531, in save
    super().save()
  File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/wallet.py", line 1838, in save
    super().save()
  File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/wallet.py", line 385, in save
    self._utxos.save()
  File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/wallet.py", line 182, in save
    self.storage.save()
  File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/storage.py", line 134, in save
    raise StorageError("Read-only storage cannot be saved.")
jmclient.storage.StorageError: Read-only storage cannot be saved.

Amp server or network failure unhandled by client application.  Dropping connection!  To avoid, add errbacks to ALL remote commands!
Traceback (most recent call last):
--- <exception caught here> ---
  File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/internet/defer.py", line 654, in _runCallbacks
    current.result = callback(current.result, *args, **kw)
  File "/home/nv01/joinmarket-clientserver/jmdaemon/jmdaemon/daemon_protocol.py", line 114, in defaultErrback
    ConnectionDone, ConnectionLost)
  File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/python/failure.py", line 460, in trap
    self.raiseException()
  File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/python/failure.py", line 488, in raiseException
    raise self.value.with_traceback(self.tb)
twisted.protocols.amp.UnknownRemoteError: Code<UNKNOWN>: Unknown Error

2020-08-20 13:52:45,357 [DEBUG]  Found a new channel, setting to: JXXX,('nXXX.onion', 6667)
2020-08-20 13:52:45,434 [DEBUG]  Nick: JXXX has left.
2020-08-20 13:53:43,052 [DEBUG]  Dynamic switch nick: JXXX
2020-08-20 13:55:25,035 [DEBUG]  JXXX has dusty minsize, capping at 2730
2020-08-20 13:55:25,155 [DEBUG]  JXXX has dusty minsize, capping at 2730
(...)

My storage is fine, there is no hardware problems, everything works perfectly on my server and certainly there is read-write rights to my /home partition where joinmarket folder reside. I'm using joinmarket from git, latest commit is:
commit 28ce6ab4596df7c34b96e0d1ba777861c72cb70b (HEAD -> master, origin/master, origin/HEAD) Merge: 8b980c1 8de8381 Author: Adam Gibson <ekaggata@gmail.com> Date: Mon Aug 10 15:37:32 2020 +0100

@github12101
Copy link
Author

I have now done git reset --hard, fetch and rebase origin, updated to latest commit and restarted YG. Will monitor for more errors.

@AdamISZ
Copy link
Member

AdamISZ commented Aug 20, 2020

So the question is why do you have a read-only storage.

As far as I know, read-only is only a mode in which a wallet can be opened, and this is only currently used by wallet-tool.py for certain methods (like display). The reason for that was to allow wallet-tool to view the wallet without acquiring the write lock (~/.joinmarket/wallets/.wallet.jmdat.lock or equivalent).

Note that this is not related to file permissions; it's a feature of the Storage class which gets instantiated when you open a wallet.

I've never heard of someone trying to run yield generator scripts and having the wallet be read only, and I can't find it in the code.
Is there anything unusual about your set up? Because I can't make any sense of it, as is.

@github12101
Copy link
Author

github12101 commented Aug 21, 2020

Thanks for your reply.
There is nothing unusual about my setup. Debian 10 Buster, stable with all updates and backports. I do not have read only storage. Server been running for 3 days straight since last system update and reboot, and it continues to run perfectly.

I've completed many transactions on YG so far and this is first time this happened. Now, after update and restart of joinmarket, YG continue to operate normally and I had few transactions since yesterday, please see parts of my log:

(...)
2020-08-20 18:24:21,394 [DEBUG]  Fast sync in progress. Got this many used addresses: 394
(...)
2020-08-20 18:25:07,024 [INFO]  All IRC servers connected, starting execution.
2020-08-20 18:25:07,026 [INFO]  JM daemon setup complete
(...)
2020-08-21 00:02:43,122 [DEBUG]  mix depths that have enough = {XXX}
2020-08-21 00:02:43,122 [INFO]  filling offer, mixdepth=0, amount=8XXX
2020-08-21 00:02:43,933 [INFO]  sending output to address=3XXX
(...)
2020-08-21 02:34:33,730 [INFO]  tx in a block: cXXX with 1 confirmations.
2020-08-21 02:34:33,734 [INFO]  Warning: too high txfee to be profitable, halfing it to: 40
2020-08-21 02:34:33,734 [INFO]  Warning: too high txfee to be profitable, halfing it to: 20
2020-08-21 02:34:33,735 [INFO]  Warning: too high txfee to be profitable, halfing it to: 10
2020-08-21 02:34:33,735 [INFO]  Warning: too high txfee to be profitable, halfing it to: 5
2020-08-21 02:34:33,735 [INFO]  Warning: too high txfee to be profitable, halfing it to: 2
2020-08-21 02:34:33,735 [INFO]  Warning: too high txfee to be profitable, halfing it to: 1
2020-08-21 02:34:33,735 [INFO]  modifying orders. to_cancel=[]
to_announce=[{'oid': 0, 'ordertype': 'swreloffer', 'minsize': XXX (...)

It's running fine, storage is read write certainly, I haven't restarted my server, other programs are running fine.
I don't see any particular in my setup to blame, and there has not been a message in dmesg for three days (meaning that Linux has not found any errors, no hard drive problems, nothing unusual is happening with the hardware etc.).

@AdamISZ
Copy link
Member

AdamISZ commented Aug 21, 2020

Interesting case. I'll have to squint at the code very hard because I can't figure out what might cause this. I mean clearly it sounds like a bug getting triggered in a rare edge case, but even if so, it's an unpleasant bug.
If you have any other contextual information you can offer that might help debugging (not necessarily 'something wrong with your environment', just details of your usage, to whatever extent possible that doesn't violate privacy), please jot it down here.

@github12101
Copy link
Author

github12101 commented Aug 22, 2020

Thanks for your interest in this. My system is nothing unusual, really.

OS: Debian GNU/Linux 10 (buster) x86_64
Kernel: 5.7.0-0.bpo.2-amd64
Uptime: 4 days, 23 hours, 15 mins
Packages: 1734 (dpkg)
Shell: bash 5.0.3
CPU: AMD Ryzen 7 1700 (16) @ 3.000GHz
Memory: 6811MiB / 32116MiB

$ dpkg -l |grep python
ii  dh-python                               3.20190308                          all          Debian helper tools for packaging Python libraries and applications
ii  libpeas-1.0-python2loader:amd64         1.22.0-4                            amd64        Application plugin library (Python 2 support)
ii  libpython-all-dev:amd64                 2.7.16-1                            amd64        package depending on all supported Python2 development packages
ii  libpython-dev:amd64                     2.7.16-1                            amd64        header files and a static library for Python2
ii  libpython-stdlib:amd64                  2.7.16-1                            amd64        interactive high-level object-oriented language (Python2)
ii  libpython2-dev:amd64                    2.7.16-1                            amd64        header files and a static library for Python2
ii  libpython2-stdlib:amd64                 2.7.16-1                            amd64        interactive high-level object-oriented language (Python2)
ii  libpython2.7:amd64                      2.7.16-2+deb10u1                    amd64        Shared Python runtime library (version 2.7)
ii  libpython2.7-dev:amd64                  2.7.16-2+deb10u1                    amd64        Header files and a static library for Python (v2.7)
ii  libpython2.7-minimal:amd64              2.7.16-2+deb10u1                    amd64        Minimal subset of the Python language (version 2.7)
ii  libpython2.7-stdlib:amd64               2.7.16-2+deb10u1                    amd64        Interactive high-level object-oriented language (standard library, version 2.7)
ii  libpython3-dev:amd64                    3.7.3-1                             amd64        header files and a static library for Python (default)
ii  libpython3-stdlib:amd64                 3.7.3-1                             amd64        interactive high-level object-oriented language (default python3 version)
ii  libpython3.7:amd64                      3.7.3-2+deb10u2                     amd64        Shared Python runtime library (version 3.7)
ii  libpython3.7-dev:amd64                  3.7.3-2+deb10u2                     amd64        Header files and a static library for Python (v3.7)
ii  libpython3.7-minimal:amd64              3.7.3-2+deb10u2                     amd64        Minimal subset of the Python language (version 3.7)
ii  libpython3.7-stdlib:amd64               3.7.3-2+deb10u2                     amd64        Interactive high-level object-oriented language (standard library, version 3.7)
ii  python                                  2.7.16-1                            amd64        interactive high-level object-oriented language (Python2 version)
ii  python-all                              2.7.16-1                            amd64        package depending on all supported Python2 runtime versions
ii  python-all-dev                          2.7.16-1                            amd64        package depending on all supported Python2 development packages
ii  python-apt-common                       1.8.4.1                             all          Python interface to libapt-pkg (locales)
ii  python-asn1crypto                       0.24.0-1                            all          Fast ASN.1 parser and serializer (Python 2)
ii  python-certbot-apache                   0.31.0-1                            all          transitional dummy package
ii  python-cffi-backend                     1.12.2-1                            amd64        Foreign Function Interface for Python calling C code - backend
ii  python-configparser                     3.5.0b2-1                           all          backport of the enhanced config parser introduced in Python 3.2
ii  python-crypto                           2.6.1-9+b1                          amd64        cryptographic algorithms and protocols for Python
ii  python-cryptography                     2.6.1-3+deb10u2                     amd64        Python library exposing cryptographic recipes and primitives (Python 2)
ii  python-dbus                             1.2.8-3                             amd64        simple interprocess messaging system (Python interface)
ii  python-dev                              2.7.16-1                            amd64        header files and a static library for Python2
ii  python-entrypoints                      0.3-1                               all          Discover and load entry points from installed packages (Python 2)
ii  python-enum34                           1.1.6-2                             all          backport of Python 3.4's enum package
ii  python-gi                               3.30.4-1                            amd64        Python 2.x bindings for gobject-introspection libraries
ii  python-ipaddress                        1.0.17-1                            all          Backport of Python 3 ipaddress module (Python 2)
ii  python-keyring                          17.1.1-1                            all          store and access your passwords safely
ii  python-keyrings.alt                     3.1.1-1                             all          alternate backend implementations for python-keyring
ii  python-mate-menu                        1.20.2-1                            amd64        implementation of the freedesktop menu specification for MATE (Python bindings)
ii  python-minimal                          2.7.16-1                            amd64        minimal subset of the Python2 language
ii  python-pip                              18.1-5                              all          Python package installer
ii  python-pip-whl                          18.1-5                              all          Python package installer
ii  python-pkg-resources                    40.8.0-1                            all          Package Discovery and Resource Access using pkg_resources
ii  python-pyicu                            2.2-2                               amd64        Python extension wrapping the ICU C++ API
ii  python-secretstorage                    2.3.1-2                             all          Python module for storing secrets - Python 2.x version
ii  python-setuptools                       40.8.0-1                            all          Python Distutils Enhancements
ii  python-six                              1.12.0-1                            all          Python 2 and 3 compatibility library (Python 2 interface)
ii  python-talloc:amd64                     2.1.14-2                            amd64        hierarchical pool based memory allocator - Python bindings
ii  python-tk                               2.7.16-2                            amd64        Tkinter - Writing Tk applications with Python2
ii  python-virtualenv                       15.1.0+ds-2                         all          Python virtual environment creator
ii  python-wheel                            0.32.3-2                            all          built-package format for Python
ii  python-xdg                              0.25-5                              all          Python 2 library to access freedesktop.org standards
ii  python2                                 2.7.16-1                            amd64        interactive high-level object-oriented language (Python2 version)
ii  python2-dev                             2.7.16-1                            amd64        header files and a static library for Python2
ii  python2-minimal                         2.7.16-1                            amd64        minimal subset of the Python2 language
ii  python2.7                               2.7.16-2+deb10u1                    amd64        Interactive high-level object-oriented language (version 2.7)
ii  python2.7-dev                           2.7.16-2+deb10u1                    amd64        Header files and a static library for Python (v2.7)
ii  python2.7-minimal                       2.7.16-2+deb10u1                    amd64        Minimal subset of the Python language (version 2.7)
ii  python3                                 3.7.3-1                             amd64        interactive high-level object-oriented language (default python3 version)
ii  python3-acme                            0.31.0-2                            all          ACME protocol library for Python 3
ii  python3-apt                             1.8.4.1                             amd64        Python 3 interface to libapt-pkg
ii  python3-asn1crypto                      0.24.0-1                            all          Fast ASN.1 parser and serializer (Python 3)
ii  python3-augeas                          0.5.0-1                             all          Python3 bindings for Augeas
ii  python3-btrfs                           11-2                                all          python module to inspect btrfs filesystems
ii  python3-cairo:amd64                     1.16.2-1+b1                         amd64        Python3 bindings for the Cairo vector graphics library
ii  python3-certbot                         0.31.0-1                            all          main library for certbot
ii  python3-certbot-apache                  0.31.0-1                            all          Apache plugin for Certbot
ii  python3-certifi                         2018.8.24-1                         all          root certificates for validating SSL certs and verifying TLS hosts (python3)
ii  python3-cffi-backend                    1.12.2-1                            amd64        Foreign Function Interface for Python 3 calling C code - runtime
ii  python3-chardet                         3.0.4-3                             all          universal character encoding detector for Python3
ii  python3-configargparse                  0.13.0-1                            all          replacement for argparse with config files and environment variables (Python 3)
ii  python3-configobj                       5.0.6-3                             all          simple but powerful config file reader and writer for Python 3
ii  python3-crypto                          2.6.1-9+b1                          amd64        cryptographic algorithms and protocols for Python 3
ii  python3-cryptography                    2.6.1-3+deb10u2                     amd64        Python library exposing cryptographic recipes and primitives (Python 3)
ii  python3-dbus                            1.2.8-3                             amd64        simple interprocess messaging system (Python 3 interface)
ii  python3-debconf                         1.5.71                              all          interact with debconf from Python 3
ii  python3-debian                          0.1.35                              all          Python 3 modules to work with Debian-related data formats
ii  python3-debianbts                       3.0.2~bpo10+1                       all          Python interface to Debian's Bug Tracking System
ii  python3-dev                             3.7.3-1                             amd64        header files and a static library for Python (default)
ii  python3-distro                          1.3.0-1                             all          Linux OS platform information API
ii  python3-distutils                       3.7.3-1                             all          distutils package for Python 3.x
ii  python3-enchant                         2.0.0-1                             all          spellchecking library for Python 3
ii  python3-entrypoints                     0.3-1                               all          Discover and load entry points from installed packages (Python 3)
ii  python3-future                          0.16.0-1                            all          Clean single-source support for Python 3 and 2 - Python 3.x
ii  python3-gi                              3.30.4-1                            amd64        Python 3 bindings for gobject-introspection libraries
ii  python3-gi-cairo                        3.30.4-1                            amd64        Python 3 Cairo bindings for the GObject library
ii  python3-gtkspellcheck                   4.0.5-1                             all          Python 3 spellchecking library for GTK+ based on Enchant
ii  python3-httplib2                        0.11.3-2                            all          comprehensive HTTP client library written for Python3
ii  python3-idna                            2.10-1~bpo10+1                      all          Python IDNA2008 (RFC 5891) handling (Python 3)
ii  python3-josepy                          1.1.0-2                             all          JOSE implementation for Python 3.x
ii  python3-keyring                         17.1.1-1                            all          store and access your passwords safely - Python 3 version of the package
ii  python3-keyrings.alt                    3.1.1-1                             all          alternate backend implementations for python3-keyring
ii  python3-lib2to3                         3.7.3-1                             all          Interactive high-level object-oriented language (2to3, version 3.6)
ii  python3-mako                            1.0.7+ds1-1                         all          fast and lightweight templating for the Python 3 platform
ii  python3-markupsafe                      1.1.0-1                             amd64        HTML/XHTML/XML string library for Python 3
ii  python3-minimal                         3.7.3-1                             amd64        minimal subset of the Python language (default python3 version)
ii  python3-mock                            2.0.0-4                             all          Mocking and Testing Library (Python3 version)
ii  python3-openssl                         19.0.0-1                            all          Python 3 wrapper around the OpenSSL library
ii  python3-parsedatetime                   2.4-2                               all          Python 3 module to parse human-readable date/time expressions
ii  python3-pbr                             4.2.0-5                             all          inject useful and sensible default behaviors into setuptools - Python 3.x
ii  python3-pip                             18.1-5                              all          Python package installer
ii  python3-pkg-resources                   40.8.0-1                            all          Package Discovery and Resource Access using pkg_resources
ii  python3-pycurl                          7.43.0.2-0.1                        amd64        Python bindings to libcurl (Python 3)
ii  python3-pyinotify                       0.9.6-1                             all          simple Linux inotify Python bindings
ii  python3-pysimplesoap                    1.16.2-1                            all          simple and lightweight SOAP Library (Python 3)
ii  python3-reportbug                       7.5.3~deb10u1                       all          Python modules for interacting with bug tracking systems
ii  python3-requests                        2.21.0-1                            all          elegant and simple HTTP library for Python3, built for human beings
ii  python3-requests-toolbelt               0.8.0-1                             all          Utility belt for advanced users of python3-requests
ii  python3-rfc3339                         1.1-1                               all          parser and generator of RFC 3339-compliant timestamps (Python 3)
ii  python3-secretstorage                   2.3.1-2                             all          Python module for storing secrets - Python 3.x version
ii  python3-setuptools                      40.8.0-1                            all          Python3 Distutils Enhancements
ii  python3-six                             1.12.0-1                            all          Python 2 and 3 compatibility library (Python 3 interface)
ii  python3-systemd                         234-2+b1                            amd64        Python 3 bindings for systemd
ii  python3-tz                              2019.1-1                            all          Python3 version of the Olson timezone database
ii  python3-urllib3                         1.24.1-1                            all          HTTP library with thread-safe connection pooling for Python3
ii  python3-virtualenv                      15.1.0+ds-2                         all          Python virtual environment creator
ii  python3-wheel                           0.32.3-2                            all          built-package format for Python
ii  python3-xdg                             0.25-5                              all          Python 3 library to access freedesktop.org standards
ii  python3-zope.component                  4.3.0-1                             all          Zope Component Architecture
ii  python3-zope.event                      4.2.0-1                             all          Very basic event publishing system
ii  python3-zope.hookable                   4.0.4-4+b4                          amd64        Hookable object support
ii  python3-zope.interface                  4.3.2-1+b2                          amd64        Interfaces for Python3
ii  python3.7                               3.7.3-2+deb10u2                     amd64        Interactive high-level object-oriented language (version 3.7)
ii  python3.7-dev                           3.7.3-2+deb10u2                     amd64        Header files and a static library for Python (v3.7)
ii  python3.7-minimal                       3.7.3-2+deb10u2                     amd64        Minimal subset of the Python language (version 3.7)

@github12101
Copy link
Author

github12101 commented Aug 22, 2020

My JoinMarket is as follows: cloned github repo to default folder. I start it each time by:

cd ~/joinmarket-clientserver/
source jmvenv/bin/activate
python scripts/yg-privacyenhanced.py walletXXX.jmdat

Every now and then, I do git reset --hard, git fetch, git rebase origin. python3 --version outputs Python 3.7.3. JoinMarket definitely uses it, as forcing it to python2 crashes, so definitely I am using python3.
I've been using YG like that for almost half a year now.
That's all what comes to my mind when describing this system.

@kristapsk
Copy link
Member

kristapsk commented Sep 29, 2020

Just noticed similar issue on my test RaspiBolt setup. It had worked for some time normally before this, so there definitely isn't any configuration / permission issues. All possible involved partitions are rw.

YYYY-MM-DD HH:MM:SS,mss [INFO]  filling offer, mixdepth=0, amount=nnn
YYYY-MM-DD HH:MM:SS,mss [INFO]  sending output to address=XXXX                                                                                                  
Unhandled Error                                           
Traceback (most recent call last):                                                                                                                                                            
  File "/home/bitcoin/joinmarket/jmvenv/lib/python3.7/site-packages/twisted/protocols/amp.py", line 1041, in _commandReceived
    deferred = self.dispatchCommand(box)                                                                                                                                                      
  File "/home/bitcoin/joinmarket/jmvenv/lib/python3.7/site-packages/twisted/protocols/amp.py", line 1099, in dispatchCommand
    return maybeDeferred(responder, box)                                                                                                                                                      
  File "/home/bitcoin/joinmarket/jmvenv/lib/python3.7/site-packages/twisted/internet/defer.py", line 151, in maybeDeferred
    result = f(*args, **kw)                                           
  File "/home/bitcoin/joinmarket/jmvenv/lib/python3.7/site-packages/twisted/protocols/amp.py", line 1186, in doit
    return maybeDeferred(aCallable, **kw).addCallback(
--- <exception caught here> ---
  File "/home/bitcoin/joinmarket/jmvenv/lib/python3.7/site-packages/twisted/internet/defer.py", line 654, in _runCallbacks
    current.result = callback(current.result, *args, **kw)
  File "/home/bitcoin/joinmarket/jmvenv/lib/python3.7/site-packages/twisted/protocols/amp.py", line 1169, in checkKnownErrors
    key = error.trap(*command.allErrors)
  File "/home/bitcoin/joinmarket/jmvenv/lib/python3.7/site-packages/twisted/python/failure.py", line 460, in trap
    self.raiseException()
  File "/home/bitcoin/joinmarket/jmvenv/lib/python3.7/site-packages/twisted/python/failure.py", line 488, in raiseException
    raise self.value.with_traceback(self.tb)
  File "/home/bitcoin/joinmarket/jmvenv/lib/python3.7/site-packages/twisted/internet/defer.py", line 151, in maybeDeferred
    result = f(*args, **kw)
  File "/home/bitcoin/joinmarket-clientserver-0.7.0/jmclient/jmclient/client_protocol.py", line 242, in on_JM_AUTH_RECEIVED
    commitment, revelation, amount, kphex)
  File "/home/bitcoin/joinmarket-clientserver-0.7.0/jmbase/jmbase/support.py", line 280, in func_wrapper
    return func(inst, *newargs, **kwargs)
  File "/home/bitcoin/joinmarket-clientserver-0.7.0/jmclient/jmclient/maker.py", line 105, in on_auth_received
    self.wallet_service.save_wallet()
  File "/home/bitcoin/joinmarket-clientserver-0.7.0/jmclient/jmclient/wallet_service.py", line 769, in save_wallet
    self.wallet.save()
  File "/home/bitcoin/joinmarket-clientserver-0.7.0/jmclient/jmclient/wallet.py", line 1531, in save
    super().save()
  File "/home/bitcoin/joinmarket-clientserver-0.7.0/jmclient/jmclient/wallet.py", line 1838, in save
    super().save()
  File "/home/bitcoin/joinmarket-clientserver-0.7.0/jmclient/jmclient/wallet.py", line 385, in save
    self._utxos.save()
  File "/home/bitcoin/joinmarket-clientserver-0.7.0/jmclient/jmclient/wallet.py", line 182, in save
    self.storage.save()
  File "/home/bitcoin/joinmarket-clientserver-0.7.0/jmclient/jmclient/storage.py", line 134, in save
    raise StorageError("Read-only storage cannot be saved.")
jmclient.storage.StorageError: Read-only storage cannot be saved.

Amp server or network failure unhandled by client application.  Dropping connection!  To avoid, add errbacks to ALL remote commands!
Traceback (most recent call last):
--- <exception caught here> ---
  File "/home/bitcoin/joinmarket/jmvenv/lib/python3.7/site-packages/twisted/internet/defer.py", line 654, in _runCallbacks
    current.result = callback(current.result, *args, **kw)
  File "/home/bitcoin/joinmarket-clientserver-0.7.0/jmdaemon/jmdaemon/daemon_protocol.py", line 114, in defaultErrback
    ConnectionDone, ConnectionLost)
  File "/home/bitcoin/joinmarket/jmvenv/lib/python3.7/site-packages/twisted/python/failure.py", line 460, in trap
    self.raiseException()
  File "/home/bitcoin/joinmarket/jmvenv/lib/python3.7/site-packages/twisted/python/failure.py", line 488, in raiseException
    raise self.value.with_traceback(self.tb)
twisted.protocols.amp.UnknownRemoteError: Code<UNKNOWN>: Unknown Error

@kristapsk kristapsk reopened this Sep 29, 2020
@kristapsk
Copy link
Member

Closing issue was accident, randomly hit some keyboard shortcut.

@AdamISZ
Copy link
Member

AdamISZ commented Sep 29, 2020

If as you said on IRC it's still running, I'll be back in a few hours from now and have a think :)

@AdamISZ
Copy link
Member

AdamISZ commented Sep 29, 2020

is there some weird sub-case where atexit.register might get called without the program shutting down?

https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master/jmclient/jmclient/storage.py#L301

As I may have mentioned before, it is almost certainly this line that is causing the offence:

https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master/jmclient/jmclient/storage.py#L312

... the obvious question being, why would Storage.close() be called if the wallet wasn't being closed. (but: see the previous question). Also worth noting is that the setting of read-only to True as part of the close() call was part of the original implementation, see this commit, I don't immediately understand it.

The above is just a summary of thoughts I already had in the previous case of this bug. I'll have another think shortly.

@undeath
Copy link
Contributor

undeath commented Sep 29, 2020

Having looked at the code, I think the problem is here:

which is called if connection to bitcoind is lost here:

After calling stopService, the wallet is closed and even with a new WalletService instance can no longer be saved.

@AdamISZ
Copy link
Member

AdamISZ commented Sep 29, 2020

Oh nice job @undeath thanks :)

@github12101
Copy link
Author

github12101 commented Sep 29, 2020

When I reported this issue at the time, bitcoind was running just fine on local machine. But I've watched recently Adam Gibson' presentation on Youtube (Bitcoin Meetup Munich, I watched 3.5hrs whole of it :) that latency (or quality of connection) to bitcoind is important and when someone is using remote bitcoind, it can cause issues and connectivity problems.

Maybe my machine was I/O busy at the time (ElectrumX is eating a lot of I/O, and I do run other programs there) and there was not enough time for bitcoind to respond to JoinMarket? And it killed connection with bitcoin and then subsequently failed on read-only storage thing? Maybe there could be added waiting time for bitcoind to reply, some 60s grace timeout or something.
Anyway, it would be great to fix this to increase reliability of JM.

@AdamISZ
Copy link
Member

AdamISZ commented Sep 29, 2020

Bitcoin Meetup Munich, I watched 3.5hrs whole of it

Sorry about that 😆

Maybe my machine was I/O busy at the time ... ()

This kind of thing seems to be fairly common, i.e. failures of RPC calls to bitcoind, especially if you're calling remotely, and yes probably having various system resource limitations/slowness may play a part too. We've had regular reports over the years of RPC calls failing, and there is a lot of exception handling code nowadays to ensure that the yg doesn't just fall over because of a temporary connection failure.

After @undeath 's diagnosis above, it should be pretty clear for me to figure out how to fix this specific bug (I will start right now), albeit problems of this type are unlikely to permanently disappear.

@AdamISZ AdamISZ added the bug label Sep 29, 2020
@AdamISZ
Copy link
Member

AdamISZ commented Sep 29, 2020

So I wonder if I can canvas opinion on this:

This kind of problem comes out of a fairly deep uncertainty on what to do in cases where there are failures in JM "talking to Bitcoin Core".
I have solid reasons why I really would prefer the program to panic when this situation occurs. If we can't update the block height, it means we don't know the block height, and the transaction monitor, which is looking for new and removed utxos in the wallet, cannot operate correctly - it uses the block height as part of the storage of utxo information so we always know the confirmations number.
But that's only part of it - how hard is it to reason about the operations of Joinmarket if the program can't even trust that it has the right state of the blockchain? Perhaps it isn't too bad, but I'd hate to be the one to reason everything through.

But there is a counterpoint: a big part of what yg does is to try to stay running for days, weeks, months at a time. It's hard if even one temporary failed network call crashes the program.

To illustrate the point, see:

if not self.update_blockheight():
# this accounts for the unusual case
# where the application started up with
# a functioning blockchain interface, but
# that bci is now failing when we are starting
# the wallet service.
raise Exception("WalletService failed to start "
"due to inability to query block height.")

Notice here we panic. I want to tend towards the first of the above two points (I hope the argument is convincing). As a result I'm really not sure why the same reasoning isn't applied everywhere that update_blockheight fails, so specifically, here:

if not self.update_blockheight():
return

... which is called on every tick of the transaction monitor loop. Currently this is where the bug will occur, because you are in a normal running state, the rpc call for blockheight fails, WalletService.stopService() is called, wallet.close() is called with puts the Storage in read only but then we continue running as if nothing happened. I think we should crash if we can't update the blockheight, unless we have a substantially more sophisticated way of operating.

Honestly it's kind of tricky.

@github12101
Copy link
Author

github12101 commented Sep 29, 2020

Sorry about that

I enjoyed it and learned a lot. 🥇 👍 It was you now I realized :) Thanks.

Perhaps easy solution can be implemented for now (crash hard with suitable error message so we know what happened, do not let it hang in zombie mode), and later implement solution to wait gracefully for Bitcoin Core to respond? At least 10 seconds wait would solve this I guess. By the way I have 2x 2TB drives in mdadm RAID1 mode for /home, they are quick and in very good condition, so it's not like it's dying, obsolete and faulty hardware generate this errors. System is on mdadm RAID1 too (2xSSD) and all is powered by 16-threaded Ryzen 7. Bitcoind and electrumx thrashing HDDs and pounding on CPU all the time and they never moan.

@AdamISZ
Copy link
Member

AdamISZ commented Sep 29, 2020

So there's been a little back and forth on IRC, but I want to summarize it here for future reference (although you can find today's log at gnusha.org/joinmarket/):

-> Does the WalletService really need to call wallet.close() when it's being stopped?

-> After some time I remembered where that call to wallet.close() (see #673 (comment) above) was put there for this reason:

Long running programs like the JoinmarketQt GUI will want to open, close multiple wallets, including the same wallet, and since the wallet is locked until it is closed, it means we need to close the wallet and shutdown the monitor service when opening a new wallet in Qt. See #595 .

-> Whilst this is true, it doesn't address the point raised in this Issue; what do we do when an RPC call fails such that our blockchain access is apparently non-functional? We cannot leave it as-is, it seems, since stopping the service and closing the wallet means the Maker is no longer monitoring the blockchain, and cannot access the wallet (as he needs to of course, when negotiating a transaction, starting in Maker.on_auth_received where he needs to grab new addresses and then update the wallet index, necessitating writing to the wallet. So I hope you can see that that is somewhat academic, the point is that with the service stopped we cannot and should not be doing anything.

-> But simply not stopping the service and not closing the wallet is in my opinion not a solution, largely because of the concerns outlined above: we don't know that we have access to up to date bitcoin blockchain information, so it is not really safe to continue.

There are therefore two approaches, as I believe I mentioned elsewhere a couple of months back: either "shut down everything" or find a way to pause the entire running of the maker until we know RPC access is working correctly.

The latter is the "right" solution but is going to take significant work. Since I, @undeath and @curious0101 above have now said largely the same thing, I think the only sensible thing is to write a short patch that gracefully quits the application when we fail to read the blockheight in WalletService.transaction_monitor(), and later a PR can be written to do the much more substantial work of having a "pause" mode for the Maker with it waking up again once the RPC calls are known to be working, and the connection to bitcoind is "live".

@AdamISZ AdamISZ closed this as completed in a2aafd2 Oct 8, 2020
AdamISZ added a commit that referenced this issue Oct 8, 2020
5604857 quit scripts gracefully on walletservice rpc startup failure (Adam Gibson)
5af2d49 handle Qt wallet load failure (Adam Gibson)
202f8ee Add clarifying comments for delayed order creation. (Adam Gibson)
a2aafd2 Fixes #673. Shutdown cleanly on failure to access blockheight (Adam Gibson)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants