1
0

add zeroconf handling to qt gui

This commit is contained in:
f321x
2025-03-03 12:35:21 +01:00
parent 838189a586
commit 5134d07b14
2 changed files with 55 additions and 12 deletions

View File

@@ -98,6 +98,8 @@ class ReceiveTab(QWidget, MessageBoxMixin, Logger):
self.receive_help_text.setLayout(QHBoxLayout())
self.receive_rebalance_button = QPushButton('Rebalance')
self.receive_rebalance_button.suggestion = None
self.receive_zeroconf_button = QPushButton(_('Accept'))
self.receive_zeroconf_button.clicked.connect(self.on_accept_zeroconf)
def on_receive_rebalance():
if self.receive_rebalance_button.suggestion:
@@ -115,6 +117,7 @@ class ReceiveTab(QWidget, MessageBoxMixin, Logger):
buttons = QHBoxLayout()
buttons.addWidget(self.receive_rebalance_button)
buttons.addWidget(self.receive_swap_button)
buttons.addWidget(self.receive_zeroconf_button)
vbox = QVBoxLayout()
vbox.addWidget(self.receive_help_text)
vbox.addLayout(buttons)
@@ -236,26 +239,37 @@ class ReceiveTab(QWidget, MessageBoxMixin, Logger):
self.ln_help = help_texts.ln_help
can_rebalance = help_texts.can_rebalance()
can_swap = help_texts.can_swap()
can_zeroconf = help_texts.can_zeroconf()
self.receive_rebalance_button.suggestion = help_texts.ln_rebalance_suggestion
self.receive_swap_button.suggestion = help_texts.ln_swap_suggestion
self.receive_rebalance_button.setVisible(can_rebalance)
self.receive_swap_button.setVisible(can_swap)
self.receive_rebalance_button.setEnabled(can_rebalance and self.window.num_tasks() == 0)
self.receive_swap_button.setEnabled(can_swap and self.window.num_tasks() == 0)
self.receive_zeroconf_button.setVisible(can_zeroconf)
self.receive_zeroconf_button.setEnabled(can_zeroconf)
text, data, help_text, title = self.get_tab_data()
self.receive_e.setText(text)
self.receive_qr.setData(data)
self.receive_help_text.setText(help_text)
for w in [self.receive_e, self.receive_qr]:
w.setEnabled(bool(text) and not help_text)
w.setEnabled(bool(text) and (not help_text or can_zeroconf))
w.setToolTip(help_text)
# macOS hack (similar to #4777)
self.receive_e.repaint()
# always show
if can_zeroconf:
# show the help message if zeroconf so user can first accept it and still sees the invoice
# after accepting
self.receive_widget.show_help()
self.receive_widget.setVisible(True)
self.toggle_qr_button.setEnabled(True)
self.update_receive_qr_window()
def on_accept_zeroconf(self):
self.receive_zeroconf_button.setVisible(False)
self.update_receive_widgets()
def get_tab_data(self):
if self.URI:
out = self.URI, self.URI, self.URI_help, _('Bitcoin URI')
@@ -374,9 +388,12 @@ class ReceiveWidget(QWidget):
self.textedit.setVisible(not is_qr)
self.qr.setVisible(is_qr)
else:
self.help_widget.setVisible(True)
self.textedit.setVisible(False)
self.qr.setVisible(False)
self.show_help()
def show_help(self):
self.help_widget.setVisible(True)
self.textedit.setVisible(False)
self.qr.setVisible(False)
def resizeEvent(self, e):
# keep square aspect ratio when resized

View File

