diff --git a/lib/database.js b/lib/database.js index 341fc3f..91d5eef 100644 --- a/lib/database.js +++ b/lib/database.js @@ -554,7 +554,7 @@ module.exports = { // loop through masternode addresses for (m = 0; m < masternodes.length; m++) { // check if this is the correct address - if ((masternodes[m].proTxHash != null ? masternodes[m].payee : masternodes[m].addr) == hash) { + if (masternodes[m].addr == hash) { // update the claim name masternodes[m]['claim_name'] = claim_name; // mark as updated @@ -1449,9 +1449,138 @@ module.exports = { }, // determine if masternode exists and save masternode to collection - save_masternode: function (raw_masternode, cb) { - var txhash = (raw_masternode.proTxHash != null ? raw_masternode.proTxHash : raw_masternode.txhash); - var addr = (raw_masternode.proTxHash != null ? raw_masternode.payee : raw_masternode.addr); + save_masternode: function (raw_masternode, object_key, cb) { + let txhash = raw_masternode.txhash; + let addr = raw_masternode.addr; + + if (txhash == null) { + // try to use a different field for the txhash + txhash = raw_masternode.proTxHash; + } + + if (addr == null) { + // try to use a different field for the addr + addr = raw_masternode.payee; + } + + // check if the txhash and addr values were found + if (txhash == null && addr == null) { + try { + // attempt to parse out data separated by spaces + // supported formats: + // 1) status protocol pubkey lastseen activetime lastpaid lastpaidblock vin + // 2) status protocol pubkey vin lastseen activetime lastpaid + const parts = raw_masternode.trim().split(/\s+/); + const result = {}; + + parts.forEach((value, index) => { + if (index == 0) { + // always save the 1st value as the status + result['status'] = value; + } else if (index == 1) { + // always save the 2nd value as the version + result['version'] = parseInt(value); + } else if (index == 2) { + // always save the 3rd value as the addr + result['addr'] = value; + } else if (index == 3) { + // determine if this is an ip address or lastseen time + if (value.indexOf(':') > -1 || value.indexOf('.') > -1) { + // this is an ip address + result['address'] = value; + } else if (Number.isInteger(Number(value))) { + // this is a lastseen time value + result['lastseen'] = parseInt(value); + } + } else if (index == 4) { + // check if this is a number value + if (Number.isInteger(Number(value))) { + // determine if this is the lastseen or activetime + if (result['lastseen'] == null) { + // this must be lastseen since it has not yet been found + result['lastseen'] = parseInt(value); + } else { + // lastseen was already found so this much be the activetime + result['activetime'] = parseInt(value); + } + } + } else if (index == 5) { + // check if this is a number value + if (Number.isInteger(Number(value))) { + // determine if this is the activetime or lastpaid time + if (result['activetime'] == null) { + // this must be activetime since it has not yet been found + result['activetime'] = parseInt(value); + } else { + // activetime was already found so this much be the lastpaid time + result['lastpaid'] = parseInt(value); + } + } + } else if (index == 6) { + // check if this is a number value + if (Number.isInteger(Number(value))) { + // determine if this is the lastpaid time or lastpaidblock + if (result['lastpaid'] == null) { + // this must be lastpaid since it has not yet been found + result['lastpaid'] = parseInt(value); + } else { + // lastpaid was already found so this much be the lastpaidblock + result['lastpaidblock'] = parseInt(value); + } + } + } else { + // determine if this is an ip address + if (value.indexOf(':') > -1 || value.indexOf('.') > -1) { + // this is an ip address + result['address'] = value; + } + } + }); + + // check if the object_key is set + if (object_key != null) { + // try to separate the txhash from the outidx + const splitHash = object_key.split('-'); + + result['txhash'] = splitHash[0]; + result['outidx'] = (splitHash.length > 1 ? parseInt(splitHash[1]) : -1); + } else { + result['txhash'] = ""; + result['outidx'] = -1; + } + + // set the txhash and addr values + txhash = result['txhash']; + addr = result['addr']; + + // update the raw_masternode object + raw_masternode = result; + } catch { + // do nothing as the masternode will already fail to be saved below + } + } else { + // try to convert as many alternately named fields as possible so that there is only one set of fields to deal with + + if (raw_masternode.proTxHash != null) { + raw_masternode.txhash = raw_masternode.proTxHash; + delete raw_masternode.proTxHash; + } + + if (raw_masternode.payee != null) { + raw_masternode.addr = raw_masternode.payee; + delete raw_masternode.payee; + } + + if (raw_masternode.lastpaidtime != null) { + raw_masternode.lastpaid = raw_masternode.lastpaidtime; + delete raw_masternode.lastpaidtime; + } + + if (raw_masternode.lastpaidtime != null) { + raw_masternode.lastpaid = raw_masternode.lastpaidtime; + delete raw_masternode.lastpaidtime; + } + } // lookup masternode in local collection find_masternode(txhash, addr, function (masternode) { @@ -1483,40 +1612,25 @@ module.exports = { // add or update a single masternode add_update_masternode(masternode, add, cb) { - if (masternode.proTxHash == null && masternode.txhash == null) { + if (masternode.txhash == null) { console.log('Masternode update error: Tx Hash is missing'); - return cb(false); } else { - // Check if this older or newer Dash masternode format - if (masternode.proTxHash != null) { - // This is the newer Dash format - var mn = new Masternode({ - txhash: masternode.proTxHash, - status: masternode.status, - addr: masternode.payee, - lastpaid: masternode.lastpaidtime, - ip_address: masternode.address, - last_paid_block: masternode.lastpaidblock, - lastseen: Math.floor(Date.now() / 1000), - claim_name: (masternode.claim_name == null ? '' : masternode.claim_name) - }); - } else { - // This is the older Dash format, or an unknown format - var mn = new Masternode({ - rank: masternode.rank, - network: masternode.network, - txhash: masternode.txhash, - outidx: masternode.outidx, - status: masternode.status, - addr: masternode.addr, - version: masternode.version, - lastseen: masternode.lastseen, - activetime: masternode.activetime, - lastpaid: masternode.lastpaid, - claim_name: (masternode.claim_name == null ? '' : masternode.claim_name) - }); - } + var mn = new Masternode({ + rank: masternode.rank, + network: masternode.network, + txhash: masternode.txhash, + outidx: masternode.outidx, + status: masternode.status, + addr: masternode.addr, + version: masternode.version, + lastseen: (masternode.lastseen == null ? Math.floor(Date.now() / 1000) : masternode.lastseen), // lastseen must have a value since masternodes are deleted based on the lastseen date being too old + activetime: masternode.activetime, + lastpaid: masternode.lastpaid, + last_paid_block: masternode.lastpaidblock, + ip_address: masternode.address, + claim_name: (masternode.claim_name == null ? '' : masternode.claim_name) + }); if (add) { // add new masternode to collection @@ -1528,7 +1642,7 @@ module.exports = { }); } else { // update existing masternode in local collection - Masternode.updateOne({ txhash: (masternode.proTxHash != null ? masternode.proTxHash : masternode.txhash) }, masternode).then(() => { + Masternode.updateOne({ txhash: masternode.txhash }, masternode).then(() => { return cb(true); }).catch((err) => { console.log(err); diff --git a/lib/explorer.js b/lib/explorer.js index 696e5a2..4ce6068 100644 --- a/lib/explorer.js +++ b/lib/explorer.js @@ -133,6 +133,56 @@ function encodeP2PKaddress(p2pk_descriptor, cb) { }); } +function normalizeMasternodeCount(raw_count) { + // check if any data was returned + if (raw_count != null) { + // check if the data is in the expected object format + if (raw_count.total != null && raw_count.enabled != null) { + // data is already in the correct format + return raw_count; + } else { + const regex = /^\d+ \/ \d+$/; + + // check if the data is in the format of "{enabled_count} / {total_count}" + if (regex.test(raw_count)) { + const splitCount = raw_count.split('/'); + + // enabled / total format detected + // return the data formatted as an object + return { + enabled: splitCount[0].trim(), + total: splitCount[1].trim() + }; + // check if the data is in the format of "Total: {total_count} Enabled: {enabled_count}" + } else if (raw_count.indexOf('Total: ') > -1 && raw_count.indexOf('Enabled: ')) { + // Total: {total_count} Enabled: {enabled_count}" format detected + const totalRegex = /Total: (\d+)/; + const enabledRegex = /Enabled: (\d+)/; + const totalMatch = raw_count.match(totalRegex); + const enabledMatch = raw_count.match(enabledRegex); + + // check if both the total and enabled values were found + if (totalMatch && enabledMatch) { + // return the data formatted as an object + return { + total: totalMatch[1], + enabled: enabledMatch[1] + }; + } else { + // the data is in an unrecognized format + return raw_count; + } + } else { + // the data is in an unrecognized format + return raw_count; + } + } + } else { + // no data returned, so nothing to fix + return raw_count; + } +} + module.exports = { convert_to_satoshi: function(amount, cb) { // fix to 8dp & convert to string @@ -358,7 +408,7 @@ module.exports = { if (response == 'There was an error. Check your console.') return cb(null); else - return cb(response); + return cb(normalizeMasternodeCount(response)); }); } else { var uri = base_url + 'getmasternodecount'; @@ -368,7 +418,7 @@ module.exports = { if (body == 'There was an error. Check your console.') return cb(null); else - return cb(body); + return cb(normalizeMasternodeCount(body)); }); } } else { diff --git a/scripts/sync.js b/scripts/sync.js index a668417..c48fed6 100644 --- a/scripts/sync.js +++ b/scripts/sync.js @@ -1658,7 +1658,7 @@ if (lib.is_locked([database]) == false) { lib.syncLoop((isObject ? objectKeys : body).length, function(loop) { var i = loop.iteration(); - db.save_masternode((isObject ? body[objectKeys[i]] : body[i]), function(success) { + db.save_masternode((isObject ? body[objectKeys[i]] : body[i]), (isObject ? objectKeys[i] : null), function(success) { if (success) { // check if the script is stopping if (stopSync) { diff --git a/views/masternodes.pug b/views/masternodes.pug index f0f3215..86960df 100644 --- a/views/masternodes.pug +++ b/views/masternodes.pug @@ -27,7 +27,18 @@ block content return ('0' + dy).slice(-2) + " day" + (('0' + dy).slice(-2) == 1 ? "" : "s") + " " + ('0' + h).slice(-2) + "h " + ('0' + m).slice(-2) + "m " + ('0' + s).slice(-2) + "s"; } $(document).ready(function() { - var useNewDashFormat = false; + var enabled_columns = { + rank: false, + network: false, + status : false, + addr: false, + version : false, + lastseen: false, + activetime: false, + lastpaid: false, + ip_address: false, + last_paid_block: false + }; var labels = !{JSON.stringify(settings.labels)}; var ctable = $('#masternodes-table').dataTable({ autoWidth: true, @@ -50,11 +61,42 @@ block content url: '/ext/getmasternodelist', dataSrc: function(json) { for (i = 0; i < json.length; i++) { - var addr = json[i]['addr']; - json[i]['address'] = "" + json[i]['address'] + ""; - json[i]['lastseen'] = '' + format_unixtime(json[i]['lastseen']) + ''; + if (json[i]['rank'] != null && json[i]['rank'] > 0) + enabled_columns.rank = true; - if (typeof json[i]['lastpaid'] != 'undefined' && json[i]['lastpaid'] != '' && json[i]['lastpaid'] != '0') + if (json[i]['network'] != null && json[i]['network'] != '') + enabled_columns.network = true; + + if (json[i]['ip_address'] != null && json[i]['ip_address'] != '') + enabled_columns.ip_address = true; + + if (json[i]['version'] != null && json[i]['version'] > 0) + enabled_columns.version = true; + + if (json[i]['lastseen'] != null && json[i]['lastseen'] > 0) + enabled_columns.lastseen = true; + + if (json[i]['lastpaid'] != null && json[i]['lastpaid'] > 0) + enabled_columns.lastpaid = true; + + if (json[i]['last_paid_block'] != null && json[i]['last_paid_block'] > 0) + enabled_columns.last_paid_block = true; + + if (json[i]['activetime'] != null && json[i]['activetime'] > 0) + enabled_columns.activetime = true; + + if (json[i]['status'] != null && json[i]['status'] != '') + enabled_columns.status = true; + + if (json[i]['addr'] != null && json[i]['addr'] != '') + enabled_columns.addr = true; + + var addr = json[i]['addr']; + + if (json[i]['lastseen'] != null) + json[i]['lastseen'] = '' + format_unixtime(json[i]['lastseen']) + ''; + + if (json[i]['lastpaid'] != null && json[i]['lastpaid'] != '' && json[i]['lastpaid'] != '0') json[i]['lastpaid'] = '' + format_unixtime(json[i]['lastpaid']) + ''; else json[i]['lastpaid'] = 'N/A'; @@ -62,6 +104,7 @@ block content json[i]['activetime'] = secondsToHms(json[i]['activetime']); else json[i]['activetime'] = 'N/A'; + json[i]['addr'] = "" + json[i]['addr'] + ('#{settings.claim_address_page.enabled}' == 'true' && json[i]['claim_name'] != null && json[i]['claim_name'] != '' ? ' (' + json[i]['claim_name'] + ')' : '') + ""; if (labels[addr] != null && labels[addr].enabled == true) { @@ -71,16 +114,14 @@ block content json[i]['addr'] = '
' + json[i]['addr']; } } - - useNewDashFormat = json.length > 0 && json[0].ip_address != null && json[0].ip_address != ''; - + return json; } }, columns: [ + { name: 'ip_address', data: 'ip_address', className: "ipAddressCol" }, { name: 'rank', data: 'rank', className: "rankCol" }, { name: 'network', data: 'network', className: "networkCol" }, - { name: 'ip_address', data: 'ip_address', className: "ipAddressCol" }, { name: 'addr', data: 'addr', className: "addressCol" }, { name: 'version', data: 'version', className: "versionCol" }, { name: 'lastseen', data: 'lastseen', className: "lastSeenCol" }, @@ -91,9 +132,7 @@ block content ], rowCallback: function(row, data, index) { $("td.addressCol", row).addClass("breakWord"); - - if (useNewDashFormat) - $("td.ipAddressCol", row).addClass("breakWord"); + $("td.ipAddressCol", row).addClass("breakWord"); switch (data['status'].toUpperCase()) { case 'ENABLED': @@ -103,6 +142,10 @@ block content $("td.statusCol", row).addClass('table-danger'); break; case 'EXPIRED': + case 'WATCHDOG_EXPIRED': + case 'NEW_START_REQUIRED': + case 'UPDATE_REQUIRED': + case 'POSE_BANNED': $("td.statusCol", row).addClass('table-warning'); break; default: @@ -117,20 +160,23 @@ block content }, fnInitComplete: function(settings, json) { setTimeout(function () { - // Hide/show columns based on which Dash masternode format is used - ctable.api().column('rank:name').visible(!useNewDashFormat, false); - ctable.api().column('network:name').visible(!useNewDashFormat, false); - ctable.api().column('version:name').visible(!useNewDashFormat, false); - ctable.api().column('lastseen:name').visible(!useNewDashFormat, false); - ctable.api().column('activetime:name').visible(!useNewDashFormat, false); - ctable.api().column('ip_address:name').visible(useNewDashFormat, false); - ctable.api().column('last_paid_block:name').visible(useNewDashFormat); + // Hide/show columns based on whether they have data or not + ctable.api().column('rank:name').visible(enabled_columns.rank, false); + ctable.api().column('network:name').visible(enabled_columns.network, false); + ctable.api().column('version:name').visible(enabled_columns.version, false); + ctable.api().column('lastseen:name').visible(enabled_columns.lastseen, false); + ctable.api().column('activetime:name').visible(enabled_columns.activetime, false); + ctable.api().column('ip_address:name').visible(enabled_columns.ip_address, false); + ctable.api().column('last_paid_block:name').visible(enabled_columns.last_paid_block, false); + ctable.api().column('status:name').visible(enabled_columns.status, false); + ctable.api().column('addr:name').visible(enabled_columns.addr, false); + ctable.api().column('lastpaid:name').visible(enabled_columns.lastpaid, false); }, 0); } }); if ('#{settings.masternodes_page.page_header.show_last_updated}' == 'true') { - var lastUpdatedDate = #{(last_updated == null || last_updated == '0' ? 0 : last_updated)}; + const lastUpdatedDate = #{(last_updated == null || last_updated == '0' ? 0 : last_updated)}; if (lastUpdatedDate != 0) { $('span#lastUpdatedDate').html(' ' + format_unixtime(lastUpdatedDate)); @@ -180,9 +226,9 @@ block content - theadClasses.push('table-' + settings.shared_pages.table_header_bgcolor); thead tr(class=theadClasses) + th.text-center IP address th.text-center Pay rank th.text-center Network - th.text-center IP address th.text-center Wallet address th.text-center Protocol th.text-center Last seen