Browse Source

Merge pull request #8716 from accumulator/cosigner_pool_proxy

plugins: add proxy aware XMLRPCProxyTransport for xmlrpc.client calls…
master
accumulator 2 years ago committed by GitHub
parent
commit
3f742a14b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 51
      electrum/plugins/cosigner_pool/qt.py

51
electrum/plugins/cosigner_pool/qt.py

@ -22,9 +22,9 @@
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
import asyncio
import time import time
from xmlrpc.client import ServerProxy from xmlrpc.client import ServerProxy, Transport
from typing import TYPE_CHECKING, Union, List, Tuple, Dict from typing import TYPE_CHECKING, Union, List, Tuple, Dict
import ssl import ssl
@ -33,14 +33,14 @@ from PyQt5.QtWidgets import QPushButton
import certifi import certifi
from electrum import util, keystore, ecc, crypto from electrum import util, keystore, ecc, crypto
from electrum import transaction
from electrum.transaction import Transaction, PartialTransaction, tx_from_any, SerializationError from electrum.transaction import Transaction, PartialTransaction, tx_from_any, SerializationError
from electrum.bip32 import BIP32Node from electrum.bip32 import BIP32Node
from electrum.plugin import BasePlugin, hook from electrum.plugin import BasePlugin, hook
from electrum.i18n import _ from electrum.i18n import _
from electrum.wallet import Multisig_Wallet, Abstract_Wallet from electrum.wallet import Multisig_Wallet, Abstract_Wallet
from electrum.util import bfh from electrum.util import bfh, make_aiohttp_session
from electrum.logging import Logger from electrum.logging import Logger
from electrum.network import Network
from electrum.gui.qt.transaction_dialog import show_transaction, TxDialog from electrum.gui.qt.transaction_dialog import show_transaction, TxDialog
from electrum.gui.qt.util import WaitingDialog from electrum.gui.qt.util import WaitingDialog
@ -52,8 +52,26 @@ if TYPE_CHECKING:
ca_path = certifi.where() ca_path = certifi.where()
ssl_context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=ca_path) ssl_context = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=ca_path)
server = ServerProxy('https://cosigner.electrum.org/', allow_none=True, context=ssl_context)
# FIXME this is not using the network proxy.
class XMLRPCProxyTransport(Transport):
def request(self, host, handler, request_body, verbose=False):
network = Network.get_instance()
if network is None:
return
async def do_request(_host, _request_body):
async with make_aiohttp_session(network.proxy) as session:
async with session.post(f'https://{_host}', data=_request_body) as response:
response.raise_for_status()
p, u = self.getparser()
data = await response.read()
p.feed(data)
p.close()
return u.close()
fut = asyncio.run_coroutine_threadsafe(do_request(host, request_body), network.asyncio_loop)
return fut.result()
class Listener(util.DaemonThread): class Listener(util.DaemonThread):
@ -69,7 +87,7 @@ class Listener(util.DaemonThread):
self.keyhashes = keyhashes self.keyhashes = keyhashes
def clear(self, keyhash): def clear(self, keyhash):
server.delete(keyhash) self.cw.cosigner_service.delete(keyhash)
self.received.remove(keyhash) self.received.remove(keyhash)
def run(self): def run(self):
@ -81,7 +99,7 @@ class Listener(util.DaemonThread):
if keyhash in self.received: if keyhash in self.received:
continue continue
try: try:
message = server.get(keyhash) message = self.cw.cosigner_service.get(keyhash)
except Exception as e: except Exception as e:
self.logger.info(f"cannot contact cosigner pool. exc: {e!r}") self.logger.info(f"cannot contact cosigner pool. exc: {e!r}")
time.sleep(30) time.sleep(30)
@ -89,10 +107,9 @@ class Listener(util.DaemonThread):
if message: if message:
self.received.add(keyhash) self.received.add(keyhash)
self.logger.info(f"received message for {keyhash}") self.logger.info(f"received message for {keyhash}")
self.cw.obj.cosigner_receive_signal.emit( self.cw.obj.cosigner_receive_signal.emit(keyhash, message)
keyhash, message)
# poll every 30 seconds time.sleep(30) # poll every 30 seconds
time.sleep(30)
class QReceiveSignalObject(QObject): class QReceiveSignalObject(QObject):
@ -106,6 +123,9 @@ class Plugin(BasePlugin):
self._init_qt_received = False self._init_qt_received = False
self.cosigner_wallets = {} # type: Dict[Abstract_Wallet, CosignerWallet] self.cosigner_wallets = {} # type: Dict[Abstract_Wallet, CosignerWallet]
transport = XMLRPCProxyTransport()
self.cosigner_service = ServerProxy('https://cosigner.electrum.org/', transport, allow_none=True, context=ssl_context)
@hook @hook
def init_qt(self, gui: 'ElectrumGui'): def init_qt(self, gui: 'ElectrumGui'):
if self._init_qt_received: # only need/want the first signal if self._init_qt_received: # only need/want the first signal
@ -118,7 +138,7 @@ class Plugin(BasePlugin):
def load_wallet(self, wallet: 'Abstract_Wallet', window: 'ElectrumWindow'): def load_wallet(self, wallet: 'Abstract_Wallet', window: 'ElectrumWindow'):
if type(wallet) != Multisig_Wallet: if type(wallet) != Multisig_Wallet:
return return
self.cosigner_wallets[wallet] = CosignerWallet(wallet, window) self.cosigner_wallets[wallet] = CosignerWallet(wallet, self.cosigner_service, window)
@hook @hook
def on_close_window(self, window): def on_close_window(self, window):
@ -144,10 +164,11 @@ class Plugin(BasePlugin):
class CosignerWallet(Logger): class CosignerWallet(Logger):
# one for each open window # one for each open window
def __init__(self, wallet: 'Multisig_Wallet', window: 'ElectrumWindow'): def __init__(self, wallet: 'Multisig_Wallet', cosigner_service: 'ServerProxy', window: 'ElectrumWindow'):
assert isinstance(wallet, Multisig_Wallet) assert isinstance(wallet, Multisig_Wallet)
self.wallet = wallet self.wallet = wallet
self.window = window self.window = window
self.cosigner_service = cosigner_service
Logger.__init__(self) Logger.__init__(self)
self.obj = QReceiveSignalObject() self.obj = QReceiveSignalObject()
self.obj.cosigner_receive_signal.connect(self.on_receive) self.obj.cosigner_receive_signal.connect(self.on_receive)
@ -226,7 +247,7 @@ class CosignerWallet(Logger):
# note: we send all messages sequentially on the same thread # note: we send all messages sequentially on the same thread
def send_messages_task(): def send_messages_task():
for _hash, message in buffer: for _hash, message in buffer:
server.put(_hash, message) self.cosigner_service.put(_hash, message)
msg = _('Sending transaction to cosigning pool...') msg = _('Sending transaction to cosigning pool...')
WaitingDialog(self.window, msg, send_messages_task, on_success, on_failure) WaitingDialog(self.window, msg, send_messages_task, on_success, on_failure)

Loading…
Cancel
Save