Survive oversized Electrum replies and ignore dust deposits (B-75, ELC-20, DEP-01, DAT-10)
A reply line over asyncio's default 64 KiB StreamReader limit raised out of _read_loop and closed the only connection; the pool address's get_history passes that after ~800 transactions, and dust sent to any public address does it on purpose. - ElectrumClient opens the stream with a 16 MiB limit and frames lines itself: an oversized line is discarded up to its newline, a non-JSON line is dropped, and the request whose id is readable in the first/last 256 bytes fails at once; the connection stays up either way. - Coins below DUST_LIMIT_SATS are never offered as credit candidates, never credited, and select_utxos never selects them. - Spec (ELC-20, DEP-01, DAT-10, ARC), storico, BUGS.md and test counts updated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b424f670c5
commit
daec4749c2
15 files changed
+245
-49
No files matched your search
@@ -194,13 +194,13 @@ sono vuoti e non sono elencati.
|
||||
| `app/wallet/hd.py` | Generazione della master key, derivazione di indirizzi/chiavi utente (`0/i`) e del pool (`1/0`), export WIF; la chiave d'account decifrata resta in cache nel processo. *Da implementare:* indirizzo del montepremi per round (`2/<round_id>`), con `1/0` come indirizzo di riserva (B-80) |
|
||||
| `app/wallet/address.py` | `is_valid_plm_address`: checksum bech32 + HRP `plm` |
|
||||
| `app/wallet/balance.py` | `recompute_balance` (saldo confermato), `compute_pending_balance` (saldo mostrato) — vedi [registrazione-e-depositi.md](registrazione-e-depositi.md) |
|
||||
| `app/wallet/psbt_builder.py` | Selezione UTXO, costruzione e firma di scommessa, prelievo e pagamento; limiti `MAX_TX_INPUTS`, `MAX_PAYOUT_TX_INPUTS`, `MAX_PARTICIPANTS_PER_ROUND`, `DUST_LIMIT_SATS`. *Da implementare:* uscita di riserva per l'RBF sul pagamento (B-79), UTXO sotto `DUST_LIMIT_SATS` esclusi dalla selezione (B-75) |
|
||||
| `app/wallet/psbt_builder.py` | Selezione UTXO, costruzione e firma di scommessa, prelievo e pagamento; limiti `MAX_TX_INPUTS`, `MAX_PAYOUT_TX_INPUTS`, `MAX_PARTICIPANTS_PER_ROUND`, `DUST_LIMIT_SATS`. *Da implementare:* uscita di riserva per l'RBF sul pagamento (B-79) |
|
||||
|
||||
### Rete Electrum
|
||||
|
||||
| File | Responsabilità |
|
||||
|---|---|
|
||||
| `app/electrum/client.py` | `ElectrumClient` (JSON-RPC, timeout per richiesta), `ElectrumEndpoint`, `parse_endpoints`. *Da implementare:* limite di lettura di 16 MiB per riga, risposta troppo grande o malformata come errore della richiesta e non della connessione (B-75); pin del certificato per endpoint (B-84) |
|
||||
| `app/electrum/client.py` | `ElectrumClient` (JSON-RPC, timeout per richiesta), `ElectrumEndpoint`, `parse_endpoints`; limite di lettura di 16 MiB per riga, risposta troppo grande o malformata come errore della richiesta e non della connessione. *Da implementare:* pin del certificato per endpoint (B-84) |
|
||||
| `app/electrum/listener.py` | `ElectrumListener`: l'unica connessione, rotazione, keepalive, validazione header, corroborazione, sottoscrizioni e accredito — vedi [connessione-electrum.md](connessione-electrum.md). Il docstring della classe cita un metodo `add_address` che non esiste: l'indirizzo di un nuovo utente si aggiunge con `address_for_new_user` |
|
||||
| `app/electrum/scripthash.py` | `address_to_scripthash`: scripthash Electrum di un indirizzo |
|
||||
|
||||
@@ -540,12 +540,10 @@ implementare» non esistono ancora nel codice (vedi [ARC-60] e [ARC-22]).
|
||||
*Codice:* `app/electrum/listener.py:ElectrumListener.run` ·
|
||||
`app/electrum/listener.py:ElectrumListener._apply_header` ·
|
||||
`app/electrum/client.py:ElectrumClient.connect` ·
|
||||
*Test:* `tests/unit/test_electrum_listener.py`
|
||||
*Stato:* da implementare (B-74, B-75, B-85, B-86) · *Oggi:* il listener
|
||||
tiene solo la punta, chiude la sessione su ogni header che non si concatena,
|
||||
non confronta la propria punta con gli altri server, e il client usa il
|
||||
limite predefinito di 64 KiB di `asyncio.open_connection`, oltre il quale
|
||||
cade l'intera connessione.
|
||||
*Test:* `tests/unit/test_electrum_listener.py`, `tests/unit/test_electrum_client.py`
|
||||
*Stato:* da implementare (B-74, B-85, B-86) · *Oggi:* il listener
|
||||
tiene solo la punta, chiude la sessione su ogni header che non si concatena
|
||||
e non confronta la propria punta con gli altri server.
|
||||
- **[ARC-27]** **`RoundScheduler`.** A ogni giro (5s) chiama
|
||||
`open_new_round_if_needed` e poi avanza il round attivo, in qualunque stato
|
||||
sia, `drawing` compreso: per un round in `drawing` il giro rientra
|
||||
|
||||
@@ -85,12 +85,8 @@ Le difese sono cinque.
|
||||
cui rispondeva fallisce subito con un errore se il suo `id` si legge nei
|
||||
primi o negli ultimi 256 byte della riga; altrimenti fallisce allo scadere
|
||||
di [ELC-04].
|
||||
*Codice:* `app/electrum/client.py:ElectrumClient.connect`, `app/electrum/client.py:ElectrumClient._read_loop` · *Test:* —
|
||||
*Stato:* da implementare (B-75) · *Oggi:* il lettore ha il limite
|
||||
predefinito di asyncio (64 KiB); una riga più lunga, o non JSON, interrompe
|
||||
`_read_loop` e chiude l'unica connessione. La cronologia dell'indirizzo del
|
||||
montepremi supera 64 KiB dopo 800 transazioni (stima di B-75), e da lì ogni controllo
|
||||
delle conferme la fa cadere.
|
||||
*Codice:* `app/electrum/client.py:ElectrumClient.connect`, `app/electrum/client.py:ElectrumClient._read_loop` ·
|
||||
*Test:* `tests/unit/test_electrum_client.py`
|
||||
|
||||
## 3. Caduta rilevata
|
||||
|
||||
|
||||
@@ -337,7 +337,7 @@ del database sono tutti uguali, perché arrivano tutti dallo stesso percorso
|
||||
corroborazione è in [connessione-electrum.md](connessione-electrum.md)).
|
||||
Le conferme richieste e la soglia sotto cui un output non si accredita
|
||||
(`DUST_LIMIT_SATS`) sono regole del deposito, definite in
|
||||
[registrazione-e-depositi.md](registrazione-e-depositi.md) (B-82, B-75): lo
|
||||
[registrazione-e-depositi.md](registrazione-e-depositi.md) (B-82): lo
|
||||
schema non le ripete. Il numero di conferme configurabile è la colonna
|
||||
`round_config.deposit_confirmations` ([DAT-62]). L'inserimento è
|
||||
idempotente su (`txid`, `vout`), che è unico su tutta la tabella, non solo
|
||||
@@ -347,8 +347,8 @@ del database sono tutti uguali, perché arrivano tutti dallo stesso percorso
|
||||
`app/deposits/service.py:credit_confirmed_utxos` ·
|
||||
`app/electrum/listener.py:ElectrumListener.refresh_user` ·
|
||||
*Test:* `tests/unit/test_deposits.py`, `tests/unit/test_electrum_listener.py`
|
||||
*Stato:* da implementare (B-82, B-75) · *Oggi:* si accredita ogni output
|
||||
con `height > 0` (1 conferma), coinbase comprese, di qualunque importo.
|
||||
*Stato:* da implementare (B-82) · *Oggi:* si accredita ogni output
|
||||
con `height > 0` (1 conferma), coinbase comprese.
|
||||
|
||||
- **[DAT-11]** Gli UTXO dei montepremi e della riserva **non** sono in
|
||||
`utxo_events`: non appartengono a un utente. Il pagamento di un round spende
|
||||
|
||||
+1
-1
@@ -685,7 +685,7 @@ con `docker compose logs app` ([architettura.md](architettura.md) ARC-09).
|
||||
`could not subscribe a newly-registered user's address` o
|
||||
`resubscribing all users failed partway through`).
|
||||
4. Electrum irraggiungibile o fermo ([OPS-11]).
|
||||
5. Dopo B-75: l'importo è sotto `DUST_LIMIT_SATS` (294 sat) e non viene
|
||||
5. L'importo è sotto `DUST_LIMIT_SATS` (294 sat) e non viene
|
||||
accreditato per scelta.
|
||||
**Cosa fare.** Verificare con un explorer che la transazione abbia le
|
||||
conferme richieste e paghi esattamente l'indirizzo dell'utente (sezione
|
||||
|
||||
@@ -226,9 +226,8 @@ monete sotto la soglia non compaiono nel saldo mostrato.
|
||||
questo documento. Non è spendibile in modo economico e, se accreditata,
|
||||
farebbe crescere senza limite il lavoro di ogni aggiornamento; chiunque
|
||||
può inviarne a qualunque indirizzo pubblico.
|
||||
*Codice:* `app/deposits/service.py:find_new_credit_candidates`, `app/deposits/service.py:credit_confirmed_utxos`, `app/wallet/psbt_builder.py:DUST_LIMIT_SATS` · *Test:* —
|
||||
*Stato:* da implementare (B-75) · *Oggi:* si accredita una moneta di
|
||||
qualunque importo.
|
||||
*Codice:* `app/deposits/service.py:find_new_credit_candidates`, `app/deposits/service.py:credit_confirmed_utxos`, `app/wallet/psbt_builder.py:DUST_LIMIT_SATS`, `app/wallet/psbt_builder.py:select_utxos` ·
|
||||
*Test:* `tests/unit/test_deposits.py`, `tests/unit/test_psbt_builder.py`
|
||||
- **[DEP-02]** Un aggiornamento dell'indirizzo di un utente legge l'elenco
|
||||
delle monete non spese (`listunspent`) dal server Electrum attivo e procede
|
||||
in tre fasi. **Lettura**, senza scrivere nulla: individuazione degli
|
||||
|
||||
+3
-3
@@ -223,7 +223,7 @@ cifrava di nuovo il file sbagliato (vedi [operativita.md](operativita.md)).
|
||||
|---|---|---|---|---|---|
|
||||
| B-73 | L'estrazione dipende solo dall'hash del blocco: un minatore con biglietti o il server Electrum attivo possono pilotarla; ordine dei partecipanti non verificabile | Critica | **aperto** | — | RND, ELC |
|
||||
| B-74 | Header accettati senza controllo della difficoltà minima; un salto di più blocchi non viene collegato; una riorganizzazione di un blocco chiude la sessione | Critica | **aperto** | — | ELC |
|
||||
| B-75 | Una risposta Electrum oltre 64 KiB chiude la connessione, e la cronologia dell'indirizzo del montepremi la supera dopo ~800 transazioni | Critica | **aperto** | — | ELC, TX |
|
||||
| B-75 | Una risposta Electrum oltre 64 KiB chiude la connessione, e la cronologia dell'indirizzo del montepremi la supera dopo ~800 transazioni | Critica | *da registrare* | `test_electrum_client.py`, `test_deposits.py`, `test_psbt_builder.py` | ELC, TX |
|
||||
| B-76 | Un invio ambiguo (timeout, connessione caduta) viene annullato come se fosse rifiutato | Critica | **aperto** | — | TX, BET, WDR |
|
||||
| B-77 | Si ricorda solo l'ultimo txid di una transazione accelerata, e la sostituzione viene inviata prima di essere salvata | Critica | **aperto** | — | TX |
|
||||
| B-78 | Una transazione viene abbandonata sulla base del silenzio di un solo server | Critica | **aperto** | — | TX, ELC |
|
||||
@@ -252,9 +252,9 @@ cifrava di nuovo il file sbagliato (vedi [operativita.md](operativita.md)).
|
||||
|
||||
- **Corretti:** B-01 … B-70, tranne B-16, che è chiuso nella sostanza (il
|
||||
crash è eliminato e `/guida` serve un segnaposto) ma lascia la guida vera
|
||||
come limite accettato; dalla revisione del 2026-09-28: B-88.
|
||||
come limite accettato; dalla revisione del 2026-09-28: B-88, B-75.
|
||||
- **Aperti:** B-71, B-72 (gravità bassa, operativi o di documentazione) e
|
||||
B-73 … B-98 dalla revisione del 2026-09-28 tranne i corretti (10 critici,
|
||||
B-73 … B-98 dalla revisione del 2026-09-28 tranne i corretti (9 critici,
|
||||
8 alti, 7 medi), da implementare nell'ordine di
|
||||
[piano-correzioni.md](piano-correzioni.md).
|
||||
- **Prossimo numero libero:** `B-99`.
|
||||
Reference in new issue
Block a user