Lavori in corso

Lavori in corso: stiamo costruendo questo sito in vista della MainNet. I dettagli cambieranno.

Questo sito è ancora in costruzione

ZooBC si costruisce alla luce del sole. Quello che vedi qui è attuale e onesto, ma non è finito: leggilo come il punto in cui siamo oggi, non come una versione definitiva.

Da qui alla MainNet le cose cambieranno: testi, struttura, immagini e cifre. Alcune pagine sono segnaposto.

L'ecosistema ZooBC nel suo insieme arriva per gradi. Il wallet, l'explorer e i canali della community entrano in funzione man mano che la MainNet si avvicina, e questo sito cresce insieme a loro.

Se qualcosa sembra sbagliato, non funziona o appare fuorviante, diccelo. Un feedback adesso vale per noi più di un lancio impeccabile domani.

ZOOBC / MANUALE

App on-chain di ZooBC

Manuale delle app

Tipi di transazione 24, 25, 26, 27, 28 e 39. Corpi, registro delle app, pagamenti e come verificare tu stesso un esito. Trascritto dai sorgenti del nodo.

Un'app su ZooBC è un gioco o una scommessa le cui regole vengono eseguite nel consenso. Ogni mossa è una transazione, la

plancia vive nello stato della catena e la vincita viene pagata dal protocollo. Non c'è alcun server di cui fidarsi, nessun

operatore che possa rifiutarsi di pagare e nessun risultato da accettare sulla fiducia: tutto è

riproducibile dalla cronologia della catena da chiunque, per sempre.

Questo manuale è il riferimento per gli integratori: i sei tipi di transazione, i corpi esatti, il registro

delle app con la codifica delle mosse di ciascuna, come si muove il denaro e come la casualità viene derivata e verificata.

Tutto ciò che trovi qui è trascritto dai sorgenti del nodo, include/zoobc/common/types.h,

src/transaction/app_rules.cpp, e src/transaction/transaction_executor.cpp, non dalle note

di progettazione, che precedono l'implementazione e in alcuni punti se ne discostano.

1. Le tre categorie

CategoriaPostiControparteCasualitàTipi
In solitario contro il banco1il pool delle app del protocollosì, seed del blocco16–21
Testa a testa2un altro giocatoresolo se l'app la usa1–8
Di gruppo3–4altri giocatoridadi dal seed del blocco32–35

Tutte e tre condividono un unico motore: gli stessi tipi di transazione, lo stesso escrow dello stake, la stessa scadenza

per mossa e la stessa regola per cui una mossa è una transazione.

seats determina la categoria e viene confrontato con il tipo di app. Un'app in solitario deve avere seats == 1

e un tipo nell'intervallo 16–31; un'app multigiocatore deve avere seats da 2 a 4 e un tipo fuori da quell'intervallo. Un errore

su questo punto viene respinto all'ammissione nella mempool, non all'esecuzione.

2. Tipi di transazione

Sei tipi. Tutti i corpi sono little-endian; tutti gli importi sono in unità atomiche (dividi per 1e8 per ottenere ZBC).

TipoNomeCorpo
24CreateAppapp_type(1) · stake_token_id(8) · stake_amount(8) · seats(1) · params_len(2) · params · [opponent(36)] · [channel(1)]
25JoinAppapp_id(8)
26AppMoveapp_id(8) · move_len(2) · move_bytes
27ResignAppapp_id(8)
28ClaimAppTimeoutapp_id(8)
39SettleAppapp_id(8) · final_seq(4) · move_count(4) · [seat(1) · move_len(2) · move · signature(64)]*

I due campi finali facoltativi di CreateApp

opponent e channel sono entrambi facoltativi, e quali siano presenti si deduce da quanti byte

restano dopo params:

Byte rimanentiSignificato
0app aperta, gioco on-chain
1channel soltanto
36opponent soltanto
37opponent seguito da channel

Un opponent trasforma l'app in una sfida diretta: solo quell'indirizzo può unirsi. Se lo ometti, chiunque

può occupare il posto. channel = 1 contrassegna un'app a canale di stato ed è valido solo quando seats == 2.

Le app multigiocatore memorizzano i giocatori in slot fissi da 36 byte, quindi ogni indirizzo seduto al tavolo deve essere canonico a 36 byte (un indirizzo ZBC o una semplice chiave pubblica da 32 byte). Gli account che non sono da 36 byte vengono respinti alla creazione. Le app in solitario non hanno questa restrizione: c'è un solo giocatore.

