EnglishGitHub
teilweisepackages/proof-of-work/src

Proof of Work

@ralphschuler/proof-of-work

Erzeugt und prüft SHA-256-Präfixbeweise mit Event-Loop-Freigabe und Abbruch.

SHA-256noncerate limiting

01 · Problem

Wofür braucht man das?

Ein Client soll vor einer Anfrage nachweisbar Rechenarbeit leisten, deren Prüfung wesentlich günstiger als ihre Suche ist.

02 · Denkmodell

Das mentale Modell

Der Miner variiert eine eindeutig codierte Nonce, bis der Hash unter dem Ziel liegt. Der Prüfer hasht genau einmal und kontrolliert dasselbe Ziel.

Im Repository

Erzeugt und prüft SHA-256-Präfixbeweise mit Event-Loop-Freigabe und Abbruch. Schwierigkeit zählt wiederholte Hex-Präfixe. Protokollkodierung und externe Rechenbudgets liegen beim Aufrufer.

03 · Kontrollfluss

Was passiert in welcher Reihenfolge?

  1. Difficulty als endliche ganze Zahl im Hashbereich validieren.
  2. Nutzdaten und Nonce kollisionsfrei in Bytes codieren.
  3. SHA-256 berechnen und Zielpräfix prüfen.
  4. In begrenzten Batches fortfahren oder auf Abort reagieren.
  5. Zur Verifikation Hash neu berechnen; mitgelieferten Hash nicht blind vertrauen.

04 · Bauteile

Die entscheidenden Verträge

ProofOfWork.mineSucht kooperativ mit optionalem AbortSignal.
ProofOfWork.validateBerechnet einen Beweis neu und prüft das Ziel.

05 · Selbst bauen

Selbst implementieren

Nutze WebCrypto oder node:crypto und verschiebe hohe Difficulty in einen Worker.

  1. Difficulty, Noncebereich und eindeutiges Encoding festlegen.
  2. Hashfunktion als austauschbaren, deterministischen Port implementieren.
  3. Batchgröße, Fortschritt, Attempt-Limit und AbortSignal anbieten.
Konzeptskizze · kann ausgelassene Helfer verwenden
async function sha256Hex(value: string) {
  const bytes = new TextEncoder().encode(value);
  const digest = await crypto.subtle.digest("SHA-256", bytes);
  return [...new Uint8Array(digest)]
    .map(byte => byte.toString(16).padStart(2, "0"))
    .join("");
}

async function validate(data: string, nonce: number, difficulty: number) {
  if (!Number.isInteger(difficulty) || difficulty < 0 || difficulty > 64) return false;
  const hash = await sha256Hex(data.length + ":" + data + ":" + nonce);
  return hash.startsWith("0".repeat(difficulty));
}

06 · Verifizieren

Was solltest du testen?

  • Gefundene Nonce validiert, veränderte Nutzdaten oder Nonce validieren nicht.
  • Negative, gebrochene, NaN- und zu große Difficulty werden abgelehnt.
  • Abort beendet eine lange Suche zeitnah und Worker werden aufgeräumt.

Selbst ausprobieren

Formuliere die erste Prüfaussage als fehlschlagenden Test, implementiere die kleinste Korrektur und ergänze einen Grenzfall.

Gefundene Nonce validiert, veränderte Nutzdaten oder Nonce validieren nicht.

Ansatz vergleichen

Dein Test sollte beim gezielten Verletzen der Invariante fehlschlagen und nach der Korrektur wieder bestehen. Halte den Aufbau deterministisch und prüfe ein beobachtbares Ergebnis.

07 · Grenzen

Kompromisse und Stolperfallen

  • Mehr Difficulty erhöht Kosten exponentiell und benachteiligt schwache Geräte.
  • Event-Loop-Yields halten die UI reaktionsfähig, Worker bieten echte Parallelität.
  • Proof of Work verhindert Missbrauch nicht allein und ist energieintensiv.
Wichtig

Schwierigkeit zählt wiederholte Hex-Präfixe. Protokollkodierung und externe Rechenbudgets liegen beim Aufrufer.

08 · Weiterdenken

Quellcode und verwandte Ideen

yarn tsx packages/proof-of-work/examples/basic.ts