1
0

LN invoices: support msat precision

fixes #6250
This commit is contained in:
SomberNight
2020-06-22 22:37:58 +02:00
parent 599797c966
commit d5f368c584
19 changed files with 260 additions and 135 deletions

View File

@@ -133,7 +133,7 @@ FALLBACK_NODE_LIST_MAINNET = [
class PaymentInfo(NamedTuple):
payment_hash: bytes
amount: int # in satoshis
amount: Optional[int] # in satoshis # TODO make it msat and rename to amount_msat
direction: int
status: int
@@ -491,7 +491,7 @@ class LNWallet(LNWorker):
self.lnwatcher = None
self.features |= LnFeatures.OPTION_DATA_LOSS_PROTECT_REQ
self.features |= LnFeatures.OPTION_STATIC_REMOTEKEY_REQ
self.payments = self.db.get_dict('lightning_payments') # RHASH -> amount, direction, is_paid
self.payments = self.db.get_dict('lightning_payments') # RHASH -> amount, direction, is_paid # FIXME amt should be msat
self.preimages = self.db.get_dict('lightning_preimages') # RHASH -> preimage
self.sweep_address = wallet.get_new_sweep_address_for_channel() # TODO possible address-reuse
self.logs = defaultdict(list) # type: Dict[str, List[PaymentAttemptLog]] # key is RHASH # (not persisted)
@@ -597,7 +597,7 @@ class LNWallet(LNWorker):
out[k] += v
return out
def get_payment_value(self, info, plist):
def get_payment_value(self, info: Optional['PaymentInfo'], plist):
amount_msat = 0
fee_msat = None
for chan_id, htlc, _direction in plist:
@@ -832,11 +832,11 @@ class LNWallet(LNWorker):
raise Exception(_("open_channel timed out"))
return chan, funding_tx
def pay(self, invoice: str, amount_sat: int = None, *, attempts: int = 1) -> Tuple[bool, List[PaymentAttemptLog]]:
def pay(self, invoice: str, *, amount_msat: int = None, attempts: int = 1) -> Tuple[bool, List[PaymentAttemptLog]]:
"""
Can be called from other threads
"""
coro = self._pay(invoice, amount_sat, attempts=attempts)
coro = self._pay(invoice, amount_msat=amount_msat, attempts=attempts)
fut = asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
return fut.result()
@@ -846,10 +846,15 @@ class LNWallet(LNWorker):
return chan
@log_exceptions
async def _pay(self, invoice: str, amount_sat: int = None, *,
attempts: int = 1,
full_path: LNPaymentPath = None) -> Tuple[bool, List[PaymentAttemptLog]]:
lnaddr = self._check_invoice(invoice, amount_sat)
async def _pay(
self,
invoice: str,
*,
amount_msat: int = None,
attempts: int = 1,
full_path: LNPaymentPath = None,
) -> Tuple[bool, List[PaymentAttemptLog]]:
lnaddr = self._check_invoice(invoice, amount_msat=amount_msat)
payment_hash = lnaddr.paymenthash
key = payment_hash.hex()
amount = int(lnaddr.amount * COIN)
@@ -901,7 +906,7 @@ class LNWallet(LNWorker):
await peer.initialized
htlc = peer.pay(route=route,
chan=chan,
amount_msat=int(lnaddr.amount * COIN * 1000),
amount_msat=lnaddr.get_amount_msat(),
payment_hash=lnaddr.paymenthash,
min_final_cltv_expiry=lnaddr.get_min_final_cltv_expiry(),
payment_secret=lnaddr.payment_secret)
@@ -993,12 +998,12 @@ class LNWallet(LNWorker):
return blacklist
@staticmethod
def _check_invoice(invoice: str, amount_sat: int = None) -> LnAddr:
def _check_invoice(invoice: str, *, amount_msat: int = None) -> LnAddr:
addr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
if addr.is_expired():
raise InvoiceError(_("This invoice has expired"))
if amount_sat:
addr.amount = Decimal(amount_sat) / COIN
if amount_msat:
addr.amount = Decimal(amount_msat) / COIN / 1000
if addr.amount is None:
raise InvoiceError(_("Missing amount"))
if addr.get_min_final_cltv_expiry() > lnutil.NBLOCK_CLTV_EXPIRY_TOO_FAR_INTO_FUTURE:
@@ -1010,7 +1015,7 @@ class LNWallet(LNWorker):
@profiler
def _create_route_from_invoice(self, decoded_invoice: 'LnAddr',
*, full_path: LNPaymentPath = None) -> LNPaymentRoute:
amount_msat = int(decoded_invoice.amount * COIN * 1000)
amount_msat = decoded_invoice.get_amount_msat()
invoice_pubkey = decoded_invoice.pubkey.serialize()
# use 'r' field from invoice
route = None # type: Optional[LNPaymentRoute]
@@ -1310,11 +1315,11 @@ class LNWallet(LNWorker):
return Decimal(max(chan.available_to_spend(REMOTE) if chan.is_open() else 0
for chan in self.channels.values()))/1000 if self.channels else 0
def can_pay_invoice(self, invoice):
return invoice.amount <= self.num_sats_can_send()
def can_pay_invoice(self, invoice: LNInvoice) -> bool:
return invoice.get_amount_sat() <= self.num_sats_can_send()
def can_receive_invoice(self, invoice):
return invoice.amount <= self.num_sats_can_receive()
def can_receive_invoice(self, invoice: LNInvoice) -> bool:
return invoice.get_amount_sat() <= self.num_sats_can_receive()
async def close_channel(self, chan_id):
chan = self._channels[chan_id]