- 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>
195 lines
11 KiB
Markdown
195 lines
11 KiB
Markdown
# Come funziona PLM Lottery
|
||
|
||
Panoramica del funzionamento della piattaforma (l'indice completo della
|
||
documentazione è [README.md](README.md)). È il punto di partenza: ogni
|
||
sezione rimanda al documento che la approfondisce.
|
||
|
||
| Documento | Cosa spiega |
|
||
|---|---|
|
||
| [registrazione-e-depositi.md](registrazione-e-depositi.md) | Come nasce un account, come arrivano i fondi, come si calcola il saldo mostrato |
|
||
| [scommesse-e-prelievi.md](scommesse-e-prelievi.md) | Come si piazza una scommessa e come si ritirano i fondi |
|
||
| [ciclo-di-vita-del-round.md](ciclo-di-vita-del-round.md) | Apertura, chiusura, estrazione del vincitore, pagamento |
|
||
| [transazioni-e-riconciliazione.md](transazioni-e-riconciliazione.md) | Come ogni movimento di denaro viene registrato, inviato, accelerato (RBF) e riconciliato con la catena |
|
||
| [connessione-electrum.md](connessione-electrum.md) | Come il server parla con la rete PLM e perché non si fida di un solo server |
|
||
| [architettura.md](architettura.md) | Struttura del codice, processi in background, configurazione, frontend, traduzioni, test |
|
||
| [modello-dati.md](modello-dati.md) | Tabelle del database, campi, stati, vincoli, migrazioni |
|
||
| [api.md](api.md) | Tutti gli endpoint HTTP, formato delle risposte, catalogo dei codici di errore |
|
||
| [sicurezza.md](sicurezza.md) | Modello di fiducia, chiavi e segreti, autenticazione, limiti sui tentativi, header HTTP |
|
||
| [audit-log.md](audit-log.md) | Catalogo degli eventi del registro di audit |
|
||
| [operativita.md](operativita.md) | Backup, riavvii, procedure per gli incidenti |
|
||
| [adr/](adr/README.md) | Le decisioni di progetto con le loro motivazioni, una per file (ADR) |
|
||
| [limiti-noti.md](limiti-noti.md) | Limiti noti accettati |
|
||
| [storico-bug.md](storico-bug.md) | Tutti i bug B-nn trovati e corretti, con commit e test |
|
||
| [piano-correzioni.md](piano-correzioni.md) | Decisioni della revisione del 2026-09-28 e ordine in cui implementare le correzioni ancora aperte |
|
||
|
||
Questi documenti sono la **specifica** del software: ogni regola ha un
|
||
identificativo stabile (ad esempio `RND-11`) con il riferimento al codice che
|
||
la implementa. Come si usano per modificare il software è spiegato in
|
||
[processo-di-modifica.md](processo-di-modifica.md).
|
||
|
||
Dalla revisione del 2026-09-28 la specifica descrive il comportamento
|
||
**atteso**, che in alcuni punti è più avanti del codice. I requisiti che il
|
||
codice non soddisfa ancora sono marcati `*Stato:* da implementare (B-nn)` e
|
||
dicono in una riga cosa fa il codice oggi (`git grep "da implementare"` li
|
||
elenca tutti); anche questa panoramica descrive il comportamento atteso. Le
|
||
decisioni prese e l'ordine di implementazione sono in
|
||
[piano-correzioni.md](piano-correzioni.md), il dettaglio tecnico di ogni voce
|
||
in [BUGS.md](../BUGS.md).
|
||
|
||
Per installazione e avvio vedi [setup.md](setup.md) e
|
||
[running-the-server.md](running-the-server.md); per l'uso delle interfacce
|
||
[guida-utente.md](guida-utente.md) e [guida-admin.md](guida-admin.md).
|
||
|
||
## In una frase
|
||
|
||
Gli utenti depositano PLM su un indirizzo personale custodito dal server,
|
||
comprano un biglietto a costo fisso per il round in corso, e allo scadere del
|
||
round un seme che combina un segreto su cui il server si è impegnato
|
||
all'apertura, l'hash di un blocco successivo alla chiusura e l'elenco dei
|
||
partecipanti sceglie un vincitore, che riceve il 70% del montepremi; il 30%
|
||
va alla piattaforma.
|
||
|
||
## Scelte di fondo
|
||
|
||
- **Custodiale.** Le chiavi sono generate e tenute dal server (una master xprv
|
||
cifrata a riposo). L'utente non controlla nulla finché non preleva.
|
||
- **Un indirizzo per utente, per sempre.** Lo stesso indirizzo serve per i
|
||
depositi, riceve le vincite e riceve il resto di ogni scommessa e prelievo.
|
||
- **Nessun nodo completo.** Tutto l'accesso alla rete passa dal protocollo
|
||
Electrum (vedi [connessione-electrum.md](connessione-electrum.md)).
|
||
- **6 conferme per i depositi, 1 per tutto il resto.** Il deposito è l'unico
|
||
ingresso che un utente può spendere due volte, perché scommesse, pagamenti
|
||
e prelievi li firma solo il server; le uscite coinbase richiedono 120
|
||
conferme (vedi [registrazione-e-depositi.md](registrazione-e-depositi.md#deposito)).
|
||
- **Estrazione con commit-reveal.** All'apertura il server si impegna su un
|
||
segreto pubblicandone l'impronta; alla chiusura si fissano elenco dei
|
||
partecipanti e altezza del blocco; il segreto viene rivelato dopo
|
||
l'estrazione. Chi produce i blocchi non può calcolare il vincitore e
|
||
l'operatore non può cambiare il segreto; chiunque può verificare il
|
||
risultato con la prova pubblica (vedi
|
||
[ciclo-di-vita-del-round.md](ciclo-di-vita-del-round.md#3--estrazione)).
|
||
- **Un indirizzo del montepremi per ogni round**, così soldi e cronologia di
|
||
un round restano separati da quelli degli altri.
|
||
- **Nel dubbio non si liberano i fondi.** Una transazione viene annullata solo
|
||
con una prova, mai per un timeout o per il silenzio di un solo server (vedi
|
||
[transazioni-e-riconciliazione.md](transazioni-e-riconciliazione.md)).
|
||
- **Parametri operativi nel database**, modificabili a caldo da `/admin`
|
||
(costo della scommessa, durata del round, commissioni…). Nel file `.env`
|
||
restano solo segreti e collegamenti infrastrutturali.
|
||
|
||
## Le cinque fasi
|
||
|
||
Diagramma del **comportamento atteso**:
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph REG["1 · Registrazione"]
|
||
direction TB
|
||
A1["Username + password"] --> A2["Il server deriva un indirizzo<br/>dedicato e permanente"]
|
||
end
|
||
|
||
subgraph DEP["2 · Deposito"]
|
||
direction TB
|
||
B1["L'utente invia PLM<br/>al proprio indirizzo"] --> B2{"6 conferme e<br/>corroborato dagli<br/>altri server?"}
|
||
B2 -- "No" --> B1b["Si riprova al prossimo<br/>aggiornamento"] --> B2
|
||
B2 -- "Sì" --> B3["Saldo accreditato"]
|
||
end
|
||
|
||
subgraph PLAY["3 · Scommessa"]
|
||
direction TB
|
||
C1{"Saldo sufficiente,<br/>nessuna scommessa attiva,<br/>round aperto e non pieno?"}
|
||
C1 -- "Sì" --> C2["Transazione: indirizzo utente →<br/>montepremi del round, resto all'utente"]
|
||
C2 --> C3{"Confermata?"}
|
||
C3 -- "No, troppo tempo" --> C4["Commissione aumentata<br/>(RBF) e reinvio"] --> C3
|
||
C3 -- "Sì" --> C5["Partecipante del round"]
|
||
end
|
||
|
||
subgraph DRAW["4 · Round ed estrazione"]
|
||
direction TB
|
||
D0["Apertura: indirizzo del montepremi<br/>del round, impronta del segreto pubblicata"] --> D1["Scadenza del round"]
|
||
D1 --> D2["Si attendono le scommesse<br/>già in volo"]
|
||
D2 --> D3["Si fissano partecipanti<br/>e altezza del blocco"]
|
||
D3 --> D3b["Blocco con 3 conferme, header<br/>concordato dal quorum:<br/>segreto + blocco + partecipanti<br/>scelgono il vincitore"]
|
||
D3b --> D3c["Segreto rivelato,<br/>prova pubblica"]
|
||
D3c --> D3d{"Scommesse ancora<br/>sulla catena?"}
|
||
D3d -- "Sì (quelle sparite<br/>sono escluse)" --> D4["70% al vincitore, 30% alla piattaforma<br/>meno la riserva per l'RBF"]
|
||
D3d -- "Sparita quella<br/>del vincitore" --> D5["Pagamento bloccato,<br/>lotteria in pausa"]
|
||
end
|
||
|
||
subgraph WITHDRAW["5 · Prelievo"]
|
||
direction TB
|
||
E1["Indirizzo esterno + importo"] --> E2["Transazione: indirizzo utente →<br/>esterno, resto all'utente"]
|
||
E2 --> E3{"Confermata?"}
|
||
E3 -- "No, troppo tempo" --> E4["RBF e reinvio"] --> E3
|
||
E3 -- "Sì" --> E5["Saldo aggiornato"]
|
||
end
|
||
|
||
A2 --> B1
|
||
B3 --> C1
|
||
B3 --> E1
|
||
C5 --> D1
|
||
D4 -.->|"round successivo"| C1
|
||
```
|
||
|
||
1. **Registrazione** — [registrazione-e-depositi.md](registrazione-e-depositi.md#registrazione)
|
||
2. **Deposito** — [registrazione-e-depositi.md](registrazione-e-depositi.md#deposito)
|
||
3. **Scommessa** — [scommesse-e-prelievi.md](scommesse-e-prelievi.md#scommessa)
|
||
4. **Round ed estrazione** — [ciclo-di-vita-del-round.md](ciclo-di-vita-del-round.md)
|
||
5. **Prelievo** — [scommesse-e-prelievi.md](scommesse-e-prelievi.md#prelievo)
|
||
|
||
## Componenti
|
||
|
||
Un solo processo Python (FastAPI) dietro Caddy, con un database SQLite. Dentro
|
||
il processo girano, oltre all'API HTTP, sei attività in background avviate
|
||
all'avvio del server:
|
||
|
||
| Attività | Ogni | Cosa fa |
|
||
|---|---|---|
|
||
| `ElectrumListener` | connessione continua, ping ogni 60s | L'unica connessione alla rete: riceve i nuovi blocchi, osserva gli indirizzi di tutti gli utenti, accredita i depositi |
|
||
| `RoundScheduler` | 5s | Apre e chiude i round, esegue l'estrazione, avvia e riprova i pagamenti |
|
||
| `ConfirmationPoller` | 10s | Porta le transazioni da "in attesa" a "confermate" |
|
||
| `RbfBumper` | 30s | Aumenta la commissione di ciò che non conferma entro il tempo limite |
|
||
| `PendingTransactionReconciler` | all'avvio, poi 120s | Confronta con la catena ogni transazione rimasta a metà |
|
||
| `DepositReconciler` | 300s | Ricontrolla tutti gli indirizzi, nel caso una notifica sia andata persa |
|
||
|
||
La cadenza di queste attività è ciò che determina quanto in fretta il sistema
|
||
si ripara da solo dopo un problema.
|
||
|
||
Le due interfacce web sono pagine statiche servite dallo stesso server, senza
|
||
build né framework:
|
||
|
||
- **`/`** — l'interfaccia per i giocatori (registrazione, deposito, scommessa,
|
||
prelievo, profilo, stato del round), tradotta in 7 lingue.
|
||
- **`/admin`** — il pannello operatore, protetto da un token condiviso,
|
||
in italiano.
|
||
|
||
Entrambe interrogano periodicamente l'API e in più ascoltano un canale
|
||
**SSE** (`GET /rounds/stream`): un semplice segnale "è cambiato qualcosa,
|
||
ricarica" inviato a ogni evento rilevante (round aperto o cambiato di stato,
|
||
scommessa o prelievo inviato, transazione confermata, deposito accreditato,
|
||
nuovo blocco). Se il canale cade, le pagine continuano a funzionare con il
|
||
solo polling.
|
||
|
||
## Parametri principali
|
||
|
||
| Parametro | Valore predefinito | Modificabile |
|
||
|---|---|---|
|
||
| Costo della scommessa | 10 PLM | da `/admin`, vale dal round successivo (B-95) |
|
||
| Ripartizione del montepremi | 70% vincitore / 30% piattaforma | no, è nel codice |
|
||
| Durata del round | 600s | da `/admin`, vale dal round successivo |
|
||
| Pausa tra un round e l'altro | 30s | da `/admin`, vale dal round successivo |
|
||
| Commissione di rete | 1 sat/vB | da `/admin` |
|
||
| Tempo prima di un RBF | 900s | da `/admin` |
|
||
| Prelievo minimo | pari al costo della scommessa | segue il costo |
|
||
| Deposito minimo | nessuno | — |
|
||
| Partecipanti massimi per round | 400 | no, è nel codice |
|
||
| Tetto al montepremi del round (`max_round_pool_sats`) | 0 = nessun tetto (B-95) | da `/admin`, vale dal round successivo |
|
||
| Conferme per i depositi (`deposit_confirmations`) | 6; 120 per le uscite coinbase (B-82) | da `/admin`; le 120 coinbase no, sono nel codice |
|
||
| Conferme sul blocco di estrazione (`draw_confirmations`) | 3 (B-73) | da `/admin`, vale dal round successivo |
|
||
| Conferme per scommesse, pagamenti, prelievi | 1 | no, è nel codice |
|
||
| Indirizzo del montepremi | uno per round, `m/84'/746'/0'/2/<id_round>` (B-80) | no, è nel codice |
|
||
| Riserva per l'RBF sul pagamento | `max(294 sat, dimensione stimata × 10 sat/vB)`, tolta dalla quota della piattaforma, verso `m/84'/746'/0'/1/0` (B-79) | no, è nel codice |
|
||
|
||
Un B-nn nella tabella indica un parametro del comportamento atteso non ancora
|
||
implementato (vedi [piano-correzioni.md](piano-correzioni.md)).
|