Add selectable solo and MM mining backends
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 36s

This commit is contained in:
Codex Bot
2026-03-21 19:43:12 +01:00
parent cc1c288f52
commit 4d43f4efb0
7 changed files with 246 additions and 5 deletions

View File

@@ -150,6 +150,42 @@
"trustProxyIP": true
},
"mining": {
"active": "solo",
"backends": {
"solo": {
"enabled": true,
"type": "solo",
"host": "127.0.0.1",
"port": 18081
},
"salvium": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "salvium",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "SC1T_PARENT_POOL_ADDRESS_HERE"
},
"monero": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "monero",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "42_PARENT_POOL_ADDRESS_HERE"
},
"zephyr": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "zephyr",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "ZEPH_PARENT_POOL_ADDRESS_HERE"
}
}
},
"miningSource": {
"host": "127.0.0.1",
"port": 18081

View File

@@ -119,6 +119,42 @@
"trustProxyIP": true
},
"mining": {
"active": "solo",
"backends": {
"solo": {
"enabled": true,
"type": "solo",
"host": "127.0.0.1",
"port": 37777
},
"salvium": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "salvium",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "SC1T_PARENT_POOL_ADDRESS_HERE"
},
"monero": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "monero",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "42_PARENT_POOL_ADDRESS_HERE"
},
"zephyr": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "zephyr",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "ZEPH_PARENT_POOL_ADDRESS_HERE"
}
}
},
"miningSource": {
"host": "127.0.0.1",
"port": 37777

View File

@@ -145,6 +145,42 @@
"trustProxyIP": true
},
"mining": {
"active": "solo",
"backends": {
"solo": {
"enabled": true,
"type": "solo",
"host": "127.0.0.1",
"port": 11812
},
"salvium": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "salvium",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "SC1T_PARENT_POOL_ADDRESS_HERE"
},
"monero": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "monero",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "42_PARENT_POOL_ADDRESS_HERE"
},
"zephyr": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "zephyr",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "ZEPH_PARENT_POOL_ADDRESS_HERE"
}
}
},
"miningSource": {
"host": "127.0.0.1",
"port": 11812

View File

@@ -111,6 +111,42 @@
"trustProxyIP": true
},
"mining": {
"active": "solo",
"backends": {
"solo": {
"enabled": true,
"type": "solo",
"host": "127.0.0.1",
"port": 17767
},
"salvium": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "salvium",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "SC1T_PARENT_POOL_ADDRESS_HERE"
},
"monero": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "monero",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "42_PARENT_POOL_ADDRESS_HERE"
},
"zephyr": {
"enabled": false,
"type": "merge-mining",
"parentCoin": "zephyr",
"host": "127.0.0.1",
"port": 37777,
"walletAddress": "ZEPH_PARENT_POOL_ADDRESS_HERE"
}
}
},
"miningSource": {
"host": "127.0.0.1",
"port": 17767

87
lib/miningBackends.js Normal file
View File

@@ -0,0 +1,87 @@
function getLegacySoloBackend() {
return {
name: 'solo',
type: 'solo',
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
};
}
function getConfiguredBackends() {
if (!config.mining || !config.mining.backends) {
return null;
}
return config.mining.backends;
}
function getActiveBackendName(backends) {
if (config.mining && config.mining.active) {
return config.mining.active;
}
let enabled = Object.keys(backends).filter(function (name) {
return backends[name] && backends[name].enabled;
});
if (enabled.length === 0) {
throw new Error('No enabled mining backend configured');
}
return enabled[0];
}
function normalizeBackend(name, backend) {
return {
name: name,
type: backend.type || (name === 'solo' ? 'solo' : 'merge-mining'),
parentCoin: backend.parentCoin || null,
host: backend.host,
port: backend.port,
alwaysPoll: backend.alwaysPoll || false,
walletAddress: backend.walletAddress || null
};
}
function getActiveMiningBackend() {
let backends = getConfiguredBackends();
if (!backends) {
return getLegacySoloBackend();
}
let activeName = getActiveBackendName(backends);
let backend = backends[activeName];
if (!backend) {
throw new Error('Active mining backend "' + activeName + '" is not defined');
}
if (!backend.enabled) {
throw new Error('Active mining backend "' + activeName + '" is disabled');
}
if (!backend.host || !backend.port) {
throw new Error('Active mining backend "' + activeName + '" is missing host/port');
}
return normalizeBackend(activeName, backend);
}
exports.getActiveMiningBackend = getActiveMiningBackend;
function getMiningRpcConfig() {
let backend = getActiveMiningBackend();
return {
host: backend.host,
port: backend.port
};
}
exports.getMiningRpcConfig = getMiningRpcConfig;
function getMiningTemplateAddress(defaultAddress) {
let backend = getActiveMiningBackend();
return backend.walletAddress || defaultAddress;
}
exports.getMiningTemplateAddress = getMiningTemplateAddress;
function isSoloMiningBackend() {
return getActiveMiningBackend().type === 'solo';
}
exports.isSoloMiningBackend = isSoloMiningBackend;

View File

@@ -1,10 +1,10 @@
let utils = require('./utils.js');
let async = require('async');
let apiInterfaces = require('./apiInterfaces.js')(config.daemon, config.wallet, config.api);
let miningBackends = require('./miningBackends.js');
let lastHash;
let POOL_NONCE_SIZE = 16 + 1; // +1 for old XMR/new TRTL bugs
let miningConfig = config.miningSource || config.daemon;
let logSystem = 'miningSource';
let blockData = JSON.stringify({
@@ -17,6 +17,15 @@ let blockData = JSON.stringify({
require('./exceptionWriter.js')(logSystem);
function runInterval () {
let miningConfig;
try {
miningConfig = miningBackends.getActiveMiningBackend();
} catch (e) {
log('error', logSystem, 'Invalid mining backend configuration: %s', [e.message]);
setTimeout(runInterval, 3000);
return;
}
async.waterfall([
function (callback) {
apiInterfaces.jsonHttpRequest(miningConfig.host, miningConfig.port, blockData, function (err, res) {
@@ -29,7 +38,7 @@ function runInterval () {
let hash = res.result.block_header.hash.toString('hex');
if (!lastHash || lastHash !== hash) {
lastHash = hash;
log('info', logSystem, '%s found new hash %s', [config.coin, 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) {
@@ -53,7 +62,7 @@ function runInterval () {
method: 'getblocktemplate',
params: {
reserve_size: POOL_NONCE_SIZE,
wallet_address: utils.getPoolTemplateAddress()
wallet_address: miningBackends.getMiningTemplateAddress(utils.getPoolTemplateAddress())
}
});
apiInterfaces.jsonHttpRequest(miningConfig.host, miningConfig.port, templateData, function (err, res) {

View File

@@ -14,6 +14,7 @@ let async = require('async');
let apiInterfaces = require('./apiInterfaces.js')(config.daemon, config.wallet, config.api);
let notifications = require('./notifications.js');
let utils = require('./utils.js');
let miningBackends = require('./miningBackends.js');
config.hashingUtil = config.hashingUtil || false;
let cnHashing = require('cryptonight-hashing');
@@ -420,7 +421,7 @@ Miner.prototype = {
height: blockTemplate.height,
submissions: []
};
if (this.lastBlockHeight === blockTemplate.height && !this.pendingDifficulty && this.cachedJob !== null && !config.daemon.alwaysPoll) {
if (this.lastBlockHeight === blockTemplate.height && !this.pendingDifficulty && this.cachedJob !== null && !miningBackends.getActiveMiningBackend().alwaysPoll) {
return this.cachedJob;
}
let blob = this.proxy ? blockTemplate.nextBlobWithChildNonce() : blockTemplate.nextBlob();
@@ -1048,7 +1049,7 @@ function processShare (miner, job, blockTemplate, params) {
);
recordShareData(miner, job, hashDiff.toString(), true, blockFastHash, shareType, blockTemplate);
}
});
}, miningBackends.getMiningRpcConfig());
} else if (hashDiff < jobDifficulty) {
log('warn', logSystem, 'Rejected low difficulty share of %s from %s@%s', [hashDiff.toString(), miner.login, miner.ip]);
return false;