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>
6.6 KiB
Setup
Passaggi da eseguire una tantum per preparare un'istanza di PLM Lottery, prima di poterla avviare (in locale o via Docker). Per come avviarla poi ogni volta, vedi running-the-server.md.
1. Prerequisiti
- Python 3.12+ (serve solo per il workflow locale/venv — puoi saltarlo se usi solo Docker)
- Docker + Docker Compose (serve solo per il workflow a container)
- Un server Electrum raggiungibile per la rete PLM. Il server di bootstrap per lo
sviluppo è
santantonio.sytes.net:50002(SSL) — va bene per i test, ma in produzione conviene usarne uno di cui ci si fida o gestirne uno proprio. - Consigliato in produzione: più di un server. Tutto passa da questa singola
connessione (accredito depositi, invio transazioni, conferme, altezza della
catena su cui si basa l'estrazione), quindi un solo server è il principale
punto di rottura della piattaforma. Elencane altri in
ELECTRUM_FALLBACK_SERVERS(vedi sotto): l'app li prova a rotazione, così un server irraggiungibile costa un solo tentativo di riconnessione invece di un disservizio.
2. Creare il file .env
Copia .env.example in .env e compila i segreti. Ogni valore sotto viene
generato una volta e non cambia più (ruotarlo invalida sessioni/dati cifrati
esistenti):
cp .env.example .env
| Variabile | Scopo | Come generarla |
|---|---|---|
XPRV_ENCRYPTION_KEY |
Chiave simmetrica che cifra a riposo la master xprv del server. Perdere questa chiave significa perdere per sempre l'accesso ai fondi di tutti gli utenti. | python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" |
JWT_SECRET |
Firma i token di sessione degli utenti. | python -c "import secrets; print(secrets.token_urlsafe(32))" |
ADMIN_TOKEN |
Token bearer richiesto sugli endpoint admin (header X-Admin-Token). |
python -c "import secrets; print(secrets.token_urlsafe(32))" |
Le chiavi Electrum (ELECTRUM_HOST/PORT/USE_SSL) hanno default sensati in
.env.example. DATABASE_URL e MASTER_KEY_PATH non sono elencate lì:
hanno un default in app/config.py, e dentro il container vengono comunque
sovrascritte da docker-compose.yml per puntare a ./data/ (elenco completo
delle variabili in architettura.md).
ENABLE_API_DOCS (default false) controlla Swagger/ReDoc/l'OpenAPI JSON grezzo
su /docs, /redoc e /openapi.json: espongono l'intera superficie dell'API,
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), 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:50002,nodo4.example.net:50002:pin=<sha256>
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
(o JWT_SECRET è più corto di 32 caratteri) il container si rifiuta di partire con
un errore esplicito, invece di avviarsi e rompersi al primo login. Nota: .env
contiene solo segreti e configurazione di infrastruttura — i parametri di
business (bet amount, durata round, fee, ecc.) si configurano dal pannello
admin dopo l'avvio, non qui — vedi guida-admin.md.
Non committare mai .env. È già escluso da .gitignore.
3. Generare la master key
Il server deriva l'indirizzo di deposito di ogni utente (e l'indirizzo pool) da
un'unica master xprv, generata una volta e cifrata a riposo con
XPRV_ENCRYPTION_KEY. Questo passaggio va eseguito esattamente una volta per
ogni deployment, dopo aver impostato XPRV_ENCRYPTION_KEY in .env:
- Locale/venv:
PYTHONPATH=. python scripts/generate_master_key.py - Docker:
docker compose run --rm app python scripts/generate_master_key.py
Questo scrive un file cifrato (MASTER_KEY_PATH, default ./master.xprv.enc in
locale o ./data/keys/master.xprv.enc con Docker). Fai il backup di questo
file insieme a XPRV_ENCRYPTION_KEY — uno dei due da solo è inutile, ma
perderli entrambi insieme significa perdere i fondi di tutti gli utenti senza
possibilità di recupero.
Recuperare o portare una xprv esistente
Due script, entrambi manuali/una tantum, per lo scenario di disaster recovery o per usare una xprv generata altrove (es. offline/air-gapped) invece di farla generare al server:
scripts/decrypt_master_key.py: decifra e stampa a schermo la xprv già presente inMASTER_KEY_PATH(con fallback automatico su./data/keys/master.xprv.encse il path di.envnon esiste in locale). Chiede conferma esplicita prima di stampare.scripts/encrypt_master_key.py: cifra una xprv esterna e la scrive inMASTER_KEY_PATHcon lo stesso identico schema (Fernet +XPRV_ENCRYPTION_KEY) usato dagenerate_master_key.py. La xprv va incollata con input nascosto (non appare a schermo). Si rifiuta di sovrascrivere un file esistente a meno di passare--overwrite.
Entrambi vanno eseguiti localmente (o dentro il container via
docker compose run --rm app ...), mai esposti da un endpoint API o dal
pannello admin: chi ottiene questa xprv ottiene il controllo dei fondi di
tutti gli utenti e del pool.
4. Installare le dipendenze (solo workflow locale/venv)
Salta questo passaggio se usi solo Docker — l'immagine installa le proprie dipendenze durante la build.
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
5. Applicare le migrazioni del database
- Locale/venv:
alembic upgrade head - Docker: le migrazioni vengono eseguite automaticamente all'avvio del
container (vedi il
CMDdelDockerfile) — nessun passaggio manuale.
6. Impostare l'indirizzo delle fee
Prima che si possa aprire il primo round, un admin deve impostare
fee_address tramite il pannello admin o l'API — vedi
guida-admin.md. Finché non è impostato nessun round si
apre, perché il pagamento non si potrebbe costruire.
A questo punto l'istanza è pronta per essere avviata — continua con running-the-server.md.