Protocolo de Publicações
Uma publicação no Hashiverse é HTML — escrita no browser com um editor de rich-text, sanitizada com DOMPurify antes de ser apresentada. Entre a autoria e a apresentação está um pipeline de compressão, cifragem, assinatura, submissão em duas fases, encaminhamento DHT e agregação em bundles. Esta página segue uma publicação por esse pipeline.
A publicação codificada
EncodedPostV1 é o formato de fio para uma única publicação. Contém:
- header: bytes da chave de verificação, bytes do compromisso pós-quântico, timestamp, comprimento da publicação e
linked_base_ids— referências a publicações anteriores a que esta publicação está a responder ou sobre as quais está a construir. - signature: assinatura Ed25519 (ou PQ) sobre o header e os hashes da publicação.
- post: o conteúdo HTML, comprimido com Brotli e cifrado.
- post_id: hash Blake3 da assinatura — um endereço de conteúdo estável e verificável.
A cifragem usa várias passphrases — uma por contexto em que a publicação aparece — através de
um esquema personalizado de várias chaves inspirado no formato de cifragem age.
Uma publicação que esteja simultaneamente na cronologia de um utilizador e sob um hashtag é
cifrada tendo como passphrases o ID público do utilizador e a string do hashtag. Qualquer
uma das chaves a decifra. Os servidores que detêm os bytes cifrados não conseguem ler nem
uma nem outra.
Submissão: Claim seguido de Commit
A submissão de uma publicação é um protocolo em duas fases:
- SubmitClaim: O cliente envia um pedido de claim com PoW. O servidor valida a PoW e, se o ID da publicação ainda não estiver presente, emite um token que concede permissão para o commit.
- SubmitCommit: O cliente envia os bytes reais da publicação com o token. O servidor guarda a publicação e devolve uma assinatura de confirmação.
Separar o claim do commit evita ataques de inundação por payload: um servidor pode rejeitar de forma barata claims de má-fé (basta verificar a PoW) antes de aceitar qualquer payload grande. A assinatura de confirmação do servidor é a prova do cliente de que a publicação foi aceite.
Origem: hashiverse-server/src/server/handlers/
Bundles e baldes
As publicações não são guardadas nem obtidas individualmente — são agrupadas em objetos
EncodedPostBundleV1, um bundle por balde por servidor. Um bundle contém cerca de
20 publicações de um determinado location ID (uma janela temporal específica para um
utilizador, hashtag ou contexto de resposta específico), mas este número pode ser maior com
auto-recuperação e atrasos de consistência eventual. Os bundles são assinados pelo par que
serve.
Obter a cronologia de um utilizador significa atravessar a hierarquia de baldes
recursivamente: começar pelo balde mensal, descer ao semanal, diário, horário e baldes mais
finos onde existam publicações. O RecursiveBucketVisitor trata disto com um
callback que decide em cada nível se recurse para granularidade mais fina ou se salta,
permitindo paginação eficiente mesmo em cronologias esparsas.
Origem: encoded_post_bundle.rs,
hashiverse-lib/src/client/timeline/
Tipos de balde
Quatro (à data de escrita) tipos de balde determinam como as publicações são indexadas e descobertas:
- User (0): a cronologia pessoal do autor
- Hashtag (1): publicações que contêm um determinado hashtag
- Mention (2): publicações que mencionam um utilizador específico
- ReplyToPost (3): publicações que respondem a uma publicação específica
Uma única publicação pode aparecer em vários baldes em simultâneo, cifrada em cada um com a passphrase apropriada a esse balde.
Origem: buckets.rs
Armazenamento
No servidor, os bundles de publicações são persistidos em disco, enquanto os seus metadados são persistidos em fjall — um key-value store embutido em puro Rust com compaction automática e bom débito de escrita. O fjall foi escolhido em detrimento do redb e do sled pelo seu histórico de manutenção e simplicidade operacional. As publicações são guardadas como bytes cifrados e comprimidos com Brotli.
No cliente do browser, as publicações são colocadas em cache em IndexedDB
via indexed_db_futures, com um stub em memória para testes. Cada categoria de
dados do lado do cliente é cifrada em repouso com uma chave diferente, escolhida para
corresponder ao seu modelo de acesso.
Origem: hashiverse-server/src/environment/,
wasm_client_storage.rs