fix closing

This commit is contained in:
dni
2026-07-13 09:09:42 +02:00
parent 0a1a578988
commit 1e4f19fd1c
+41 -24
View File
@@ -465,6 +465,7 @@ class ElectrumClient:
self._ping_task: asyncio.Task[None] | None = None self._ping_task: asyncio.Task[None] | None = None
self._reader: asyncio.StreamReader | None = None self._reader: asyncio.StreamReader | None = None
self._writer: asyncio.StreamWriter | None = None self._writer: asyncio.StreamWriter | None = None
self.closed: asyncio.Event = asyncio.Event()
self.server_version: str = "" self.server_version: str = ""
self.negotiated_protocol: str = "" self.negotiated_protocol: str = ""
@@ -599,6 +600,7 @@ class ElectrumClient:
except Exception: except Exception:
logger.exception("Electrum: recv loop error") logger.exception("Electrum: recv loop error")
finally: finally:
self.closed.set()
for fut in self._pending.values(): for fut in self._pending.values():
if not fut.done(): if not fut.done():
fut.set_exception(ElectrumError("Connection closed")) fut.set_exception(ElectrumError("Connection closed"))
@@ -792,9 +794,6 @@ class AddressTracker:
while is_active(): while is_active():
try: try:
async with ElectrumClient(self.url) as client: async with ElectrumClient(self.url) as client:
await self._fetch_and_dispatch(
client, address, scripthash, callback
)
async def on_status_change(params: list[Any]) -> None: async def on_status_change(params: list[Any]) -> None:
if params and params[0] == scripthash: if params and params[0] == scripthash:
@@ -803,8 +802,15 @@ class AddressTracker:
) )
await client.subscribe_scripthash(scripthash, on_status_change) await client.subscribe_scripthash(scripthash, on_status_change)
await self._fetch_and_dispatch(
client, address, scripthash, callback
)
while is_active(): while is_active():
await asyncio.sleep(30) try:
await asyncio.wait_for(client.closed.wait(), timeout=30)
break # connection closed; reconnect
except asyncio.TimeoutError:
pass
except asyncio.CancelledError: except asyncio.CancelledError:
raise raise
except Exception as exc: except Exception as exc:
@@ -820,25 +826,32 @@ class AddressTracker:
scripthash: str, scripthash: str,
callback: Callable[[OnchainAddressEvent], Coroutine[Any, Any, None]], callback: Callable[[OnchainAddressEvent], Coroutine[Any, Any, None]],
) -> None: ) -> None:
balance = await client.get_balance(scripthash) balance_r, history_r, mempool_r = await asyncio.gather(
history: list[HistoryEntry] = [] client.get_balance(scripthash),
history_error: str | None = None client.get_history(scripthash),
try: client.get_mempool(scripthash),
history = await client.get_history(scripthash) return_exceptions=True,
except ElectrumError as exc: )
history_error = str(exc) if isinstance(balance_r, BaseException):
try: raise balance_r
history: list[HistoryEntry] = (
[] if isinstance(history_r, BaseException) else history_r
)
history_error: str | None = (
str(history_r) if isinstance(history_r, BaseException) else None
)
if not isinstance(mempool_r, BaseException):
seen = {e.tx_hash for e in history} seen = {e.tx_hash for e in history}
for m in await client.get_mempool(scripthash): for m in mempool_r:
if m.tx_hash not in seen: if m.tx_hash not in seen:
history.append(HistoryEntry(tx_hash=m.tx_hash, height=0, fee=m.fee)) history.append(
except ElectrumError: HistoryEntry(tx_hash=m.tx_hash, height=0, fee=m.fee)
pass )
await callback( await callback(
OnchainAddressEvent( OnchainAddressEvent(
address=address, address=address,
confirmed=balance.confirmed, confirmed=balance_r.confirmed,
unconfirmed=balance.unconfirmed, unconfirmed=balance_r.unconfirmed,
history=history, history=history,
history_error=history_error, history_error=history_error,
) )
@@ -916,11 +929,6 @@ class TransactionTracker:
return False return False
scripthash = tx_watch_scripthash(parse_raw_tx(raw)) scripthash = tx_watch_scripthash(parse_raw_tx(raw))
event = await self._fetch_status(client, txid, scripthash)
await callback(event)
if event.confirmed:
return True
confirmed_event = asyncio.Event() confirmed_event = asyncio.Event()
async def on_change( async def on_change(
@@ -937,8 +945,17 @@ class TransactionTracker:
if scripthash: if scripthash:
await client.subscribe_scripthash(scripthash, on_change) await client.subscribe_scripthash(scripthash, on_change)
event = await self._fetch_status(client, txid, scripthash)
await callback(event)
if event.confirmed:
return True
while is_active() and not confirmed_event.is_set(): while is_active() and not confirmed_event.is_set():
await asyncio.sleep(5) try:
await asyncio.wait_for(client.closed.wait(), timeout=30)
break # connection closed; reconnect
except asyncio.TimeoutError:
pass
return confirmed_event.is_set() return confirmed_event.is_set()
@staticmethod @staticmethod