Updated structure
This commit is contained in:
parent
2b5aefd7b4
commit
cea68b771f
12
README.md
12
README.md
@ -32,16 +32,6 @@ Requirements
|
|||||||
------------
|
------------
|
||||||
* node v0.10+
|
* node v0.10+
|
||||||
* coin daemon
|
* coin daemon
|
||||||
* PostgreSQL
|
|
||||||
* npm dependencies
|
|
||||||
* [scrypt256-hash](https://github.com/zone117x/node-scrypt256-hash)
|
|
||||||
* [scrypt-jane-hash](https://github.com/zone117x/node-scrypt-jane-hash)
|
|
||||||
* [quark-hash](https://github.com/zone117x/node-quark-hash)
|
|
||||||
* [binpack](https://github.com/russellmcc/node-binpack)
|
|
||||||
* [bignum](https://github.com/justmoon/node-bignum)
|
|
||||||
* [buffertools] (https://github.com/bnoordhuis/node-buffertools)
|
|
||||||
* [base58-native](https://github.com/gasteve/node-base58)
|
|
||||||
* [async](https://github.com/caolan/async)
|
|
||||||
|
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
@ -98,7 +88,7 @@ Installation
|
|||||||
* To start the poolserver run:
|
* To start the poolserver run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
node init.js
|
node index.js
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,13 +6,11 @@
|
|||||||
"address": "n3s8iDk1onxyY2nuC1k4HoRQFGJ7BhjFcq",
|
"address": "n3s8iDk1onxyY2nuC1k4HoRQFGJ7BhjFcq",
|
||||||
"stratumPort": 3334,
|
"stratumPort": 3334,
|
||||||
"difficulty": 8,
|
"difficulty": 8,
|
||||||
"blockRefreshInterval": 1,
|
"blockRefreshInterval": 5,
|
||||||
"merkleRefreshInterval": 60,
|
|
||||||
"daemon": {
|
"daemon": {
|
||||||
"host": "localhost",
|
"host": "localhost",
|
||||||
"port": 19334,
|
"port": 19334,
|
||||||
"user": "testnet",
|
"user": "testnet",
|
||||||
"password": "testnet1"
|
"password": "testnet1"
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,40 +0,0 @@
|
|||||||
var events = require('events');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This ShareManager Events table: will emit the following events:
|
|
||||||
*
|
|
||||||
* LISTENS on:
|
|
||||||
* - pool('share')
|
|
||||||
**/
|
|
||||||
|
|
||||||
var ShareManager = exports.ShareManager = function(pool) {
|
|
||||||
pool.on('share', function(isValid, data) {
|
|
||||||
if (isValid) {
|
|
||||||
handleValidShare(
|
|
||||||
data.client,
|
|
||||||
data.blockHeaderHex,
|
|
||||||
data.jobId,
|
|
||||||
data.extraNonce1,
|
|
||||||
data.extraNonce2,
|
|
||||||
data.nTime,
|
|
||||||
data.nonce);
|
|
||||||
} else {
|
|
||||||
handleInvalidShare(
|
|
||||||
data.client,
|
|
||||||
data.error[0],
|
|
||||||
data.error[1]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleValidShare(client, headerHex, jobId, extraNonce1, extraNonce2, nTime, nonce) {
|
|
||||||
console.log("A new Valid share from "+client.workerName+" has arrived! - "+headerHex);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleInvalidShare(client, errorCode, errorDescription) {
|
|
||||||
console.log("Invalid share form "+client.workerName+" ErrorCode: "+errorCode+ " ErrorDescription: "+errorDescription);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ShareManager.prototype.__proto__ = events.EventEmitter.prototype;
|
|
||||||
|
|
||||||
|
|
||||||
264
index.js
264
index.js
@ -1,233 +1,67 @@
|
|||||||
var net = require('net');
|
var net = require('net');
|
||||||
var events = require('events');
|
var fs = require('fs');
|
||||||
var fs = require('fs');
|
var path = require('path');
|
||||||
var async = require('async');
|
var pool = require('lib/pool.js');
|
||||||
var daemon = require('./libs/daemon.js');
|
|
||||||
var stratum = require('./libs/stratum.js');
|
|
||||||
var jobManager = require('./libs/jobManager.js');
|
|
||||||
var util = require('./libs/util.js');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main pool object. It emits the following events:
|
|
||||||
* - 'started'() - when the pool is effectively started.
|
var index = module.exports = function index(options){
|
||||||
* - 'share'(isValid, dataObj) - In case it's valid the dataObj variable will contain (TODO) and in case it's invalid (TODO)
|
|
||||||
*/
|
|
||||||
var pool = module.exports = function pool(coin, authorizeFn){
|
|
||||||
|
|
||||||
var _this = this;
|
var _this = this;
|
||||||
var publicKeyBuffer;
|
this.pools = [];
|
||||||
|
|
||||||
(function Init(){
|
var emitLog = function(text){
|
||||||
SetupJobManager();
|
_this.emit('log', text);
|
||||||
SetupDaemonInterface();
|
};
|
||||||
SetupShareManager();
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
if (options.blockNotifyListener.enabled){
|
||||||
function SetupJobManager(){
|
SetupBlockListener();
|
||||||
_this.jobManager = new jobManager({
|
|
||||||
algorithm : coin.options.algorithm,
|
|
||||||
address : coin.options.address
|
|
||||||
});
|
|
||||||
_this.jobManager.on('newBlock', function(blockTemplate){
|
|
||||||
if ( typeof(_this.stratumServer ) === 'undefined') {
|
|
||||||
console.warn("Stratum server still not started! cannot broadcast block!");
|
|
||||||
} else {
|
|
||||||
_this.stratumServer.broadcastMiningJobs(blockTemplate.getJobParams());
|
|
||||||
}
|
|
||||||
|
|
||||||
}).on('blockFound', function(blockHex, headerHex, third){
|
|
||||||
if (coin.options.hasSubmitMethod) {
|
|
||||||
_this.daemon.cmd('submitblock',
|
|
||||||
[blockHex],
|
|
||||||
function(error, result){
|
|
||||||
console.log(JSON.stringify(error));
|
|
||||||
console.log(JSON.stringify(result));
|
|
||||||
console.log("submitblock", JSON.stringify(error), JSON.stringify(result));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
_this.daemon.cmd('getblocktemplate',
|
|
||||||
[{'mode': 'submit', 'data': blockHex}],
|
|
||||||
function(error, result){
|
|
||||||
console.log(JSON.stringify(error));
|
|
||||||
console.log(JSON.stringify(result));
|
|
||||||
console.log("submitblockgetBlockTEmplate", JSON.stringify(error), JSON.stringify(result));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function SetupDaemonInterface(){
|
function SetupBlockListener(){
|
||||||
console.log('Connecting to daemon for ' + coin.options.name);
|
console.log("Block listener is enabled, starting server on port " + config.blockNotifyListener.port);
|
||||||
_this.daemon = new daemon.interface(coin.options.daemon);
|
var blockNotifyServer = net.createServer(function(c) {
|
||||||
_this.daemon.on('online', function(){
|
emitLog('Block listener has incoming connection');
|
||||||
async.parallel({
|
var data = '';
|
||||||
addressInfo: function(callback){
|
c.on('data', function(d){
|
||||||
_this.daemon.cmd('validateaddress',
|
emitLog('Block listener received blocknotify data');
|
||||||
[coin.options.address],
|
data += d;
|
||||||
function(error, result){
|
if (data.slice(-1) === '\n'){
|
||||||
if (error){
|
c.end();
|
||||||
console.log('validateaddress rpc error for ' + coin.options.name);
|
}
|
||||||
callback(error);
|
});
|
||||||
} else if (!result.isvalid) {
|
c.on('end', function() {
|
||||||
console.log('address is not valid for ' + coin.options.name);
|
|
||||||
callback("address-not-valid");
|
emitLog('Block listener connection ended');
|
||||||
} else {
|
|
||||||
console.log("LOALASD"+JSON.stringify(result))
|
var message = JSON.parse(data);
|
||||||
callback(error, result);
|
if (message.password === config.blockNotifyListener.password){
|
||||||
}
|
|
||||||
|
for (var i = 0; i < this.pools.length; i++){
|
||||||
|
if (this.pools[i].options.symbol === message.coin){
|
||||||
|
this.pools[i].processBlockNotify(message.blockHash)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
},
|
emitLog('Block listener could not find pool to notify');
|
||||||
submitMethod: function(callback){
|
|
||||||
_this.daemon.cmd('submitblock',
|
|
||||||
[],
|
|
||||||
function(error, result){
|
|
||||||
if (error && error.message === 'Method not found')
|
|
||||||
callback(null, false);
|
|
||||||
else
|
|
||||||
callback(null, true);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}, function(err, results){
|
else
|
||||||
if (err) return;
|
emitLog('Block listener received notification with incorrect password');
|
||||||
|
|
||||||
console.log('Connected to daemon for ' + coin.options.name);
|
|
||||||
coin.options.hasSubmitMethod = results.submitMethod;
|
|
||||||
|
|
||||||
publicKeyBuffer = coin.options.reward === 'POW' ?
|
|
||||||
util.script_to_address(results.addressInfo.address) :
|
|
||||||
util.script_to_pubkey(results.addressInfo.pubkey);
|
|
||||||
|
|
||||||
StartStratumServer();
|
|
||||||
SetupBlockPolling();
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}).on('startFailed', function(){
|
blockNotifyServer.listen(options.blockNotifyListener.port, function() {
|
||||||
console.log('Failed to start daemon for ' + coin.name);
|
emitLog('Block notify listener server started on port ' + options.blockNotifyListener.port)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function StartStratumServer(){
|
this.createPool = function(poolOptions, authorizeFn){
|
||||||
console.log('Stratum server starting on port ' + coin.options.stratumPort + ' for ' + coin.options.name);
|
var newPool = new pool(poolOptions, authorizeFn);
|
||||||
_this.stratumServer = new stratum.Server({
|
this.pools.push(newPool);
|
||||||
port : coin.options.stratumPort,
|
return newPool;
|
||||||
authorizeFn : authorizeFn,
|
};
|
||||||
});
|
|
||||||
_this.stratumServer.on('started', function(){
|
|
||||||
console.log('Stratum server started on port ' + coin.options.stratumPort + ' for ' + coin.options.name);
|
|
||||||
}).on('client.connected', function(client){
|
|
||||||
client.on('subscription', function(params, resultCallback){
|
|
||||||
|
|
||||||
var extraNonce = _this.jobManager.extraNonceCounter.next();
|
|
||||||
var extraNonce2Size = _this.jobManager.extraNonce2Size;
|
|
||||||
resultCallback(null,
|
|
||||||
extraNonce,
|
|
||||||
extraNonce2Size
|
|
||||||
);
|
|
||||||
var clientThis = this;
|
|
||||||
|
|
||||||
//if (clientThis.authorized) {
|
|
||||||
if (typeof(_this.jobManager.currentJob) !== 'undefined') {
|
|
||||||
clientThis.sendMiningJob(_this.jobManager.currentJob.getJobParams());
|
|
||||||
}
|
|
||||||
|
|
||||||
//}
|
|
||||||
|
|
||||||
}).on('submit', function(params, resultCallback){
|
|
||||||
var result =_this.jobManager.processShare(
|
|
||||||
params.jobId,
|
|
||||||
client.difficulty,
|
|
||||||
client.extraNonce1,
|
|
||||||
params.extraNonce2,
|
|
||||||
params.nTime,
|
|
||||||
params.nonce
|
|
||||||
);
|
|
||||||
if (result.error){
|
|
||||||
resultCallback(result.error);
|
|
||||||
_this.emit('share', false, {
|
|
||||||
client : client,
|
|
||||||
error : result.error
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resultCallback(null, true);
|
|
||||||
_this.emit('share', true, {
|
|
||||||
client : client,
|
|
||||||
blockHeaderHex : result.headerHEX,
|
|
||||||
workerName : params.name,
|
|
||||||
jobId : params.jobId,
|
|
||||||
extraNonce2 : params.extraNonce2,
|
|
||||||
nTime : params.nTime,
|
|
||||||
nonce : params.nonce
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function SetupShareManager(){
|
|
||||||
this.shareManager = undefined; // just for us to know that the variable should be this one.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function SetupBlockPolling(){
|
|
||||||
|
|
||||||
if (coin.options.blockRefreshInterval === 0){
|
|
||||||
console.log('Block template polling has been disabled for ' + coin.options.name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var pollingInterval = coin.options.blockRefreshInterval * 1000;
|
|
||||||
var pollTimeout;
|
|
||||||
var setPoll;
|
|
||||||
|
|
||||||
setInterval(function () {
|
|
||||||
GetBlockTemplate(function(error, result) {
|
|
||||||
if (error)
|
|
||||||
console.error("Block polling error getting block template for " + coin.options.name);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}, pollingInterval);
|
|
||||||
console.log('Block polling setup for every ' + pollingInterval + ' milliseconds for ' + coin.options.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function GetBlockTemplate(callback){
|
|
||||||
_this.daemon.cmd('getblocktemplate',
|
|
||||||
[{"capabilities": [ "coinbasetxn", "workid", "coinbase/append" ]}],
|
|
||||||
function(error, result){
|
|
||||||
if (error) {
|
|
||||||
callback(error);
|
|
||||||
} else {
|
|
||||||
_this.jobManager.processTemplate(result, publicKeyBuffer);
|
|
||||||
callback(null, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is being called from the blockNotify so that when a new block is discovered by the daemon
|
|
||||||
* We can inform our miners about the newly found block
|
|
||||||
**/
|
|
||||||
this.processBlockNotify = function(blockHash){
|
|
||||||
if (blockHash !== _this.jobManager.currentJob.rpcData.previousblockhash){
|
|
||||||
GetBlockTemplate(function(error, result){
|
|
||||||
if (error)
|
|
||||||
console.error('Block notify error getting block template for ' + coin.options.name);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
pool.prototype.__proto__ = events.EventEmitter.prototype;
|
index.prototype.__proto__ = events.EventEmitter.prototype;
|
||||||
@ -1,7 +1,7 @@
|
|||||||
var binpack = require('binpack');
|
var binpack = require('binpack');
|
||||||
var merkleTree = require('./merkleTree.js');
|
var merkleTree = require('./merkleTree.js');
|
||||||
var transactions = require('./transactions.js');
|
var transactions = require('./transactions.js');
|
||||||
var util = require('./util.js');
|
var util = require('./util.js');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1,6 +1,6 @@
|
|||||||
var http = require('http');
|
var http = require('http');
|
||||||
var cp = require('child_process');
|
var cp = require('child_process');
|
||||||
var events = require('events');
|
var events = require('events');
|
||||||
var startFailedTimeout = 120; //seconds
|
var startFailedTimeout = 120; //seconds
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -193,14 +193,12 @@ var JobManager = module.exports = function JobManager(options){
|
|||||||
var blockBuf = job.serializeBlock(headerBuffer, coinbaseBuffer);
|
var blockBuf = job.serializeBlock(headerBuffer, coinbaseBuffer);
|
||||||
console.log("EXPECTED BLOCK HASH: "+blockHashHex(headerBuffer)); // NOT WORKING :(?
|
console.log("EXPECTED BLOCK HASH: "+blockHashHex(headerBuffer)); // NOT WORKING :(?
|
||||||
_this.emit('blockFound', blockBuf.toString('hex'));
|
_this.emit('blockFound', blockBuf.toString('hex'));
|
||||||
} else {
|
}
|
||||||
// If block is not found we want also to check the difficulty of the share.
|
|
||||||
// TODO: this seems to not be working properly
|
|
||||||
var targetUser = bignum(diffDividend / difficulty);
|
|
||||||
|
|
||||||
if (headerBigNum.gt(targetUser)){
|
// TODO: this seems to not be working properly
|
||||||
return {error: [23, 'low difficulty share', null]};
|
var targetUser = bignum(diffDividend / difficulty);
|
||||||
}
|
if (headerBigNum.gt(targetUser)){
|
||||||
|
return {error: [23, 'low difficulty share', null]};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {result: true, headerHEX: headerBigNum.toString(16)};
|
return {result: true, headerHEX: headerBigNum.toString(16)};
|
||||||
226
lib/pool.js
Normal file
226
lib/pool.js
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
var net = require('net');
|
||||||
|
var events = require('events');
|
||||||
|
var fs = require('fs');
|
||||||
|
var async = require('async');
|
||||||
|
var daemon = require('./daemon.js');
|
||||||
|
var stratum = require('./stratum.js');
|
||||||
|
var jobManager = require('./jobManager.js');
|
||||||
|
var util = require('./util.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main pool object. It emits the following events:
|
||||||
|
* - 'started'() - when the pool is effectively started.
|
||||||
|
* - 'share'(isValid, dataObj) - In case it's valid the dataObj variable will contain (TODO) and in case it's invalid (TODO)
|
||||||
|
*/
|
||||||
|
var pool = module.exports = function pool(options, authorizeFn){
|
||||||
|
|
||||||
|
this.options = options;
|
||||||
|
var _this = this;
|
||||||
|
var publicKeyBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
var emitLog = function(text){ _this.emit('log', text) };
|
||||||
|
|
||||||
|
|
||||||
|
(function Init(){
|
||||||
|
SetupJobManager();
|
||||||
|
SetupDaemonInterface();
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function SetupJobManager(){
|
||||||
|
_this.jobManager = new jobManager({
|
||||||
|
algorithm : options.algorithm,
|
||||||
|
address : options.address
|
||||||
|
});
|
||||||
|
_this.jobManager.on('newBlock', function(blockTemplate){
|
||||||
|
if ( typeof(_this.stratumServer ) === 'undefined') {
|
||||||
|
console.warn("Stratum server still not started! cannot broadcast block!");
|
||||||
|
} else {
|
||||||
|
_this.stratumServer.broadcastMiningJobs(blockTemplate.getJobParams());
|
||||||
|
}
|
||||||
|
}).on('blockFound', function(blockHex, headerHex, third){
|
||||||
|
if (options.hasSubmitMethod) {
|
||||||
|
_this.daemon.cmd('submitblock',
|
||||||
|
[blockHex],
|
||||||
|
function(error, result){
|
||||||
|
console.log(JSON.stringify(error));
|
||||||
|
console.log(JSON.stringify(result));
|
||||||
|
console.log("submitblock", JSON.stringify(error), JSON.stringify(result));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
_this.daemon.cmd('getblocktemplate',
|
||||||
|
[{'mode': 'submit', 'data': blockHex}],
|
||||||
|
function(error, result){
|
||||||
|
console.log(JSON.stringify(error));
|
||||||
|
console.log(JSON.stringify(result));
|
||||||
|
console.log("submitblockgetBlockTEmplate", JSON.stringify(error), JSON.stringify(result));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function SetupDaemonInterface(){
|
||||||
|
emitLog('Connecting to daemon');
|
||||||
|
_this.daemon = new daemon.interface(options.daemon);
|
||||||
|
_this.daemon.on('online', function(){
|
||||||
|
async.parallel({
|
||||||
|
addressInfo: function(callback){
|
||||||
|
_this.daemon.cmd('validateaddress',
|
||||||
|
[options.address],
|
||||||
|
function(error, result){
|
||||||
|
if (error){
|
||||||
|
emitLog('validateaddress rpc error');
|
||||||
|
callback(error);
|
||||||
|
} else if (!result.isvalid) {
|
||||||
|
emitLog('address is not valid');
|
||||||
|
callback("address-not-valid");
|
||||||
|
} else {
|
||||||
|
callback(error, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
submitMethod: function(callback){
|
||||||
|
_this.daemon.cmd('submitblock',
|
||||||
|
[],
|
||||||
|
function(error, result){
|
||||||
|
if (error && error.message === 'Method not found')
|
||||||
|
callback(null, false);
|
||||||
|
else
|
||||||
|
callback(null, true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, function(err, results){
|
||||||
|
if (err) return;
|
||||||
|
|
||||||
|
emitLog('Connected to daemon');
|
||||||
|
options.hasSubmitMethod = results.submitMethod;
|
||||||
|
|
||||||
|
publicKeyBuffer = options.reward === 'POW' ?
|
||||||
|
util.script_to_address(results.addressInfo.address) :
|
||||||
|
util.script_to_pubkey(results.addressInfo.pubkey);
|
||||||
|
|
||||||
|
StartStratumServer();
|
||||||
|
SetupBlockPolling();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}).on('startFailed', function(){
|
||||||
|
emitLog('Failed to start daemon');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function StartStratumServer(){
|
||||||
|
emitLog('Stratum server starting on port ' + options.stratumPort);
|
||||||
|
_this.stratumServer = new stratum.Server({
|
||||||
|
port: options.stratumPort,
|
||||||
|
authorizeFn: authorizeFn
|
||||||
|
});
|
||||||
|
_this.stratumServer.on('started', function(){
|
||||||
|
emitLog('Stratum server started on port ' + options.stratumPort);
|
||||||
|
}).on('client.connected', function(client){
|
||||||
|
client.on('subscription', function(params, resultCallback){
|
||||||
|
|
||||||
|
var extraNonce = _this.jobManager.extraNonceCounter.next();
|
||||||
|
var extraNonce2Size = _this.jobManager.extraNonce2Size;
|
||||||
|
resultCallback(null,
|
||||||
|
extraNonce,
|
||||||
|
extraNonce2Size
|
||||||
|
);
|
||||||
|
|
||||||
|
this.sendAndSetDifficultyIfNew(options.difficulty);
|
||||||
|
this.sendMiningJob(_this.jobManager.currentJob.getJobParams());
|
||||||
|
|
||||||
|
|
||||||
|
}).on('submit', function(params, resultCallback){
|
||||||
|
var result =_this.jobManager.processShare(
|
||||||
|
params.jobId,
|
||||||
|
client.difficulty,
|
||||||
|
client.extraNonce1,
|
||||||
|
params.extraNonce2,
|
||||||
|
params.nTime,
|
||||||
|
params.nonce
|
||||||
|
);
|
||||||
|
if (result.error){
|
||||||
|
resultCallback(result.error);
|
||||||
|
_this.emit('share', false, {
|
||||||
|
client : client,
|
||||||
|
error : result.error
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
resultCallback(null, true);
|
||||||
|
_this.emit('share', true, {
|
||||||
|
client : client,
|
||||||
|
blockHeaderHex : result.headerHEX,
|
||||||
|
workerName : params.name,
|
||||||
|
jobId : params.jobId,
|
||||||
|
extraNonce2 : params.extraNonce2,
|
||||||
|
nTime : params.nTime,
|
||||||
|
nonce : params.nonce
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function SetupBlockPolling(){
|
||||||
|
|
||||||
|
if (options.blockRefreshInterval === 0){
|
||||||
|
emitLog('Block template polling has been disabled');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pollingInterval = options.blockRefreshInterval * 1000;
|
||||||
|
var pollTimeout;
|
||||||
|
var setPoll;
|
||||||
|
|
||||||
|
setInterval(function () {
|
||||||
|
GetBlockTemplate(function(error, result) {
|
||||||
|
if (error)
|
||||||
|
console.error("Block polling error getting block template for " + options.name);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}, pollingInterval);
|
||||||
|
emitLog('Block polling setup for every ' + pollingInterval + ' milliseconds');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function GetBlockTemplate(callback){
|
||||||
|
_this.daemon.cmd('getblocktemplate',
|
||||||
|
[{"capabilities": [ "coinbasetxn", "workid", "coinbase/append" ]}],
|
||||||
|
function(error, result){
|
||||||
|
if (error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
_this.jobManager.processTemplate(result, publicKeyBuffer);
|
||||||
|
callback(null, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is being called from the blockNotify so that when a new block is discovered by the daemon
|
||||||
|
* We can inform our miners about the newly found block
|
||||||
|
**/
|
||||||
|
this.processBlockNotify = function(blockHash){
|
||||||
|
if (blockHash !== _this.jobManager.currentJob.rpcData.previousblockhash){
|
||||||
|
GetBlockTemplate(function(error, result){
|
||||||
|
if (error)
|
||||||
|
console.error('Block notify error getting block template for ' + options.name);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
pool.prototype.__proto__ = events.EventEmitter.prototype;
|
||||||
@ -92,41 +92,18 @@ var StratumClient = function(options){
|
|||||||
_this.workerIP = options.socket.address().address;
|
_this.workerIP = options.socket.address().address;
|
||||||
_this.workerName = message.params[0];
|
_this.workerName = message.params[0];
|
||||||
_this.workerPass = message.params[1];
|
_this.workerPass = message.params[1];
|
||||||
options.authorizeFn(_this.workerIP, _this.workerName, _this.workerPass, function(err, authorized, shouldCloseSocket, difficulty) {
|
options.authorizeFn(_this.workerIP, _this.workerName, _this.workerPass, function(result) {
|
||||||
_this.authorized = ( ! err && authorized );
|
_this.authorized = (!result.error && result.authorized);
|
||||||
sendJson({
|
sendJson({
|
||||||
id : message.id,
|
id : message.id,
|
||||||
result : _this.authorized,
|
result : _this.authorized,
|
||||||
error : err
|
error : result.error
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the authorizer wants us to close the socket lets do it.
|
// If the authorizer wants us to close the socket lets do it.
|
||||||
if (typeof(shouldCloseSocket) === 'boolean' && shouldCloseSocket) {
|
if (result.disconnect === true) {
|
||||||
options.socket.end();
|
options.socket.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send difficulty
|
|
||||||
if (typeof(difficulty) === 'function') {
|
|
||||||
difficulty(_this.workerName, function(err, diff) {
|
|
||||||
if (err) {
|
|
||||||
console.error("Cannot set difficulty for "+_this.workernName+" error: "+JSON.stringify(err));
|
|
||||||
options.socket.end();
|
|
||||||
} else {
|
|
||||||
_this.sendAndSetDifficultyIfNew(diff);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
} else if (typeof(difficulty) === 'number') {
|
|
||||||
_this.sendAndSetDifficultyIfNew(difficulty);
|
|
||||||
} else {
|
|
||||||
process.exit("Difficulty from authorizeFn callback is neither a function or a number");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_this.requestedSubscriptionBeforeAuth === true) {
|
|
||||||
delete _this.requestedSubscriptionBeforeAuth; // we do not need this anymore.
|
|
||||||
//TODO: We should send a mining job here. For now we send it before the auth has taken place but.....
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
2
node_modules/bignum/package.json
generated
vendored
2
node_modules/bignum/package.json
generated
vendored
@ -2,7 +2,7 @@
|
|||||||
"name": "bignum",
|
"name": "bignum",
|
||||||
"version": "0.6.2",
|
"version": "0.6.2",
|
||||||
"description": "Arbitrary-precision integer arithmetic using OpenSSL",
|
"description": "Arbitrary-precision integer arithmetic using OpenSSL",
|
||||||
"main": "./index.js",
|
"main": "./pool.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "http://github.com/justmoon/node-bignum.git"
|
"url": "http://github.com/justmoon/node-bignum.git"
|
||||||
|
|||||||
2
node_modules/binpack/node_modules/bindings/bindings.js
generated
vendored
2
node_modules/binpack/node_modules/bindings/bindings.js
generated
vendored
@ -131,7 +131,7 @@ exports.getFileName = function getFileName () {
|
|||||||
* somewhere in the module tree. The "root directory" is the directory
|
* somewhere in the module tree. The "root directory" is the directory
|
||||||
* containing the `package.json` file.
|
* containing the `package.json` file.
|
||||||
*
|
*
|
||||||
* In: /home/nate/node-native-module/lib/index.js
|
* In: /home/nate/node-native-module/lib/pool.js
|
||||||
* Out: /home/nate/node-native-module
|
* Out: /home/nate/node-native-module
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
2
node_modules/quark-hash/node_modules/bindings/bindings.js
generated
vendored
2
node_modules/quark-hash/node_modules/bindings/bindings.js
generated
vendored
@ -131,7 +131,7 @@ exports.getFileName = function getFileName () {
|
|||||||
* somewhere in the module tree. The "root directory" is the directory
|
* somewhere in the module tree. The "root directory" is the directory
|
||||||
* containing the `package.json` file.
|
* containing the `package.json` file.
|
||||||
*
|
*
|
||||||
* In: /home/nate/node-native-module/lib/index.js
|
* In: /home/nate/node-native-module/lib/pool.js
|
||||||
* Out: /home/nate/node-native-module
|
* Out: /home/nate/node-native-module
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
2
node_modules/scrypt-jane-hash/node_modules/bindings/bindings.js
generated
vendored
2
node_modules/scrypt-jane-hash/node_modules/bindings/bindings.js
generated
vendored
@ -131,7 +131,7 @@ exports.getFileName = function getFileName () {
|
|||||||
* somewhere in the module tree. The "root directory" is the directory
|
* somewhere in the module tree. The "root directory" is the directory
|
||||||
* containing the `package.json` file.
|
* containing the `package.json` file.
|
||||||
*
|
*
|
||||||
* In: /home/nate/node-native-module/lib/index.js
|
* In: /home/nate/node-native-module/lib/pool.js
|
||||||
* Out: /home/nate/node-native-module
|
* Out: /home/nate/node-native-module
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
2
node_modules/scrypt256-hash/node_modules/bindings/bindings.js
generated
vendored
2
node_modules/scrypt256-hash/node_modules/bindings/bindings.js
generated
vendored
@ -131,7 +131,7 @@ exports.getFileName = function getFileName () {
|
|||||||
* somewhere in the module tree. The "root directory" is the directory
|
* somewhere in the module tree. The "root directory" is the directory
|
||||||
* containing the `package.json` file.
|
* containing the `package.json` file.
|
||||||
*
|
*
|
||||||
* In: /home/nate/node-native-module/lib/index.js
|
* In: /home/nate/node-native-module/lib/pool.js
|
||||||
* Out: /home/nate/node-native-module
|
* Out: /home/nate/node-native-module
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
39
package.json
Normal file
39
package.json
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"name": "http-server",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"author": "Matthew Little",
|
||||||
|
"description": "High performance Stratum poolserver in Node.js",
|
||||||
|
"contributors": [
|
||||||
|
"vekexasia"
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"block-notify": "./scripts/blockNotify.js"
|
||||||
|
},
|
||||||
|
"main": "index.js",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zone117x/node-stratum.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"stratum",
|
||||||
|
"pool",
|
||||||
|
"server",
|
||||||
|
"poolserver",
|
||||||
|
"bitcoin",
|
||||||
|
"litecoin",
|
||||||
|
"scrypt"
|
||||||
|
],
|
||||||
|
"bundledDependencies": [
|
||||||
|
"scrypt256-hash",
|
||||||
|
"scrypt-jane-hash",
|
||||||
|
"quark-hash",
|
||||||
|
"binpack",
|
||||||
|
"bignum",
|
||||||
|
"buffertools",
|
||||||
|
"base58-native"
|
||||||
|
],
|
||||||
|
"license": "GPL-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user