3. Il registro delle app

app_type è un singolo byte. Sono noti solo questi valori; qualsiasi altro viene respinto.

Testa a testa (2 posti)

TipoAppPlancia / statoByte della mossa
1Tris9 caselle[cell 0..8]
2Scacchi64 case[from, to], legalità completa, scacco, scacco matto, stallo, promozione automatica a donna
3Connect-442 caselle (7×6)[column 0..6], gravità, 4 in fila
4Dama64 caselle + blocco della presa multipla[from, to], presa obbligatoria, prosecuzione della presa multipla, dame
5Reversi64 caselle[cell 0..63], bisogna girare almeno una pedina; chi non ha mosse passa; vince chi ha più pedine
6Gomoku225 caselle (15×15)[x, y], 5 in fila
7Battaglia navale6400 di commitment + 200 di rivelazionecommit-reveal, vedi sotto
8Punti e quadrati24 lati + 9 quadrati[edge 0..23], chi completa un quadrato muove ancora

In solitario contro il banco

TipoAppparamsPaga
16Due dadi[bet_type 0..3, total]sotto il 7 / sopra il 7 2.28×, 7 fortunato 5.7×, totale esatto 3420/ways %
17Testa o croce[choice 0/1]1.98×
18Roulette[bet_type, value]numero singolo 36×, colore 2×
19Slotnessunotris 15×, triplo 7 50×, qualsiasi coppia 1.8×
20Lotteria[pick 0..99]90×
21Crash[target ×100, 2 bytes LE]target ×, da 1.01× a 10.00×

I tipi di puntata per i dadi sono 0 sotto il 7, 1 7 fortunato, 2 sopra il 7, 3 totale esatto. Per un totale esatto il

moltiplicatore è 3420 / ways in centesimi, dove ways = 6 - |7 - total|, quindi il 7 paga 5.70× e il 2 o il

12 pagano 34.20×. La roulette ha 37 caselle; lo 0 è verde e perde su entrambi i colori.

Di gruppo (3–4 posti)

TipoAppStatoByte della mossa
32Ludoseats×4 posizioni delle pedine + dado in sospesoin due fasi: tira, poi scegli una pedina
33Pigseats punteggi + totale del turno[0 roll, 1 hold]
34Corsa (scale e serpenti)seats posizioni[0], tira
35Monopoli semplificatodenaro, posizioni, proprietà, bancarotta, fasein due fasi: tira, poi eventualmente compra

4. Denaro

Stake. CreateApp mette in escrow lo stake del creatore. Ogni JoinApp mette in escrow uno stake uguale. Il piatto

è la somma. Un stake_token_id pari a 0 indica ZBC; qualsiasi altro valore usa come stake quel token colorato, e

l'intera app (piatto, rake, vincita) viene regolata in quel token.

Rake. In caso di esito decisivo, l'1% del piatto va al pool delle app e il vincitore riceve il

resto. In caso di pareggio o di app annullata, ogni stake viene rimborsato e non si trattiene alcun rake.

Il pool delle app è un account di protocollo con un saldo per ciascun token. Cresce grazie a quel rake dell'1% più

il vantaggio del banco nelle app in solitario. È la controparte di ogni puntata in solitario, quindi è il suo saldo a rendere

possibile il gioco in solitario; puoi consultarlo in qualsiasi momento:


GET https://zoobc.network/api/v1/apps/pool

Tetto del bankroll. La vincita massima possibile di una singola puntata in solitario non può superare il 5% del pool per

quel token. Il controllo si basa sul caso peggiore della puntata per il banco, non sulla sua media, quindi nessuna

singola vincita può prosciugare il pool. Una puntata che lo supererebbe viene respinta: se una puntata elevata viene rifiutata,

di solito il motivo è questo.

5. La casualità, e come verificarla

Le app in solitario si risolvono a partire dal seed del blocco, che su ZooBC è

block_seed = blocksmith_signature(SHA3(previous_block.block_seed)), deterministico, verificabile

pubblicamente con la chiave pubblica del blocksmith e impossibile da conoscere prima che il blocco esista.

Una puntata inserita nel blocco all'altezza H si risolve a H + 2:


r = SHA3-256( block_seed[H+2] ‖ app_id )   →   the low 8 bytes, little-endian, as a uint64

