UNPKG

usb-miner

Version:

```js const IntMiner = require('./src'); const Debug = require('./src/log')(); const fs = require('fs'); const COMP = '[SIPC]';

1,158 lines (1,096 loc) 34.5 kB
const EventEmitter = require('events'); const uuid = require("uuid"); const Proxy = require('./proxy/build'); const Queue_1 = require('./proxy/build/Queue'); const cryptocurrency = require('./cryptocurrency/cryptocurrency'); const Miner_1 = require('./miner/minerApi'); const Algo_1 = require('./algo/algo'); const Debug = require('./log')(); const Ping = require('./ping'); const crc32 = require('crc32'); const Q = require('bluebird'); const locks = require('locks'); const SN = require('./sn')(); const COMP = '[Miner]'; var __assign = (this && this.__assign) || Object.assign || function (t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; const MinerType = [ { name: 'simplenode', type: 'X10' } ] class Miner extends EventEmitter { constructor({ algoname, minername, pool, cryptoname, protocolname }) { super(); var _this = this _this.algoname = algoname; _this.minername = minername; _this.protocolname = protocolname; _this.cryptoname = cryptoname; _this.pool = pool; _this.RunningMiner = []; _this.checkNet = null; _this.unlink = 0; _this.unlinkShutdown = false; _this.netThread() _this.crypto = cryptocurrency({ name: _this.cryptoname }); if (!_this.crypto) { this.emit('error', '不支持此币种:', _this.crytoname); } _this.on('error', function (error, Device) { Debug.IbctLogErr(COMP, "error:", error); if (Array.isArray(Device)) { _this.DisableMiners(Device); } else if (Device) { _this.DisableMiner(Device); } }); _this.on('warning', function (error) { Debug.IbctLogDbg(COMP, error); }); } getMinerType(name) { for (var i = 0; i < MinerType.length; i++) { if (MinerType[i].name === name) return MinerType[i].type; } return null; } startMiner(Device) { var _this = this if (_this.unlinkShutdown) { setTimeout(function() { _this.startMiner(Device); }, 1000); return } _this.EnableMiner(Device); } restartMiner(Device) { var state = this.GetMinerRunningState(Device) var status = this.GetMinerRunningStatus(Device) var _this = this if (state === 'miner' && !status) { setTimeout(function() { _this.restartMiner(Device); }, 1000); return } if (_this.unlinkShutdown) { Q.try(async () => { await _this.DisableMiner(Device); _this.startMiner(Device); }) return } Q.try(async () => { await this.DisableMiner(Device); await this.EnableMiner(Device); }) } netThread() { var _this = this; if (!_this.pool) return if (_this.checkNet) { clearInterval(_this.checkNet); _this.checkNet = null; _this.unlink = 0; _this.unlinkShutdown = false; } _this.checkNet = setInterval(function () { _this.netPing(function (err) { if (err) { _this.unlink++; } else { _this.unlink = 0; if (_this.unlinkShutdown) { _this.unlinkShutdown = false; _this.emit("warning", '网络重新连通'); } } if (_this.unlink > 2) { _this.unlink = 0; if (!_this.unlinkShutdown) { _this.unlinkShutdown = true; _this.emit("error", '网络失去连接', null); } } }) }, 1000); } netPing(callback) { Ping.ping({ address: this.pool.host, port: this.pool.port, attempts: 1, timeout: 2000 }, function (error, target) { if (error) { Debug.IbctLogDbg(COMP, 'ping', error) callback(target + ": " + error.toString()) return; } callback(null); }) } async ExitMiner() { } proxyConnect(Device) { var _this = this; var user = _this.pool.user; if (_this.pool.user.includes('.')) { user += ('_' + Device.dev.sn); } else { user += ('.' + Device.dev.sn); } if (Device.dev.blacklist > 0) { user += '_bk' + Device.dev.blacklist.toString() } Device.dev.Proxy = new Proxy({ host: _this.pool.host, port: _this.pool.port, user: user, pass: _this.pool.pass, protocolname: _this.protocolname }); Device.dev.Proxy.on("open", function (data) { Debug.IbctLogInfo(COMP, 'Proxy open'); return _this.emit("open", data); }); Device.dev.Proxy.on("authed", function (data) { Debug.IbctLogInfo(COMP, 'Proxy authed'); return _this.emit("authed", data); }); Device.dev.Proxy.on("job", function (data) { Debug.IbctLogInfo(COMP, 'Proxy job'); return _this.emit("job", data); }); Device.dev.Proxy.on("found", function (data) { Debug.IbctLogInfo(COMP, 'Proxy found'); return _this.emit("found", data); }); Device.dev.Proxy.on("accepted", function (data) { Debug.IbctLogInfo(COMP, 'Proxy accepted'); return _this.emit("accepted", data); }); Device.dev.Proxy.on("rejected", function (data) { Debug.IbctLogInfo(COMP, 'Proxy rejected'); return _this.emit("rejected", data); }); Device.dev.Proxy.on("close", function (data) { Debug.IbctLogInfo(COMP, 'Proxy close'); return _this.emit("close", data); }); Device.dev.Proxy.on("error", function (data) { if (data.indexOf('You are blacklisted') >= 0) { // blacklisted Device.dev.blacklist++; } setTimeout(function() { _this.restartMiner(Device) }, 1000); return _this.emit("error", data, null, Device.devID); }); } proxyKill(Device) { Device.dev.Proxy.removeAllListeners("open"); Device.dev.Proxy.removeAllListeners("authed"); Device.dev.Proxy.removeAllListeners("job"); Device.dev.Proxy.removeAllListeners("found"); Device.dev.Proxy.removeAllListeners("accepted"); Device.dev.Proxy.removeAllListeners("rejected"); Device.dev.Proxy.removeAllListeners("close"); Device.dev.Proxy.removeAllListeners("error"); Device.dev.Proxy.kill(); } version_compare(version1, version2) { let v1 = version1.split('.'); let v2 = version2.split('.'); let r0 = parseInt(v1[0]); let r1 = parseInt(v1[1]); let r2 = parseInt(v1[2]); let s = r0 * 100 + r1 * 10 + r2; r0 = parseInt(v2[0]); r1 = parseInt(v2[1]); r2 = parseInt(v2[2]); let d = r0 * 100 + r1 * 10 + r2; if (s === d) return 0; else if (s < d) return 1; else return 0; } async controlMinerSN(Device) { var minerInfo = this.GetMinerInfo(Device); var _this = this; var ret; return new Promise(async (resolve)=> { if (Device.dev.sn) { resolve(0); return } Device.dev.sn = minerInfo.sn; if (Device.dev.sn) { resolve(0); return } ret = _this.version_compare(minerInfo.firmwareVer, '0.0.9'); if (ret) { resolve(0); _this.emit("warning", '此矿机版本过低, 请先升级', null, Device.dev.DevID); Device.dev.sn = Device.devID; return } Device.dev.sn = await SN.GetSN(_this.getMinerType(minerInfo.modelName)); if (!Device.dev.sn) { resolve(1); return } ret = await _this.BurnMinerSNInfo(Device, { sn: Device.dev.sn }); resolve(ret ? 1 : 0) }) } findMiner(Device, callback) { var _this = this; Device.dev.miner = Miner_1({ name: _this.minername, devPath: Device.port, algo: Device.dev.algorithm, varity: 0, crypto: _this.crypto }); Device.dev.miner.on("error", function (data) { return _this.emit("error", data, Device, Device.devID); }) Device.dev.miner.on("warning", function (data) { return _this.emit("warning", data, Device, Device.devID); }) if (Device.dev.miner) { callback(Device); } else { callback(Device, 'Error to find Miner'); } } async InitMiner(Device) { return Device.dev.miner ? await Device.dev.miner.init() : null; } GetMinerInfo(Device) { return Device.dev.miner ? Device.dev.miner.getInfo() : null; } SetMinerDevice(Device) { return Device.dev.miner ? Device.dev.miner.setDevice() : null; } MinerScanWork(Device, work, callback) { return Device.dev.miner ? Device.dev.miner.scanWork(work, callback) : null; } async DetectMiner(Device) { return Device.dev.miner ? await Device.dev.miner.detect(this.minername) : null; } async BurnMinerSNInfo(Device, ptInfo) { return Device.dev.miner ? await Device.dev.miner.burnSNInfo(ptInfo) : null; } StopMiner(Device) { return Device.dev.miner ? Device.dev.miner.stop(false) : null; } ReleaseMiner(Device) { return Device.dev.miner ? Device.dev.miner.release() : null; } SetMinerLedStatus(Device, Enable) { return Device.dev.miner ? Device.dev.miner.setLed(Enable) : null; } RebootHWMiner(Device) { return Device.dev.miner ? Device.dev.miner.reboot() : null; } UpdateMinerImage(Device, Image, Callback) { return Device.dev.miner ? Device.dev.miner.updateImage(Image, Callback) : null; } GetMinerState(Device) { return Device.dev.miner ? Device.dev.miner.getState() : null; } stopScanWork(Device) { return Device.dev.miner ? Device.dev.miner.stopScanWork() : null; } PoolLogin(Device) { Device.dev.pool.handleMessage({ type: 'auth', params: { site_key: null, user: null } }); } PoolSubmit(Device, nonce) { Device.dev.pool.handleMessage({ type: 'submit', params: this.crypto.getSubmitParams(Device, nonce.toString('hex')) }); } PutNonceToPoolQueue(Device) { var work = Device.dev.work; Device.dev.hwPoolQueue.push({ job_id: work.job_id, difficulty: work.difficulty }); } CleanPoolQueue(Device, submit) { var dev = Device.dev; dev.hwPoolQueue = dev.hwPoolQueue.filter(function (data) { if (data.job_id === submit.job_id) { return false; } else { return true; } }); } CleanAllPoolQueue(Device) { if (Device.dev.hwPoolQueue.length) { Device.dev.hwPoolQueue.splice(0, Device.dev.hwPoolQueue.length); } } CheckNonce(Device, nonce) { var hwTarget = Device.dev.work.hwTarget ? Device.dev.work.hwTarget : Device.dev.work.target; var target = Device.dev.work.target; var hash = null; hash = this.crypto.calHash(Device, nonce); if (this.crypto.checkHash(hwTarget, hash)) { if (this.crypto.checkHash(target, hash)) { // Device.dev.minerstatus.txtotal++; this.PutNonceToPoolQueue(Device); this.PoolSubmit(Device, nonce); } return true } else { Device.dev.minerstatus.hardwareErr++; Debug.IbctLogDbg(COMP, 'HardwareErr: nonce', nonce.toString('hex'), '; hwTarget', hwTarget.toString('hex'), '; calTarget', hash.toString('hex')); return false } } setMinerTargetByWork(Device, Work) { var minerstatus = Device.dev.minerstatus; if (Work.hwdifficulty) return; minerstatus.target = Work.hwTarget ? Work.hwTarget : Work.target; minerstatus.target = minerstatus.target.toString('hex'); Work.hwdifficulty = this.crypto.targetToDiff(minerstatus.target); minerstatus.difficulty = Work.hwdifficulty; } GetTime() { return Math.floor(((new Date())).getTime() / 1000); } ConvertUnion(Hashrate) { if (Hashrate < 1000) return Hashrate.toString() + ' H/s'; else if (Hashrate < 1000000) return (Hashrate / 1000).toFixed(2) + ' kH/s'; else if (Hashrate < 1000000000) return (Hashrate / 1000000).toFixed(2) + ' MH/s'; else return (Hashrate / 1000000000).toFixed(2) + ' GH/s'; } updateMinerAvHashrate(Device, onlyCal) { var dev = Device.dev; var minerstatus = dev.minerstatus; var curtime = this.GetTime(); if (onlyCal) { minerstatus.avHashrate = this.ConvertUnion(dev.hwCal / (curtime - dev.stime)); return; } if (!minerstatus.difficulty) return; dev.hwCal += minerstatus.difficulty; minerstatus.avHashrate = this.ConvertUnion(dev.hwCal / (curtime - dev.stime)); } updateMinerPoolHashrate(Device, submit) { var dev = Device.dev; var curtime = this.GetTime(); var minerstatus = Device.dev.minerstatus; var _this = this; if (!submit) { minerstatus.plHashrate = _this.ConvertUnion(dev.hwPool / (curtime - dev.stime)); return } dev.hwPoolQueue = dev.hwPoolQueue.filter(function (data) { if (data.job_id === submit.job_id) { dev.hwPool += data.difficulty; minerstatus.share += data.difficulty; minerstatus.plHashrate = _this.ConvertUnion(dev.hwPool / (curtime - dev.stime)); return false; } else { return true; } }); } updateMinerInstantHashrate(Device, onlyCal) { var hwInstant = Device.dev.hwInstant; var minerstatus = Device.dev.minerstatus; var work = Device.dev.work; var newHash = { difficulty: onlyCal ? 0 : work.hwdifficulty, time: this.GetTime() }; var allTime = 0; var allhash = 0; var times = 0; hwInstant.push(newHash); Device.dev.hwInstant = hwInstant.filter(function (dev) { times = newHash.time - dev.time; if (times > 40) { return false; } else { if (times > allTime) allTime = times; allhash += dev.difficulty; return true; } }) times = newHash.time - Device.dev.stime; if (times < 40) { minerstatus.hashrate = '0 H/s' } else { minerstatus.hashrate = this.ConvertUnion(allhash / allTime); } } updateMinerRate(Device) { this.updateMinerAvHashrate(Device, false); this.updateMinerInstantHashrate(Device, false); } updateMinerTemperature(Device) { var minerstatus = Device.dev.minerstatus; var minerstate = this.GetMinerState(Device); minerstatus.temperatue = minerstate.temp.toString() + ' ℃'; } DumpMinerStatus(Device, ms) { var _this = this; Device.dev.dump = setInterval(function () { _this.updateMinerTemperature(Device); Debug.IbctLogDbg(COMP, JSON.stringify(Device.dev.minerstatus)); }, ms); } DisableDumpMinerStatus(Device) { if (Device.dev.dump) { clearInterval(Device.dev.dump); } } MinerPutJob(Device, data) { Device.dev.jobQueue.push(data); } MinerCleanJob(Device) { if (Device.dev.jobQueue.length < 4) return for (var i = 0; i < (Device.dev.jobQueue.length - 4); i++) { Device.dev.jobQueue.shift(); } } MinerCleanAllJob(Device) { if (Device.dev.jobQueue.length) { Device.dev.jobQueue.splice(0, Device.dev.jobQueue.length); } } MinerGetJob(Device) { return Device.dev.jobQueue.pop(); } MinerThread(Device) { var _this = this; var job = {}; var Work = { job_id: null, snonce: 0, enonce: 0xffffffff, difficulty: 0, target: null, hwTarget: null, hwdifficulty: null, data: null, ntime: null, clean: false }; if (!_this.GetMinerRunningStatus(Device)) { return; } job = _this.MinerGetJob(Device); if (job === undefined) { setTimeout(function () { _this.MinerThread(Device); }, 100); return; } // Debug.IbctLogInfo(COMP, 'MinerThread', job); if (!_this.crypto.JobtoWork(job, Work)) { this.emit('error', '任务转换失败', Device, Device.devID); return; } if (!_this.GetMinerRunningStatus(Device)) { return; } // set current work Device.dev.work = Work; _this.MinerScanWork(Device, Work, function (err, data) { if (err) { Debug.IbctLogErr(COMP, 'ScanWork Err: ', err); return; } if (data !== null) { Device.dev.minerstatus.total++; if (!Work.hwdifficulty) { _this.setMinerTargetByWork(Device, Work); } if (_this.CheckNonce(Device, data)) { _this.updateMinerRate(Device); } return; } setTimeout(function () { _this.MinerThread(Device); }, 50); }); } setSubmitResult(Device, res) { Device.dev.submitResult.push(res); if (Device.dev.submitResult.length > 10) Device.dev.submitResult.shift(); } checkSubmitResult(Device) { var res = 0; if (!Device.dev.submitResult.length) return false; for (var i = 0; i < Device.dev.submitResult.length; i++) res += Device.dev.submitResult[i]; return (res > 5) ? true : false; } cleanAllSubmitResult(Device) { if (Device.dev.submitResult.length) { Device.dev.submitResult.splice(0, Device.dev.submitResult.length); } } errRelease(Device) { var _this = this; Debug.IbctLogDbg(COMP, 'errRelease'); _this.proxyKill(Device); Device.dev.poolQueue.stop(); _this.DisableDumpMinerStatus(Device); _this.CleanAllPoolQueue(Device); _this.MinerCleanAllJob(Device); _this.cleanAllSubmitResult(Device); _this.SetMinerRunningState(Device, 'standy'); Device.dev.poolQueue.removeAllListeners("job:" + Device.dev.id); Device.dev.poolQueue.removeAllListeners("authed:" + Device.dev.id); Device.dev.poolQueue.removeAllListeners("accepted:" + Device.dev.id); Device.dev.poolQueue.removeAllListeners("rejected:" + Device.dev.id); Device.dev.poolQueue.removeAllListeners("error:" + Device.dev.id); } async StartMinerThread(Device, done) { var _this = this; Debug.IbctLogDbg(COMP, 'StartMinerThread'); if (_this.GetMinerRunningStatus(Device)) { return; } _this.DumpMinerStatus(Device, 5000); Device.dev.stime = _this.GetTime(); Device.dev.hwCal = 0; Device.dev.hwPool = 0; Device.dev.poolQueue.start(); _this.proxyConnect(Device); _this.SetMinerRunningState(Device, 'miner'); Device.dev.pool = Device.dev.Proxy.createProxy(Device.dev.id, Device.dev.poolQueue); Device.dev.poolQueue.on("job:" + Device.dev.id, function (data) { var packet = null; if (_this.protocolname === 'stratum') { packet = _this.crypto.stratum_notify(data); } else { packet = data; } // Debug.IbctLogInfo(COMP, 'job poolQueue: ', packet); if (packet.clean) { _this.stopScanWork(Device) } _this.MinerPutJob(Device, packet); _this.MinerCleanJob(Device); }) Device.dev.poolQueue.on("authed:" + Device.dev.id, function (data) { Debug.IbctLogDbg(COMP, 'authed poolQueue: ', data); Device.dev.poolId = data.auth; }) Device.dev.poolQueue.on("accepted:" + Device.dev.id, function (data) { Debug.IbctLogDbg(COMP, 'accepted poolQueue: ', JSON.stringify(data.nonce)); _this.setSubmitResult(Device, 0); Device.dev.minerstatus.accepted++; _this.updateMinerPoolHashrate(Device, data.nonce) }) Device.dev.poolQueue.on("rejected:" + Device.dev.id, function (data) { Debug.IbctLogDbg(COMP, 'rejected poolQueue: ', JSON.stringify(data.nonce)); Debug.IbctLogDbg(COMP, 'rejected poolQueue: ', JSON.stringify(data.err)); _this.CleanPoolQueue(Device, data.nonce); _this.setSubmitResult(Device, 1); Device.dev.minerstatus.rejected++; if (data.err && data.err.message.indexOf('You are in blacklist') >= 0) { Device.dev.blacklist++; _this.restartMiner(Device); _this.emit("error", '矿机进入黑名单状态,将换用户名重启', null, Device.devID); } if (_this.checkSubmitResult(Device)) { _this.restartMiner(Device); _this.emit("error", '矿机rejected过多,将重启', null, Device.devID); } }) Device.dev.poolQueue.on("error:" + Device.dev.id, function (data) { Debug.IbctLogDbg(COMP, 'error poolQueue: ', data); }) var ret = await _this.InitMiner(Device); if (ret) { _this.emit("error", '初始化矿机失败', null, Device.devID); _this.errRelease(Device); return false; } _this.PoolLogin(Device); // for MinerThread _this.SetMinerRunningStatus(Device, true); _this.MinerThread(Device); return true } async StopMinerThread(Device, flags) { var _this = this; Debug.IbctLogDbg(COMP, 'StopMinerThread'); if (!_this.GetMinerRunningStatus(Device)) { return; } _this.proxyKill(Device); Device.dev.poolQueue.stop(); if (flags) { Device.dev.miner.removeAllListeners("error"); Device.dev.miner.removeAllListeners("warning"); await _this.ReleaseMiner(Device); } else { await _this.StopMiner(Device); } _this.DisableDumpMinerStatus(Device); _this.SetMinerRunningState(Device, 'standy'); _this.CleanAllPoolQueue(Device); _this.MinerCleanAllJob(Device); _this.cleanAllSubmitResult(Device); Device.dev.poolQueue.removeAllListeners("job:" + Device.dev.id); Device.dev.poolQueue.removeAllListeners("authed:" + Device.dev.id); Device.dev.poolQueue.removeAllListeners("accepted:" + Device.dev.id); Device.dev.poolQueue.removeAllListeners("rejected:" + Device.dev.id); Device.dev.poolQueue.removeAllListeners("error:" + Device.dev.id); } HasExistMiner(Device) { return this.RunningMiner.some(function (dev) { return dev.devID === Device.devID; }); } GetMinerByDevID(id) { var device = null; this.RunningMiner.forEach(function (Dev) { if (Dev.devID === id) device = Dev; }); return device; } GetMinerRunningStatus(Device) { return this.RunningMiner.some(function (Dev) { if (Dev.devID === Device.devID) return Dev.enable; }); } SetMinerRunningStatus(Device, status) { this.RunningMiner.forEach(function (Dev, index) { if (Dev.devID === Device.devID) { Dev.enable = status; // set minerstatus state Dev.dev.minerstatus.state = status ? 'on' : 'off'; } }) } GetMinerRunningState(Device) { var status = null; this.RunningMiner.forEach(function (Dev) { if (Dev.devID === Device.devID) status = Dev.status; }); return status; } SetMinerRunningState(Device, status) { this.RunningMiner.forEach(function (Dev, index) { if (Dev.devID === Device.devID) { Dev.status = status; } }) } minuteToString(s) { var d = Math.floor(s / 86400); s %= 86400; var h = Math.floor(s / 3600); s %= 3600; var m = Math.floor(s / 60); return d + 'd ' + h + 'h ' + m + 'm'; } GetMinerStatus(Device) { var status = { devID: 0, miningName: null, miningSN: null, comm: null, state: 'off', version: '1.0.0', miningType: 'ltc', hashrate: '0 KH/s', avHashrate: '0 KH/s', plHashrate: '0 KH/s', share: 0, hardwareErr: 0, rejected: 0, nonces: 0, accepted: 0, temperatue: '0 ℃', elapsed: '0d0h0m', pools: null }; var dev = null; var minerInfo = null; var minerstatus = null; dev = this.GetMinerByDevID(Device.devID); if (!dev) return null; status.comm = dev.port; status.devID = dev.devID; status.miningType = this.cryptoname; status.miningSN = dev.dev.sn; minerInfo = this.GetMinerInfo(dev); if (minerInfo) { status.miningName = minerInfo.modelName; status.version = minerInfo.firmwareVer; } if (this.GetMinerRunningStatus(dev)) { minerstatus = dev.dev.minerstatus; status.state = minerstatus.state; this.updateMinerInstantHashrate(dev, true); status.hashrate = minerstatus.hashrate; this.updateMinerAvHashrate(dev, true); status.avHashrate = minerstatus.avHashrate; this.updateMinerPoolHashrate(dev, null); status.plHashrate = minerstatus.plHashrate; status.share = minerstatus.share; status.accepted = minerstatus.accepted; status.rejected = minerstatus.rejected; status.hardwareErr = minerstatus.hardwareErr; status.nonces = minerstatus.total; status.temperatue = minerstatus.temperatue; status.elapsed = this.minuteToString(this.GetTime() - dev.dev.stime) + '_' + dev.dev.jobQueue.length.toString() + '_' + dev.dev.hwPoolQueue.length.toString() + '_' + dev.dev.hwInstant.length.toString(); status.pools = this.pool; } return status; } GetMinersStatus(Devices) { var status = []; var temp = null; var _this = this; Devices.forEach(function (Dev, index) { temp = _this.GetMinerStatus(Dev); if (temp) { status.push(temp); } }) return status; } async EnableMiner(Device) { var _this = this; var dev = null; var ret; dev = _this.GetMinerByDevID(Device.devID); if (!dev) return; dev.dev.mutex.lock(async () => { if (dev && !_this.GetMinerRunningStatus(dev)) { // mining or burn status, need not start to mine if (_this.GetMinerRunningState(dev) === 'burn' || _this.GetMinerRunningState(dev) === 'miner') return; ret = await _this.StartMinerThread(dev); if (ret) _this.SetMinerRunningStatus(dev, true); } dev.dev.mutex.unlock(); }) } async EnableMiners(Devices) { if (!this.pool) { this.emit("error", '开始挖矿前,请先设置矿池'); return; } for (var i = 0; i < Devices.length; i++) { await this.EnableMiner(Devices[i]); } } SetMinerConfig(setName, settings) { var alive = false; if (setName === 'pool') { for (var i = 0; i < this.RunningMiner.length; i++) { if (this.GetMinerRunningStatus(this.RunningMiner[i])) { alive = true; break; } } if (alive) { this.emit("error", '设置矿池前,请先停止挖矿'); return; } else { this.pool = settings; this.netThread(); } } } async DisableMiner(Device) { var _this = this; var dev = null; dev = _this.GetMinerByDevID(Device.devID); if (!dev) return dev.dev.mutex.lock(async () => { if (dev && _this.GetMinerRunningStatus(dev)) { await _this.StopMinerThread(dev, false); _this.SetMinerRunningStatus(dev, false); } dev.dev.mutex.unlock(); }) } async DisableMiners(Devices) { for (var i = 0; i < Devices.length; i++) { await this.DisableMiner(Devices[i]); } } async AddMiner(Device) { var _this = this; return new Promise(function (resolve, reject) { Device.mutex.lock(async () => { if (!_this.HasExistMiner(Device)) { var Dev = __assign({}, Device, { enable: false, dev: { // miner id id: uuid.v4(), // miner status: standby; miner; burn status: 'standy', // miner SN sn: null, // for blacklist blacklist: 0, // mutex mutex: locks.createMutex(), // pool set id to miner poolId: 0, // proxy Proxy: null, // connected pool pool: null, // communication with proxy poolQueue: new Queue_1.default(), // job queue jobQueue: [], // miner device miner: null, // miner algorithm algorithm: Algo_1({ name: _this.algoname }), // current work work: null, // setInterval dump: null, // rejected submitResult: [], // start run time stime: 0, // Chip calulate number for avhashrate hwCal: 0, // 20s hashrate hwInstant: [], // pool hw hashrate hwPool: 0, // pool nonce id&difficult queue hwPoolQueue: [], // miner status minerstatus: { state: 'off', target: 0, difficulty: 0, share: 0, hashrate: '0 KH/s', avHashrate: '0 KH/s', plHashrate: '0 KH/s', accepted: 0, rejected: 0, hardwareErr: 0, total: 0, temperatue: '0 ℃' } } }) _this.findMiner(Dev, function (data, err) { if (err) { _this.emit("error", '查找矿机失败', null, Dev.devID); Device.mutex.unlock(); return resolve(1); } _this.RunningMiner.push(Dev); Device.mutex.unlock(); resolve(0); }) } }) }) } async AddMiners(Devices) { for (var i = 0; i < Devices.length; i++) { await this.AddMiner(Devices[i]); } } async connectMiner(Device) { var ret; var dev; dev = this.GetMinerByDevID(Device.devID); if (!dev) return false ret = await this.DetectMiner(dev); if (ret) { this.emit("error", '探测矿机失败', null, dev.devID); return false } ret = await this.controlMinerSN(dev); if (ret) { this.emit("error", '处理矿机条码失败', null, dev.devID); return false } return true } async connectMiners(Devices) { for (var i = 0; i < Devices.length; i++) { await this.connectMiner(Devices[i]); } } async RemoveMiner(Device) { var _this = this; var dev = null; await Device.mutex.lock(async () => { if (_this.HasExistMiner(Device)) { dev = _this.GetMinerByDevID(Device.devID); if (!dev) return; dev.dev.mutex.lock(async () => { if (dev) { if (_this.GetMinerRunningStatus(dev)) { await _this.StopMinerThread(dev, true); _this.SetMinerRunningStatus(dev, false); } else { // throngh have stop miner, but need to remove miner totally dev.dev.miner.removeAllListeners("error"); dev.dev.miner.removeAllListeners("warning"); await _this.ReleaseMiner(dev); } } _this.RunningMiner = _this.RunningMiner.filter(function (dev) { if (dev.devID !== Device.devID) { return true; } else { return false; } }); // dev.dev.mutex.resetQueue(); dev.dev.mutex._waiting = []; dev.dev.mutex.unlock(); }) } Device.mutex.unlock(); }) } async RemoveMiners(Devices) { var _this = this; for (var i = 0; i < Devices.length; i++) { await _this.RemoveMiner(Devices[i]); } } RebootMiner(Device) { var dev; dev = this.GetMinerByDevID(Device.devID); if (!dev) return null; // reboot miner may cause usb plug-in & plug-out this.RebootHWMiner(dev); } RebootMiners(Devices) { var _this = this; Devices.forEach(function (Device, index) { _this.RebootMiner(Device); }) } SetMinerLed(Device, Enable) { var dev = this.GetMinerByDevID(Device.devID); if (!dev) return null; this.SetMinerLedStatus(dev, Enable); } SetMinersLed(Devices, Enable) { var _this = this; Devices.forEach(function (Device, index) { _this.SetMinerLed(Device, Enable); }) } CheckFirmware(Image) { var temp = Buffer.from(Image, 0, 64); var head = { magic: 0, model_name: null, version: null, crc: 0, res: null } if (!Image) return false; head.magic = temp.readUInt32LE(0); head.model_name = temp.toString('utf8', 4, 19); head.version = temp.toString('utf8', 20, 27); head.crc = temp.readUInt32LE(28); head.res = temp.toString('utf8', 32, 63); Debug.IbctLogDbg(COMP, JSON.stringify(head)); if (head.magic !== 0x20190428) return false; if (head.model_name.slice(0, this.minername.length) !== this.minername) return false; var crcValue = crc32(Image.slice(64)); if (parseInt('0x' + crcValue, 16) !== head.crc) return false; Debug.IbctLogDbg('Burn Image Check OK'); return true; } async BurnMinerFirmware(Device, Image, Callback) { var dev = this.GetMinerByDevID(Device.devID); if (!dev) return; await this.DisableMiner(dev); this.SetMinerRunningState(dev, 'burn'); if (!this.CheckFirmware(Image)) { Callback('非法固件,请联系Intchains'); return; } this.UpdateMinerImage(dev, Image.slice(64), Callback); } async BurnMinersFirmware(Devices, Image, Callback) { for (var i = 0; i < Devices.length; i++) { await this.BurnMinerFirmware(Devices[i], Image, Callback); } } } module.exports = function RunMiner(options = {}) { return new Miner(options); };