URI: 
       tKivy: open channel dialog - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 7db9a22d6354c72e0ca0f267866030cd6d35aca5
   DIR parent 3430d1aaa3238e51ea514a4f0c11b9f61b5b2e52
  HTML Author: Janus <ysangkok@gmail.com>
       Date:   Mon, 12 Nov 2018 18:01:59 +0100
       
       Kivy: open channel dialog
       
       Diffstat:
         M .gitignore                          |       1 +
         M electrum/gui/kivy/Makefile          |       1 +
         M electrum/gui/kivy/main.kv           |       5 +----
         M electrum/gui/kivy/main_window.py    |      12 ++++++++----
         D electrum/gui/kivy/theming/light/ne… |       0 
         A electrum/gui/kivy/theming/light/ne… |       6 ++++++
         M electrum/gui/kivy/uix/dialogs/ligh… |      54 +++++++++++++++++++++----------
         A electrum/gui/kivy/uix/dialogs/ligh… |     141 +++++++++++++++++++++++++++++++
         D electrum/gui/kivy/uix/dialogs/ligh… |      93 -------------------------------
         M electrum/gui/kivy/uix/screens.py    |       8 +++++---
         M electrum/lnworker.py                |       3 +++
       
       11 files changed, 203 insertions(+), 121 deletions(-)
       ---
   DIR diff --git a/.gitignore b/.gitignore
       t@@ -18,6 +18,7 @@ bin/
        # icons
        electrum/gui/kivy/theming/light-0.png
        electrum/gui/kivy/theming/light.atlas
       +electrum/gui/kivy/theming/light/network.png
        
        # tests/tox
        .tox/
   DIR diff --git a/electrum/gui/kivy/Makefile b/electrum/gui/kivy/Makefile
       t@@ -5,6 +5,7 @@ PYTHON = python3
        .PHONY: theming apk clean
        
        theming:
       +        bash -c "convert -background none theming/light/network.{svg,png}"
                $(PYTHON) -m kivy.atlas theming/light 1024 theming/light/*.png
        prepare:
                # running pre build setup
   DIR diff --git a/electrum/gui/kivy/main.kv b/electrum/gui/kivy/main.kv
       t@@ -450,11 +450,8 @@ BoxLayout:
                            name: 'network'
                            text: _('Network')
                        ActionOvrButton:
       -                    name: 'lightning_payer_dialog'
       -                    text: _('Pay Lightning Invoice')
       -                ActionOvrButton:
                            name: 'lightning_channels_dialog'
       -                    text: _('Lightning Channels')
       +                    text: _('Channels')
                        ActionOvrButton:
                            name: 'settings'
                            text: _('Settings')
   DIR diff --git a/electrum/gui/kivy/main_window.py b/electrum/gui/kivy/main_window.py
       t@@ -75,7 +75,7 @@ from electrum.util import (base_units, NoDynamicFeeEstimates, decimal_point_to_b
                                   base_unit_name_to_decimal_point, NotEnoughFunds, UnknownBaseUnit,
                                   DECIMAL_POINT_DEFAULT)
        
       -from .uix.dialogs.lightning_payer import LightningPayerDialog
       +from .uix.dialogs.lightning_open_channel import LightningOpenChannelDialog
        from .uix.dialogs.lightning_channels import LightningChannelsDialog
        
        class ElectrumWindow(App):
       t@@ -645,8 +645,8 @@ class ElectrumWindow(App):
                self._settings_dialog.update()
                self._settings_dialog.open()
        
       -    def lightning_payer_dialog(self):
       -        d = LightningPayerDialog(self)
       +    def lightning_open_channel_dialog(self):
       +        d = LightningOpenChannelDialog(self)
                d.open()
        
            def lightning_channels_dialog(self):
       t@@ -803,7 +803,11 @@ class ElectrumWindow(App):
                inputs = self.wallet.get_spendable_coins(None, self.electrum_config)
                if not inputs:
                    return ''
       -        addr = str(self.send_screen.screen.address) or self.wallet.dummy_address()
       +        addr = None
       +        if self.send_screen:
       +            addr = str(self.send_screen.screen.address)
       +        if not addr:
       +            addr = self.wallet.dummy_address()
                outputs = [TxOutput(TYPE_ADDRESS, addr, '!')]
                try:
                    tx = self.wallet.make_unsigned_transaction(inputs, outputs, self.electrum_config)
   DIR diff --git a/electrum/gui/kivy/theming/light/network.png b/electrum/gui/kivy/theming/light/network.png
       Binary files differ.
   DIR diff --git a/electrum/gui/kivy/theming/light/network.svg b/electrum/gui/kivy/theming/light/network.svg
       t@@ -0,0 +1,6 @@
       +<?xml version="1.0" encoding="UTF-8"?>
       +<svg width="512" height="512" version="1.1" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
       + <use transform="translate(-216 -252)" width="100%" height="100%" xlink:href="#path831"/>
       + <path id="path831" d="m244.94 256.71c-14.934 1.4562-25.469 19.091-24.913 37.987-2.155 55.246-0.0543 91.614 0.17146 143.49 0.95499 15.061 13.656 34.066 35.042 34.181 6.5619 0.30953 16.143 0.34717 30.995 0.34717 27.995 0 41.291 0.77865 41.291 2.4214 0 1.3327-2.9613 5.3827-6.5786 9-5.0074 5.0074-8.6562 6.5787-15.298 6.5787-10.341 0-14.124 3.1317-14.124 11.698v6.3018h144v-6.3018c0-8.5666-3.7834-11.698-14.124-11.698-6.6413 0-10.29-1.5713-15.297-6.5787-3.6174-3.6173-6.5786-7.6673-6.5786-9 0-1.6428 13.297-2.4214 41.291-2.4214 15.112-7e-3 63.701 6.378 66.081-35.293 0.62209-11.405 0.62843-32.056 0.62843-72.708 0-39.56-7e-3 -60.178-0.58008-71.767-0.6711-12.6-1.8798-36.301-24.834-36.233h-118.59zm10.586 36h216v144h-216v-72z" fill="#fff"/>
       + <path d="m110.41 469.11c-4.9443-1.8094-13.262-7.4832-18.485-12.608-15.863-15.568-16.401-19.038-16.401-105.69v-76.1h36v150.96l5.5228 5.5227c5.4382 5.4383 6.1188 5.5228 44.468 5.5228h38.945c3.4461 14.807 6.6856 24.504 14.871 36-30.131-0.82757-61.12 0.99452-90.818-1.2282-6.8699-0.53546-11.167-1.3039-14.104-2.3788z" fill="#fff"/>
       +</svg>
   DIR diff --git a/electrum/gui/kivy/uix/dialogs/lightning_channels.py b/electrum/gui/kivy/uix/dialogs/lightning_channels.py
       t@@ -7,22 +7,35 @@ from kivy.clock import Clock
        from electrum.gui.kivy.uix.context_menu import ContextMenu
        from electrum.util import bh2u
        from electrum.lnutil import LOCAL, REMOTE
       +from electrum.gui.kivy.i18n import _
        
       -Builder.load_string('''
       +Builder.load_string(r'''
        <LightningChannelItem@CardItem>
            details: {}
            active: False
            channelId: '<channelId not set>'
       +    id: card
       +    _chan: None
            Label:
       +        color: (.5,.5,.5,1) if not card.active else (1,1,1,1)
                text: root.channelId
       +    Label:
       +        text: _('State:\n') + (card._chan.get_state() if card._chan else 'n/a')
       +        font_size: '10sp'
        
        <LightningChannelsDialog@Popup>:
            name: 'lightning_channels'
       -    title: 'Lightning channels. Tap to select.'
       +    title: _('Lightning channels. Tap for options.')
       +    id: popup
            BoxLayout:
                id: box
                orientation: 'vertical'
                spacing: '1dp'
       +        Button:
       +            size_hint: 1, None
       +            height: '48dp'
       +            text: _('New channel...')
       +            on_press: popup.app.popup_dialog('lightning_open_channel_dialog')
                ScrollView:
                    GridLayout:
                        cols: 1
       t@@ -95,7 +108,7 @@ class LightningChannelsDialog(Factory.Popup):
        
            def show_channel_details(self, obj):
                p = Factory.ChannelDetailsPopup()
       -        p.title = 'Lightning channels details for ' + self.presentable_chan_id(obj._chan)
       +        p.title = _('Details for channel ') + self.presentable_chan_id(obj._chan)
                p.data = [{'keyName': key, 'value': str(obj.details[key])} for key in obj.details.keys()]
                p.open()
        
       t@@ -104,25 +117,28 @@ class LightningChannelsDialog(Factory.Popup):
                coro = asyncio.run_coroutine_threadsafe(self.app.wallet.lnworker.close_channel(obj._chan.channel_id), loop)
                try:
                    coro.result(5)
       -            self.app.show_info('Channel closed')
       +            self.app.show_info(_('Channel closed'))
                except Exception as e:
       -            self.app.show_info('Could not close channel: ' + repr(e)) # repr because str(Exception()) == ''
       +            self.app.show_info(_('Could not close channel: ') + repr(e)) # repr because str(Exception()) == ''
        
            def force_close_channel(self, obj):
       +        if obj._chan.get_state() == 'CLOSED':
       +            self.app.show_error(_('Channel already closed'))
       +            return
                loop = self.app.wallet.network.asyncio_loop
                coro = asyncio.run_coroutine_threadsafe(self.app.wallet.lnworker.force_close_channel(obj._chan.channel_id), loop)
                try:
                    coro.result(1)
       -            self.app.show_info('Channel closed, you may need to wait at least ' + str(obj._chan.config[REMOTE].to_self_delay) + ' blocks, because of CSV delays')
       +            self.app.show_info(_('Channel closed, you may need to wait at least {} blocks, because of CSV delays'.format(obj._chan.config[REMOTE].to_self_delay)))
                except Exception as e:
       -            self.app.show_info('Could not force close channel: ' + repr(e)) # repr because str(Exception()) == ''
       +            self.app.show_info(_('Could not force close channel: ') + repr(e)) # repr because str(Exception()) == ''
        
            def show_menu(self, obj):
                self.hide_menu()
                self.context_menu = ContextMenu(obj, [
       -            ("Force close", self.force_close_channel),
       -            ("Co-op close", self.close_channel),
       -            ("Details", self.show_channel_details)])
       +            (_("Force close"), self.force_close_channel),
       +            (_("Co-op close"), self.close_channel),
       +            (_("Details"), self.show_channel_details)])
                self.ids.box.add_widget(self.context_menu)
        
            def hide_menu(self):
       t@@ -136,6 +152,8 @@ class LightningChannelsDialog(Factory.Popup):
            def channels_update(self, evt):
                channel_cards = self.ids.lightning_channels_container
                channel_cards.clear_widgets()
       +        if not self.app.wallet:
       +            return
                lnworker = self.app.wallet.lnworker
                for i in lnworker.channels.values():
                    item = Factory.LightningChannelItem()
       t@@ -147,10 +165,12 @@ class LightningChannelsDialog(Factory.Popup):
                    channel_cards.add_widget(item)
        
            def channel_details(self, chan):
       -        return {'Node ID': bh2u(chan.node_id),
       -                'Channel ID': bh2u(chan.channel_id),
       -                'Capacity': self.app.format_amount_and_units(chan.constraints.capacity),
       -                'Funding TXID': chan.funding_outpoint.txid,
       -                'Short Chan ID': bh2u(chan.short_channel_id) if chan.short_channel_id else 'Not available',
       -                'Available to spend': self.app.format_amount_and_units(chan.available_to_spend(LOCAL) // 1000),
       -                'State': chan.get_state()}
       +        return {_('Node ID'): bh2u(chan.node_id),
       +                _('Channel ID'): bh2u(chan.channel_id),
       +                _('Capacity'): self.app.format_amount_and_units(chan.constraints.capacity),
       +                _('Funding TXID'): chan.funding_outpoint.txid,
       +                _('Short Chan ID'): bh2u(chan.short_channel_id) if chan.short_channel_id else _('Not available'),
       +                _('Available to spend'): self.app.format_amount_and_units(chan.available_to_spend(LOCAL) // 1000),
       +                _('State'): chan.get_state(),
       +                _('Initiator'): 'Opened/funded by us' if chan.constraints.is_initiator else 'Opened/funded by remote party',
       +                _('Current feerate'): chan.constraints.feerate}
   DIR diff --git a/electrum/gui/kivy/uix/dialogs/lightning_open_channel.py b/electrum/gui/kivy/uix/dialogs/lightning_open_channel.py
       t@@ -0,0 +1,141 @@
       +from kivy.lang import Builder
       +from kivy.factory import Factory
       +from electrum.gui.kivy.i18n import _
       +from electrum.lnaddr import lndecode
       +from electrum.gui.kivy.uix.dialogs.choice_dialog import ChoiceDialog
       +from electrum.util import bh2u
       +from electrum.bitcoin import COIN
       +import electrum.simple_config as config
       +from .label_dialog import LabelDialog
       +
       +Builder.load_string('''
       +<LightningOpenChannelDialog@Popup>
       +    id: s
       +    name: 'lightning_open_channel'
       +    title: _('Open Lightning Channel')
       +    pubkey: ''
       +    amount: ''
       +    ipport: ''
       +    BoxLayout
       +        spacing: '12dp'
       +        padding: '12dp'
       +        orientation: 'vertical'
       +        SendReceiveBlueBottom:
       +            id: blue_bottom
       +            size_hint: 1, None
       +            height: self.minimum_height
       +            BoxLayout:
       +                size_hint: 1, None
       +                height: blue_bottom.item_height
       +                Image:
       +                    source: 'atlas://electrum/gui/kivy/theming/light/globe'
       +                    size_hint: None, None
       +                    size: '22dp', '22dp'
       +                    pos_hint: {'center_y': .5}
       +                BlueButton:
       +                    text: s.pubkey if s.pubkey else _('Node ID, [pubkey]@[host]:[port]')
       +                    shorten: True
       +                    on_release: s.choose_node()
       +                IconButton:
       +                    on_release: app.scan_qr(on_complete=s.on_pubkey)
       +                    icon: 'atlas://electrum/gui/kivy/theming/light/camera'
       +                    color: blue_bottom.foreground_color
       +                    size: '22dp', '22dp'
       +                    pos_hint: {'center_y': .5}
       +                    size_hint: None, None
       +            CardSeparator:
       +                color: blue_bottom.foreground_color
       +            BoxLayout:
       +                size_hint: 1, None
       +                height: blue_bottom.item_height
       +                Image:
       +                    source: 'atlas://electrum/gui/kivy/theming/light/network'
       +                    size_hint: None, None
       +                    size: '22dp', '22dp'
       +                    pos_hint: {'center_y': .5}
       +                BlueButton:
       +                    text: s.ipport if s.ipport else _('Auto-detect IP/port')
       +                    on_release: s.ipport_dialog()
       +            CardSeparator:
       +                color: blue_bottom.foreground_color
       +            BoxLayout:
       +                size_hint: 1, None
       +                height: blue_bottom.item_height
       +                Image:
       +                    source: 'atlas://electrum/gui/kivy/theming/light/calculator'
       +                    size_hint: None, None
       +                    size: '22dp', '22dp'
       +                    pos_hint: {'center_y': .5}
       +                BlueButton:
       +                    text: s.amount if s.amount else _('Channel capacity amount')
       +                    on_release: app.amount_dialog(s, True)
       +        Button:
       +            size_hint: 1, None
       +            height: blue_bottom.item_height
       +            text: _('Paste')
       +            on_release: s.do_paste()
       +        Button:
       +            size_hint: 1, None
       +            height: blue_bottom.item_height
       +            text: _('Open Channel')
       +            on_release: s.do_open_channel()
       +''')
       +
       +class LightningOpenChannelDialog(Factory.Popup):
       +    def ipport_dialog(self):
       +        def callback(text):
       +            self.ipport = text
       +        d = LabelDialog(_('IP/port in format:\n[host]:[port]'), self.ipport, callback)
       +        d.open()
       +
       +    def on_pubkey(self, data):
       +        self.pubkey = data.replace('\n', '') # strip newlines if we choose from ChoiseDialog
       +
       +    def choose_node(self):
       +        lines = []
       +        suggested = self.app.wallet.lnworker.suggest_peer()
       +        if suggested:
       +            assert len(suggested) == 33
       +            for i in range(0, 34, 11):
       +                lines += [bh2u(suggested[i:i+11])]
       +        servers = ['\n'.join(lines)]
       +        ChoiceDialog(_('Choose node to connect to'), sorted(servers), self.pubkey, self.on_pubkey).open()
       +
       +    def __init__(self, app, lnaddr=None, msg=None):
       +        super(LightningOpenChannelDialog, self).__init__()
       +        self.app = app
       +        self.lnaddr = lnaddr
       +        self.msg = msg
       +
       +    def open(self, *args, **kwargs):
       +        super(LightningOpenChannelDialog, self).open(*args, **kwargs)
       +        if self.lnaddr:
       +            fee = self.app.electrum_config.fee_per_kb()
       +            if not fee:
       +                fee = config.FEERATE_FALLBACK_STATIC_FEE
       +            self.amount = self.app.format_amount_and_units(self.lnaddr.amount * COIN + fee * 2)
       +            self.pubkey = bh2u(self.lnaddr.pubkey.serialize())
       +        if self.msg:
       +            self.app.show_info(self.msg)
       +
       +    def do_paste(self):
       +        contents = self.app._clipboard.paste()
       +        if not contents:
       +            self.app.show_info(_("Clipboard is empty"))
       +            return
       +        self.pubkey = contents
       +
       +    def do_open_channel(self):
       +        if not self.pubkey or not self.amount:
       +            self.app.show_info(_('All fields must be filled out'))
       +            return
       +        conn_str = self.pubkey
       +        if self.ipport:
       +            conn_str += '@' + self.ipport.strip()
       +        try:
       +            node_id_hex = self.app.wallet.lnworker.open_channel(conn_str, self.app.get_amount(self.amount), 0)
       +        except Exception as e:
       +            self.app.show_error(_('Problem opening channel: ') + '\n' + repr(e))
       +            return
       +        self.app.show_info(_('Please wait for confirmation, channel is opening with node ') + node_id_hex[:16])
       +        self.dismiss()
   DIR diff --git a/electrum/gui/kivy/uix/dialogs/lightning_payer.py b/electrum/gui/kivy/uix/dialogs/lightning_payer.py
       t@@ -1,93 +0,0 @@
       -import binascii
       -from kivy.lang import Builder
       -from kivy.factory import Factory
       -from electrum.gui.kivy.i18n import _
       -from kivy.clock import mainthread
       -from electrum.lnaddr import lndecode
       -
       -Builder.load_string('''
       -<LightningPayerDialog@Popup>
       -    id: s
       -    name: 'lightning_payer'
       -    invoice_data: ''
       -    BoxLayout:
       -        orientation: "vertical"
       -        BlueButton:
       -            text: s.invoice_data if s.invoice_data else _('Lightning invoice')
       -            shorten: True
       -            on_release: Clock.schedule_once(lambda dt: app.show_info(_('Copy and paste the lightning invoice using the Paste button, or use the camera to scan a QR code.')))
       -        GridLayout:
       -            cols: 4
       -            size_hint: 1, None
       -            height: '48dp'
       -            IconButton:
       -                id: qr
       -                on_release: Clock.schedule_once(lambda dt: app.scan_qr(on_complete=s.on_lightning_qr))
       -                icon: 'atlas://gui/kivy/theming/light/camera'
       -            Button:
       -                text: _('Paste')
       -                on_release: s.do_paste()
       -            Button:
       -                text: _('Paste using xclip')
       -                on_release: s.do_paste_xclip()
       -            Button:
       -                text: _('Clear')
       -                on_release: s.do_clear()
       -        Button:
       -            size_hint: 1, None
       -            height: '48dp'
       -            text: _('Open channel to pubkey in invoice')
       -            on_release: s.do_open_channel()
       -        Button:
       -            size_hint: 1, None
       -            height: '48dp'
       -            text: _('Pay pasted/scanned invoice')
       -            on_release: s.do_pay()
       -''')
       -
       -class LightningPayerDialog(Factory.Popup):
       -    def __init__(self, app):
       -        super(LightningPayerDialog, self).__init__()
       -        self.app = app
       -
       -    #def open(self, *args, **kwargs):
       -    #    super(LightningPayerDialog, self).open(*args, **kwargs)
       -    #def dismiss(self, *args, **kwargs):
       -    #    super(LightningPayerDialog, self).dismiss(*args, **kwargs)
       -
       -    def do_paste_xclip(self):
       -        import subprocess
       -        proc = subprocess.run(["xclip","-sel","clipboard","-o"], stdout=subprocess.PIPE)
       -        self.invoice_data = proc.stdout.decode("ascii")
       -
       -    def do_paste(self):
       -        contents = self.app._clipboard.paste()
       -        if not contents:
       -            self.app.show_info(_("Clipboard is empty"))
       -            return
       -        self.invoice_data = contents
       -
       -    def do_clear(self):
       -        self.invoice_data = ""
       -
       -    def do_open_channel(self):
       -        compressed_pubkey_bytes = lndecode(self.invoice_data).pubkey.serialize()
       -        hexpubkey = binascii.hexlify(compressed_pubkey_bytes).decode("ascii")
       -        local_amt = 200000
       -        push_amt = 100000
       -
       -        def on_success(pw):
       -            # node_id, local_amt, push_amt, emit_function, get_password
       -            self.app.wallet.lnworker.open_channel_from_other_thread(hexpubkey, local_amt, push_amt, mainthread(lambda parent: self.app.show_info(_("Channel open, waiting for locking..."))), lambda: pw)
       -
       -        if self.app.wallet.has_keystore_encryption():
       -            # wallet, msg, on_success (Tuple[str, str] -> ()), on_failure (() -> ())
       -            self.app.password_dialog(self.app.wallet, _("Password needed for opening channel"), on_success, lambda: self.app.show_error(_("Failed getting password from you")))
       -        else:
       -            on_success("")
       -
       -    def do_pay(self):
       -        self.app.wallet.lnworker.pay_invoice_from_other_thread(self.invoice_data)
       -
       -    def on_lightning_qr(self, data):
       -        self.invoice_data = str(data)
   DIR diff --git a/electrum/gui/kivy/uix/screens.py b/electrum/gui/kivy/uix/screens.py
       t@@ -32,7 +32,7 @@ from electrum.lnaddr import lndecode
        from electrum.lnutil import RECEIVED, SENT
        
        from .context_menu import ContextMenu
       -
       +from .dialogs.lightning_open_channel import LightningOpenChannelDialog
        
        from electrum.gui.kivy.i18n import _
        
       t@@ -280,11 +280,13 @@ class SendScreen(CScreen):
                    return
                invoice = self.screen.address
                amount_sat = self.app.get_amount(self.screen.amount)
       +        addr = self.app.wallet.lnworker._check_invoice(invoice, amount_sat)
                try:
       -            addr = self.app.wallet.lnworker._check_invoice(invoice, amount_sat)
                    route = self.app.wallet.lnworker._create_route_from_invoice(decoded_invoice=addr)
                except Exception as e:
       -            self.app.show_error(_('Could not find path for payment. Check if you have open channels. Error details:') + ':\n' + repr(e))
       +            dia = LightningOpenChannelDialog(self.app, addr, str(e) + _(':\nYou can open a channel.'))
       +            dia.open()
       +            return
                self.app.network.register_callback(self.payment_completed_async_thread, ['ln_payment_completed'])
                _addr, _peer, coro = self.app.wallet.lnworker._pay(invoice, amount_sat)
                fut = asyncio.run_coroutine_threadsafe(coro, self.app.network.asyncio_loop)
   DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py
       t@@ -240,6 +240,7 @@ class LNWorker(PrintError):
                if conf >= chan.constraints.funding_txn_minimum_depth > 0:
                    chan.short_channel_id = chan.short_channel_id_predicted
                    self.save_channel(chan)
       +            self.on_channels_updated()
                    return True, conf
                return False, conf
        
       t@@ -255,6 +256,7 @@ class LNWorker(PrintError):
                if is_spent:
                    if chan.get_state() != 'FORCE_CLOSING':
                        chan.set_state("CLOSED")
       +                self.on_channels_updated()
                    self.channel_db.remove_channel(chan.short_channel_id)
                self.network.trigger_callback('channel', chan)
        
       t@@ -543,6 +545,7 @@ class LNWorker(PrintError):
                tx = chan.force_close_tx()
                chan.set_state('FORCE_CLOSING')
                self.save_channel(chan)
       +        self.on_channels_updated()
                return await self.network.broadcast_transaction(tx)
        
            def _get_next_peers_to_try(self) -> Sequence[LNPeerAddr]: