commit 8d77a7ecd86fb39c1fb21a506144ba23dcabb83a
parent ecd9508233ad2512b09cc1d9a681da076dd1a54e
Author: ThomasV <thomasv@electrum.org>
Date: Thu, 7 Mar 2019 17:51:35 +0100
save timestamps in htlc log
Diffstat:
6 files changed, 40 insertions(+), 39 deletions(-)
diff --git a/electrum/gui/qt/invoice_list.py b/electrum/gui/qt/invoice_list.py
@@ -31,7 +31,7 @@ from PyQt5.QtWidgets import QHeaderView, QMenu
from electrum.i18n import _
from electrum.util import format_time, pr_tooltips, PR_UNPAID
-from electrum.lnutil import lndecode
+from electrum.lnutil import lndecode, RECEIVED
from electrum.bitcoin import COIN
from electrum import constants
@@ -92,8 +92,8 @@ class InvoiceList(MyTreeView):
self.model().insertRow(idx, items)
lnworker = self.parent.wallet.lnworker
- for key, (invoice, is_received) in lnworker.invoices.items():
- if is_received:
+ for key, (invoice, direction, is_paid) in lnworker.invoices.items():
+ if direction == RECEIVED:
continue
status = lnworker.get_invoice_status(key)
lnaddr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
diff --git a/electrum/gui/qt/request_list.py b/electrum/gui/qt/request_list.py
@@ -94,7 +94,7 @@ class RequestList(MyTreeView):
return
req = self.parent.get_request_URI(key)
elif request_type == REQUEST_TYPE_LN:
- req, is_received = self.wallet.lnworker.invoices.get(key) or (None, None)
+ req, direction, is_paid = self.wallet.lnworker.invoices.get(key) or (None, None)
if req is None:
self.update()
return
@@ -136,8 +136,8 @@ class RequestList(MyTreeView):
self.filter()
# lightning
lnworker = self.wallet.lnworker
- for key, (invoice, is_received) in lnworker.invoices.items():
- if not is_received:
+ for key, (invoice, direction, is_paid) in lnworker.invoices.items():
+ if direction == SENT:
continue
status = lnworker.get_invoice_status(key)
lnaddr = lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py
@@ -613,9 +613,8 @@ class Channel(PrintError):
assert htlc.payment_hash == sha256(preimage)
assert htlc_id not in log['settles']
self.hm.send_settle(htlc_id)
- # save timestamp in LNWorker.preimages
if self.lnworker:
- self.lnworker.save_preimage(htlc.payment_hash, preimage, timestamp=int(time.time()))
+ self.lnworker.set_paid(htlc.payment_hash)
def receive_htlc_settle(self, preimage, htlc_id):
self.print_error("receive_htlc_settle")
@@ -625,7 +624,8 @@ class Channel(PrintError):
assert htlc_id not in log['settles']
self.hm.recv_settle(htlc_id)
if self.lnworker:
- self.lnworker.save_preimage(htlc.payment_hash, preimage, timestamp=int(time.time()))
+ self.lnworker.save_preimage(htlc.payment_hash, preimage)
+ self.lnworker.set_paid(htlc.payment_hash)
def fail_htlc(self, htlc_id):
self.print_error("fail_htlc")
diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
@@ -864,7 +864,7 @@ class Peer(PrintError):
secret_key = os.urandom(32)
onion = new_onion_packet([x.node_id for x in route], secret_key, hops_data, associated_data=payment_hash)
# create htlc
- htlc = UpdateAddHtlc(amount_msat=amount_msat, payment_hash=payment_hash, cltv_expiry=cltv)
+ htlc = UpdateAddHtlc(amount_msat=amount_msat, payment_hash=payment_hash, cltv_expiry=cltv, timestamp=int(time.time()))
htlc = chan.add_htlc(htlc)
remote_ctn = chan.get_current_ctn(REMOTE)
chan.onion_keys[htlc.htlc_id] = secret_key
@@ -943,7 +943,7 @@ class Peer(PrintError):
if cltv_expiry >= 500_000_000:
pass # TODO fail the channel
# add htlc
- htlc = UpdateAddHtlc(amount_msat=amount_msat_htlc, payment_hash=payment_hash, cltv_expiry=cltv_expiry)
+ htlc = UpdateAddHtlc(amount_msat=amount_msat_htlc, payment_hash=payment_hash, cltv_expiry=cltv_expiry, timestamp=int(time.time()))
htlc = chan.receive_htlc(htlc)
local_ctn = chan.get_current_ctn(LOCAL)
remote_ctn = chan.get_current_ctn(REMOTE)
@@ -980,7 +980,7 @@ class Peer(PrintError):
self.print_error('forwarding htlc to', next_chan.node_id)
next_cltv_expiry = int.from_bytes(dph.outgoing_cltv_value, 'big')
next_amount_msat_htlc = int.from_bytes(dph.amt_to_forward, 'big')
- next_htlc = UpdateAddHtlc(amount_msat=next_amount_msat_htlc, payment_hash=htlc.payment_hash, cltv_expiry=next_cltv_expiry)
+ next_htlc = UpdateAddHtlc(amount_msat=next_amount_msat_htlc, payment_hash=htlc.payment_hash, cltv_expiry=next_cltv_expiry, timestamp=int(time.time()))
next_htlc = next_chan.add_htlc(next_htlc)
next_remote_ctn = next_chan.get_current_ctn(REMOTE)
next_peer.send_message(
diff --git a/electrum/lnutil.py b/electrum/lnutil.py
@@ -666,7 +666,7 @@ def format_short_channel_id(short_channel_id: Optional[bytes]):
+ 'x' + str(int.from_bytes(short_channel_id[6:], 'big'))
-class UpdateAddHtlc(namedtuple('UpdateAddHtlc', ['amount_msat', 'payment_hash', 'cltv_expiry', 'htlc_id'])):
+class UpdateAddHtlc(namedtuple('UpdateAddHtlc', ['amount_msat', 'payment_hash', 'cltv_expiry', 'htlc_id', 'timestamp'])):
# note: typing.NamedTuple cannot be used because we are overriding __new__
__slots__ = ()
diff --git a/electrum/lnworker.py b/electrum/lnworker.py
@@ -71,8 +71,8 @@ class LNWorker(PrintError):
def __init__(self, wallet: 'Abstract_Wallet'):
self.wallet = wallet
self.storage = wallet.storage
- self.invoices = self.storage.get('lightning_invoices', {}) # RHASH -> (invoice, is_received)
- self.preimages = self.storage.get('lightning_preimages', {}) # RHASH -> (preimage, timestamp)
+ self.invoices = self.storage.get('lightning_invoices', {}) # RHASH -> (invoice, direction, is_paid)
+ self.preimages = self.storage.get('lightning_preimages', {}) # RHASH -> preimage
self.sweep_address = wallet.get_receiving_address()
self.lock = threading.RLock()
self.ln_keystore = self._read_ln_keystore()
@@ -133,13 +133,11 @@ class LNWorker(PrintError):
timestamp = int(time.time())
self.network.trigger_callback('ln_payment_completed', timestamp, direction, htlc, preimage, chan_id)
- def get_invoice_status(self, payment_hash):
- if payment_hash not in self.preimages:
+ def get_invoice_status(self, key):
+ if key not in self.invoices:
return PR_UNKNOWN
- preimage, timestamp = self.preimages.get(payment_hash)
- if timestamp is None:
- return PR_UNPAID
- return PR_PAID
+ invoice, direction, is_paid = self.invoices[key]
+ return PR_PAID if is_paid else PR_UNPAID
def get_payments(self):
# return one item per payment_hash
@@ -159,14 +157,15 @@ class LNWorker(PrintError):
direction = 'sent' if _direction == SENT else 'received'
amount_msat= int(_direction) * htlc.amount_msat
label = ''
+ timestamp = htlc.timestamp
else:
# assume forwarding
direction = 'forwarding'
amount_msat = sum([int(_direction) * htlc.amount_msat for chan_id, htlc, _direction, status in plist])
status = ''
label = _('Forwarding')
+ timestamp = min([htlc.timestamp for chan_id, htlc, _direction, status in plist])
- timestamp = self.preimages[payment_hash][1] if payment_hash in self.preimages else None
item = {
'type': 'payment',
'label': label,
@@ -490,7 +489,7 @@ class LNWorker(PrintError):
if not chan:
raise Exception("PathFinder returned path with short_channel_id {} that is not in channel list".format(bh2u(short_channel_id)))
peer = self.peers[route[0].node_id]
- self.save_invoice(addr.paymenthash, pay_req, SENT)
+ self.save_invoice(addr.paymenthash, pay_req, SENT, is_paid=False)
htlc = await peer.pay(route, chan, int(addr.amount * COIN * 1000), addr.paymenthash, addr.get_min_final_cltv_expiry())
self.network.trigger_callback('htlc_added', htlc, addr, SENT)
@@ -574,40 +573,42 @@ class LNWorker(PrintError):
('c', MIN_FINAL_CLTV_EXPIRY_FOR_INVOICE)]
+ routing_hints),
self.node_keypair.privkey)
- self.save_invoice(payment_hash, invoice, RECEIVED)
- self.save_preimage(payment_hash, payment_preimage, timestamp=None)
+ self.save_invoice(payment_hash, invoice, RECEIVED, is_paid=False)
+ self.save_preimage(payment_hash, payment_preimage)
return invoice
- def save_preimage(self, payment_hash: bytes, preimage: bytes, *, timestamp: Optional[int]):
+ def save_preimage(self, payment_hash: bytes, preimage: bytes):
assert sha256(preimage) == payment_hash
- if timestamp is not None:
- timestamp = int(timestamp)
key = bh2u(payment_hash)
- self.preimages[key] = bh2u(preimage), timestamp
+ self.preimages[key] = bh2u(preimage)
self.storage.put('lightning_preimages', self.preimages)
self.storage.write()
- def get_preimage_and_timestamp(self, payment_hash: bytes) -> Tuple[bytes, int]:
+ def get_preimage(self, payment_hash: bytes) -> bytes:
try:
- preimage_hex, timestamp = self.preimages[bh2u(payment_hash)]
- preimage = bfh(preimage_hex)
+ preimage = bfh(self.preimages[bh2u(payment_hash)])
assert sha256(preimage) == payment_hash
- return preimage, timestamp
+ return preimage
except KeyError as e:
raise UnknownPaymentHash(payment_hash) from e
- def get_preimage(self, payment_hash: bytes) -> bytes:
- return self.get_preimage_and_timestamp(payment_hash)[0]
-
- def save_invoice(self, payment_hash:bytes, invoice, direction):
+ def save_invoice(self, payment_hash:bytes, invoice, direction, *, is_paid=False):
key = bh2u(payment_hash)
- self.invoices[key] = invoice, direction==RECEIVED
+ self.invoices[key] = invoice, direction, is_paid
self.storage.put('lightning_invoices', self.invoices)
self.storage.write()
+ def set_paid(self, payment_hash):
+ key = bh2u(payment_hash)
+ if key not in self.invoices:
+ # if we are forwarding
+ return
+ invoice, direction, _ = self.invoices[key]
+ self.save_invoice(payment_hash, invoice, direction, is_paid=True)
+
def get_invoice(self, payment_hash: bytes) -> LnAddr:
try:
- invoice, is_received = self.invoices[bh2u(payment_hash)]
+ invoice, direction, is_paid = self.invoices[bh2u(payment_hash)]
return lndecode(invoice, expected_hrp=constants.net.SEGWIT_HRP)
except KeyError as e:
raise UnknownPaymentHash(payment_hash) from e