Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions electrum/gui/kivy/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -1100,19 +1100,31 @@ def _sign_tx(self, tx, password, on_success, on_failure):
on_success = run_hook('tc_sign_wrapper', self.wallet, tx, on_success, on_failure) or on_success
Clock.schedule_once(lambda dt: on_success(tx))

def _broadcast_thread(self, tx, on_complete):
def _broadcast_thread(self, tx, pr, on_complete):
status = False
if pr and pr.has_expired():
self.send_screen.payment_request = None
status, msg = False, _("Invoice has expired")
Clock.schedule_once(lambda dt: on_complete(status, msg))
return
try:
self.network.run_from_another_thread(self.network.broadcast_transaction(tx))
except TxBroadcastError as e:
msg = e.get_message_for_gui()
except BestEffortRequestFailed as e:
msg = repr(e)
else:
if pr:
self.send_screen.payment_request = None
refund_address = self.wallet.get_receiving_address()
coro = pr.send_payment_and_receive_paymentack(tx.serialize(), refund_address)
fut = asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
ack_status, ack_msg = fut.result(timeout=20)
self.logger.info(f"Payment ACK: {ack_status}. Ack message: {ack_msg}")
status, msg = True, tx.txid()
Clock.schedule_once(lambda dt: on_complete(status, msg))

def broadcast(self, tx):
def broadcast(self, tx, pr=None):
def on_complete(ok, msg):
if ok:
self.show_info(_('Payment sent.'))
Expand All @@ -1124,7 +1136,7 @@ def on_complete(ok, msg):

if self.network and self.network.is_connected():
self.show_info(_('Sending'))
threading.Thread(target=self._broadcast_thread, args=(tx, on_complete)).start()
threading.Thread(target=self._broadcast_thread, args=(tx, pr, on_complete)).start()
else:
self.show_info(_('Cannot broadcast transaction') + ':\n' + _('Not connected'))

Expand Down
5 changes: 3 additions & 2 deletions electrum/gui/kivy/uix/dialogs/tx_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,12 @@ class ActionButtonOption(NamedTuple):

class TxDialog(Factory.Popup):

def __init__(self, app, tx):
def __init__(self, app, tx, pr=None):
Factory.Popup.__init__(self)
self.app = app # type: ElectrumWindow
self.wallet = self.app.wallet
self.tx = tx # type: Transaction
self.pr = pr
self._action_button_fn = lambda btn: None

# If the wallet can populate the inputs with more info, do it now.
Expand Down Expand Up @@ -339,7 +340,7 @@ def __do_sign(self, password):
self.update()

def do_broadcast(self):
self.app.broadcast(self.tx)
self.app.broadcast(self.tx, self.pr)

def show_qr(self):
original_raw_tx = str(self.tx)
Expand Down
7 changes: 4 additions & 3 deletions electrum/gui/kivy/uix/screens.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,19 +383,20 @@ def _do_pay_onchain(self, invoice: OnchainInvoice) -> None:
def send_tx(self, tx, invoice, password):
if self.app.wallet.has_password() and password is None:
return
pr = self.payment_request
self.save_invoice(invoice)
def on_success(tx):
if tx.is_complete():
self.app.broadcast(tx)
self.app.broadcast(tx, pr)
else:
self.app.tx_dialog(tx)
self.app.tx_dialog(tx, pr)
def on_failure(error):
self.app.show_error(error)
if self.app.wallet.can_sign(tx):
self.app.show_info("Signing...")
self.app.sign_tx(tx, password, on_success, on_failure)
else:
self.app.tx_dialog(tx)
self.app.tx_dialog(tx, pr)


class ReceiveScreen(CScreen):
Expand Down
12 changes: 7 additions & 5 deletions electrum/gui/qt/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -1688,10 +1688,11 @@ def pay_onchain_dialog(
if cancelled:
return
if is_send:
pr = self.payment_request
self.save_pending_invoice()
def sign_done(success):
if success:
self.broadcast_or_show(tx)
self.broadcast_or_show(tx, pr)
self.sign_tx_with_password(tx, callback=sign_done, password=password,
external_keypairs=external_keypairs)
else:
Expand All @@ -1703,15 +1704,16 @@ def preview_tx_dialog(self, *, make_tx, external_keypairs=None):
window=self)
d.show()

def broadcast_or_show(self, tx: Transaction):
def broadcast_or_show(self, tx: Transaction,
pr: Optional[paymentrequest.PaymentRequest]):
if not tx.is_complete():
self.show_transaction(tx)
return
if not self.network:
self.show_error(_("You can't broadcast a transaction without a live network connection."))
self.show_transaction(tx)
return
self.broadcast_transaction(tx)
self.broadcast_transaction(tx, pr)

@protected
def sign_tx(self, tx, *, callback, external_keypairs, password):
Expand All @@ -1735,11 +1737,11 @@ def on_failure(exc_info):
msg = _('Signing transaction...')
WaitingDialog(self, msg, task, on_success, on_failure)

def broadcast_transaction(self, tx: Transaction):
def broadcast_transaction(self, tx: Transaction,
pr: Optional[paymentrequest.PaymentRequest]):

def broadcast_thread():
# non-GUI thread
pr = self.payment_request
if pr and pr.has_expired():
self.payment_request = None
return False, _("Invoice has expired")
Expand Down
3 changes: 2 additions & 1 deletion electrum/gui/qt/transaction_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,11 @@ def set_tx(self, tx: 'Transaction'):
)

def do_broadcast(self):
pr = self.main_window.payment_request
self.main_window.push_top_level_window(self)
self.main_window.save_pending_invoice()
try:
self.main_window.broadcast_transaction(self.tx)
self.main_window.broadcast_transaction(self.tx, pr)
finally:
self.main_window.pop_top_level_window(self)
self.saved = True
Expand Down