commit 67d24bf12981a730b7b95c369360ccbec5ed29c9
parent fd56fb918982c7afbf96267e03d7cfb2ca7fc858
Author: SomberNight <somber.night@protonmail.com>
Date: Sat, 29 Feb 2020 20:02:45 +0100
add LN gossip sync progress estimate indicator to Qt GUI
Diffstat:
4 files changed, 50 insertions(+), 9 deletions(-)
diff --git a/electrum/channel_db.py b/electrum/channel_db.py
@@ -271,6 +271,7 @@ class ChannelDB(SqlDB):
self.num_channels = len(self._channels)
self.num_policies = len(self._policies)
self.network.trigger_callback('channel_db', self.num_nodes, self.num_channels, self.num_policies)
+ self.network.trigger_callback('ln_gossip_sync_progress')
def get_channel_ids(self):
with self.lock:
@@ -590,19 +591,30 @@ class ChannelDB(SqlDB):
self._channels_for_node[channel_info.node2_id].add(channel_info.short_channel_id)
self.logger.info(f'load data {len(self._channels)} {len(self._policies)} {len(self._channels_for_node)}')
self.update_counts()
- self.logger.info(f'semi-orphaned channels: {self.get_num_incomplete_channels()}')
+ (nchans_with_0p, nchans_with_1p, nchans_with_2p) = self.get_num_channels_partitioned_by_policy_count()
+ self.logger.info(f'num_channels_partitioned_by_policy_count. '
+ f'0p: {nchans_with_0p}, 1p: {nchans_with_1p}, 2p: {nchans_with_2p}')
self.data_loaded.set()
- def get_num_incomplete_channels(self) -> int:
- found = set()
+ def get_num_channels_partitioned_by_policy_count(self) -> Tuple[int, int, int]:
+ chans_with_zero_policies = set()
+ chans_with_one_policies = set()
+ chans_with_two_policies = set()
with self.lock:
_channels = self._channels.copy()
for short_channel_id, ci in _channels.items():
p1 = self.get_policy_for_node(short_channel_id, ci.node1_id)
p2 = self.get_policy_for_node(short_channel_id, ci.node2_id)
- if p1 is None or p2 is not None:
- found.add(short_channel_id)
- return len(found)
+ if p1 is not None and p2 is not None:
+ chans_with_two_policies.add(short_channel_id)
+ elif p1 is None and p2 is None:
+ chans_with_zero_policies.add(short_channel_id)
+ else:
+ chans_with_one_policies.add(short_channel_id)
+ nchans_with_0p = len(chans_with_zero_policies)
+ nchans_with_1p = len(chans_with_one_policies)
+ nchans_with_2p = len(chans_with_two_policies)
+ return nchans_with_0p, nchans_with_1p, nchans_with_2p
def get_policy_for_node(self, short_channel_id: bytes, node_id: bytes, *,
my_channels: Dict[ShortChannelID, 'Channel'] = None) -> Optional['Policy']:
diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py
@@ -265,7 +265,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
'new_transaction', 'status',
'banner', 'verified', 'fee', 'fee_histogram', 'on_quotes',
'on_history', 'channel', 'channels_updated',
- 'invoice_status', 'request_status']
+ 'invoice_status', 'request_status', 'ln_gossip_sync_progress']
# To avoid leaking references to "self" that prevent the
# window from being GC-ed when closed, callbacks should be
# methods of this class only, and specifically not be
@@ -430,6 +430,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
pass
elif event == 'fee_histogram':
self.history_model.on_fee_histogram()
+ elif event == 'ln_gossip_sync_progress':
+ self.update_lightning_icon()
else:
self.logger.info(f"unexpected network event: {event} {args}")
@@ -2085,6 +2087,20 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
self.coincontrol_label.setText(msg)
self.coincontrol_sb.setVisible(True)
+ def update_lightning_icon(self): # TODO rate-limit?
+ self.lightning_button.setMaximumWidth(25 + 4 * char_width_in_lineedit())
+ cur, total = self.network.lngossip.get_sync_progress_estimate()
+ # self.logger.debug(f"updating lngossip sync progress estimate: cur={cur}, total={total}")
+ if cur is None or total is None:
+ progress_str = "??%"
+ else:
+ if total > 0:
+ progress_percent = 100 * cur // total
+ else:
+ progress_percent = 0
+ progress_str = f"{progress_percent}%"
+ self.lightning_button.setText(progress_str)
+
def update_lock_icon(self):
icon = read_QIcon("lock.png") if self.wallet.has_password() else read_QIcon("unlock.png")
self.password_button.setIcon(icon)
diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
@@ -125,7 +125,7 @@ class Peer(Logger):
self.initialized.set_result(True)
def is_initialized(self):
- return self.initialized.done() and self.initialized.result() == True
+ return self.initialized.done() and self.initialized.result() is True
async def initialize(self):
if isinstance(self.transport, LNTransport):
diff --git a/electrum/lnworker.py b/electrum/lnworker.py
@@ -198,7 +198,7 @@ class LNWorker(Logger):
def peer_closed(self, peer: Peer) -> None:
self.peers.pop(peer.pubkey)
- def num_peers(self):
+ def num_peers(self) -> int:
return sum([p.is_initialized() for p in self.peers.values()])
def start_network(self, network: 'Network'):
@@ -359,14 +359,27 @@ class LNGossip(LNWorker):
self.unknown_ids.update(new)
self.network.trigger_callback('unknown_channels', len(self.unknown_ids))
self.network.trigger_callback('gossip_peers', self.num_peers())
+ self.network.trigger_callback('ln_gossip_sync_progress')
def get_ids_to_query(self):
N = 500
l = list(self.unknown_ids)
self.unknown_ids = set(l[N:])
self.network.trigger_callback('unknown_channels', len(self.unknown_ids))
+ self.network.trigger_callback('ln_gossip_sync_progress')
return l[0:N]
+ def get_sync_progress_estimate(self) -> Tuple[Optional[int], Optional[int]]:
+ if self.num_peers() == 0:
+ return None, None
+ num_db_channels = self.channel_db.num_channels
+ nchans_with_0p, nchans_with_1p, nchans_with_2p = self.channel_db.get_num_channels_partitioned_by_policy_count()
+ # some channels will never have two policies (only one is in gossip?...)
+ # so if we have at least 1 policy for a channel, we consider that channel "complete" here
+ current_est = num_db_channels - nchans_with_0p
+ total_est = len(self.unknown_ids) + num_db_channels
+ return current_est, total_est
+
class LNWallet(LNWorker):