Files
plm-lottery/docs/come-funziona.md
T
davideandClaude Sonnet 5.5 b424f670c5 Restructure docs: docs-first, SSOT, one ADR per decision
- 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>
2026-10-14 12:05:57 +02:00

195 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)).