electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 7a6ec23b6ecfe48e28e16d2a9cd1bb255ead75c8
parent 1a9e6a434f9fb5277c0813e2438805e1f23397be
Author: SomberNight <somber.night@protonmail.com>
Date:   Mon, 29 Jun 2020 02:19:03 +0200

cosigner pool: use single thread to send messages

ServerProxy does not seem to be thread-safe.
For e.g. a 2of3 multisig wallet, which would send two messages,
one msg would get sent but the other might error out. See trace:

E | plugins.cosigner_pool.qt.Plugin | on_failure
Traceback (most recent call last):
  File "...\electrum\electrum\gui\qt\util.py", line 832, in run
    result = task.task()
  File "...\electrum\electrum\plugins\cosigner_pool\qt.py", line 199, in <lambda>
    task = lambda: server.put(_hash, message)
  File "...\Python38\lib\xmlrpc\client.py", line 1109, in __call__
    return self.__send(self.__name, args)
  File "...\Python38\lib\xmlrpc\client.py", line 1450, in __request
    response = self.__transport.request(
  File "...\Python38\lib\xmlrpc\client.py", line 1153, in request
    return self.single_request(host, handler, request_body, verbose)
  File "...\Python38\lib\xmlrpc\client.py", line 1165, in single_request
    http_conn = self.send_request(host, handler, request_body, verbose)
  File "...\Python38\lib\xmlrpc\client.py", line 1271, in send_request
    connection.putrequest("POST", handler, skip_accept_encoding=True)
  File "...\Python38\lib\http\client.py", line 1088, in putrequest
    raise CannotSendRequest(self.__state)
http.client.CannotSendRequest: Request-sent

Diffstat:
Melectrum/plugins/cosigner_pool/qt.py | 20+++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/electrum/plugins/cosigner_pool/qt.py b/electrum/plugins/cosigner_pool/qt.py @@ -188,17 +188,27 @@ class Plugin(BasePlugin): except OSError: pass window.show_error(_("Failed to send transaction to cosigning pool") + ':\n' + repr(e)) + buffer = [] + some_window = None + # construct messages for window, xpub, K, _hash in self.cosigner_list: if not self.cosigner_can_sign(tx, xpub): continue - # construct message + some_window = window raw_tx_bytes = tx.serialize_as_bytes() public_key = ecc.ECPubkey(K) message = public_key.encrypt_message(raw_tx_bytes).decode('ascii') - # send message - task = lambda: server.put(_hash, message) - msg = _('Sending transaction to cosigning pool...') - WaitingDialog(window, msg, task, on_success, on_failure) + buffer.append((_hash, message)) + if not buffer: + return + + # send messages + # note: we send all messages sequentially on the same thread + def send_messages_task(): + for _hash, message in buffer: + server.put(_hash, message) + msg = _('Sending transaction to cosigning pool...') + WaitingDialog(some_window, msg, send_messages_task, on_success, on_failure) def on_receive(self, keyhash, message): self.logger.info(f"signal arrived for {keyhash}")