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>
38 lines
2.6 KiB
Markdown
38 lines
2.6 KiB
Markdown
# ADR-07 — Ogni decisione che sposta denaro in base a una risposta di rete è corroborata da un quorum degli altri server configurati
|
|
|
|
- **Stato:** Accettata — implementazione da completare (B-83)
|
|
- **Area:** Conferme e fiducia nella rete
|
|
- **Fonte di verità per:** la scelta di progetto descritta qui sotto; i requisiti (`PREFISSO-NN`) che la attuano stanno nei documenti di dominio, indicati nelle *Conseguenze*.
|
|
|
|
## Decisione
|
|
|
|
**Ogni decisione che sposta denaro in base a una risposta di
|
|
rete è corroborata da un quorum degli altri server configurati**: il blocco
|
|
che semina l'estrazione, una moneta data per spesa all'esterno, un nuovo
|
|
deposito da accreditare, il ripristino di una moneta, la conferma di una
|
|
transazione (con prova merkle contro un header che possediamo), l'abbandono
|
|
di una transazione, le monete del round verificate prima del pagamento. Si
|
|
interrogano solo gli *altri* server, mai quello attivo (che è ciò che un
|
|
attaccante controllerebbe); servono **almeno 2 risposte** e la maggioranza
|
|
stretta di chi risponde. Il server rifiuta di partire con meno di 2 server
|
|
di riserva, salvo `ALLOW_NO_QUORUM=true` (solo sviluppo). Se rispondono meno
|
|
di 2 server, la corroborazione fallisce.
|
|
- *Motivazione:* un solo server ostile non deve poter scegliere il
|
|
vincitore (B-28), azzerare un saldo (B-29) o gonfiarlo (B-59), né far
|
|
credere confermato un pagamento mai trasmesso (B-83). I saldi si muovono in
|
|
entrambe le direzioni, quindi entrambe richiedono il quorum. Con 0 o 1
|
|
server di riserva la «maggioranza» è una sola voce, o nessuna (B-84).
|
|
- *Alternative scartate:* quorum facoltativo, che passa sempre con la lista
|
|
vuota (la regola precedente: il default di `.env.example` spegneva ogni
|
|
difesa senza avvisare).
|
|
- *Conseguenze:* una corroborazione fallita **ritarda**, non perde e non
|
|
libera fondi ([ADR-51](ADR-51-dubbio-liberano-mai-fondi.md)): il deposito è riproposto al refresh successivo,
|
|
l'estrazione richiede di nuovo lo stesso blocco. Il quorum resta fra server
|
|
scelti dall'operatore ([LIM-11]). Regole in
|
|
[connessione-electrum.md](../connessione-electrum.md#5-il-quorum) (B-83, B-84).
|
|
|
|
*Codice:* `app/electrum/listener.py:ElectrumListener._corroborate_majority` · `app/electrum/listener.py:ElectrumListener.corroborate_header` · `app/electrum/listener.py:ElectrumListener.corroborate_utxo_spent` · `app/electrum/listener.py:ElectrumListener.corroborate_utxo_credit` · `app/main.py:lifespan` ·
|
|
*Test:* `tests/unit/test_electrum_listener.py`
|
|
*Stato:* da implementare (B-83) · *Oggi:* conferme, ripristini e abbandoni
|
|
si decidono sul solo server attivo.
|