# Buggy code
def loadWalletFromBlockchain(self, firstarg=None, pwd=None):
    if firstarg:
        wallet_path = get_wallet_path(str(firstarg), None)
        try:
            wallet = open_test_wallet_maybe(
                wallet_path,
                str(firstarg),
                None,
                ask_for_password=False,
                password=pwd.encode("utf-8") if pwd else None,
                gap_limit=jm_single().config.getint("GUI", "gaplimit"),
            )
        except RetryableStorageError as e:
            JMQtMessageBox(self, str(e), mbtype="warn", title="Error")
            return False
        # only used for GUI display on regtest:
        self.testwalletname = wallet.seed = str(firstarg)
    if isinstance(wallet, FidelityBondMixin):
        raise Exception("Fidelity bond wallets not supported by Qt")
    if "listunspent_args" not in jm_single().config.options("POLICY"):
        jm_single().config.set("POLICY", "listunspent_args", "[0]")
    assert wallet, "No wallet loaded"

    # shut down any existing wallet service
    # monitoring loops
    if self.wallet_service is not None:
        if self.wallet_service.isRunning():
            self.wallet_service.stopService()
    if self.walletRefresh is not None:
        self.walletRefresh.stop()

    self.wallet_service = WalletService(wallet)

    if jm_single().bc_interface is None:
        self.centralWidget().widget(0).updateWalletInfo(
            get_wallet_printout(self.wallet_service)
        )
        return True

    # add information callbacks:
    self.wallet_service.add_restart_callback(self.restartWithMsg)
    self.wallet_service.autofreeze_warning_cb = self.autofreeze_warning_cb
    self.wallet_service.startService()
    self.syncmsg = ""
    self.walletRefresh = task.LoopingCall(self.updateWalletInfo)
    self.walletRefresh.start(5.0)

    self.statusBar().showMessage("Reading wallet from blockchain ...")
    return True


# 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 loadWalletFromBlockchain(self, firstarg=None, pwd=None):
    if firstarg:
        wallet_path = get_wallet_path(str(firstarg), None)
        try:
            wallet = open_test_wallet_maybe(
                wallet_path,
                str(firstarg),
                None,
                ask_for_password=False,
                password=pwd.encode("utf-8") if pwd else None,
                gap_limit=jm_single().config.getint("GUI", "gaplimit"),
            )
        except RetryableStorageError as e:
            JMQtMessageBox(self, str(e), mbtype="warn", title="Error")
            return False
        # only used for GUI display on regtest:
        self.testwalletname = wallet.seed = str(firstarg)
    if isinstance(wallet, FidelityBondMixin):
        raise Exception("Fidelity bond wallets not supported by Qt")
    if "listunspent_args" not in jm_single().config.options("POLICY"):
        jm_single().config.set("POLICY", "listunspent_args", "[0]")
    assert wallet, "No wallet loaded"

    # shut down any existing wallet service
    # monitoring loops
    if self.wallet_service is not None:
        if self.wallet_service.isRunning():
            self.wallet_service.stopService()
    if self.walletRefresh is not None:
        self.walletRefresh.stop()

    self.wallet_service = WalletService(wallet)
    # in case an RPC error occurs in the constructor:
    if self.wallet_service.rpc_error:
        JMQtMessageBox(
            self, self.wallet_service.rpc_error, mbtype="warn", title="Error"
        )
        return "error"

    if jm_single().bc_interface is None:
        self.centralWidget().widget(0).updateWalletInfo(
            get_wallet_printout(self.wallet_service)
        )
        return True

    # add information callbacks:
    self.wallet_service.add_restart_callback(self.restartWithMsg)
    self.wallet_service.autofreeze_warning_cb = self.autofreeze_warning_cb
    self.wallet_service.startService()
    self.syncmsg = ""
    self.walletRefresh = task.LoopingCall(self.updateWalletInfo)
    self.walletRefresh.start(5.0)

    self.statusBar().showMessage("Reading wallet from blockchain ...")
    return True