Browse Source

Merge pull request #8231 from spesmilo/fix_8213

Refresh bolt11 routing hints when channel liquidity changes:
master
ThomasV 3 years ago committed by GitHub
parent
commit
4ad9caddab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      electrum/gui/qml/qeinvoicelistmodel.py
  2. 2
      electrum/gui/qml/qerequestdetails.py
  3. 2
      electrum/gui/qt/receive_tab.py
  4. 2
      electrum/gui/qt/request_list.py
  5. 107
      electrum/invoices.py
  6. 62
      electrum/lnworker.py
  7. 8
      electrum/submarine_swaps.py
  8. 14
      electrum/tests/test_invoices.py
  9. 3
      electrum/tests/test_lnpeer.py
  10. 41
      electrum/wallet.py
  11. 22
      electrum/wallet_db.py

3
electrum/gui/qml/qeinvoicelistmodel.py

@ -124,8 +124,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
item['address'] = ''
item['date'] = format_time(item['timestamp'])
item['amount'] = QEAmount(from_invoice=invoice)
item['onchain_fallback'] = invoice.is_lightning() and invoice._lnaddr.get_fallback_address()
item['type'] = 'invoice'
item['onchain_fallback'] = invoice.is_lightning() and invoice.get_address()
return item

2
electrum/gui/qml/qerequestdetails.py

@ -118,7 +118,7 @@ class QERequestDetails(QObject, QtEventListener):
def bolt11(self):
can_receive = self._wallet.wallet.lnworker.num_sats_can_receive() if self._wallet.wallet.lnworker else 0
if self._req and can_receive > 0 and self._req.amount_msat/1000 <= can_receive:
return self._req.lightning_invoice
return self._wallet.wallet.get_bolt11_invoice(self._req)
else:
return ''

2
electrum/gui/qt/receive_tab.py

@ -224,7 +224,7 @@ class ReceiveTab(QWidget, MessageBoxMixin, Logger):
help_texts = self.wallet.get_help_texts_for_receive_request(req)
addr = (req.get_address() or '') if not help_texts.address_is_error else ''
URI = (self.wallet.get_request_URI(req) or '') if not help_texts.URI_is_error else ''
lnaddr = (req.lightning_invoice or '') if not help_texts.ln_is_error else ''
lnaddr = self.wallet.get_bolt11_invoice(req) if not help_texts.ln_is_error else ''
address_help = help_texts.address_help
URI_help = help_texts.URI_help
ln_help = help_texts.ln_help

2
electrum/gui/qt/request_list.py

@ -197,7 +197,7 @@ class RequestList(MyTreeView):
if URI := self.wallet.get_request_URI(req):
copy_menu.addAction(_("Bitcoin URI"), lambda: self.parent.do_copy(URI, title='Bitcoin URI'))
if req.is_lightning():
copy_menu.addAction(_("Lightning Request"), lambda: self.parent.do_copy(req.lightning_invoice, title='Lightning Request'))
copy_menu.addAction(_("Lightning Request"), lambda: self.parent.do_copy(self.wallet.get_bolt11_invoice(req), title='Lightning Request'))
#if 'view_url' in req:
# menu.addAction(_("View in web browser"), lambda: webopen(req['view_url']))
menu.addAction(_("Delete"), lambda: self.delete_requests([key]))

107
electrum/invoices.py

