Browse Source

add LN gossip sync progress estimate indicator to Qt GUI

hard-fail-on-bad-server-string
SomberNight 5 years ago
parent
commit
67d24bf129
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 24
      electrum/channel_db.py
  2. 18
      electrum/gui/qt/main_window.py
  3. 2
      electrum/lnpeer.py
  4. 15
      electrum/lnworker.py

24
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']:

18
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)

2
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):

15
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):

Loading…
Cancel
Save