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:
davideandClaude Sonnet 5.5 committed 2026-10-14 14:04:35 +02:00
1 parent fd6a91e93d
commit 13cb66cc06
18 files changed
+451 -125

No files matched your search

+8 -4
View File
@@ -47,14 +47,18 @@ endpoint admin inclusi, quindi restano disattivati a meno di non impostarlo
esplicitamente a `true` — utile in locale, da evitare in produzione.
`ELECTRUM_FALLBACK_SERVERS` elenca i server di riserva, separati da virgola, nel
formato `host:porta` (TLS, il caso normale) oppure `host:porta:notls`. Esempio:
formato `host:porta` (TLS, il caso normale), `host:porta:notls` oppure
`host:porta:pin=<sha256>` (TLS con il certificato del server fissato). Esempio:
```
ELECTRUM_FALLBACK_SERVERS=nodo2.example.net:50002,nodo3.example.net:50001:notls
ELECTRUM_FALLBACK_SERVERS=nodo2.example.net:50002,nodo3.example.net:50002,nodo4.example.net:50002:pin=<sha256>
```
Vengono provati a rotazione dopo il primario. Attenzione: un valore scritto male
**blocca l'avvio** dell'app — è voluto, meglio accorgersene subito che durante il
Vengono provati a rotazione dopo il primario e servono anche da quorum: ne
servono **almeno 2**, altrimenti l'app non parte (`ALLOW_NO_QUORUM=true` lo
permette, ma solo in sviluppo). `ELECTRUM_CERT_PIN` fissa allo stesso modo il
certificato del primario. Attenzione: un valore scritto male **blocca
l'avvio** dell'app — è voluto, meglio accorgersene subito che durante il
disservizio in cui il fallback serve davvero.
`JWT_SECRET` e `XPRV_ENCRYPTION_KEY` vengono verificati all'avvio: se sono vuoti