Expose merge-mining block classifications
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 41s

This commit is contained in:
Codex Bot
2026-03-24 01:59:54 +01:00
parent aa404d185e
commit 06f9ba1c9f
3 changed files with 116 additions and 5 deletions

View File

@@ -79,6 +79,9 @@ function handleServerRequest (request, response) {
case '/get_blocks':
handleGetBlocks(urlParts, response);
break;
case '/get_mm_blocks':
handleGetMergeMiningBlocks(urlParts, response);
break;
// Get market prices
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
**/

View File

@@ -53,7 +53,10 @@ function runInterval () {
time: parts[3],
difficulty: parts[4],
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);
@@ -159,7 +162,10 @@ function runInterval () {
block.time,
block.difficulty,
block.shares,
block.orphaned
block.orphaned,
block.mmClassification || 'plain',
block.auxAccepted || 0,
block.parentAccepted || 0
].join(':')]);
if (block.workerScores && !slushMiningEnabled) {
@@ -217,7 +223,10 @@ function runInterval () {
block.difficulty,
block.shares,
block.orphaned,
block.reward
block.reward,
block.mmClassification || 'plain',
block.auxAccepted || 0,
block.parentAccepted || 0
].join(':')]);
let feePercent = (config.blockUnlocker.poolFee > 0 ? config.blockUnlocker.poolFee : 0) / 100;

View File

@@ -881,6 +881,20 @@ function recordShareData (miner, job, shareDiff, blockCandidate, hashHex, shareT
let candidateHash = blockMeta && blockMeta.hash ? blockMeta.hash : hashHex;
let workerName = miner.workerName;
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;
// Weighting older shares lower than newer ones to prevent pool hopping
if (slushMiningEnabled) {
@@ -991,7 +1005,10 @@ function recordShareData (miner, job, shareDiff, blockCandidate, hashHex, shareT
Date.now() / 1000 | 0,
blockTemplate.difficulty,
totalShares,
totalScore
totalScore,
mmClassification,
auxAccepted,
parentAccepted
].join(':'), function (err, result) {
if (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',
[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);
} else if (hashDiff < jobDifficulty) {