Wiki de ZooBC
Apps y desarrollo sobre ZooBC

Crear una app como una sola página HTML

Una aplicación de ZooBC puede ser un solo archivo HTML sin ningún servidor detrás. La página lee la cadena desde la API HTTP de un nodo, construye y firma las transacciones en el navegador con la clave del usuario y envía los bytes firmados. Los usuarios no ejecutan ningún nodo, y no hay ninguna clave de API que solicitar. La billetera oficial es la prueba: es ella misma un archivo HTML, que cada nodo sirve en / y en /wallet (billetera web).

Un archivo HTML lee con GET, firma en el navegador y envía los bytes firmados a un nodo o a una pasarela.
Un archivo HTML lee con GET, firma en el navegador y envía los bytes firmados a un nodo o a una pasarela.

La API del nodo

Cada nodo sirve una API HTTP/1.1 en texto plano, por defecto en el puerto 8080, con más de cien rutas bajo /api/v1/: bloques, cuentas, tokens, apps, el exchange y más (API del nodo). Cada respuesta lleva estas cabeceras, y una petición OPTIONS recibe un 200 de inmediato, así que una página alojada en cualquier sitio puede llamar a cualquier 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

El nodo en sí no tiene TLS. Los dominios públicos terminan el TLS en una pasarela, que añade sus propias cabeceras CORS. Los navegadores bloquean las llamadas en HTTP plano desde una página cargada por HTTPS, así que una página pública habla con una pasarela.

Todas las rutas salvo ocho son lecturas sin autenticación, y enviar una transacción no necesita ninguna clave de ningún tipo, porque la transacción lleva su propia firma. Los límites se aplican por dirección de cliente: 300 peticiones de escritura por minuto, y después un 429 con una cabecera Retry-After; las lecturas no tienen límite salvo que el operador fije uno; y 20 autenticaciones firmadas fallidas en 5 minutos bloquean al cliente durante 300 segundos.

Firmar en el navegador

La página firma un resumen que vincula la transacción a una sola cadena:

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

Una cuenta nativa lo firma con Ed25519. La página lee genesis_hash y signing_version (2) de GET /api/v1/node/info, y como el hash del génesis está dentro del resumen, una firma hecha para una cadena no vale nada en otra (firmas vinculadas a la cadena). No hace falta ningún SDK: bastan Ed25519, SHA3-256 y el hash del génesis, y el formato de bytes se describe en sobre de la transacción. Las herramientas públicas también ofrecen bibliotecas ya hechas, entre ellas un archivo JavaScript sin dependencias para una etiqueta script (herramientas de línea de comandos). La clave nunca sale de la página.

Enviar y seguir

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 aceptada, no hecha. El nodo ha analizado la transacción, ha hecho sus primeras comprobaciones y la ha pasado a staging; todavía tiene que incluirla un productor de bloques. Hasta que el estado diga confirmed, no ha cambiado ningún saldo. Con un bloque cada 15 segundos, consultar cada par de segundos es más que suficiente.

Si se pierde una respuesta, reenvía exactamente los mismos bytes firmados. El hash de la transacción es el SHA3-256 de los bytes sin firmar y la firma, así que un nodo que ya tiene la transacción responde 202 con "duplicate": true, añadiendo "state": "confirmed" una vez que está en un bloque, y la transacción solo se ejecuta una vez. Volver a firmar con una marca de tiempo nueva crea una transacción distinta, y así es como se producen los pagos dobles.

Por defecto, un bloque puede incluir una transacción hasta 3600 segundos después de su marca de tiempo; una transacción de versión 3 indica su propia ventana, de hasta 86 400 segundos; y una marca de tiempo más de 3600 segundos en el futuro se rechaza (caducidad y marcas de tiempo). Antes de entregar mercancía a cambio de un pago, espera a la confirmación y después al indicador finalized, que recibe una transacción cuando un bloque de la spine cofirmado cubre su bloque (finalidad y reversión). La API también indica finalized_height, el block_seed_proof de cada bloque, la expiry de una transacción y los bloques de la spine en /spine/blocks/:height.

Después del 202: staging, mempool, confirmed, finalized; una respuesta perdida se reenvía con los mismos bytes.
Después del 202: staging, mempool, confirmed, finalized; una respuesta perdida se reenvía con los mismos bytes.

Rutas para apps

Es el propio nodo, y no el servicio de archivo, el que sirve las rutas de las apps: /apps (filtros status, limit y category, que puede ser solo, pvp o party), /apps/open, /apps/pool, /apps/stats, /apps/:id (con su liquidación, si la hay) y /accounts/:a/apps.

Lista de comprobación

  • Lee a través de una pasarela por HTTPS; escribe enviando bytes firmados, con la clave guardada en la página.
  • Sigue cada transacción por su hash, y reintenta reenviando los mismos bytes, nunca volviendo a firmar.
  • Respeta el 429 y Retry-After.
  • Muestra el texto de la cadena con textContent (datos de la cadena son entradas no confiables).
  • Trata «confirmed» como recibido y «finalized» como liquidado.

Véase también