Harden MM pool flow and frontend guards
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 1m3s

This commit is contained in:
Codex Bot
2026-03-22 17:23:38 +01:00
parent 38a8187c07
commit 4207f95790
5 changed files with 62 additions and 27 deletions

View File

@@ -3,8 +3,8 @@
"coin": "Peya", "coin": "Peya",
"symbol": "PEY", "symbol": "PEY",
"coinUnits": 1000000000000, "coinUnits": 100000000,
"coinDecimalPlaces": 12, "coinDecimalPlaces": 8,
"coinDifficultyTarget": 120, "coinDifficultyTarget": 120,
"daemonType": "default", "daemonType": "default",

View File

@@ -9,19 +9,20 @@
var http = require('http'); var http = require('http');
var https = require('https'); var https = require('https');
function jsonHttpRequest (host, port, data, callback, path) { function jsonHttpRequest (host, port, data, callback, path, extraHeaders) {
path = path || '/json_rpc'; path = path || '/json_rpc';
callback = callback || function () {}; callback = callback || function () {};
extraHeaders = extraHeaders || {};
var options = { var options = {
hostname: host, hostname: host,
port: port, port: port,
path: path, path: path,
method: data ? 'POST' : 'GET', method: data ? 'POST' : 'GET',
headers: { headers: Object.assign({
'Content-Length': data.length, 'Content-Length': data.length,
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Accept': 'application/json' 'Accept': 'application/json'
} }, extraHeaders)
}; };
var req = (port === 443 ? https : http) var req = (port === 443 ? https : http)
.request(options, function (res) { .request(options, function (res) {
@@ -51,7 +52,7 @@ function jsonHttpRequest (host, port, data, callback, path) {
/** /**
* Send RPC request * Send RPC request
**/ **/
function rpc (host, port, method, params, callback) { function rpc (host, port, method, params, callback, extraHeaders) {
var data = JSON.stringify({ var data = JSON.stringify({
id: "0", id: "0",
jsonrpc: "2.0", jsonrpc: "2.0",
@@ -64,7 +65,7 @@ function rpc (host, port, method, params, callback) {
return; return;
} }
callback(replyJson.error, replyJson.result); callback(replyJson.error, replyJson.result);
}); }, '/json_rpc', extraHeaders);
} }
/** /**
@@ -99,11 +100,11 @@ module.exports = function (daemonConfig, walletConfig, poolApiConfig) {
batchRpcDaemon: function (batchArray, callback) { batchRpcDaemon: function (batchArray, callback) {
batchRpc(daemonConfig.host, daemonConfig.port, batchArray, callback); batchRpc(daemonConfig.host, daemonConfig.port, batchArray, callback);
}, },
rpcDaemon: function (method, params, callback, serverConfig) { rpcDaemon: function (method, params, callback, serverConfig, extraHeaders) {
if (serverConfig) { if (serverConfig) {
rpc(serverConfig.host, serverConfig.port, method, params, callback); rpc(serverConfig.host, serverConfig.port, method, params, callback, extraHeaders);
} else { } else {
rpc(daemonConfig.host, daemonConfig.port, method, params, callback); rpc(daemonConfig.host, daemonConfig.port, method, params, callback, extraHeaders);
} }
}, },
rpcWallet: function (method, params, callback) { rpcWallet: function (method, params, callback) {

View File

@@ -366,6 +366,7 @@ function getPoolChartsData (callback) {
**/ **/
function getUserChartsData (address, paymentsData, callback) { function getUserChartsData (address, paymentsData, callback) {
let stats = {}; let stats = {};
let userChartsConfig = config.charts && config.charts.user ? config.charts.user : {};
let chartsFuncs = { let chartsFuncs = {
hashrate: function (callback) { hashrate: function (callback) {
getUserHashrateChartData(address, function (data) { getUserHashrateChartData(address, function (data) {
@@ -378,7 +379,8 @@ function getUserChartsData (address, paymentsData, callback) {
} }
}; };
for (let chartName in chartsFuncs) { for (let chartName in chartsFuncs) {
if (!config.charts.user[chartName].enabled) { let chartConfig = userChartsConfig[chartName];
if (chartConfig && chartConfig.enabled === false) {
delete chartsFuncs[chartName]; delete chartsFuncs[chartName];
} }
} }

View File

@@ -864,12 +864,13 @@ function IsBannedIp (ip) {
} }
} }
function recordShareData (miner, job, shareDiff, blockCandidate, hashHex, shareType, blockTemplate) { function recordShareData (miner, job, shareDiff, blockCandidate, hashHex, shareType, blockTemplate, blockMeta) {
let dateNow = Date.now(); let dateNow = Date.now();
let dateNowSeconds = dateNow / 1000 | 0; let dateNowSeconds = dateNow / 1000 | 0;
let coin = config.coin; let coin = config.coin;
let login = miner.login; let login = miner.login;
let job_height = job.height; let job_height = blockMeta && blockMeta.height ? blockMeta.height : job.height;
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 updateScore; let updateScore;
@@ -960,23 +961,39 @@ function recordShareData (miner, job, shareDiff, blockCandidate, hashHex, shareT
return p + parseInt(workerShares[c]) return p + parseInt(workerShares[c])
}, 0); }, 0);
} }
redisClient.zadd(coin + ':blocks:candidates', job_height, [ redisClient.zrangebyscore(coin + ':blocks:candidates', job_height, job_height, function (err, existingCandidates) {
rewardType,
login,
hashHex,
Date.now() / 1000 | 0,
blockTemplate.difficulty,
totalShares,
totalScore
].join(':'), function (err, result) {
if (err) { if (err) {
log('error', logSystem, 'Failed inserting block candidate %s \n %j', [hashHex, err]); log('error', logSystem, 'Failed loading existing block candidates for height %d before inserting %s \n %j', [job_height, candidateHash, err]);
return;
} }
let duplicateCandidate = existingCandidates.some(function (candidate) {
let parts = candidate.split(':');
return parts.length >= 3 && parts[2] === candidateHash;
});
if (duplicateCandidate) {
return;
}
redisClient.zadd(coin + ':blocks:candidates', job_height, [
rewardType,
login,
candidateHash,
Date.now() / 1000 | 0,
blockTemplate.difficulty,
totalShares,
totalScore
].join(':'), function (err, result) {
if (err) {
log('error', logSystem, 'Failed inserting block candidate %s \n %j', [candidateHash, err]);
}
});
}); });
notifications.sendToAll('blockFound', { notifications.sendToAll('blockFound', {
'HEIGHT': job_height, 'HEIGHT': job_height,
'HASH': hashHex, 'HASH': candidateHash,
'DIFFICULTY': blockTemplate.difficulty, 'DIFFICULTY': blockTemplate.difficulty,
'SHARES': totalShares, 'SHARES': totalShares,
'MINER': login.substring(0, 7) + '...' + login.substring(login.length - 7) 'MINER': login.substring(0, 7) + '...' + login.substring(login.length - 7)
@@ -1054,19 +1071,33 @@ function processShare (miner, job, blockTemplate, params) {
let jobDifficulty = BigInt(job.difficulty); let jobDifficulty = BigInt(job.difficulty);
if (hashDiff >= blockDifficulty) { if (hashDiff >= blockDifficulty) {
let submitHeaders = {
'X-Hash-Difficulty': hashDiff.toString()
};
apiInterfaces.rpcDaemon('submitblock', [shareBuffer.toString('hex')], function (error, result) { apiInterfaces.rpcDaemon('submitblock', [shareBuffer.toString('hex')], function (error, result) {
if (error) { if (error) {
log('error', logSystem, 'Error submitting block at height %d from %s@%s, share type: "%s" - %j', [job.height, miner.login, miner.ip, shareType, error]); log('error', logSystem, 'Error submitting block at height %d from %s@%s, share type: "%s" - %j', [job.height, miner.login, miner.ip, shareType, error]);
} else { } else {
let blockFastHash = utils.cnUtil.get_block_id(shareBuffer, getMiningParams().cnBlobType).toString('hex'); let blockFastHash = utils.cnUtil.get_block_id(shareBuffer, getMiningParams().cnBlobType).toString('hex');
let acceptedBlockMeta = null;
if (result && result.aux_accepted && result.aux_height && result.aux_block_id) {
acceptedBlockMeta = {
height: result.aux_height,
hash: result.aux_block_id
};
} else if (result && result.block_id) {
acceptedBlockMeta = {
height: job.height,
hash: result.block_id
};
}
log('info', logSystem, log('info', logSystem,
'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); recordShareData(miner, job, hashDiff.toString(), true, blockFastHash, shareType, blockTemplate, acceptedBlockMeta);
} }
}, miningBackends.getMiningRpcConfig()); }, miningBackends.getMiningRpcConfig(), submitHeaders);
} else if (hashDiff < jobDifficulty) { } else if (hashDiff < jobDifficulty) {
log('warn', logSystem, 'Rejected low difficulty share of %s from %s@%s', [hashDiff.toString(), miner.login, miner.ip]); log('warn', logSystem, 'Rejected low difficulty share of %s from %s@%s', [hashDiff.toString(), miner.login, miner.ip]);
return false; return false;

View File

@@ -219,6 +219,7 @@ function fetchLiveStats(endPoint, key) {
// Fetch Block and Transaction Explorer Urls // Fetch Block and Transaction Explorer Urls
let xhrBlockExplorers; let xhrBlockExplorers;
let xhrMergedApis;
function fetchBlockExplorers() { function fetchBlockExplorers() {
let apiURL = api + '/block_explorers'; let apiURL = api + '/block_explorers';