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.
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?
- Difficulty als endliche ganze Zahl im Hashbereich validieren.
- Nutzdaten und Nonce kollisionsfrei in Bytes codieren.
- SHA-256 berechnen und Zielpräfix prüfen.
- In begrenzten Batches fortfahren oder auf Abort reagieren.
- 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.
- Difficulty, Noncebereich und eindeutiges Encoding festlegen.
- Hashfunktion als austauschbaren, deterministischen Port implementieren.
- Batchgröße, Fortschritt, Attempt-Limit und AbortSignal anbieten.
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.
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