@ -7,6 +7,7 @@ import attr
from .json_db import StoredObject
from .i18n import _
from .util import age, InvoiceError
from .lnutil import hex_to_bytes
from .lnaddr import lndecode, LnAddr
from . import constants
from .bitcoin import COIN, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC
@ -83,7 +84,11 @@ LN_EXPIRY_NEVER = 100 * 365 * 24 * 60 * 60 # 100 years
@attr.s
class Invoice(StoredObject):
class BaseInvoice(StoredObject):
"""
Base class for Invoice and Request
In the code, we use 'invoice' for outgoing payments, and 'request' for incoming payments.
"""
# mandatory fields
amount_msat = attr.ib(kw_only=True) # type: Optional[Union[int, str]] # can be '!' or None
@ -101,10 +106,6 @@ class Invoice(StoredObject):
bip70 = attr.ib(type=str, kw_only=True) # type: Optional[str]
#bip70_requestor = attr.ib(type=str, kw_only=True) # type: Optional[str]
# lightning only
lightning_invoice = attr.ib(type=str, kw_only=True) # type: Optional[str]
__lnaddr = None
def is_lightning(self):
return self.lightning_invoice is not None
@ -117,15 +118,6 @@ class Invoice(StoredObject):
status_str = _('Expires') + ' ' + age(expiration, include_seconds=True)
return status_str
def get_address(self) -> Optional[str]:
"""returns the first address, to be displayed in GUI"""
address = None
if self.outputs:
address = self.outputs[0].address if len(self.outputs) > 0 else None
if not address and self.is_lightning():
address = self._lnaddr.get_fallback_address() or None
return address
def get_outputs(self) -> Sequence[PartialTxOutput]:
outputs = self.outputs or []
if not outputs:
@ -135,12 +127,6 @@ class Invoice(StoredObject):
outputs = [PartialTxOutput.from_address_and_value(address, int(amount))]
return outputs
def can_be_paid_onchain(self) -> bool:
if self.is_lightning():
return bool(self._lnaddr.get_fallback_address())
else:
return True
def get_expiration_date(self):
# 0 means never
return self.exp + self.time if self.exp else 0
@ -193,12 +179,6 @@ class Invoice(StoredObject):
uri = create_bip21_uri(addr, amount, message, extra_query_params=extra)
return str(uri)
@lightning_invoice.validator
def _validate_invoice_str(self, attribute, value):
if value is not None:
lnaddr = lndecode(value) # this checks the str can be decoded
self.__lnaddr = lnaddr # save it, just to avoid having to recompute later
@amount_msat.validator
def _validate_amount(self, attribute, value):
if value is None:
@ -212,16 +192,6 @@ class Invoice(StoredObject):
else:
raise InvoiceError(f"unexpected amount: {value!r}")
@property
def _lnaddr(self) -> LnAddr:
if self.__lnaddr is None:
self.__lnaddr = lndecode(self.lightning_invoice)
return self.__lnaddr
@property
def rhash(self) -> str:
return self._lnaddr.paymenthash.hex()
@classmethod
def from_bech32(cls, invoice: str) -> 'Invoice':
"""Constructs Invoice object from BOLT-11 string.
@ -259,6 +229,48 @@ class Invoice(StoredObject):
lightning_invoice=None,
)
def get_id(self) -> str:
if self.is_lightning():
return self.rhash
else: # on-chain
return get_id_from_onchain_outputs(outputs=self.get_outputs(), timestamp=self.time)
@attr.s
class Invoice(BaseInvoice):
lightning_invoice = attr.ib(type=str, kw_only=True) # type: Optional[str]
__lnaddr = None
def get_address(self) -> Optional[str]:
"""returns the first address, to be displayed in GUI"""
address = None
if self.outputs:
address = self.outputs[0].address if len(self.outputs) > 0 else None
if not address and self.is_lightning():
address = self._lnaddr.get_fallback_address() or None
return address
@property
def _lnaddr(self) -> LnAddr:
if self.__lnaddr is None:
self.__lnaddr = lndecode(self.lightning_invoice)
return self.__lnaddr
@property
def rhash(self) -> str:
return self._lnaddr.paymenthash.hex()
@lightning_invoice.validator
def _validate_invoice_str(self, attribute, value):
if value is not None:
lnaddr = lndecode(value) # this checks the str can be decoded
self.__lnaddr = lnaddr # save it, just to avoid having to recompute later
def can_be_paid_onchain(self) -> bool:
if self.is_lightning():
return bool(self._lnaddr.get_fallback_address())
else:
return True
def to_debug_json(self) -> Dict[str, Any]:
d = self.to_json()
d.update({
@ -274,11 +286,24 @@ class Invoice(StoredObject):
d['r_tags'] = [str((a.hex(),b.hex(),c,d,e)) for a,b,c,d,e in ln_routing_info[-1]]
return d
def get_id(self) -> str:
if self.is_lightning():
return self.rhash
else: # on-chain
return get_id_from_onchain_outputs(outputs=self.get_outputs(), timestamp=self.time)
@attr.s
class Request(BaseInvoice):
payment_hash = attr.ib(type=bytes, kw_only=True, converter=hex_to_bytes) # type: Optional[bytes]
def is_lightning(self):
return self.payment_hash is not None
def get_address(self) -> Optional[str]:
"""returns the first address, to be displayed in GUI"""
address = None
if self.outputs:
address = self.outputs[0].address if len(self.outputs) > 0 else None
return address
@property
def rhash(self) -> str:
return self.payment_hash.hex()
def get_id_from_onchain_outputs(outputs: List[PartialTxOutput], *, timestamp: int) -> str:

62
electrum/lnworker.py

@ -633,6 +633,7 @@ class LNWallet(LNWorker):
self.lnrater: LNRater = None
self.payment_info = self.db.get_dict('lightning_payments') # RHASH -> amount, direction, is_paid
self.preimages = self.db.get_dict('lightning_preimages') # RHASH -> preimage
self._bolt11_cache = {}
# note: this sweep_address is only used as fallback; as it might result in address-reuse
self.logs = defaultdict(list) # type: Dict[str, List[HtlcLog]] # key is RHASH # (not persisted)
# used in tests
@ -980,6 +981,7 @@ class LNWallet(LNWorker):
def channel_state_changed(self, chan: Channel):
if type(chan) is Channel:
self.save_channel(chan)
self.clear_invoices_cache()
util.trigger_callback('channel', self.wallet, chan)
def save_channel(self, chan: Channel):
@ -1781,27 +1783,31 @@ class LNWallet(LNWorker):
route[-1].node_features |= invoice_features
return route
def create_invoice(
def clear_invoices_cache(self):
self._bolt11_cache.clear()
def get_bolt11_invoice(
self, *,
payment_hash: bytes,
amount_msat: Optional[int],
message: str,
expiry: int,
fallback_address: Optional[str],
write_to_disk: bool = True,
channels: Optional[Sequence[Channel]] = None,
) -> Tuple[LnAddr, str]:
pair = self._bolt11_cache.get(payment_hash)
if pair:
lnaddr, invoice = pair
assert lnaddr.get_amount_msat() == amount_msat
return pair
assert amount_msat is None or amount_msat > 0
timestamp = int(time.time())
routing_hints, trampoline_hints = self.calc_routing_hints_for_invoice(amount_msat, channels=channels)
if not routing_hints:
self.logger.info(
"Warning. No routing hints added to invoice. "
"Other clients will likely not be able to send to us.")
self.logger.info(f"creating bolt11 invoice with routing_hints: {routing_hints}")
invoice_features = self.features.for_invoice()
payment_preimage = os.urandom(32)
payment_hash = sha256(payment_preimage)
info = PaymentInfo(payment_hash, amount_msat, RECEIVED, PR_UNPAID)
payment_preimage = self.get_preimage(payment_hash)
amount_btc = amount_msat/Decimal(COIN*1000) if amount_msat else None
if expiry == 0:
expiry = LN_EXPIRY_NEVER
@ -1820,30 +1826,20 @@ class LNWallet(LNWorker):
date=timestamp,
payment_secret=derive_payment_secret_from_payment_preimage(payment_preimage))
invoice = lnencode(lnaddr, self.node_keypair.privkey)
pair = lnaddr, invoice
self._bolt11_cache[payment_hash] = pair
return pair
def create_payment_info(self, amount_sat: Optional[int], write_to_disk=True) -> bytes:
amount_msat = amount_sat * 1000 if amount_sat else None
payment_preimage = os.urandom(32)
payment_hash = sha256(payment_preimage)
info = PaymentInfo(payment_hash, amount_msat, RECEIVED, PR_UNPAID)
self.save_preimage(payment_hash, payment_preimage, write_to_disk=False)
self.save_payment_info(info, write_to_disk=False)
if write_to_disk:
self.wallet.save_db()
return lnaddr, invoice
def add_request(
self,
*,
amount_sat: Optional[int],
message: str,
expiry: int,
fallback_address: Optional[str],
) -> str:
# passed expiry is relative, it is absolute in the lightning invoice
amount_msat = amount_sat * 1000 if amount_sat else None
lnaddr, invoice = self.create_invoice(
amount_msat=amount_msat,
message=message,
expiry=expiry,
fallback_address=fallback_address,
write_to_disk=False,
)
return invoice
return payment_hash
def save_preimage(self, payment_hash: bytes, preimage: bytes, *, write_to_disk: bool = True):
assert sha256(preimage) == payment_hash
@ -1853,7 +1849,7 @@ class LNWallet(LNWorker):
def get_preimage(self, payment_hash: bytes) -> Optional[bytes]:
r = self.preimages.get(payment_hash.hex())
return bfh(r) if r else None
return bytes.fromhex(r) if r else None
def get_payment_info(self, payment_hash: bytes) -> Optional[PaymentInfo]:
"""returns None if payment_hash is a payment we are forwarding"""
@ -1922,6 +1918,8 @@ class LNWallet(LNWorker):
self.set_payment_status(bfh(key), status)
util.trigger_callback('invoice_status', self.wallet, key, status)
self.logger.info(f"invoice status triggered (2) for key {key} and status {status}")
# liquidity changed
self.clear_invoices_cache()
def set_request_status(self, payment_hash: bytes, status: int) -> None:
if self.get_payment_status(payment_hash) == status:
@ -2138,7 +2136,7 @@ class LNWallet(LNWorker):
channels = list(self.channels.values())
# we exclude channels that cannot *right now* receive (e.g. peer offline)
channels = [chan for chan in channels
if (chan.is_active() and not chan.is_frozen_for_receiving())]
if (chan.is_open() and not chan.is_frozen_for_receiving())]
# Filter out nodes that have low receive capacity compared to invoice amt.
# Even with MPP, below a certain threshold, including these channels probably
# hurts more than help, as they lead to many failed attempts for the sender.
@ -2283,7 +2281,7 @@ class LNWallet(LNWorker):
raise Exception('Rebalance requires two different channels')
if self.uses_trampoline() and chan1.node_id == chan2.node_id:
raise Exception('Rebalance requires channels from different trampolines')
lnaddr, invoice = self.create_invoice(
lnaddr, invoice = self.add_reqest(
amount_msat=amount_msat,
message='rebalance',
expiry=3600,

8
electrum/submarine_swaps.py

@ -261,14 +261,16 @@ class SwapManager(Logger):
assert self.lnwatcher
privkey = os.urandom(32)
pubkey = ECPrivkey(privkey).get_public_key_bytes(compressed=True)
lnaddr, invoice = self.lnworker.create_invoice(
amount_msat=lightning_amount_sat * 1000,
amount_msat = lightning_amount_sat * 1000
payment_hash = self.lnworker.create_payment_info(lightning_amount_sat)
lnaddr, invoice = self.lnworker.get_bolt11_invoice(
payment_hash=payment_hash,
amount_msat=amount_msat,
message='swap',
expiry=3600 * 24,
fallback_address=None,
channels=channels,
)
payment_hash = lnaddr.paymenthash
preimage = self.lnworker.get_preimage(payment_hash)
request_data = {
"type": "submarine",

14
electrum/tests/test_invoices.py

@ -5,7 +5,7 @@ from . import ElectrumTestCase
from electrum.simple_config import SimpleConfig
from electrum.wallet import restore_wallet_from_text, Standard_Wallet, Abstract_Wallet
from electrum.invoices import PR_UNPAID, PR_PAID, PR_UNCONFIRMED, Invoice
from electrum.invoices import PR_UNPAID, PR_PAID, PR_UNCONFIRMED, BaseInvoice
from electrum.address_synchronizer import TX_HEIGHT_UNCONFIRMED
from electrum.transaction import Transaction, PartialTxOutput
from electrum.util import TxMinedInfo
@ -20,11 +20,11 @@ class TestWalletPaymentRequests(ElectrumTestCase):
self.config = SimpleConfig({'electrum_path': self.electrum_path})
self.wallet1_path = os.path.join(self.electrum_path, "somewallet1")
self.wallet2_path = os.path.join(self.electrum_path, "somewallet2")
self._orig_get_cur_time = Invoice._get_cur_time
self._orig_get_cur_time = BaseInvoice._get_cur_time
def tearDown(self):
super().tearDown()
Invoice._get_cur_time = staticmethod(self._orig_get_cur_time)
BaseInvoice._get_cur_time = staticmethod(self._orig_get_cur_time)
def create_wallet2(self) -> Standard_Wallet:
text = 'cross end slow expose giraffe fuel track awake turtle capital ranch pulp'
@ -156,8 +156,6 @@ class TestWalletPaymentRequests(ElectrumTestCase):
self.assertTrue(pr1.is_lightning())
self.assertEqual(PR_UNPAID, wallet1.get_invoice_status(pr1))
self.assertEqual(addr1, pr1.get_address())
self.assertEqual(addr1, pr1._lnaddr.get_fallback_address())
self.assertTrue(pr1.can_be_paid_onchain())
self.assertFalse(pr1.has_expired())
# create payreq2
@ -213,7 +211,7 @@ class TestWalletPaymentRequests(ElectrumTestCase):
self.assertEqual(addr1, pr1.get_address())
self.assertFalse(pr1.has_expired())
Invoice._get_cur_time = lambda *args: time.time() + 100_000
BaseInvoice._get_cur_time = lambda *args: time.time() + 100_000
self.assertTrue(pr1.has_expired())
# create payreq2
@ -240,7 +238,7 @@ class TestWalletPaymentRequests(ElectrumTestCase):
self.assertFalse(pr1.has_expired())
self.assertEqual(pr1, wallet1.get_request_by_addr(addr1))
Invoice._get_cur_time = lambda *args: time.time() + 100_000
BaseInvoice._get_cur_time = lambda *args: time.time() + 100_000
self.assertTrue(pr1.has_expired())
self.assertEqual(None, wallet1.get_request_by_addr(addr1))
@ -265,6 +263,6 @@ class TestWalletPaymentRequests(ElectrumTestCase):
self.assertEqual(PR_UNCONFIRMED, wallet1.get_invoice_status(pr1))
# now make both invoices be past their expiration date. pr2 should be unaffected.
Invoice._get_cur_time = lambda *args: time.time() + 200_000
BaseInvoice._get_cur_time = lambda *args: time.time() + 200_000
self.assertEqual(PR_UNCONFIRMED, wallet1.get_invoice_status(pr2))
self.assertEqual(pr2, wallet1.get_request_by_addr(addr1))

3
electrum/tests/test_lnpeer.py

@ -175,6 +175,9 @@ class MockLNWallet(Logger, EventListener, NetworkRetryManager[LNPeerAddr]):
self.logger.info(f"created LNWallet[{name}] with nodeID={local_keypair.pubkey.hex()}")
def clear_invoices_cache(self):
pass
def pay_scheduled_invoices(self):
pass

41
electrum/wallet.py

@ -74,7 +74,7 @@ from .transaction import (Transaction, TxInput, UnknownTxinType, TxOutput,
from .plugin import run_hook
from .address_synchronizer import (AddressSynchronizer, TX_HEIGHT_LOCAL,
TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED, TX_HEIGHT_FUTURE)
from .invoices import Invoice
from .invoices import Invoice, Request
from .invoices import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED, PR_UNCONFIRMED
from .contacts import Contacts
from .interface import NetworkException
@ -2443,7 +2443,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
}
if is_lightning:
d['rhash'] = x.rhash
d['lightning_invoice'] = x.lightning_invoice
d['lightning_invoice'] = self.get_bolt11_invoice(x)
d['amount_msat'] = x.get_amount_msat()
if self.lnworker and status == PR_UNPAID:
d['can_receive'] = self.lnworker.can_receive_invoice(x)
@ -2477,7 +2477,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
'invoice_id': key,
}
if is_lightning:
d['lightning_invoice'] = x.lightning_invoice
d['lightning_invoice'] = self.get_bolt11_invoice(x)
d['amount_msat'] = x.get_amount_msat()
if self.lnworker and status == PR_UNPAID:
d['can_pay'] = self.lnworker.can_pay_invoice(x)
@ -2508,6 +2508,18 @@ class Abstract_Wallet(ABC, Logger, EventListener):
relevant_invoice_keys.add(invoice_key)
self._update_onchain_invoice_paid_detection(relevant_invoice_keys)
def get_bolt11_invoice(self, req: Request) -> str:
if not self.lnworker:
return ''
amount_msat = req.amount_msat if req.amount_msat > 0 else None
lnaddr, invoice = self.lnworker.get_bolt11_invoice(
payment_hash=req.payment_hash,
amount_msat=amount_msat,
message=req.message,
expiry=req.exp,
fallback_address=req.get_address() if self.config.get('bolt11_fallback', True) else None)
return invoice
def create_request(self, amount_sat: int, message: str, exp_delay: int, address: Optional[str]):
# for receiving
amount_sat = amount_sat or 0
@ -2515,21 +2527,11 @@ class Abstract_Wallet(ABC, Logger, EventListener):
message = message or ''
address = address or None # converts "" to None
exp_delay = exp_delay or 0
timestamp = int(Invoice._get_cur_time())
fallback_address = address if self.config.get('bolt11_fallback', True) else None
lightning = self.has_lightning()
if lightning:
lightning_invoice = self.lnworker.add_request(
amount_sat=amount_sat,
message=message,
expiry=exp_delay,
fallback_address=fallback_address,
)
else:
lightning_invoice = None
timestamp = int(Request._get_cur_time())
payment_hash = self.lnworker.create_payment_info(amount_sat, write_to_disk=False) if self.has_lightning() else None
outputs = [ PartialTxOutput.from_address_and_value(address, amount_sat)] if address else []
height = self.adb.get_local_height()
req = Invoice(
req = Request(
outputs=outputs,
message=message,
time=timestamp,
@ -2537,7 +2539,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
exp=exp_delay,
height=height,
bip70=None,
lightning_invoice=lightning_invoice,
payment_hash=payment_hash,
)
key = self.add_payment_request(req)
return key
@ -2858,7 +2860,6 @@ class Abstract_Wallet(ABC, Logger, EventListener):
ln_is_error = False
ln_swap_suggestion = None
ln_rebalance_suggestion = None
lnaddr = req.lightning_invoice or ''
URI = self.get_request_URI(req) or ''
lightning_online = self.lnworker and self.lnworker.num_peers() > 0
can_receive_lightning = self.lnworker and amount_sat <= self.lnworker.num_sats_can_receive()
@ -2878,7 +2879,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
URI_help = _('This request cannot be paid on-chain')
if is_amt_too_small_for_onchain:
URI_help = _('Amount too small to be received onchain')
if not lnaddr:
if not req.is_lightning():
ln_is_error = True
ln_help = _('This request does not have a Lightning invoice.')
@ -2886,7 +2887,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
if self.adb.is_used(addr):
address_help = URI_help = (_("This address has already been used. "
"For better privacy, do not reuse it for new payments."))
if lnaddr:
if req.is_lightning():
if not lightning_online:
ln_is_error = True
ln_help = _('You must be online to receive Lightning payments.')

22
electrum/wallet_db.py

@ -33,7 +33,7 @@ import binascii
from . import util, bitcoin
from .util import profiler, WalletFileException, multisig_type, TxMinedInfo, bfh
from .invoices import Invoice
from .invoices import Invoice, Request
from .keystore import bip44_derivation
from .transaction import Transaction, TxOutpoint, tx_from_any, PartialTransaction, PartialTxOutput
from .logging import Logger
@ -52,7 +52,7 @@ if TYPE_CHECKING:
OLD_SEED_VERSION = 4 # electrum versions < 2.0
NEW_SEED_VERSION = 11 # electrum versions >= 2.0
FINAL_SEED_VERSION = 50 # electrum >= 2.7 will set this to prevent
FINAL_SEED_VERSION = 51 # electrum >= 2.7 will set this to prevent
# old versions from overwriting new format
@ -199,6 +199,7 @@ class WalletDB(JsonDB):
self._convert_version_48()
self._convert_version_49()
self._convert_version_50()
self._convert_version_51()
self.put('seed_version', FINAL_SEED_VERSION) # just to be sure
self._after_upgrade_tasks()
@ -980,6 +981,21 @@ class WalletDB(JsonDB):
self._convert_invoices_keys(requests)
self.data['seed_version'] = 50
def _convert_version_51(self):
from .lnaddr import lndecode
if not self._is_upgrade_method_needed(50, 50):
return
requests = self.data.get('payment_requests', {})
for key, item in list(requests.items()):
lightning_invoice = item.pop('lightning_invoice')
if lightning_invoice is None:
payment_hash = None
else:
lnaddr = lndecode(lightning_invoice)
payment_hash = lnaddr.paymenthash.hex()
item['payment_hash'] = payment_hash
self.data['seed_version'] = 51
def _convert_imported(self):
if not self._is_upgrade_method_needed(0, 13):
return
@ -1460,7 +1476,7 @@ class WalletDB(JsonDB):
if key == 'invoices':
v = dict((k, Invoice(**x)) for k, x in v.items())
if key == 'payment_requests':
v = dict((k, Invoice(**x)) for k, x in v.items())
v = dict((k, Request(**x)) for k, x in v.items())
elif key == 'adds':
v = dict((k, UpdateAddHtlc.from_tuple(*x)) for k, x in v.items())
elif key == 'fee_updates':

Loading…
Cancel
Save