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 logSystem = 'miningSource'; let blockData = JSON.stringify({ id: "0", jsonrpc: "2.0", method: 'getlastblockheader', params: {} }); 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 { miningConfig = miningBackends.getActiveMiningBackend(); } catch (e) { log('error', logSystem, 'Invalid mining backend configuration: %s', [e.message]); setTimeout(runInterval, 3000); return; } async.waterfall([ function (callback) { pollMiningTip(miningConfig, function (err, tip) { if (err) { log('error', logSystem, '%s error from mining source', [config.coin]); setTimeout(runInterval, 3000); 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 { callback(true); return; } }); }, function (_getbc, callback) { let templateData = JSON.stringify({ id: "0", jsonrpc: "2.0", method: 'getblocktemplate', params: { reserve_size: POOL_NONCE_SIZE, wallet_address: miningBackends.getMiningTemplateAddress(utils.getPoolTemplateAddress()) } }); apiInterfaces.jsonHttpRequest(miningConfig.host, miningConfig.port, templateData, function (err, res) { if (err) { log('error', logSystem, 'Error polling getblocktemplate %j', [err]); callback(null); return; } if (res.error) { log('error', logSystem, 'Error polling getblocktemplate %j', [res.error]); callback(null); return; } if (config.coin == 'talleo' && res.result.height >= 10000 && res.result.num_transactions == 0) { callback(null); return; } process.send({ type: 'BlockTemplate', block: res.result }); callback(null); }); } ], function () { setTimeout(function () { runInterval(); }, config.poolServer.blockRefreshInterval); }); } runInterval();