From fd672fed9f553efe0e5a0bdc356be62b9eacfd8e Mon Sep 17 00:00:00 2001 From: ThomasV Date: Tue, 7 May 2024 08:46:48 +0200 Subject: [PATCH] submarine swaps: separate server logic from transport --- electrum/lnworker.py | 4 +- electrum/plugins/swapserver/server.py | 51 +--------------- electrum/submarine_swaps.py | 83 +++++++++++++++++++++++---- 3 files changed, 76 insertions(+), 62 deletions(-) diff --git a/electrum/lnworker.py b/electrum/lnworker.py index 7fb40590d..8751bfcab 100644 --- a/electrum/lnworker.py +++ b/electrum/lnworker.py @@ -83,7 +83,7 @@ from .lnutil import ImportedChannelBackupStorage, OnchainChannelBackupStorage from .lnchannel import ChannelBackup from .channel_db import UpdateStatus, ChannelDBNotLoaded from .channel_db import get_mychannel_info, get_mychannel_policy -from .submarine_swaps import SwapManager +from .submarine_swaps import HttpSwapManager from .channel_db import ChannelInfo, Policy from .mpp_split import suggest_splits, SplitConfigRating from .trampoline import create_trampoline_route_and_onion, TRAMPOLINE_FEES, is_legacy_relay @@ -856,7 +856,7 @@ class LNWallet(LNWorker): # payment_hash -> callback: self.hold_invoice_callbacks = {} # type: Dict[bytes, Callable[[bytes], Awaitable[None]]] self.payment_bundles = [] # lists of hashes. todo:persist - self.swap_manager = SwapManager(wallet=self.wallet, lnworker=self) + self.swap_manager = HttpSwapManager(wallet=self.wallet, lnworker=self) def has_deterministic_node_id(self) -> bool: diff --git a/electrum/plugins/swapserver/server.py b/electrum/plugins/swapserver/server.py index f2dadb01f..1e0b0daaa 100644 --- a/electrum/plugins/swapserver/server.py +++ b/electrum/plugins/swapserver/server.py @@ -94,60 +94,15 @@ class SwapServer(Logger, EventListener): async def add_swap_invoice(self, r): request = await r.json() - invoice = request['invoice'] - self.sm.add_invoice(invoice, pay_now=True) + self.sm.server_add_swap_invoice(request) return web.json_response({}) async def create_normal_swap(self, r): - # normal for client, reverse for server request = await r.json() - lightning_amount_sat = request['invoiceAmount'] - their_pubkey = bytes.fromhex(request['refundPublicKey']) - assert len(their_pubkey) == 33 - swap = self.sm.create_reverse_swap( - lightning_amount_sat=lightning_amount_sat, - their_pubkey=their_pubkey, - ) - response = { - "id": swap.payment_hash.hex(), - 'preimageHash': swap.payment_hash.hex(), - "acceptZeroConf": False, - "expectedAmount": swap.onchain_amount, - "timeoutBlockHeight": swap.locktime, - "address": swap.lockup_address, - "redeemScript": swap.redeem_script.hex(), - } + response = self.sm.server_create_normal_swap(request) return web.json_response(response) async def create_swap(self, r): - # reverse for client, forward for server - # requesting a normal swap (old protocol) will raise an exception - self.sm.init_pairs() request = await r.json() - req_type = request['type'] - assert request['pairId'] == 'BTC/BTC' - if req_type == 'reversesubmarine': - lightning_amount_sat=request['invoiceAmount'] - payment_hash=bytes.fromhex(request['preimageHash']) - their_pubkey=bytes.fromhex(request['claimPublicKey']) - assert len(payment_hash) == 32 - assert len(their_pubkey) == 33 - swap, invoice, prepay_invoice = self.sm.create_normal_swap( - lightning_amount_sat=lightning_amount_sat, - payment_hash=payment_hash, - their_pubkey=their_pubkey - ) - response = { - 'id': payment_hash.hex(), - 'invoice': invoice, - 'minerFeeInvoice': prepay_invoice, - 'lockupAddress': swap.lockup_address, - 'redeemScript': swap.redeem_script.hex(), - 'timeoutBlockHeight': swap.locktime, - "onchainAmount": swap.onchain_amount, - } - elif req_type == 'submarine': - raise Exception('Deprecated API. Please upgrade your version of Electrum') - else: - raise Exception('unsupported request type:' + req_type) + response = self.sm.server_create_swap(request) return web.json_response(response) diff --git a/electrum/submarine_swaps.py b/electrum/submarine_swaps.py index 9f7cd9ce9..6ff13c33c 100644 --- a/electrum/submarine_swaps.py +++ b/electrum/submarine_swaps.py @@ -565,7 +565,8 @@ class SwapManager(Logger): self.add_lnwatcher_callback(swap) return swap - def add_invoice(self, invoice: str, pay_now: bool = False) -> None: + def server_add_swap_invoice(self, request): + invoice = request['invoice'] invoice = Invoice.from_bech32(invoice) key = invoice.rhash payment_hash = bytes.fromhex(key) @@ -573,19 +574,13 @@ class SwapManager(Logger): swap = self.swaps[key] assert swap.lightning_amount == int(invoice.get_amount_sat()) self.wallet.save_invoice(invoice) - if pay_now: - # check that we have the preimage - assert sha256(swap.preimage) == payment_hash - assert swap.spending_txid is None - self.invoices_to_pay[key] = 0 + # check that we have the preimage + assert sha256(swap.preimage) == payment_hash + assert swap.spending_txid is None + self.invoices_to_pay[key] = 0 async def send_request_to_server(self, method, request_data): - response = await self.network.async_send_http_on_proxy( - 'post' if request_data else 'get', - self.api_url + '/' + method, - json=request_data, - timeout=30) - return json.loads(response) + raise NotImplementedError() async def normal_swap( self, @@ -1090,3 +1085,67 @@ class SwapManager(Logger): max_amt_oc = self.get_send_amount(max_amt_ln, is_reverse=False) or 0 min_amt_oc = self.get_send_amount(self.get_min_amount(), is_reverse=False) or 0 return max_amt_oc if max_amt_oc >= min_amt_oc else None + + def server_create_normal_swap(self, request): + # normal for client, reverse for server + #request = await r.json() + lightning_amount_sat = request['invoiceAmount'] + their_pubkey = bytes.fromhex(request['refundPublicKey']) + assert len(their_pubkey) == 33 + swap = self.create_reverse_swap( + lightning_amount_sat=lightning_amount_sat, + their_pubkey=their_pubkey, + ) + response = { + "id": swap.payment_hash.hex(), + 'preimageHash': swap.payment_hash.hex(), + "acceptZeroConf": False, + "expectedAmount": swap.onchain_amount, + "timeoutBlockHeight": swap.locktime, + "address": swap.lockup_address, + "redeemScript": swap.redeem_script.hex(), + } + return response + + def server_create_swap(self, request): + # reverse for client, forward for server + # requesting a normal swap (old protocol) will raise an exception + self.init_pairs() + #request = await r.json() + req_type = request['type'] + assert request['pairId'] == 'BTC/BTC' + if req_type == 'reversesubmarine': + lightning_amount_sat=request['invoiceAmount'] + payment_hash=bytes.fromhex(request['preimageHash']) + their_pubkey=bytes.fromhex(request['claimPublicKey']) + assert len(payment_hash) == 32 + assert len(their_pubkey) == 33 + swap, invoice, prepay_invoice = self.create_normal_swap( + lightning_amount_sat=lightning_amount_sat, + payment_hash=payment_hash, + their_pubkey=their_pubkey + ) + response = { + 'id': payment_hash.hex(), + 'invoice': invoice, + 'minerFeeInvoice': prepay_invoice, + 'lockupAddress': swap.lockup_address, + 'redeemScript': swap.redeem_script.hex(), + 'timeoutBlockHeight': swap.locktime, + "onchainAmount": swap.onchain_amount, + } + elif req_type == 'submarine': + raise Exception('Deprecated API. Please upgrade your version of Electrum') + else: + raise Exception('unsupported request type:' + req_type) + return response + + +class HttpSwapManager(SwapManager): + async def send_request_to_server(self, method, request_data): + response = await self.network.async_send_http_on_proxy( + 'post' if request_data else 'get', + self.api_url + '/' + method, + json=request_data, + timeout=30) + return json.loads(response)