refactor lnworker.pay_invoice to accept Invoice object instead of bolt11 string
rename lnworker._check_invoice to lnworker._check_bolt11_invoice
This commit is contained in:
@@ -1264,10 +1264,11 @@ class Commands(Logger):
|
||||
@command('wnpl')
|
||||
async def lnpay(self, invoice, timeout=120, password=None, wallet: Abstract_Wallet = None):
|
||||
lnworker = wallet.lnworker
|
||||
lnaddr = lnworker._check_invoice(invoice)
|
||||
lnaddr = lnworker._check_bolt11_invoice(invoice)
|
||||
payment_hash = lnaddr.paymenthash
|
||||
wallet.save_invoice(Invoice.from_bech32(invoice))
|
||||
success, log = await lnworker.pay_invoice(invoice)
|
||||
invoice_obj = Invoice.from_bech32(invoice)
|
||||
wallet.save_invoice(invoice_obj)
|
||||
success, log = await lnworker.pay_invoice(invoice_obj)
|
||||
return {
|
||||
'payment_hash': payment_hash.hex(),
|
||||
'success': success,
|
||||
|
||||
@@ -7,14 +7,15 @@ from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, pyqtEnum,
|
||||
|
||||
from electrum.i18n import _
|
||||
from electrum.logging import get_logger
|
||||
from electrum.invoices import (Invoice, PR_UNPAID, PR_EXPIRED, PR_UNKNOWN, PR_PAID, PR_INFLIGHT,
|
||||
PR_FAILED, PR_ROUTING, PR_UNCONFIRMED, PR_BROADCASTING, PR_BROADCAST, LN_EXPIRY_NEVER)
|
||||
from electrum.invoices import (
|
||||
Invoice, PR_UNPAID, PR_EXPIRED, PR_UNKNOWN, PR_PAID, PR_INFLIGHT, PR_FAILED, PR_ROUTING, PR_UNCONFIRMED,
|
||||
PR_BROADCASTING, PR_BROADCAST, LN_EXPIRY_NEVER
|
||||
)
|
||||
from electrum.transaction import PartialTxOutput, TxOutput
|
||||
from electrum.util import NotEnoughFunds, NoDynamicFeeEstimates
|
||||
from electrum.lnutil import format_short_channel_id
|
||||
from electrum.bitcoin import COIN, address_to_script
|
||||
from electrum.paymentrequest import PaymentRequest
|
||||
from electrum.payment_identifier import (PaymentIdentifier, PaymentIdentifierState, PaymentIdentifierType)
|
||||
from electrum.payment_identifier import PaymentIdentifier, PaymentIdentifierState, PaymentIdentifierType
|
||||
|
||||
from .qetypes import QEAmount
|
||||
from .qewallet import QEWallet
|
||||
@@ -56,7 +57,7 @@ class QEInvoice(QObject, QtEventListener):
|
||||
self._canPay = False
|
||||
self._key = None
|
||||
self._invoiceType = QEInvoice.Type.Invalid
|
||||
self._effectiveInvoice = None
|
||||
self._effectiveInvoice = None # type: Optional[Invoice]
|
||||
self._userinfo = ''
|
||||
self._lnprops = {}
|
||||
self._amount = QEAmount()
|
||||
|
||||
@@ -29,7 +29,7 @@ from .util import QtEventListener, qt_event_listener
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from electrum.wallet import Abstract_Wallet
|
||||
from .qeinvoice import QEInvoice
|
||||
from electrum.invoices import Invoice
|
||||
|
||||
|
||||
class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
@@ -640,12 +640,12 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
|
||||
self.paymentAuthRejected.emit()
|
||||
|
||||
@auth_protect(message=_('Pay lightning invoice?'), reject='ln_auth_rejected')
|
||||
def pay_lightning_invoice(self, invoice: 'QEInvoice'):
|
||||
def pay_lightning_invoice(self, invoice: 'Invoice'):
|
||||
amount_msat = invoice.get_amount_msat()
|
||||
|
||||
def pay_thread():
|
||||
try:
|
||||
coro = self.wallet.lnworker.pay_invoice(invoice.lightning_invoice, amount_msat=amount_msat)
|
||||
coro = self.wallet.lnworker.pay_invoice(invoice, amount_msat=amount_msat)
|
||||
fut = asyncio.run_coroutine_threadsafe(coro, get_asyncio_loop())
|
||||
fut.result()
|
||||
except Exception as e:
|
||||
|
||||
@@ -719,7 +719,7 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
|
||||
if not self.question(msg):
|
||||
return
|
||||
self.save_pending_invoice()
|
||||
coro = lnworker.pay_invoice(invoice.lightning_invoice, amount_msat=amount_msat)
|
||||
coro = lnworker.pay_invoice(invoice, amount_msat=amount_msat)
|
||||
self.window.run_coroutine_from_thread(coro, _('Sending payment'))
|
||||
|
||||
def broadcast_transaction(self, tx: Transaction, *, payment_identifier: PaymentIdentifier = None):
|
||||
|
||||
@@ -670,7 +670,7 @@ class ElectrumGui(BaseElectrumGui, EventListener):
|
||||
if not self.question(msg):
|
||||
return
|
||||
self.save_pending_invoice(invoice)
|
||||
coro = self.wallet.lnworker.pay_invoice(invoice.lightning_invoice, amount_msat=amount_msat)
|
||||
coro = self.wallet.lnworker.pay_invoice(invoice, amount_msat=amount_msat)
|
||||
|
||||
#self.window.run_coroutine_from_thread(coro, _('Sending payment'))
|
||||
self.show_message(_("Please wait..."), getchar=False)
|
||||
|
||||
@@ -1491,14 +1491,14 @@ class LNWallet(LNWorker):
|
||||
|
||||
@log_exceptions
|
||||
async def pay_invoice(
|
||||
self, invoice: str, *,
|
||||
self, invoice: Invoice, *,
|
||||
amount_msat: int = None,
|
||||
attempts: int = None, # used only in unit tests
|
||||
full_path: LNPaymentPath = None,
|
||||
channels: Optional[Sequence[Channel]] = None,
|
||||
) -> Tuple[bool, List[HtlcLog]]:
|
||||
|
||||
lnaddr = self._check_invoice(invoice, amount_msat=amount_msat)
|
||||
bolt11 = invoice.lightning_invoice
|
||||
lnaddr = self._check_bolt11_invoice(bolt11, amount_msat=amount_msat)
|
||||
min_final_cltv_delta = lnaddr.get_min_final_cltv_delta()
|
||||
payment_hash = lnaddr.paymenthash
|
||||
key = payment_hash.hex()
|
||||
@@ -1850,11 +1850,11 @@ class LNWallet(LNWorker):
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _check_invoice(self, invoice: str, *, amount_msat: int = None) -> LnAddr:
|
||||
def _check_bolt11_invoice(self, bolt11_invoice: str, *, amount_msat: int = None) -> LnAddr:
|
||||
"""Parses and validates a bolt11 invoice str into a LnAddr.
|
||||
Includes pre-payment checks external to the parser.
|
||||
"""
|
||||
addr = lndecode(invoice)
|
||||
addr = lndecode(bolt11_invoice)
|
||||
if addr.is_expired():
|
||||
raise InvoiceError(_("This invoice has expired"))
|
||||
# check amount
|
||||
@@ -2872,8 +2872,8 @@ class LNWallet(LNWorker):
|
||||
fallback_address=None,
|
||||
channels=[chan2],
|
||||
)
|
||||
return await self.pay_invoice(
|
||||
invoice, channels=[chan1])
|
||||
invoice_obj = Invoice.from_bech32(invoice)
|
||||
return await self.pay_invoice(invoice_obj, channels=[chan1])
|
||||
|
||||
def can_receive_invoice(self, invoice: BaseInvoice) -> bool:
|
||||
assert invoice.is_lightning()
|
||||
|
||||
@@ -298,7 +298,7 @@ class SwapManager(Logger):
|
||||
self.invoices_to_pay[key] = 1000000000000 # lock
|
||||
try:
|
||||
invoice = self.wallet.get_invoice(key)
|
||||
success, log = await self.lnworker.pay_invoice(invoice.lightning_invoice, attempts=10)
|
||||
success, log = await self.lnworker.pay_invoice(invoice, attempts=10)
|
||||
except Exception as e:
|
||||
self.logger.info(f'exception paying {key}, will not retry')
|
||||
self.invoices_to_pay.pop(key, None)
|
||||
@@ -908,13 +908,13 @@ class SwapManager(Logger):
|
||||
if locktime - self.network.get_local_height() <= MIN_LOCKTIME_DELTA:
|
||||
raise Exception("rswap check failed: locktime too close")
|
||||
# verify invoice payment_hash
|
||||
lnaddr = self.lnworker._check_invoice(invoice)
|
||||
lnaddr = self.lnworker._check_bolt11_invoice(invoice)
|
||||
invoice_amount = int(lnaddr.get_amount_sat())
|
||||
if lnaddr.paymenthash != payment_hash:
|
||||
raise Exception("rswap check failed: inconsistent RHASH and invoice")
|
||||
# check that the lightning amount is what we requested
|
||||
if fee_invoice:
|
||||
fee_lnaddr = self.lnworker._check_invoice(fee_invoice)
|
||||
fee_lnaddr = self.lnworker._check_bolt11_invoice(fee_invoice)
|
||||
invoice_amount += fee_lnaddr.get_amount_sat()
|
||||
prepay_hash = fee_lnaddr.paymenthash
|
||||
else:
|
||||
@@ -935,13 +935,15 @@ class SwapManager(Logger):
|
||||
swap._zeroconf = zeroconf
|
||||
# initiate fee payment.
|
||||
if fee_invoice:
|
||||
asyncio.ensure_future(self.lnworker.pay_invoice(fee_invoice))
|
||||
fee_invoice_obj = Invoice.from_bech32(fee_invoice)
|
||||
asyncio.ensure_future(self.lnworker.pay_invoice(fee_invoice_obj))
|
||||
# we return if we detect funding
|
||||
async def wait_for_funding(swap):
|
||||
while swap.funding_txid is None:
|
||||
await asyncio.sleep(1)
|
||||
# initiate main payment
|
||||
tasks = [asyncio.create_task(self.lnworker.pay_invoice(invoice, channels=channels)), asyncio.create_task(wait_for_funding(swap))]
|
||||
invoice_obj = Invoice.from_bech32(invoice)
|
||||
tasks = [asyncio.create_task(self.lnworker.pay_invoice(invoice_obj, channels=channels)), asyncio.create_task(wait_for_funding(swap))]
|
||||
await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
|
||||
return swap.funding_txid
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ from electrum.lnworker import PaymentInfo, RECEIVED
|
||||
from electrum.lnonion import OnionFailureCode, OnionRoutingFailure
|
||||
from electrum.lnutil import UpdateAddHtlc
|
||||
from electrum.lnutil import LOCAL, REMOTE
|
||||
from electrum.invoices import PR_PAID, PR_UNPAID
|
||||
from electrum.invoices import PR_PAID, PR_UNPAID, Invoice
|
||||
from electrum.interface import GracefulDisconnect
|
||||
from electrum.simple_config import SimpleConfig
|
||||
from electrum.fee_policy import FeeTimeEstimates
|
||||
@@ -291,7 +291,7 @@ class MockLNWallet(Logger, EventListener, NetworkRetryManager[LNPeerAddr]):
|
||||
get_preimage = LNWallet.get_preimage
|
||||
create_route_for_single_htlc = LNWallet.create_route_for_single_htlc
|
||||
create_routes_for_payment = LNWallet.create_routes_for_payment
|
||||
_check_invoice = LNWallet._check_invoice
|
||||
_check_bolt11_invoice = LNWallet._check_bolt11_invoice
|
||||
pay_to_route = LNWallet.pay_to_route
|
||||
pay_to_node = LNWallet.pay_to_node
|
||||
pay_invoice = LNWallet.pay_invoice
|
||||
@@ -536,7 +536,7 @@ class TestPeer(ElectrumTestCase):
|
||||
payment_hash: bytes = None,
|
||||
invoice_features: LnFeatures = None,
|
||||
min_final_cltv_delta: int = None,
|
||||
) -> Tuple[LnAddr, str]:
|
||||
) -> Tuple[LnAddr, Invoice]:
|
||||
amount_btc = amount_msat/Decimal(COIN*1000)
|
||||
if payment_preimage is None and not payment_hash:
|
||||
payment_preimage = os.urandom(32)
|
||||
@@ -571,7 +571,7 @@ class TestPeer(ElectrumTestCase):
|
||||
)
|
||||
invoice = lnencode(lnaddr1, w2.node_keypair.privkey)
|
||||
lnaddr2 = lndecode(invoice) # unlike lnaddr1, this now has a pubkey set
|
||||
return lnaddr2, invoice
|
||||
return lnaddr2, Invoice.from_bech32(invoice)
|
||||
|
||||
async def _activate_trampoline(self, w: MockLNWallet):
|
||||
if w.network.channel_db:
|
||||
@@ -1349,7 +1349,7 @@ class TestPeerDirect(TestPeer):
|
||||
p1, p2, w1, w2, q1, q2 = self.prepare_peers(alice_channel, bob_channel)
|
||||
lnaddr, pay_req = self.prepare_invoice(w2)
|
||||
|
||||
lnaddr = w1._check_invoice(pay_req)
|
||||
lnaddr = w1._check_bolt11_invoice(pay_req.lightning_invoice)
|
||||
shi = (await w1.create_routes_from_invoice(lnaddr.get_amount_msat(), decoded_invoice=lnaddr))[0][0]
|
||||
route, amount_msat = shi.route, shi.amount_msat
|
||||
assert amount_msat == lnaddr.get_amount_msat()
|
||||
|
||||
Reference in New Issue
Block a user