diff --git a/Example_MergeMining.json b/Example_MergeMining.json deleted file mode 100644 index 74777c4..0000000 --- a/Example_MergeMining.json +++ /dev/null @@ -1,419 +0,0 @@ -{ - "poolHost": "your.pool.host", - "coin": "Arqma", - "symbol": "ARQ", - "coinUnits": 1000000000, - "coinDecimalPlaces": 9, - "coinDifficultyTarget": 120, - "blockchainExplorer": "http://blockexplorer.arqma.com/block/{id}", - "transactionExplorer": "http://blockexplorer.arqma.com/tx/{id}", - "includeHeight": false, - "includeAlgo": null, - "isRandomX": false, - "daemonType": "default", - "cnAlgorithm": "cryptonight_pico", - "cnVariant": 2, - "cnBlobType": 0, - - "logging": { - "files": { - "level": "info", - "directory": "logs", - "flushInterval": 5 - }, - "console": { - "level": "info", - "colors": true - } - }, - "childPools": [{ - "poolAddress": "** Your pool wallet address **", - "pubAddressPrefix": null, - "intAddressPrefix": null, - "subAddressPrefix": null, - "coin": "CyprusCoin", - "childDaemon": { - "host": "1.2.3.4", - "port": 11975 - }, - "pattern": "^XCY", - "blockchainExplorer": "http://explorer.mycypruscoin.com/?hash={id}#blockchain_block", - "transactionExplorer": "http://explorer.mycypruscoin.com/?hash={id}#blockchain_transaction", - "api": "https://your.pool.host/apiMerged1", - "enabled": true - }, - { - "poolAddress": "** Your pool wallet address **", - "pubAddressPrefix": null, - "intAddressPrefix": null, - "subAddressPrefix": null, - "coin": "Turtlecoin", - "childDaemon": { - "host": "1.2.3.4", - "port": 11898 - }, - "pattern": "^TRTL", - "blockchainExplorer": "https://explorer.turtlecoin.lol/block.html?hash={id}", - "transactionExplorer": "https://explorer.turtlecoin.lol/block.html?hash={id}", - "api": "https://your.pool.host/apiMerged2", - "enabled": true - }, - { - "poolAddress": "** Your pool wallet address **", - "pubAddressPrefix": null, - "intAddressPrefix": null, - "subAddressPrefix": null, - "coin": "Plenteum", - "childDaemon": { - "host": "1.2.3.4", - "port": 44016 - }, - "pattern": "^Pl", - "blockchainExplorer": "http://block-explorer.plenteum.com/?hash={id}#blockchain_block", - "transactionExplorer": "http://block-explorer.plenteum.com/?hash={id}#blockchain_transaction", - "api": "https://your.pool.host/apiMerged3", - "enabled": true - }, - { - "poolAddress": "** Your pool wallet address **", - "pubAddressPrefix": null, - "intAddressPrefix": null, - "subAddressPrefix": null, - "coin": "Iridium", - "childDaemon": { - "host": "1.2.3.4", - "port": 13007 - }, - "pattern": "^ir", - "blockchainExplorer": "http://explorer.ird.cash/?hash={id}#block", - "transactionExplorer": "http://explorer.ird.cash/?hash={id}#transaction", - "api": "https://your.pool.host/apiMerged4", - "enabled": true - }, - { - "poolAddress": "** Your pool wallet address **", - "pubAddressPrefix": null, - "intAddressPrefix": null, - "subAddressPrefix": null, - "coin": "Tritanium", - "childDaemon": { - "host": "1.2.3.4", - "port": 16123 - }, - "pattern": "^Tri", - "blockchainExplorer": "http://www.tritaniumcoin.com/?hash={id}#blockchain_block", - "transactionExplorer": "http://www.tritaniumcoin.com/?hash={id}#blockchain_transaction", - "api": "https://your.pool.host/apiMerged5", - "enabled": true - }, - { - "poolAddress": "** Your pool wallet address **", - "pubAddressPrefix": null, - "intAddressPrefix": null, - "subAddressPrefix": null, - "coin": "WrkzCoin", - "childDaemon": { - "host": "1.2.3.4", - "port": 17856 - }, - "pattern": "^Wrkz", - "blockchainExplorer": "http://myexplorer.wrkz.work/?hash={id}#blockchain_block", - "transactionExplorer": "http://myexplorer.wrkz.work/?hash={id}#blockchain_transaction", - "api": "https://your.pool.host/apiMerged6", - "enabled": true - }, - { - "poolAddress": "** Your pool wallet address **", - "pubAddressPrefix": null, - "intAddressPrefix": null, - "subAddressPrefix": null, - "coin": "Elphyrecoin2", - "childDaemon": { - "host": "1.2.3.4", - "port": 45501 - }, - "pattern": "^Phy", - "blockchainExplorer": "http://explorer2.elphyrecoin.xyz/?hash={id}#blockchain_block", - "transactionExplorer": "http://explorer2.elphyrecoin.xyz/?hash={id}#blockchain_transaction", - "api": "https://your.pool.host/apiMerged7", - "enabled": true - } - ], - "poolServer": { - "enabled": true, - "mergedMining": true, - "clusterForks": 5, - "poolAddress": "** Your pool wallet address **", - "pubAddressPrefix": null, - "intAddressPrefix": 1141703, - "subAddressPrefix": null, - "blockRefreshInterval": 1000, - "minerTimeout": 900, - "sslCert": "cert.pem", - "sslKey": "privkey.pem", - "sslCA": "chain.pem", - "ports": [ - { - "port": 1444, - "difficulty": 5000, - "desc": "Low end hardware" - }, - { - "port": 2444, - "difficulty": 50000, - "desc": "Mid range hardware" - }, - { - "port": 3444, - "difficulty": 500000, - "desc": "High end hardware" - } - ], - "varDiff": { - "minDiff": 500, - "maxDiff": 100000000, - "targetTime": 45, - "retargetTime": 40, - "variancePercent": 30, - "maxJump": 60 - }, - "paymentId": { - "addressSeparator": "+" - }, - "fixedDiff": { - "enabled": true, - "addressSeparator": "." - }, - "shareTrust": { - "enabled": true, - "min": 10, - "stepDown": 3, - "threshold": 10, - "penalty": 30 - }, - "banning": { - "enabled": true, - "time": 600, - "invalidPercent": 25, - "checkThreshold": 30 - }, - "slushMining": { - "enabled": false, - "weight": 300, - "blockTime": 60, - "lastBlockCheckRate": 1 - } - }, - - "payments": { - "enabled": true, - "interval": 900, - "maxAddresses": 5, - "mixin": 6, - "priority": 0, - "transferFee": 10000000, - "dynamicTransferFee": true, - "minerPayFee": true, - "minPayment": 1000000000, - "maxPayment": null, - "maxTransactionAmount": 100000000000, - "denomination": 1000000000 - }, - - "blockUnlocker": { - "enabled": true, - "interval": 30, - "depth": 18, - "poolFee": 0.5, - "devDonation": 0, - "networkFee": 0.0 - }, - - "api": { - "enabled": true, - "hashrateWindow": 600, - "updateInterval": 60, - "bindIp": "127.0.0.1", - "port": 8217, - "blocks": 30, - "payments": 30, - "password": "password", - "ssl": false, - "sslPort": 8119, - "sslCert": "cert.pem", - "sslKey": "privkey.pem", - "sslCA": "chain.pem", - "trustProxyIP": true - }, - - "daemon": { - "host": "127.0.0.1", - "port": 19994 - }, - - "wallet": { - "host": "1.2.3.4", - "port": 19996 - }, - - "redis": { - "host": "1.2.3.4", - "port": 6379, - "auth": null, - "db": 10, - "cleanupInterval": 15 - }, - - "notifications": { - "emailTemplate": "email_templates/default.txt", - "emailSubject": { - "emailAdded": "Your email was registered", - "workerConnected": "Worker %WORKER_NAME% connected", - "workerTimeout": "Worker %WORKER_NAME% stopped hashing", - "workerBanned": "Worker %WORKER_NAME% banned", - "blockFound": "Block %HEIGHT% found !", - "blockUnlocked": "Block %HEIGHT% unlocked !", - "blockOrphaned": "Block %HEIGHT% orphaned !", - "payment": "We sent you a payment !" - }, - "emailMessage": { - "emailAdded": "Your email has been registered to receive pool notifications.", - "workerConnected": "Your worker %WORKER_NAME% for address %MINER% is now connected from ip %IP%.", - "workerTimeout": "Your worker %WORKER_NAME% for address %MINER% has stopped submitting hashes on %LAST_HASH%.", - "workerBanned": "Your worker %WORKER_NAME% for address %MINER% has been banned.", - "blockFound": "Block found at height %HEIGHT% by miner %MINER% on %TIME%. Waiting maturity.", - "blockUnlocked": "Block mined at height %HEIGHT% with %REWARD% and %EFFORT% effort on %TIME%.", - "blockOrphaned": "Block orphaned at height %HEIGHT% :(", - "payment": "A payment of %AMOUNT% has been sent to %ADDRESS% wallet." - }, - "telegramMessage": { - "workerConnected": "Your worker _%WORKER_NAME%_ for address _%MINER%_ is now connected from ip _%IP%_.", - "workerTimeout": "Your worker _%WORKER_NAME%_ for address _%MINER%_ has stopped submitting hashes on _%LAST_HASH%_.", - "workerBanned": "Your worker _%WORKER_NAME%_ for address _%MINER%_ has been banned.", - "blockFound": "*Block found at height* _%HEIGHT%_ *by miner* _%MINER%_*! Waiting maturity.*", - "blockUnlocked": "*Block mined at height* _%HEIGHT%_ *with* _%REWARD%_ *and* _%EFFORT%_ *effort on* _%TIME%_*.*", - "blockOrphaned": "*Block orphaned at height* _%HEIGHT%_ *:(*", - "payment": "A payment of _%AMOUNT%_ has been sent." - } - }, - - "email": { - "enabled": false, - "fromAddress": "your@email.com", - "transport": "sendmail", - "sendmail": { - "path": "/usr/sbin/sendmail" - }, - "smtp": { - "host": "smtp.example.com", - "port": 587, - "secure": false, - "auth": { - "user": "username", - "pass": "password" - }, - "tls": { - "rejectUnauthorized": false - } - }, - "mailgun": { - "key": "your-private-key", - "domain": "mg.yourdomain" - } - }, - - "telegram": { - "enabled": false, - "botName": "", - "token": "", - "channel": "", - "channelStats": { - "enabled": false, - "interval": 30 - }, - "botCommands": { - "stats": "/stats", - "report": "/report", - "notify": "/notify", - "blocks": "/blocks" - } - }, - - "monitoring": { - "daemon": { - "checkInterval": 60, - "rpcMethod": "getblockcount" - }, - "wallet": { - "checkInterval": 60, - "rpcMethod": "getbalance" - } - }, - - "prices": { - "source": "tradeogre", - "currency": "USD" - }, - - "charts": { - "pool": { - "hashrate": { - "enabled": true, - "updateInterval": 60, - "stepInterval": 1800, - "maximumPeriod": 86400 - }, - "miners": { - "enabled": true, - "updateInterval": 60, - "stepInterval": 1800, - "maximumPeriod": 86400 - }, - "workers": { - "enabled": true, - "updateInterval": 60, - "stepInterval": 1800, - "maximumPeriod": 86400 - }, - "difficulty": { - "enabled": true, - "updateInterval": 1800, - "stepInterval": 10800, - "maximumPeriod": 604800 - }, - "price": { - "enabled": true, - "updateInterval": 1800, - "stepInterval": 10800, - "maximumPeriod": 604800 - }, - "profit": { - "enabled": true, - "updateInterval": 1800, - "stepInterval": 10800, - "maximumPeriod": 604800 - } - }, - "user": { - "hashrate": { - "enabled": true, - "updateInterval": 180, - "stepInterval": 1800, - "maximumPeriod": 86400 - }, - "worker_hashrate": { - "enabled": true, - "updateInterval": 60, - "stepInterval": 60, - "maximumPeriod": 86400 - }, - "payments": { - "enabled": true - } - }, - "blocks": { - "enabled": true, - "days": 30 - } - } -} diff --git a/README.md b/README.md index 124670c..390cdc6 100644 --- a/README.md +++ b/README.md @@ -31,4 +31,4 @@ Notes: - `Peya` and `Salvium` are treated as current-carrot chains. - `Zephyr` solo validation was done on the local fastfork testnet harness. - `Monero` solo validation was done on local `regtest`. -- merge mining will be built as the next product layer on top of this repo, but the architecture will diverge from the legacy generic pool model. +- merge mining will be built as a separate product layer on top of this repo; legacy child-pool merge-mining code is being removed from this baseline. diff --git a/config_examples/monero.json b/config_examples/monero.json index 52ed6e2..fa8497e 100644 --- a/config_examples/monero.json +++ b/config_examples/monero.json @@ -26,10 +26,8 @@ "colors": true } }, - "childPools": null, "poolServer": { "enabled": true, - "mergedMining": false, "clusterForks": "auto", "poolAddress": "** Your pool wallet address **", "intAddressPrefix": 19, diff --git a/config_examples/peya.json b/config_examples/peya.json index 610da44..8a1e3c8 100644 --- a/config_examples/peya.json +++ b/config_examples/peya.json @@ -39,10 +39,8 @@ } }, - "childPools": null, "poolServer": { "enabled": true, - "mergedMining": false, "clusterForks": "auto", "poolAddress": "PtYa_YOUR_POOL_CARROT_ADDRESS_HERE", "intAddressPrefix": null, diff --git a/config_examples/salvium.json b/config_examples/salvium.json index 81bd9ff..5dae720 100644 --- a/config_examples/salvium.json +++ b/config_examples/salvium.json @@ -55,10 +55,8 @@ "carrotDonationAddress": "SC1_YOUR_DONATION_CARROT_ADDRESS_HERE" }, - "childPools": null, "poolServer": { "enabled": true, - "mergedMining": false, "clusterForks": "auto", "poolAddress": "SaLv_YOUR_POOL_CRYPTONOTE_ADDRESS_HERE", "intAddressPrefix": null, diff --git a/config_examples/zephyr.json b/config_examples/zephyr.json index a396597..8e1be38 100644 --- a/config_examples/zephyr.json +++ b/config_examples/zephyr.json @@ -28,10 +28,8 @@ } }, - "childPools": null, "poolServer": { "enabled": true, - "mergedMining": false, "clusterForks": "auto", "poolAddress": "ZPHT_YOUR_POOL_ADDRESS_HERE", "intAddressPrefix": 19, diff --git a/init.js b/init.js index d04f27e..163f4f0 100644 --- a/init.js +++ b/init.js @@ -39,11 +39,6 @@ auth_pass: config.redis.auth }); - if ((typeof config.poolServer.mergedMining !== 'undefined' && config.poolServer.mergedMining) && typeof config.childPools !== 'undefined') - config.childPools = config.childPools.filter(pool => pool.enabled); - else - config.childPools = []; - // Load pool modules if (cluster.isWorker) { switch (process.env.workerType) { @@ -53,9 +48,6 @@ case 'daemon': require('./lib/daemon.js') break - case 'childDaemon': - require('./lib/childDaemon.js') - break case 'blockUnlocker': require('./lib/blockUnlocker.js'); break; @@ -129,8 +121,6 @@ } else { spawnPoolWorkers(); spawnDaemon(); - if (config.poolServer.mergedMining) - spawnChildDaemons(); spawnBlockUnlocker(); spawnPaymentProcessor(); spawnApi(); @@ -238,65 +228,6 @@ }, 10); } - /** - * Spawn pool workers module - **/ - function spawnChildDaemons () { - if (!config.poolServer || !config.poolServer.enabled || !config.poolServer.ports || config.poolServer.ports.length === 0) return; - - if (config.poolServer.ports.length === 0) { - log('error', logSystem, 'Pool server enabled but no ports specified'); - return; - } - - let numForks = config.childPools.length; - if (numForks === 0) return; - var daemonWorkers = {}; - - var createDaemonWorker = function (poolId) { - var worker = cluster.fork({ - workerType: 'childDaemon', - poolId: poolId - }); - worker.poolId = poolId; - worker.type = 'childDaemon'; - daemonWorkers[poolId] = worker; - worker.on('exit', function (code, signal) { - log('error', logSystem, 'Child Daemon fork %s died, spawning replacement worker...', [poolId]); - setTimeout(function () { - createDaemonWorker(poolId); - }, 2000); - }) - .on('message', function (msg) { - switch (msg.type) { - case 'ChildBlockTemplate': - Object.keys(cluster.workers) - .forEach(function (id) { - if (cluster.workers[id].type === 'pool') { - cluster.workers[id].send({ - type: 'ChildBlockTemplate', - block: msg.block, - poolIndex: msg.poolIndex - }); - } - }); - break; - } - }); - }; - - var i = 0; - var spawnInterval = setInterval(function () { - createDaemonWorker(i.toString()) - i++ - if (i === numForks) { - clearInterval(spawnInterval); - log('info', logSystem, 'Child Daemon spawned on %d thread(s)', [numForks]); - } - }, 10); - } - - /** * Spawn daemon module **/ diff --git a/lib/api.js b/lib/api.js index 7c5d721..1cd0a18 100644 --- a/lib/api.js +++ b/lib/api.js @@ -112,9 +112,6 @@ function handleServerRequest (request, response) { case '/block_explorers': handleBlockExplorers(response) break - case '/get_apis': - handleGetApis(response) - break // Miners/workers hashrate (used for charts) case '/miners_hashrate': if (!authorize(request, response)) { @@ -220,14 +217,6 @@ function collectStats () { healthCommands.push(['hget', `${config.coin}:status:daemon`, 'lastStatus']); healthCommands.push(['hget', `${config.coin}:status:wallet`, 'lastStatus']); healthCommands.push(['hget', `${config.coin}:status:price`, 'lastReponse']); - /* - config.childPools.forEach(pool => { - healthCommands.push(['hmget', `${pool.coin}:status:daemon`, 'lastStatus']); - healthCommands.push(['hmget', `${pool.coin}:status:wallet`, 'lastStatus']); - keys.push(pool.coin); - - }) - */ redisClient.multi(healthCommands).exec(function (error, replies) { if (error) { @@ -644,17 +633,6 @@ function getLastBlockData (callback) { }); } -function handleGetApis (callback) { - let apis = {}; - config.childPools.forEach(pool => { - if (pool.enabled) - apis[pool.coin] = { - api: pool.api - } - }) - callback(apis) -} - /** * Broadcast live statistics **/ @@ -1089,37 +1067,6 @@ function handleGetMarket (urlParts, response) { }); } -function handleGetApis (response) { - async.waterfall([ - function (callback) { - let apis = {}; - config.childPools.forEach(pool => { - if (pool.enabled) - apis[pool.coin] = { - api: pool.api - } - }) - callback(null, apis); - } - ], function (error, data) { - if (error) { - response.end(JSON.stringify({ - error: 'Error collecting Api Information' - })); - return; - } - 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); - }) -} - /** * Return top 10 miners **/ @@ -1131,13 +1078,6 @@ function handleBlockExplorers (response) { "blockchainExplorer": config.blockchainExplorer, "transactionExplorer": config.transactionExplorer } - config.childPools.forEach(pool => { - if (pool.enabled) - blockExplorers[pool.coin] = { - "blockchainExplorer": pool.blockchainExplorer, - "transactionExplorer": pool.transactionExplorer - } - }) callback(null, blockExplorers); } ], function (error, data) { @@ -1895,11 +1835,7 @@ function handleAdminUsers (request, response) { // get workers data function (workerKeys, callback) { - let allCoins = config.childPools.filter(pool => pool.enabled).map(pool => { - return `${pool.coin}` - }) - - allCoins.push(otherCoin); + let allCoins = otherCoin ? [otherCoin] : []; let redisCommands = workerKeys.map(function (k) { return ['hmget', k, 'balance', 'paid', 'lastShare', 'hashes', ...allCoins]; diff --git a/lib/childDaemon.js b/lib/childDaemon.js deleted file mode 100644 index c6c4ad4..0000000 --- a/lib/childDaemon.js +++ /dev/null @@ -1,84 +0,0 @@ -let async = require('async'); -let apiInterfaces = require('./apiInterfaces.js')(config.daemon, config.wallet, config.api); -let lastHash; -let POOL_NONCE_SIZE = 16 + 1; // +1 for old XMR/new TRTL bugs - -let logSystem = 'childDaemon' -require('./exceptionWriter.js')(logSystem); - - -let pool = config.childPools[process.env.poolId]; - -let blockData = JSON.stringify({ - id: "0", - jsonrpc: "2.0", - method: 'getlastblockheader', - params: {} -}) - -let templateData = JSON.stringify({ - id: "0", - jsonrpc: "2.0", - method: 'getblocktemplate', - params: { - reserve_size: POOL_NONCE_SIZE, - wallet_address: pool.poolAddress - } -}) - - -function runInterval () { - async.waterfall([ - function (callback) { - apiInterfaces.jsonHttpRequest(pool.childDaemon.host, pool.childDaemon.port, blockData, function (err, res) { - if (err) { - log('error', logSystem, '%s error from daemon', [pool.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', [pool.coin, hash]); - callback(null, true); - return; - } else if (config.daemon.alwaysPoll || false) { - callback(null, true); - return; - } else { - callback(true); - return; - } - } else { - log('error', logSystem, '%s bad reponse from daemon', [pool.coin]); - setTimeout(runInterval, 3000); - return; - } - }); - }, - function (getbc, callback) { - apiInterfaces.jsonHttpRequest(pool.childDaemon.host, pool.childDaemon.port, templateData, function (err, res) { - if (err) { - log('error', logSystem, '%s Error polling getblocktemplate %j', [pool.coin, err]) - callback(null) - return - } - process.send({ - type: 'ChildBlockTemplate', - block: res.result, - poolIndex: process.env.poolId - }) - callback(null) - }) - } - ], - function (error) { - if (error) {} - setTimeout(function () { - runInterval() - }, config.poolServer.blockRefreshInterval) - }) -} - -runInterval() diff --git a/lib/daemon.js b/lib/daemon.js index 871e976..a93c6e2 100644 --- a/lib/daemon.js +++ b/lib/daemon.js @@ -4,10 +4,6 @@ let apiInterfaces = require('./apiInterfaces.js')(config.daemon, config.wallet, let lastHash; let POOL_NONCE_SIZE = 16 + 1; // +1 for old XMR/new TRTL bugs -let EXTRA_NONCE_TEMPLATE = "02" + POOL_NONCE_SIZE.toString(16) + "00".repeat(POOL_NONCE_SIZE); -let POOL_NONCE_MM_SIZE = POOL_NONCE_SIZE + utils.cnUtil.get_merged_mining_nonce_size(); -let EXTRA_NONCE_NO_CHILD_TEMPLATE = "02" + POOL_NONCE_MM_SIZE.toString(16) + "00".repeat(POOL_NONCE_MM_SIZE); - let logSystem = 'daemon' let blockData = JSON.stringify({ @@ -56,7 +52,7 @@ function runInterval () { jsonrpc: "2.0", method: 'getblocktemplate', params: { - reserve_size: config.poolServer.mergedMining ? POOL_NONCE_MM_SIZE : POOL_NONCE_SIZE, + reserve_size: POOL_NONCE_SIZE, wallet_address: utils.getPoolTemplateAddress() } }); diff --git a/lib/logger.js b/lib/logger.js index 619917b..b815b35 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -75,7 +75,7 @@ global.log = function (severity, system, text, data) { if (logConsole) { if (config.logging.console.colors) - if (system === 'daemon' || system === 'childDaemon') { + if (system === 'daemon') { console.log(severityMap[severity](time) + clc.green.bold(' [' + system + '] ' + formattedMessage)); } else { diff --git a/lib/pool.js b/lib/pool.js index 592307d..cae1e29 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -25,7 +25,6 @@ let noncePattern = new RegExp("^[0-9A-Fa-f]{8}$"); // Set redis database cleanup interval let cleanupInterval = config.redis.cleanupInterval && config.redis.cleanupInterval > 0 ? config.redis.cleanupInterval : 15; -let fallBackCoin = typeof config.poolServer.fallBackCoin !== 'undefined' && config.poolServer.fallBackCoin ? config.poolServer.fallBackCoin : 0 // Initialize log system let logSystem = 'pool'; @@ -54,12 +53,8 @@ let instanceId = utils.instanceId(); // Pool variables let poolStarted = false; let connectedMiners = {}; -// Get merged mining tag reseved space size let POOL_NONCE_SIZE = 16 + 1; // +1 for old XMR/new TRTL bugs let EXTRA_NONCE_TEMPLATE = "02" + POOL_NONCE_SIZE.toString(16) + "00".repeat(POOL_NONCE_SIZE); -let POOL_NONCE_MM_SIZE = POOL_NONCE_SIZE + utils.cnUtil.get_merged_mining_nonce_size(); -let EXTRA_NONCE_NO_CHILD_TEMPLATE = "02" + POOL_NONCE_MM_SIZE.toString(16) + "00".repeat(POOL_NONCE_MM_SIZE); -let mergedMining = config.poolServer.mergedMining && (Array.isArray(config.childPools) && config.childPools.length > 0) function randomIntFromInterval (min, max) { return Math.floor(Math.random() * (max - min + 1) + min); @@ -112,20 +107,11 @@ function Create2DArray (rows) { return arr; } -if (mergedMining) { - config.childPools = config.childPools.filter(pool => pool.enabled); -} - - // Block templates -let validBlockTemplates = mergedMining ? Create2DArray(config.childPools.length) : Create2DArray(1); +let validBlockTemplates = Create2DArray(1); let currentBlockTemplate = []; -// Child Block templates -let currentChildBlockTemplate = new Array(mergedMining ? config.childPools.length : 1); - - // Difficulty buffer const DIFF1 = (1n << 256n) - 1n; @@ -211,13 +197,7 @@ process.on('message', function (message) { 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)]); - if (mergedMining) { - for (var childPoolIndex = 0; childPoolIndex < config.childPools.length; childPoolIndex++) { - processBlockTemplate(message.block, childPoolIndex); - } - } else { - processBlockTemplate(message.block, 0); - } + processBlockTemplate(message.block); return; } else { return; @@ -225,21 +205,6 @@ process.on('message', function (message) { } catch (e) { log('error', logSystem, `BlockTemplate ${e}`); } - break; - case 'ChildBlockTemplate': - let poolIndex = parseInt(message.poolIndex); - try { - if (!currentChildBlockTemplate[poolIndex] || message.block.height > currentChildBlockTemplate[poolIndex].height || (currentChildBlockTemplate[poolIndex].num_transactions == 0 && message.block.num_transactions > 0)) { - log('info', logSystem, 'New %s child block to mine at height %d w/ difficulty of %d (%d transactions)', [config.childPools[poolIndex].coin, message.block.height, message.block.difficulty, (message.block.num_transactions || 0)]); - processChildBlockTemplate(poolIndex, message.block); - return; - } else { - return; - } - } catch (e) { - log('error', logSystem, `ChildBlockTemplate ${e}`); - } - break; } }); @@ -247,7 +212,7 @@ process.on('message', function (message) { /** * Block template **/ -function BlockTemplate (template, parent, indexOfChildPool) { +function BlockTemplate (template) { this.difficulty = template.difficulty; this.height; try { @@ -259,25 +224,15 @@ function BlockTemplate (template, parent, indexOfChildPool) { this.blocktemplate_blob = template.blocktemplate_blob; let blob = this.blocktemplate_blob; this.buffer = Buffer.from(blob, 'hex'); - let template_hex = EXTRA_NONCE_TEMPLATE; - if (parent && mergedMining) { - if (currentChildBlockTemplate[indexOfChildPool]) { - this.childBlockTemplate = currentChildBlockTemplate[indexOfChildPool]; - this.buffer = utils.cnUtil.construct_mm_parent_block_blob(this.buffer, cnBlobType, this.childBlockTemplate.buffer); - blob = this.buffer.toString('hex'); - } else { - template_hex = EXTRA_NONCE_NO_CHILD_TEMPLATE; - } - } this.isRandomX = config.isRandomX - if (!mergedMining && this.isRandomX) { + if (this.isRandomX) { this.seed_hash = template.seed_hash; this.next_seed_hash = template.next_seed_hash; } - var found_template_at = blob.indexOf(template_hex); + var found_template_at = blob.indexOf(EXTRA_NONCE_TEMPLATE); if (found_template_at !== -1) { this.reserveOffset = offset + (found_template_at >> 1); - if (this.reserveOffset != template.reserved_offset && !mergedMining) { + if (this.reserveOffset != template.reserved_offset) { log('error', logSystem, "INTERNAL ERROR: found reserve offset in unexpected place (found at %d, expected at %d)", [this.reserveOffset, template.reserved_offset]); } @@ -297,11 +252,8 @@ function BlockTemplate (template, parent, indexOfChildPool) { this.buffer.copy(this.prev_hash, 0, previousOffset, 39); } BlockTemplate.prototype = { - nextBlob: function (index) { + nextBlob: function () { this.buffer.writeUInt32BE(++this.extraNonce, this.reserveOffset); - if (mergedMining && this.childBlockTemplate) { - return utils.cnUtil.convert_blob(this.buffer, cnBlobType, this.childBlockTemplate.buffer).toString('hex'); - } return utils.cnUtil.convert_blob(this.buffer, cnBlobType).toString('hex'); }, nextBlobWithChildNonce: function () { @@ -316,43 +268,25 @@ BlockTemplate.prototype = { /** * Process block template **/ -function processBlockTemplate (template, indexOfChildPool) { - let block_template = new BlockTemplate(template, true, indexOfChildPool); +function processBlockTemplate (template) { + let block_template = new BlockTemplate(template); - if (currentBlockTemplate[indexOfChildPool]) { - validBlockTemplates[indexOfChildPool].push(currentBlockTemplate[indexOfChildPool]); + if (currentBlockTemplate[0]) { + validBlockTemplates[0].push(currentBlockTemplate[0]); } - while (validBlockTemplates[indexOfChildPool].length > (mergedMining ? 6 : 3)) { - validBlockTemplates[indexOfChildPool].shift(); + while (validBlockTemplates[0].length > 3) { + validBlockTemplates[0].shift(); } - currentBlockTemplate[indexOfChildPool] = block_template; - notifyConnectedMiners(indexOfChildPool); + currentBlockTemplate[0] = block_template; + notifyConnectedMiners(); } - - -/** - * Process child block template - **/ -function processChildBlockTemplate (indexOfChildPool, template) { - let block_template = new BlockTemplate(template, false); - - currentChildBlockTemplate[indexOfChildPool] = block_template; - - // Update the parent block template to include this new child - if (currentBlockTemplate[indexOfChildPool]) { - processBlockTemplate(currentBlockTemplate[indexOfChildPool], indexOfChildPool); - } -} - -function notifyConnectedMiners (indexOfChildPool) { - let now = Date.now() / 1000 | 0; +function notifyConnectedMiners () { for (let minerId in connectedMiners) { let miner = connectedMiners[minerId]; - if (indexOfChildPool === miner.activeChildPool) - miner.pushMessage('job', miner.getJob()); + miner.pushMessage('job', miner.getJob()); } } @@ -384,15 +318,10 @@ function GetRewardTypeAsKey (rewardType) { /** * Miner **/ -function Miner (rewardType, childRewardType, id, childPoolIndex, login, pass, ip, port, agent, childLogin, startingDiff, noRetarget, pushMessage) { +function Miner (rewardType, id, login, pass, ip, port, agent, startingDiff, noRetarget, pushMessage) { this.rewardType = rewardType; - this.childRewardType = childRewardType; this.rewardTypeAsKey = GetRewardTypeAsKey(rewardType); - this.childRewardTypeAsKey = GetRewardTypeAsKey(childRewardType); - - this.lastChildBlockHeight = 0; this.id = id; - this.activeChildPool = childPoolIndex || 0; this.login = login; this.pass = pass; this.ip = ip; @@ -402,7 +331,6 @@ function Miner (rewardType, childRewardType, id, childPoolIndex, login, pass, ip this.proxy = true; } this.workerName = 'undefined'; - this.childLogin = childLogin; if (pass.lastIndexOf('@') >= 0 && pass.lastIndexOf('@') < pass.length) { passDelimiterPos = pass.lastIndexOf('@') + 1; this.workerName = pass.substr(passDelimiterPos, pass.length) @@ -486,23 +414,14 @@ Miner.prototype = { return hex; }, getJob: function () { - let blockTemplate = currentBlockTemplate[this.activeChildPool]; + let blockTemplate = currentBlockTemplate[0]; let newJob = { id: utils.uid(), height: blockTemplate.height, submissions: [] }; - if (mergedMining) { - if (this.lastBlockHeight === blockTemplate.height && (!currentChildBlockTemplate[this.activeChildPool] || this.lastChildBlockHeight === currentChildBlockTemplate[this.activeChildPool].height) && !this.pendingDifficulty && this.cachedJob !== null && !config.daemon.alwaysPoll) { - return this.cachedJob; - } - this.lastChildBlockHeight = currentChildBlockTemplate ? currentChildBlockTemplate[this.activeChildPool].height : -1; - newJob.activeChildPool = this.activeChildPool; - newJob.childHeight = this.lastChildBlockHeight; - } else { - if (this.lastBlockHeight === blockTemplate.height && !this.pendingDifficulty && this.cachedJob !== null && !config.daemon.alwaysPoll) { - return this.cachedJob; - } + if (this.lastBlockHeight === blockTemplate.height && !this.pendingDifficulty && this.cachedJob !== null && !config.daemon.alwaysPoll) { + return this.cachedJob; } let blob = this.proxy ? blockTemplate.nextBlobWithChildNonce() : blockTemplate.nextBlob(); this.lastBlockHeight = blockTemplate.height; @@ -534,7 +453,6 @@ Miner.prototype = { this.cachedJob.blocktemplate_blob = blob; this.cachedJob.difficulty = blockTemplate.difficulty; this.cachedJob.height = blockTemplate.height; - this.cachedJob.childHeight = this.lastChildBlockHeight; this.cachedJob.reserved_offset = blockTemplate.reserveOffset; this.cachedJob.client_nonce_offset = blockTemplate.clientNonceLocation; this.cachedJob.client_pool_offset = blockTemplate.clientPoolLocation; @@ -647,79 +565,6 @@ function handleMinerMethod (method, params, ip, portData, sendReply, pushMessage let paymentid = null; let port = portData.port; let pass = params.pass; - let childLogin = pass.trim(); - let childPoolIndex = 0; - let childRewardType = rewardType; - if (mergedMining) { - childPoolIndex = -1; - if (!validateMinerPaymentId_difficulty(pass, ip, config.poolServer, 'child ', sendReply)) - { - return - } - - calculated = utils.determineRewardData(pass); - pass = calculated.address; - childRewardType = calculated.rewardType; - - if (pass.indexOf('@') >= 0 && pass.indexOf('@') >= 0) { - passDelimiterPos = pass.lastIndexOf('@'); - childLogin = pass.substr(0, passDelimiterPos).trim(); - } - childLogin = childLogin.replace(/\s/g, ''); - childLogin = utils.cleanupSpecialChars(childLogin); - - - let addr = childLogin.split(config.poolServer.paymentId.addressSeparator); - address = addr[0] || null; - paymentId = addr[1] || null; - - if (!address) { - log('warn', logSystem, 'No address specified for login'); - sendReply('No address specified for login'); - } - - - if (paymentId && config.poolServer.paymentId.validation) { - let valid = false; - config.poolServer.paymentId.validations.forEach(validation => { - if (paymentId.match(`^([a-zA-Z0-9]){${validation}}$`)) { - return valid = true; - } - }) - if (!valid) { - log('warn', logSystem, 'Invalid paymentId specified for login'); - } - if (config.poolServer.paymentId.ban) { - process.send({ - type: 'banIP', - ip: ip - }); - sendReply(`Invalid paymentId specified for login, ${portData.ip} banned for ${config.poolServer.banning.time / 60} minutes`); - } - } - - for (i = 0; i < config.childPools.length; i++) { - if (config.childPools[i].pattern) { - if (new RegExp(config.childPools[i].pattern, 'i').test(address)) { - childPoolIndex = i; - break; - } - } - } - if (childPoolIndex < 0) { - childPoolIndex = fallBackCoin; - address = config.childPools[childPoolIndex].poolAddress; - childLogin = config.childPools[childPoolIndex].poolAddress; - } - if (!utils.validateChildMinerAddress(address, childPoolIndex)) { - let addressPrefix = utils.getAddressPrefix(address); - if (!addressPrefix) addressPrefix = 'N/A'; - - log('warn', logSystem, 'Invalid address used for childLogin (prefix: %s): %s', [addressPrefix, address]); - sendReply('Invalid address used for childLogin'); - return; - } - } let difficulty = portData.difficulty; @@ -775,7 +620,7 @@ function handleMinerMethod (method, params, ip, portData, sendReply, pushMessage } let minerId = utils.uid(); - miner = new Miner(rewardType, childRewardType, minerId, childPoolIndex, login, pass, ip, port, params.agent, childLogin, difficulty, noRetarget, pushMessage); + miner = new Miner(rewardType, minerId, login, pass, ip, port, params.agent, difficulty, noRetarget, pushMessage); connectedMiners[minerId] = miner; sendReply(null, { @@ -875,14 +720,10 @@ function handleMinerMethod (method, params, ip, portData, sendReply, pushMessage } let isJobBlock = function (b) { - return b.height === job.height && job.childHeight === ( - b.childBlockTemplate ? b.childBlockTemplate.height : undefined); + return b.height === job.height; }; - let blockTemplate = currentBlockTemplate[miner.activeChildPool]; - if (job.childHeight) { - blockTemplate = isJobBlock(currentBlockTemplate[miner.activeChildPool]) ? currentBlockTemplate[miner.activeChildPool] : validBlockTemplates[miner.activeChildPool].filter(isJobBlock)[0]; - } + let blockTemplate = isJobBlock(currentBlockTemplate[0]) ? currentBlockTemplate[0] : validBlockTemplates[0].filter(isJobBlock)[0]; if (!blockTemplate) { sendReply('Block expired'); return; @@ -958,28 +799,6 @@ function newConnectedWorker (miner) { }); } }); - if (config.poolServer.mergedMining) { - redisClient.sadd(`${config.childPools[miner.activeChildPool].coin}:workers_ip:${miner.childLogin}`, miner.ip); - redisClient.hincrby(`${config.childPools[miner.activeChildPool].coin}:ports:${miner.port}`, 'users', 1); - - redisClient.hincrby(`${config.childPools[miner.activeChildPool].coin}:active_connections${miner.childRewardTypeAsKey}`, `${miner.childLogin}~${miner.workerName}`, 1, function (error, connectedWorkers) {}); - - - let redisCommands = config.childPools.map(item => { - return ['hdel', `${config.coin}:workers:${miner.login}`, `${item.coin}`, ] - }) - redisClient.multi(redisCommands) - .exec(function (error, replies) { - if (error) { - log('error', logSystem, 'Failed to clear childCoins from parent in redis %j \n %j', [err, redisCommands]); - } - }) - - redisClient.hset(`${config.coin}:workers:${miner.login}`, `${config.childPools[miner.activeChildPool].coin}`, miner.childLogin); - - redisClient.hset(`${config.childPools[miner.activeChildPool].coin}:workers:${miner.childLogin}`, `${config.coin}`, miner.login); - - } } /** @@ -987,10 +806,6 @@ function newConnectedWorker (miner) { **/ function removeConnectedWorker (miner, reason) { redisClient.hincrby(`${config.coin}:ports:${miner.port}`, 'users', '-1'); - if (mergedMining) { - redisClient.hincrby(`${config.childPools[miner.activeChildPool].coin}:ports:${miner.port}`, 'users', '-1'); - redisClient.hincrby(`${config.childPools[miner.activeChildPool].coin}:active_connections${miner.childRewardTypeAsKey}`, `${miner.childLogin}~${miner.workerName}`, 1, function (error, connectedWorkers) {}); - } redisClient.hincrby(`${config.coin}:active_connections${miner.rewardTypeAsKey}`, `${miner.login}~${miner.workerName}`, -1, function (error, connectedWorkers) { if (reason === 'banned') { @@ -1032,14 +847,14 @@ function IsBannedIp (ip) { } } -function recordShareData (miner, job, shareDiff, blockCandidate, hashHex, shareType, blockTemplate, pool) { +function recordShareData (miner, job, shareDiff, blockCandidate, hashHex, shareType, blockTemplate) { let dateNow = Date.now(); let dateNowSeconds = dateNow / 1000 | 0; - let coin = pool !== null ? pool.coin : config.coin; - let login = pool !== null ? miner.childLogin : miner.login; - let job_height = pool !== null ? job.childHeight : job.height; + let coin = config.coin; + let login = miner.login; + let job_height = job.height; let workerName = miner.workerName; - let rewardType = pool !== null ? miner.childRewardType : miner.rewardType; + let rewardType = miner.rewardType; let updateScore; // Weighting older shares lower than newer ones to prevent pool hopping if (slushMiningEnabled) { @@ -1231,60 +1046,14 @@ 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, null); + recordShareData(miner, job, hashDiff.toString(), true, blockFastHash, shareType, blockTemplate); } }); } else if (hashDiff < jobDifficulty) { log('warn', logSystem, 'Rejected low difficulty share of %s from %s@%s', [hashDiff.toString(), miner.login, miner.ip]); return false; } else { - recordShareData(miner, job, hashDiff.toString(), false, null, shareType, null, null); - } - - if (!job.childHeight) { - return true; - } - - var childBlockTemplate = blockTemplate.childBlockTemplate; - - if (childBlockTemplate) { - if (mergedMining) { - let pool = config.childPools[miner.activeChildPool] - if (hashDiff >= BigInt(childBlockTemplate.difficulty)) { - let mergedBuffer = null - try { - mergedBuffer = utils.cnUtil.construct_mm_child_block_blob(shareBuffer, cnBlobType, childBlockTemplate.buffer); - } catch (e) { - log('error', logSystem, "Failed to construct MM child block: " + e); - } - if (mergedBuffer === null) { - recordShareStatusMerged(miner, 'invalid'); - } else { - - let onChildSuccess = (result) => { - let blockFastHash = utils.cnUtil.get_block_id(mergedBuffer, 2).toString('hex') - log('info', logSystem, - 'Child Block %s found at height %d by miner %s@%s - submit result: %j', - [blockFastHash.substr(0, 6), job.childHeight, miner.workerName, miner.ip, result]); - recordShareData(miner, job, hashDiff.toString(), true, blockFastHash, shareType, childBlockTemplate, pool); - } - - apiInterfaces.rpcDaemon('submitblock', [mergedBuffer.toString('hex')], function (error, result) { - if (error) { - log('error', logSystem, 'Error submitting child block at height %d from %s@%s, share type: "%s" - %j', [job.childHeight, miner.login, miner.ip, shareType, error]); - } else { - onChildSuccess(result) - } - }, pool.childDaemon); - } - } else if (hashDiff < jobDifficulty) { - log('warn', logSystem, 'Rejected low difficulty share of %s from %s@%s', [hashDiff.toString(), miner.workerName, miner.ip]); - return false; - } else { - recordShareData(miner, job, hashDiff.toString(), false, null, shareType, null, pool); - } - } - return true; + recordShareData(miner, job, hashDiff.toString(), false, null, shareType, null); } return true; } diff --git a/lib/utils.js b/lib/utils.js index dc768fa..e8b8ac4 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -73,17 +73,6 @@ function characterCount (string, char) { } exports.characterCount = characterCount; -// Validate miner address -exports.validateChildMinerAddress = (address, index) => { - let childAddressBase58Prefix = parseInt(cnUtil.address_decode(Buffer.from(config.childPools[index].poolAddress)).toString()); - let childIntegratedAddressBase58Prefix = config.poolServer.intChildAddressPrefix ? parseInt(config.childPools[index].intAddressPrefix) : childAddressBase58Prefix + 1; - - let addressPrefix = getAddressPrefix(address); - if (addressPrefix === childAddressBase58Prefix) return true; - else if (addressPrefix === childIntegratedAddressBase58Prefix) return true; - return false; -} - // Return if value is an integrated address exports.isIntegratedAddress = function (address) { let addressPrefix = getAddressPrefix(address); diff --git a/website_example/admin.html b/website_example/admin.html index 39dc397..a086d20 100644 --- a/website_example/admin.html +++ b/website_example/admin.html @@ -79,37 +79,17 @@ mergedStats = {}; let mergedApis = {}; $(function() { - - - let merged_apis = $.ajax({ - url: `${api}/get_apis`, - dataType: 'json', - cache: 'false' - }) - let poolStats = $.ajax({ url: `${api}/stats`, dataType: 'json', cache: 'false' }) - Promise.all([poolStats, merged_apis]) + Promise.all([poolStats]) .then(values => { lastStats = values[0] - mergedApis = values[1] - let subs = []; - Object.keys(mergedApis).some(key => { - let apiUrl = `${mergedApis[key].api}/stats` - subs.push($.ajax({url: apiUrl, dataType: 'json', cache: 'false'})) - }) - Promise.all(subs) - .then(data => { - data.forEach(item => { - mergedStats[item.config.coin] = item - }) - $('#poolVersion').html(lastStats.config.version); - routePage(); - }) + $('#poolVersion').html(lastStats.config.version); + routePage(); }) }); diff --git a/website_example/index.html b/website_example/index.html index 7877ee5..800f972 100644 --- a/website_example/index.html +++ b/website_example/index.html @@ -197,19 +197,6 @@ function loadLiveStats(reload) { }); - Object.keys(mergedApis).some(key => { - let apiUrl = `${mergedApis[key].api}/stats` - // if (xhrLiveStats[key]){ - // xhrLiveStats[key].abort(); - // } - - $.get(apiUrl, function(data){ - updateLiveStats(data, key); - if (!reload){ - routePage(fetchLiveStats(mergedApis[key].api, key)); - } - }); - }) } // Fetch live statistics @@ -239,7 +226,6 @@ function fetchLiveStats(endPoint, key) { // Fetch Block and Transaction Explorer Urls let xhrBlockExplorers; -let xhrMergedApis; function fetchBlockExplorers() { let apiURL = api + '/block_explorers'; @@ -249,17 +235,7 @@ function fetchBlockExplorers() { cache: 'false' }).done(function(data){ blockExplorers = data; - }) - - apiURL = api + '/get_apis'; - - xhrMergedApis = $.ajax({ - url: apiURL, - dataType: 'json', - cache: 'false', - }).done(function(data){ - mergedApis = data; - loadLiveStats() + loadLiveStats(); }) } diff --git a/website_example/pages/faq.html b/website_example/pages/faq.html index 9aaeb57..ff9cb24 100644 --- a/website_example/pages/faq.html +++ b/website_example/pages/faq.html @@ -1,117 +1,91 @@

Frequently Asked Questions (FAQ)

-

How do I pick which coins to merge mine?

-

The hash work of your miner application to the parent coin is also applied to the child coin you specify in the mining software pool password field.

- -

You must mine at one parent coin, which in this case is ARQ for ArQmA. -Specify your ArQmA wallet address and static difficulty per the Getting Started page. -Using the pool password field in your miner to specify one of the child coin wallet addresses. See which child coins are listed on the pool's Dashboard page. -You will need at least a wallet address from an exchange or a wallet/paper wallet application to get an coin address for the parent coin and each child coin you wish to merge mine.

- -

You can also connect multiple rigs with the same wallet address for the parent coin, and different child coin wallet address to apply hash to that child coin also.

- -

Specify your rig_id in your miner software.

-

Put your child coin wallet address in the pool password field and put "@rig_id" at the end. - It can be a direct to exchange address also.

-

For example in XMR-STAK, the pools.txt config file looks something like this: -"rig_id" : "Johnny5", -An example wallet for Turtle child coin is "TRTL2aedfsr23blahlongaddressfield+paymentIDsomething" -so make it formatted for the pool password as -"pool_password" : "TRTL2aedfsr23blahlongaddressfield+paymentIDsomething@Johnny5"

- -

You can also use the configuration generator within the Getting Started section of the pool.

-

Also, you can segment your cpu mining on one mining application to be applied to -the parent coin and specify your hash work one of the several child coins. -There is no limit on how many workers you can specify. You can also customize your miner application to mine only with certain gpus to a particular parent/child combination. Probably you can run several mining applications in tandem as long as they use only resources you specify.

- +

Which coin am I mining here?

+
+ You are mining the coin configured by this pool instance. The miner login should be your wallet address for that coin.
-

Where are the stats for the pool? Why hasn't anything changed?

-
The dashboard lists the coins being mined, reward for each block, current effort on each block for the merged mining. Sometimes the Pool Blocks section and Worker Statistics needs a refresh by your browser to get updated stats. Typically that is pressing CTRL+F5 to flush the cache and ask your brower for fresh data.
- - -

What is difficulty?

-
Difficulty is a measure of how difficult it is to find a hash below a given target. The target difficulty changes from block to block based on the network hashrate attempted by all nodes on a coin network. However, the difficulty for child coins can be dissimlar to the parent coin you start mining with
- -

What is luck?

-
Mining is probabilistic in nature: if you find a block earlier than you statistically should on average you are lucky if it takes longer, you are unlucky. In a perfect World pool would find a block on 100% luck value. Less then 100% means the pool was lucky. More then 100% means the pool was unlucky. +

