textend 'add_peer', 'list_peers' commands to gossip - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit ef5ad5f22f3d42d0dc7e1e81eaacaad84b3fcda2 DIR parent c454564ed6e094aa36be9fbe7aa9e9113a28710c HTML Author: ThomasV <thomasv@electrum.org> Date: Thu, 16 Apr 2020 12:39:12 +0200 extend 'add_peer', 'list_peers' commands to gossip Diffstat: M electrum/commands.py | 13 +++++++++---- M electrum/lnpeer.py | 9 +++++---- M electrum/lnworker.py | 49 +++++++++++++++---------------- 3 files changed, 37 insertions(+), 34 deletions(-) --- DIR diff --git a/electrum/commands.py b/electrum/commands.py t@@ -53,6 +53,7 @@ from .wallet import Abstract_Wallet, create_new_wallet, restore_wallet_from_text from .address_synchronizer import TX_HEIGHT_LOCAL from .mnemonic import Mnemonic from .lnutil import SENT, RECEIVED +from .lnutil import LnFeatures from .lnutil import ln_dummy_address from .lnpeer import channel_id_from_funding_tx from .plugin import run_hook t@@ -965,18 +966,21 @@ class Commands: # lightning network commands @command('wn') - async def add_peer(self, connection_string, timeout=20, wallet: Abstract_Wallet = None): - await wallet.lnworker.add_peer(connection_string) + async def add_peer(self, connection_string, timeout=20, gossip=False, wallet: Abstract_Wallet = None): + lnworker = self.network.lngossip if gossip else wallet.lnworker + await lnworker.add_peer(connection_string) return True @command('wn') - async def list_peers(self, wallet: Abstract_Wallet = None): + async def list_peers(self, gossip=False, wallet: Abstract_Wallet = None): + lnworker = self.network.lngossip if gossip else wallet.lnworker return [{ 'node_id':p.pubkey.hex(), 'address':p.transport.name(), 'initialized':p.is_initialized(), + 'features': str(LnFeatures(p.features)), 'channels': [c.funding_outpoint.to_str() for c in p.channels.values()], - } for p in wallet.lnworker.peers.values()] + } for p in lnworker.peers.values()] @command('wpn') async def open_channel(self, connection_string, amount, push_amount=0, password=None, wallet: Abstract_Wallet = None): t@@ -1165,6 +1169,7 @@ command_options = { 'from_height': (None, "Only show transactions that confirmed after given block height"), 'to_height': (None, "Only show transactions that confirmed before given block height"), 'iknowwhatimdoing': (None, "Acknowledge that I understand the full implications of what I am about to do"), + 'gossip': (None, "Apply command to gossip node instead of wallet"), } DIR diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py t@@ -74,6 +74,7 @@ class Peer(Logger): self.lnworker = lnworker self.privkey = self.transport.privkey # local privkey self.features = self.lnworker.features + self.their_features = 0 self.node_ids = [self.pubkey, privkey_to_pubkey(self.privkey)] self.network = lnworker.network self.channel_db = lnworker.network.channel_db t@@ -200,15 +201,15 @@ class Peer(Logger): if self._received_init: self.logger.info("ALREADY INITIALIZED BUT RECEIVED INIT") return - their_features = LnFeatures(int.from_bytes(payload['features'], byteorder="big")) + self.their_features = LnFeatures(int.from_bytes(payload['features'], byteorder="big")) their_globalfeatures = int.from_bytes(payload['globalfeatures'], byteorder="big") - their_features |= their_globalfeatures + self.their_features |= their_globalfeatures # check transitive dependencies for received features - if not their_features.validate_transitive_dependecies(): + if not self.their_features.validate_transitive_dependecies(): raise GracefulDisconnect("remote did not set all dependencies for the features they sent") # check if features are compatible, and set self.features to what we negotiated try: - self.features = ln_compare_features(self.features, their_features) + self.features = ln_compare_features(self.features, self.their_features) except IncompatibleLightningFeatures as e: self.initialized.set_exception(e) raise GracefulDisconnect(f"{str(e)}") DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py t@@ -392,6 +392,29 @@ class LNWorker(Logger, NetworkRetryManager[LNPeerAddr]): peer.close_and_cleanup() self._clear_addr_retry_times() + @log_exceptions + async def add_peer(self, connect_str: str) -> Peer: + node_id, rest = extract_nodeid(connect_str) + peer = self._peers.get(node_id) + if not peer: + if rest is not None: + host, port = split_host_port(rest) + else: + addrs = self.channel_db.get_node_addresses(node_id) + if not addrs: + raise ConnStringFormatError(_('Don\'t know any addresses for node:') + ' ' + bh2u(node_id)) + host, port, timestamp = self.choose_preferred_address(addrs) + port = int(port) + # Try DNS-resolving the host (if needed). This is simply so that + # the caller gets a nice exception if it cannot be resolved. + try: + await asyncio.get_event_loop().getaddrinfo(host, port) + except socket.gaierror: + raise ConnStringFormatError(_('Hostname does not resolve (getaddrinfo failed)')) + # add peer + peer = await self._add_peer(host, port, node_id) + return peer + class LNGossip(LNWorker): max_age = 14*24*3600 t@@ -716,9 +739,6 @@ class LNWallet(LNWorker): self.logger.info('REBROADCASTING CLOSING TX') await self.network.try_broadcasting(force_close_tx, 'force-close') - - - @log_exceptions async def _open_channel_coroutine(self, *, connect_str: str, funding_tx: PartialTransaction, funding_sat: int, push_sat: int, t@@ -750,29 +770,6 @@ class LNWallet(LNWorker): channels_db[chan.channel_id.hex()] = chan.storage self.wallet.save_backup() - @log_exceptions - async def add_peer(self, connect_str: str) -> Peer: - node_id, rest = extract_nodeid(connect_str) - peer = self._peers.get(node_id) - if not peer: - if rest is not None: - host, port = split_host_port(rest) - else: - addrs = self.channel_db.get_node_addresses(node_id) - if not addrs: - raise ConnStringFormatError(_('Don\'t know any addresses for node:') + ' ' + bh2u(node_id)) - host, port, timestamp = self.choose_preferred_address(addrs) - port = int(port) - # Try DNS-resolving the host (if needed). This is simply so that - # the caller gets a nice exception if it cannot be resolved. - try: - await asyncio.get_event_loop().getaddrinfo(host, port) - except socket.gaierror: - raise ConnStringFormatError(_('Hostname does not resolve (getaddrinfo failed)')) - # add peer - peer = await self._add_peer(host, port, node_id) - return peer - def mktx_for_open_channel(self, *, coins: Sequence[PartialTxInput], funding_sat: int, fee_est=None) -> PartialTransaction: dummy_address = ln_dummy_address()