aboutsummaryrefslogtreecommitdiff
path: root/web/js/proof-of-work-slow.mjs
blob: 0bdc1466181690973e348f75bf6c3d1aec70d516 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// https://dev.to/ratmd/simple-proof-of-work-in-javascript-3kgm

export default function process(
  data,
  difficulty = 5,
  signal = null,
  progressCallback = null,
  _threads = 1,
) {
  console.debug("slow algo");
  return new Promise((resolve, reject) => {
    let webWorkerURL = URL.createObjectURL(new Blob([
      '(', processTask(), ')()'
    ], { type: 'application/javascript' }));

    let worker = new Worker(webWorkerURL);
    const terminate = () => {
      worker.terminate();
      if (signal != null) {
        // clean up listener to avoid memory leak
        signal.removeEventListener("abort", terminate);
        if (signal.aborted) {
          console.log("PoW aborted");
          reject(false);
        }
      }
    };
    if (signal != null) {
      signal.addEventListener("abort", terminate, { once: true });
    }

    worker.onmessage = (event) => {
      if (typeof event.data === "number") {
        progressCallback?.(event.data);
      } else {
        terminate();
        resolve(event.data);
      }
    };

    worker.onerror = (event) => {
      terminate();
      reject(event);
    };

    worker.postMessage({
      data,
      difficulty
    });

    URL.revokeObjectURL(webWorkerURL);
  });
}

function processTask() {
  return function () {
    const sha256 = (text) => {
      const encoded = new TextEncoder().encode(text);
      return crypto.subtle.digest("SHA-256", encoded.buffer)
        .then((result) =>
          Array.from(new Uint8Array(result))
            .map((c) => c.toString(16).padStart(2, "0"))
            .join(""),
        );
    };

    addEventListener('message', async (event) => {
      let data = event.data.data;
      let difficulty = event.data.difficulty;

      let hash;
      let nonce = 0;
      do {
        if (nonce & 1023 === 0) {
          postMessage(nonce);
        }
        hash = await sha256(data + nonce++);
      } while (hash.substring(0, difficulty) !== Array(difficulty + 1).join('0'));

      nonce -= 1; // last nonce was post-incremented

      postMessage({
        hash,
        data,
        difficulty,
        nonce,
      });
    });
  }.toString();
}