Il giocatore si impegna due blocchi prima che esista il seed con cui la puntata verrà risolta, quindi non può

né prevederlo né sceglierlo. Chiunque può ricalcolare r in seguito a partire dal seed del blocco e dall'id dell'app, e

quindi ricalcolare l'esito. Nulla del risultato dipende da dati che la catena non contiene.

Crash ricava il suo punto di crash dallo stesso r:


u = r mod 1e6
C = 99_000_000 / (1_000_000 - u)      clamped to [100, 1000], i.e. 1.00× .. 10.00×

La puntata vince stake × target / 100 quando C >= target. Il 99 al numeratore è il vantaggio

del banco, l'1%. Il limite di 10.00× è il tetto, quindi la vincita massima possibile a Crash è dieci volte la puntata.

Giocata multipla. Qualsiasi app in solitario può essere giocata fino a 100 volte con una sola puntata. Aggiungi in coda un byte

di conteggio N a params, dopo i byte di scelta di quell'app. Lo stake viene diviso in parti uguali tra le N giocate

e le vincite vengono sommate, così una transazione e una rivelazione producono N esiti indipendenti senza

attendere un blocco per ciascuno. Omettere N significa una singola giocata, e una singola giocata è identica bit per bit a come

sarebbe stata prima che esistesse la giocata multipla. N deve essere compreso tra 1 e 100 e lo stake deve dividersi in modo che ogni giocata

punti almeno un'unità.

6. Turni, scadenze e conclusioni

Un'app diventa attiva quando viene occupato l'ultimo posto. Da quel momento ogni mossa accettata imposta


deadline_height = current_height + 240        (~1 hour at 15 s per block)

Una mossa viene accettata solo dal giocatore di turno, solo mentre l'app è attiva e solo

prima che scada il termine. Un'app può concludersi in quattro modi:

  • Una vittoria o un pareggio secondo le regole. Regolata immediatamente: il vincitore viene pagato, oppure, in caso di pareggio, tutti gli stake vengono rimborsati.
  • ResignApp. Abbandoni; la tua quota del piatto va all'avversario.
  • ClaimAppTimeout. Il tuo avversario ha lasciato scadere il termine di 240 blocchi. Lo rivendichi e vinci il piatto.

Sta a te rivendicarlo: non succede nulla in automatico solo perché il termine è scaduto.

  • Nessuno si unisce. Un'app aperta che nessuno accetta viene annullata e lo stake rimborsato.

7. Canali di stato e SettleApp

In un'app testa a testa, giocare ogni mossa on-chain costa una transazione e un blocco per mossa. Un

canale di stato sostituisce tutto questo con un unico regolamento: crea con channel = 1 e seats = 2, gioca

off-chain con ciascuna parte che firma ogni mossa e invia l'intera partita una sola volta come SettleApp (tipo 39).

La catena riesegue le mosse firmate, in ordine, a partire dallo stato iniziale dell'app attraverso lo stesso motore

di regole, verifica ogni firma e ogni turno e paga il vincitore. Un regolamento può essere sostituito da

uno con un final_seq più alto per 240 blocchi dopo la sua inclusione; una volta trascorsa quella finestra

di contestazione, diventa definitivo.

Sul corpo vengono applicati tre limiti, e un integratore deve rispettarli tutti e tre:

  • final_seq deve essere uguale a move_count.
  • move_count non può superare 1024 voci.
  • move_count non può superare ciò che il resto del corpo può fisicamente contenere. Ogni voce occupa almeno 67

byte, seat(1) + move_len(2) + signature(64), quindi un conteggio superiore a remaining / 67 viene

respinto prima che venga allocato un solo byte.

Il limite di 1024 voci si riferisce alle semimosse, non alle coppie di mosse: una voce è una semimossa, quindi un regolamento da 1024 voci copre una partita di 512 mosse. La partita a scacchi più lunga mai registrata è durata 269 mosse, cioè 538 semimosse, quindi il tetto è circa il doppio della partita più lunga mai giocata davvero.

8. Battaglia navale (tipo 7)

Battaglia navale è l'unica app testa a testa che richiede informazioni nascoste, quindi usa lo schema commit-reveal.

La plancia è 10×10. Per ciascuna delle 100 caselle il giocatore sceglie un salt casuale da 32 byte e impegna

SHA3(is_ship ‖ salt); il commitment è la concatenazione di quei 100 hash, 3200 byte, passata come

