node-miner
Version:
With this miner you can easily mine cryptocurrencies [Monero (XMR)](https://getmonero.org/) and [Electroneum (ETN)](http://electroneum.com/) on any stratum pool from node.js with the highest hashrate on your hardware. To get maximum hashrate this package
290 lines (289 loc) • 10.1 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var EventEmitter = require("events");
var net = require("net");
var tls = require("tls");
var uuid = require("uuid");
var Queue_1 = require("./Queue");
var Metrics_1 = require("./Metrics");
var Connection = /** @class */ (function (_super) {
__extends(Connection, _super);
function Connection(options) {
var _this = _super.call(this) || this;
_this.id = uuid.v4();
_this.host = null;
_this.port = null;
_this.ssl = null;
_this.online = null;
_this.socket = null;
_this.queue = null;
_this.buffer = "";
_this.rpcId = 1;
_this.rpc = {};
_this.auth = {};
_this.minerId = {};
_this.miners = [];
_this.donations = [];
_this.host = options.host;
_this.port = options.port;
_this.ssl = options.ssl;
_this.donation = options.donation;
return _this;
}
Connection.prototype.connect = function () {
var _this = this;
if (this.online) {
this.kill();
}
this.queue = new Queue_1.default();
if (this.ssl) {
this.socket = tls.connect(+this.port, this.host, { rejectUnauthorized: false });
}
else {
this.socket = net.connect(+this.port, this.host);
}
this.socket.on("connect", this.ready.bind(this));
this.socket.on("error", function (error) {
if (_this.online) {
console.warn("socket error (" + _this.host + ":" + _this.port + ")", error.message);
_this.emit("error", error);
_this.connect();
}
});
this.socket.on("close", function () {
if (_this.online) {
console.log("socket closed (" + _this.host + ":" + _this.port + ")");
_this.emit("close");
}
});
this.socket.setKeepAlive(true);
this.socket.setEncoding("utf8");
this.online = true;
if (!this.donation) {
Metrics_1.connectionsCounter.inc();
}
};
Connection.prototype.kill = function () {
if (this.socket != null) {
try {
this.socket.end();
this.socket.destroy();
}
catch (e) {
console.warn("something went wrong while destroying socket (" + this.host + ":" + this.port + "):", e.message);
}
}
if (this.queue != null) {
this.queue.stop();
}
if (this.online) {
this.online = false;
if (!this.donation) {
Metrics_1.connectionsCounter.dec();
}
}
};
Connection.prototype.ready = function () {
var _this = this;
// message from pool
this.socket.on("data", function (chunk) {
_this.buffer += chunk;
while (_this.buffer.includes("\n")) {
var newLineIndex = _this.buffer.indexOf("\n");
var stratumMessage = _this.buffer.slice(0, newLineIndex);
_this.buffer = _this.buffer.slice(newLineIndex + 1);
_this.receive(stratumMessage);
}
});
// message from miner
this.queue.on("message", function (message) {
if (!_this.online) {
return false;
}
if (!_this.socket.writable) {
if (message.method === "keepalived") {
return false;
}
var retry = message.retry ? message.retry * 2 : 1;
var ms = retry * 100;
message.retry = retry;
setTimeout(function () {
_this.queue.push({
type: "message",
payload: message
});
}, ms);
return false;
}
try {
if (message.retry) {
delete message.retry;
}
_this.socket.write(JSON.stringify(message) + "\n");
}
catch (e) {
console.warn("failed to send message to pool (" + _this.host + ":" + _this.port + "): " + JSON.stringify(message));
}
});
// kick it
this.queue.start();
this.emit("ready");
};
Connection.prototype.receive = function (message) {
var data = null;
try {
data = JSON.parse(message);
}
catch (e) {
return console.warn("invalid stratum message:", message);
}
// it's a response
if (data.id) {
var response = data;
if (!this.rpc[response.id]) {
// miner is not online anymore
return;
}
var minerId = this.rpc[response.id].minerId;
var method = this.rpc[response.id].message.method;
switch (method) {
case "login": {
if (response.error && response.error.code === -1) {
this.emit(minerId + ":error", {
error: "invalid_site_key"
});
return;
}
var result = response.result;
var auth = result.id;
this.auth[minerId] = auth;
this.minerId[auth] = minerId;
this.emit(minerId + ":authed", auth);
if (result.job) {
this.emit(minerId + ":job", result.job);
}
break;
}
case "submit": {
var job = this.rpc[response.id].message.params;
if (response.result && response.result.status === "OK") {
this.emit(minerId + ":accepted", job);
}
else if (response.error) {
this.emit(minerId + ":error", response.error);
}
break;
}
default: {
if (response.error && response.error.code === -1) {
this.emit(minerId + ":error", response.error);
}
}
}
delete this.rpc[response.id];
}
else {
// it's a request
var request = data;
switch (request.method) {
case "job": {
var jobParams = request.params;
var minerId = this.minerId[jobParams.id];
if (!minerId) {
// miner is not online anymore
return;
}
this.emit(minerId + ":job", request.params);
break;
}
}
}
};
Connection.prototype.send = function (id, method, params) {
if (params === void 0) { params = {}; }
var message = {
id: this.rpcId++,
method: method,
params: params
};
switch (method) {
case "login": {
// ..
break;
}
case "keepalived": {
if (this.auth[id]) {
var keepAliveParams = message.params;
keepAliveParams.id = this.auth[id];
}
else {
return false;
}
}
case "submit": {
if (this.auth[id]) {
var submitParams = message.params;
submitParams.id = this.auth[id];
}
else {
return false;
}
}
}
this.rpc[message.id] = {
minerId: id,
message: message
};
this.queue.push({
type: "message",
payload: message
});
};
Connection.prototype.addMiner = function (miner) {
if (this.miners.indexOf(miner) === -1) {
this.miners.push(miner);
}
};
Connection.prototype.removeMiner = function (minerId) {
var miner = this.miners.find(function (x) { return x.id === minerId; });
if (miner) {
this.miners = this.miners.filter(function (x) { return x.id !== minerId; });
this.clear(miner.id);
}
};
Connection.prototype.addDonation = function (donation) {
if (this.donations.indexOf(donation) === -1) {
this.donations.push(donation);
}
};
Connection.prototype.removeDonation = function (donationId) {
var donation = this.donations.find(function (x) { return x.id === donationId; });
if (donation) {
this.donations = this.donations.filter(function (x) { return x.id !== donationId; });
this.clear(donation.id);
}
};
Connection.prototype.clear = function (id) {
var _this = this;
var auth = this.auth[id];
delete this.auth[id];
delete this.minerId[auth];
Object.keys(this.rpc).forEach(function (key) {
if (_this.rpc[key].minerId === id) {
delete _this.rpc[key];
}
});
};
return Connection;
}(EventEmitter));
exports.default = Connection;