Masternode improvements
-Added support for a couple masternode list and count formats that do not have a separate fieldname for each value -Masternode grid columns are now shown or hidden based on whether there is any data
This commit is contained in:
+150
-36
@@ -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);
|
||||
|
||||
+52
-2
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+68
-22
@@ -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'] = "<a href='/address/" + json[i]['address'] + "'>" + json[i]['address'] + "</a>";
|
||||
json[i]['lastseen'] = '<span' + (#{settings.shared_pages.date_time.enable_alt_timezone_tooltips} == true ? ' data-bs-toggle="tooltip" data-bs-placement="auto" title="' + format_unixtime(json[i]['lastseen'], true) + '"' : '') + '>' + format_unixtime(json[i]['lastseen']) + '</span>';
|
||||
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'] = '<span' + (#{settings.shared_pages.date_time.enable_alt_timezone_tooltips} == true ? ' data-bs-toggle="tooltip" data-bs-placement="auto" title="' + format_unixtime(json[i]['lastseen'], true) + '"' : '') + '>' + format_unixtime(json[i]['lastseen']) + '</span>';
|
||||
|
||||
if (json[i]['lastpaid'] != null && json[i]['lastpaid'] != '' && json[i]['lastpaid'] != '0')
|
||||
json[i]['lastpaid'] = '<span' + (#{settings.shared_pages.date_time.enable_alt_timezone_tooltips} == true ? ' data-bs-toggle="tooltip" data-bs-placement="auto" title="' + format_unixtime(json[i]['lastpaid'], true) + '"' : '') + '>' + format_unixtime(json[i]['lastpaid']) + '</span>';
|
||||
else
|
||||
json[i]['lastpaid'] = '<em>N/A</em>';
|
||||
@@ -62,6 +104,7 @@ block content
|
||||
json[i]['activetime'] = secondsToHms(json[i]['activetime']);
|
||||
else
|
||||
json[i]['activetime'] = '<em>N/A</em>';
|
||||
|
||||
json[i]['addr'] = "<a href='/address/" + json[i]['addr'] + "'>" + json[i]['addr'] + ('#{settings.claim_address_page.enabled}' == 'true' && json[i]['claim_name'] != null && json[i]['claim_name'] != '' ? ' <span class="small fw-normal">(' + json[i]['claim_name'] + ')</span>' : '') + "</a>";
|
||||
|
||||
if (labels[addr] != null && labels[addr].enabled == true) {
|
||||
@@ -71,16 +114,14 @@ block content
|
||||
json[i]['addr'] = '<div><label class="badge bg-default" style="margin-bottom:10px;">' + labels[addr].label + (labels[addr].url ? '<a href="' + labels[addr].url + '" target="_blank", alt="Visit site", title="Visit site" data-bs-toggle="tooltip" data-bs-placement="top"><span class="fa-solid fa-circle-question" style="margin-left:5px"></span></a>' : '') + '</label></div>' + 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
|
||||
|
||||
Reference in New Issue
Block a user