UNPKG

intchains_ibctminer

Version:

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

802 lines (768 loc) 23.7 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 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; }; 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.crypto = cryptocurrency({ name: _this.cryptoname }); if (!_this.crypto) { this.emit('error', 'Get crypto Err'); } _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); }); } async ExitMiner() { } proxyConnect(Device) { var _this = this; var user = _this.pool.user; if (_this.pool.user.includes('.')) { user += ('_' + Device.devID); } else { user += ('.' + Device.devID); } 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) { _this.DisableMiner(Device); setTimeout(function () { _this.EnableMiner(Device); }, 2000); return _this.emit("error", data + ' About Miner ' + 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(); } 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.dev.miner.on("warning", function (data) { return _this.emit("warning", data); }) 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; } StopMiner(Device) { return Device.dev.miner ? Device.dev.miner.stop() : 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 }); } 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); } } else { Device.dev.minerstatus.hardwareErr++; Debug.IbctLogDbg(COMP, 'HardwareErr: nonce', nonce.toString('hex'), '; hwTarget', hwTarget.toString('hex'), '; calTarget', hash.toString('hex')); } } 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) { var dev = Device.dev; var minerstatus = dev.minerstatus; var curtime = this.GetTime(); 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; dev.hwPoolQueue = dev.hwPoolQueue.filter(function (data) { if (data.job_id === submit.job_id) { dev.hwPool += data.difficulty; minerstatus.plHashrate = _this.ConvertUnion(dev.hwPool / (curtime - dev.stime)); return false; } else { return true; } }); } updateMinerInstantHashrate(Device) { var hwInstant = Device.dev.hwInstant; var minerstatus = Device.dev.minerstatus; var work = Device.dev.work; var newHash = { difficulty: work.hwdifficulty, time: this.GetTime() }; var allTime = 0; var allhash = 0; var times = 0; hwInstant.push(newHash); 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); this.updateMinerInstantHashrate(Device); } 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); } 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', 'Job to Work Error', Device); 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); } _this.updateMinerRate(Device); _this.CheckNonce(Device, data); return; } setTimeout(function () { _this.MinerThread(Device); }, 50); }); } async StartMinerThread(Device, done) { var _this = this; Debug.IbctLogDbg(COMP, 'StartMinerThread'); if (_this.GetMinerRunningStatus(Device)) { _this.StopMinerThread(Device); } _this.DumpMinerStatus(Device, 5000); Device.dev.stime = _this.GetTime(); 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); }) 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)); Device.dev.minerstatus.accepted++; _this.updateMinerPoolHashrate(Device, data.nonce) }) Device.dev.poolQueue.on("rejected:" + Device.dev.id, function (data) { Debug.IbctLogDbg(COMP, 'rejected poolQueue: ', data); Device.dev.minerstatus.rejected++; }) Device.dev.poolQueue.on("error:" + Device.dev.id, function (data) { Debug.IbctLogDbg(COMP, 'error poolQueue: ', data); }) var ret = await _this.DetectMiner(Device); if (ret) { _this.emit("error", 'Detect Miner ' + Device.devID + ' Error'); return; } ret = await _this.InitMiner(Device); if (ret) { _this.emit("error", 'Init Miner ' + Device.devID + ' Error'); return; } _this.MinerThread(Device); _this.PoolLogin(Device); } StopMinerThread(Device) { var _this = this; Debug.IbctLogDbg(COMP, 'StopMinerThread'); if (!_this.GetMinerRunningStatus(Device)) { return; } _this.proxyKill(Device); Device.dev.poolQueue.stop(); _this.StopMiner(Device); Device.dev.miner.removeAllListeners("error"); Device.dev.miner.removeAllListeners("warning"); _this.DisableDumpMinerStatus(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); } 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, state: 'off', version: '1.0.0', hashrate: '0 KH/s', avHashrate: '0 KH/s', 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.devID = dev.devID; minerInfo = this.GetMinerInfo(dev); if (minerInfo) { status.miningName = minerInfo.modelName; status.version = minerInfo.firmwareVer; } if (this.GetMinerRunningStatus(Device)) { minerstatus = dev.dev.minerstatus; status.state = minerstatus.state; status.hashrate = minerstatus.hashrate; status.avHashrate = minerstatus.avHashrate; status.plHashrate = minerstatus.plHashrate; 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); 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; dev = _this.GetMinerByDevID(Device.devID); if (dev && !_this.GetMinerRunningStatus(dev)) { // mining or burn status, need not start to mine if (_this.GetMinerRunningState(dev) === 'burn' || _this.GetMinerRunningState(dev) === 'miner') return; await _this.StartMinerThread(dev); _this.SetMinerRunningStatus(dev, true); } } async EnableMiners(Devices) { if (!this.pool) { this.emit("error", 'Set Pool First'); 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", 'Disable Some Miners First'); return; } else { this.pool = settings; } } } async DisableMiner(Device) { var _this = this; var dev = null; dev = _this.GetMinerByDevID(Device.devID); if (dev && _this.GetMinerRunningStatus(dev)) { await _this.StopMinerThread(dev); _this.SetMinerRunningStatus(dev, false); } } async DisableMiners(Devices) { for (var i = 0; i < Devices.length; i++) { await this.DisableMiner(Devices[i]); } } AddMiner(Device) { var _this = this; if (!_this.HasExistMiner(Device)) { var Dev = __assign({}, Device, { enable: false, dev: { // miner id id: uuid.v4(), // miner status: standby; miner; burn status: 'standy', // 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, // 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, 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", 'Find Miner ' + data.devID + ' Error'); return; } _this.RunningMiner.push(Dev); }) } } AddMiners(Devices) { var _this = this; Devices.forEach(function (Device, index) { _this.AddMiner(Device); }) } RemoveMiner(Device) { var _this = this; if (_this.HasExistMiner(Device)) { _this.RunningMiner = _this.RunningMiner.filter(function (dev) { if (dev.devID !== Device.devID) { return true; } else { if (_this.GetMinerRunningStatus(dev)) { _this.DisableMiner(Device); } return false; } }); } } RemoveMiners(Devices) { var _this = this; Devices.forEach(function (Device, index) { _this.DisableMiner(Device); }) } 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; } BurnMinerFirmware(Device, Image, Callback) { var dev = this.GetMinerByDevID(Device.devID); if (!dev) return; if (this.GetMinerRunningStatus(dev)) { this.DisableMiner(dev); } this.SetMinerRunningState(dev, 'burn'); if (!this.CheckFirmware(Image)) { Callback('Check Firmware Error'); return; } this.UpdateMinerImage(dev, Image.slice(64), Callback); } BurnMinersFirmware(Devices, Image, Callback) { var _this = this; Devices.forEach(function (Device, index) { _this.BurnMinerFirmware(Device, Image, Callback); }) } } module.exports = function RunMiner(options = {}) { return new Miner(options); };