@@ -53,6 +53,7 @@ from .i18n import _
from .bip32 import BIP32Node, convert_bip32_intpath_to_strpath, convert_bip32_strpath_to_intpath
from .crypto import sha256
from . import util
from .lntransport import extract_nodeid
from .util import (NotEnoughFunds, UserCancelled, profiler, OldTaskGroup, ignore_exceptions,
format_satoshis, format_fee_satoshis, NoDynamicFeeEstimates,
WalletFileException, BitcoinException,
@@ -60,6 +61,7 @@ from .util import (NotEnoughFunds, UserCancelled, profiler, OldTaskGroup, ignore
Fiat, bfh, TxMinedInfo, quantize_feerate, OrderedDictWithIndex)
from .simple_config import SimpleConfig
from .fee_policy import FeePolicy, FixedFeePolicy, FeeMethod, FEE_RATIO_HIGH_WARNING, FEERATE_WARNING_HIGH_FEE
from .lnutil import MIN_FUNDING_SAT
from .bitcoin import COIN, TYPE_ADDRESS
from .bitcoin import is_address, address_to_script, is_minikey, relayfee, dust_threshold
from .bitcoin import DummyAddress, DummyAddressUsedInTxException
@@ -346,6 +348,7 @@ class ReceiveRequestHelp(NamedTuple):
ln_swap_suggestion: Optional[Any] = None
ln_rebalance_suggestion: Optional[Any] = None
ln_zeroconf_suggestion: bool = False
def can_swap(self) -> bool:
return bool(self.ln_swap_suggestion)
@@ -353,6 +356,9 @@ class ReceiveRequestHelp(NamedTuple):
def can_rebalance(self) -> bool:
return bool(self.ln_rebalance_suggestion)
def can_zeroconf(self) -> bool:
return self.ln_zeroconf_suggestion
class TxWalletDelta(NamedTuple):
is_relevant: bool # "related to wallet?"
@@ -3250,12 +3256,19 @@ class Abstract_Wallet(ABC, Logger, EventListener):
ln_is_error = False
ln_swap_suggestion = None
ln_rebalance_suggestion = None
ln_zeroconf_suggestion = False
URI = self.get_request_URI(req) or ''
lightning_has_channels = (
self.lnworker and len([chan for chan in self.lnworker.channels.values() if chan.is_open()]) > 0
)
lightning_online = self.lnworker and self.lnworker.num_peers() > 0
can_receive_lightning = self.lnworker and amount_sat <= self.lnworker.num_sats_can_receive()
try:
zeroconf_nodeid = extract_nodeid(self.config.ZEROCONF_TRUSTED_NODE)[0]
except Exception:
zeroconf_nodeid = None
can_get_zeroconf_channel = (self.lnworker and self.config.ACCEPT_ZEROCONF_CHANNELS
and zeroconf_nodeid in self.lnworker.peers)
status = self.get_invoice_status(req)
if status == PR_EXPIRED:
@@ -3281,21 +3294,33 @@ class Abstract_Wallet(ABC, Logger, EventListener):
address_help = URI_help = (_("This address has already been used. "
"For better privacy, do not reuse it for new payments."))
if req.is_lightning():
if not lightning_has_channels:
if not lightning_has_channels and not can_get_zeroconf_channel:
ln_is_error = True
ln_help = _("You must have an open Lightning channel to receive payments.")
elif not lightning_online:
ln_is_error = True
ln_help = _('You must be online to receive Lightning payments.')
elif not can_receive_lightning:
ln_is_error = True
elif not can_receive_lightning or (amount_sat <= 0 and not lightning_has_channels):
ln_rebalance_suggestion = self.lnworker.suggest_rebalance_to_receive(amount_sat)
ln_swap_suggestion = self.lnworker.suggest_swap_to_receive(amount_sat)
ln_help = _('You do not have the capacity to receive this amount with Lightning.')
if bool(ln_rebalance_suggestion):
ln_help += '\n\n' + _('You may have that capacity if you rebalance your channels.')
elif bool(ln_swap_suggestion):
ln_help += '\n\n' + _('You may have that capacity if you swap some of your funds.')
# prefer to use swaps over JIT channels if possible
if can_get_zeroconf_channel and not bool(ln_rebalance_suggestion) and not bool(ln_swap_suggestion):
if amount_sat < MIN_FUNDING_SAT:
ln_is_error = True
ln_help = (_('Cannot receive this payment. Request at least {} '
'to purchase a Lightning channel from your service provider.')
.format(self.config.format_amount_and_units(amount_sat=MIN_FUNDING_SAT)))
else:
ln_zeroconf_suggestion = True
ln_help = _(f'Receiving this payment will purchase a payment channel from your '
f'service provider. Service fees are deducted from the incoming payment.')
else:
ln_is_error = True
ln_help = _('You do not have the capacity to receive this amount with Lightning.')
if bool(ln_rebalance_suggestion):
ln_help += '\n\n' + _('You may have that capacity if you rebalance your channels.')
elif bool(ln_swap_suggestion):
ln_help += '\n\n' + _('You may have that capacity if you swap some of your funds.')
# for URI that has LN part but no onchain part, copy error:
if not addr and ln_is_error:
URI_is_error = ln_is_error
@@ -3309,6 +3334,7 @@ class Abstract_Wallet(ABC, Logger, EventListener):
ln_is_error=ln_is_error,
ln_rebalance_suggestion=ln_rebalance_suggestion,
ln_swap_suggestion=ln_swap_suggestion,
ln_zeroconf_suggestion=ln_zeroconf_suggestion
)