Files
plm-lottery/docs/come-funziona.md
T
davideandClaude Sonnet 5 88221b0dbd Document the 2026-09-28 specification review and its fixes (B-73..B-97)
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>
2026-09-28 15:51:13 +02:00

11 KiB
Raw Blame History

Come funziona PLM Lottery

Panoramica del funzionamento della piattaforma. È il punto di partenza: ogni sezione rimanda al documento che la approfondisce.

Documento Cosa spiega
registrazione-e-depositi.md Come nasce un account, come arrivano i fondi, come si calcola il saldo mostrato
scommesse-e-prelievi.md Come si piazza una scommessa e come si ritirano i fondi
ciclo-di-vita-del-round.md Apertura, chiusura, estrazione del vincitore, pagamento
transazioni-e-riconciliazione.md Come ogni movimento di denaro viene registrato, inviato, accelerato (RBF) e riconciliato con la catena
connessione-electrum.md Come il server parla con la rete PLM e perché non si fida di un solo server
architettura.md Struttura del codice, processi in background, configurazione, frontend, traduzioni, test
modello-dati.md Tabelle del database, campi, stati, vincoli, migrazioni
api.md Tutti gli endpoint HTTP, formato delle risposte, catalogo dei codici di errore
sicurezza.md Modello di fiducia, chiavi e segreti, autenticazione, limiti sui tentativi, header HTTP
audit-log.md Catalogo degli eventi del registro di audit
operativita.md Backup, riavvii, procedure per gli incidenti
decisioni-e-limiti.md Decisioni di progetto con le loro motivazioni, limiti noti accettati
storico-bug.md Tutti i bug B-nn trovati e corretti, con commit e test
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.

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, il dettaglio tecnico di ogni voce in BUGS.md.

Per installazione e avvio vedi setup.md e running-the-server.md; per l'uso delle interfacce guida-utente.md e 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).
  • 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).
  • 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).
  • 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).
  • 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:

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
  2. Deposito — registrazione-e-depositi.md
  3. Scommessa — scommesse-e-prelievi.md
  4. Round ed estrazione — ciclo-di-vita-del-round.md
  5. Prelievo — scommesse-e-prelievi.md

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).