Run pool through MM proxy with Salvium backend
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 37s

This commit is contained in:
Codex Bot
2026-03-21 20:00:18 +01:00
parent 4d43f4efb0
commit d8a3c32ff5
4 changed files with 127 additions and 40 deletions

View File

@@ -125,32 +125,60 @@
"solo": {
"enabled": true,
"type": "solo",
"coin": "Peya",
"symbol": "PEY",
"host": "127.0.0.1",
"port": 37777
"port": 37777,
"cnAlgorithm": "randomx",
"cnVariant": 0,
"cnBlobType": 15,
"includeHeight": true,
"isRandomX": true
},
"salvium": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "salvium",
"coin": "Salvium",
"symbol": "SAL",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "SC1T_PARENT_POOL_ADDRESS_HERE"
"walletAddress": "SC1T_PARENT_POOL_ADDRESS_HERE",
"cnAlgorithm": "randomx",
"cnVariant": 0,
"cnBlobType": 0,
"includeHeight": true,
"isRandomX": true
},
"monero": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "monero",
"coin": "Monero",
"symbol": "XMR",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "42_PARENT_POOL_ADDRESS_HERE"
"walletAddress": "42_PARENT_POOL_ADDRESS_HERE",
"cnAlgorithm": "randomx",
"cnVariant": 0,
"cnBlobType": 0,
"includeHeight": true,
"isRandomX": true
},
"zephyr": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "zephyr",
"coin": "Zephyr",
"symbol": "ZEPH",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "ZEPH_PARENT_POOL_ADDRESS_HERE"
"walletAddress": "ZEPH_PARENT_POOL_ADDRESS_HERE",
"cnAlgorithm": "randomx",
"cnVariant": 0,
"cnBlobType": 13,
"includeHeight": true,
"isRandomX": true
}
}
},

View File

@@ -2,10 +2,17 @@ function getLegacySoloBackend() {
return {
name: 'solo',
type: 'solo',
coin: config.coin,
symbol: config.symbol,
host: (config.miningSource && config.miningSource.host) || config.daemon.host,
port: (config.miningSource && config.miningSource.port) || config.daemon.port,
alwaysPoll: (config.miningSource && config.miningSource.alwaysPoll) || config.daemon.alwaysPoll || false,
walletAddress: null
walletAddress: null,
cnAlgorithm: config.cnAlgorithm || 'cryptonight',
cnVariant: config.cnVariant || 0,
cnBlobType: config.cnBlobType || 0,
includeHeight: typeof config.includeHeight !== 'undefined' ? config.includeHeight : false,
isRandomX: config.isRandomX || false
};
}
@@ -37,10 +44,17 @@ function normalizeBackend(name, backend) {
name: name,
type: backend.type || (name === 'solo' ? 'solo' : 'merge-mining'),
parentCoin: backend.parentCoin || null,
coin: backend.coin || config.coin,
symbol: backend.symbol || config.symbol,
host: backend.host,
port: backend.port,
alwaysPoll: backend.alwaysPoll || false,
walletAddress: backend.walletAddress || null
walletAddress: backend.walletAddress || null,
cnAlgorithm: backend.cnAlgorithm || config.cnAlgorithm || 'cryptonight',
cnVariant: typeof backend.cnVariant !== 'undefined' ? backend.cnVariant : (config.cnVariant || 0),
cnBlobType: typeof backend.cnBlobType !== 'undefined' ? backend.cnBlobType : (config.cnBlobType || 0),
includeHeight: typeof backend.includeHeight !== 'undefined' ? backend.includeHeight : (typeof config.includeHeight !== 'undefined' ? config.includeHeight : false),
isRandomX: typeof backend.isRandomX !== 'undefined' ? backend.isRandomX : (config.isRandomX || false)
};
}
@@ -85,3 +99,17 @@ function isSoloMiningBackend() {
return getActiveMiningBackend().type === 'solo';
}
exports.isSoloMiningBackend = isSoloMiningBackend;
function getActiveMiningParams() {
let backend = getActiveMiningBackend();
return {
coin: backend.coin,
symbol: backend.symbol,
cnAlgorithm: backend.cnAlgorithm,
cnVariant: backend.cnVariant,
cnBlobType: backend.cnBlobType,
includeHeight: backend.includeHeight,
isRandomX: backend.isRandomX
};
}
exports.getActiveMiningParams = getActiveMiningParams;