What is difficulty?

+
+ Difficulty measures how hard it is to find a valid hash for the current network target. Higher network hashrate usually means higher difficulty.
-

What is share?

-
Share is a possible valid hash for the block. Shares are beings sent by your rigs to the pool to prove their work. You should set your fixed difficulty to be somewhere around your hash rate average on your miner multiplied by 28-30. Aim for your average number of accepted shares to be within the block time (30 seconds typically for child coins, 2 minutes for ARQ) -If your shares are accepted faster, but with lower difficulty each share is worth less, but you should get at least one share in per average block time. It doesn't help the pool by spamming a large amount of low difficulty shares. It tends to tie up more resources and might get you banned.
- -

What is block?

-
Transaction data is recorded in blocks. New transactions are being processes by miners into new blocks which are added to the end of the blockchain.
- -

How long does it take to find a block?

-
It depends on amount of active miners. The more miners work on pool → the more hashrate pool has → the more blocks are found by the pool. However the more miners are active → the less reward you get from each block found. -Probablistically, even smaller pools will less miners or hash rate will eventually get a block. -Decentralizing the hash proof of work across several pools on any network is important for security of the coin network, for both the parent coin and the child coins. -The block time is how long it can take on average amount effort . The average for ArQmA is 120 seconds. However, some of the child coins have block timeframes on the average of 15 to 30 seconds. Check your child coins network specification. Some blocks are solved faster than the average block time, some blocks can have a higher than average block effort time. -Also some other pools might solve the block first, and there is a slim possibility of an orphan block on a child coin being mined.
- -

What is an orphan block?

-
An orphan is a block that didn't meet the requirement as a solution to the block found. Also, there can be a situation where another pool or solo miner found the block solution first, and narrowly won the race. Blocks are confirmed by hash verfication by all the nodes on the coin's network. If there is a consensus of which node(pool,solo) found it first, then that block is added to the block chain permanenty with credit applying to that pool/solo/node. -A few orphan blocks on child coins can happen when the parent coin's hash work doesn't meet the requirements.
- - -

Which payouts scheme is used?

-
Proportional (Share-based): Every time a block is found, its reward is split between miners according to the number of shares they submitted.
- -

How current payout estimate is calculated?

-
The estimated payout is a calculated using your percentage of valid shares on the total for current round in proportion to the total shares submitted by all miners/workers in that round. This percentage is then applied to the reward of the last block found by the network and subtracting the small pool fee.. See the Worker Statistics page on the pool web page. +

What is luck?

+
+ Mining is probabilistic. Less than 100% round luck means the pool found a block faster than statistically expected, more than 100% means it took longer.
-

I have been mining on this pool for 1 hour but still have not received any payouts. WTF?

-

As soon as the block is found you will get your reward. Please wait a little bit more time. In the case of ArQmA, a block has at least 18 confirmations before the pool starts its payout cycle. Typically every 36 minutes for a completed block plus the time interval set by the pool operator on the pool's Dashboard screeen. Payments can be halted for various reasons within the automated pool software, but highly unlikely. There is usually a minimum payout for each parent coin and child coins. Payments for matured blocks that meet the minimum can also be triggered manually by a pool operator/administrator. Ask nicely in Telegram or Discord support. Please have your information all in order before you ask such as miner application, version number, gpu and cpu information, wallet addresses, and error messages reported. -

