Last active
December 30, 2025 02:48
-
-
Save Timonchegs/9d8ac1920f2737ecbfa6e8c183cc0d23 to your computer and use it in GitHub Desktop.
deepseek_proxy
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 http = require('http'); | |
| const crypto = require('crypto'); | |
| // КОНФИГУРАЦИЯ | |
| const CONFIG = { | |
| STRATUM_PORT: 3333, | |
| NODE_RPC_HOST: '127.0.0.1', | |
| NODE_GETWORK_PORT: 8668, | |
| RPC_USER: 'tteFTlJ7YOfGDA2KBMHKqnDnXeE=', | |
| RPC_PASS: 'SOkvF8sxay8ViOxpgbraHmqJmSU=', | |
| INITIAL_DIFFICULTY: 0.5 | |
| }; | |
| class SmartAbelianProxy { | |
| constructor() { | |
| this.currentJob = null; | |
| this.jobs = new Map(); | |
| this.miners = new Map(); | |
| this.sessionId = 1; | |
| this.server = net.createServer((socket) => this.handleConnection(socket)); | |
| // Кеширование результатов тестов | |
| this.testedCombinations = new Set(); | |
| this.successfulCombo = null; | |
| } | |
| async start() { | |
| console.log('🧠 Умный Abelian Proxy'); | |
| console.log('====================\n'); | |
| // Проверка ноды | |
| try { | |
| await this.updateWork(); | |
| console.log('✅ Нода подключена\n'); | |
| } catch (error) { | |
| console.error('❌ Ошибка ноды:', error.message); | |
| process.exit(1); | |
| } | |
| this.server.listen(CONFIG.STRATUM_PORT, '0.0.0.0', () => { | |
| console.log(`📡 Прокси слушает :${CONFIG.STRATUM_PORT}\n`); | |
| }); | |
| // Обновление работы каждые 30 сек | |
| setInterval(() => this.updateWork(), 30000); | |
| } | |
| // ---------- RPC ВЗАИМОДЕЙСТВИЕ ---------- | |
| async rpcCall(method, params) { | |
| const data = JSON.stringify({ | |
| jsonrpc: '2.0', | |
| id: Date.now(), | |
| method, | |
| params | |
| }); | |
| const auth = 'Basic ' + Buffer.from(`${CONFIG.RPC_USER}:${CONFIG.RPC_PASS}`).toString('base64'); | |
| const options = { | |
| hostname: CONFIG.NODE_RPC_HOST, | |
| port: CONFIG.NODE_GETWORK_PORT, | |
| path: '/', | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| 'Content-Length': data.length, | |
| 'Authorization': auth | |
| }, | |
| timeout: 5000 | |
| }; | |
| return new Promise((resolve, reject) => { | |
| const req = http.request(options, (res) => { | |
| let response = ''; | |
| res.on('data', chunk => response += chunk); | |
| res.on('end', () => { | |
| try { | |
| resolve(JSON.parse(response)); | |
| } catch { | |
| reject(new Error('Invalid JSON response')); | |
| } | |
| }); | |
| }); | |
| req.on('error', reject); | |
| req.write(data); | |
| req.end(); | |
| }); | |
| } | |
| async updateWork() { | |
| try { | |
| const result = await this.rpcCall('getwork', [""]); | |
| if (!result.result) throw new Error('No work from node'); | |
| const work = result.result; | |
| const jobId = Date.now().toString(36).slice(-6); | |
| this.currentJob = { | |
| id: jobId, | |
| nodeJobId: work.jobid, | |
| contentHash: work.contenthash.replace('0x', ''), | |
| epochSeed: work.epochseed.replace('0x', ''), | |
| epoch: work.epoch || 0, | |
| target: work.targetboundary?.replace('0x', '') || '0'.repeat(64) | |
| }; | |
| this.jobs.set(jobId, this.currentJob); | |
| console.log(`🔄 Новая работа: ${jobId} (эпоха ${this.currentJob.epoch})`); | |
| // Рассылка авторизованным майнерам | |
| this.miners.forEach(miner => { | |
| if (miner.authorized) this.sendJob(miner); | |
| }); | |
| } catch (error) { | |
| console.error('⚠️ Ошибка обновления:', error.message); | |
| } | |
| } | |
| // ---------- STRATUM ОБРАБОТКА ---------- | |
| handleConnection(socket) { | |
| const minerId = `${socket.remoteAddress}:${socket.remotePort}`; | |
| console.log(`\n🔌 Подключение: ${minerId}`); | |
| const miner = { | |
| id: minerId, | |
| socket, | |
| sessionId: `s${this.sessionId++}`, | |
| extraNonce: crypto.randomBytes(2).toString('hex'), | |
| authorized: false, | |
| workerName: null | |
| }; | |
| this.miners.set(minerId, miner); | |
| socket.on('data', (data) => { | |
| const lines = data.toString().trim().split('\n'); | |
| lines.forEach(line => line && this.processMessage(miner, line)); | |
| }); | |
| socket.on('close', () => { | |
| console.log(`🔌 Отключение: ${minerId}`); | |
| this.miners.delete(minerId); | |
| }); | |
| } | |
| processMessage(miner, message) { | |
| try { | |
| const msg = JSON.parse(message); | |
| if (msg.method === 'mining.hello') { | |
| this.send(miner.socket, { | |
| id: msg.id, | |
| result: { | |
| proto: "AbelianStratum", | |
| encoding: "utf-8", | |
| extranonce: miner.extraNonce, | |
| version: "1.0.0", | |
| algo: "abelhash", | |
| resume: "0", | |
| timeout: "300" | |
| }, | |
| error: null | |
| }); | |
| } | |
| else if (msg.method === 'mining.subscribe') { | |
| this.send(miner.socket, { | |
| id: msg.id, | |
| result: { | |
| session_id: miner.sessionId, | |
| extra_nonce1: miner.extraNonce | |
| }, | |
| error: null | |
| }); | |
| } | |
| else if (msg.method === 'mining.authorize') { | |
| miner.authorized = true; | |
| miner.workerName = msg.params[0]; | |
| console.log(`✅ Авторизация: ${miner.workerName}`); | |
| this.send(miner.socket, { | |
| id: msg.id, | |
| result: { worker: miner.id, registered: "0" }, | |
| error: null | |
| }); | |
| // Отправляем сложность и работу | |
| setTimeout(() => { | |
| this.send(miner.socket, { | |
| id: null, | |
| method: 'mining.set_difficulty', | |
| params: [CONFIG.INITIAL_DIFFICULTY] | |
| }); | |
| if (this.currentJob) this.sendJob(miner); | |
| }, 100); | |
| } | |
| else if (msg.method === 'mining.submit') { | |
| this.handleSubmit(miner, msg); | |
| } | |
| } catch (error) { | |
| console.error('❌ Ошибка обработки:', error.message); | |
| } | |
| } | |
| async handleSubmit(miner, msg) { | |
| const [jobId, submittedNonce, workerName] = msg.params; | |
| const job = this.jobs.get(jobId); | |
| if (!job) { | |
| this.send(miner.socket, { id: msg.id, result: false, error: "Stale job" }); | |
| return; | |
| } | |
| console.log(`\n🎯 Submit от ${miner.workerName}`); | |
| console.log(`📦 Nonce: ${submittedNonce}, Job: ${jobId}`); | |
| // Если уже нашли работающую комбинацию - используем её | |
| if (this.successfulCombo) { | |
| const result = await this.testCombination(job, submittedNonce, this.successfulCombo); | |
| this.send(miner.socket, { id: msg.id, result: result.success, error: null }); | |
| return; | |
| } | |
| // Тестируем только 4 ключевые гипотезы | |
| const hypotheses = [ | |
| // ГИПОТЕЗА 1: Ethash-like (Keccak от header + nonce) | |
| { | |
| name: 'Ethash-like', | |
| prepare: (nonce) => { | |
| const cleanNonce = nonce.slice(miner.extraNonce.length); | |
| const mixHash = crypto.createHash('sha3-256') | |
| .update(job.contentHash + cleanNonce, 'hex') | |
| .digest('hex'); | |
| return { | |
| params: [job.nodeJobId, cleanNonce, '0x' + mixHash], | |
| desc: `nonce=${cleanNonce}, Keccak(header+nonce)` | |
| }; | |
| } | |
| }, | |
| // ГИПОТЕЗА 2: Nonce как mixDigest (редкий случай) | |
| { | |
| name: 'Nonce-as-mix', | |
| prepare: (nonce) => ({ | |
| params: [job.nodeJobId, job.contentHash, '0x' + nonce], | |
| desc: `nonce как mixDigest` | |
| }) | |
| }, | |
| // ГИПОТЕЗА 3: Epoch-based (используем epochSeed) | |
| { | |
| name: 'Epoch-based', | |
| prepare: (nonce) => { | |
| const cleanNonce = nonce.slice(miner.extraNonce.length); | |
| const mixHash = crypto.createHash('sha3-256') | |
| .update(job.epochSeed + cleanNonce, 'hex') | |
| .digest('hex'); | |
| return { | |
| params: [job.nodeJobId, cleanNonce, '0x' + mixHash], | |
| desc: `nonce=${cleanNonce}, Keccak(epochSeed+nonce)` | |
| }; | |
| } | |
| }, | |
| // ГИПОТЕЗА 4: Простой contentHash как mixDigest | |
| { | |
| name: 'Simple-header', | |
| prepare: (nonce) => ({ | |
| params: [job.nodeJobId, nonce.slice(miner.extraNonce.length), '0x' + job.contentHash], | |
| desc: `contentHash как mixDigest` | |
| }) | |
| } | |
| ]; | |
| let shareAccepted = false; | |
| for (const hypothesis of hypotheses) { | |
| const comboKey = hypothesis.name; | |
| // Пропускаем если уже тестировали | |
| if (this.testedCombinations.has(comboKey)) continue; | |
| console.log(`🔍 Тестируем: ${hypothesis.name}`); | |
| const prepared = hypothesis.prepare(submittedNonce); | |
| console.log(` ${prepared.desc}`); | |
| const result = await this.rpcCall('submitwork', prepared.params); | |
| if (result.result === true) { | |
| console.log(`🎉🎉🎉 РАБОЧАЯ КОМБИНАЦИЯ: ${hypothesis.name}`); | |
| this.successfulCombo = hypothesis; | |
| shareAccepted = true; | |
| break; | |
| } else if (result.error) { | |
| console.log(` ❌ ${result.error.code}: ${result.error.message}`); | |
| this.testedCombinations.add(comboKey); | |
| } | |
| // Пауза между запросами | |
| await new Promise(r => setTimeout(r, 100)); | |
| } | |
| // Если ни одна гипотеза не сработала | |
| if (!shareAccepted && this.testedCombinations.size === hypotheses.length) { | |
| console.log('🚫 Все гипотезы проверены, ни одна не работает'); | |
| console.log('💡 Возможные причины:'); | |
| console.log(' 1. Неверный алгоритм хеширования mixDigest'); | |
| console.log(' 2. Неверный порядок параметров submitwork'); | |
| console.log(' 3. Нужен 4-й параметр (epoch или что-то ещё)'); | |
| } | |
| this.send(miner.socket, { | |
| id: msg.id, | |
| result: shareAccepted, | |
| error: shareAccepted ? null : "Share rejected" | |
| }); | |
| } | |
| sendJob(miner) { | |
| if (!this.currentJob) return; | |
| // mining.set | |
| this.send(miner.socket, { | |
| id: null, | |
| method: 'mining.set', | |
| params: { | |
| epoch: "65", | |
| target: "00000001ffff0000000000000000000000000000000000000000000000000000", | |
| algo: "abelhash", | |
| extranonce: miner.extraNonce, | |
| extra_nonce_bits_num: "10" | |
| } | |
| }); | |
| // mining.notify | |
| this.send(miner.socket, { | |
| id: null, | |
| method: 'mining.notify', | |
| params: { | |
| job_id: this.currentJob.id, | |
| height: this.currentJob.epoch.toString(16), | |
| content_hash: this.currentJob.contentHash, | |
| clean_job: "0" | |
| } | |
| }); | |
| console.log(`📤 Работа ${this.currentJob.id} → ${miner.workerName}`); | |
| } | |
| send(socket, data) { | |
| socket.write(JSON.stringify(data) + '\n'); | |
| } | |
| async testCombination(job, submittedNonce, hypothesis) { | |
| const prepared = hypothesis.prepare(submittedNonce); | |
| const result = await this.rpcCall('submitwork', prepared.params); | |
| return { success: result.result === true }; | |
| } | |
| } | |
| // Запуск | |
| const proxy = new SmartAbelianProxy(); | |
| proxy.start().catch(console.error); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment