Added rewardRecipients config, moved peer magic to coin config
This commit is contained in:
parent
64d832e1a2
commit
dfad9e58c6
40
README.md
40
README.md
@ -89,9 +89,16 @@ var myCoin = {
|
|||||||
"name": "Dogecoin",
|
"name": "Dogecoin",
|
||||||
"symbol": "DOGE",
|
"symbol": "DOGE",
|
||||||
"algorithm": "scrypt",
|
"algorithm": "scrypt",
|
||||||
"nValue": 1024, //optional. Defaults to 1024
|
"nValue": 1024, //optional - defaults to 1024
|
||||||
"rValue": 1, //optional. Defaults to 1
|
"rValue": 1, //optional - defaults to 1
|
||||||
"txMessages": false, //or true (not required, defaults to false)
|
"txMessages": false, //optional - defaults to false,
|
||||||
|
|
||||||
|
/* Magic value only required for setting up p2p block notifications. It is found in the daemon
|
||||||
|
source code as the pchMessageStart variable.
|
||||||
|
For example, litecoin mainnet magic: http://git.io/Bi8YFw
|
||||||
|
And for litecoin testnet magic: http://git.io/NXBYJA */
|
||||||
|
"peerMagic": "fbc0b6db" //optional
|
||||||
|
"peerMagicTestnet": "fcc1b7dc" //optional
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -154,6 +161,18 @@ var pool = Stratum.createPool({
|
|||||||
"coin": myCoin,
|
"coin": myCoin,
|
||||||
|
|
||||||
"address": "mi4iBXbBsydtcc5yFmsff2zCFVX4XG7qJc", //Address to where block rewards are given
|
"address": "mi4iBXbBsydtcc5yFmsff2zCFVX4XG7qJc", //Address to where block rewards are given
|
||||||
|
|
||||||
|
/* Block rewards go to the configured pool wallet address to later be paid out to miners,
|
||||||
|
except for a percentages that can go to pool operator(s) as pool fees or donations.
|
||||||
|
Addresses or hashed public keys can be used. */
|
||||||
|
"rewardRecipients": {
|
||||||
|
"n37vuNFkXfk15uFnGoVyHZ6PYQxppD3QqK": 1.5, //1.5% goes to pool op
|
||||||
|
"mirj3LtZxbSTharhtXvotqtJXUY7ki5qfx": 0.5, //0.5% goes to a pool co-owner
|
||||||
|
|
||||||
|
//0.1% donation to NOMP to help support development
|
||||||
|
"22851477d63a085dbc2398c8430af1c09e7343f6": 0.1
|
||||||
|
},
|
||||||
|
|
||||||
"blockRefreshInterval": 1000, //How often to poll RPC daemons for new blocks, in milliseconds
|
"blockRefreshInterval": 1000, //How often to poll RPC daemons for new blocks, in milliseconds
|
||||||
|
|
||||||
/* How many milliseconds should have passed before new block transactions will trigger a new
|
/* How many milliseconds should have passed before new block transactions will trigger a new
|
||||||
@ -220,7 +239,6 @@ var pool = Stratum.createPool({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/* Recommended to have at least two daemon instances running in case one drops out-of-sync
|
/* Recommended to have at least two daemon instances running in case one drops out-of-sync
|
||||||
or offline. For redundancy, all instances will be polled for block/transaction updates
|
or offline. For redundancy, all instances will be polled for block/transaction updates
|
||||||
and be used for submitting blocks. Creating a backup daemon involves spawning a daemon
|
and be used for submitting blocks. Creating a backup daemon involves spawning a daemon
|
||||||
@ -246,8 +264,8 @@ var pool = Stratum.createPool({
|
|||||||
|
|
||||||
/* This allows the pool to connect to the daemon as a node peer to receive block updates.
|
/* This allows the pool to connect to the daemon as a node peer to receive block updates.
|
||||||
It may be the most efficient way to get block updates (faster than polling, less
|
It may be the most efficient way to get block updates (faster than polling, less
|
||||||
intensive than blocknotify script). It requires additional setup: the 'magic' field must
|
intensive than blocknotify script). It requires the additional field "peerMagic" in
|
||||||
be exact (extracted from the coin source code). */
|
the coin config. */
|
||||||
"p2p": {
|
"p2p": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
|
|
||||||
@ -260,13 +278,8 @@ var pool = Stratum.createPool({
|
|||||||
/* If your coin daemon is new enough (i.e. not a shitcoin) then it will support a p2p
|
/* If your coin daemon is new enough (i.e. not a shitcoin) then it will support a p2p
|
||||||
feature that prevents the daemon from spamming our peer node with unnecessary
|
feature that prevents the daemon from spamming our peer node with unnecessary
|
||||||
transaction data. Assume its supported but if you have problems try disabling it. */
|
transaction data. Assume its supported but if you have problems try disabling it. */
|
||||||
"disableTransactions": true,
|
"disableTransactions": true
|
||||||
|
|
||||||
/* Magic value is different for main/testnet and for each coin. It is found in the daemon
|
|
||||||
source code as the pchMessageStart variable.
|
|
||||||
For example, litecoin mainnet magic: http://git.io/Bi8YFw
|
|
||||||
And for litecoin testnet magic: http://git.io/NXBYJA */
|
|
||||||
"magic": "fcc1b7dc"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}, function(ip, workerName, password, callback){ //stratum authorization function
|
}, function(ip, workerName, password, callback){ //stratum authorization function
|
||||||
@ -289,7 +302,8 @@ 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
|
||||||
reward: 5000000000, //the number of satoshis received as payment for solving this block
|
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
|
||||||
difficulty: 64, //stratum worker difficulty
|
difficulty: 64, //stratum worker difficulty
|
||||||
shareDiff: 78, //actual difficulty of the share
|
shareDiff: 78, //actual difficulty of the share
|
||||||
blockDiff: 3349, //block difficulty adjusted for share padding
|
blockDiff: 3349, //block difficulty adjusted for share padding
|
||||||
|
|||||||
@ -9,7 +9,7 @@ var util = require('./util.js');
|
|||||||
* The BlockTemplate class holds a single job.
|
* The BlockTemplate class holds a single job.
|
||||||
* and provides several methods to validate and submit it to the daemon coin
|
* and provides several methods to validate and submit it to the daemon coin
|
||||||
**/
|
**/
|
||||||
var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, publicKey, extraNoncePlaceholder, reward, txMessages){
|
var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, poolAddressScript, extraNoncePlaceholder, reward, txMessages, recipients){
|
||||||
|
|
||||||
//private members
|
//private members
|
||||||
|
|
||||||
@ -34,6 +34,14 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, publ
|
|||||||
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
|
//Use the 'target' field if available, but some daemons only return the 'bits' field
|
||||||
@ -55,10 +63,11 @@ var BlockTemplate = module.exports = function BlockTemplate(jobId, rpcData, publ
|
|||||||
this.merkleBranch = getMerkleHashes(this.merkleTree.steps);
|
this.merkleBranch = getMerkleHashes(this.merkleTree.steps);
|
||||||
this.generationTransaction = transactions.CreateGeneration(
|
this.generationTransaction = transactions.CreateGeneration(
|
||||||
rpcData,
|
rpcData,
|
||||||
publicKey,
|
poolAddressScript,
|
||||||
extraNoncePlaceholder,
|
extraNoncePlaceholder,
|
||||||
reward,
|
reward,
|
||||||
txMessages
|
txMessages,
|
||||||
|
recipients
|
||||||
);
|
);
|
||||||
|
|
||||||
this.serializeCoinbase = function(extraNonce1, extraNonce2){
|
this.serializeCoinbase = function(extraNonce1, extraNonce2){
|
||||||
|
|||||||
@ -81,7 +81,7 @@ function DaemonInterface(options){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeof(dataJson) !== 'undefined'){
|
if (typeof(dataJson) !== 'undefined'){
|
||||||
callback(dataJson.error, dataJson);
|
callback(dataJson.error, dataJson, data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
callback(parsingError);
|
callback(parsingError);
|
||||||
@ -141,20 +141,20 @@ function DaemonInterface(options){
|
|||||||
/* Sends a JSON RPC (http://json-rpc.org/wiki/specification) command to every configured daemon.
|
/* Sends a JSON RPC (http://json-rpc.org/wiki/specification) command to every configured daemon.
|
||||||
The callback function is fired once with the result from each daemon unless streamResults is
|
The callback function is fired once with the result from each daemon unless streamResults is
|
||||||
set to true. */
|
set to true. */
|
||||||
function cmd(method, params, callback, streamResults){
|
function cmd(method, params, callback, streamResults, returnRawData){
|
||||||
|
|
||||||
var results = [];
|
var results = [];
|
||||||
|
|
||||||
async.each(instances, function(instance, eachCallback){
|
async.each(instances, function(instance, eachCallback){
|
||||||
|
|
||||||
var itemFinished = function(error, result){
|
var itemFinished = function(error, result, data){
|
||||||
|
|
||||||
var returnObj = {
|
var returnObj = {
|
||||||
error: error,
|
error: error,
|
||||||
response: (result || {}).result,
|
response: (result || {}).result,
|
||||||
instance: instance
|
instance: instance
|
||||||
};
|
};
|
||||||
|
if (returnRawData) returnObj.data = data;
|
||||||
if (streamResults) callback(returnObj);
|
if (streamResults) callback(returnObj);
|
||||||
else results.push(returnObj);
|
else results.push(returnObj);
|
||||||
eachCallback();
|
eachCallback();
|
||||||
@ -167,8 +167,8 @@ function DaemonInterface(options){
|
|||||||
id: Date.now() + Math.floor(Math.random() * 10)
|
id: Date.now() + Math.floor(Math.random() * 10)
|
||||||
});
|
});
|
||||||
|
|
||||||
performHttpRequest(instance, requestJson, function(error, result){
|
performHttpRequest(instance, requestJson, function(error, result, data){
|
||||||
itemFinished(error, result);
|
itemFinished(error, result, data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -109,14 +109,15 @@ var JobManager = module.exports = function JobManager(options){
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
this.updateCurrentJob = function(publicKey){
|
this.updateCurrentJob = function(){
|
||||||
var tmpBlockTemplate = new blockTemplate(
|
var tmpBlockTemplate = new blockTemplate(
|
||||||
jobCounter.next(),
|
jobCounter.next(),
|
||||||
_this.currentJob.rpcData,
|
_this.currentJob.rpcData,
|
||||||
publicKey,
|
options.poolAddressScript,
|
||||||
_this.extraNoncePlaceholder,
|
_this.extraNoncePlaceholder,
|
||||||
options.coin.reward,
|
options.coin.reward,
|
||||||
options.coin.txMessages
|
options.coin.txMessages,
|
||||||
|
options.recipients
|
||||||
);
|
);
|
||||||
|
|
||||||
_this.currentJob = tmpBlockTemplate;
|
_this.currentJob = tmpBlockTemplate;
|
||||||
@ -128,7 +129,7 @@ var JobManager = module.exports = function JobManager(options){
|
|||||||
};
|
};
|
||||||
|
|
||||||
//returns true if processed a new block
|
//returns true if processed a new block
|
||||||
this.processTemplate = function(rpcData, publicKey){
|
this.processTemplate = function(rpcData){
|
||||||
|
|
||||||
/* Block is new if A) its the first block we have seen so far or B) the blockhash is different and the
|
/* Block is new if A) its the first block we have seen so far or B) the blockhash is different and the
|
||||||
block height is greater than the one we have */
|
block height is greater than the one we have */
|
||||||
@ -159,10 +160,11 @@ var JobManager = module.exports = function JobManager(options){
|
|||||||
var tmpBlockTemplate = new blockTemplate(
|
var tmpBlockTemplate = new blockTemplate(
|
||||||
jobCounter.next(),
|
jobCounter.next(),
|
||||||
rpcData,
|
rpcData,
|
||||||
publicKey,
|
options.poolAddressScript,
|
||||||
_this.extraNoncePlaceholder,
|
_this.extraNoncePlaceholder,
|
||||||
options.coin.reward,
|
options.coin.reward,
|
||||||
options.coin.txMessages
|
options.coin.txMessages,
|
||||||
|
options.recipients
|
||||||
);
|
);
|
||||||
|
|
||||||
this.currentJob = tmpBlockTemplate;
|
this.currentJob = tmpBlockTemplate;
|
||||||
@ -283,7 +285,8 @@ var JobManager = module.exports = function JobManager(options){
|
|||||||
ip: ipAddress,
|
ip: ipAddress,
|
||||||
worker: workerName,
|
worker: workerName,
|
||||||
height: job.rpcData.height,
|
height: job.rpcData.height,
|
||||||
reward: 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,
|
||||||
|
|||||||
@ -46,7 +46,7 @@ var Peer = module.exports = function (options) {
|
|||||||
|
|
||||||
var _this = this;
|
var _this = this;
|
||||||
var client;
|
var client;
|
||||||
var magic = new Buffer(options.p2p.magic, 'hex');
|
var magic = new Buffer(options.testnet ? options.coin.peerMagicTestnet : options.coin.peerMagic, 'hex');
|
||||||
var magicInt = magic.readUInt32LE(0);
|
var magicInt = magic.readUInt32LE(0);
|
||||||
var verack = false;
|
var verack = false;
|
||||||
var validConnectionConfig = true;
|
var validConnectionConfig = true;
|
||||||
|
|||||||
78
lib/pool.js
78
lib/pool.js
@ -9,21 +9,6 @@ var jobManager = require('./jobManager.js');
|
|||||||
var util = require('./util.js');
|
var util = require('./util.js');
|
||||||
|
|
||||||
|
|
||||||
var bignum = require('bignum');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main pool object. It emits the following events:
|
|
||||||
* - started() - when the pool is effectively started
|
|
||||||
* - share(isValidShare, isValidBlock, shareData) - When a share is submitted
|
|
||||||
* - log(severity, key, text) - for debug, warning, and error messages
|
|
||||||
*
|
|
||||||
* It initializes and connects:
|
|
||||||
* - JobManager - for generating miner work, processing block templates and shares
|
|
||||||
* - DaemonInterface - for RPC communication with daemon
|
|
||||||
* - StratumServer - for TCP socket communication with miners
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
var pool = module.exports = function pool(options, authorizeFn){
|
var pool = module.exports = function pool(options, authorizeFn){
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
@ -44,13 +29,6 @@ var pool = module.exports = function pool(options, authorizeFn){
|
|||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
//var diff1 = options.coin.diffShift ?
|
|
||||||
// util.getTruncatedDiff(options.coin.diffShift) :
|
|
||||||
// algos[options.coin.algorithm].diff;
|
|
||||||
|
|
||||||
|
|
||||||
//Which number to use as dividend when converting difficulty to target
|
|
||||||
//var maxDifficulty = algos[options.coin.algorithm].maxDiff;
|
|
||||||
|
|
||||||
|
|
||||||
this.start = function(){
|
this.start = function(){
|
||||||
@ -58,6 +36,7 @@ var pool = module.exports = function pool(options, authorizeFn){
|
|||||||
SetupApi();
|
SetupApi();
|
||||||
SetupDaemonInterface(function(){
|
SetupDaemonInterface(function(){
|
||||||
DetectCoinData(function(){
|
DetectCoinData(function(){
|
||||||
|
SetupRecipients();
|
||||||
SetupJobManager();
|
SetupJobManager();
|
||||||
OnBlockchainSynced(function(){
|
OnBlockchainSynced(function(){
|
||||||
GetFirstJob(function(){
|
GetFirstJob(function(){
|
||||||
@ -122,7 +101,8 @@ var pool = module.exports = function pool(options, authorizeFn){
|
|||||||
'Current Block Diff:\t' + _this.jobManager.currentJob.difficulty * algos[options.coin.algorithm].multiplier,
|
'Current Block Diff:\t' + _this.jobManager.currentJob.difficulty * algos[options.coin.algorithm].multiplier,
|
||||||
'Network Difficulty:\t' + options.initStats.difficulty,
|
'Network Difficulty:\t' + options.initStats.difficulty,
|
||||||
'Network Hash Rate:\t' + util.getReadableHashRateString(options.initStats.networkHashRate),
|
'Network Hash Rate:\t' + util.getReadableHashRateString(options.initStats.networkHashRate),
|
||||||
'Stratum Port(s):\t' + _this.options.initStats.stratumPorts.join(', ')
|
'Stratum Port(s):\t' + _this.options.initStats.stratumPorts.join(', '),
|
||||||
|
'Pool Fee Percent:\t' + _this.options.feePercent + '%'
|
||||||
];
|
];
|
||||||
|
|
||||||
if (typeof options.blockRefreshInterval === "number" && options.blockRefreshInterval > 0)
|
if (typeof options.blockRefreshInterval === "number" && options.blockRefreshInterval > 0)
|
||||||
@ -198,6 +178,16 @@ var pool = module.exports = function pool(options, authorizeFn){
|
|||||||
function SetupPeer(){
|
function SetupPeer(){
|
||||||
if (!options.p2p || !options.p2p.enabled)
|
if (!options.p2p || !options.p2p.enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (options.testnet && !options.coin.peerMagicTestnet){
|
||||||
|
emitErrorLog('p2p cannot be enabled in testnet without peerMagicTestnet set in coin configuration');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (!options.coin.peerMagic){
|
||||||
|
emitErrorLog('p2p cannot be enabled without peerMagic set in coin configuration');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_this.peer = new peer(options);
|
_this.peer = new peer(options);
|
||||||
_this.peer.on('connected', function() {
|
_this.peer.on('connected', function() {
|
||||||
emitLog('p2p connection successful');
|
emitLog('p2p connection successful');
|
||||||
@ -263,6 +253,33 @@ var pool = module.exports = function pool(options, authorizeFn){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function SetupRecipients(){
|
||||||
|
var recipients = [];
|
||||||
|
options.feePercent = 0;
|
||||||
|
options.rewardRecipients = options.rewardRecipients || {};
|
||||||
|
for (var r in options.rewardRecipients){
|
||||||
|
var percent = options.rewardRecipients[r];
|
||||||
|
var rObj = {
|
||||||
|
percent: percent / 100
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
if (r.length === 40)
|
||||||
|
rObj.script = util.miningKeyToScript(r);
|
||||||
|
else
|
||||||
|
rObj.script = util.addressToScript(r);
|
||||||
|
recipients.push(rObj);
|
||||||
|
options.feePercent += percent;
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
emitErrorLog('Error generating transaction output script for ' + r + ' in rewardRecipients');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (recipients.length === 0){
|
||||||
|
emitErrorLog('No rewardRecipients have been setup which means no fees will be taken');
|
||||||
|
}
|
||||||
|
options.recipients = recipients;
|
||||||
|
}
|
||||||
|
|
||||||
function SetupJobManager(){
|
function SetupJobManager(){
|
||||||
|
|
||||||
_this.jobManager = new jobManager(options);
|
_this.jobManager = new jobManager(options);
|
||||||
@ -385,7 +402,7 @@ var pool = module.exports = function pool(options, authorizeFn){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
options.publicKeyBuffer = (function(){
|
options.poolAddressScript = (function(){
|
||||||
switch(options.coin.reward){
|
switch(options.coin.reward){
|
||||||
case 'POS':
|
case 'POS':
|
||||||
return util.pubkeyToScript(rpcResults.validateaddress.pubkey);
|
return util.pubkeyToScript(rpcResults.validateaddress.pubkey);
|
||||||
@ -433,7 +450,7 @@ var pool = module.exports = function pool(options, authorizeFn){
|
|||||||
|
|
||||||
}).on('broadcastTimeout', function(){
|
}).on('broadcastTimeout', function(){
|
||||||
emitLog('No new work for ' + options.jobRebroadcastTimeout + ' seconds - updating & rebroadcasting current job');
|
emitLog('No new work for ' + options.jobRebroadcastTimeout + ' seconds - updating & rebroadcasting current job');
|
||||||
_this.jobManager.updateCurrentJob(options.publicKeyBuffer);
|
_this.jobManager.updateCurrentJob();
|
||||||
|
|
||||||
}).on('client.connected', function(client){
|
}).on('client.connected', function(client){
|
||||||
if (typeof(_this.varDiff[client.socket.localPort]) !== 'undefined') {
|
if (typeof(_this.varDiff[client.socket.localPort]) !== 'undefined') {
|
||||||
@ -541,16 +558,7 @@ var pool = module.exports = function pool(options, authorizeFn){
|
|||||||
result.instance.index + ' with error ' + JSON.stringify(result.error));
|
result.instance.index + ' with error ' + JSON.stringify(result.error));
|
||||||
callback(result.error);
|
callback(result.error);
|
||||||
} else {
|
} else {
|
||||||
var processedNewBlock = _this.jobManager.processTemplate(result.response, options.publicKeyBuffer);
|
var processedNewBlock = _this.jobManager.processTemplate(result.response);
|
||||||
|
|
||||||
if (processedNewBlock) {
|
|
||||||
|
|
||||||
Object.keys(_this.varDiff).forEach(function(port){
|
|
||||||
_this.varDiff[port].setNetworkDifficulty(_this.jobManager.currentJob.difficulty);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
callback(null, result.response, processedNewBlock);
|
callback(null, result.response, processedNewBlock);
|
||||||
callback = function(){};
|
callback = function(){};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -123,9 +123,42 @@ 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 totalOutputs = 1;
|
||||||
|
|
||||||
|
var txOutputBuffers = [];
|
||||||
|
|
||||||
|
var totalToRecipients = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < recipients.length; i++){
|
||||||
|
var recipientReward = Math.floor(recipients[i].percent * reward);
|
||||||
|
totalToRecipients += recipientReward;
|
||||||
|
totalOutputs++;
|
||||||
|
txOutputBuffers.push(Buffer.concat([
|
||||||
|
util.packInt64LE(recipientReward),
|
||||||
|
util.varIntBuffer(recipients[i].script.length),
|
||||||
|
recipients[i].script
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
var rewardToPool = reward - totalToRecipients;
|
||||||
|
|
||||||
|
txOutputBuffers.push(Buffer.concat([
|
||||||
|
util.packInt64LE(rewardToPool),
|
||||||
|
util.varIntBuffer(poolRecipient.length),
|
||||||
|
poolRecipient
|
||||||
|
]));
|
||||||
|
|
||||||
|
return Buffer.concat([
|
||||||
|
util.varIntBuffer(totalOutputs),
|
||||||
|
Buffer.concat(txOutputBuffers)
|
||||||
|
]);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
exports.CreateGeneration = function(rpcData, publicKey, extraNoncePlaceholder, reward, txMessages){
|
exports.CreateGeneration = function(rpcData, publicKey, extraNoncePlaceholder, reward, txMessages, recipients){
|
||||||
|
|
||||||
var txInputsCount = 1;
|
var txInputsCount = 1;
|
||||||
var txOutputsCount = 1;
|
var txOutputsCount = 1;
|
||||||
@ -158,9 +191,9 @@ exports.CreateGeneration = function(rpcData, publicKey, extraNoncePlaceholder, r
|
|||||||
var p1 = Buffer.concat([
|
var p1 = Buffer.concat([
|
||||||
util.packUInt32LE(txVersion),
|
util.packUInt32LE(txVersion),
|
||||||
txTimestamp,
|
txTimestamp,
|
||||||
util.varIntBuffer(txInputsCount),
|
|
||||||
|
|
||||||
//transaction input
|
//transaction input
|
||||||
|
util.varIntBuffer(txInputsCount),
|
||||||
util.uint256BufferFromHash(txInPrevOutHash),
|
util.uint256BufferFromHash(txInPrevOutHash),
|
||||||
util.packUInt32LE(txInPrevOutIndex),
|
util.packUInt32LE(txInPrevOutIndex),
|
||||||
util.varIntBuffer(scriptSigPart1.length + extraNoncePlaceholder.length + scriptSigPart2.length),
|
util.varIntBuffer(scriptSigPart1.length + extraNoncePlaceholder.length + scriptSigPart2.length),
|
||||||
@ -179,12 +212,8 @@ exports.CreateGeneration = function(rpcData, publicKey, extraNoncePlaceholder, r
|
|||||||
util.packUInt32LE(txInSequence),
|
util.packUInt32LE(txInSequence),
|
||||||
//end transaction input
|
//end transaction input
|
||||||
|
|
||||||
util.varIntBuffer(txOutputsCount),
|
|
||||||
|
|
||||||
//transaction output
|
//transaction output
|
||||||
util.packInt64LE(rpcData.coinbasevalue),
|
generateOutputTransactions(publicKey, recipients, rpcData.coinbasevalue),
|
||||||
util.varIntBuffer(publicKey.length),
|
|
||||||
publicKey,
|
|
||||||
//end transaction ouput
|
//end transaction ouput
|
||||||
|
|
||||||
util.packUInt32LE(txLockTime),
|
util.packUInt32LE(txLockTime),
|
||||||
|
|||||||
@ -253,6 +253,11 @@ exports.pubkeyToScript = function(key){
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.miningKeyToScript = function(key){
|
||||||
|
var keyBuffer = new Buffer(key, 'hex');
|
||||||
|
return Buffer.concat([new Buffer([0x76, 0xa9, 0x14]), keyBuffer, new Buffer([0x88, 0xac])]);
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
For POW coins - used to format wallet address for use in generation transaction's output
|
For POW coins - used to format wallet address for use in generation transaction's output
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -48,8 +48,6 @@ function toFixed(num, len) {
|
|||||||
var varDiff = module.exports = function varDiff(port, varDiffOptions){
|
var varDiff = module.exports = function varDiff(port, varDiffOptions){
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
|
||||||
var networkDifficulty;
|
|
||||||
|
|
||||||
var bufferSize, tMin, tMax;
|
var bufferSize, tMin, tMax;
|
||||||
|
|
||||||
//if (!varDiffOptions) return;
|
//if (!varDiffOptions) return;
|
||||||
@ -61,9 +59,6 @@ var varDiff = module.exports = function varDiff(port, varDiffOptions){
|
|||||||
tMin = varDiffOptions.targetTime - variance;
|
tMin = varDiffOptions.targetTime - variance;
|
||||||
tMax = varDiffOptions.targetTime + variance;
|
tMax = varDiffOptions.targetTime + variance;
|
||||||
|
|
||||||
this.setNetworkDifficulty = function(diff){
|
|
||||||
networkDifficulty = diff;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
this.manageClient = function(client){
|
this.manageClient = function(client){
|
||||||
@ -113,7 +108,6 @@ var varDiff = module.exports = function varDiff(port, varDiffOptions){
|
|||||||
if (options.x2mode) {
|
if (options.x2mode) {
|
||||||
ddiff = 2;
|
ddiff = 2;
|
||||||
}
|
}
|
||||||
//var diffMax = networkDifficulty < options.maxDiff ? networkDifficulty : options.maxDiff;
|
|
||||||
var diffMax = options.maxDiff;
|
var diffMax = options.maxDiff;
|
||||||
if (ddiff * client.difficulty > diffMax) {
|
if (ddiff * client.difficulty > diffMax) {
|
||||||
ddiff = diffMax / client.difficulty;
|
ddiff = diffMax / client.difficulty;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user