Updated to support new Darkcoin masternode features
This commit is contained in:
parent
9821694812
commit
a06ba67ab3
@ -304,7 +304,6 @@ Listen to pool events
|
|||||||
ip: '71.33.19.37', //ip address of client
|
ip: '71.33.19.37', //ip address of client
|
||||||
worker: 'matt.worker1', //stratum worker name
|
worker: 'matt.worker1', //stratum worker name
|
||||||
height: 443795, //block height
|
height: 443795, //block height
|
||||||
poolReward: 4900000000, //the number of satoshis sent to the configured pool address
|
|
||||||
blockReward: 5000000000, //the number of satoshis received as payment for solving this block
|
blockReward: 5000000000, //the number of satoshis received as payment for solving this block
|
||||||
difficulty: 64, //stratum worker difficulty
|
difficulty: 64, //stratum worker difficulty
|
||||||
shareDiff: 78, //actual difficulty of the share
|
shareDiff: 78, //actual difficulty of the share
|
||||||
|
|||||||
@ -28,26 +28,23 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, pool
|
|||||||
return [null].concat(txHashes);
|
return [null].concat(txHashes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getVoteData(){
|
||||||
|
if (!rpcData.masternode_payments) return new Buffer([]);
|
||||||
|
|
||||||
|
return Buffer.concat(
|
||||||
|
[util.varIntBuffer(rpcData.votes.length)].concat(
|
||||||
|
rpcData.votes.map(function (vt) {
|
||||||
|
return new Buffer(vt, 'hex');
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
//public members
|
//public members
|
||||||
|
|
||||||
this.rpcData = rpcData;
|
this.rpcData = rpcData;
|
||||||
this.jobId = jobId;
|
this.jobId = jobId;
|
||||||
|
|
||||||
this.poolReward = (function(){
|
|
||||||
var pReward = rpcData.coinbasevalue;
|
|
||||||
for (var i = 0; i < recipients.length; i++){
|
|
||||||
var recipientReward = Math.floor(recipients[i].percent * rpcData.coinbasevalue);
|
|
||||||
pReward -= recipientReward;
|
|
||||||
}
|
|
||||||
return pReward;
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
||||||
//Use the 'target' field if available, but some daemons only return the 'bits' field
|
|
||||||
/*this.target = rpcData.target ?
|
|
||||||
bignum.fromBuffer(new Buffer(rpcData.target, 'hex')) :
|
|
||||||
util.bignumFromBits(rpcData.bits);*/
|
|
||||||
|
|
||||||
this.target = rpcData.target ?
|
this.target = rpcData.target ?
|
||||||
bignum(rpcData.target, 16) :
|
bignum(rpcData.target, 16) :
|
||||||
@ -55,6 +52,10 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, pool
|
|||||||
|
|
||||||
this.difficulty = parseFloat((diff1 / this.target.toNumber()).toFixed(9));
|
this.difficulty = parseFloat((diff1 / this.target.toNumber()).toFixed(9));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.prevHashReversed = util.reverseByteOrder(new Buffer(rpcData.previousblockhash, 'hex')).toString('hex');
|
this.prevHashReversed = util.reverseByteOrder(new Buffer(rpcData.previousblockhash, 'hex')).toString('hex');
|
||||||
this.transactionData = Buffer.concat(rpcData.transactions.map(function(tx){
|
this.transactionData = Buffer.concat(rpcData.transactions.map(function(tx){
|
||||||
return new Buffer(tx.data, 'hex');
|
return new Buffer(tx.data, 'hex');
|
||||||
@ -98,9 +99,13 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, pool
|
|||||||
this.serializeBlock = function(header, coinbase){
|
this.serializeBlock = function(header, coinbase){
|
||||||
return Buffer.concat([
|
return Buffer.concat([
|
||||||
header,
|
header,
|
||||||
|
|
||||||
util.varIntBuffer(this.rpcData.transactions.length + 1),
|
util.varIntBuffer(this.rpcData.transactions.length + 1),
|
||||||
coinbase,
|
coinbase,
|
||||||
this.transactionData,
|
this.transactionData,
|
||||||
|
|
||||||
|
getVoteData(),
|
||||||
|
|
||||||
//POS coins require a zero byte appended to block which the daemon replaces with the signature
|
//POS coins require a zero byte appended to block which the daemon replaces with the signature
|
||||||
new Buffer(reward === 'POS' ? [0] : [])
|
new Buffer(reward === 'POS' ? [0] : [])
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -13,16 +13,19 @@ var async = require('async');
|
|||||||
* - 'password': password for the rpc interface of the coin
|
* - 'password': password for the rpc interface of the coin
|
||||||
**/
|
**/
|
||||||
|
|
||||||
function DaemonInterface(options){
|
function DaemonInterface(daemons, logger){
|
||||||
|
|
||||||
//private members
|
//private members
|
||||||
var _this = this;
|
var _this = this;
|
||||||
this.options = options;
|
logger = logger || function(severity, message){
|
||||||
|
console.log(severity + ': ' + message);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
var instances = (function(){
|
var instances = (function(){
|
||||||
for (var i = 0; i < options.length; i++)
|
for (var i = 0; i < daemons.length; i++)
|
||||||
options[i]['index'] = i;
|
daemons[i]['index'] = i;
|
||||||
return options;
|
return daemons;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
@ -58,33 +61,28 @@ function DaemonInterface(options){
|
|||||||
|
|
||||||
var parseJson = function(res, data){
|
var parseJson = function(res, data){
|
||||||
var dataJson;
|
var dataJson;
|
||||||
var parsingError;
|
|
||||||
|
if (res.statusCode === 401){
|
||||||
|
logger('error', 'Unauthorized RPC access - invalid RPC username or password');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
dataJson = JSON.parse(data);
|
dataJson = JSON.parse(data);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch(e){
|
catch(e){
|
||||||
if (res.statusCode === 401){
|
if (data.indexOf(':-nan') !== -1){
|
||||||
parsingError = 'unauthorized';
|
data = data.replace(/:-nan,/g, ":0");
|
||||||
_this.emit('error', 'Invalid RPC username or password');
|
|
||||||
}
|
|
||||||
else if (data.indexOf(':-nan,') !== -1){
|
|
||||||
data = data.replace(/:-nan,/g, ":0,");
|
|
||||||
parseJson(res, data);
|
parseJson(res, data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else{
|
logger('error', 'Could not parse rpc data from daemon instance ' + instance.index
|
||||||
parsingError = e;
|
+ '\nRequest Data: ' + jsonData
|
||||||
_this.emit('error', 'could not parse rpc data with request of: ' + jsonData +
|
+ '\nReponse Data: ' + data);
|
||||||
' on instance ' + instance.index + ' data: ' + data + ' Error ' + JSON.stringify(parsingError));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (typeof(dataJson) !== 'undefined'){
|
if (dataJson)
|
||||||
callback(dataJson.error, dataJson, data);
|
callback(dataJson.error, dataJson, data);
|
||||||
}
|
|
||||||
else
|
|
||||||
callback(parsingError);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var req = http.request(options, function(res) {
|
var req = http.request(options, function(res) {
|
||||||
|
|||||||
@ -286,7 +286,6 @@ var JobManager = module.exports = function JobManager(options){
|
|||||||
worker: workerName,
|
worker: workerName,
|
||||||
height: job.rpcData.height,
|
height: job.rpcData.height,
|
||||||
blockReward: job.rpcData.coinbasevalue,
|
blockReward: job.rpcData.coinbasevalue,
|
||||||
poolReward: job.poolReward,
|
|
||||||
difficulty: difficulty,
|
difficulty: difficulty,
|
||||||
shareDiff: shareDiff.toFixed(8),
|
shareDiff: shareDiff.toFixed(8),
|
||||||
blockDiff : blockDiffAdjusted,
|
blockDiff : blockDiffAdjusted,
|
||||||
|
|||||||
30
lib/pool.js
30
lib/pool.js
@ -8,6 +8,10 @@ var stratum = require('./stratum.js');
|
|||||||
var jobManager = require('./jobManager.js');
|
var jobManager = require('./jobManager.js');
|
||||||
var util = require('./util.js');
|
var util = require('./util.js');
|
||||||
|
|
||||||
|
process.on('uncaughtException', function(err) {
|
||||||
|
console.log(err.stack);
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
var pool = module.exports = function pool(options, authorizeFn){
|
var pool = module.exports = function pool(options, authorizeFn){
|
||||||
|
|
||||||
@ -235,17 +239,21 @@ var pool = module.exports = function pool(options, authorizeFn){
|
|||||||
_this.daemon.cmd(rpcCommand,
|
_this.daemon.cmd(rpcCommand,
|
||||||
rpcArgs,
|
rpcArgs,
|
||||||
function(results){
|
function(results){
|
||||||
results.forEach(function(result){
|
for (var i = 0; i < results.length; i++){
|
||||||
if (result.error)
|
var result = results[i];
|
||||||
|
if (result.error) {
|
||||||
emitErrorLog('rpc error with daemon instance ' +
|
emitErrorLog('rpc error with daemon instance ' +
|
||||||
result.instance.index + ' when submitting block with ' + rpcCommand + ' ' +
|
result.instance.index + ' when submitting block with ' + rpcCommand + ' ' +
|
||||||
JSON.stringify(result.error)
|
JSON.stringify(result.error)
|
||||||
);
|
);
|
||||||
else
|
return;
|
||||||
emitLog('Submitted Block using ' + rpcCommand + ' to daemon instance ' +
|
}
|
||||||
result.instance.index
|
else if (result.response === 'rejected') {
|
||||||
);
|
emitErrorLog('Daemon instance ' + result.instance.index + ' rejected a supposedly valid block');
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emitLog('Submitted Block using ' + rpcCommand + ' successfully to daemon instance(s)');
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -338,7 +346,9 @@ var pool = module.exports = function pool(options, authorizeFn){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_this.daemon = new daemon.interface(options.daemons);
|
_this.daemon = new daemon.interface(options.daemons, function(severity, message){
|
||||||
|
_this.emit('log', severity , message);
|
||||||
|
});
|
||||||
|
|
||||||
_this.daemon.once('online', function(){
|
_this.daemon.once('online', function(){
|
||||||
finishedCallback();
|
finishedCallback();
|
||||||
|
|||||||
@ -123,18 +123,35 @@ For some (probably outdated and incorrect) documentation about whats kinda going
|
|||||||
see: https://en.bitcoin.it/wiki/Protocol_specification#tx
|
see: https://en.bitcoin.it/wiki/Protocol_specification#tx
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var generateOutputTransactions = function(poolRecipient, recipients, reward){
|
var generateOutputTransactions = function(poolRecipient, recipients, rpcData){
|
||||||
|
|
||||||
var totalOutputs = 1;
|
var reward = rpcData.coinbasevalue;
|
||||||
|
var rewardToPool = reward;
|
||||||
|
|
||||||
var txOutputBuffers = [];
|
var txOutputBuffers = [];
|
||||||
|
|
||||||
var totalToRecipients = 0;
|
|
||||||
|
|
||||||
|
if (rpcData.payee) {
|
||||||
|
var payeeReward = Math.ceil(reward / 10);
|
||||||
|
|
||||||
|
reward -= payeeReward;
|
||||||
|
rewardToPool -= payeeReward;
|
||||||
|
|
||||||
|
var payeeScript = util.addressToScript(rpcData.payee);
|
||||||
|
txOutputBuffers.push(Buffer.concat([
|
||||||
|
util.packInt64LE(payeeReward),
|
||||||
|
util.varIntBuffer(payeeScript.length),
|
||||||
|
payeeScript
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (var i = 0; i < recipients.length; i++){
|
for (var i = 0; i < recipients.length; i++){
|
||||||
var recipientReward = Math.floor(recipients[i].percent * reward);
|
var recipientReward = Math.floor(recipients[i].percent * reward);
|
||||||
totalToRecipients += recipientReward;
|
rewardToPool -= recipientReward;
|
||||||
totalOutputs++;
|
|
||||||
txOutputBuffers.push(Buffer.concat([
|
txOutputBuffers.push(Buffer.concat([
|
||||||
util.packInt64LE(recipientReward),
|
util.packInt64LE(recipientReward),
|
||||||
util.varIntBuffer(recipients[i].script.length),
|
util.varIntBuffer(recipients[i].script.length),
|
||||||
@ -142,7 +159,6 @@ var generateOutputTransactions = function(poolRecipient, recipients, reward){
|
|||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
var rewardToPool = reward - totalToRecipients;
|
|
||||||
|
|
||||||
txOutputBuffers.push(Buffer.concat([
|
txOutputBuffers.push(Buffer.concat([
|
||||||
util.packInt64LE(rewardToPool),
|
util.packInt64LE(rewardToPool),
|
||||||
@ -151,7 +167,7 @@ var generateOutputTransactions = function(poolRecipient, recipients, reward){
|
|||||||
]));
|
]));
|
||||||
|
|
||||||
return Buffer.concat([
|
return Buffer.concat([
|
||||||
util.varIntBuffer(totalOutputs),
|
util.varIntBuffer(txOutputBuffers.length),
|
||||||
Buffer.concat(txOutputBuffers)
|
Buffer.concat(txOutputBuffers)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -207,13 +223,16 @@ exports.CreateGeneration = function(rpcData, publicKey, extraNoncePlaceholder, r
|
|||||||
a valid share and/or block.
|
a valid share and/or block.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
var outputTransactions = generateOutputTransactions(publicKey, recipients, rpcData);
|
||||||
|
|
||||||
var p2 = Buffer.concat([
|
var p2 = Buffer.concat([
|
||||||
scriptSigPart2,
|
scriptSigPart2,
|
||||||
util.packUInt32LE(txInSequence),
|
util.packUInt32LE(txInSequence),
|
||||||
//end transaction input
|
//end transaction input
|
||||||
|
|
||||||
//transaction output
|
//transaction output
|
||||||
generateOutputTransactions(publicKey, recipients, rpcData.coinbasevalue),
|
outputTransactions,
|
||||||
//end transaction ouput
|
//end transaction ouput
|
||||||
|
|
||||||
util.packUInt32LE(txLockTime),
|
util.packUInt32LE(txLockTime),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user