Beitragsprotokoll

Ein Beitrag in Hashiverse ist HTML — im Browser mit einem Rich-Text-Editor verfasst, mit DOMPurify vor der Anzeige bereinigt. Zwischen Verfassen und Anzeige liegt eine Pipeline aus Kompression, Verschlüsselung, Signatur, Zwei-Phasen-Einreichung, DHT-Routing und Bundle-Aggregation. Diese Seite verfolgt einen Beitrag durch diese Pipeline.

Der kodierte Beitrag

EncodedPostV1 ist das Drahtformat für einen einzelnen Beitrag. Er enthält:

Die Verschlüsselung verwendet mehrere Passphrasen — eine pro Kontext, in dem der Beitrag erscheint — über ein eigenes Mehrschlüssel-Schema, inspiriert vom age-Verschlüsselungs­format. Ein Beitrag, der sowohl in der Timeline eines Nutzers als auch unter einem Hashtag erscheint, wird mit der öffentlichen ID des Nutzers und dem Hashtag-String als Passphrasen verschlüsselt. Jede der Schlüssel entschlüsselt ihn. Server, die die verschlüsselten Bytes halten, können keine davon lesen.

Einreichung: Claim, dann Commit

Die Beitragseinreichung ist ein Zwei-Phasen-Protokoll:

  1. SubmitClaim: Der Client sendet eine Claim-Anfrage mit PoW. Der Server validiert die PoW und gibt, wenn die Beitrags-ID nicht bereits existiert, ein Token aus, das die Erlaubnis zum Commit gewährt.
  2. SubmitCommit: Der Client sendet die eigentlichen Beitrags-Bytes mit dem Token. Der Server speichert den Beitrag und gibt eine Bestätigungs­signatur zurück.

Die Trennung von Claim und Commit verhindert Nutzlast-Flutangriffe: Ein Server kann böswillige Claims günstig ablehnen (nur die PoW prüfen), bevor er eine große Nutzlast annimmt. Die Bestätigungs­signatur des Servers ist der Beweis des Clients, dass der Beitrag akzeptiert wurde.

Quelle: hashiverse-server/src/server/handlers/

Bundles und Buckets

Beiträge werden weder einzeln gespeichert noch einzeln abgerufen — sie werden in EncodedPostBundleV1-Objekte gruppiert, ein Bundle pro Bucket pro Server. Ein Bundle enthält etwa 20 Beiträge aus einer bestimmten Standort-ID (ein konkretes Zeitfenster für einen konkreten Nutzer, Hashtag oder Antwortkontext), aber diese Zahl kann mit Heilung und eventuell konsistenten Verzögerungen größer werden. Bundles werden vom liefernden Peer signiert.

Die Timeline eines Nutzers abzurufen bedeutet, die Bucket-Hierarchie rekursiv zu durchlaufen: mit dem Monats-Bucket beginnen, in das wöchentliche, tägliche, stündliche und feinere Buckets absteigen, wo Beiträge existieren. Der RecursiveBucketVisitor handhabt das mit einem Callback, der auf jeder Ebene entscheidet, ob in feinere Granularität abzusteigen ist oder ob übersprungen wird, was effiziente Paginierung selbst über spärliche Timelines hinweg erlaubt.

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

Bucket-Typen

Vier (zum Zeitpunkt des Schreibens) Bucket-Typen bestimmen, wie Beiträge indiziert und entdeckt werden:

Ein einzelner Beitrag kann gleichzeitig in mehreren Buckets erscheinen, jeweils mit der für diesen Bucket passenden Passphrase verschlüsselt.

Quelle: buckets.rs

Speicherung

Auf dem Server werden Beitrags-Bundles auf die Festplatte persistiert, während ihre Metadaten in fjall persistiert werden — einem in reinem Rust geschriebenen, eingebetteten Schlüssel-Wert-Speicher mit automatischer Verdichtung und gutem Schreib­durchsatz. fjall wurde gegenüber redb und sled wegen seiner Wartungs­bilanz und betrieblichen Einfachheit gewählt. Beiträge werden als Brotli-komprimierte, verschlüsselte Bytes gespeichert.

Im Browser-Client werden Beiträge in IndexedDB über indexed_db_futures zwischengespeichert, mit einem In-Memory-Stub für Tests. Jede Kategorie clientseitiger Daten wird im Ruhezustand mit einem anderen Schlüssel verschlüsselt, gewählt passend zu ihrem Zugriffsmodell.

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