View File

@@ -16,6 +16,40 @@ let blockData = JSON.stringify({
require('./exceptionWriter.js')(logSystem);
function pollMiningTip(miningConfig, callback) {
apiInterfaces.jsonHttpRequest(miningConfig.host, miningConfig.port, blockData, function (err, res) {
if (err) {
callback(err);
return;
}
if (res && res.result && res.result.status === "OK" && res.result.hasOwnProperty('block_header')) {
callback(null, {
hash: res.result.block_header.hash,
height: res.result.block_header.height
});
return;
}
apiInterfaces.jsonHttpRequest(miningConfig.host, miningConfig.port, '', function (heightErr, heightRes) {
if (heightErr) {
callback(heightErr);
return;
}
if (heightRes && heightRes.status === 'OK' && heightRes.hash) {
callback(null, {
hash: heightRes.hash,
height: heightRes.height
});
return;
}
callback(new Error('bad response from mining source'));
}, '/get_height');
});
}
function runInterval () {
let miningConfig;
try {
@@ -28,29 +62,23 @@ function runInterval () {
async.waterfall([
function (callback) {
apiInterfaces.jsonHttpRequest(miningConfig.host, miningConfig.port, blockData, function (err, res) {
pollMiningTip(miningConfig, function (err, tip) {
if (err) {
log('error', logSystem, '%s error from mining source', [config.coin]);
setTimeout(runInterval, 3000);
return;
}
if (res && res.result && res.result.status === "OK" && res.result.hasOwnProperty('block_header')) {
let hash = res.result.block_header.hash.toString('hex');
if (!lastHash || lastHash !== hash) {
lastHash = hash;
log('info', logSystem, '%s found new hash %s via %s', [config.coin, hash, miningConfig.name]);
callback(null, true);
return;
} else if (miningConfig.alwaysPoll || config.daemon.alwaysPoll || false) {
callback(null, true);
return;
} else {
callback(true);
return;
}
let hash = tip.hash.toString('hex');
if (!lastHash || lastHash !== hash) {
lastHash = hash;
log('info', logSystem, '%s found new hash %s via %s at height %s', [miningConfig.coin || config.coin, hash, miningConfig.name, tip.height]);
callback(null, true);
return;
} else if (miningConfig.alwaysPoll || config.daemon.alwaysPoll || false) {
callback(null, true);
return;
} else {
log('error', logSystem, 'bad response from mining source');
setTimeout(runInterval, 3000);
callback(true);
return;
}
});

View File

@@ -36,10 +36,14 @@ let log = function (severity, system, text, data) {
global.log(severity, system, threadId + text, data);
};
function getMiningParams() {
return miningBackends.getActiveMiningParams();
}
// Set cryptonight algorithm
let cnAlgorithm = config.cnAlgorithm || "cryptonight";
let cnVariant = config.cnVariant || 0;
let cnBlobType = config.cnBlobType || 0;
let cnAlgorithm = getMiningParams().cnAlgorithm || "cryptonight";
let cnVariant = getMiningParams().cnVariant || 0;
let cnBlobType = getMiningParams().cnBlobType || 0;
let cryptoNight;
if (!cnHashing || !cnHashing[cnAlgorithm]) {
@@ -90,8 +94,6 @@ if (config.poolServer.paymentId.validations == null) {
config.poolServer.paymentId.validation = false;
}
config.isRandomX = config.isRandomX || false;
let previousOffset = config.previousOffset || 7;
let offset = config.offset || 2;
config.daemonType = config.daemonType || 'default';
@@ -197,7 +199,7 @@ process.on('message', function (message) {
buffer.copy(new_hash, 0, previousOffset, 39);
try {
if (!currentBlockTemplate[0] || new_hash.toString('hex') !== currentBlockTemplate[0].prev_hash.toString('hex') || (currentBlockTemplate[0].num_transactions == 0 && message.block.num_transactions > 0)) {
log('info', logSystem, 'New %s block to mine at height %d w/ difficulty of %d (%d transactions)', [config.coin, message.block.height, message.block.difficulty, (message.block.num_transactions || 0)]);
log('info', logSystem, 'New %s block to mine at height %d w/ difficulty of %d (%d transactions)', [miningBackends.getActiveMiningBackend().coin, message.block.height, message.block.difficulty, (message.block.num_transactions || 0)]);
processBlockTemplate(message.block);
return;
} else {
@@ -225,7 +227,7 @@ function BlockTemplate (template) {
this.blocktemplate_blob = template.blocktemplate_blob;
let blob = this.blocktemplate_blob;
this.buffer = Buffer.from(blob, 'hex');
this.isRandomX = config.isRandomX
this.isRandomX = getMiningParams().isRandomX;
if (this.isRandomX) {
this.seed_hash = template.seed_hash;
this.next_seed_hash = template.next_seed_hash;
@@ -255,7 +257,7 @@ function BlockTemplate (template) {
BlockTemplate.prototype = {
nextBlob: function () {
this.buffer.writeUInt32BE(++this.extraNonce, this.reserveOffset);
return utils.cnUtil.convert_blob(this.buffer, cnBlobType).toString('hex');
return utils.cnUtil.convert_blob(this.buffer, getMiningParams().cnBlobType).toString('hex');
},
nextBlobWithChildNonce: function () {
// Write a 32 bit integer, big-endian style to the 0 byte of the reserve offset.
@@ -468,7 +470,7 @@ Miner.prototype = {
if (typeof config.includeAlgo !== "undefined" && config.includeAlgo) {
this.cachedJob.algo = config.includeAlgo
}
if (typeof config.includeHeight !== "undefined" && config.includeHeight) {
if (getMiningParams().includeHeight) {
this.cachedJob.height = blockTemplate.height
}
@@ -987,7 +989,7 @@ function getShareBuffer (miner, job, blockTemplate, params) {
}
try {
let shareBuffer = utils.cnUtil.construct_block_blob(template, Buffer.from(nonce, 'hex'), cnBlobType);
let shareBuffer = utils.cnUtil.construct_block_blob(template, Buffer.from(nonce, 'hex'), getMiningParams().cnBlobType);
return shareBuffer;
} catch (e) {
log('error', logSystem, "Can't get share buffer with nonce %s from %s@%s: %s", [nonce, miner.login, miner.ip, e]);
@@ -1011,18 +1013,19 @@ function processShare (miner, job, blockTemplate, params) {
hash = Buffer.from(resultHash, 'hex');
shareType = 'trusted';
} else {
let convertedBlob = utils.cnUtil.convert_blob(shareBuffer, cnBlobType);
let miningParams = getMiningParams();
let convertedBlob = utils.cnUtil.convert_blob(shareBuffer, miningParams.cnBlobType);
let hard_fork_version = convertedBlob[0];
if (blockTemplate.isRandomX) {
hash = cryptoNight(convertedBlob, Buffer.from(blockTemplate.seed_hash, 'hex'), cnVariant);
hash = cryptoNight(convertedBlob, Buffer.from(blockTemplate.seed_hash, 'hex'), miningParams.cnVariant);
} else {
if (typeof config.includeHeight !== "undefined" && config.includeHeight)
hash = cryptoNight(convertedBlob, cnVariant, job.height);
if (miningParams.includeHeight)
hash = cryptoNight(convertedBlob, miningParams.cnVariant, job.height);
else
hash = cryptoNight(convertedBlob, cnVariant);
hash = cryptoNight(convertedBlob, miningParams.cnVariant);
}
log('info', logSystem, 'Mining pool algorithm: %s variant %d, Hard fork version: %d', [cnAlgorithm, cnVariant, hard_fork_version]);
log('info', logSystem, 'Mining pool algorithm: %s variant %d, Hard fork version: %d', [miningParams.cnAlgorithm, miningParams.cnVariant, hard_fork_version]);
shareType = 'valid'
}
@@ -1042,7 +1045,7 @@ function processShare (miner, job, blockTemplate, params) {
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]);
} else {
let blockFastHash = utils.cnUtil.get_block_id(shareBuffer, cnBlobType).toString('hex');
let blockFastHash = utils.cnUtil.get_block_id(shareBuffer, getMiningParams().cnBlobType).toString('hex');
log('info', logSystem,
'Block %s found at height %d by miner %s@%s - submit result: %j',
[blockFastHash.substr(0, 6), job.height, miner.login, miner.ip, result]