params alla creazione. seats deve valere 2 e il commitment deve essere di esattamente 3200 byte, altrimenti la creazione viene

respinta.

Il gioco alterna due tipi di mossa:

  • Fuoco [0, cell]: spari a una casella della plancia avversaria. Il turno passa all'avversario, che deve rivelare.
  • Rivelazione [1, cell, is_ship, salt(32)]: l'avversario dimostra cosa c'era aprendo il commitment

di quella sola casella. Poiché ogni casella è impegnata separatamente, un giocatore non può mentire su nessuna casella.

Viene registrato se il colpo è andato a segno o a vuoto, poi tocca a chi ha rivelato sparare.

Colpisci tutte le 17 caselle delle navi e vinci. Un giocatore che non rivela è soggetto alla scadenza come per qualsiasi altra mossa,

quindi si applica ClaimAppTimeout.

Le commissioni crescono con la dimensione. Una creazione da 3200 byte è una transazione grande, e la commissione minima cresce con la dimensione della transazione. Su una catena attiva una commissione di 0.1 ZBC è stata respinta perché troppo bassa, mentre circa 5 ZBC sono stati accettati. Mettilo in conto alla creazione; le mosse di fuoco e di rivelazione sono piccole ed economiche.

9. Leggere lo stato delle app

Cinque endpoint, serviti dall'API del nodo; nota che sono endpoint del nodo, non di archivio:

URL di base https://zoobc.network/api/v1. È il gateway pubblico della TestNet di ZooBC, non la MainNet.

EndpointRestituisce
GET /api/v1/appsla lobby; filtra con status=, category=solo|pvp|party, limit=
GET /api/v1/apps/opensfide testa a testa aperte a cui chiunque può unirsi
GET /api/v1/apps/:idlo stato completo di un'app
GET /api/v1/apps/pooli saldi del pool delle app, per token
GET /api/v1/apps/statsconteggi in tempo reale: totali, aperte, attive, concluse, giocatori, piatto in gioco

Una riga di app contiene id, app_type, status (0 aperta, 1 attiva, 2 conclusa, 3 annullata), seats,

creator_address, players, opponent_address, stake_token_id, stake_amount, pot,

state_blob, turn, created_height, last_move_height, deadline_height, resolve_height,

winner_address, persist_height e channel.

Lo state_blob è la plancia derivata corrente, conservata perché un nodo non debba rieseguire la cronologia a ogni blocco.

È una comodità, non il registro: il registro sono le transazioni delle mosse, e un client può rieseguirle

per verifica o animazione. La riga attiva di un'app conclusa viene eliminata dopo un periodo di tolleranza; le sue mosse restano

per sempre nella cronologia della catena, quindi l'app è sempre ricostruibile.

10. Dalla riga di comando

zoobc-cli copre tutti e sei i tipi. Il primo parametro è sempre la chiave privata del mittente.

ComandoTipo
app-create24
app-join25
app-move26
app-resign27
app-claim28
app-settle39

# a coin-flip against the house: type 17, 1 ZBC, seats=1, choice 0
zoobc-cli app-create <privkey> 17 0 100000000 1 00 --api $API

# tic-tac-toe, open to anyone, 1 ZBC
zoobc-cli app-create <privkey> 1 0 100000000 2 --api $API

# take the middle square
zoobc-cli app-move <privkey> <app_id> 04 --api $API

zoobc-cli help app-create elenca i campi di ciascuno. Consulta il Manuale della CLI per l'insieme completo

dei comandi e il Manuale delle transazioni per la struttura in byte di tutti i 50 tipi di transazione.

11. Costanti

CostanteValoreCosa regola
Rake1% del piattoal pool delle app, solo in caso di esito decisivo
Scadenza della mossa240 blocchi~1 ora; si azzera a ogni mossa accettata
Risoluzione in solitarioaltezza della puntata + 2~30 secondi
Tetto del bankroll5% del poolvincita massima di una singola puntata in solitario
Tetto della giocata multipla100giocate per puntata in solitario
Tetto delle mosse nel regolamento1024voci per SettleApp, ≥67 byte ciascuna
Finestra di contestazione del regolamento240 blocchi~1 ora durante la quale prevale un final_seq più alto
Posti1, oppure 2–41 è in solitario; 2–4 è multigiocatore
Commitment di Battaglia navale3200 byteesatti, altrimenti la creazione viene respinta