Skip to content

Commit

Permalink
detect conflicting channel backups, add warning before channel creation
Browse files Browse the repository at this point in the history
  • Loading branch information
ecdsa committed Mar 30, 2021
1 parent f2040b1 commit cd4df2f
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 4 deletions.
13 changes: 13 additions & 0 deletions electrum/gui/kivy/uix/dialogs/lightning_open_channel.py
Expand Up @@ -15,6 +15,7 @@
from .label_dialog import LabelDialog
from .confirm_tx_dialog import ConfirmTxDialog
from .qr_dialog import QRDialog
from .question import Question

if TYPE_CHECKING:
from ...main_window import ElectrumWindow
Expand Down Expand Up @@ -179,6 +180,18 @@ def open_channel(self):
amount = '!' if self.is_max else self.app.get_amount(self.amount)
self.dismiss()
lnworker = self.app.wallet.lnworker
node_id, rest = extract_nodeid(conn_str)
if lnworker.has_conflicting_backup_with(node_id):
msg = messages.MGS_CONFLICTING_BACKUP_INSTANCE
d = Question(msg, lambda x: self._open_channel(x, conn_str, amount))
d.open()
else:
self._open_channel(True, conn_str, amount)

def _open_channel(self, x, conn_str, amount):
if not x:
return
lnworker = self.app.wallet.lnworker
coins = self.app.wallet.get_spendable_coins(None, nonlocal_only=True)
node_id, rest = extract_nodeid(conn_str)
make_tx = lambda rbf: lnworker.mktx_for_open_channel(
Expand Down
6 changes: 6 additions & 0 deletions electrum/gui/messages.py
Expand Up @@ -31,3 +31,9 @@ def to_rtf(msg):
Downloading the network gossip uses quite some bandwidth and storage, and is not recommended on mobile devices. If you use trampoline, you can only open channels with trampoline nodes.
"""

MGS_CONFLICTING_BACKUP_INSTANCE = """
Another instance of this wallet (same seed) has an open channel with the same remote node. If you create this channel, you will not be able to use both wallets at the same time.
Are you sure?
"""
4 changes: 4 additions & 0 deletions electrum/gui/qt/main_window.py
Expand Up @@ -1813,6 +1813,10 @@ def open_channel(self, connect_str, funding_sat, push_amt):
except ConnStringFormatError as e:
self.show_error(str(e))
return
if self.wallet.lnworker.has_conflicting_backup_with(node_id):
msg = messages.MGS_CONFLICTING_BACKUP_INSTANCE
if not self.question(msg):
return
# use ConfirmTxDialog
# we need to know the fee before we broadcast, because the txid is required
make_tx = self.mktx_for_open_channel(funding_sat=funding_sat, node_id=node_id)
Expand Down
5 changes: 1 addition & 4 deletions electrum/lnrater.py
Expand Up @@ -243,9 +243,6 @@ def suggest_node_channel_open(self) -> Tuple[bytes, NodeStats]:
node_keys = list(self._node_stats.keys())
node_ratings = list(self._node_ratings.values())
channel_peers = self.lnworker.channel_peers()
channel_backup_peers = [
cb.node_id for cb in self.lnworker.channel_backups.values()
if (not cb.is_closed() and cb.get_local_pubkey() == self.lnworker.node_keypair.pubkey)]
node_info: Optional["NodeInfo"] = None

while True:
Expand All @@ -264,7 +261,7 @@ def suggest_node_channel_open(self) -> Tuple[bytes, NodeStats]:
if pk in channel_peers:
continue
# don't want to connect to nodes we already have a channel with on another device
if any(pk.startswith(cb_peer_nodeid) for cb_peer_nodeid in channel_backup_peers):
if self.lnworker.has_conflicting_backup_with(pk):
continue
break

Expand Down
7 changes: 7 additions & 0 deletions electrum/lnworker.py
Expand Up @@ -2123,6 +2123,13 @@ def import_channel_backup(self, data):
util.trigger_callback('channels_updated', self.wallet)
self.lnwatcher.add_channel(cb.funding_outpoint.to_str(), cb.get_funding_address())

def has_conflicting_backup_with(self, remote_node_id: bytes):
""" Returns whether we have an active channel with this node on another device, using same local node id. """
channel_backup_peers = [
cb.node_id for cb in self.channel_backups.values()
if (not cb.is_closed() and cb.get_local_pubkey() == self.node_keypair.pubkey)]
return any(remote_node_id.startswith(cb_peer_nodeid) for cb_peer_nodeid in channel_backup_peers)

def remove_channel_backup(self, channel_id):
chan = self.channel_backups[channel_id]
assert chan.can_be_deleted()
Expand Down

0 comments on commit cd4df2f

Please sign in to comment.