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>
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>
- Add docs/README.md as the index of all documentation.
- Split the 52 DEC entries of decisioni-e-limiti.md into docs/adr/ADR-NN
files (same numbers), add ADR-53 (audit log), TEMPLATE.md and an ADR index
with a feature -> ADR table.
- Rename decisioni-e-limiti.md to limiti-noti.md (LIM only) and rewrite all
DEC-nn references as links to the ADRs.
- Document the docs-first / SSOT / ADR rules in processo-di-modifica.md and
map the docs in CLAUDE.md and README.md.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Fourth full audit, run against the docs/ specification instead of the code
alone, found logical flaws rooted in PLM's small hashrate (~22 TH/s): a
minable draw, no distinction between "never broadcast" and "unknown if
broadcast", an Electrum client that degrades as the pool address's history
grows, and 1-confirmation deposits on a chain where a reorg is rentable.
The spec now describes the target behaviour for every finding, marked
*Stato:* da implementare (B-nn) with an *Oggi:* line for what the code does
now; docs/piano-correzioni.md records the design decisions and the
implementation order. No code changed — this is spec-only, per B-nn
convention when a bug reveals the spec itself was incomplete.
Also documents, as an accepted-but-open risk (LIM-24), that the optional
jackpot cap (max_round_pool_sats) isn't tied to the cost of a 51% attack —
deferred, not decided.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The two Mermaid diagrams under flowchart/ described the intended flow but
had drifted from the code and carried no link back to it. docs/ now holds
the specification instead: 15 Italian documents (flows, architecture, data
model, API, security, audit log, operations, decisions and limits, bug
history) with 472 numbered requirements, each pointing at the function
that implements it and the test that covers it. docs/processo-di-modifica.md
defines the ID convention and the spec -> code -> test change workflow, and
CLAUDE.md now names docs/ as authoritative.
Writing the spec from the code also corrected stale claims in CLAUDE.md
(B-41's get_history check, BUGS.md still tracking B-71/B-72, Cache-Control
scope, the error contract's bare-string exceptions) and in the operator
guides (payouts do retry, only `drawing` fails to resume, rounds do not
open without fee_address). The B-70 doc test now pins the prose in
docs/scommesse-e-prelievi.md instead of the deleted diagram.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>