Harden MM pool flow and frontend guards
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 1m3s
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 1m3s
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
63
lib/pool.js
63
lib/pool.js
@@ -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;
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user