Berichtenprotocol

Een bericht in Hashiverse is HTML — geschreven in de browser met een rich-text-editor, DOMPurify-gesaneerd voor weergave. Tussen auteurschap en weergave zit een pijplijn van compressie, versleuteling, ondertekening, twee-fase-indiening, DHT-routing en bundle-aggregatie. Deze pagina volgt een bericht door die pijplijn.

Het gecodeerde bericht

EncodedPostV1 is het draadformaat voor een enkel bericht. Het bevat:

Versleuteling gebruikt meerdere wachtwoordzinnen — één per context waarin het bericht verschijnt — via een aangepast multi-key-schema geïnspireerd op het age-versleutelingsformaat. Een bericht dat zowel in de tijdlijn van een gebruiker als onder een hashtag staat, wordt versleuteld met zowel de publieke ID van de gebruiker als de hashtag-string als wachtwoordzinnen. Beide sleutels ontsleutelen het. Servers die de versleutelde bytes bewaren kunnen geen van beide lezen.

Indiening: Claim dan Commit

Bericht-indiening is een twee-fase-protocol:

  1. SubmitClaim: De client stuurt een claim-verzoek met PoW. De server valideert de PoW en, als de bericht-ID nog niet aanwezig is, geeft een token uit dat toestemming verleent om te commit'en.
  2. SubmitCommit: De client stuurt de werkelijke berichtbytes met het token. De server slaat het bericht op en retourneert een bevestigingshandtekening.

Het scheiden van claim en commit voorkomt aanvallen via payload-flooding: een server kan claims te kwader trouw goedkoop afwijzen (alleen PoW verifiëren) voordat een grote payload wordt geaccepteerd. De bevestigingshandtekening van de server is voor de client het bewijs dat het bericht is geaccepteerd.

Bron: hashiverse-server/src/server/handlers/

Bundles en buckets

Berichten worden niet individueel opgeslagen of opgehaald — ze worden gegroepeerd in EncodedPostBundleV1-objecten, één bundle per bucket per server. Een bundle bevat ongeveer 20 berichten van een bepaalde location-ID (een specifiek tijdvenster voor een specifieke gebruiker, hashtag of antwoord-context), maar dit getal kan groter zijn door healing en eventuele consistentievertragingen. Bundles worden ondertekend door de bedienende peer.

De tijdlijn van een gebruiker ophalen betekent de bucket-hiërarchie recursief doorlopen: begin met de maandelijkse bucket, drill in de wekelijkse, dagelijkse, uurlijkse en fijnere buckets waar berichten bestaan. De RecursiveBucketVisitor behandelt dit met een callback die op elk niveau beslist of er in fijnere granulariteit moet worden recursied of overgeslagen, wat efficiënte paginering mogelijk maakt zelfs over spaarzame tijdlijnen.

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

Bucket-types

Vier (op het moment van schrijven) bucket-types bepalen hoe berichten worden geïndexeerd en ontdekt:

Een enkel bericht kan tegelijkertijd in meerdere buckets verschijnen, elk versleuteld met de passende wachtwoordzin voor die bucket.

Bron: buckets.rs

Opslag

Op de server worden bericht-bundles op schijf gepersisteerd, terwijl hun metadata wordt gepersisteerd naar fjall — een puur-Rust ingebedde key-value-store met automatische compactie en goede schrijfdoorvoer. fjall is gekozen boven redb en sled vanwege zijn onderhoudsstaat van dienst en operationele eenvoud. Berichten worden opgeslagen als Brotli-gecomprimeerde, versleutelde bytes.

Op de browserclient worden berichten gecached in IndexedDB via indexed_db_futures, met een in-memory stub voor testen. Elke categorie client-side-data wordt in rust versleuteld met een andere sleutel, gekozen om bij zijn toegangsmodel te passen.

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