mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
invoices: deal with expiration of "0" mess
Internally, we've been using an expiration of 0 to mean "never expires". For LN invoices, BOLT-11 does not specify what an expiration of 0 means. Other clients seem to treat it as "0 seconds" (i.e. already expired). This means there is no way to create a BOLT-11 invoice that "never" expires. For LN invoices, - we now treat an expiration of 0, , as "0 seconds", - when creating an invoice, if the user selected never, we will put 100 years as expiration
This commit is contained in:
parent
4c177c4c92
commit
7962e17df6
5 changed files with 33 additions and 17 deletions
|
@ -24,7 +24,7 @@ from kivy.utils import platform
|
|||
from kivy.logger import Logger
|
||||
|
||||
from electrum.util import profiler, parse_URI, format_time, InvalidPassword, NotEnoughFunds, Fiat
|
||||
from electrum.util import PR_TYPE_ONCHAIN, PR_TYPE_LN
|
||||
from electrum.util import PR_TYPE_ONCHAIN, PR_TYPE_LN, PR_DEFAULT_EXPIRATION_WHEN_CREATING
|
||||
from electrum import bitcoin, constants
|
||||
from electrum.transaction import Transaction, tx_from_any, PartialTransaction, PartialTxOutput
|
||||
from electrum.util import (parse_URI, InvalidBitcoinURI, PR_PAID, PR_UNKNOWN, PR_EXPIRED,
|
||||
|
@ -419,7 +419,7 @@ class ReceiveScreen(CScreen):
|
|||
Clock.schedule_interval(lambda dt: self.update(), 5)
|
||||
|
||||
def expiry(self):
|
||||
return self.app.electrum_config.get('request_expiry', 3600) # 1 hour
|
||||
return self.app.electrum_config.get('request_expiry', PR_DEFAULT_EXPIRATION_WHEN_CREATING)
|
||||
|
||||
def clear(self):
|
||||
self.screen.address = ''
|
||||
|
|
|
@ -62,7 +62,7 @@ from electrum.util import (format_time, format_satoshis, format_fee_satoshis,
|
|||
get_new_wallet_name, send_exception_to_crash_reporter,
|
||||
InvalidBitcoinURI, maybe_extract_bolt11_invoice, NotEnoughFunds,
|
||||
NoDynamicFeeEstimates, MultipleSpendMaxTxOutputs)
|
||||
from electrum.util import PR_TYPE_ONCHAIN, PR_TYPE_LN
|
||||
from electrum.util import PR_TYPE_ONCHAIN, PR_TYPE_LN, PR_DEFAULT_EXPIRATION_WHEN_CREATING
|
||||
from electrum.transaction import (Transaction, PartialTxInput,
|
||||
PartialTransaction, PartialTxOutput)
|
||||
from electrum.address_synchronizer import AddTransactionException
|
||||
|
@ -1007,7 +1007,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
|||
evl = sorted(pr_expiration_values.items())
|
||||
evl_keys = [i[0] for i in evl]
|
||||
evl_values = [i[1] for i in evl]
|
||||
default_expiry = self.config.get('request_expiry', 3600)
|
||||
default_expiry = self.config.get('request_expiry', PR_DEFAULT_EXPIRATION_WHEN_CREATING)
|
||||
try:
|
||||
i = evl_keys.index(default_expiry)
|
||||
except ValueError:
|
||||
|
@ -1139,7 +1139,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
|||
def create_invoice(self, is_lightning):
|
||||
amount = self.receive_amount_e.get_amount()
|
||||
message = self.receive_message_e.text()
|
||||
expiry = self.config.get('request_expiry', 3600)
|
||||
expiry = self.config.get('request_expiry', PR_DEFAULT_EXPIRATION_WHEN_CREATING)
|
||||
if is_lightning:
|
||||
key = self.wallet.lnworker.add_request(amount, message, expiry)
|
||||
else:
|
||||
|
|
|
@ -199,6 +199,8 @@ def lnencode(addr, privkey):
|
|||
# Get minimal length by trimming leading 5 bits at a time.
|
||||
expirybits = bitstring.pack('intbe:64', v)[4:64]
|
||||
while expirybits.startswith('0b00000'):
|
||||
if len(expirybits) == 5:
|
||||
break # v == 0
|
||||
expirybits = expirybits[5:]
|
||||
data += tagged('x', expirybits)
|
||||
elif k == 'h':
|
||||
|
@ -259,21 +261,24 @@ class LnAddr(object):
|
|||
return self._min_final_cltv_expiry
|
||||
|
||||
def get_tag(self, tag):
|
||||
description = ''
|
||||
for k,v in self.tags:
|
||||
for k, v in self.tags:
|
||||
if k == tag:
|
||||
description = v
|
||||
break
|
||||
return description
|
||||
return v
|
||||
return None
|
||||
|
||||
def get_description(self):
|
||||
return self.get_tag('d')
|
||||
def get_description(self) -> str:
|
||||
return self.get_tag('d') or ''
|
||||
|
||||
def get_expiry(self):
|
||||
return int(self.get_tag('x') or '3600')
|
||||
def get_expiry(self) -> int:
|
||||
exp = self.get_tag('x')
|
||||
if exp is None:
|
||||
exp = 3600
|
||||
return int(exp)
|
||||
|
||||
def is_expired(self):
|
||||
def is_expired(self) -> bool:
|
||||
now = time.time()
|
||||
# BOLT-11 does not specify what expiration of '0' means.
|
||||
# we treat it as 0 seconds here (instead of never)
|
||||
return now > self.get_expiry() + self.date
|
||||
|
||||
|
||||
|
|
|
@ -1112,7 +1112,7 @@ class LNWallet(LNWorker):
|
|||
raise Exception(_("add invoice timed out"))
|
||||
|
||||
@log_exceptions
|
||||
async def _add_request_coro(self, amount_sat, message, expiry):
|
||||
async def _add_request_coro(self, amount_sat, message, expiry: int):
|
||||
timestamp = int(time.time())
|
||||
routing_hints = await self._calc_routing_hints_for_invoice(amount_sat)
|
||||
if not routing_hints:
|
||||
|
@ -1122,6 +1122,12 @@ class LNWallet(LNWorker):
|
|||
payment_hash = sha256(payment_preimage)
|
||||
info = PaymentInfo(payment_hash, amount_sat, RECEIVED, PR_UNPAID)
|
||||
amount_btc = amount_sat/Decimal(COIN) if amount_sat else None
|
||||
if expiry == 0:
|
||||
# hack: BOLT-11 is not really clear on what an expiry of 0 means.
|
||||
# It probably interprets it as 0 seconds, so already expired...
|
||||
# Our higher level invoices code however uses 0 for "never".
|
||||
# Hence set some high expiration here
|
||||
expiry = 100 * 365 * 24 * 60 * 60 # 100 years
|
||||
lnaddr = LnAddr(payment_hash, amount_btc,
|
||||
tags=[('d', message),
|
||||
('c', MIN_FINAL_CLTV_EXPIRY_FOR_INVOICE),
|
||||
|
|
|
@ -104,17 +104,22 @@ pr_tooltips = {
|
|||
PR_FAILED:_('Failed'),
|
||||
}
|
||||
|
||||
PR_DEFAULT_EXPIRATION_WHEN_CREATING = 24*60*60 # 1 day
|
||||
pr_expiration_values = {
|
||||
0: _('Never'),
|
||||
10*60: _('10 minutes'),
|
||||
60*60: _('1 hour'),
|
||||
24*60*60: _('1 day'),
|
||||
7*24*60*60: _('1 week')
|
||||
7*24*60*60: _('1 week'),
|
||||
}
|
||||
assert PR_DEFAULT_EXPIRATION_WHEN_CREATING in pr_expiration_values
|
||||
|
||||
|
||||
def get_request_status(req):
|
||||
status = req['status']
|
||||
exp = req.get('exp', 0) or 0
|
||||
if req.get('type') == PR_TYPE_LN and exp == 0:
|
||||
status = PR_EXPIRED # for BOLT-11 invoices, exp==0 means 0 seconds
|
||||
if req['status'] == PR_UNPAID and exp > 0 and req['time'] + req['exp'] < time.time():
|
||||
status = PR_EXPIRED
|
||||
status_str = pr_tooltips[status]
|
||||
|
|
Loading…
Add table
Reference in a new issue