-
-
Save Timonchegs/52891cc693ab6fcd4f548453fb5ce887 to your computer and use it in GitHub Desktop.
gemini
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const net = require('net'); | |
| const axios = require('axios'); | |
| // ================= НАСТРОЙКИ ================= | |
| const PROXY_PORT = 3333; | |
| const NODE_RPC_URL = 'http://127.0.0.1:8668'; | |
| const NODE_RPC_USER = 'tteFTlJ7YOfGDA2KBMHKqnDnXeE='; | |
| const NODE_RPC_PASS = 'SOkvF8sxay8ViOxpgbraHmqJmSU='; | |
| // ============================================= | |
| const auth = Buffer.from(`${NODE_RPC_USER}:${NODE_RPC_PASS}`).toString('base64'); | |
| let currentJob = null; | |
| let clients = []; | |
| // Чистит хекс от 0x | |
| const fixHex = (hex) => hex ? hex.replace(/^0x/, '').toLowerCase() : ''; | |
| // Таргет обязан быть 64 символа (32 байта). Добиваем нулями слева. | |
| const pad64 = (hex) => fixHex(hex).padStart(64, '0'); | |
| async function fetchWork() { | |
| try { | |
| const response = await axios.post(NODE_RPC_URL, { | |
| jsonrpc: '1.0', id: 'getwork', method: 'getwork', params: [""] | |
| }, { headers: { 'Authorization': `Basic ${auth}` }, timeout: 2000 }); | |
| const r = response.data.result; | |
| // Если ответ пустой или нет jobid - выходим | |
| if (!r || !r.jobid) return; | |
| const nodeJobId = String(r.jobid); | |
| if (!currentJob || currentJob.nodeJobId !== nodeJobId) { | |
| // --- ЗАЩИТА ОТ NULL И NAN (ГЛАВНЫЙ ФИКС) --- | |
| // 1. Высота: Если пришел null/undefined, ставим безопасную заглушку (например 1), лишь бы не null | |
| let safeHeight = (r.height !== undefined && r.height !== null) ? Number(r.height) : 1; | |
| if (isNaN(safeHeight)) safeHeight = 1; | |
| // 2. Время: Если пришло null/undefined, берем текущее время сервера | |
| let safeTimeNum = (r.time !== undefined && r.time !== null) ? Number(r.time) : Math.floor(Date.now() / 1000); | |
| if (isNaN(safeTimeNum)) safeTimeNum = Math.floor(Date.now() / 1000); | |
| // Переводим время в HEX-строку (как требует TRM) | |
| const timeHex = safeTimeNum.toString(16).toLowerCase(); | |
| // 3. Таргет: строго 64 символа | |
| const target64 = pad64(r.targetboundary); | |
| currentJob = { | |
| id: Date.now().toString(), // ID задания для майнера | |
| nodeJobId: nodeJobId, // ID задания в ноде | |
| headerHash: fixHex(r.contenthash), | |
| seedHash: fixHex(r.epochseed), | |
| target: target64, | |
| height: safeHeight, // Теперь это точно Число | |
| time: timeHex // Теперь это точно HEX-строка (не "nan") | |
| }; | |
| console.log(`[NEW JOB] ID:${currentJob.nodeJobId} H:${currentJob.height} T:${currentJob.time}`); | |
| broadcastJob(currentJob); | |
| } | |
| } catch (e) { | |
| // Ошибки соединения игнорим, чтобы не спамить, но можно включить для отладки | |
| // console.error("RPC Poll Error:", e.message); | |
| } | |
| } | |
| function broadcastJob(job) { | |
| // Формируем пакет. | |
| // Гарантируем, что null здесь не окажется благодаря проверкам выше. | |
| const msg = JSON.stringify({ | |
| id: null, | |
| method: "mining.notify", | |
| params: [ | |
| job.id, // Job ID | |
| job.headerHash, // Header | |
| job.seedHash, // Seed | |
| job.target, // Target (64 chars) | |
| true, // Clean Jobs | |
| job.height, // Height (Number) | |
| job.time, // Time (Hex String) | |
| "00000000", // ExtraNonce2 | |
| "00" // Reserved | |
| ] | |
| }) + '\n'; | |
| clients.forEach(s => { | |
| if (!s.destroyed && s.isReady) s.write(msg); | |
| }); | |
| } | |
| setInterval(fetchWork, 500); // Опрашиваем чаще (500мс), чтобы быстрее подхватить работу | |
| const server = net.createServer((socket) => { | |
| socket.isReady = false; | |
| clients.push(socket); | |
| let buffer = ''; | |
| console.log(`[CONN] Miner connected: ${socket.remoteAddress}`); | |
| socket.on('data', async (chunk) => { | |
| buffer += chunk.toString(); | |
| while (buffer.indexOf('\n') !== -1) { | |
| const lineIndex = buffer.indexOf('\n'); | |
| const line = buffer.substring(0, lineIndex); | |
| buffer = buffer.substring(lineIndex + 1); | |
| if (!line.trim()) continue; | |
| try { | |
| const req = JSON.parse(line); | |
| if (req.method === 'mining.hello') { | |
| socket.write(JSON.stringify({id: req.id, result: { version: "1.0.0", algo: "abelian" }, error: null}) + '\n'); | |
| } | |
| else if (req.method === 'mining.subscribe') { | |
| socket.write(JSON.stringify({id: req.id, result: [[["mining.notify", "1"]], "000000", 4], error: null}) + '\n'); | |
| } | |
| else if (req.method === 'mining.authorize') { | |
| socket.write(JSON.stringify({ id: req.id, result: true, error: null }) + '\n'); | |
| socket.write(JSON.stringify({ method: "mining.set_difficulty", params: [1] }) + '\n'); | |
| socket.isReady = true; | |
| // Если работа уже есть, шлем сразу | |
| if (currentJob) { | |
| const msg = JSON.stringify({ | |
| id: null, | |
| method: "mining.notify", | |
| params: [currentJob.id, currentJob.headerHash, currentJob.seedHash, currentJob.target, true, currentJob.height, currentJob.time, "00000000", "00"] | |
| }) + '\n'; | |
| socket.write(msg); | |
| } | |
| } | |
| else if (req.method === 'mining.submit') { | |
| const [worker, jid, nonce] = req.params; | |
| if (currentJob && currentJob.id === jid) { | |
| // 1. Реверс Nonce (Little Endian <-> Big Endian) | |
| const revNonce = nonce.match(/../g).reverse().join(''); | |
| // 2. MIXHASH FIX: Шлем 64 нуля, а не хедер | |
| const mixHashZero = "0000000000000000000000000000000000000000000000000000000000000000"; | |
| console.log(`[SUBMIT] Nonce: ${nonce} -> Sending to Node...`); | |
| axios.post(NODE_RPC_URL, { | |
| jsonrpc: '1.0', id: 's', method: 'submitwork', | |
| params: [ | |
| currentJob.nodeJobId, | |
| revNonce, | |
| mixHashZero | |
| ] | |
| }, { headers: { 'Authorization': `Basic ${auth}` } }) | |
| .then(r => { | |
| const success = r.data.result === true; | |
| console.log(`[SHARE] Node Response: ${success ? 'ACCEPTED' : 'REJECTED'}`); | |
| socket.write(JSON.stringify({ id: req.id, result: success, error: null }) + '\n'); | |
| }) | |
| .catch(e => { | |
| console.log(`[SHARE ERR] ${e.message}`); | |
| socket.write(JSON.stringify({ id: req.id, result: true, error: null }) + '\n'); | |
| }); | |
| } else { | |
| // Работа устарела | |
| socket.write(JSON.stringify({ id: req.id, result: true, error: null }) + '\n'); | |
| } | |
| } | |
| } catch (e) { | |
| console.log(`JSON Error: ${e.message}`); | |
| } | |
| } | |
| }); | |
| socket.on('close', () => { clients = clients.filter(c => c !== socket); }); | |
| socket.on('error', (e) => {}); | |
| }); | |
| server.listen(PROXY_PORT, '0.0.0.0', () => { | |
| console.log(`V39 - FINAL FIX (NULL/NAN PROTECTION + SUBMIT FIX)`); | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment