1
0

lnpeer: await init in main_loop

Because `LNPeer.initialized` was awaited in
`LNPeer._query_gossip()` instead of the main loop the other tasks got
spawned concurrently and each task on its own has to wait for the
initialization. In `LNPeer._send_own_gossip()` this was missing, instead
there is a fixed 10 sec sleep. If the connection was not initialized but
the 10 sec are exceeded `_send_own_gossip()` tries to send gossip and
causes this exception as the `LNTransport` is not ready:

```
  2.13 | E | lnpeer.Peer.[LNWallet, 0288fa27c0-bc1900c8] | Exception in main_loop: AttributeError("'LNTransport' object has no attribute 'sk'")
Traceback (most recent call last):
  File "/home/user/code/electrum-fork/electrum/util.py", line 1232, in wrapper
    return await func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/code/electrum-fork/electrum/lnpeer.py", line 511, in wrapper_func
    return await func(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/code/electrum-fork/electrum/lnpeer.py", line 525, in main_loop
    async with self.taskgroup as group:
               ^^^^^^^^^^^^^^
  File "/home/user/code/electrum-fork/env/lib/python3.14/site-packages/aiorpcx/curio.py", line 304, in __aexit__
    await self.join()
  File "/home/user/code/electrum-fork/electrum/util.py", line 1420, in join
    task.result()
    ~~~~~~~~~~~^^
  File "/home/user/code/electrum-fork/electrum/lnpeer.py", line 573, in _send_own_gossip
    self.send_node_announcement(alias, color)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
  File "/home/user/code/electrum-fork/electrum/lnpeer.py", line 1830, in send_node_announcement
    self.transport.send_bytes(raw_msg)
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/home/user/code/electrum-fork/electrum/lntransport.py", line 225, in send_bytes
    lc = aead_encrypt(self.sk, self.sn(), b'', l)
                      ^^^^^^^
AttributeError: 'LNTransport' object has no attribute 'sk'. Did you mean: 'sn'?
```

By awaiting the initialization directly in the `main_loop` it is more
clear that the task getting spawned subsequently depend on the transport
being available and separates the initialization more clearly these
other functions.
This commit is contained in:
f321x
2025-10-28 15:32:58 +01:00
parent d379a66a8f
commit a5cf5f75fc

View File

@@ -523,7 +523,11 @@ class Peer(Logger, EventListener):
@handle_disconnect
async def main_loop(self):
async with self.taskgroup as group:
await group.spawn(self._message_loop())
await group.spawn(self._message_loop()) # initializes connection
try:
await util.wait_for2(self.initialized, LN_P2P_NETWORK_TIMEOUT)
except Exception as e:
raise GracefulDisconnect(f"Failed to initialize: {e!r}") from e
await group.spawn(self._query_gossip())
await group.spawn(self._process_gossip())
await group.spawn(self._send_own_gossip())
@@ -563,6 +567,7 @@ class Peer(Logger, EventListener):
async def _send_own_gossip(self):
if self.lnworker == self.lnworker.network.lngossip:
return
assert self.is_initialized()
await asyncio.sleep(10)
while True:
public_channels = [chan for chan in self.lnworker.channels.values() if chan.is_public()]
@@ -583,6 +588,7 @@ class Peer(Logger, EventListener):
return False
async def _forward_gossip(self):
assert self.is_initialized()
if not self._should_forward_gossip():
return
@@ -632,10 +638,7 @@ class Peer(Logger, EventListener):
return amount_sent
async def _query_gossip(self):
try:
await util.wait_for2(self.initialized, LN_P2P_NETWORK_TIMEOUT)
except Exception as e:
raise GracefulDisconnect(f"Failed to initialize: {e!r}") from e
assert self.is_initialized()
if self.lnworker == self.lnworker.network.lngossip:
if not self.their_features.supports(LnFeatures.GOSSIP_QUERIES_OPT):
raise GracefulDisconnect("remote does not support gossip_queries, which we need")