plugins: add proxy aware XMLRPCProxyTransport for xmlrpc.client calls in cosigner plugin
This commit is contained in:
@@ -22,9 +22,9 @@
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
import asyncio
|
||||
import time
|
||||
from xmlrpc.client import ServerProxy
|
||||
from xmlrpc.client import ServerProxy, Transport
|
||||
from typing import TYPE_CHECKING, Union, List, Tuple, Dict
|
||||
import ssl
|
||||
|
||||
@@ -33,14 +33,14 @@ from PyQt5.QtWidgets import QPushButton
|
||||
import certifi
|
||||
|
||||
from electrum import util, keystore, ecc, crypto
|
||||
from electrum import transaction
|
||||
from electrum.transaction import Transaction, PartialTransaction, tx_from_any, SerializationError
|
||||
from electrum.bip32 import BIP32Node
|
||||
from electrum.plugin import BasePlugin, hook
|
||||
from electrum.i18n import _
|
||||
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.network import Network
|
||||
|
||||
from electrum.gui.qt.transaction_dialog import show_transaction, TxDialog
|
||||
from electrum.gui.qt.util import WaitingDialog
|
||||
@@ -52,8 +52,26 @@ if TYPE_CHECKING:
|
||||
|
||||
ca_path = certifi.where()
|
||||
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):
|
||||
@@ -69,7 +87,7 @@ class Listener(util.DaemonThread):
|
||||
self.keyhashes = keyhashes
|
||||
|
||||
def clear(self, keyhash):
|
||||
server.delete(keyhash)
|
||||
self.cw.cosigner_service.delete(keyhash)
|
||||
self.received.remove(keyhash)
|
||||
|
||||
def run(self):
|
||||
@@ -81,7 +99,7 @@ class Listener(util.DaemonThread):
|
||||
if keyhash in self.received:
|
||||
continue
|
||||
try:
|
||||
message = server.get(keyhash)
|
||||
message = self.cw.cosigner_service.get(keyhash)
|
||||
except Exception as e:
|
||||
self.logger.info(f"cannot contact cosigner pool. exc: {e!r}")
|
||||
time.sleep(30)
|
||||
@@ -89,10 +107,9 @@ class Listener(util.DaemonThread):
|
||||
if message:
|
||||
self.received.add(keyhash)
|
||||
self.logger.info(f"received message for {keyhash}")
|
||||
self.cw.obj.cosigner_receive_signal.emit(
|
||||
keyhash, message)
|
||||
# poll every 30 seconds
|
||||
time.sleep(30)
|
||||
self.cw.obj.cosigner_receive_signal.emit(keyhash, message)
|
||||
|
||||
time.sleep(30) # poll every 30 seconds
|
||||
|
||||
|
||||
class QReceiveSignalObject(QObject):
|
||||
@@ -106,6 +123,9 @@ class Plugin(BasePlugin):
|
||||
self._init_qt_received = False
|
||||
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
|
||||
def init_qt(self, gui: 'ElectrumGui'):
|
||||
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'):
|
||||
if type(wallet) != Multisig_Wallet:
|
||||
return
|
||||
self.cosigner_wallets[wallet] = CosignerWallet(wallet, window)
|
||||
self.cosigner_wallets[wallet] = CosignerWallet(wallet, self.cosigner_service, window)
|
||||
|
||||
@hook
|
||||
def on_close_window(self, window):
|
||||
@@ -144,10 +164,11 @@ class Plugin(BasePlugin):
|
||||
class CosignerWallet(Logger):
|
||||
# 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)
|
||||
self.wallet = wallet
|
||||
self.window = window
|
||||
self.cosigner_service = cosigner_service
|
||||
Logger.__init__(self)
|
||||
self.obj = QReceiveSignalObject()
|
||||
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
|
||||
def send_messages_task():
|
||||
for _hash, message in buffer:
|
||||
server.put(_hash, message)
|
||||
self.cosigner_service.put(_hash, message)
|
||||
msg = _('Sending transaction to cosigning pool...')
|
||||
WaitingDialog(self.window, msg, send_messages_task, on_success, on_failure)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user