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:
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}")