Require a real Electrum quorum and allow certificate pinning (B-84, ELC-01, ELC-03, ELC-14, ELC-19, ARC-20, OPS-12)
An empty ELECTRUM_FALLBACK_SERVERS (the .env.example default) silently made every corroboration pass, and with fallbacks the majority was taken over whoever answered, so one reachable fallback decided alone. TLS certificates were never checked. - _corroborate_majority passes only with at least 2 answers (MIN_QUORUM_RESPONSES) and a strict majority of the answers; no other server configured, or fewer than 2 answering, fails. ALLOW_NO_QUORUM=true keeps the old reduced rule. - config.validate_quorum_servers, called from the lifespan after parse_endpoints, refuses to start with fewer than 2 fallback servers unless ALLOW_NO_QUORUM=true (which logs a warning at every start). - Optional pinning: `host:port[:mode]:pin=<sha256>` per fallback and ELECTRUM_CERT_PIN for the primary; ElectrumClient compares the SHA-256 of the DER certificate after the TLS handshake and a mismatch fails like an unreachable server. A pin on a plaintext entry is a startup error. - .env.example now ships the four bootstrap servers and documents both new variables; docs/setup.md, spec, storico and BUGS.md updated. - Tests changed because the spec changed: the two "no other servers configured -> True" corroboration tests now assert that outcome only under allow_no_quorum. Note: a dev .env with fewer than 2 fallback servers will now refuse to start. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fd6a91e93d
commit
13cb66cc06
18 files changed
+451
-125
No files matched your search
@@ -27,15 +27,14 @@ Le difese sono cinque.
|
||||
`ELECTRUM_USE_SSL`) seguito da quelli di riserva. Ogni voce di riserva è
|
||||
`host:porta` (TLS), `host:porta:<modo>` con `<modo>` tra `ssl`/`tls` (TLS) e
|
||||
`notls`/`plain` (in chiaro), oppure `host:porta:pin=<sha256>` (TLS con
|
||||
certificato fissato, [ELC-03]); `<sha256>` sono 64 cifre esadecimali. Le
|
||||
certificato fissato, [ELC-03]); `<sha256>` sono 64 cifre esadecimali (maiuscole accettate, conservate in
|
||||
minuscolo); `pin=` può seguire anche `<modo>` con TLS, mai `notls`/`plain`
|
||||
(non c'è un certificato da fissare). Le
|
||||
voci vuote sono ignorate e i duplicati eliminati mantenendo la prima
|
||||
posizione. Una voce malformata blocca l'avvio subito, non durante il guasto
|
||||
in cui servirebbe.
|
||||
*Codice:* `app/electrum/client.py:parse_endpoints` ·
|
||||
*Test:* `tests/unit/test_electrum_client.py`
|
||||
*Stato:* da implementare (B-84), per la forma `pin=` · *Oggi:* il terzo
|
||||
campo accetta solo `ssl`/`tls`/`notls`/`plain`; `pin=…` è una voce
|
||||
malformata.
|
||||
- **[ELC-02]** Dopo ogni sessione fallita o caduta si prova **subito** il
|
||||
server successivo nell'elenco, a rotazione; l'attesa crescente (da 1s
|
||||
raddoppiando fino a 30s) scatta solo dopo che ogni server ha fallito una
|
||||
@@ -52,9 +51,8 @@ Le difese sono cinque.
|
||||
irraggiungibile e si passa al successivo ([ELC-02]). Senza pin la fiducia
|
||||
non viene dal TLS ma dal quorum ([§ 5](#5-il-quorum)). Ogni connessione si
|
||||
apre con la stretta di mano `server.version`.
|
||||
*Codice:* `app/electrum/client.py:ElectrumClient.connect` · *Test:* —
|
||||
*Stato:* da implementare (B-84) · *Oggi:* nessun certificato viene mai
|
||||
verificato; non esiste un modo di fissarlo.
|
||||
*Codice:* `app/electrum/client.py:ElectrumClient.connect`, `app/electrum/client.py:ElectrumClient._check_pin`, `app/main.py:_make_electrum_client` ·
|
||||
*Test:* `tests/unit/test_electrum_client.py`
|
||||
- **[ELC-19]** Il server **rifiuta di avviarsi** se, dopo l'eliminazione dei
|
||||
duplicati, l'elenco contiene meno di **2 server di riserva** oltre al
|
||||
principale: con meno di tre server il quorum di [ELC-14] non può mai avere
|
||||
@@ -62,10 +60,8 @@ Le difese sono cinque.
|
||||
`ALLOW_NO_QUORUM=true`, **solo per lo sviluppo**: il server parte, scrive un
|
||||
avviso nei log a ogni avvio, e le corroborazioni seguono la regola ridotta
|
||||
di [ELC-14].
|
||||
*Codice:* `app/config.py:validate_runtime_secrets`, `app/main.py:lifespan` · *Test:* —
|
||||
*Stato:* da implementare (B-84) · *Oggi:* un `ELECTRUM_FALLBACK_SERVERS`
|
||||
vuoto (il valore di `.env.example`) è accettato in silenzio e disattiva
|
||||
ogni corroborazione.
|
||||
*Codice:* `app/config.py:validate_quorum_servers`, `app/main.py:lifespan` ·
|
||||
*Test:* `tests/unit/test_electrum_listener.py`
|
||||
|
||||
## 2. Richieste con limite di tempo
|
||||
|
||||
@@ -299,11 +295,6 @@ server attivo; sono le righe [ELC-26], [ELC-28], [ELC-25] e [ELC-27].
|
||||
maggioranza stretta delle risposte, anche di una sola.
|
||||
*Codice:* `app/electrum/listener.py:ElectrumListener._corroborate_majority` ·
|
||||
*Test:* `tests/unit/test_electrum_listener.py`
|
||||
*Stato:* da implementare (B-84) · *Oggi:* vale per tutti la regola ridotta.
|
||||
Senza server di riserva ogni verifica passa; con server di riserva la
|
||||
maggioranza è calcolata su chi ha risposto, quindi **una risposta su una
|
||||
decide**: se è raggiungibile un solo altro server, la sua parola basta.
|
||||
Nessuna risposta fa fallire la verifica.
|
||||
|
||||
| ID | Prima di… | Si verifica che… |
|
||||
|---|---|---|
|
||||
|
||||
Reference in new issue
Block a user