ln: store network addresses for channel counterparties in channels

So we can reconnect to them without relying on gossip db.
This commit is contained in:
SomberNight 2020-03-06 03:37:00 +01:00
parent 942e03e3ae
commit fa0ef9c548
No known key found for this signature in database
GPG key ID: B33B5F232C6271E9
3 changed files with 38 additions and 15 deletions

View file

@ -27,10 +27,12 @@ from collections import namedtuple, defaultdict
import binascii import binascii
import json import json
from enum import IntEnum 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 time
import threading import threading
from aiorpcx import NetAddress
from . import ecc from . import ecc
from . import constants from . import constants
from .util import bfh, bh2u from .util import bfh, bh2u
@ -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, HTLC_TIMEOUT_WEIGHT, HTLC_SUCCESS_WEIGHT, extract_ctn_from_tx_and_chan, UpdateAddHtlc,
funding_output_script, SENT, RECEIVED, LOCAL, REMOTE, HTLCOwner, make_commitment_outputs, funding_output_script, SENT, RECEIVED, LOCAL, REMOTE, HTLCOwner, make_commitment_outputs,
ScriptHtlc, PaymentFailure, calc_onchain_fees, RemoteMisbehaving, make_htlc_output_witness_script, 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_sweeptxs_for_our_ctx, create_sweeptxs_for_their_ctx
from .lnsweep import create_sweeptx_for_their_revoked_htlc, SweepInfo from .lnsweep import create_sweeptx_for_their_revoked_htlc, SweepInfo
from .lnhtlc import HTLCManager from .lnhtlc import HTLCManager
@ -183,6 +185,20 @@ class Channel(Logger):
def get_remote_update(self) -> Optional[bytes]: def get_remote_update(self) -> Optional[bytes]:
return bfh(self.storage.get('remote_update')) if self.storage.get('remote_update') else None 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: def get_outgoing_gossip_channel_update(self) -> bytes:
if self._outgoing_channel_update is not None: if self._outgoing_channel_update is not None:
return self._outgoing_channel_update return self._outgoing_channel_update

View file

@ -202,6 +202,8 @@ class Peer(Logger):
raise GracefulDisconnect(f"{str(e)}") raise GracefulDisconnect(f"{str(e)}")
if isinstance(self.transport, LNTransport): if isinstance(self.transport, LNTransport):
self.channel_db.add_recent_peer(self.transport.peer_addr) 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._received_init = True
self.maybe_set_initialized() self.maybe_set_initialized()
@ -597,6 +599,8 @@ class Peer(Logger):
lnworker=self.lnworker, lnworker=self.lnworker,
initial_feerate=feerate) initial_feerate=feerate)
chan.storage['funding_inputs'] = [txin.prevout.to_json() for txin in funding_tx.inputs()] 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() sig_64, _ = chan.sign_next_commitment()
self.temp_id_to_id[temp_channel_id] = channel_id self.temp_id_to_id[temp_channel_id] = channel_id
self.send_message("funding_created", self.send_message("funding_created",
@ -695,6 +699,8 @@ class Peer(Logger):
lnworker=self.lnworker, lnworker=self.lnworker,
initial_feerate=feerate) initial_feerate=feerate)
chan.storage['init_timestamp'] = int(time.time()) 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'] remote_sig = funding_created['signature']
chan.receive_new_commitment(remote_sig, []) chan.receive_new_commitment(remote_sig, [])
sig_64, _ = chan.sign_next_commitment() sig_64, _ = chan.sign_next_commitment()

View file

@ -1313,24 +1313,25 @@ class LNWallet(LNWorker):
@ignore_exceptions @ignore_exceptions
@log_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() now = time.time()
# try last good address first peer_addresses = []
peer = self.channel_db.get_last_good_address(chan.node_id) # will try last good address first, from gossip
if peer: 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) last_tried = self._last_tried_peer.get(peer, 0)
if last_tried + PEER_RETRY_INTERVAL_FOR_CHANNELS < now: if last_tried + PEER_RETRY_INTERVAL_FOR_CHANNELS < now:
await self._add_peer(peer.host, peer.port, peer.pubkey) await self._add_peer(peer.host, peer.port, peer.pubkey)
return 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): async def reestablish_peers_and_channels(self):
while True: while True: