# Buggy code
def __init__(self, wallet):
    # The two principal member variables
    # are the blockchaininterface instance,
    # which is currently global in JM but
    # could be more flexible in future, and
    # the JM wallet object.
    self.bci = jm_single().bc_interface

    # main loop used to check for transactions, instantiated
    # after wallet is synced:
    self.monitor_loop = None
    self.wallet = wallet
    self.synced = False

    # keep track of the quasi-real-time blockheight
    # (updated in main monitor loop)
    self.current_blockheight = None
    if self.bci is not None:
        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."
            )
    else:
        jlog.warning(
            "No blockchain source available, "
            + "wallet tools will not show correct balances."
        )

    # Dicts of registered callbacks, by type
    # and then by txinfo, for events
    # on transactions.
    self.callbacks = {}
    self.callbacks["all"] = []
    self.callbacks["unconfirmed"] = {}
    self.callbacks["confirmed"] = {}

    self.restart_callback = None

    # transactions we are actively monitoring,
    # i.e. they are not new but we want to track:
    self.active_txids = []
    # to ensure transactions are only processed once:
    self.processed_txids = []

    self.set_autofreeze_warning_cb()


# Traceback (jmclient.storage.StorageError)
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
(...)

# Fixed code
def __init__(self, wallet):
    # The two principal member variables
    # are the blockchaininterface instance,
    # which is currently global in JM but
    # could be more flexible in future, and
    # the JM wallet object.
    self.bci = jm_single().bc_interface

    # main loop used to check for transactions, instantiated
    # after wallet is synced:
    self.monitor_loop = None
    self.wallet = wallet
    self.synced = False

    # keep track of the quasi-real-time blockheight
    # (updated in main monitor loop)
    self.current_blockheight = None
    if self.bci is not None:
        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.
            jlog.error(
                "Failure of RPC connection to Bitcoin Core in "
                "wallet service startup. Application cannot "
                "continue, shutting down."
            )
            stop_reactor()
    else:
        jlog.warning(
            "No blockchain source available, "
            + "wallet tools will not show correct balances."
        )

    # Dicts of registered callbacks, by type
    # and then by txinfo, for events
    # on transactions.
    self.callbacks = {}
    self.callbacks["all"] = []
    self.callbacks["unconfirmed"] = {}
    self.callbacks["confirmed"] = {}

    self.restart_callback = None

    # transactions we are actively monitoring,
    # i.e. they are not new but we want to track:
    self.active_txids = []
    # to ensure transactions are only processed once:
    self.processed_txids = []

    self.set_autofreeze_warning_cb()