The merge mined child coins have a different number of confirmation blocks needed, but at least the pool checks for fully verified blocks set at the interval on the Dashboard page. Not every parent block found generates a child block. -Check the Pool Blocks page on the pool. Or configure your settings to get an email alert if you like on the Settings pool page. -

- -

My hashrate is wrong! Why?

-
Since you start to mine your hashrate grows gradually. Please wait. The pool determines your hashrate based on the amount of shares sent by your mining rigs (workers). This value could be a little bit different from reported hasrate (in your mining software). +

What is a share?

+
+ A share is proof that your miner is doing useful work. Shares do not have to be full blocks to count toward your round contribution.
-

What is solo mining?

-

Solo mining is attempting to find a block by yourself separate from the pool of proportional miners collectively solving the current block.You get almost the entire block reward minus a small fee for the pool. You can specfy your mining software by changing the wallet address with a prefix of "solo:" added to your wallet specification. -However, if the coin network has a high hash in total (see Dashboard), the difficulty is also higher. Typically only very large mining rigs with at least 5-10% of the coin network total is needed to get timely solo blocks. However, you could get a string of blocks on lucky streak, then not find a block solution for a very long time. The more hash rate, the higher the probability(luck). You can generate a solo configuration on the Getting Started page on the pool. Tick the checkbox "solo mining". However, as solo you are also competing against the pool proportional share miners, and evvery single node on the parent coin network also. -

-

In the case of solo merged mining specified in the pool password field, you are also competing against the main pool users on proportional shares, and the entire child coin network and the other pools on the parent network that are also merge mining. However the reward is much higher since you might get two coin blocks(or more) for the same effort. -

+

What is a block?

+
+ Transactions are grouped into blocks. Miners build and solve new blocks which are then appended to the blockchain.
-

I've been banned by the pool itself. What do I do now?

-

Disconnect your miner for five minutes at least. Then try again. Please pay close attention to error messages reported by the pool software to your miner client software. Typical errors are invalid parent wallet address format, or bad child coin wallet address specified in the pool password field. Check your miner logs if you have them turned on. -

-

Did you forget to turn off nicehash option?

-

For persistent banning, check with the pool operator or Admininstrator to see if there is something else going wrong outside of your control. Links for Telegram and Discord support are on the left side of the pool web page front end.

+

How long does it take to find a block?

+
+ It depends on total pool hashrate, network difficulty and luck. Some blocks arrive quickly, others take much longer than average.
+

What is an orphan block?

+
+ An orphan is a block that lost the race to another valid block at the same height and was not accepted into the main chain. +
+ +

Which payout scheme is used?

+
+ Proportional share-based payout: when the pool finds a block, the reward is split according to submitted shares. +
+ +

