URI: 
       tln: store network addresses for channel counterparties in channels - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit fa0ef9c5481861484b504dab5c7eb703c5edb49f
   DIR parent 942e03e3ae59d6bd8900d6c63a2c52b19fc5bf04
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Fri,  6 Mar 2020 03:37:00 +0100
       
       ln: store network addresses for channel counterparties in channels
       
       So we can reconnect to them without relying on gossip db.
       
       Diffstat:
         M electrum/lnchannel.py               |      20 ++++++++++++++++++--
         M electrum/lnpeer.py                  |       6 ++++++
         M electrum/lnworker.py                |      27 ++++++++++++++-------------
       
       3 files changed, 38 insertions(+), 15 deletions(-)
       ---
   DIR diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py
       t@@ -27,10 +27,12 @@ from collections import namedtuple, defaultdict
        import binascii
        import json
        from enum import IntEnum
       -from typing import Optional, Dict, List, Tuple, NamedTuple, Set, Callable, Iterable, Sequence, TYPE_CHECKING
       +from typing import Optional, Dict, List, Tuple, NamedTuple, Set, Callable, Iterable, Sequence, TYPE_CHECKING, Iterator
        import time
        import threading
        
       +from aiorpcx import NetAddress
       +
        from . import ecc
        from . import constants
        from .util import bfh, bh2u
       t@@ -47,7 +49,7 @@ from .lnutil import (Outpoint, LocalConfig, RemoteConfig, Keypair, OnlyPubkeyKey
                            HTLC_TIMEOUT_WEIGHT, HTLC_SUCCESS_WEIGHT, extract_ctn_from_tx_and_chan, UpdateAddHtlc,
                            funding_output_script, SENT, RECEIVED, LOCAL, REMOTE, HTLCOwner, make_commitment_outputs,
                            ScriptHtlc, PaymentFailure, calc_onchain_fees, RemoteMisbehaving, make_htlc_output_witness_script,
       -                    ShortChannelID, map_htlcs_to_ctx_output_idxs)
       +                    ShortChannelID, map_htlcs_to_ctx_output_idxs, LNPeerAddr)
        from .lnsweep import create_sweeptxs_for_our_ctx, create_sweeptxs_for_their_ctx
        from .lnsweep import create_sweeptx_for_their_revoked_htlc, SweepInfo
        from .lnhtlc import HTLCManager
       t@@ -183,6 +185,20 @@ class Channel(Logger):
            def get_remote_update(self) -> Optional[bytes]:
                return bfh(self.storage.get('remote_update')) if self.storage.get('remote_update') else None
        
       +    def add_or_update_peer_addr(self, peer: LNPeerAddr) -> None:
       +        if 'peer_network_addresses' not in self.storage:
       +            self.storage['peer_network_addresses'] = {}
       +        now = int(time.time())
       +        self.storage['peer_network_addresses'][peer.net_addr_str()] = now
       +
       +    def get_peer_addresses(self) -> Iterator[LNPeerAddr]:
       +        # sort by timestamp: most recent first
       +        addrs = sorted(self.storage.get('peer_network_addresses', {}).items(),
       +                       key=lambda x: x[1], reverse=True)
       +        for net_addr_str, ts in addrs:
       +            net_addr = NetAddress.from_string(net_addr_str)
       +            yield LNPeerAddr(host=str(net_addr.host), port=net_addr.port, pubkey=self.node_id)
       +
            def get_outgoing_gossip_channel_update(self) -> bytes:
                if self._outgoing_channel_update is not None:
                    return self._outgoing_channel_update
   DIR diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
       t@@ -202,6 +202,8 @@ class Peer(Logger):
                    raise GracefulDisconnect(f"{str(e)}")
                if isinstance(self.transport, LNTransport):
                    self.channel_db.add_recent_peer(self.transport.peer_addr)
       +            for chan in self.channels.values():
       +                chan.add_or_update_peer_addr(self.transport.peer_addr)
                self._received_init = True
                self.maybe_set_initialized()
        
       t@@ -597,6 +599,8 @@ class Peer(Logger):
                               lnworker=self.lnworker,
                               initial_feerate=feerate)
                chan.storage['funding_inputs'] = [txin.prevout.to_json() for txin in funding_tx.inputs()]
       +        if isinstance(self.transport, LNTransport):
       +            chan.add_or_update_peer_addr(self.transport.peer_addr)
                sig_64, _ = chan.sign_next_commitment()
                self.temp_id_to_id[temp_channel_id] = channel_id
                self.send_message("funding_created",
       t@@ -695,6 +699,8 @@ class Peer(Logger):
                               lnworker=self.lnworker,
                               initial_feerate=feerate)
                chan.storage['init_timestamp'] = int(time.time())
       +        if isinstance(self.transport, LNTransport):
       +            chan.add_or_update_peer_addr(self.transport.peer_addr)
                remote_sig = funding_created['signature']
                chan.receive_new_commitment(remote_sig, [])
                sig_64, _ = chan.sign_next_commitment()
   DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py
       t@@ -1313,24 +1313,25 @@ class LNWallet(LNWorker):
        
            @ignore_exceptions
            @log_exceptions
       -    async def reestablish_peer_for_given_channel(self, chan):
       +    async def reestablish_peer_for_given_channel(self, chan: Channel) -> None:
                now = time.time()
       -        # try last good address first
       -        peer = self.channel_db.get_last_good_address(chan.node_id)
       -        if peer:
       +        peer_addresses = []
       +        # will try last good address first, from gossip
       +        last_good_addr = self.channel_db.get_last_good_address(chan.node_id)
       +        if last_good_addr:
       +            peer_addresses.append(last_good_addr)
       +        # will try addresses for node_id from gossip
       +        addrs_from_gossip = self.channel_db.get_node_addresses(chan.node_id) or []
       +        for host, port, ts in addrs_from_gossip:
       +            peer_addresses.append(LNPeerAddr(host, port, chan.node_id))
       +        # will try addresses stored in channel storage
       +        peer_addresses += list(chan.get_peer_addresses())
       +        # now select first one that has not failed recently
       +        for peer in peer_addresses:
                    last_tried = self._last_tried_peer.get(peer, 0)
                    if last_tried + PEER_RETRY_INTERVAL_FOR_CHANNELS < now:
                        await self._add_peer(peer.host, peer.port, peer.pubkey)
                        return
       -        # try random address for node_id
       -        addresses = self.channel_db.get_node_addresses(chan.node_id)
       -        if not addresses:
       -            return
       -        host, port, t = random.choice(list(addresses))
       -        peer = LNPeerAddr(host, port, chan.node_id)
       -        last_tried = self._last_tried_peer.get(peer, 0)
       -        if last_tried + PEER_RETRY_INTERVAL_FOR_CHANNELS < now:
       -            await self._add_peer(host, port, chan.node_id)
        
            async def reestablish_peers_and_channels(self):
                while True: