diff --git a/lnbits/core/views/blockexplorer_api.py b/lnbits/core/views/blockexplorer_api.py index 93d90cc5e..814a8c45a 100644 --- a/lnbits/core/views/blockexplorer_api.py +++ b/lnbits/core/views/blockexplorer_api.py @@ -63,15 +63,31 @@ async def _tx_status( c: ElectrumClient, txid: str, scripthash: str | None ) -> dict[str, Any]: if scripthash: - history: list[HistoryEntry] = await c.get_history(scripthash) - for entry in history: - if entry.tx_hash == txid: - return { - "txid": txid, - "confirmed": entry.height > 0, - "height": entry.height if entry.height > 0 else None, - "fee": entry.fee, - } + try: + history: list[HistoryEntry] = await c.get_history(scripthash) + for entry in history: + if entry.tx_hash == txid: + return { + "txid": txid, + "confirmed": entry.height > 0, + "height": entry.height if entry.height > 0 else None, + "fee": entry.fee, + } + except ElectrumError: + # History too large; check mempool to determine confirmation status. + try: + mempool = await c.get_mempool(scripthash) + for entry in mempool: + if entry.tx_hash == txid: + return { + "txid": txid, + "confirmed": False, + "height": None, + "fee": entry.fee, + } + return {"txid": txid, "confirmed": True, "height": None, "fee": None} + except ElectrumError: + pass return {"txid": txid, "confirmed": False, "height": None, "fee": None} @@ -145,11 +161,22 @@ async def api_address(address: str) -> AddressResponse: raise HTTPException(HTTPStatus.BAD_REQUEST, detail=str(e)) from e try: async with _client() as c: - balance, history = await asyncio.gather( + balance_res, history_res = await asyncio.gather( c.get_balance(scripthash), c.get_history(scripthash), + return_exceptions=True, ) - return AddressResponse(balance=balance, history=history) + if isinstance(balance_res, Exception): + raise HTTPException( + HTTPStatus.SERVICE_UNAVAILABLE, detail=str(balance_res) + ) + history = [] if isinstance(history_res, Exception) else history_res + history_error = str(history_res) if isinstance(history_res, Exception) else None + return AddressResponse( + balance=balance_res, history=history, history_error=history_error + ) + except HTTPException: + raise except ElectrumError as e: raise HTTPException(HTTPStatus.SERVICE_UNAVAILABLE, detail=str(e)) from e @@ -200,19 +227,38 @@ async def ws_address(websocket: WebSocket, address: str) -> None: try: async with _client() as c: await c.subscribe_scripthash(scripthash) - balance, history = await asyncio.gather( - c.get_balance(scripthash), c.get_history(scripthash) + balance_res, history_res = await asyncio.gather( + c.get_balance(scripthash), + c.get_history(scripthash), + return_exceptions=True, + ) + if isinstance(balance_res, Exception): + await websocket.send_json({"error": str(balance_res)}) + return + history = [] if isinstance(history_res, Exception) else history_res + history_error = ( + str(history_res) if isinstance(history_res, Exception) else None + ) + resp = AddressResponse( + balance=balance_res, history=history, history_error=history_error ) - resp = AddressResponse(balance=balance, history=history) await websocket.send_json(resp.dict()) async def on_address_change(params: list[Any]) -> None: try: - bal, hist = await asyncio.gather( - c.get_balance(scripthash), c.get_history(scripthash) + bal_r, hist_r = await asyncio.gather( + c.get_balance(scripthash), + c.get_history(scripthash), + return_exceptions=True, ) + if isinstance(bal_r, Exception): + return + hist = [] if isinstance(hist_r, Exception) else hist_r + h_err = str(hist_r) if isinstance(hist_r, Exception) else None await websocket.send_json( - AddressResponse(balance=bal, history=hist).dict() + AddressResponse( + balance=bal_r, history=hist, history_error=h_err + ).dict() ) except Exception as e: logger.debug(f"ws_address send error: {e}") diff --git a/lnbits/static/i18n/en.js b/lnbits/static/i18n/en.js index 4432ae668..b02961e10 100644 --- a/lnbits/static/i18n/en.js +++ b/lnbits/static/i18n/en.js @@ -870,5 +870,6 @@ window.localisation.en = { confirmed: 'Confirmed', unconfirmed: 'Unconfirmed', no_transactions: 'No transactions found', + history_unavailable: 'Transaction history unavailable (address has too many transactions)', address: 'Address' } diff --git a/lnbits/static/js/pages/blockexplorer.js b/lnbits/static/js/pages/blockexplorer.js index b1d54dcc0..2f263856c 100644 --- a/lnbits/static/js/pages/blockexplorer.js +++ b/lnbits/static/js/pages/blockexplorer.js @@ -119,6 +119,16 @@ window.PageBlockExplorer = { this.fees = r.data } catch (_) {} }, + clearResult() { + this.txResult = null + this.txStatus = null + this.addressResult = null + this.query = '' + if (this._searchWs) { + this._searchWs.close() + this._searchWs = null + } + }, async search() { const q = this.query.trim() if (!q) return diff --git a/lnbits/templates/pages/blockexplorer.vue b/lnbits/templates/pages/blockexplorer.vue index ec4823f44..8ec3d2dd7 100644 --- a/lnbits/templates/pages/blockexplorer.vue +++ b/lnbits/templates/pages/blockexplorer.vue @@ -120,14 +120,17 @@ -
-
- - +
+
+
+ + +
+
txid: @@ -200,6 +203,14 @@ v-text="vout.scriptPubKey.address" > + @@ -218,7 +229,10 @@ -
+
+
+ +
@@ -286,7 +300,12 @@
+
diff --git a/lnbits/utils/electrum.py b/lnbits/utils/electrum.py index 006a2347e..acc8bdaef 100644 --- a/lnbits/utils/electrum.py +++ b/lnbits/utils/electrum.py @@ -249,6 +249,7 @@ class FeeResponse(BaseModel): class AddressResponse(BaseModel): balance: Balance history: list[HistoryEntry] + history_error: str | None = None class BlockInfo(BaseModel):