Orphan block fix + other misc improvements
-The block sync will now remove orphaned block data from the txes collecton, address balances/sent/received data as well as addresstx data and now stores limited info in a new orphans collection -Added a new optional page for viewing orphaned block data -The coinbase address now updates sent totals from POS rewards and other transactions that have vout but no vin addresses -Block and transaction pages now display a warning when viewing an orphaned block or tx -Added a couple new fields to the coinstats collection for tracking orphaned blocks -Added new locale strings for the orphaned block feature
This commit is contained in:
@@ -130,6 +130,7 @@ Table of Contents
|
||||
- **getmasternoderewards:** Returns a list of masternode reward transactions for a specific address that arrived after a specific block height *\*only applicable to masternode coins*
|
||||
- **getmasternoderewardstotal:** Returns the total number of coins earned in masternode rewards for a specific address that arrived after a specific block height *\*only applicable to masternode coins*
|
||||
- **Claim Address:** Allows anyone to set custom display names for wallet addresses that they own using the **Sign Message** feature from their local wallet. Includes *bad word* filter support.
|
||||
- **Orphaned Blocks:** Displays a list of orphaned blocks with links to the next and previous "good" blocks
|
||||
- **Block Info:** Displays block summary and list of transactions for a specific block height
|
||||
- **Transaction Info:** Displays transaction summary, optional OP_RETURN value, list of input addresses and output addresses for a specific transaction
|
||||
- **Address Info:** Displays wallet address summary (balance, total sent, total received, QR code) and a list of latest transactions for a specific wallet address
|
||||
|
||||
@@ -592,6 +592,39 @@ app.use('/ext/getmasternoderewardstotal/:hash/:since', function(req, res) {
|
||||
res.end('This method is disabled');
|
||||
});
|
||||
|
||||
// get the list of orphans from local collection
|
||||
app.use('/ext/getorphanlist/:start/:length', function(req, res) {
|
||||
// check the headers to see if it matches an internal ajax request from the explorer itself (TODO: come up with a more secure method of whitelisting ajax calls from the explorer)
|
||||
if (req.headers['x-requested-with'] != null && req.headers['x-requested-with'].toLowerCase() == 'xmlhttprequest' && req.headers.referer != null && req.headers.accept.indexOf('text/javascript') > -1 && req.headers.accept.indexOf('application/json') > -1) {
|
||||
// fix parameters
|
||||
if (typeof req.params.start === 'undefined' || isNaN(req.params.start) || req.params.start < 0)
|
||||
req.params.start = 0;
|
||||
if (typeof req.params.length === 'undefined' || isNaN(req.params.length))
|
||||
req.params.length = 10;
|
||||
|
||||
// get the orphan list from local collection
|
||||
db.get_orphans(req.params.start, req.params.length, function(orphans, count) {
|
||||
var data = [];
|
||||
|
||||
for (i = 0; i < orphans.length; i++) {
|
||||
var row = [];
|
||||
|
||||
row.push(orphans[i].blockindex);
|
||||
row.push(orphans[i].orphan_blockhash);
|
||||
row.push(orphans[i].good_blockhash);
|
||||
row.push(orphans[i].prev_blockhash);
|
||||
row.push(orphans[i].next_blockhash);
|
||||
|
||||
data.push(row);
|
||||
}
|
||||
|
||||
// display data formatted for internal datatable
|
||||
res.json({"data": data, "recordsTotal": count, "recordsFiltered": count});
|
||||
});
|
||||
} else
|
||||
res.end('This method is disabled');
|
||||
});
|
||||
|
||||
app.use('/ext/getnetworkchartdata', function(req, res) {
|
||||
db.get_network_chart_data(function(data) {
|
||||
if (data)
|
||||
@@ -766,6 +799,7 @@ app.set('richlist_page', settings.richlist_page);
|
||||
app.set('markets_page', settings.markets_page);
|
||||
app.set('api_page', settings.api_page);
|
||||
app.set('claim_address_page', settings.claim_address_page);
|
||||
app.set('orphans_page', settings.orphans_page);
|
||||
app.set('labels', settings.labels);
|
||||
app.set('api_cmds', settings.api_cmds);
|
||||
app.set('blockchain_specific', settings.blockchain_specific);
|
||||
|
||||
+30
-5
@@ -5,6 +5,7 @@ var mongoose = require('mongoose'),
|
||||
Address = require('../models/address'),
|
||||
AddressTx = require('../models/addresstx'),
|
||||
Tx = require('../models/tx'),
|
||||
Orphans = require('../models/orphans'),
|
||||
Richlist = require('../models/richlist'),
|
||||
Peers = require('../models/peers'),
|
||||
Heavy = require('../models/heavy'),
|
||||
@@ -403,7 +404,13 @@ module.exports = {
|
||||
// collection has data
|
||||
// determine if last_usd_price field exists
|
||||
check_add_db_field(Stats, 'last_usd_price', 0, function(exists) {
|
||||
return cb(true);
|
||||
// determine if orphan_index field exists
|
||||
check_add_db_field(Stats, 'orphan_index', 0, function(exists) {
|
||||
// determine if orphan_current field exists
|
||||
check_add_db_field(Stats, 'orphan_current', 0, function(exists) {
|
||||
return cb(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
} else
|
||||
return cb(false);
|
||||
@@ -424,7 +431,9 @@ module.exports = {
|
||||
if (!skip) {
|
||||
var newStats = new Stats({
|
||||
coin: coin,
|
||||
last: 0
|
||||
last: 0,
|
||||
orphan_index: 0,
|
||||
orphan_current: 0
|
||||
});
|
||||
|
||||
newStats.save(function(err) {
|
||||
@@ -1068,7 +1077,9 @@ module.exports = {
|
||||
supply: (supply ? supply : 0),
|
||||
connections: (connections ? connections : 0),
|
||||
last: (stats.last ? stats.last : 0),
|
||||
txes: (stats.txes ? stats.txes : 0)
|
||||
txes: (stats.txes ? stats.txes : 0),
|
||||
orphan_index: (stats.orphan_index ? stats.orphan_index : 0),
|
||||
orphan_current: (stats.orphan_current ? stats.orphan_current : 0)
|
||||
});
|
||||
});
|
||||
} else {
|
||||
@@ -1511,7 +1522,7 @@ module.exports = {
|
||||
if (tx && tx != 'There was an error. Check your console.') {
|
||||
lib.prepare_vin(tx, function(vin, tx_type_vin) {
|
||||
lib.prepare_vout(tx.vout, txid, vin, ((!settings.blockchain_specific.zksnarks.enabled || typeof tx.vjoinsplit === 'undefined' || tx.vjoinsplit == null) ? [] : tx.vjoinsplit), function(vout, nvin, tx_type_vout) {
|
||||
lib.syncLoop(vin.length, function (loop) {
|
||||
lib.syncLoop(nvin.length, function (loop) {
|
||||
var i = loop.iteration();
|
||||
|
||||
// check if address is inside an array
|
||||
@@ -1556,7 +1567,7 @@ module.exports = {
|
||||
|
||||
var newTx = new Tx({
|
||||
txid: tx.txid,
|
||||
vin: nvin,
|
||||
vin: (vin == null || vin.length == 0 ? [] : nvin),
|
||||
vout: vout,
|
||||
total: total.toFixed(8),
|
||||
timestamp: tx.time,
|
||||
@@ -1582,5 +1593,19 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
// get the list of orphans from local collection
|
||||
get_orphans: function(start, length, cb) {
|
||||
// get the count of orphaned blocks
|
||||
Orphans.find({}).countDocuments(function(err, count) {
|
||||
// get the actual orphaned block data
|
||||
Orphans.find({}).sort({blockindex: -1}).skip(Number(start)).limit(Number(length)).exec(function(err, orphans) {
|
||||
if (err)
|
||||
return cb([], count);
|
||||
else
|
||||
return cb(orphans, count);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
fs: fs
|
||||
};
|
||||
+21
-1
@@ -1202,7 +1202,27 @@ module.exports = {
|
||||
arr_vout[0].amount = arr_vout[0].amount - arr_vin[0].amount;
|
||||
arr_vin.shift();
|
||||
|
||||
return cb(arr_vout, arr_vin, tx_type);
|
||||
// check if any vin remains
|
||||
if (arr_vin == null || arr_vin.length == 0) {
|
||||
// empty vin should be linked to coinbase
|
||||
arr_vin = [{coinbase: "coinbase"}];
|
||||
|
||||
var new_vout = [];
|
||||
|
||||
// loop through the arr_vout to create a copy of the data with coin amounts only for use with prepare_vin()
|
||||
for (i = 0; i < arr_vout.length; i++) {
|
||||
new_vout.push({
|
||||
value: arr_vout[i].amount / 100000000
|
||||
});
|
||||
}
|
||||
|
||||
// call the prepare_vin again to populate the vin data correctly
|
||||
module.exports.prepare_vin({txid: txid, vin: arr_vin, vout: new_vout}, function(return_vin, return_tx_type_vin) {
|
||||
return cb(arr_vout, return_vin, return_tx_type_vin);
|
||||
});
|
||||
} else {
|
||||
return cb(arr_vout, arr_vin, tx_type);
|
||||
}
|
||||
} else
|
||||
return cb(arr_vout, arr_vin, tx_type);
|
||||
} else
|
||||
|
||||
@@ -16,6 +16,7 @@ exports.menu_movement = "Movement",
|
||||
exports.menu_node = "Nodes",
|
||||
exports.menu_network = "Network",
|
||||
exports.menu_claim_address = "Claim Address",
|
||||
exports.menu_orphans = "Orphaned Blocks",
|
||||
|
||||
exports.ex_title = "{1} Block Explorer",
|
||||
exports.ex_description = "A listing of all verified {1} transactions",
|
||||
@@ -166,6 +167,16 @@ exports.mkt_select = "Market Select",
|
||||
exports.claim_title = "{1} Wallet Address Claim",
|
||||
exports.claim_description = "Verify ownership of your {1} wallet address and set a custom display name in the explorer",
|
||||
|
||||
// Orphans view
|
||||
exports.orphan_title = "{1} Orphaned Blocks",
|
||||
exports.orphan_description = "A listing of valid blocks that have been orphaned and do not belong to the main blockchain",
|
||||
exports.orphan_block_list = "Orphaned Block List",
|
||||
exports.orphan_block_hash = "Orphaned Block Hash",
|
||||
exports.orphan_actual_block = "Actual Block",
|
||||
exports.orphan_prev_block = "Previous Block",
|
||||
exports.orphan_next_block = "Next Block",
|
||||
exports.view_orphan = "View Orphaned Block",
|
||||
|
||||
// Heavycoin
|
||||
exports.heavy_vote = "Vote",
|
||||
// Heavycoin rewards view
|
||||
|
||||
@@ -1184,6 +1184,38 @@ exports.claim_address_page = {
|
||||
"enable_bad_word_filter": true
|
||||
};
|
||||
|
||||
// orphans_page: a collection of settings that pertain to the orphans page
|
||||
exports.orphans_page = {
|
||||
// enabled: Enable/disable the orphans page (true/false)
|
||||
// If set to false, the orphans page will be completely inaccessible
|
||||
"enabled": false,
|
||||
// show_panels: Determine whether to show the panels configured in the shared_pages.page_header section across the top of this page (true/false)
|
||||
"show_panels": false,
|
||||
// show_nethash_chart: Determine whether to show the network hashrate chart configured in the shared_pages.network_charts.nethash_chart section across the top of this page (true/false)
|
||||
"show_nethash_chart": false,
|
||||
// show_difficulty_chart: Determine whether to show the network difficulty chart configured in the shared_pages.network_charts.difficulty_chart section across the top of this page (true/false)
|
||||
"show_difficulty_chart": false,
|
||||
// page_header: a collection of settings that pertain to the orphans page header
|
||||
"page_header": {
|
||||
// show_img: Determine whether to show the page title image defined in the "shared_pages.page_header.page_title_image" setting (true/false)
|
||||
"show_img": true,
|
||||
// show_title: Determine whether to show the page title as defined in "locale.orphan_title" (true/false)
|
||||
"show_title": true,
|
||||
// show_last_updated: Determine whether to show a label below the page title with the last updated date (true/false)
|
||||
"show_last_updated": true,
|
||||
// show_description: Determine whether to show the page description as defined in "locale.orphan_description" (true/false)
|
||||
"show_description": true
|
||||
},
|
||||
// orphans_table: a collection of settings that pertain to the orphans table on the orphans page
|
||||
// Table data is populated via the /ext/getorphanlist api
|
||||
"orphans_table": {
|
||||
// page_length_options: An array of page length options that determine how many items/records to display in the table at any given time
|
||||
"page_length_options": [ 10, 25, 50, 75, 100, 250, 500, 1000 ],
|
||||
// items_per_page: The default amount of items/records to display in the table at any given time
|
||||
"items_per_page": 10
|
||||
}
|
||||
};
|
||||
|
||||
// sync: a collection of settings that pertain to the data synchronization process
|
||||
exports.sync = {
|
||||
// block_parallel_tasks: Use multiple threads to do blockchain syncing which greatly improves the initial sync speed, but there is a drawback.
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"menu_node": "Nodes",
|
||||
"menu_network": "Network",
|
||||
"menu_claim_address": "Claim Address",
|
||||
"menu_orphans": "Orphaned Blocks",
|
||||
|
||||
// explorer view
|
||||
"ex_title": "{1} Block Explorer",
|
||||
@@ -169,6 +170,16 @@
|
||||
"claim_title": "{1} Wallet Address Claim",
|
||||
"claim_description": "Verify ownership of your {1} wallet address and set a custom display name in the explorer",
|
||||
|
||||
// orphans view
|
||||
"orphan_title": "{1} Orphaned Blocks",
|
||||
"orphan_description": "A listing of valid blocks that have been orphaned and do not belong to the main blockchain",
|
||||
"orphan_block_list": "Orphaned Block List",
|
||||
"orphan_block_hash": "Orphaned Block Hash",
|
||||
"orphan_actual_block": "Actual Block",
|
||||
"orphan_prev_block": "Previous Block",
|
||||
"orphan_next_block": "Next Block",
|
||||
"view_orphan": "View Orphaned Block",
|
||||
|
||||
// heavycoin rewards view
|
||||
"heavy_title": "{1} Reward/Voting Details",
|
||||
"heavy_description": "Viewing {1} voting data and coin reward change details",
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
var mongoose = require('mongoose'),
|
||||
Schema = mongoose.Schema;
|
||||
|
||||
var OrphanSchema = new Schema({
|
||||
blockindex: {type: Number, default: 0, index: true},
|
||||
orphan_blockhash: {type: String, unique: true, index: true},
|
||||
good_blockhash: {type: String, index: true},
|
||||
prev_blockhash: {type: String, index: true},
|
||||
next_blockhash: {type: String, index: true}
|
||||
}, {id: false});
|
||||
|
||||
module.exports = mongoose.model('Orphan', OrphanSchema);
|
||||
+3
-1
@@ -15,7 +15,9 @@ var StatsSchema = new Schema({
|
||||
masternodes_last_updated: { type: Number, default: 0 },
|
||||
network_last_updated: { type: Number, default: 0 },
|
||||
richlist_last_updated: { type: Number, default: 0 },
|
||||
markets_last_updated: { type: Number, default: 0 }
|
||||
markets_last_updated: { type: Number, default: 0 },
|
||||
orphan_index: { type: Number, default: 0 },
|
||||
orphan_current: { type: Number, default: 0 }
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('coinstats', StatsSchema);
|
||||
+135
-81
@@ -24,7 +24,10 @@ function route_get_block(res, blockhash) {
|
||||
page_title_prefix: settings.coin.name + ' Genesis Block'
|
||||
}
|
||||
);
|
||||
else {
|
||||
else if (block.confirmations == -1) {
|
||||
// this is an orphaned block, so get the data from the wallet directly
|
||||
get_block_data_from_wallet(block, res, true);
|
||||
} else {
|
||||
db.get_txs(block, function(txs) {
|
||||
if (txs.length > 0)
|
||||
res.render(
|
||||
@@ -43,45 +46,7 @@ function route_get_block(res, blockhash) {
|
||||
);
|
||||
else {
|
||||
// cannot find block in local database so get the data from the wallet directly
|
||||
var ntxs = [];
|
||||
|
||||
lib.syncLoop(block.tx.length, function (loop) {
|
||||
var i = loop.iteration();
|
||||
|
||||
lib.get_rawtransaction(block.tx[i], function(tx) {
|
||||
if (tx && tx != 'There was an error. Check your console.') {
|
||||
lib.prepare_vin(tx, function(vin, tx_type_vin) {
|
||||
lib.prepare_vout(tx.vout, block.tx[i], vin, ((!settings.blockchain_specific.zksnarks.enabled || typeof tx.vjoinsplit === 'undefined' || tx.vjoinsplit == null) ? [] : tx.vjoinsplit), function(vout, nvin, tx_type_vout) {
|
||||
lib.calculate_total(vout, function(total) {
|
||||
ntxs.push({
|
||||
txid: block.tx[i],
|
||||
vout: vout,
|
||||
total: total.toFixed(8)
|
||||
});
|
||||
|
||||
loop.next();
|
||||
});
|
||||
});
|
||||
});
|
||||
} else
|
||||
loop.next();
|
||||
});
|
||||
}, function() {
|
||||
res.render(
|
||||
'block',
|
||||
{
|
||||
active: 'block',
|
||||
block: block,
|
||||
confirmations: settings.shared_pages.confirmations,
|
||||
txs: ntxs,
|
||||
showSync: db.check_show_sync_message(),
|
||||
customHash: get_file_timestamp('./public/css/custom.scss'),
|
||||
styleHash: get_file_timestamp('./public/css/style.scss'),
|
||||
themeHash: get_file_timestamp('./public/css/themes/' + settings.shared_pages.theme.toLowerCase() + '/bootstrap.min.css'),
|
||||
page_title_prefix: settings.coin.name + ' Block ' + block.height
|
||||
}
|
||||
);
|
||||
});
|
||||
get_block_data_from_wallet(block, res, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -157,48 +122,57 @@ function route_get_tx(res, txid) {
|
||||
lib.prepare_vout(rtx.vout, rtx.txid, vin, ((!settings.blockchain_specific.zksnarks.enabled || typeof rtx.vjoinsplit === 'undefined' || rtx.vjoinsplit == null) ? [] : rtx.vjoinsplit), function(rvout, rvin, tx_type_vout) {
|
||||
lib.calculate_total(rvout, function(total) {
|
||||
if (!rtx.confirmations > 0) {
|
||||
var utx = {
|
||||
txid: rtx.txid,
|
||||
vin: rvin,
|
||||
vout: rvout,
|
||||
total: total.toFixed(8),
|
||||
timestamp: rtx.time,
|
||||
blockhash: '-',
|
||||
blockindex: -1
|
||||
};
|
||||
lib.get_block(rtx.blockhash, function(block) {
|
||||
if (block && block != 'There was an error. Check your console.') {
|
||||
var utx = {
|
||||
txid: rtx.txid,
|
||||
vin: rvin,
|
||||
vout: rvout,
|
||||
total: total.toFixed(8),
|
||||
timestamp: (rtx.time == null ? block.time : rtx.time),
|
||||
blockhash: (rtx.blockhash == null ? '-' : rtx.blockhash),
|
||||
blockindex: block.height
|
||||
};
|
||||
|
||||
if (settings.claim_address_page.enabled == true) {
|
||||
db.populate_claim_address_names(utx, function(utx) {
|
||||
res.render(
|
||||
'tx',
|
||||
{
|
||||
active: 'tx',
|
||||
tx: utx,
|
||||
confirmations: settings.shared_pages.confirmations,
|
||||
blockcount: -1,
|
||||
showSync: db.check_show_sync_message(),
|
||||
customHash: get_file_timestamp('./public/css/custom.scss'),
|
||||
styleHash: get_file_timestamp('./public/css/style.scss'),
|
||||
themeHash: get_file_timestamp('./public/css/themes/' + settings.shared_pages.theme.toLowerCase() + '/bootstrap.min.css'),
|
||||
page_title_prefix: settings.coin.name + ' Transaction ' + utx.txid
|
||||
}
|
||||
);
|
||||
});
|
||||
} else
|
||||
res.render(
|
||||
'tx',
|
||||
{
|
||||
active: 'tx',
|
||||
tx: utx,
|
||||
confirmations: settings.shared_pages.confirmations,
|
||||
blockcount: -1,
|
||||
showSync: db.check_show_sync_message(),
|
||||
customHash: get_file_timestamp('./public/css/custom.scss'),
|
||||
styleHash: get_file_timestamp('./public/css/style.scss'),
|
||||
themeHash: get_file_timestamp('./public/css/themes/' + settings.shared_pages.theme.toLowerCase() + '/bootstrap.min.css'),
|
||||
page_title_prefix: settings.coin.name + ' Transaction ' + utx.txid
|
||||
}
|
||||
);
|
||||
if (settings.claim_address_page.enabled == true) {
|
||||
db.populate_claim_address_names(utx, function(utx) {
|
||||
res.render(
|
||||
'tx',
|
||||
{
|
||||
orphan: true,
|
||||
active: 'tx',
|
||||
tx: utx,
|
||||
confirmations: settings.shared_pages.confirmations,
|
||||
blockcount: (block.height - 1),
|
||||
showSync: db.check_show_sync_message(),
|
||||
customHash: get_file_timestamp('./public/css/custom.scss'),
|
||||
styleHash: get_file_timestamp('./public/css/style.scss'),
|
||||
themeHash: get_file_timestamp('./public/css/themes/' + settings.shared_pages.theme.toLowerCase() + '/bootstrap.min.css'),
|
||||
page_title_prefix: settings.coin.name + ' Transaction ' + utx.txid
|
||||
}
|
||||
);
|
||||
});
|
||||
} else
|
||||
res.render(
|
||||
'tx',
|
||||
{
|
||||
orphan: true,
|
||||
active: 'tx',
|
||||
tx: utx,
|
||||
confirmations: settings.shared_pages.confirmations,
|
||||
blockcount: (block.height - 1),
|
||||
showSync: db.check_show_sync_message(),
|
||||
customHash: get_file_timestamp('./public/css/custom.scss'),
|
||||
styleHash: get_file_timestamp('./public/css/style.scss'),
|
||||
themeHash: get_file_timestamp('./public/css/themes/' + settings.shared_pages.theme.toLowerCase() + '/bootstrap.min.css'),
|
||||
page_title_prefix: settings.coin.name + ' Transaction ' + utx.txid
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// cannot load tx
|
||||
route_get_index(res, null);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// check if blockheight exists
|
||||
if (!rtx.blockheight && rtx.blockhash) {
|
||||
@@ -418,6 +392,62 @@ function route_get_claim_form(res, hash) {
|
||||
route_get_address(res, hash);
|
||||
}
|
||||
|
||||
function get_last_updated_date(show_last_updated, last_updated_field, cb) {
|
||||
// check if the last updated date is needed
|
||||
if (show_last_updated == true) {
|
||||
// lookup the stats record
|
||||
db.get_stats(settings.coin.name, function (stats) {
|
||||
// return the last updated date
|
||||
return cb(stats[last_updated_field]);
|
||||
});
|
||||
} else {
|
||||
return cb(null);
|
||||
}
|
||||
}
|
||||
|
||||
function get_block_data_from_wallet(block, res, orphan) {
|
||||
var ntxs = [];
|
||||
|
||||
lib.syncLoop(block.tx.length, function (loop) {
|
||||
var i = loop.iteration();
|
||||
|
||||
lib.get_rawtransaction(block.tx[i], function(tx) {
|
||||
if (tx && tx != 'There was an error. Check your console.') {
|
||||
lib.prepare_vin(tx, function(vin, tx_type_vin) {
|
||||
lib.prepare_vout(tx.vout, block.tx[i], vin, ((!settings.blockchain_specific.zksnarks.enabled || typeof tx.vjoinsplit === 'undefined' || tx.vjoinsplit == null) ? [] : tx.vjoinsplit), function(vout, nvin, tx_type_vout) {
|
||||
lib.calculate_total(vout, function(total) {
|
||||
ntxs.push({
|
||||
txid: block.tx[i],
|
||||
vout: vout,
|
||||
total: total.toFixed(8)
|
||||
});
|
||||
|
||||
loop.next();
|
||||
});
|
||||
});
|
||||
});
|
||||
} else
|
||||
loop.next();
|
||||
});
|
||||
}, function() {
|
||||
res.render(
|
||||
'block',
|
||||
{
|
||||
orphan: orphan,
|
||||
active: 'block',
|
||||
block: block,
|
||||
confirmations: settings.shared_pages.confirmations,
|
||||
txs: ntxs,
|
||||
showSync: db.check_show_sync_message(),
|
||||
customHash: get_file_timestamp('./public/css/custom.scss'),
|
||||
styleHash: get_file_timestamp('./public/css/style.scss'),
|
||||
themeHash: get_file_timestamp('./public/css/themes/' + settings.shared_pages.theme.toLowerCase() + '/bootstrap.min.css'),
|
||||
page_title_prefix: settings.coin.name + ' Block ' + block.height
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/* GET home page. */
|
||||
|
||||
router.get('/', function(req, res) {
|
||||
@@ -770,6 +800,30 @@ router.get('/address/:hash', function(req, res) {
|
||||
route_get_address(res, req.params.hash);
|
||||
});
|
||||
|
||||
router.get('/orphans', function(req, res) {
|
||||
// ensure orphans page is enabled
|
||||
if (settings.orphans_page.enabled == true) {
|
||||
// lookup the last updated date if necessary
|
||||
get_last_updated_date(settings.orphans_page.page_header.show_last_updated, 'blockchain_last_updated', function(last_updated_date) {
|
||||
res.render(
|
||||
'orphans',
|
||||
{
|
||||
active: 'orphans',
|
||||
last_updated: last_updated_date,
|
||||
showSync: db.check_show_sync_message(),
|
||||
customHash: get_file_timestamp('./public/css/custom.scss'),
|
||||
styleHash: get_file_timestamp('./public/css/style.scss'),
|
||||
themeHash: get_file_timestamp('./public/css/themes/' + settings.shared_pages.theme.toLowerCase() + '/bootstrap.min.css'),
|
||||
page_title_prefix: locale.orphan_title.replace('{1}', settings.coin.name)
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// orphans page is not enabled so default to the index page
|
||||
route_get_index(res, null);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/search', function(req, res) {
|
||||
if (settings.shared_pages.page_header.search.enabled == true) {
|
||||
var query = req.body.search.trim();
|
||||
|
||||
+823
-71
File diff suppressed because it is too large
Load Diff
@@ -1268,6 +1268,38 @@
|
||||
"enable_bad_word_filter": true
|
||||
},
|
||||
|
||||
// orphans_page: a collection of settings that pertain to the orphans page
|
||||
"orphans_page": {
|
||||
// enabled: Enable/disable the orphans page (true/false)
|
||||
// If set to false, the orphans page will be completely inaccessible
|
||||
"enabled": true,
|
||||
// show_panels: Determine whether to show the panels configured in the shared_pages.page_header section across the top of this page (true/false)
|
||||
"show_panels": false,
|
||||
// show_nethash_chart: Determine whether to show the network hashrate chart configured in the shared_pages.network_charts.nethash_chart section across the top of this page (true/false)
|
||||
"show_nethash_chart": false,
|
||||
// show_difficulty_chart: Determine whether to show the network difficulty chart configured in the shared_pages.network_charts.difficulty_chart section across the top of this page (true/false)
|
||||
"show_difficulty_chart": false,
|
||||
// page_header: a collection of settings that pertain to the orphans page header
|
||||
"page_header": {
|
||||
// show_img: Determine whether to show the page title image defined in the "shared_pages.page_header.page_title_image" setting (true/false)
|
||||
"show_img": true,
|
||||
// show_title: Determine whether to show the page title as defined in "locale.orphan_title" (true/false)
|
||||
"show_title": true,
|
||||
// show_last_updated: Determine whether to show a label below the page title with the last updated date (true/false)
|
||||
"show_last_updated": true,
|
||||
// show_description: Determine whether to show the page description as defined in "locale.orphan_description" (true/false)
|
||||
"show_description": true
|
||||
},
|
||||
// orphans_table: a collection of settings that pertain to the orphans table on the orphans page
|
||||
// Table data is populated via the /ext/getorphanlist api
|
||||
"orphans_table": {
|
||||
// page_length_options: An array of page length options that determine how many items/records to display in the table at any given time
|
||||
"page_length_options": [ 10, 25, 50, 75, 100, 250, 500, 1000 ],
|
||||
// items_per_page: The default amount of items/records to display in the table at any given time
|
||||
"items_per_page": 10
|
||||
}
|
||||
},
|
||||
|
||||
// sync: a collection of settings that pertain to the data synchronization process
|
||||
"sync": {
|
||||
// block_parallel_tasks: Use multiple threads to do blockchain syncing which greatly improves the initial sync speed, but there is a drawback.
|
||||
|
||||
@@ -30,6 +30,14 @@ block content
|
||||
startRotateElement('img#header-img');
|
||||
});
|
||||
.col-xs-12.col-md-12
|
||||
if orphan != null && orphan == true
|
||||
.col-12
|
||||
.alert.alert-warning.alert-dismissible.fade.show(role='alert')
|
||||
button.btn-close(type='button', data-bs-dismiss='alert')
|
||||
.cardSpacer
|
||||
span.fas.fa-exclamation-triangle(style='margin-right:5px')
|
||||
strong=settings.locale.ex_warning
|
||||
div="This is an orphaned block"
|
||||
if settings.block_page.page_header.show_img == true || settings.block_page.page_header.show_title == true || settings.block_page.page_header.show_description == true
|
||||
#page-header-container(style='align-items:' + (settings.block_page.page_header.show_img == true && settings.block_page.page_header.show_title == true && settings.block_page.page_header.show_description == true ? 'flex-start' : 'center'))
|
||||
if settings.block_page.page_header.show_img == true
|
||||
|
||||
@@ -117,6 +117,13 @@ html(lang='en')
|
||||
- showNethashChart = true
|
||||
if settings.claim_address_page.show_difficulty_chart == true
|
||||
- showDifficultyChart = true
|
||||
when 'orphans'
|
||||
if settings.orphans_page.show_panels == true
|
||||
- showPanels = true
|
||||
if settings.orphans_page.show_nethash_chart == true
|
||||
- showNethashChart = true
|
||||
if settings.orphans_page.show_difficulty_chart == true
|
||||
- showDifficultyChart = true
|
||||
when 'reward'
|
||||
if settings.blockchain_specific.heavycoin.reward_page.show_panels == true
|
||||
- showPanels = true
|
||||
@@ -1135,6 +1142,11 @@ html(lang='en')
|
||||
a.nav-link(href='/claim')
|
||||
span.far.fa-address-card
|
||||
span.margin-left-5 #{settings.locale.menu_claim_address}
|
||||
if settings.orphans_page.enabled == true
|
||||
li#orphans.nav-item
|
||||
a.nav-link(href='/orphans')
|
||||
span.far.fa-window-close
|
||||
span.margin-left-5 #{settings.locale.menu_orphans}
|
||||
if settings.shared_pages.page_header.search.enabled == true && settings.shared_pages.page_header.search.position.toString().toLowerCase() == 'inside-header'
|
||||
span#search-header-span(alt='Search', title='Search', data-bs-toggle='tooltip', data-bs-placement='left')
|
||||
button#search-header-button(data-bs-toggle='collapse', data-bs-target='#search-navbar-collapse')
|
||||
@@ -1247,6 +1259,11 @@ html(lang='en')
|
||||
a.nav-link(href='/claim')
|
||||
span.nav-icon.far.fa-address-card
|
||||
span.margin-left-5 #{settings.locale.menu_claim_address}
|
||||
if settings.orphans_page.enabled == true
|
||||
li#orphans.nav-item(alt=settings.locale.menu_orphans, title=settings.locale.menu_orphans, data-bs-toggle='tooltip', data-bs-placement='right')
|
||||
a.nav-link(href='/orphans')
|
||||
span.nav-icon.far.fa-window-close
|
||||
span.margin-left-5 #{settings.locale.menu_orphans}
|
||||
div#side-offcanvas.offcanvas.offcanvas-start(tabindex='-1')
|
||||
div.offcanvas-body.d-block.navbar(class=sideBarClasses)
|
||||
div#main-container(class=mainContainerClasses)
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
extends layout
|
||||
|
||||
block content
|
||||
include ./includes/common.pug
|
||||
script.
|
||||
var setting_txPerPage = parseInt("#{settings.orphans_page.orphans_table.items_per_page}");
|
||||
var lengthMenuOpts = !{JSON.stringify(settings.orphans_page.orphans_table.page_length_options)};
|
||||
var addedLength = false;
|
||||
for (i = 0; i < lengthMenuOpts.length; i++) {
|
||||
if (!addedLength) {
|
||||
if (lengthMenuOpts[i] > setting_txPerPage) {
|
||||
lengthMenuOpts.splice(i, 0, setting_txPerPage);
|
||||
addedLength = true;
|
||||
} else if (lengthMenuOpts[i] == setting_txPerPage)
|
||||
addedLength = true;
|
||||
}
|
||||
}
|
||||
if (!addedLength && setting_txPerPage != lengthMenuOpts[lengthMenuOpts.length - 1])
|
||||
lengthMenuOpts.push(setting_txPerPage);
|
||||
$(document).ready(function() {
|
||||
var otable = $('#orphans-table').dataTable({
|
||||
autoWidth: true,
|
||||
searching: false,
|
||||
ordering: false,
|
||||
lengthChange: true,
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
iDisplayLength: setting_txPerPage,
|
||||
lengthMenu: lengthMenuOpts,
|
||||
scrollX: true,
|
||||
ajax: {
|
||||
url: '/ext/getorphanlist',
|
||||
beforeSend: function(jqXHR, settings) {
|
||||
settings.url = settings.url.substring(0, settings.url.indexOf('?')) + '/' + getParameterByName('start', settings.url) + '/' + getParameterByName('length', settings.url);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
language: {
|
||||
paginate: {
|
||||
previous: '<',
|
||||
next: '>'
|
||||
}
|
||||
},
|
||||
rowCallback: function(row, data, index) {
|
||||
var blockindex = data[0];
|
||||
var orphan_blockhash = data[1];
|
||||
var good_blockhash = data[2];
|
||||
var prev_blockhash = data[3];
|
||||
var next_blockhash = data[4];
|
||||
$("td:eq(0)", row).html('<a href="/block/' + orphan_blockhash + '"><span class="fa fa-eye" data-bs-toggle="tooltip" data-bs-placement="top" title="#{settings.locale.view_orphan}"></span></a>').addClass('text-center d-table-cell d-md-none');
|
||||
$("td:eq(1)", row).html('<a href="/block/' + orphan_blockhash + '">' + orphan_blockhash + '</a>').addClass('breakWord d-none d-md-table-cell');
|
||||
$("td:eq(2)", row).html('<a href="/block/' + good_blockhash + '">' + blockindex.toString() + '</a>').addClass('text-center');
|
||||
$("td:eq(3)", row).html('<a href="/block/' + prev_blockhash + '">' + (blockindex - 1).toString() + '</a>').addClass('text-center');
|
||||
|
||||
if (next_blockhash == null)
|
||||
$("td:eq(4)", row).html(' ');
|
||||
else
|
||||
$("td:eq(4)", row).html('<a href="/block/' + next_blockhash + '">' + (blockindex + 1).toString() + '</a>').addClass('text-center');
|
||||
},
|
||||
fnDrawCallback: function(settings) {
|
||||
fixDataTableColumns();
|
||||
fixFooterHeightAndPosition();
|
||||
enableTooltips();
|
||||
}
|
||||
});
|
||||
|
||||
if ('#{settings.orphans_page.page_header.show_last_updated}' == 'true') {
|
||||
var lastUpdatedDate = #{(last_updated == null || last_updated == '0' ? 0 : last_updated)};
|
||||
|
||||
if (lastUpdatedDate != 0) {
|
||||
$('span#lastUpdatedDate').html(' ' + format_unixtime(lastUpdatedDate));
|
||||
|
||||
if (#{settings.shared_pages.date_time.enable_alt_timezone_tooltips} == true) {
|
||||
$('span#lastUpdatedDate').attr('data-bs-toggle', 'tooltip').attr('data-bs-placement', 'auto').attr('title', format_unixtime(lastUpdatedDate, true));
|
||||
enableTooltips();
|
||||
}
|
||||
} else
|
||||
$('span#lastUpdatedDate').html(' N/A');
|
||||
}
|
||||
if (#{settings.shared_pages.page_header.page_title_image.enable_animation} == true && #{settings.orphans_page.page_header.show_img} == true)
|
||||
startRotateElement('img#header-img');
|
||||
});
|
||||
.col-md-12
|
||||
if settings.orphans_page.page_header.show_img == true || settings.orphans_page.page_header.show_title == true || settings.orphans_page.page_header.show_last_updated == true || settings.orphans_page.page_header.show_description == true
|
||||
#page-header-container(style='align-items:' + (settings.orphans_page.page_header.show_img == true && settings.orphans_page.page_header.show_title == true && settings.orphans_page.page_header.show_last_updated == true && settings.orphans_page.page_header.show_description == true ? 'flex-start' : 'center'))
|
||||
if settings.orphans_page.page_header.show_img == true
|
||||
#header-img-container
|
||||
img#header-img(src=(settings.shared_pages.page_header.page_title_image == null || settings.shared_pages.page_header.page_title_image.image_path == null || settings.shared_pages.page_header.page_title_image.image_path == '' ? '/img/page-title-img.png' : settings.shared_pages.page_header.page_title_image.image_path))
|
||||
#page-title-container
|
||||
if settings.orphans_page.page_header.show_title == true
|
||||
h3#page-title #{settings.locale.orphan_title.replace('{1}', settings.coin.name)}
|
||||
if settings.orphans_page.page_header.show_last_updated == true
|
||||
if settings.orphans_page.page_header.show_title != true && settings.orphans_page.page_header.show_description != true
|
||||
#page-title-container
|
||||
.sub-page-header
|
||||
span.fw-bold=settings.locale.last_updated + ':'
|
||||
span.text-muted#lastUpdatedDate
|
||||
else
|
||||
.sub-page-header(style='margin-bottom:' + (settings.orphans_page.page_header.show_description == true ? '5' : '0') + 'px')
|
||||
span.fw-bold=settings.locale.last_updated + ':'
|
||||
span.text-muted#lastUpdatedDate
|
||||
if settings.orphans_page.page_header.show_description == true
|
||||
if settings.orphans_page.page_header.show_title != true && settings.orphans_page.page_header.show_last_updated != true
|
||||
#page-title-container
|
||||
.sub-page-header.text-muted=settings.locale.orphan_description
|
||||
else
|
||||
.sub-page-header.text-muted=settings.locale.orphan_description
|
||||
.cardSpacer.clearfix
|
||||
.card.card-default.border-0.cardSpacer
|
||||
.card-header
|
||||
strong=settings.locale.orphan_block_list
|
||||
table#orphans-table.table.table-bordered.table-striped.table-paging.table-hover.mobile-border-right
|
||||
- var theadClasses = [];
|
||||
if settings.shared_pages.table_header_bgcolor != null && settings.shared_pages.table_header_bgcolor != ''
|
||||
- theadClasses.push('table-' + settings.shared_pages.table_header_bgcolor);
|
||||
thead
|
||||
tr(class=theadClasses)
|
||||
th.d-table-cell.d-md-none
|
||||
th.d-none.d-md-table-cell #{settings.locale.orphan_block_hash}
|
||||
th.text-center #{settings.locale.orphan_actual_block}
|
||||
th.text-center #{settings.locale.orphan_prev_block}
|
||||
th.text-center #{settings.locale.orphan_next_block}
|
||||
tbody
|
||||
@@ -17,6 +17,14 @@ block content
|
||||
startRotateElement('img#header-img');
|
||||
});
|
||||
.col-xs-12.col-md-12
|
||||
if orphan != null && orphan == true
|
||||
.col-12
|
||||
.alert.alert-warning.alert-dismissible.fade.show(role='alert')
|
||||
button.btn-close(type='button', data-bs-dismiss='alert')
|
||||
.cardSpacer
|
||||
span.fas.fa-exclamation-triangle(style='margin-right:5px')
|
||||
strong=settings.locale.ex_warning
|
||||
div="This is an orphaned transaction"
|
||||
if settings.transaction_page.page_header.show_img == true || settings.transaction_page.page_header.show_title == true || settings.transaction_page.page_header.show_description == true
|
||||
#page-header-container(style='align-items:' + (settings.transaction_page.page_header.show_img == true && settings.transaction_page.page_header.show_title == true && settings.transaction_page.page_header.show_description == true ? 'flex-start' : 'center'))
|
||||
if settings.transaction_page.page_header.show_img == true
|
||||
|
||||
Reference in New Issue
Block a user