Added fixes for POS. And when getblocktemplate fails because its out of sync then it shows syncing progress :)
This commit is contained in:
parent
32dc22944e
commit
ffc01054c6
@ -83,7 +83,6 @@ var pool = Stratum.createPool({
|
||||
name: "Dogecoin",
|
||||
symbol: "doge",
|
||||
algorithm: "scrypt", //or "sha256", "scrypt-jane", "quark", "x11"
|
||||
reward: "POW", //or "POS"
|
||||
txMessages: false //or true
|
||||
},
|
||||
|
||||
|
||||
@ -67,6 +67,11 @@ function DaemonInterface(options){
|
||||
|
||||
var dataJson;
|
||||
var parsingError;
|
||||
|
||||
//if (data.indexOf(':-nan,') !== -1){
|
||||
// data = data.replace(/:-nan,/g, ":0,")
|
||||
//}
|
||||
|
||||
try{
|
||||
dataJson = JSON.parse(data);
|
||||
|
||||
@ -79,7 +84,7 @@ function DaemonInterface(options){
|
||||
else{
|
||||
parsingError = e;
|
||||
_this.emit('error', 'could not parse rpc data with request of: ' + jsonData +
|
||||
' on instance ' + instance.index + ' data: ' + data);
|
||||
' on instance ' + instance.index + ' data: ' + data + ' Error ' + JSON.stringify(parsingError));
|
||||
}
|
||||
}
|
||||
if (typeof(dataJson) !== 'undefined'){
|
||||
|
||||
@ -50,6 +50,7 @@ var JobCounter = function(){
|
||||
**/
|
||||
var JobManager = module.exports = function JobManager(options){
|
||||
|
||||
|
||||
//private members
|
||||
|
||||
var _this = this;
|
||||
@ -58,7 +59,7 @@ var JobManager = module.exports = function JobManager(options){
|
||||
|
||||
//Which number to use as dividend when converting difficulty to target
|
||||
var diffDividend = bignum((function(){
|
||||
switch(options.algorithm){
|
||||
switch(options.coin.algorithm){
|
||||
case 'sha256':
|
||||
case 'skein':
|
||||
return '00000000ffff0000000000000000000000000000000000000000000000000000';
|
||||
@ -76,7 +77,7 @@ var JobManager = module.exports = function JobManager(options){
|
||||
|
||||
//On initialization lets figure out which hashing algorithm to use
|
||||
var hashDigest = (function(){
|
||||
switch(options.algorithm){
|
||||
switch(options.coin.algorithm){
|
||||
case 'sha256':
|
||||
return function(){
|
||||
return util.doublesha.apply(this, arguments);
|
||||
@ -119,6 +120,10 @@ var JobManager = module.exports = function JobManager(options){
|
||||
//https://github.com/Prydie/maxcoin-hash-python
|
||||
//https://github.com/ahmedbodi/stratum-mining-maxcoin/blob/master/lib/template_registry.py
|
||||
}
|
||||
default:
|
||||
return function(){
|
||||
console.log('Hashing algorithm ' + options.coin.algorithm + ' not supported');
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
@ -167,8 +172,8 @@ var JobManager = module.exports = function JobManager(options){
|
||||
rpcData,
|
||||
publicKey,
|
||||
_this.extraNoncePlaceholder,
|
||||
options.reward,
|
||||
options.txMessages
|
||||
options.coin.reward,
|
||||
options.coin.txMessages
|
||||
);
|
||||
|
||||
this.currentJob = tmpBlockTemplate;
|
||||
|
||||
218
lib/pool.js
218
lib/pool.js
@ -39,14 +39,7 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
emitLog('Starting pool for ' + options.coin.name + ' [' + options.coin.symbol.toUpperCase() + ']');
|
||||
SetupJobManager();
|
||||
SetupVarDiff();
|
||||
SetupDaemonInterface(function (err, newDaemon) {
|
||||
if (!err) {
|
||||
_this.daemon = newDaemon;
|
||||
SetupBlockPolling();
|
||||
StartStratumServer();
|
||||
SetupPeer();
|
||||
}
|
||||
});
|
||||
SetupDaemonInterface();
|
||||
SetupApi();
|
||||
};
|
||||
|
||||
@ -76,6 +69,7 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
}
|
||||
|
||||
function SetupVarDiff(){
|
||||
_this.varDiff = {};
|
||||
Object.keys(options.ports).forEach(function(port) {
|
||||
if (options.ports[port].varDiff)
|
||||
_this.setVarDiff(port, new varDiff(port, options.ports[port].varDiff));
|
||||
@ -120,13 +114,9 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
|
||||
|
||||
function SetupJobManager(){
|
||||
_this.jobManager = new jobManager({
|
||||
address : options.address,
|
||||
algorithm : options.coin.algorithm,
|
||||
reward : options.coin.reward,
|
||||
txMessages: options.coin.txMessages,
|
||||
txRefreshInterval: options.txRefreshInterval
|
||||
});
|
||||
|
||||
_this.jobManager = new jobManager(options);
|
||||
|
||||
_this.jobManager.on('newBlock', function(blockTemplate){
|
||||
//Check if stratumServer has been initialized yet
|
||||
if ( typeof(_this.stratumServer ) !== 'undefined') {
|
||||
@ -170,12 +160,15 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
}
|
||||
|
||||
|
||||
function SetupDaemonInterface(cback){
|
||||
var newDaemon = new daemon.interface(options.daemons);
|
||||
newDaemon.once('online', function(){
|
||||
function SetupDaemonInterface(){
|
||||
|
||||
if (!_this.daemon) _this.daemon = new daemon.interface(options.daemons);
|
||||
|
||||
_this.daemon.once('online', function(){
|
||||
async.parallel({
|
||||
|
||||
addressInfo: function(callback){
|
||||
newDaemon.cmd('validateaddress', [options.address], function(results){
|
||||
_this.daemon.cmd('validateaddress', [options.address], function(results){
|
||||
|
||||
//Make sure address is valid with each daemon
|
||||
var allValid = results.every(function(result){
|
||||
@ -197,8 +190,9 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
|
||||
});
|
||||
},
|
||||
miningInfo: function(callback){
|
||||
newDaemon.cmd('getmininginfo', [], function(results){
|
||||
|
||||
info: function(callback){
|
||||
_this.daemon.cmd('getinfo', [], function(results){
|
||||
|
||||
// Print which network each daemon is running on
|
||||
|
||||
@ -212,9 +206,6 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
return false;
|
||||
}
|
||||
|
||||
var network = result.response.testnet ? 'testnet' : 'live blockchain';
|
||||
emitLog('Daemon instance ' + result.instance.index + ' is running on ' + network);
|
||||
|
||||
if (typeof isTestnet === 'undefined'){
|
||||
isTestnet = result.response.testnet;
|
||||
return true;
|
||||
@ -242,17 +233,41 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
rewardType: function(callback){
|
||||
_this.daemon.cmd('getdifficulty', [], function(results){
|
||||
|
||||
var isPos = results.every(function(result){
|
||||
|
||||
if (result.error){
|
||||
emitErrorLog('getinfo on init failed with daemon instance ' +
|
||||
result.instance.index + ', error ' + JSON.stringify(result.error)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return isNaN(result.response) && 'proof-of-stake' in result.response;
|
||||
});
|
||||
|
||||
options.coin.reward = isPos ? 'POS' : 'POW'
|
||||
callback(null);
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
submitMethod: function(callback){
|
||||
/* This checks to see whether the daemon uses submitblock
|
||||
or getblocktemplate for submitting new blocks */
|
||||
newDaemon.cmd('submitblock', [], function(results){
|
||||
_this.daemon.cmd('submitblock', [], function(results){
|
||||
var couldNotDetectMethod = results.every(function(result){
|
||||
if (result.error && result.error.message === 'Method not found'){
|
||||
callback(null, false);
|
||||
options.hasSubmitMethod = false;
|
||||
callback(null);
|
||||
return false;
|
||||
}
|
||||
else if (result.error && result.error.code === -1){
|
||||
callback(null, true);
|
||||
options.hasSubmitMethod = true;
|
||||
callback(null);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@ -267,76 +282,127 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
}, function(err, results){
|
||||
if (err){
|
||||
emitErrorLog('Could not start pool, ' + JSON.stringify(err));
|
||||
cback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
emitLog('Connected to daemon via RPC');
|
||||
|
||||
|
||||
options.hasSubmitMethod = results.submitMethod;
|
||||
|
||||
if (options.coin.reward === 'POS' && typeof(results.addressInfo.pubkey) == 'undefined') {
|
||||
// address provided is not of the wallet.
|
||||
emitErrorLog('The address provided is not from the daemon wallet.');
|
||||
cback(err);
|
||||
return;
|
||||
} else {
|
||||
|
||||
publicKeyBuffer = options.coin.reward === 'POW' ?
|
||||
util.script_to_address(results.addressInfo.address) :
|
||||
util.script_to_pubkey(results.addressInfo.pubkey);
|
||||
|
||||
//var networkDifficulty = Math.round(results.miningInfo.difficulty * 65536);
|
||||
|
||||
|
||||
GetBlockTemplate(newDaemon, function(error, result){
|
||||
if (error) {
|
||||
emitErrorLog('Error with getblocktemplate on initializing');
|
||||
cback(error);
|
||||
} else {
|
||||
|
||||
var networkDifficulty = _this.jobManager.currentJob.difficulty;
|
||||
emitLog('Current block height at ' + results.miningInfo.blocks +
|
||||
' with block difficulty of ' + networkDifficulty);
|
||||
|
||||
Object.keys(options.ports).forEach(function(port){
|
||||
var portDiff = options.ports[port].diff;
|
||||
if (portDiff > networkDifficulty)
|
||||
emitWarningLog('diff of ' + portDiff + ' on port ' + port +
|
||||
' was set higher than network difficulty of ' + networkDifficulty);
|
||||
});
|
||||
|
||||
|
||||
cback(null, newDaemon); // finish!
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
publicKeyBuffer = options.coin.reward === 'POW' ?
|
||||
util.script_to_address(results.addressInfo.address) :
|
||||
util.script_to_pubkey(results.addressInfo.pubkey);
|
||||
|
||||
var networkDifficulty = Math.round(results.info.difficulty * 65536);
|
||||
var network = results.info.testnet ? 'testnet' : 'live blockchain';
|
||||
|
||||
emitLog('Connected to ' + network +
|
||||
'; detected ' + options.coin.reward +
|
||||
' reward type; block height of ' + results.info.blocks +
|
||||
'; difficulty of ' + networkDifficulty);
|
||||
|
||||
GetBlockTemplate(function(error, result){
|
||||
if (error) {
|
||||
if (error.code === -10){
|
||||
emitErrorLog('Daemon is still syncing with network (download blocks)');
|
||||
WaitForSync(results.info.blocks);
|
||||
}
|
||||
else
|
||||
emitErrorLog('Error with getblocktemplate on initializing');
|
||||
|
||||
} else {
|
||||
Object.keys(options.ports).forEach(function(port){
|
||||
var portDiff = options.ports[port].diff;
|
||||
if (portDiff > networkDifficulty)
|
||||
emitWarningLog('Pool difficulty of ' + portDiff + ' on port ' + port +
|
||||
' was set higher than network difficulty of ' + networkDifficulty);
|
||||
});
|
||||
|
||||
SetupBlockPolling();
|
||||
StartStratumServer();
|
||||
SetupPeer();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}).on('connectionFailed', function(error){
|
||||
emitErrorLog('Failed to connect daemon(s): ' + JSON.stringify(error));
|
||||
|
||||
}).on('error', function(message){
|
||||
emitErrorLog(message);
|
||||
|
||||
});
|
||||
|
||||
newDaemon.init();
|
||||
_this.daemon.init();
|
||||
}
|
||||
|
||||
function WaitForSync(currentBlocks){
|
||||
|
||||
var generateProgress = function(currentBlocks){
|
||||
|
||||
//get list of peers and their highest block height to compare to ours
|
||||
|
||||
_this.daemon.cmd('getpeerinfo', [], function(results){
|
||||
|
||||
var peers = results[0].response;
|
||||
var totalBlocks = peers.sort(function(a, b){
|
||||
return b.startingheight - a.startingheight;
|
||||
})[0].startingheight;
|
||||
|
||||
var percent = (currentBlocks / totalBlocks * 100).toFixed(2);
|
||||
|
||||
//Only let the first fork show synced status or the log wil look flooded with it
|
||||
if (process.env.forkId === '0')
|
||||
emitWarningLog('Downloaded ' + percent + '% of blockchain from network');
|
||||
});
|
||||
};
|
||||
generateProgress(currentBlocks);
|
||||
|
||||
setInterval(function(){
|
||||
|
||||
_this.daemon.cmd('getblocktemplate', [], function(results){
|
||||
var synced = results.every(function(r){
|
||||
return r.error.code !== -10;
|
||||
});
|
||||
if (synced){
|
||||
SetupDaemonInterface();
|
||||
}
|
||||
else{
|
||||
_this.daemon.cmd('getinfo', [], function(results){
|
||||
var smallestHeight = results.sort(function(a, b){
|
||||
return b.response.blocks - a.response.blocks;
|
||||
})[0].response.blocks;
|
||||
generateProgress(smallestHeight);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}, 5000);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function StartStratumServer(){
|
||||
_this.stratumServer = new stratum.Server(options.ports, options.connectionTimeout, options.banning, authorizeFn);
|
||||
|
||||
_this.stratumServer.on('started', function(){
|
||||
emitLog('Stratum server started on port(s): ' + Object.keys(options.ports).join(', '));
|
||||
_this.emit('started');
|
||||
|
||||
}).on('client.connected', function(client){
|
||||
if (typeof(_this.varDiff[client.socket.localPort]) !== 'undefined') {
|
||||
_this.varDiff[client.socket.localPort].manageClient(client);
|
||||
}
|
||||
|
||||
|
||||
client.on('difficultyChanged', function(diff){
|
||||
|
||||
_this.emit('difficultyUpdate', client.workerName, diff);
|
||||
|
||||
}).on('subscription', function(params, resultCallback){
|
||||
|
||||
var extraNonce = _this.jobManager.extraNonceCounter.next();
|
||||
@ -370,14 +436,19 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
|
||||
}).on('malformedMessage', function (message) {
|
||||
emitWarningLog(client.workerName + " has sent us a malformed message: " + message);
|
||||
|
||||
}).on('socketError', function(err) {
|
||||
emitWarningLog(client.workerName + " has somehow had a socket error: " + JSON.stringify(err));
|
||||
|
||||
}).on('socketDisconnect', function() {
|
||||
emitLog("Client '" + client.workerName + "' disconnected!");
|
||||
|
||||
}).on('unknownStratumMethod', function(fullMessage) {
|
||||
emitLog("Client '" + client.workerName + "' has sent us an unknown stratum method: " + fullMessage.method);
|
||||
|
||||
}).on('socketFlooded', function(){
|
||||
emitWarningLog('Detected socket flooding and purged buffer');
|
||||
|
||||
}).on('ban', function(ipAddress){
|
||||
_this.emit('banIP', ipAddress);
|
||||
emitWarningLog('banned IP ' + ipAddress);
|
||||
@ -400,16 +471,12 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
emitLog('Block polling every ' + pollingInterval + ' milliseconds');
|
||||
}
|
||||
|
||||
function GetBlockTemplate(daemonObj, callback){
|
||||
if (typeof(callback) === 'undefined') {
|
||||
callback = daemonObj;
|
||||
daemonObj = _this.daemon;
|
||||
}
|
||||
daemonObj.cmd('getblocktemplate',
|
||||
function GetBlockTemplate(callback){
|
||||
_this.daemon.cmd('getblocktemplate',
|
||||
[{"capabilities": [ "coinbasetxn", "workid", "coinbase/append" ]}],
|
||||
function(result){
|
||||
if (result.error){
|
||||
emitErrorLog('system', 'getblocktemplate call failed for daemon instance ' +
|
||||
emitErrorLog('getblocktemplate call failed for daemon instance ' +
|
||||
result.instance.index + ' with error ' + JSON.stringify(result.error));
|
||||
callback(result.error);
|
||||
} else {
|
||||
@ -458,7 +525,7 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
if (typeof(_this.jobManager.currentJob) !== 'undefined' && blockHash !== _this.jobManager.currentJob.rpcData.previousblockhash){
|
||||
GetBlockTemplate(function(error, result){
|
||||
if (error)
|
||||
emitErrorLog('system', 'Block notify error getting block template for ' + options.coin.name);
|
||||
emitErrorLog('Block notify error getting block template for ' + options.coin.name);
|
||||
})
|
||||
}
|
||||
};
|
||||
@ -508,9 +575,6 @@ var pool = module.exports = function pool(options, authorizeFn){
|
||||
};
|
||||
|
||||
this.setVarDiff = function(port, varDiffInstance) {
|
||||
if (typeof(_this.varDiff) === 'undefined') {
|
||||
_this.varDiff = {};
|
||||
}
|
||||
if (typeof(_this.varDiff[port]) != 'undefined' ) {
|
||||
_this.varDiff[port].removeAllListeners();
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user