Expose merge-mining block classifications
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 41s
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 41s
This commit is contained in:
85
lib/api.js
85
lib/api.js
@@ -79,6 +79,9 @@ function handleServerRequest (request, response) {
|
|||||||
case '/get_blocks':
|
case '/get_blocks':
|
||||||
handleGetBlocks(urlParts, response);
|
handleGetBlocks(urlParts, response);
|
||||||
break;
|
break;
|
||||||
|
case '/get_mm_blocks':
|
||||||
|
handleGetMergeMiningBlocks(urlParts, response);
|
||||||
|
break;
|
||||||
|
|
||||||
// Get market prices
|
// Get market prices
|
||||||
case '/get_market':
|
case '/get_market':
|
||||||
@@ -1034,6 +1037,88 @@ function handleGetBlocks (urlParts, response) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parsePoolBlockEntry (serialized, score, source) {
|
||||||
|
let block = serialized.split(':');
|
||||||
|
let rewardType = block[0];
|
||||||
|
let base = {
|
||||||
|
source: source,
|
||||||
|
height: parseInt(score),
|
||||||
|
rewardType: rewardType,
|
||||||
|
miner: rewardType === 'solo' || rewardType === 'prop'
|
||||||
|
? `${block[1].substring(0, 7)}...${block[1].substring(block[1].length - 7)}`
|
||||||
|
: block[1],
|
||||||
|
hash: block[2],
|
||||||
|
timestamp: parseInt(block[3]),
|
||||||
|
difficulty: parseInt(block[4]),
|
||||||
|
shares: parseInt(block[5]),
|
||||||
|
orphaned: false,
|
||||||
|
reward: null,
|
||||||
|
mmClassification: 'plain',
|
||||||
|
auxAccepted: false,
|
||||||
|
parentAccepted: false
|
||||||
|
};
|
||||||
|
|
||||||
|
if (source === 'candidate') {
|
||||||
|
base.score = block[6] ? parseFloat(block[6]) : parseInt(block[5]);
|
||||||
|
base.mmClassification = block[7] || 'plain';
|
||||||
|
base.auxAccepted = block[8] === '1';
|
||||||
|
base.parentAccepted = block[9] === '1';
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.orphaned = block[6] === '1';
|
||||||
|
let hasReward = block.length >= 8 && /^\d+$/.test(block[7]);
|
||||||
|
base.reward = hasReward ? block[7] : null;
|
||||||
|
let mmIndex = hasReward ? 8 : 7;
|
||||||
|
base.mmClassification = block[mmIndex] || 'plain';
|
||||||
|
base.auxAccepted = block[mmIndex + 1] === '1';
|
||||||
|
base.parentAccepted = block[mmIndex + 2] === '1';
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleGetMergeMiningBlocks (urlParts, response) {
|
||||||
|
let fromHeight = parseInt(urlParts.query.from_height || 0);
|
||||||
|
let limit = parseInt(urlParts.query.limit || config.api.blocks || 100);
|
||||||
|
if (isNaN(fromHeight) || fromHeight < 0) fromHeight = 0;
|
||||||
|
if (isNaN(limit) || limit <= 0) limit = config.api.blocks || 100;
|
||||||
|
|
||||||
|
let redisCommands = [
|
||||||
|
['zrevrangebyscore', `${config.coin}:blocks:candidates`, '+inf', fromHeight, 'WITHSCORES', 'LIMIT', 0, limit],
|
||||||
|
['zrevrangebyscore', `${config.coin}:blocks:matured`, '+inf', fromHeight, 'WITHSCORES', 'LIMIT', 0, limit]
|
||||||
|
];
|
||||||
|
|
||||||
|
redisClient.multi(redisCommands).exec(function (err, replies) {
|
||||||
|
let data;
|
||||||
|
if (err) {
|
||||||
|
data = { error: 'Query failed' };
|
||||||
|
} else {
|
||||||
|
let items = [];
|
||||||
|
let candidates = replies[0] || [];
|
||||||
|
let matured = replies[1] || [];
|
||||||
|
|
||||||
|
for (let i = 0; i < candidates.length; i += 2) {
|
||||||
|
items.push(parsePoolBlockEntry(candidates[i], candidates[i + 1], 'candidate'));
|
||||||
|
}
|
||||||
|
for (let i = 0; i < matured.length; i += 2) {
|
||||||
|
items.push(parsePoolBlockEntry(matured[i], matured[i + 1], 'matured'));
|
||||||
|
}
|
||||||
|
|
||||||
|
data = {
|
||||||
|
items: items
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let reply = JSON.stringify(data);
|
||||||
|
response.writeHead("200", {
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Cache-Control': 'no-cache',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Content-Length': Buffer.byteLength(reply, 'utf8')
|
||||||
|
});
|
||||||
|
response.end(reply);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get market exchange prices
|
* Get market exchange prices
|
||||||
**/
|
**/
|
||||||
|
|||||||
@@ -53,7 +53,10 @@ function runInterval () {
|
|||||||
time: parts[3],
|
time: parts[3],
|
||||||
difficulty: parts[4],
|
difficulty: parts[4],
|
||||||
shares: parts[5],
|
shares: parts[5],
|
||||||
score: parts.length >= 7 ? parts[6] : parts[5]
|
score: parts.length >= 7 ? parts[6] : parts[5],
|
||||||
|
mmClassification: parts.length >= 8 ? parts[7] : 'plain',
|
||||||
|
auxAccepted: parts.length >= 9 ? parts[8] : 0,
|
||||||
|
parentAccepted: parts.length >= 10 ? parts[9] : 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
callback(null, blocks);
|
callback(null, blocks);
|
||||||
@@ -159,7 +162,10 @@ function runInterval () {
|
|||||||
block.time,
|
block.time,
|
||||||
block.difficulty,
|
block.difficulty,
|
||||||
block.shares,
|
block.shares,
|
||||||
block.orphaned
|
block.orphaned,
|
||||||
|
block.mmClassification || 'plain',
|
||||||
|
block.auxAccepted || 0,
|
||||||
|
block.parentAccepted || 0
|
||||||
].join(':')]);
|
].join(':')]);
|
||||||
|
|
||||||
if (block.workerScores && !slushMiningEnabled) {
|
if (block.workerScores && !slushMiningEnabled) {
|
||||||
@@ -217,7 +223,10 @@ function runInterval () {
|
|||||||
block.difficulty,
|
block.difficulty,
|
||||||
block.shares,
|
block.shares,
|
||||||
block.orphaned,
|
block.orphaned,
|
||||||
block.reward
|
block.reward,
|
||||||
|
block.mmClassification || 'plain',
|
||||||
|
block.auxAccepted || 0,
|
||||||
|
block.parentAccepted || 0
|
||||||
].join(':')]);
|
].join(':')]);
|
||||||
|
|
||||||
let feePercent = (config.blockUnlocker.poolFee > 0 ? config.blockUnlocker.poolFee : 0) / 100;
|
let feePercent = (config.blockUnlocker.poolFee > 0 ? config.blockUnlocker.poolFee : 0) / 100;
|
||||||
|
|||||||
21
lib/pool.js
21
lib/pool.js
@@ -881,6 +881,20 @@ function recordShareData (miner, job, shareDiff, blockCandidate, hashHex, shareT
|
|||||||
let candidateHash = blockMeta && blockMeta.hash ? blockMeta.hash : hashHex;
|
let candidateHash = blockMeta && blockMeta.hash ? blockMeta.hash : hashHex;
|
||||||
let workerName = miner.workerName;
|
let workerName = miner.workerName;
|
||||||
let rewardType = miner.rewardType;
|
let rewardType = miner.rewardType;
|
||||||
|
let mmClassification = 'plain';
|
||||||
|
let auxAccepted = 0;
|
||||||
|
let parentAccepted = 0;
|
||||||
|
|
||||||
|
if (arguments.length >= 9 && arguments[8]) {
|
||||||
|
let submitResult = arguments[8];
|
||||||
|
auxAccepted = submitResult.aux_accepted ? 1 : 0;
|
||||||
|
parentAccepted = submitResult.parent_accepted ? 1 : 0;
|
||||||
|
if (auxAccepted && parentAccepted) {
|
||||||
|
mmClassification = 'dual-mm';
|
||||||
|
} else if (auxAccepted) {
|
||||||
|
mmClassification = 'aux-mm';
|
||||||
|
}
|
||||||
|
}
|
||||||
let updateScore;
|
let updateScore;
|
||||||
// Weighting older shares lower than newer ones to prevent pool hopping
|
// Weighting older shares lower than newer ones to prevent pool hopping
|
||||||
if (slushMiningEnabled) {
|
if (slushMiningEnabled) {
|
||||||
@@ -991,7 +1005,10 @@ function recordShareData (miner, job, shareDiff, blockCandidate, hashHex, shareT
|
|||||||
Date.now() / 1000 | 0,
|
Date.now() / 1000 | 0,
|
||||||
blockTemplate.difficulty,
|
blockTemplate.difficulty,
|
||||||
totalShares,
|
totalShares,
|
||||||
totalScore
|
totalScore,
|
||||||
|
mmClassification,
|
||||||
|
auxAccepted,
|
||||||
|
parentAccepted
|
||||||
].join(':'), function (err, result) {
|
].join(':'), function (err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
log('error', logSystem, 'Failed inserting block candidate %s \n %j', [candidateHash, err]);
|
log('error', logSystem, 'Failed inserting block candidate %s \n %j', [candidateHash, err]);
|
||||||
@@ -1103,7 +1120,7 @@ function processShare (miner, job, blockTemplate, params) {
|
|||||||
'Block %s found at height %d by miner %s@%s - submit result: %j',
|
'Block %s found at height %d by miner %s@%s - submit result: %j',
|
||||||
[blockFastHash.substr(0, 6), job.height, miner.login, miner.ip, result]
|
[blockFastHash.substr(0, 6), job.height, miner.login, miner.ip, result]
|
||||||
);
|
);
|
||||||
recordShareData(miner, job, hashDiff.toString(), true, blockFastHash, shareType, blockTemplate, acceptedBlockMeta);
|
recordShareData(miner, job, hashDiff.toString(), true, blockFastHash, shareType, blockTemplate, acceptedBlockMeta, result);
|
||||||
}
|
}
|
||||||
}, miningBackends.getMiningRpcConfig(), submitHeaders);
|
}, miningBackends.getMiningRpcConfig(), submitHeaders);
|
||||||
} else if (hashDiff < jobDifficulty) {
|
} else if (hashDiff < jobDifficulty) {
|
||||||
|
|||||||
Reference in New Issue
Block a user