URI: 
       tln: announcement reliability fixes for qt, remove asserts forbidding unbalanced channels - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 6f88c55f170774e24623e39c32120cb296602ad6
   DIR parent e9fec66eb4d4c8292f86b8869ee794a5d0cfdf1a
  HTML Author: Janus <ysangkok@gmail.com>
       Date:   Tue, 19 Jun 2018 13:02:59 +0200
       
       ln: announcement reliability fixes for qt, remove asserts forbidding unbalanced channels
       
       Diffstat:
         M lib/lnbase.py                       |      35 ++++++++++++++++++++++---------
         M lib/lnhtlc.py                       |      12 ++++--------
         M lib/lnworker.py                     |      33 +++++++++++++++----------------
       
       3 files changed, 45 insertions(+), 35 deletions(-)
       ---
   DIR diff --git a/lib/lnbase.py b/lib/lnbase.py
       t@@ -279,7 +279,7 @@ ChannelConfig = namedtuple("ChannelConfig", [
            "to_self_delay", "dust_limit_sat", "max_htlc_value_in_flight_msat", "max_accepted_htlcs"])
        OnlyPubkeyKeypair = namedtuple("OnlyPubkeyKeypair", ["pubkey"])
        RemoteState = namedtuple("RemoteState", ["ctn", "next_per_commitment_point", "amount_msat", "revocation_store", "last_per_commitment_point", "next_htlc_id"])
       -LocalState = namedtuple("LocalState", ["ctn", "per_commitment_secret_seed", "amount_msat", "next_htlc_id", "funding_locked_received"])
       +LocalState = namedtuple("LocalState", ["ctn", "per_commitment_secret_seed", "amount_msat", "next_htlc_id", "funding_locked_received", "was_announced"])
        ChannelConstraints = namedtuple("ChannelConstraints", ["feerate", "capacity", "is_initiator", "funding_txn_minimum_depth"])
        OpenChannel = namedtuple("OpenChannel", ["channel_id", "short_channel_id", "funding_outpoint", "local_config", "remote_config", "remote_state", "local_state", "constraints", "node_id"])
        
       t@@ -600,7 +600,6 @@ class Peer(PrintError):
                self.commitment_signed = defaultdict(asyncio.Queue)
                self.announcement_signatures = defaultdict(asyncio.Queue)
                self.update_fail_htlc = defaultdict(asyncio.Queue)
       -        self.is_funding_six_deep = defaultdict(lambda: False)
                self.localfeatures = (0x08 if request_initial_sync else 0)
                self.nodes = {}
                self.channels = lnworker.channels
       t@@ -771,7 +770,11 @@ class Peer(PrintError):
        
            def on_announcement_signatures(self, payload):
                channel_id = payload['channel_id']
       -        self.announcement_signatures[channel_id].put_nowait(payload)
       +        chan = self.channels[payload['channel_id']]
       +        if chan.local_state.was_announced:
       +            h, local_node_sig, local_bitcoin_sig = self.send_announcement_signatures(chan)
       +        else:
       +            self.announcement_signatures[channel_id].put_nowait(payload)
        
            @aiosafe
            async def main_loop(self):
       t@@ -794,6 +797,7 @@ class Peer(PrintError):
                self.print_error('closing lnbase')
                self.writer.close()
        
       +    @aiosafe
            async def channel_establishment_flow(self, wallet, config, password, funding_sat, push_msat, temp_channel_id):
                await self.initialized
                # see lnd/keychain/derivation.go
       t@@ -900,7 +904,8 @@ class Peer(PrintError):
                            per_commitment_secret_seed=per_commitment_secret_seed,
                            amount_msat=local_amount,
                            next_htlc_id = 0,
       -                    funding_locked_received = False
       +                    funding_locked_received = False,
       +                    was_announced = False
                        ),
                        constraints=ChannelConstraints(capacity=funding_sat, feerate=local_feerate, is_initiator=True, funding_txn_minimum_depth=funding_txn_minimum_depth)
                )
       t@@ -976,10 +981,20 @@ class Peer(PrintError):
                if chan.short_channel_id:
                    self.mark_open(chan)
        
       -    async def funding_six_deep(self, chan):
       -        if self.is_funding_six_deep[chan.channel_id]:
       -            return
       -        self.is_funding_six_deep[chan.channel_id] = True
       +    def on_network_update(self, chan, funding_tx_depth):
       +        """
       +        Only called when the channel is OPEN.
       +
       +        Runs on the Network thread.
       +        """
       +        if not chan.local_state.was_announced and funding_tx_depth >= 6:
       +            chan = chan._replace(local_state=chan.local_state._replace(was_announced=True))
       +            coro = self.handle_announcements(chan)
       +            self.lnworker.save_channel(chan)
       +            asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
       +
       +    @aiosafe
       +    async def handle_announcements(self, chan):
                h, local_node_sig, local_bitcoin_sig = self.send_announcement_signatures(chan)
                announcement_signatures_msg = await self.announcement_signatures[chan.channel_id].get()
                remote_node_sig = announcement_signatures_msg["node_signature"]
       t@@ -1006,7 +1021,7 @@ class Peer(PrintError):
                    bitcoin_signature_1=bitcoin_sigs[0],
                    bitcoin_signature_2=bitcoin_sigs[1],
                    len=0,
       -            #features
       +            #features not set (defaults to zeros)
                    chain_hash=bytes.fromhex(rev_hex(constants.net.GENESIS)),
                    short_channel_id=chan.short_channel_id,
                    node_id_1=node_ids[0],
       t@@ -1048,7 +1063,7 @@ class Peer(PrintError):
        
                chan_ann = gen_msg("channel_announcement",
                    len=0,
       -            #features
       +            #features not set (defaults to zeros)
                    chain_hash=bytes.fromhex(rev_hex(constants.net.GENESIS)),
                    short_channel_id=chan.short_channel_id,
                    node_id_1=node_ids[0],
   DIR diff --git a/lib/lnhtlc.py b/lib/lnhtlc.py
       t@@ -146,8 +146,6 @@ class HTLCStateMachine(PrintError):
                    if htlc.r_locked_in is None: htlc.r_locked_in = self.state.remote_state.ctn
                assert len(htlc_sigs) == 0 or type(htlc_sigs[0]) is bytes
        
       -        assert len(htlc_sigs) == len(self.local_commitment.outputs()) - 2, (len(htlc_sigs), len(self.local_commitment.outputs()) - 2, self.diagnostic_name())
       -
                preimage_hex = self.local_commitment.serialize_preimage(0)
                pre_hash = Hash(bfh(preimage_hex))
                if not ecc.verify_signature(self.state.remote_config.multisig_key.pubkey, sig, pre_hash):
       t@@ -298,8 +296,8 @@ class HTLCStateMachine(PrintError):
                  htlc_value_local
                remote_msat = self.state.remote_state.amount_msat -\
                  htlc_value_remote
       -        assert local_msat > 0
       -        assert remote_msat > 0
       +        assert local_msat >= 0
       +        assert remote_msat >= 0
        
                this_point = self.state.remote_state.next_per_commitment_point
        
       t@@ -320,7 +318,6 @@ class HTLCStateMachine(PrintError):
                commit = make_commitment_using_open_channel(self.state, self.state.remote_state.ctn + 1,
                    False, this_point,
                    remote_msat - total_fee_remote, local_msat - total_fee_local, htlcs_in_local + htlcs_in_remote)
       -        assert len(commit.outputs()) == 2 + len(htlcs_in_local) + len(htlcs_in_remote)
                return commit
        
            @property
       t@@ -332,8 +329,8 @@ class HTLCStateMachine(PrintError):
                  htlc_value_local
                remote_msat = self.state.remote_state.amount_msat -\
                  htlc_value_remote
       -        assert local_msat > 0
       -        assert remote_msat > 0
       +        assert local_msat >= 0
       +        assert remote_msat >= 0
        
                _, this_point, _ = self.points
        
       t@@ -354,7 +351,6 @@ class HTLCStateMachine(PrintError):
                commit = make_commitment_using_open_channel(self.state, self.state.local_state.ctn + 1,
                    True, this_point,
                    local_msat - total_fee_local, remote_msat - total_fee_remote, htlcs_in_local + htlcs_in_remote)
       -        assert len(commit.outputs()) == 2 + len(htlcs_in_local) + len(htlcs_in_remote)
                return commit
        
            def gen_htlc_indices(self, subject):
   DIR diff --git a/lib/lnworker.py b/lib/lnworker.py
       t@@ -144,30 +144,29 @@ class LNWorker(PrintError):
                        return None
                    chan = chan._replace(short_channel_id = calc_short_channel_id(block_height, tx_pos, chan.funding_outpoint.output_index))
                    self.save_channel(chan)
       -            return chan, conf
       -        return None, None
       +            return chan
       +        return None
        
            def on_network_update(self, event, *args):
                for chan in self.channels.values():
       -            if self.channel_state[chan.channel_id] == "OPEN":
       -                conf = self.wallet.get_tx_height(chan.funding_outpoint.txid)[1]
       -                if conf >= 6:
       -                    peer = self.peers[chan.node_id]
       -                    coro = peer.funding_six_deep(chan)
       -                    fut = asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop)
       -                    fut.result()
       -            if self.channel_state[chan.channel_id] != "OPENING":
       -                continue
       -            chan, conf = self.save_short_chan_id(chan)
       -            if not chan:
       -                self.print_error("network update but funding tx is still not at sufficient depth")
       -                continue
                    peer = self.peers[chan.node_id]
       -            peer.funding_locked(chan)
       +            if self.channel_state[chan.channel_id] == "OPENING":
       +                chan = self.save_short_chan_id(chan)
       +                if not chan:
       +                    self.print_error("network update but funding tx is still not at sufficient depth")
       +                    continue
       +                # this results in the channel being marked OPEN
       +                peer.funding_locked(chan)
       +            elif self.channel_state[chan.channel_id] == "OPEN":
       +                conf = self.wallet.get_tx_height(chan.funding_outpoint.txid)[1]
       +                peer.on_network_update(chan, conf)
        
            # not aiosafe because we call .result() which will propagate an exception
            async def _open_channel_coroutine(self, node_id, amount_sat, push_sat, password):
       -        peer = self.peers[bfh(node_id)]
       +        if node_id == "":
       +            peer = next(iter(self.peers.values()))
       +        else:
       +            peer = self.peers[bfh(node_id)]
                openingchannel = await peer.channel_establishment_flow(self.wallet, self.config, password, amount_sat, push_sat * 1000, temp_channel_id=os.urandom(32))
                self.print_error("SAVING OPENING CHANNEL")
                self.save_channel(openingchannel)