Add check for if submitblock was successful and refined the data emitted by onShare

This commit is contained in:
Matthew Little 2014-01-15 16:03:30 -07:00
parent cbcaa1cf98
commit cb5d7c7bdc
4 changed files with 108 additions and 46 deletions

View File

@ -78,8 +78,15 @@ function DaemonInterface(options){
data += chunk;
});
res.on('end', function(){
var dataJson = JSON.parse(data);
callback(dataJson.error, dataJson.result);
var dataJson;
try{
dataJson = JSON.parse(data);
}
catch(e){
_this.emit('error', 'daemon interface could not parse rpc data from method: ' + method + ' ' + options.hostname);
}
if (typeof(dataJson) !== 'undefined')
callback(dataJson.error, dataJson.result);
});
});

View File

@ -126,33 +126,45 @@ var JobManager = module.exports = function JobManager(options){
}
};
this.processShare = function(jobId, difficulty, extraNonce1, extraNonce2, nTime, nonce){
this.processShare = function(jobId, difficulty, extraNonce1, extraNonce2, nTime, nonce, ipAddress, workerName){
var shareError = function(error){
_this.emit('share', {
job: jobId,
ip: ipAddress,
worker: workerName,
difficulty: difficulty,
error: error.error[1]
});
return error;
};
var submitTime = Date.now() / 1000 | 0;
if (extraNonce2.length / 2 !== _this.extraNonce2Size)
return {error: [20, 'incorrect size of extranonce2', null]};
return shareError({error: [20, 'incorrect size of extranonce2']});
var job = this.currentJob;
if ( job.jobId != jobId ) {
return {error: [21, 'job not found', null]};
return shareError({error: [21, 'job not found']});
}
if (nTime.length !== 8) {
return {error: [20, 'incorrect size of ntime']};
return shareError({error: [20, 'incorrect size of ntime']});
}
var nTimeInt = parseInt(nTime, 16);
if (nTimeInt < job.rpcData.curtime || nTime > submitTime + 7200) {
return {error: [20, 'ntime out of range', null]};
return shareError({error: [20, 'ntime out of range']});
}
if (nonce.length !== 8) {
return {error: [20, 'incorrect size of nonce']};
return shareError({error: [20, 'incorrect size of nonce']});
}
if (!job.registerSubmit(extraNonce1, extraNonce2, nTime, nonce)) {
return {error: [22, 'duplicate share', null]};
return shareError({error: [22, 'duplicate share']});
}
@ -169,19 +181,27 @@ var JobManager = module.exports = function JobManager(options){
var headerBigNum = bignum.fromBuffer(headerHash, {endian: 'little', size: 32});
var blockHash;
var blockHex;
if (job.target.ge(headerBigNum)){
var blockHex = job.serializeBlock(headerBuffer, coinbaseBuffer).toString('hex');
blockHex = job.serializeBlock(headerBuffer, coinbaseBuffer).toString('hex');
blockHash = util.reverseBuffer(util.doublesha(headerBuffer)).toString('hex');
_this.emit('blockFound', blockHex, blockHash);
}
else {
var targetUser = bignum(diffDividend / difficulty);
if (headerBigNum.gt(targetUser)){
return {error: [23, 'low difficulty share', null]};
return shareError({error: [23, 'low difficulty share']});
}
}
_this.emit('share', {
job: jobId,
ip: ipAddress,
worker: workerName,
difficulty: difficulty,
solution: blockHash
}, blockHex);
return {result: true, error: null, solution: blockHash};
};
};

View File

@ -29,6 +29,32 @@ var pool = module.exports = function pool(options, authorizeFn){
})();
function SubmitBlock(blockHex, callback){
if (options.hasSubmitMethod) {
_this.daemon.cmd('submitblock',
[blockHex],
function(error, result){
if (error)
emitErrorLog('submitblock', 'rpc error when submitting block with submitblock')
else
emitLog('submitblock', 'Submitted Block using submitblock');
callback();
}
);
} else {
_this.daemon.cmd('getblocktemplate',
[{'mode': 'submit', 'data': blockHex}],
function(error, result){
if (error)
emitErrorLog('submitblock', 'rpc error when submitting block with getblocktemplate')
else
emitLog('submitblock', 'Submitted Block using getblocktemplate');
callback()
}
);
}
}
function SetupJobManager(){
_this.jobManager = new jobManager({
@ -42,21 +68,27 @@ var pool = module.exports = function pool(options, authorizeFn){
emitLog('system', 'Detected new block');
_this.stratumServer.broadcastMiningJobs(blockTemplate.getJobParams());
}
}).on('blockFound', function(blockHex, blockHash){
if (options.hasSubmitMethod) {
_this.daemon.cmd('submitblock',
[blockHex],
function(error, result){
emitLog('submitblock', 'Submitted Block using submitblock :'+blockHash);
}
);
} else {
_this.daemon.cmd('getblocktemplate',
[{'mode': 'submit', 'data': blockHex}],
function(error, result){
emitLog('submitblock', 'Submitted Block using getblocktemplate: '+blockHash);
}
);
}).on('share', function(shareData, blockHex){
var isValidShare = !shareData.error;
var isValidBlock = !!blockHex;
var emitShare = function(){
_this.emit('share', isValidShare, isValidBlock, shareData);
};
/*
If we calculated that the block solution was found,
before we emit the share, lets submit the block,
then check if it was accepted using RPC getblock
*/
if (!isValidBlock)
emitShare();
else{
SubmitBlock(blockHex, function(){
CheckBlockAccepted(shareData.solution, function(isAccepted){
isValidBlock = isAccepted;
emitShare();
});
});
}
});
}
@ -72,10 +104,10 @@ var pool = module.exports = function pool(options, authorizeFn){
[options.address],
function(error, result){
if (error){
emitLog('system','validateaddress rpc error');
emitErrorLog('system','validateaddress rpc error');
callback(error);
} else if (!result.isvalid) {
emitLog('system','address is not valid');
emitErrorLog('system','address is not valid');
callback("address-not-valid");
} else {
callback(error, result);
@ -111,6 +143,8 @@ var pool = module.exports = function pool(options, authorizeFn){
}).on('startFailed', function(){
emitErrorLog('system','Failed to start daemon');
}).on('error', function(message){
emitErrorLog('system', message);
});
}
@ -148,25 +182,13 @@ var pool = module.exports = function pool(options, authorizeFn){
client.extraNonce1,
params.extraNonce2,
params.nTime,
params.nonce
params.nonce,
client.socket.remoteAddress,
params.name
);
resultCallback(result.error, result.result ? true : null);
_this.emit('share', !result.error, {
job: params.jobId,
ip: client.socket.remoteAddress,
worker: params.name,
solution: result.solution,
error: result.error ? result.error[1] : undefined,
difficulty: client.difficulty,
timestamp: Date.now() / 1000 | 0,
accepted: !!result.result,
extraNonce2: params.extraNonce2,
nTime: params.nTime,
nonce: params.nonce
});
}).on('malformedMessage', function (message) {
emitWarningLog('client', client.workerName+" has sent us a malformed message: "+message);
}).on('socketError', function() {
@ -202,7 +224,6 @@ var pool = module.exports = function pool(options, authorizeFn){
emitLog('system', 'Block polling setup for every ' + pollingInterval + ' milliseconds');
}
function GetBlockTemplate(callback){
_this.daemon.cmd('getblocktemplate',
[{"capabilities": [ "coinbasetxn", "workid", "coinbase/append" ]}],
@ -217,6 +238,19 @@ var pool = module.exports = function pool(options, authorizeFn){
);
}
function CheckBlockAccepted(blockHash, callback){
_this.daemon.cmd('getblock',
[blockHash],
function(error, result){
if (error)
callback(false);
else if (result.hash === blockHash)
callback(true);
else
callback(false);
}
);
}
/**
* This method is being called from the blockNotify so that when a new block is discovered by the daemon

View File

@ -239,7 +239,8 @@ var StratumServer = exports.Server = function StratumServer(options){
var subscriptionCounter = SubscriptionCounter();
(function init(){
_socketServer = socketServer = net.createServer(function(c){
_socketServer = socketServer = net.createServer({allowHalfOpen: true}, function(c){
c.setKeepAlive(true);
var subscriptionId = subscriptionCounter.next();
var client = new StratumClient(
{