Browse Source

ln: store network addresses for channel counterparties in channels

So we can reconnect to them without relying on gossip db.
hard-fail-on-bad-server-string
SomberNight 5 years ago
parent
commit
fa0ef9c548
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 20
      electrum/lnchannel.py
  2. 6
      electrum/lnpeer.py
  3. 27
      electrum/lnworker.py

20
electrum/lnchannel.py

@ -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

6
electrum/lnpeer.py

@ -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()

27
electrum/lnworker.py

@ -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:

Loading…
Cancel
Save