Document the three sequential block confirmations behind the draw/payout timing

CLAUDE.md and the user/admin guides only mentioned "a confirmed block" for
the draw, leaving the actual end-to-end timing (why it can take several
minutes after the countdown hits zero) unclear. Spell out the three distinct
confirmations in sequence — last pending bet, draw block, payout tx — and
the resulting best/worst-case wall-clock estimates.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 14:14:09 +02:00
co-authored by Claude Sonnet 5
parent 7dcf6d2756
commit 9fa7eec378
3 changed files with 22 additions and 4 deletions
+7
View File
@@ -102,6 +102,13 @@ The flow is organized into 5 phases, each a subgraph in [flowchart.mmd](flowchar
PLAY and WITHDRAW share a **per-user DB lock**: a user can never have a bet-build and a withdrawal-build in flight at the same time, since both would otherwise spend from the same UTXO set on the user's dedicated address.
**Three separate on-chain confirmations, not one, between the timer hitting zero and the payout landing** — a common point of confusion, worth spelling out explicitly:
1. **Last bet's confirmation** (`scheduler.py`'s `_tick`, the `pending_count` check before `_close_and_draw`) — the round doesn't even flip to `"closing"` until every already-broadcast bet has its 1st confirmation. This can already have happened before the timer expired; it's the earliest of the three and not necessarily tied to the deadline at all.
2. **The draw block** (`_wait_for_next_block`, waits for `tip_height > tip_at_close`, where `tip_at_close` is recorded only once step 1 is done) — by construction this must be a **later, different block** than whichever one confirmed the last bet in step 1.
3. **Payout confirmation**`_trigger_payout` broadcasts only after step 2's block is known, then registers a `PendingTransaction(kind="payout")` that the same generic `ConfirmationPoller` (`app/tx/confirmation.py`) waits on independently — this needs **yet another, later block** than step 2's, since the payout can't be built before the winner is known.
So worst case (last bet confirms right at the deadline) is ~3 block times end-to-end; best case (all bets already confirmed before the timer hit zero) is ~2 (draw block + payout block). At PLM's 120s block time that's roughly 46 minutes worst case, 24 minutes best case — independent of `draw_animation_seconds`, which only sets a cosmetic minimum for the frontend animation.
## Admin dashboard and test UI
Two static single-page apps, served directly by FastAPI (`app/main.py` mounts `app/static/` and adds a dedicated `GET /admin` route) — no build step, no framework:
+1 -1
View File
@@ -40,7 +40,7 @@ business — quelli si toccano solo da qui.
| **Bet amount (PLM)** | Il costo fisso d'ingresso per round. |
| **Durata round (secondi)** | Quanto resta aperto un round prima di chiudersi ed estrarre il vincitore. Il taglio per le nuove giocate scatta esattamente allo scadere di questo tempo (verificato ad ogni bet, non dipende dal ciclo dello scheduler) — è un "semaforo giallo": nessuna nuova entrata, ma le bet già trasmesse prima dello scadere hanno comunque tempo di confermarsi prima che il round chiuda ed estragga. |
| **Pausa tra un round e il successivo (secondi)** | Cooldown dopo la chiusura di un round, prima che il successivo si apra — dà tempo ai giocatori di vedere l'esito. |
| **Durata animazione estrazione (secondi)** | Tempo minimo per cui la dashboard di ogni utente mostra l'animazione "Estrazione in corso" dopo la chiusura del round, prima di rivelare il vincitore. È solo un minimo: l'estrazione reale aspetta un blocco confermato (~2 minuti in media), quindi l'animazione può durare più a lungo di questo valore, mai meno. |
| **Durata animazione estrazione (secondi)** | Tempo minimo per cui la dashboard di ogni utente mostra l'animazione "Estrazione in corso" dopo la chiusura del round, prima di rivelare il vincitore. È solo un minimo: il processo reale aspetta fino a 3 blocchi confermati in sequenza (ultima bet in sospeso, estrazione, payout — ~2 minuti l'uno), quindi l'animazione può durare più a lungo di questo valore, mai meno. |
| **Importo minimo deposito/prelievo (PLM)** | Soglia minima per un prelievo (i depositi non hanno un controllo minimo lato server, solo un floor consigliato). |
| **Fee rate di rete (sat/vB)** | Fee per byte usata per costruire bet, payout e prelievi. |
| **Timeout prima del fee-bump RBF (secondi)** | Dopo quanto tempo senza conferma una transazione viene ritrasmessa con fee più alta. |
+14 -3
View File
@@ -45,9 +45,20 @@ round. Solo a quel punto la card mostra un'animazione ("Estrazione del
vincitore in corso…") al posto del timer — la stessa cosa compare nella
dashboard di ogni giocatore, non solo la tua. L'animazione resta visibile
per almeno un tempo minimo configurabile dall'admin (default 20s), ma può
durare più a lungo: il vincitore viene scelto usando l'hash del primo
blocco confermato dopo la chiusura, quindi il tempo reale dipende dalla
rete (mediamente ~2 minuti, il block time di PLM).
durare più a lungo, perché sotto la copertina servono **fino a tre
conferme sulla rete PLM in sequenza**, una diversa dall'altra:
1. conferma dell'ultima giocata rimasta in sospeso (se ce n'era una proprio
allo scadere del timer — altrimenti questo passo è già superato);
2. un nuovo blocco dopo la chiusura, il cui hash serve a scegliere il
vincitore;
3. la conferma della transazione che paga effettivamente la vincita.
Con un blocco PLM ogni ~2 minuti, il tempo reale dall'azzeramento del
timer all'accredito della vincita è quindi in media **4-6 minuti** (se
c'era una giocata da confermare all'ultimo istante) o **2-4 minuti** (se
tutte le giocate erano già confermate prima dello zero) — non pochi
secondi, ed è normale.
Appena il vincitore è determinato, l'animazione lascia spazio a un
messaggio: