Wiki di ZooBC
App e sviluppo su ZooBC

Costruire un'app come singola pagina HTML

Un'applicazione ZooBC può essere un unico file HTML senza alcun server dietro. La pagina legge la catena dall'API HTTP di un nodo, costruisce e firma le transazioni nel browser con la chiave dell'utente e invia i byte firmati. Gli utenti non gestiscono un nodo, e non c'è alcuna chiave API da richiedere. Il wallet ufficiale ne è la prova: è esso stesso un unico file HTML, che ogni nodo serve su / e /wallet (wallet web).

Un unico file HTML legge con GET, firma nel browser e invia byte firmati a un nodo o a un gateway.
Un unico file HTML legge con GET, firma nel browser e invia byte firmati a un nodo o a un gateway.

L'API del nodo

Ogni nodo offre un'API HTTP/1.1 in chiaro, per impostazione predefinita sulla porta 8080, con più di cento route sotto /api/v1/: blocchi, account, token, app, l'exchange e altro (API del nodo). Ogni risposta contiene queste intestazioni, e una richiesta OPTIONS riceve subito 200, quindi una pagina ospitata ovunque può chiamare qualsiasi nodo:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, X-Node-Public-Key, X-Timestamp, X-Signature

Il nodo stesso non ha TLS. I domini pubblici terminano il TLS su un gateway, che aggiunge le proprie intestazioni CORS. I browser bloccano le chiamate in HTTP semplice da una pagina caricata in HTTPS, quindi una pagina pubblica dialoga con un gateway.

Tutte le route tranne otto sono letture non autenticate, e inviare una transazione non richiede chiavi di alcun tipo, perché la transazione porta con sé la propria firma. I limiti si applicano per indirizzo del client: 300 richieste di scrittura al minuto, poi 429 con un'intestazione Retry-After; le letture sono illimitate a meno che l'operatore non fissi un limite; e 20 autenticazioni firmate fallite in 5 minuti bloccano il client per 300 secondi.

Firmare nel browser

La pagina firma un digest che lega la transazione a una sola catena:

digest = SHA3-256("ZBC-TX" ‖ genesis hash ‖ unsigned transaction bytes)

Un account nativo lo firma con Ed25519. La pagina legge genesis_hash e signing_version (2) da GET /api/v1/node/info, e poiché l'hash genesi è dentro il digest, una firma fatta per una catena non vale nulla su un'altra (firme legate alla catena). Non serve alcun SDK: bastano Ed25519, SHA3-256 e l'hash genesi, e la struttura dei byte è descritta nell'articolo involucro della transazione. Gli strumenti pubblici offrono anche librerie pronte, compreso un file JavaScript senza dipendenze da includere con un tag script (strumenti da riga di comando). La chiave non lascia mai la pagina.

Inviare e seguire

POST /api/v1/transactions               → 202, with "transaction_hash"
GET  /api/v1/transactions/<hash>/status → staging, mempool, confirmed (with block_height),
                                          rejected (with the reason and stage), or 404 not_found

Un 202 significa accettata, non completata. Il nodo ha interpretato la transazione, eseguito le prime verifiche e l'ha presa in staging; un produttore di blocchi deve ancora includerla. Finché lo stato non dice confirmed, nessun saldo è cambiato. Con un blocco ogni 15 secondi, interrogare ogni paio di secondi è più che sufficiente.

Se una risposta va persa, reinvia gli stessi identici byte firmati. L'hash della transazione è lo SHA3-256 dei byte non firmati e della firma, quindi un nodo che detiene già la transazione risponde 202 con "duplicate": true, aggiungendo "state": "confirmed" una volta che è in un blocco, e la transazione viene eseguita una sola volta. Firmare di nuovo con un nuovo timestamp crea una transazione diversa, ed è così che nascono i pagamenti doppi.

Per impostazione predefinita un blocco può includere una transazione fino a 3.600 secondi dopo il suo timestamp; una transazione di versione 3 indica la propria finestra, fino a 86.400 secondi; e un timestamp più di 3.600 secondi nel futuro viene rifiutato (scadenza e timestamp). Prima di consegnare merce a fronte di un pagamento, attendi la conferma, poi il flag finalized, che una transazione ottiene quando un blocco spine co-firmato copre il suo blocco (finalità e rollback). L'API riporta anche finalized_height, il block_seed_proof di ogni blocco, la expiry di una transazione e i blocchi spine su /spine/blocks/:height.

Dopo il 202: staging, mempool, confirmed, finalized; una risposta persa si reinvia con gli stessi byte.
Dopo il 202: staging, mempool, confirmed, finalized; una risposta persa si reinvia con gli stessi byte.

Route per le app

È il nodo stesso, non il servizio di archivio, a servire le route delle app: /apps (filtri status, limit e category, che può essere solo, pvp o party), /apps/open, /apps/pool, /apps/stats, /apps/:id (con l'eventuale regolazione) e /accounts/:a/apps.

Lista di controllo

  • Leggi tramite un gateway in HTTPS; scrivi inviando byte firmati, con la chiave tenuta nella pagina.
  • Segui le transazioni tramite hash, e ritenta reinviando gli stessi byte, mai firmando di nuovo.
  • Rispetta 429 e Retry-After.
  • Mostra il testo della catena con textContent (dati della catena sono input non attendibile).
  • Considera «confirmed» come ricevuto e «finalized» come regolato definitivamente.

Vedi anche