Browse Source

lntransport: change name used in logs to make collisions unlikely

In particular, in the regtests, with incoming peers, we can have multiple transports open with the same node simultaneously
(see e.g. lnworker._request_force_close_from_backup).
We now use the first few bytes of peer_pubkey, as that is potentially familiar to users,
and the first few bytes of sha256(id(self)) to mitigate collisions in case the peer_pubkeys collide.

log excerpt:
```
I/P | lnpeer.Peer.[LNWallet, 030f0bf260-e0b33756] | handshake done for 030f0bf260acdbd3edcad84d7588ec7c5df4711e87e6a23016f989b8d3a4147230@163.172.94.64:9735
D/P | lnpeer.Peer.[LNWallet, 030f0bf260-e0b33756] | Sending INIT
I/P | lnpeer.Peer.[LNWallet, 03933884aa-5e5dce45] | handshake done for 03933884aaf1d6b108397e5efe5c86bcf2d8ca8d2f700eda99db9214fc2712b134@34.250.234.192:9735
D/P | lnpeer.Peer.[LNWallet, 03933884aa-5e5dce45] | Sending INIT
D/P | lnpeer.Peer.[LNWallet, 030f0bf260-e0b33756] | Received INIT
I/P | lnpeer.Peer.[LNWallet, 02651acf4a-79696c42] | handshake done for 02651acf4a7096091bf42baad19b3643ea318d6979f6dcc16ebaec43d5b0f4baf2@82.119.233.36:19735
D/P | lnpeer.Peer.[LNWallet, 02651acf4a-79696c42] | Sending INIT
D/P | lnpeer.Peer.[LNWallet, 03933884aa-5e5dce45] | Received INIT
I/P | lnpeer.Peer.[LNWallet, 030f0bf260-e0b33756] | saved remote_update
D/P | lnpeer.Peer.[LNWallet, 030f0bf260-e0b33756] | Received CHANNEL_REESTABLISH
```
patch-4
SomberNight 3 years ago
parent
commit
40c1597c0a
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 2
      electrum/lnpeer.py
  2. 21
      electrum/lntransport.py
  3. 1
      electrum/tests/test_lnpeer.py

2
electrum/lnpeer.py

@ -150,8 +150,10 @@ class Peer(Logger):
and self.initialized.result() is True) and self.initialized.result() is True)
async def initialize(self): async def initialize(self):
# If outgoing transport, do handshake now. For incoming, it has already been done.
if isinstance(self.transport, LNTransport): if isinstance(self.transport, LNTransport):
await self.transport.handshake() await self.transport.handshake()
self.logger.info(f"handshake done for {self.transport.peer_addr or self.pubkey.hex()}")
features = self.features.for_init_message() features = self.features.for_init_message()
b = int.bit_length(features) b = int.bit_length(features)
flen = b // 8 + int(bool(b % 8)) flen = b // 8 + int(bool(b % 8))

21
electrum/lntransport.py

@ -9,6 +9,7 @@ import hashlib
import asyncio import asyncio
from asyncio import StreamReader, StreamWriter from asyncio import StreamReader, StreamWriter
from typing import Optional from typing import Optional
from functools import cached_property
from .crypto import sha256, hmac_oneshot, chacha20_poly1305_encrypt, chacha20_poly1305_decrypt from .crypto import sha256, hmac_oneshot, chacha20_poly1305_encrypt, chacha20_poly1305_decrypt
from .lnutil import (get_ecdh, privkey_to_pubkey, LightningPeerConnectionClosed, from .lnutil import (get_ecdh, privkey_to_pubkey, LightningPeerConnectionClosed,
@ -92,9 +93,18 @@ class LNTransportBase:
reader: StreamReader reader: StreamReader
writer: StreamWriter writer: StreamWriter
privkey: bytes privkey: bytes
peer_addr: Optional[LNPeerAddr] = None
def name(self) -> str: def name(self) -> str:
raise NotImplementedError() pubkey = self.remote_pubkey()
pubkey_hex = pubkey.hex() if pubkey else pubkey
return f"{pubkey_hex[:10]}-{self._id_hash[:8]}"
@cached_property
def _id_hash(self) -> str:
id_int = id(self)
id_bytes = id_int.to_bytes((id_int.bit_length() + 7) // 8, byteorder='big')
return sha256(id_bytes).hex()
def send_bytes(self, msg: bytes) -> None: def send_bytes(self, msg: bytes) -> None:
l = len(msg).to_bytes(2, 'big') l = len(msg).to_bytes(2, 'big')
@ -169,10 +179,8 @@ class LNResponderTransport(LNTransportBase):
self.privkey = privkey self.privkey = privkey
self._pubkey = None # remote pubkey self._pubkey = None # remote pubkey
def name(self): def name(self) -> str:
pubkey = self.remote_pubkey() return f"{super().name()}(in)"
pubkey_hex = pubkey.hex() if pubkey else pubkey
return f"{pubkey_hex}(in)"
async def handshake(self, **kwargs): async def handshake(self, **kwargs):
hs = HandshakeState(privkey_to_pubkey(self.privkey)) hs = HandshakeState(privkey_to_pubkey(self.privkey))
@ -243,9 +251,6 @@ class LNTransport(LNTransportBase):
self.peer_addr = peer_addr self.peer_addr = peer_addr
self.proxy = MySocksProxy.from_proxy_dict(proxy) self.proxy = MySocksProxy.from_proxy_dict(proxy)
def name(self):
return self.peer_addr.net_addr_str()
async def handshake(self): async def handshake(self):
if not self.proxy: if not self.proxy:
self.reader, self.writer = await asyncio.open_connection(self.peer_addr.host, self.peer_addr.port) self.reader, self.writer = await asyncio.open_connection(self.peer_addr.host, self.peer_addr.port)

1
electrum/tests/test_lnpeer.py

@ -249,6 +249,7 @@ class MockTransport:
def __init__(self, name): def __init__(self, name):
self.queue = asyncio.Queue() self.queue = asyncio.Queue()
self._name = name self._name = name
self.peer_addr = None
def name(self): def name(self):
return self._name return self._name

Loading…
Cancel
Save