How is my current payout estimate calculated?

+
+ The estimate is based on your share of valid work in the current round relative to all miners in that round. +
+ +

I have been mining for a while and still have not received a payout. Why?

+
+ Pool rewards must first mature on-chain and then exceed the configured payout threshold. Check the Blocks and Payments pages before assuming something is wrong. +
+ +

My hashrate looks wrong. Why?

+
+ Pool hashrate is estimated from submitted shares over time, so it ramps up gradually and may differ from your miner's local display. +
+ +

What is solo mining?

+
+ Solo mining means you are trying to win full blocks for yourself through the pool infrastructure instead of sharing rewards proportionally with the round. +
+ +

I've been banned by the pool. What should I do?

+
+ Stop the miner for a few minutes, then reconnect and check your miner logs. Invalid wallet addresses, malformed logins and duplicate or invalid shares are common causes. +
-

How to use the Telegram Bot?

+

How to use the Telegram Bot?

-
Telegram bot will report via Telegram, when your worker is connected, disconnected or banned, and payments have been made to your wallet. Also you can check pool stats directly from him.
+
Telegram bot will report worker connects, disconnects, bans and payments, and can also provide pool stats directly.

- Bot name: @Pool_bot
+ Bot name: @Pool_bot

- Commands:
- /stats - Pool statistics
- /blocks - Blocks notifications (enable or disable)
- /report address - Miner statistics
- /notify address - Miner notifications (enable or disable)
+ Commands:
+ /stats - Pool statistics
+ /blocks - Blocks notifications (enable or disable)
+ /report address - Miner statistics
+ /notify address - Miner notifications (enable or disable)

- Multiple addresses monitoring available.
+ Multiple addresses monitoring available.
- \ No newline at end of file + diff --git a/website_example/pages/getting_started.html b/website_example/pages/getting_started.html index 3e68abb..0592c04 100644 --- a/website_example/pages/getting_started.html +++ b/website_example/pages/getting_started.html @@ -21,10 +21,10 @@

Password

-
Use your Iridium OR Nibble wallet address in the password field for merged mining.
-
Exchange Payment ID: child address+paymentID
-
Worker Name: child-address@workerName
-
Payment ID and Worker Name: child-address+paymentID@workerName
+
Use the password field only for optional worker naming or miner-specific settings if your miner supports them.
+
Exchange Payment ID: wallet address+paymentID
+
Worker Name: wallet-address@workerName
+
Payment ID and Worker Name: wallet-address+paymentID@workerName
@@ -287,8 +287,7 @@ currentPage = { updateTextClasses('exampleHost', getPoolHost()); updateText('paymentIdSeparator', lastStats.config.paymentIdSeparator); updateText('fixedDiffSeparator', lastStats.config.fixedDiffSeparator); - let childCoins = Object.keys(mergedStats).join(' or ') - updateText('paymentChildCoins', `${childCoins} wallet address`); + updateText('paymentChildCoins', `${lastStats.config.symbol} wallet address`); if (!lastStats.config.fixedDiffEnabled) $('#fixedDiff').hide(); var algorithm = 'RandomX';