Protocolo de publicaciones

Una publicación en Hashiverse es HTML — escrita en el navegador con un editor de texto enriquecido, saneada con DOMPurify antes de mostrarse. Entre la autoría y la visualización hay un pipeline de compresión, cifrado, firma, envío en dos fases, enrutamiento DHT y agregación en bundles. Esta página sigue una publicación a lo largo de ese pipeline.

La publicación codificada

EncodedPostV1 es el formato de cable de una publicación individual. Contiene:

El cifrado usa varias passphrases — una por cada contexto en el que aparece la publicación — mediante un esquema personalizado de varias claves inspirado en el formato de cifrado age. Una publicación que está a la vez en la cronología de un usuario y bajo un hashtag se cifra con el identificador público del usuario y la cadena del hashtag como passphrases. Cualquiera de las claves la descifra. Los servidores que guardan los bytes cifrados no pueden leer ninguna de ellas.

Envío: Claim y luego Commit

El envío de publicaciones es un protocolo en dos fases:

  1. SubmitClaim: el cliente envía una solicitud de claim con PoW. El servidor valida la PoW y, si el ID de publicación no está ya presente, emite un token que concede permiso para hacer commit.
  2. SubmitCommit: el cliente envía los bytes reales de la publicación con el token. El servidor almacena la publicación y devuelve una firma de confirmación.

Separar claim de commit evita ataques de inundación de payload: un servidor puede rechazar claims maliciosos a bajo coste (basta verificar la PoW) antes de aceptar cualquier payload grande. La firma de confirmación del servidor es la prueba para el cliente de que la publicación fue aceptada.

Fuente: hashiverse-server/src/server/handlers/

Bundles y buckets

Las publicaciones no se almacenan ni recuperan individualmente — se agrupan en objetos EncodedPostBundleV1, un bundle por bucket por servidor. Un bundle contiene unas 20 publicaciones de un ID de ubicación concreto (una ventana temporal específica para un usuario, hashtag o contexto de respuesta determinado), pero ese número puede ser mayor por la reparación y los retrasos de consistencia eventual. Los bundles los firma el par que sirve.

Recuperar la cronología de un usuario significa recorrer la jerarquía de buckets de forma recursiva: empezar por el bucket mensual, profundizar en el semanal, diario, horario y buckets más finos donde existen publicaciones. El RecursiveBucketVisitor gestiona esto con un callback que decide en cada nivel si descender a granularidad más fina o saltar, permitiendo paginación eficiente incluso en cronologías dispersas.

Fuente: encoded_post_bundle.rs, hashiverse-lib/src/client/timeline/

Tipos de bucket

Cuatro (al momento de escribir) tipos de bucket determinan cómo se indexan y descubren las publicaciones:

Una misma publicación puede aparecer en varios buckets simultáneamente, cada uno cifrado con la passphrase apropiada para ese bucket.

Fuente: buckets.rs

Almacenamiento

En el servidor, los bundles de publicaciones se persisten en disco, mientras que sus metadatos se persisten en fjall — un almacén clave-valor embebido, en Rust puro, con compactación automática y buen rendimiento de escritura. Se eligió fjall frente a redb y sled por su trayectoria de mantenimiento y simplicidad operativa. Las publicaciones se almacenan como bytes comprimidos con Brotli y cifrados.

En el cliente del navegador, las publicaciones se cachean en IndexedDB a través de indexed_db_futures, con un stub en memoria para pruebas. Cada categoría de datos del lado del cliente se cifra en reposo con una clave distinta, elegida para encajar con su modelo de acceso.

Fuente: hashiverse-server/src/environment/, wasm_client_storage.rs