From 4790764e2cf1463c4682439282237211e629c1f0 Mon Sep 17 00:00:00 2001 From: joeuhren <46763106+joeuhren@users.noreply.github.com> Date: Fri, 22 Jan 2021 15:04:32 -0700 Subject: [PATCH] Massive overhaul and cleanup of settings -Restructured the settings.json.template and settings.js files with better groupings -Added better comments for improved explanations of all settings -Better handling of page length options on all datatables; Page length options are now configurable and also only display options based on limits set by certain items_per_page and max_items_per_query settings -Markets have been extended to support unlimited trading pairs for each exchange -Added coin_symbol and pair_symbol to the markets schema to support multiple trading pairs -Added a burned field to the richlist schema for tracking burned coin addresses -Added a locale string for the new richlist wealth distribution "Top 1-100 Total" table row -Updated a couple locale strings that were incomplete or needed fixing (api_getblockhash and api_getnextrewardwhenstr) -Added a new css class to remove some redundant inline styles for the richlist wealth distribution color boxes -Richlist page now allows better separation of the top list(s) and the wealth distribution table and chart (you can now hide or show sections as desired) -Richlist page now allows for better burned coin support (Hide burned coin addresses from lists and totals even when the burned coin amounts are still included in the total coin supply value) -Block page now only displays the raw block link if the api_page.public_apis.rpc.getblock.enabled settings is set to true -Transaction page now only displays the raw tx link if the api_page.public_apis.rpc.getrawtransaction.enabled setting is set to true -Rate limiting class has been made global and is now used to limit market requests -getnetworkhashps rpc call now returns a '-' if shared_pages.show_hashrate is not set to true -Searching for unsycned blocks/txs no longer saves the data locally but instead still shows the data on screen. This helps prevent syncing data out-of-order (This eliminates the need for db_index.pid which has been removed) -Coin supply is now always taken from the stats collection database instead of from the wallet via rpc command in all cases except when syncing -Lots of misc fixes and code cleanup changes -List of changed settings: -title -> shared_pages.page_title -coin -> coin.name -symbol -> coin.symbol -logo -> shared_pages.logo -headerlogo -> shared_pages.page_header.home_link_logo -favicon -> shared_pages.favicon -homelink -> shared_pages.page_header.home_link -logoheight -> shared_pages.page_header.home_link_logo_height -sticky_header -> shared_pages.page_header.sticky_header -sticky_footer -> shared_pages.page_footer.sticky_footer -footer_height_desktop -> shared_pages.page_footer.footer_height_desktop -footer_height_tablet -> shared_pages.page_footer.footer_height_tablet -footer_height_mobile -> shared_pages.page_footer.footer_height_mobile -social_link_percent_height_desktop -> shared_pages.page_footer.social_link_percent_height_desktop -social_link_percent_height_tablet -> shared_pages.page_footer.social_link_percent_height_tablet -social_link_percent_height_mobile -> shared_pages.page_footer.social_link_percent_height_mobile -theme -> shared_pages.theme -port -> webserver.port -update_timeout -> sync.update_timeout -check_timeout -> sync.check_timeout -block_parallel_tasks -> sync.block_parallel_tasks -use_rpc -> api_cmds.use_rpc -confirmations -> shared_pages.confirmations -display.api -> api_page.enabled -display.markets -> markets_page.enabled -display.richlist -> richlist_page.enabled -display.search -> shared_pages.page_header.show_search -display.movement -> movement_page.enabled -display.network -> network_page.enabled -display.masternodes -> masternodes_page.enabled -display.claim_address -> claim_address_page.enabled -display.claim_address_header_menu -> claim_address_page.show_header_menu -display.page_header_bgcolor -> shared_pages.page_header.bgcolor -display.page_footer_bgcolor -> shared_pages.page_footer.bgcolor -display.table_header_bgcolor -> shared_pages.table_header_bgcolor -display.networkpnl -> shared_pages.page_header.panels.network_panel.display_order -display.difficultypnl -> shared_pages.page_header.panels.difficulty_panel.display_order -display.masternodespnl -> shared_pages.page_header.panels.masternodes_panel.display_order -display.coinsupplypnl -> shared_pages.page_header.panels.coin_supply_panel.display_order -display.pricepnl -> shared_pages.page_header.panels.price_panel.display_order -display.marketcappnl -> shared_pages.page_header.panels.market_cap_panel.display_order -display.logopnl -> shared_pages.page_header.panels.logo_panel.display_order -index.show_last_updated -> index_page.show_last_updated -index.show_hashrate -> shared_pages.show_hashrate -index.difficulty -> shared_pages.difficulty -index.last_txs -> api_page.public_apis.ext.getlasttxs.max_items_per_query -index.txs_per_page -> index_page.transaction_table.items_per_page (for index page) AND movement_page.movement_table.items_per_page (for movement page) -reward_page.show_last_updated -> blockchain_specific.heavycoin.reward_page.show_last_updated -api.blockindex -> api_page.sample_data.blockindex -api.blockhash -> api_page.sample_data.blockhash -api.txhash -> api_page.sample_data.txhash -api.address -> api_page.sample_data.address -markets.exchange -> markets_page.default_exchange.trading_pair -markets.default -> markets_page.default_exchange.exchange_name -markets.market_dropdown_menu -> markets_page.show_market_dropdown_menu -markets.market_select_visible -> markets_page.show_market_select -richlist.distribution -> richlist_page.wealth_distribution.show_distribution_chart -richlist.received -> richlist_page.show_received_coins -richlist.balance -> richlist_page.show_current_balance -movement.min_amount -> movement_page.movement_table.min_amount -movement.low_flag -> movement_page.movement_table.low_warning_flag -movement.high_flag -> movement_page.movement_table.high_warning_flag -social_links -> shared_pages.page_footer.social_links -social_links[x].image_url -> shared_pages.page_footer.social_links[x].image_path -genesis_tx -> transaction_page.genesis_tx -genesis_block -> block_page.genesis_block -heavy -> blockchain_specific.heavycoin.enabled -save_stats_after_sync_blocks -> sync.save_stats_after_sync_blocks -txcount -> api_page.public_apis.ext.getaddresstxs.max_items_per_query -txcount_per_page -> address_page.history_table.items_per_page -show_sent_received -> address_page.show_sent_received -supply -> sync.supply -nethash -> shared_pages.page_header.panels.network_panel.nethash -nethash_units -> shared_pages.page_header.panels.network_panel.nethash_units -usecors -> webserver.cors.enabled -corsorigin -> webserver.cors.corsorigin -burned_coins -> richlist_page.burned_coins.addresses -public_api.rpc.getdifficulty -> api_page.public_apis.rpc.getdifficulty.enabled -public_api.rpc.getconnectioncount -> api_page.public_apis.rpc.getconnectioncount.enabled -public_api.rpc.getblockcount -> api_page.public_apis.rpc.getblockcount.enabled -public_api.rpc.getblockhash -> api_page.public_apis.rpc.getblockhash.enabled -public_api.rpc.getblock -> api_page.public_apis.rpc.getblock.enabled -public_api.rpc.getrawtransaction -> api_page.public_apis.rpc.getrawtransaction.enabled -public_api.rpc.getnetworkhashps -> api_page.public_apis.rpc.getnetworkhashps.enabled -public_api.rpc.getvotelist -> api_page.public_apis.rpc.getvotelist.enabled -public_api.rpc.getmasternodecount -> api_page.public_apis.rpc.getmasternodecount.enabled -public_api.rpc.getmaxmoney -> blockchain_specific.heavycoin.public_apis.getmaxmoney.enabled -public_api.rpc.getmaxvote -> blockchain_specific.heavycoin.public_apis.getmaxvote.enabled -public_api.rpc.getvote -> blockchain_specific.heavycoin.public_apis.getvote.enabled -public_api.rpc.getphase -> blockchain_specific.heavycoin.public_apis.getphase.enabled -public_api.rpc.getreward -> blockchain_specific.heavycoin.public_apis.getreward.enabled -public_api.rpc.getsupply -> blockchain_specific.heavycoin.public_apis.getsupply.enabled -public_api.rpc.getnextrewardestimate -> blockchain_specific.heavycoin.public_apis.getnextrewardestimate.enabled -public_api.rpc.getnextrewardwhenstr -> blockchain_specific.heavycoin.public_apis.getnextrewardwhenstr.enabled -public_api.ext.getmoneysupply -> api_page.public_apis.ext.getmoneysupply.enabled -public_api.ext.getdistribution -> api_page.public_apis.ext.getdistribution.enabled -public_api.ext.getaddress -> api_page.public_apis.ext.getaddress.enabled -public_api.ext.getaddresstxs -> api_page.public_apis.ext.getaddresstxs.enabled -public_api.ext.gettx -> api_page.public_apis.ext.gettx.enabled -public_api.ext.getbalance -> api_page.public_apis.ext.getbalance.enabled -public_api.ext.getlasttxs -> api_page.public_apis.ext.getlasttxs.enabled -public_api.ext.getcurrentprice -> api_page.public_apis.ext.getcurrentprice.enabled -public_api.ext.getbasicstats -> api_page.public_apis.ext.getbasicstats.enabled -public_api.ext.getsummary -> api_page.public_apis.ext.getsummary.enabled -public_api.ext.getnetworkpeers -> api_page.public_apis.ext.getnetworkpeers.enabled -public_api.ext.getmasternodelist -> api_page.public_apis.ext.getmasternodelist.enabled -public_api.ext.getmasternoderewards -> api_page.public_apis.ext.getmasternoderewards.enabled -public_api.ext.getmasternoderewardstotal -> api_page.public_apis.ext.getmasternoderewardstotal.enabled -api_cmds.heavies.getmaxmoney -> blockchain_specific.heavycoin.api_cmds.getmaxmoney -api_cmds.heavies.getmaxvote -> blockchain_specific.heavycoin.api_cmds.getmaxvote -api_cmds.heavies.getvote -> blockchain_specific.heavycoin.api_cmds.getvote -api_cmds.heavies.getphase -> blockchain_specific.heavycoin.api_cmds.getphase -api_cmds.heavies.getreward -> blockchain_specific.heavycoin.api_cmds.getreward -api_cmds.heavies.getnextrewardestimate -> blockchain_specific.heavycoin.api_cmds.getnextrewardestimate -api_cmds.heavies.getnextrewardwhenstr -> blockchain_specific.heavycoin.api_cmds.getnextrewardwhenstr -api_cmds.heavies.getsupply -> blockchain_specific.heavycoin.api_cmds.getsupply -List of new settings: -shared_pages.page_header.panels.network_panel.enabled: allow enabling/disabling of the network panel -shared_pages.page_header.panels.difficulty_panel.enabled: allow enabling/disabling of the difficulty panel -shared_pages.page_header.panels.masternodes_panel.enabled: allow enabling/disabling of the masternodes panel -shared_pages.page_header.panels.coin_supply_panel.enabled: allow enabling/disabling of the coin supply panel -shared_pages.page_header.panels.price_panel.enabled: allow enabling/disabling of the price panel -shared_pages.page_header.panels.market_cap_panel.enabled: allow enabling/disabling of the market cap panel -shared_pages.page_header.panels.logo_panel.enabled: allow enabling/disabling of the logo panel -index_page.transaction_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -index_page.transaction_table.reload_table_seconds: the time in seconds to automatically reload the table data from the server -address_page.history_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -masternodes_page.masternode_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -masternodes_page.masternode_table.items_per_page: the default amount of items/records to display in the table at any given time -movement_page.movement_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -movement_page.movement_table.reload_table_seconds: the time in seconds to automatically reload the table data from the server -network_page.connections_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -network_page.connections_table.items_per_page: the default amount of items/records to display in the table at any given time -network_page.addnodes_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -network_page.addnodes_table.items_per_page: the default amount of items/records to display in the table at any given time -network_page.onetry_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -network_page.onetry_table.items_per_page: the default amount of items/records to display in the table at any given time -richlist_page.wealth_distribution.show_distribution_table: show/hide the wealth distribution summary table -richlist_page.wealth_distribution.colors: a list of html color codes to represent the top 100 groupings in the wealth distribution table and pie chart -richlist_page.burned_coins.include_burned_coins_in_distribution: determine whether to include burned coins in the wealth distribution section or not -markets_page.exchanges.altmarkets.enabled: enable/disable the altmarkets exchange -markets_page.exchanges.altmarkets.trading_pairs: a list of market trading pair symbols -markets_page.exchanges.bittrex.enabled: enable/disable the bittrex exchange -markets_page.exchanges.bittrex.trading_pairs: a list of market trading pair symbols -markets_page.exchanges.bleutrade.enabled: enable/disable the bleutrade exchange -markets_page.exchanges.bleutrade.trading_pairs: a list of market trading pair symbols -markets_page.exchanges.crex.enabled: enable/disable the crex exchange -markets_page.exchanges.crex.trading_pairs: a list of market trading pair symbols -markets_page.exchanges.poloniex.enabled: enable/disable the poloniex exchange -markets_page.exchanges.poloniex.trading_pairs: a list of market trading pair symbols -markets_page.exchanges.stex.enabled: enable/disable the stex exchange -markets_page.exchanges.stex.trading_pairs: a list of market trading pair symbols -markets_page.exchanges.yobit.enabled: enable/disable the yobit exchange -markets_page.exchanges.yobit.trading_pairs: a list of market trading pair symbols -claim_address_page.enable_bad_word_filter: enable/disable the "bad word" filter for claimed addresses, so that trying to claim an address with a bad word will fail -sync.show_sync_msg_when_syncing_more_than_blocks: show the sync msg at the top of all pages during index syncronization if there are more than this many blocks to process -labels[x].enabled: allow enabling/disabling of specific wallet address labels -blockchain_specific.heavycoin.reward_page.enabled: enable/disable the reward page -blockchain_specific.zksnarks.enabled: enable/disable Zcash zk-SNARKs private transaction support (WIP - 90% complete) -List of deleted settings -address: unnecessary setting has been replaced by dynamic values via http request -markets.coin: replaced by a richer set of settings that allow choosing the coin for each market -markets.enabled -> replaced by a richer set of settings that allow enabling/disabling each market specifically -lock_during_index: no longer possible to save unsynced blocks/txs via search so this settings is now obsolete/unused --- app.js | 362 +++++---- bin/instance | 64 +- lib/database.js | 444 +++++------ lib/explorer.js | 188 ++--- lib/locale.js | 10 +- lib/nodeapi.js | 26 +- lib/ratelimit.js | 52 ++ lib/settings.js | 1164 +++++++++++++++++++++++------ locale/en.json | 7 +- models/heavy.js | 8 +- models/markets.js | 2 + models/richlist.js | 7 +- public/css/style.scss | 6 + routes/index.js | 235 +++--- scripts/benchmark.js | 2 +- scripts/sass_theme_reader.sh | 2 +- scripts/sync.js | 227 +++--- scripts/sync.sh | 13 - settings.json.template | 1370 +++++++++++++++++++++++++--------- views/address.pug | 62 +- views/block.pug | 25 +- views/claim_address.pug | 2 +- views/includes/rl_labels.pug | 2 +- views/index.pug | 49 +- views/info.pug | 104 +-- views/layout.pug | 167 +++-- views/market.pug | 45 +- views/masternodes.pug | 24 +- views/movement.pug | 59 +- views/network.pug | 32 +- views/reward.pug | 14 +- views/richlist.pug | 331 ++++---- views/tx.pug | 15 +- 33 files changed, 3332 insertions(+), 1788 deletions(-) create mode 100644 lib/ratelimit.js diff --git a/app.js b/app.js index 12ca1a2..b83a41a 100644 --- a/app.js +++ b/app.js @@ -18,24 +18,28 @@ var apiAccessList = []; // pass wallet rpc connection info to nodeapi nodeapi.setWalletDetails(settings.wallet); -// dynamically build the nodeapi cmd access list by adding all non-heavy api cmds that have a value -Object.keys(settings.api_cmds).forEach(function(key, index, map) { - if (key != 'heavies' && settings.api_cmds[key] != null && settings.api_cmds[key] != '') +// dynamically build the nodeapi cmd access list by adding all non-blockchain-specific api cmds that have a value +Object.keys(settings.api_cmds).forEach(function(key, index, map) { + if (key != 'use_rpc' && settings.api_cmds[key] != null && settings.api_cmds[key] != '') apiAccessList.push(key); }); -if (settings.heavy) { - // add all heavy api cmds that have a value - Object.keys(settings.api_cmds.heavies).forEach(function(key, index, map) { - if (settings.api_cmds.heavies[key] != null && settings.api_cmds.heavies[key] != '') - apiAccessList.push(key); - }); -} +// dynamically find and add additional blockchain_specific api cmds +Object.keys(settings.blockchain_specific).forEach(function(key, index, map) { + // check if this feature is enabled and has api cmds + if (settings.blockchain_specific[key].enabled == true && Object.keys(settings.blockchain_specific[key]).indexOf('api_cmds') > -1) { + // add all blockchain specific api cmds that have a value + Object.keys(settings.blockchain_specific[key]['api_cmds']).forEach(function(key2, index, map) { + if (settings.blockchain_specific[key]['api_cmds'][key2] != null && settings.blockchain_specific[key]['api_cmds'][key2] != '') + apiAccessList.push(key2); + }); + } +}); // whitelist the cmds in the nodeapi access list nodeapi.setAccess('only', apiAccessList); // determine if cors should be enabled -if (settings.usecors == true) { +if (settings.webserver.cors.enabled == true) { app.use(function(req, res, next) { - res.header("Access-Control-Allow-Origin", settings.corsorigin); + res.header("Access-Control-Allow-Origin", settings.webserver.cors.corsorigin); res.header('Access-Control-Allow-Methods', 'DELETE, PUT, GET, POST'); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); @@ -45,7 +49,7 @@ if (settings.usecors == true) { app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'pug'); -app.use(favicon(path.join(__dirname, settings.favicon))); +app.use(favicon(path.join(__dirname, settings.shared_pages.favicon))); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); @@ -58,12 +62,18 @@ app.use('/', routes); // post method to claim an address using verifymessage functionality app.post('/claim', function(req, res) { - // initialize the bad-words filter - var bad_word_lib = require('bad-words'); - var bad_word_filter = new bad_word_lib(); + // check if the bad-words filter is enabled + if (settings.claim_address_page.enable_bad_word_filter == true) { + // initialize the bad-words filter + var bad_word_lib = require('bad-words'); + var bad_word_filter = new bad_word_lib(); - // clean the message (Display name) of bad words - var message = (req.body.message == null || req.body.message == '' ? '' : bad_word_filter.clean(req.body.message)); + // clean the message (Display name) of bad words + var message = (req.body.message == null || req.body.message == '' ? '' : bad_word_filter.clean(req.body.message)); + } else { + // Do not use the bad word filter + var message = (req.body.message == null || req.body.message == '' ? '' : req.body.message); + } // check if the message was filtered if (message == req.body.message) { @@ -93,10 +103,11 @@ app.post('/claim', function(req, res) { // extended apis app.use('/ext/getmoneysupply', function(req, res) { // check if the getmoneysupply api is enabled - if (settings.display.api == true && settings.public_api.ext['getmoneysupply']) { - lib.get_supply(function(supply) { + if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getmoneysupply.enabled == true) { + // lookup stats + db.get_stats(settings.coin.name, function (stats) { res.setHeader('content-type', 'text/plain'); - res.end((supply ? supply.toString() : '0')); + res.end((stats && stats.supply ? stats.supply.toString() : '0')); }); } else res.end('This method is disabled'); @@ -104,9 +115,9 @@ app.use('/ext/getmoneysupply', function(req, res) { app.use('/ext/getaddress/:hash', function(req, res) { // check if the getaddress api is enabled - if (settings.display.api == true && settings.public_api.ext['getaddress']) { + if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getaddress.enabled == true) { db.get_address(req.params.hash, false, function(address) { - db.get_address_txs_ajax(req.params.hash, 0, settings.txcount, function(txs, count) { + db.get_address_txs_ajax(req.params.hash, 0, settings.api_page.public_apis.ext.getaddresstxs.max_items_per_query, function(txs, count) { if (address) { var last_txs = []; for (i = 0; i < txs.length; i++) { @@ -148,12 +159,12 @@ app.use('/ext/getaddress/:hash', function(req, res) { app.use('/ext/gettx/:txid', function(req, res) { // check if the gettx api is enabled - if (settings.display.api == true && settings.public_api.ext['gettx']) { + if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.gettx.enabled == true) { var txid = req.params.txid; db.get_tx(txid, function(tx) { if (tx) { lib.get_blockcount(function(blockcount) { - res.send({ active: 'tx', tx: tx, confirmations: settings.confirmations, blockcount: (blockcount ? blockcount : 0)}); + res.send({ active: 'tx', tx: tx, confirmations: settings.shared_pages.confirmations, blockcount: (blockcount ? blockcount : 0)}); }); } else { @@ -172,7 +183,7 @@ app.use('/ext/gettx/:txid', function(req, res) { blockhash: '-', blockindex: -1, }; - res.send({ active: 'tx', tx: utx, confirmations: settings.confirmations, blockcount:-1}); + res.send({ active: 'tx', tx: utx, confirmations: settings.shared_pages.confirmations, blockcount:-1}); } else { var utx = { txid: rtx.txid, @@ -184,7 +195,7 @@ app.use('/ext/gettx/:txid', function(req, res) { blockindex: rtx.blockheight, }; lib.get_blockcount(function(blockcount) { - res.send({ active: 'tx', tx: utx, confirmations: settings.confirmations, blockcount: (blockcount ? blockcount : 0)}); + res.send({ active: 'tx', tx: utx, confirmations: settings.shared_pages.confirmations, blockcount: (blockcount ? blockcount : 0)}); }); } }); @@ -202,7 +213,7 @@ app.use('/ext/gettx/:txid', function(req, res) { app.use('/ext/getbalance/:hash', function(req, res) { // check if the getbalance api is enabled - if (settings.display.api == true && settings.public_api.ext['getbalance']) { + if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getbalance.enabled == true) { db.get_address(req.params.hash, false, function(address) { if (address) { res.setHeader('content-type', 'text/plain'); @@ -216,9 +227,9 @@ app.use('/ext/getbalance/:hash', function(req, res) { app.use('/ext/getdistribution', function(req, res) { // check if the getdistribution api is enabled - if (settings.display.api == true && settings.public_api.ext['getdistribution']) { - db.get_richlist(settings.coin, function(richlist) { - db.get_stats(settings.coin, function(stats) { + if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getdistribution.enabled == true) { + db.get_richlist(settings.coin.name, function(richlist) { + db.get_stats(settings.coin.name, function(stats) { db.get_distribution(richlist, stats, function(dist) { res.send(dist); }); @@ -230,9 +241,9 @@ app.use('/ext/getdistribution', function(req, res) { app.use('/ext/getcurrentprice', function(req, res) { // check if the getcurrentprice api is enabled - if (settings.display.api == true && settings.public_api.ext['getcurrentprice']) { - db.get_stats(settings.coin, function (stats) { - eval('var p_ext = { "last_price_'+settings.markets.exchange.toLowerCase()+'": stats.last_price, "last_price_usd": stats.last_usd_price, }'); + if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getcurrentprice.enabled == true) { + db.get_stats(settings.coin.name, function (stats) { + eval('var p_ext = { "last_price_' + settings.markets_page.default_exchange.trading_pair.split('/')[1].toLowerCase() + '": stats.last_price, "last_price_usd": stats.last_usd_price, }'); res.send(p_ext); }); } else @@ -241,27 +252,21 @@ app.use('/ext/getcurrentprice', function(req, res) { app.use('/ext/getbasicstats', function(req, res) { // check if the getbasicstats api is enabled - if (settings.display.api == true && settings.public_api.ext['getbasicstats']) { + if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getbasicstats.enabled == true) { // lookup stats - db.get_stats(settings.coin, function (stats) { - // lookup coin supply - lib.get_supply(function(supply) { - // lookup block count - lib.get_blockcount(function(blockcount) { - // check if the masternode count api is enabled - if (settings.public_api.rpc['getmasternodecount'] == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '') { - // masternode count api is available - lib.get_masternodecount(function(masternodestotal) { - eval('var p_ext = { "block_count": (blockcount ? blockcount : 0), "money_supply": (supply ? supply : 0), "last_price_'+settings.markets.exchange.toLowerCase()+'": stats.last_price, "last_price_usd": stats.last_usd_price, "masternode_count": masternodestotal.total }'); - res.send(p_ext); - }); - } else { - // masternode count api is not available - eval('var p_ext = { "block_count": (blockcount ? blockcount : 0), "money_supply": (supply ? supply : 0), "last_price_'+settings.markets.exchange.toLowerCase()+'": stats.last_price, "last_price_usd": stats.last_usd_price }'); - res.send(p_ext); - } + db.get_stats(settings.coin.name, function (stats) { + // check if the masternode count api is enabled + if (settings.api_page.public_apis.rpc.getmasternodecount.enabled == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '') { + // masternode count api is available + lib.get_masternodecount(function(masternodestotal) { + eval('var p_ext = { "block_count": (stats.count ? stats.count : 0), "money_supply": (stats.supply ? stats.supply : 0), "last_price_' + settings.markets_page.default_exchange.trading_pair.split('/')[1].toLowerCase() + '": stats.last_price, "last_price_usd": stats.last_usd_price, "masternode_count": masternodestotal.total }'); + res.send(p_ext); }); - }); + } else { + // masternode count api is not available + eval('var p_ext = { "block_count": (stats.count ? stats.count : 0), "money_supply": (stats.supply ? stats.supply : 0), "last_price_' + settings.markets_page.default_exchange.trading_pair.split('/')[1].toLowerCase() + '": stats.last_price, "last_price_usd": stats.last_usd_price }'); + res.send(p_ext); + } }); } else res.end('This method is disabled'); @@ -269,7 +274,7 @@ app.use('/ext/getbasicstats', function(req, res) { app.use('/ext/getlasttxs/:min', function(req, res) { // check if the getlasttxs api is enabled or else 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 ((settings.display.api == true && settings.public_api.ext['getlasttxs']) || (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)) { + if ((settings.api_page.enabled == true && settings.api_page.public_apis.ext.getlasttxs.enabled == true) || (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)) { var min = req.params.min, start, length, internal = false; // split url suffix by forward slash and remove blank entries var split = req.url.split('/').filter(function(v) { return v; }); @@ -296,8 +301,8 @@ app.use('/ext/getlasttxs/:min', function(req, res) { } // fix parameters - if (typeof length === 'undefined' || isNaN(length) || length > settings.index.last_txs) - length = settings.index.last_txs; + if (typeof length === 'undefined' || isNaN(length) || length > settings.api_page.public_apis.ext.getlasttxs.max_items_per_query) + length = settings.api_page.public_apis.ext.getlasttxs.max_items_per_query; if (typeof start === 'undefined' || isNaN(start) || start < 0) start = 0; if (typeof min === 'undefined' || isNaN(min) || min < 0) @@ -321,7 +326,7 @@ app.use('/ext/getlasttxs/:min', function(req, res) { app.use('/ext/getaddresstxs/:address/:start/:length', function(req, res) { // check if the getaddresstxs api is enabled or else 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 ((settings.display.api == true && settings.public_api.ext['getaddresstxs']) || (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)) { + if ((settings.api_page.enabled == true && settings.api_page.public_apis.ext.getaddresstxs.enabled == true) || (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)) { var internal = false; // split url suffix by forward slash and remove blank entries var split = req.url.split('/').filter(function(v) { return v; }); @@ -329,8 +334,8 @@ app.use('/ext/getaddresstxs/:address/:start/:length', function(req, res) { if (split.length > 0 && split[0] == 'internal') internal = true; // fix parameters - if (typeof req.params.length === 'undefined' || isNaN(req.params.length) || req.params.length > settings.txcount) - req.params.length = settings.txcount; + if (typeof req.params.length === 'undefined' || isNaN(req.params.length) || req.params.length > settings.api_page.public_apis.ext.getaddresstxs.max_items_per_query) + req.params.length = settings.api_page.public_apis.ext.getaddresstxs.max_items_per_query; if (typeof req.params.start === 'undefined' || isNaN(req.params.start) || req.params.start < 0) req.params.start = 0; if (typeof req.params.min === 'undefined' || isNaN(req.params.min) || req.params.min < 0) @@ -391,14 +396,14 @@ app.use('/ext/getaddresstxs/:address/:start/:length', function(req, res) { app.use('/ext/getsummary', function(req, res) { // check if the getsummary api is enabled or else 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 ((settings.display.api == true && settings.public_api.ext['getsummary']) || (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)) { + if ((settings.api_page.enabled == true && settings.api_page.public_apis.ext.getsummary.enabled == true) || (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)) { lib.get_difficulty(function(difficulty) { difficultyHybrid = ''; if (difficulty && difficulty['proof-of-work']) { - if (settings.index.difficulty == 'Hybrid') { + if (settings.shared_pages.difficulty == 'Hybrid') { difficultyHybrid = 'POS: ' + difficulty['proof-of-stake']; difficulty = 'POW: ' + difficulty['proof-of-work']; - } else if (settings.index.difficulty == 'POW') + } else if (settings.shared_pages.difficulty == 'POW') difficulty = difficulty['proof-of-work']; else difficulty = difficulty['proof-of-stake']; @@ -406,12 +411,12 @@ app.use('/ext/getsummary', function(req, res) { lib.get_hashrate(function(hashrate) { lib.get_connectioncount(function(connections) { lib.get_blockcount(function(blockcount) { - db.get_stats(settings.coin, function (stats) { + db.get_stats(settings.coin.name, function (stats) { lib.get_masternodecount(function(masternodestotal) { if (hashrate == 'There was an error. Check your console.') hashrate = 0; // check if the masternode count api is enabled - if (settings.public_api.rpc['getmasternodecount'] == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '') { + if (settings.api_page.public_apis.rpc.getmasternodecount.enabled == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '') { // masternode count api is available var mn_total = 0; var mn_enabled = 0; @@ -457,7 +462,7 @@ app.use('/ext/getsummary', function(req, res) { app.use('/ext/getnetworkpeers', function(req, res) { // check if the getnetworkpeers api is enabled or else 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 ((settings.display.api == true && settings.public_api.ext['getnetworkpeers']) || (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)) { + if ((settings.api_page.enabled == true && settings.api_page.public_apis.ext.getnetworkpeers.enabled == true) || (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)) { var internal = false; // split url suffix by forward slash and remove blank entries var split = req.url.split('/').filter(function(v) { return v; }); @@ -488,7 +493,7 @@ app.use('/ext/getnetworkpeers', function(req, res) { // get the list of masternodes from local collection app.use('/ext/getmasternodelist', function(req, res) { // check if the getmasternodelist api is enabled or else 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 ((settings.display.api == true && settings.public_api.ext['getmasternodelist']) || (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)) { + if ((settings.api_page.enabled == true && settings.api_page.public_apis.ext.getmasternodelist.enabled == true) || (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)) { // get the masternode list from local collection db.get_masternodes(function(masternodes) { // loop through masternode list and remove the mongo _id and __v keys @@ -506,7 +511,7 @@ app.use('/ext/getmasternodelist', function(req, res) { // returns a list of masternode reward txs for a single masternode address from a specific block height app.use('/ext/getmasternoderewards/:hash/:since', function(req, res) { // check if the getmasternoderewards api is enabled - if (settings.display.api == true && settings.public_api.ext['getmasternoderewards']) { + if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getmasternoderewards.enabled == true) { db.get_masternode_rewards(req.params.hash, req.params.since, function(rewards) { if (rewards != null) { // loop through the tx list to fix vout values and remove unnecessary data such as the always empty vin array and the mongo _id and __v keys @@ -531,7 +536,7 @@ app.use('/ext/getmasternoderewards/:hash/:since', function(req, res) { // returns the total masternode rewards received for a single masternode address from a specific block height app.use('/ext/getmasternoderewardstotal/:hash/:since', function(req, res) { // check if the getmasternoderewardstotal api is enabled - if (settings.display.api == true && settings.public_api.ext['getmasternoderewardstotal']) { + if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getmasternoderewardstotal.enabled == true) { db.get_masternode_rewards_totals(req.params.hash, req.params.since, function(total_rewards) { if (total_rewards != null) { // return the total of masternode rewards @@ -543,117 +548,156 @@ app.use('/ext/getmasternoderewardstotal/:hash/:since', function(req, res) { res.end('This method is disabled'); }); -// locals -app.set('title', settings.title); -app.set('explorer_version', package_metadata.version); -app.set('symbol', settings.symbol); -app.set('coin', settings.coin); -app.set('locale', locale); -app.set('display', settings.display); -app.set('markets', settings.markets); -app.set('social_links', settings.social_links); +var market_data = []; +var market_count = 0; -app.set('genesis_block', settings.genesis_block); -app.set('index', settings.index); -app.set('reward_page', settings.reward_page); +// check if markets are enabled +if (settings.markets_page.enabled == true) { + // dynamically populate market data + Object.keys(settings.markets_page.exchanges).forEach(function (key, index, map) { + // check if market is enabled via settings + if (settings.markets_page.exchanges[key].enabled == true) { + // check if market is installed/supported + if (db.fs.existsSync('./lib/markets/' + key + '.js')) { + // load market file + var exMarket = require('./lib/markets/' + key); + // save market_name and market_logo from market file to settings + eval('market_data.push({id: "' + key + '", name: "' + (exMarket.market_name == null ? '' : exMarket.market_name) + '", logo: "' + (exMarket.market_logo == null ? '' : exMarket.market_logo) + '", trading_pairs: []});'); + // loop through all trading pairs for this market + for (var i = 0; i < settings.markets_page.exchanges[key].trading_pairs.length; i++) { + // ensure trading pair setting is always uppercase + settings.markets_page.exchanges[key].trading_pairs[i] = settings.markets_page.exchanges[key].trading_pairs[i].toUpperCase(); + // add trading pair to market_data + market_data[market_data.length - 1].trading_pairs.push(settings.markets_page.exchanges[key].trading_pairs[i]); + // increment the market count + market_count++; + } + } + } + }); + + // sort market data by market name + market_data.sort(function(a, b) { + var name1 = a.name.toLowerCase(); + var name2 = b.name.toLowerCase(); + + if (name1 < name2) + return -1; + else if (name1 > name2) + return 1; + else + return 0; + }); + + // Fix default exchange case + settings.markets_page.default_exchange.exchange_name = settings.markets_page.default_exchange.exchange_name.toLowerCase(); + settings.markets_page.default_exchange.trading_pair = settings.markets_page.default_exchange.trading_pair.toUpperCase(); + + var ex = settings.markets_page.exchanges; + var ex_name = settings.markets_page.default_exchange.exchange_name; + var ex_pair = settings.markets_page.default_exchange.trading_pair; + var ex_keys = Object.keys(ex); + var ex_error = ''; + + // check to ensure default market and trading pair exist and are enabled + if (ex[ex_name] == null) { + // exchange name does not exist in exchanges list + ex_error = 'Default exchange name is not valid' + ': ' + ex_name; + } else if (!ex[ex_name].enabled) { + // exchange is not enabled + ex_error = 'Default exchange is disabled in settings' + ': ' + ex_name; + } else if (ex[ex_name].trading_pairs.findIndex(p => p.toLowerCase() == ex_pair.toLowerCase()) == -1) { + // invalid default exchange trading pair + ex_error = 'Default exchange trading pair is not valid' + ': ' + ex_pair; + } + + // check if there was an error msg + if (ex_error != '') { + // there was an error, so find the next available market from settings.json + var new_default_index = -1; + + // find the first enabled exchange with at least one trading pair + for (var i = 0; i < ex_keys.length; i++) { + if (ex[ex_keys[i]]['enabled'] === true && ex[ex_keys[i]]['trading_pairs'].length > 0) { + // found a match so save the index + new_default_index = i; + // stop looking for more matches + break; + } + } + + // check if a valid and enabled market was found + if (new_default_index == -1) { + // no valid markets found + console.log('WARNING: ' + ex_error + '. ' + 'No valid or enabled markets found in settings.json. The markets feature will be temporarily disabled. To restore markets functionality, please enable at least 1 market and ensure at least 1 valid trading pair is added. Finally, restart the explorer to resolve the problem'); + // disable the markets feature for this session + settings.markets_page.enabled = false; + } else { + // a valid and enabled market was found to replace the default + console.log('WARNING: ' + ex_error + '. ' + 'Default exchange will be set to' + ': ' + ex_keys[new_default_index] + ' (' + ex[ex_keys[new_default_index]].trading_pairs[0] + ')'); + // set new default exchange data + settings.markets_page.default_exchange.exchange_name = ex_keys[new_default_index]; + settings.markets_page.default_exchange.trading_pair = ex[ex_keys[new_default_index]].trading_pairs[0]; + } + } +} + +// check if home_link_logo file exists +if (!db.fs.existsSync(path.join('./public', settings.shared_pages.page_header.home_link_logo))) + settings.shared_pages.page_header.home_link_logo = ''; + +// always disable the rpc masternode list cmd from public apis +settings.api_page.public_apis.rpc.getmasternodelist = { "enabled": false }; + +// locals +app.set('explorer_version', package_metadata.version); +app.set('locale', locale); +app.set('coin', settings.coin); +app.set('shared_pages', settings.shared_pages); +app.set('index_page', settings.index_page); +app.set('block_page', settings.block_page); +app.set('transaction_page', settings.transaction_page); +app.set('address_page', settings.address_page); app.set('masternodes_page', settings.masternodes_page); app.set('movement_page', settings.movement_page); app.set('network_page', settings.network_page); app.set('richlist_page', settings.richlist_page); app.set('markets_page', settings.markets_page); -app.set('use_rpc', settings.use_rpc); -app.set('heavy', settings.heavy); -app.set('save_stats_after_sync_blocks', settings.save_stats_after_sync_blocks); -app.set('lock_during_index', settings.lock_during_index); -app.set('txcount', settings.txcount); -app.set('txcount_per_page', settings.txcount_per_page); -app.set('nethash', settings.nethash); -app.set('nethash_units', settings.nethash_units); -app.set('show_sent_received', settings.show_sent_received); -app.set('logo', settings.logo); - -// Check if header logo file exists -if (db.fs.existsSync(path.join('./public', settings.headerlogo))) - app.set('headerlogo', settings.headerlogo); -else - app.set('headerlogo', ''); - -app.set('theme', settings.theme); +app.set('api_page', settings.api_page); +app.set('claim_address_page', settings.claim_address_page); app.set('labels', settings.labels); -app.set('homelink', settings.homelink); -app.set('logoheight', settings.logoheight); -app.set('burned_coins', settings.burned_coins); app.set('api_cmds', settings.api_cmds); - -// Always disable the rpc masternode list cmd from public apis -settings.public_api['rpc']['getmasternodelist'] = false; -app.set('public_api', settings.public_api); - -app.set('sticky_header', settings.sticky_header); -app.set('sticky_footer', settings.sticky_footer); - -app.set('footer_height_desktop', settings.footer_height_desktop); -app.set('footer_height_tablet', settings.footer_height_tablet); -app.set('footer_height_mobile', settings.footer_height_mobile); - -app.set('social_link_percent_height_desktop', settings.social_link_percent_height_desktop); -app.set('social_link_percent_height_tablet', settings.social_link_percent_height_tablet); -app.set('social_link_percent_height_mobile', settings.social_link_percent_height_mobile); +app.set('blockchain_specific', settings.blockchain_specific); // determine panel offset based on which panels are enabled var paneltotal = 5; -var panelcount = (settings.display.networkpnl > 0 ? 1 : 0) + - (settings.display.difficultypnl > 0 ? 1 : 0) + - (settings.display.masternodespnl > 0 ? 1 : 0) + - (settings.display.coinsupplypnl > 0 ? 1 : 0) + - (settings.display.pricepnl > 0 ? 1 : 0) + - (settings.display.marketcappnl > 0 ? 1 : 0) + - (settings.display.logopnl > 0 ? 1 : 0); +var panelcount = (settings.shared_pages.page_header.panels.network_panel.enabled == true && settings.shared_pages.page_header.panels.network_panel.display_order > 0 ? 1 : 0) + + (settings.shared_pages.page_header.panels.difficulty_panel.enabled == true && settings.shared_pages.page_header.panels.difficulty_panel.display_order > 0 ? 1 : 0) + + (settings.shared_pages.page_header.panels.masternodes_panel.enabled == true && settings.shared_pages.page_header.panels.masternodes_panel.display_order > 0 ? 1 : 0) + + (settings.shared_pages.page_header.panels.coin_supply_panel.enabled == true && settings.shared_pages.page_header.panels.coin_supply_panel.display_order > 0 ? 1 : 0) + + (settings.shared_pages.page_header.panels.price_panel.enabled == true && settings.shared_pages.page_header.panels.price_panel.display_order > 0 ? 1 : 0) + + (settings.shared_pages.page_header.panels.market_cap_panel.enabled == true && settings.shared_pages.page_header.panels.market_cap_panel.display_order > 0 ? 1 : 0) + + (settings.shared_pages.page_header.panels.logo_panel.enabled == true && settings.shared_pages.page_header.panels.logo_panel.display_order > 0 ? 1 : 0); app.set('paneloffset', paneltotal + 1 - panelcount); // determine panel order -var panelorder = new Array(); +var panel_order = new Array(); -if (settings.display.networkpnl > 0) panelorder.push({name: 'networkpnl', val: settings.display.networkpnl}); -if (settings.display.difficultypnl > 0) panelorder.push({name: 'difficultypnl', val: settings.display.difficultypnl}); -if (settings.display.masternodespnl > 0) panelorder.push({name: 'masternodespnl', val: settings.display.masternodespnl}); -if (settings.display.coinsupplypnl > 0) panelorder.push({name: 'coinsupplypnl', val: settings.display.coinsupplypnl}); -if (settings.display.pricepnl > 0) panelorder.push({name: 'pricepnl', val: settings.display.pricepnl}); -if (settings.display.marketcappnl > 0) panelorder.push({name: 'marketcappnl', val: settings.display.marketcappnl}); -if (settings.display.logopnl > 0) panelorder.push({name: 'logopnl', val: settings.display.logopnl}); +if (settings.shared_pages.page_header.panels.network_panel.enabled == true && settings.shared_pages.page_header.panels.network_panel.display_order > 0) panel_order.push({name: 'network_panel', val: settings.shared_pages.page_header.panels.network_panel.display_order}); +if (settings.shared_pages.page_header.panels.difficulty_panel.enabled == true && settings.shared_pages.page_header.panels.difficulty_panel.display_order > 0) panel_order.push({name: 'difficulty_panel', val: settings.shared_pages.page_header.panels.difficulty_panel.display_order}); +if (settings.shared_pages.page_header.panels.masternodes_panel.enabled == true && settings.shared_pages.page_header.panels.masternodes_panel.display_order > 0) panel_order.push({name: 'masternodes_panel', val: settings.shared_pages.page_header.panels.masternodes_panel.display_order}); +if (settings.shared_pages.page_header.panels.coin_supply_panel.enabled == true && settings.shared_pages.page_header.panels.coin_supply_panel.display_order > 0) panel_order.push({name: 'coin_supply_panel', val: settings.shared_pages.page_header.panels.coin_supply_panel.display_order}); +if (settings.shared_pages.page_header.panels.price_panel.enabled == true && settings.shared_pages.page_header.panels.price_panel.display_order > 0) panel_order.push({name: 'price_panel', val: settings.shared_pages.page_header.panels.price_panel.display_order}); +if (settings.shared_pages.page_header.panels.market_cap_panel.enabled == true && settings.shared_pages.page_header.panels.market_cap_panel.display_order > 0) panel_order.push({name: 'market_cap_panel', val: settings.shared_pages.page_header.panels.market_cap_panel.display_order}); +if (settings.shared_pages.page_header.panels.logo_panel.enabled == true && settings.shared_pages.page_header.panels.logo_panel.display_order > 0) panel_order.push({name: 'logo_panel', val: settings.shared_pages.page_header.panels.logo_panel.display_order}); -panelorder.sort(function(a,b) { return a.val - b.val; }); +panel_order.sort(function(a,b) { return a.val - b.val; }); for (var i=1; i<6; i++) - app.set('panel'+i.toString(), ((panelorder.length >= i) ? panelorder[i-1].name : '')); - -// Dynamically populate market data -var market_data = []; - -settings.markets.enabled.forEach(function (market) { - // Check if market file exists - if (db.fs.existsSync('./lib/markets/' + market + '.js')) { - // Load market file - var exMarket = require('./lib/markets/' + market); - // Save market_name and market_logo from market file to settings - eval('market_data.push({id: "' + market + '", name: "' + (exMarket.market_name == null ? '' : exMarket.market_name) + '", logo: "' + (exMarket.market_logo == null ? '' : exMarket.market_logo) + '"});'); - } -}); - -// Sort market data by name -market_data.sort(function(a, b) { - var name1 = a.name.toLowerCase(); - var name2 = b.name.toLowerCase(); - - if (name1 < name2) - return -1; - else if (name1 > name2) - return 1; - else - return 0; -}); + app.set('panel'+i.toString(), ((panel_order.length >= i) ? panel_order[i-1].name : '')); app.set('market_data', market_data); +app.set('market_count', market_count); // catch 404 and forward to error handler app.use(function(req, res, next) { diff --git a/bin/instance b/bin/instance index 1c3c34a..6460cdf 100644 --- a/bin/instance +++ b/bin/instance @@ -4,7 +4,7 @@ var settings = require('../lib/settings'); var db = require('../lib/database'); var app = require('../app'); -app.set('port', process.env.PORT || settings.port); +app.set('port', process.env.PORT || settings.webserver.port); var dbString = 'mongodb://' + settings.dbsettings.user; dbString = dbString + ':' + settings.dbsettings.password; @@ -13,48 +13,60 @@ dbString = dbString + ':' + settings.dbsettings.port; dbString = dbString + '/' + settings.dbsettings.database; db.connect(dbString, function() { - db.check_stats(settings.coin, function(exists) { + db.check_stats(settings.coin.name, function(exists) { if (exists == false) { console.log('no stats entry found, creating now..'); - db.create_stats(settings.coin, function(){ + db.create_stats(settings.coin.name, function(){ //console.log('stats entry created successfully.'); }); } else { - db.get_stats(settings.coin, function (stats) { + db.get_stats(settings.coin.name, function (stats) { app.locals.stats = stats; }); } }); - // check markets - var markets = settings.markets.enabled; - for (var i = 0; i < markets.length; i++) { - // check if market is installed - if (db.fs.existsSync('./lib/markets/' + markets[i] + '.js')) { - db.check_market(markets[i], function(market, exists) { - if (exists == false) { - console.log('no %s entry found, creating now..', market); - db.create_market(settings.markets.coin, settings.markets.exchange, market, function() { + + // check markets/exchanges + if (settings.markets_page.enabled == true) { + // loop through and test all exchanges defined in the settings.json file + Object.keys(settings.markets_page.exchanges).forEach(function (key, index, map) { + // check if market is enabled via settings + if (settings.markets_page.exchanges[key].enabled == true) { + // check if exchange is installed/supported + if (db.fs.existsSync('./lib/markets/' + key + '.js')) { + // loop through all trading pairs + settings.markets_page.exchanges[key].trading_pairs.forEach(function (pair_key, pair_index, pair_map) { + // split the pair data + var split_pair = pair_key.split('/'); + // check if this is a valid trading pair + if (split_pair.length == 2) { + // lookup the exchange in the market collection + db.check_market(key, split_pair[0], split_pair[1], function(market, exists) { + // check if exchange trading pair exists in the market collection + if (!exists) { + // exchange doesn't exist in the market collection so add a default definition now + console.log('no %s: %s entry found, creating now..', market, pair_key); + db.create_market(split_pair[0], split_pair[1], market, function() {}); + } + }); + } }); } - }); - } + } + }); } - db.check_richlist(settings.coin, function(exists){ + db.check_richlist(settings.coin.name, function(exists){ if (exists == false) { console.log('no richlist entry found, creating now..'); - db.create_richlist(settings.coin, function() { - - }); + db.create_richlist(settings.coin.name, function() {}); } }); - if (settings.heavy == true) { - db.check_heavy(settings.coin, function(exists){ + if (settings.blockchain_specific.heavycoin.enabled == true) { + db.check_heavy(settings.coin.name, function(exists){ if (exists == false) { - console.log('no heavy entry found, creating now..'); - db.create_heavy(settings.coin, function() { - - }); + console.log('no heavycoin entry found, creating now..'); + db.create_heavy(settings.coin.name, function() {}); } }); } @@ -62,4 +74,4 @@ db.connect(dbString, function() { var server = app.listen(app.get('port'), '::', function() { debug('Express server listening on port ' + server.address().port); }); -}); +}); \ No newline at end of file diff --git a/lib/database.js b/lib/database.js index 12c8b2c..43a88f8 100644 --- a/lib/database.js +++ b/lib/database.js @@ -116,27 +116,26 @@ function find_tx(txid, cb) { } function save_tx(txid, blockheight, cb) { - lib.get_rawtransaction(txid, function(tx){ + lib.get_rawtransaction(txid, function(tx) { if (tx && tx != 'There was an error. Check your console.') { lib.prepare_vin(tx, function(vin) { - lib.prepare_vout(tx.vout, txid, vin, ((typeof tx.vjoinsplit === 'undefined' || tx.vjoinsplit == null) ? [] : tx.vjoinsplit), function(vout, nvin) { + lib.prepare_vout(tx.vout, txid, vin, ((!settings.blockchain_specific.zksnarks.enabled || typeof tx.vjoinsplit === 'undefined' || tx.vjoinsplit == null) ? [] : tx.vjoinsplit), function(vout, nvin) { lib.syncLoop(vin.length, function (loop) { var i = loop.iteration(); - update_address(nvin[i].addresses, blockheight, txid, nvin[i].amount, 'vin', function(){ + update_address(nvin[i].addresses, blockheight, txid, nvin[i].amount, 'vin', function() { loop.next(); }); - }, function(){ + }, function() { lib.syncLoop(vout.length, function (subloop) { var t = subloop.iteration(); if (vout[t].addresses) { - update_address(vout[t].addresses, blockheight, txid, vout[t].amount, 'vout', function(){ + update_address(vout[t].addresses, blockheight, txid, vout[t].amount, 'vout', function() { subloop.next(); }); - } else { + } else subloop.next(); - } - }, function(){ - lib.calculate_total(vout, function(total){ + }, function() { + lib.calculate_total(vout, function(total) { var newTx = new Tx({ txid: tx.txid, vin: nvin, @@ -147,79 +146,29 @@ function save_tx(txid, blockheight, cb) { blockindex: blockheight, }); newTx.save(function(err) { - if (err) { + if (err) return cb(err, false); - } else { + else return cb(null, vout.length > 0); - } }); }); }); }); }); }); - } else { + } else return cb('tx not found: ' + txid, false); - } }); } -function get_market_data(market, cb) { +function get_market_data(market, coin_symbol, pair_symbol, cb) { if (fs.existsSync('./lib/markets/' + market + '.js')) { exMarket = require('./markets/' + market); - exMarket.get_data(settings.markets, function(err, obj) { + exMarket.get_data({coin: coin_symbol, exchange: pair_symbol}, function(err, obj) { return cb(err, obj); }); - } else { + } else return cb(null); - } -} - -function create_lock(lockfile, cb) { - if (settings.lock_during_index == true) { - var fname = './tmp/' + lockfile + '.pid'; - fs.appendFile(fname, process.pid.toString(), function (err) { - if (err) { - console.log("Error: unable to create %s", fname); - process.exit(1); - } else { - return cb(); - } - }); - } else { - return cb(); - } -} - -function remove_lock(lockfile, cb) { - if (settings.lock_during_index == true) { - var fname = './tmp/' + lockfile + '.pid'; - fs.unlink(fname, function (err){ - if(err) { - console.log("unable to remove lock: %s", fname); - process.exit(1); - } else { - return cb(); - } - }); - } else { - return cb(); - } -} - -function is_locked(lockfile, cb) { - if (settings.lock_during_index == true) { - var fname = './tmp/' + lockfile + '.pid'; - fs.exists(fname, function (exists){ - if(exists) { - return cb(true); - } else { - return cb(false); - } - }); - } else { - return cb(false); - } } module.exports = { @@ -230,23 +179,12 @@ module.exports = { console.log('Unable to connect to database: %s', database); console.log('Aborting'); process.exit(1); - } - //console.log('Successfully connected to MongoDB'); + return cb(); }); }, - is_locked: function(cb) { - is_locked("db_index", function (exists) { - if (exists) { - return cb(true); - } else { - return cb(false); - } - }); - }, - check_show_sync_message: function() { return fs.existsSync('./tmp/show_sync_message.tmp'); }, @@ -274,9 +212,9 @@ module.exports = { update_richlist_claim_name: function(hash, claim_name, cb) { // check if the richlist is enabled - if (settings.display.richlist) { + if (settings.richlist_page.enabled == true) { // ensure that if this address exists in the richlist that it displays the new alias - module.exports.get_richlist(settings.coin, function(richlist) { + module.exports.get_richlist(settings.coin.name, function(richlist) { var updated = false; // loop through received addresses for (r = 0; r < richlist.received.length; r++) { @@ -301,7 +239,7 @@ module.exports = { // check if the address was updated in the richlist if (updated) { // save the richlist back to collection - Richlist.updateOne({coin: settings.coin}, { + Richlist.updateOne({coin: settings.coin.name}, { received: richlist.received, balance: richlist.balance }, function() { @@ -321,7 +259,7 @@ module.exports = { update_masternode_claim_name: function(hash, claim_name, cb) { // check if the masternode list is enabled - if (settings.display.masternodes) { + if (settings.masternodes_page.enabled == true) { // ensure that if this address exists in the masternode that it displays the new alias module.exports.get_masternodes(function(masternodes) { var updated = false; @@ -415,33 +353,60 @@ module.exports = { }, // 'list' variable can be either 'received' or 'balance' - update_richlist: function(list, cb){ - // Create the burn address array so that we omit burned coins from the rich list - var oBurnAddresses = []; - for (var x = 0; x < settings.burned_coins.length; x++) { - oBurnAddresses.push(settings.burned_coins[x].address); - } + update_richlist: function(list, cb) { + // number of addresses to lookup + var total_addresses = 100; + // create the burn address array so that we omit burned coins from the rich list + var burn_addresses = settings.richlist_page.burned_coins.addresses; // always omit the private address from the richlist - oBurnAddresses.push("private_tx"); + burn_addresses.push("private_tx"); if (list == 'received') { - // Update 'received' richlist data - Address.find({a_id: { $nin: oBurnAddresses }}, 'a_id name balance received').sort({received: 'desc'}).limit(100).exec(function(err, addresses) { - Richlist.updateOne({coin: settings.coin}, { + // update 'received' richlist data + Address.find({a_id: { $nin: burn_addresses }}, 'a_id name balance received').sort({received: 'desc'}).limit(total_addresses).exec(function(err, addresses) { + Richlist.updateOne({coin: settings.coin.name}, { received: addresses }, function() { return cb(); }); }); } else { - // Update 'balance' richlist data - Address.find({a_id: { $nin: oBurnAddresses }}, 'a_id name balance received').sort({balance: 'desc'}).limit(100).exec(function(err, addresses) { - Richlist.updateOne({coin: settings.coin}, { - balance: addresses - }, function() { - return cb(); + // update 'balance' richlist data + // check if burned addresses are in use and if it is necessary to track burned balances + if (settings.richlist_page.burned_coins.addresses == null || settings.richlist_page.burned_coins.addresses.length == 0 || !settings.richlist_page.burned_coins.include_burned_coins_in_distribution) { + // update 'balance' richlist data by filtering burned coin addresses immidiately + Address.find({a_id: { $nin: burn_addresses }}, 'a_id name balance received').sort({balance: 'desc'}).limit(total_addresses).exec(function(err, addresses) { + Richlist.updateOne({coin: settings.coin.name}, { + balance: addresses + }, function() { + return cb(); + }); }); - }); + } else { + // do not omit burned addresses from database query. instead, increase the limit of returned addresses and manually remove each burned address that made it into the rich list after recording the burned balance + Address.find({}, 'a_id name balance received').sort({balance: 'desc'}).limit(total_addresses + burn_addresses.length).exec(function(err, addresses) { + var return_addresses = []; + var burned_balance = 0.0; + // loop through all richlist addresses + addresses.forEach(function (address) { + // check if this is a burned coin address + if (burn_addresses.findIndex(p => p.toLowerCase() == address.a_id.toLowerCase()) > -1) { + // this is a burned coin address so save the balance, not the address + burned_balance += address.balance; + } else if (return_addresses.length < total_addresses) { + // this is not a burned address so add it to the return list + return_addresses.push(address); + } + }); + // update the rich list collection + Richlist.updateOne({coin: settings.coin.name}, { + balance: return_addresses, + burned: burned_balance + }, function() { + return cb(); + }); + }); + } } }, @@ -468,29 +433,6 @@ module.exports = { }); }, - create_txs: function(block, cb) { - is_locked("db_index", function (exists) { - if (exists) { - console.log("db_index lock file exists..."); - return cb(); - } else { - lib.syncLoop(block.tx.length, function (loop) { - var i = loop.iteration(); - save_tx(block.tx[i], block.height, function(err, tx_has_vout) { - if (err) { - loop.next(); - } else { - //console.log('tx stored: %s', block.tx[i]); - loop.next(); - } - }); - }, function(){ - return cb(); - }); - } - }); - }, - get_last_txs: function(start, length, min, internal, cb) { this.get_last_txs_ajax(start, length, min, function(txs, count) { var data = []; @@ -536,7 +478,7 @@ module.exports = { }); } else { // min is zero (shouldn't ever be negative) which means we must pull record count from the coinstats collection (pulling from txes could potentially take a long time because it would include coinbase txes) - Stats.findOne({coin:settings.coin}, function(err, stats) { + Stats.findOne({coin: settings.coin.name}, function(err, stats) { // Get last transactions where there is at least 1 vout Tx.find({'total': {$gte: min}, 'vout': { $gte: { $size: 1 }}}).sort({blockindex: -1}).skip(Number(start)).limit(Number(length)).exec(function(err, txs) { if (err) { @@ -613,11 +555,11 @@ module.exports = { }); }, - create_market: function(coin, exchange, market, cb) { + create_market: function(coin_symbol, pair_symbol, market, cb) { var newMarkets = new Markets({ market: market, - coin: coin, - exchange: exchange, + coin_symbol: coin_symbol, + pair_symbol: pair_symbol, }); newMarkets.save(function(err) { @@ -625,32 +567,26 @@ module.exports = { console.log(err); return cb(); } else { - console.log("initial markets entry created for %s", market); - //console.log(newMarkets); + console.log("initial market entry created for %s: %s", market, coin_symbol +'/' + pair_symbol); return cb(); } }); }, - // checks market data exists for given market - check_market: function(market, cb) { - Markets.findOne({market: market}, function(err, exists) { - if(exists) { - return cb(market, true); - } else { - return cb(market, false); - } + // check if market data exists for a given market and trading pair + check_market: function(market, coin_symbol, pair_symbol, cb) { + Markets.findOne({market: market, coin_symbol: coin_symbol, pair_symbol: pair_symbol}, function(err, exists) { + return cb(market, exists); }); }, - // gets market data for given market - get_market: function(market, cb) { - Markets.findOne({market: market}, function(err, data) { - if(data) { + // gets market data for given market and trading pair + get_market: function(market, coin_symbol, pair_symbol, cb) { + Markets.findOne({market: market, coin_symbol: coin_symbol, pair_symbol: pair_symbol}, function(err, data) { + if (data) return cb(data); - } else { + else return cb(null); - } }); }, @@ -701,8 +637,7 @@ module.exports = { console.log(err); return cb(); } else { - console.log("initial heavy entry created for %s", coin); - console.log(newHeavy); + console.log("initial heavycoin entry created for %s", coin); return cb(); } }); @@ -727,7 +662,8 @@ module.exports = { } }); }, - get_distribution: function(richlist, stats, cb){ + + get_distribution: function(richlist, stats, cb) { var distribution = { supply: stats.supply, t_1_25: {percent: 0, total: 0 }, @@ -736,30 +672,36 @@ module.exports = { t_76_100: {percent: 0, total: 0 }, t_101plus: {percent: 0, total: 0 } }; + lib.syncLoop(richlist.balance.length, function (loop) { var i = loop.iteration(); var count = i + 1; var percentage = ((richlist.balance[i].balance / 100000000) / stats.supply) * 100; + if (count <= 25 ) { distribution.t_1_25.percent = distribution.t_1_25.percent + percentage; distribution.t_1_25.total = distribution.t_1_25.total + (richlist.balance[i].balance / 100000000); } + if (count <= 50 && count > 25) { distribution.t_26_50.percent = distribution.t_26_50.percent + percentage; distribution.t_26_50.total = distribution.t_26_50.total + (richlist.balance[i].balance / 100000000); } + if (count <= 75 && count > 50) { distribution.t_51_75.percent = distribution.t_51_75.percent + percentage; distribution.t_51_75.total = distribution.t_51_75.total + (richlist.balance[i].balance / 100000000); } + if (count <= 100 && count > 75) { distribution.t_76_100.percent = distribution.t_76_100.percent + percentage; distribution.t_76_100.total = distribution.t_76_100.total + (richlist.balance[i].balance / 100000000); } + loop.next(); - }, function(){ - distribution.t_101plus.percent = parseFloat(100 - distribution.t_76_100.percent - distribution.t_51_75.percent - distribution.t_26_50.percent - distribution.t_1_25.percent).toFixed(2); - distribution.t_101plus.total = parseFloat(distribution.supply - distribution.t_76_100.total - distribution.t_51_75.total - distribution.t_26_50.total - distribution.t_1_25.total).toFixed(8); + }, function() { + distribution.t_101plus.percent = parseFloat(100 - distribution.t_76_100.percent - distribution.t_51_75.percent - distribution.t_26_50.percent - distribution.t_1_25.percent - (settings.richlist_page.burned_coins.include_burned_coins_in_distribution == true && richlist.burned > 0 ? ((richlist.burned / 100000000) / stats.supply) * 100 : 0)).toFixed(2); + distribution.t_101plus.total = parseFloat(distribution.supply - distribution.t_76_100.total - distribution.t_51_75.total - distribution.t_26_50.total - distribution.t_1_25.total - (settings.richlist_page.burned_coins.include_burned_coins_in_distribution == true && richlist.burned > 0 ? (richlist.burned / 100000000) : 0)).toFixed(8); distribution.t_1_25.percent = parseFloat(distribution.t_1_25.percent).toFixed(2); distribution.t_1_25.total = parseFloat(distribution.t_1_25.total).toFixed(8); distribution.t_26_50.percent = parseFloat(distribution.t_26_50.percent).toFixed(2); @@ -772,7 +714,7 @@ module.exports = { }); }, - // updates heavy stats for coin + // updates heavycoin stats // height: current block height, count: amount of votes to store update_heavy: function(coin, height, count, cb) { var newVotes = []; @@ -782,7 +724,7 @@ module.exports = { lib.get_vote( function (vote) { lib.get_phase( function (phase) { lib.get_reward( function (reward) { - lib.get_supply( function (supply) { + module.exports.get_stats(settings.coin.name, function (stats) { lib.get_estnext( function (estnext) { lib.get_nextin( function (nextin) { lib.syncLoop(count, function (loop) { @@ -797,7 +739,7 @@ module.exports = { Heavy.updateOne({coin: coin}, { lvote: (vote ? vote : 0), reward: (reward ? reward : 0), - supply: (supply ? supply : 0), + supply: (stats && stats.supply ? stats.supply : 0), cap: (maxmoney ? maxmoney : 0), estnext: (estnext ? estnext : 0), phase: (phase ? phase : 'N/A'), @@ -806,8 +748,8 @@ module.exports = { votes: newVotes }, function() { // update reward_last_updated value - module.exports.update_last_updated_stats(settings.coin, { reward_last_updated: Math.floor(new Date() / 1000) }, function (new_cb) { - console.log('heavy update complete'); + module.exports.update_last_updated_stats(settings.coin.name, { reward_last_updated: Math.floor(new Date() / 1000) }, function (new_cb) { + console.log('heavycoin update complete'); return cb(); }); }); @@ -823,29 +765,36 @@ module.exports = { }, // updates market data for given market; called by sync.js - update_markets_db: function(market, cb) { + update_markets_db: function(market, coin_symbol, pair_symbol, cb) { // check if market exists if (fs.existsSync('./lib/markets/' + market + '.js')) { - get_market_data(market, function (err, obj) { + get_market_data(market, coin_symbol, pair_symbol, function (err, obj) { + // check if there was an error with getting market data if (err == null) { - Markets.updateOne({market:market}, { + // update the market collection for the current market and trading pair combination + Markets.updateOne({market: market, coin_symbol: coin_symbol, pair_symbol: pair_symbol}, { chartdata: JSON.stringify(obj.chartdata), buys: obj.buys, sells: obj.sells, history: obj.trades, summary: obj.stats }, function() { - if ( market == settings.markets.default ) { - Stats.updateOne({coin:settings.coin}, { + // check if this is the default market + if (market == settings.markets_page.default_exchange.exchange_name) { + // this is the default market so update the last price stats + Stats.updateOne({coin: settings.coin.name}, { last_price: obj.stats.last, - }, function(){ + }, function() { + // finished updating market data return cb(null); }); } else { + // this is not the default market so we are finished updating market data return cb(null); } }); } else { + // an error occurred with getting market data so return the error msg return cb(err); } }); @@ -854,25 +803,26 @@ module.exports = { return cb('market is not installed'); } }, - + get_last_usd_price: function(cb) { - // Check if the market price is being recorded in BTC - if (settings.markets.enabled.length > 0 && settings.markets.exchange.toLowerCase() == "btc") { - // Convert btc to usd via coindesk api - coindesk.get_data(function (err, last_usd) { - // Get current stats - Stats.findOne({coin:settings.coin}, function(err, stats) { - // Update the last usd price - Stats.updateOne({coin:settings.coin}, { - last_usd_price: (last_usd * stats.last_price), - }, function(){ - return cb(null); - }); - }); - }); - } else { - return cb(null); - } + // check if the default market price is enabled and being recorded in BTC + if (settings.markets_page.exchanges[settings.markets_page.default_exchange.exchange_name].enabled == true && settings.markets_page.exchanges[settings.markets_page.default_exchange.exchange_name].trading_pairs.findIndex(p => p.toLowerCase().indexOf('/btc') > -1) > -1) { + // convert btc to usd via coindesk api + coindesk.get_data(function (err, last_usd) { + // get current stats + Stats.findOne({coin: settings.coin.name}, function(err, stats) { + // update the last usd price + Stats.updateOne({coin: settings.coin.name}, { + last_usd_price: (last_usd * stats.last_price), + }, function() { + return cb(null); + }); + }); + }); + } else { + // only btc conversion supported so just exit without updating last price for now + return cb(null); + } }, // updates stats data for given coin; called by sync.js @@ -882,7 +832,7 @@ module.exports = { console.log('Unable to connect to explorer API'); return cb(false); } - lib.get_supply( function (supply) { + lib.get_supply(function (supply) { lib.get_connectioncount(function (connections) { Stats.findOne({coin: coin}, function(err, stats) { if (stats) { @@ -916,91 +866,75 @@ module.exports = { // updates tx, address & richlist db's; called by sync.js update_tx_db: function(coin, start, end, txes, timeout, cb) { - is_locked("db_index", function (exists) { - if (exists) { - console.log("db_index lock file exists..."); - return cb(); - } else { - create_lock("db_index", function (){ - var complete = false; - var blocks_to_scan = []; - var task_limit_blocks = settings.block_parallel_tasks; - if (typeof start === 'undefined' || start < 1) start = 1; // fix for invalid block height (skip genesis block as it should not have valid txs) - if (task_limit_blocks < 1) { task_limit_blocks = 1; } - var task_limit_txs = 1; - for (i=start; i<(end+1); i++) { - blocks_to_scan.push(i); - } - async.eachLimit(blocks_to_scan, task_limit_blocks, function(block_height, next_block) { - if (block_height % settings.save_stats_after_sync_blocks === 0) { - Stats.updateOne({coin: coin}, { - last: block_height - 1, - txes: txes, - last_txs: '' //not used anymore left to clear out existing objects - }, function() {}); - } - lib.get_blockhash(block_height, function(blockhash){ - if (blockhash) { - lib.get_block(blockhash, function(block) { - if (block) { - async.eachLimit(block.tx, task_limit_txs, function(txid, next_tx) { - Tx.findOne({txid: txid}, function(err, tx) { - if(tx) { - setTimeout( function(){ - tx = null; - next_tx(); - }, timeout); - } else { - save_tx(txid, block_height, function(err, tx_has_vout) { - if (err) { - console.log(err); - } else { - console.log('%s: %s', block_height, txid); - } - if (tx_has_vout) - txes++; - setTimeout( function(){ - tx = null; - next_tx(); - }, timeout); - }); - } - }); - }, function(){ - setTimeout( function(){ - blockhash = null; - block = null; - next_block(); + var complete = false; + var blocks_to_scan = []; + var task_limit_blocks = settings.sync.block_parallel_tasks; + if (typeof start === 'undefined' || start < 1) start = 1; // fix for invalid block height (skip genesis block as it should not have valid txs) + if (task_limit_blocks < 1) { task_limit_blocks = 1; } + var task_limit_txs = 1; + for (i=start; i<(end+1); i++) + blocks_to_scan.push(i); + async.eachLimit(blocks_to_scan, task_limit_blocks, function(block_height, next_block) { + if (block_height % settings.sync.save_stats_after_sync_blocks === 0) { + Stats.updateOne({coin: coin}, { + last: block_height - 1, + txes: txes + }, function() {}); + } + lib.get_blockhash(block_height, function(blockhash) { + if (blockhash) { + lib.get_block(blockhash, function(block) { + if (block) { + async.eachLimit(block.tx, task_limit_txs, function(txid, next_tx) { + Tx.findOne({txid: txid}, function(err, tx) { + if(tx) { + setTimeout( function() { + tx = null; + next_tx(); + }, timeout); + } else { + save_tx(txid, block_height, function(err, tx_has_vout) { + if (err) + console.log(err); + else + console.log('%s: %s', block_height, txid); + + if (tx_has_vout) + txes++; + setTimeout( function() { + tx = null; + next_tx(); }, timeout); }); - } else { - console.log('block not found: %s', blockhash); - setTimeout( function(){ - next_block(); - }, timeout); } }); - } else { - setTimeout( function(){ + }, function() { + setTimeout( function() { + blockhash = null; + block = null; next_block(); }, timeout); - } - }); - }, function(){ - Tx.find({}).sort({timestamp: 'desc'}).limit(settings.index.last_txs).exec(function(err, txs){ - Stats.updateOne({coin: coin}, { - last: end, - txes: txes, - last_txs: '' //not used anymore left to clear out existing objects - }, function() { - remove_lock("db_index", function(){ - return cb(); - }); }); - }); + } else { + console.log('block not found: %s', blockhash); + setTimeout( function() { + next_block(); + }, timeout); + } }); - }); - } + } else { + setTimeout( function() { + next_block(); + }, timeout); + } + }); + }, function() { + Stats.updateOne({coin: coin}, { + last: end, + txes: txes + }, function() { + return cb(); + }); }); }, @@ -1067,7 +1001,7 @@ module.exports = { // lookup masternode in local collection module.exports.find_masternode(raw_masternode.txhash, raw_masternode.outidx, function (masternode) { // determine if the claim address feature is enabled - if (settings.display.claim_address) { + if (settings.claim_address_page.enabled == true) { // claim address is enabled so lookup the address claim name find_address(raw_masternode.addr, false, function(address) { if (address) { diff --git a/lib/explorer.js b/lib/explorer.js index 3b59978..1dede55 100644 --- a/lib/explorer.js +++ b/lib/explorer.js @@ -2,7 +2,7 @@ var request = require('postman-request') , settings = require('./settings') , Address = require('../models/address'); -var base_server = 'http://127.0.0.1:' + settings.port + "/"; +var base_server = 'http://127.0.0.1:' + settings.webserver.port + "/"; var base_url = base_server + 'api/'; @@ -50,19 +50,19 @@ function prepareRpcCommand(cmd, addParams) { } function convertHashUnits(hashes) { - if (settings.nethash_units == 'K') { + if (settings.shared_pages.page_header.panels.network_panel.nethash_units == 'K') { // return units in KH/s return (hashes / 1000).toFixed(4); - } else if (settings.nethash_units == 'M') { + } else if (settings.shared_pages.page_header.panels.network_panel.nethash_units == 'M') { // return units in MH/s return (hashes / 1000000).toFixed(4); - } else if (settings.nethash_units == 'G') { + } else if (settings.shared_pages.page_header.panels.network_panel.nethash_units == 'G') { // return units in GH/s return (hashes / 1000000000).toFixed(4); - } else if (settings.nethash_units == 'T') { + } else if (settings.shared_pages.page_header.panels.network_panel.nethash_units == 'T') { // return units in TH/s return (hashes / 1000000000000).toFixed(4); - } else if (settings.nethash_units == 'P') { + } else if (settings.shared_pages.page_header.panels.network_panel.nethash_units == 'P') { // return units in PH/s return (hashes / 1000000000000000).toFixed(4); } else { @@ -81,15 +81,15 @@ module.exports = { get_hashrate: function(cb) { // check if hash rate should be hidden - if (settings.index.show_hashrate == false) return cb('-'); + if (settings.shared_pages.show_hashrate == false) return cb('-'); // check how to acquire network hashrate - if (settings.nethash == 'netmhashps') { + if (settings.shared_pages.page_header.panels.network_panel.nethash == 'netmhashps') { // load getmininginfo rpc call from settings var cmd = prepareRpcCommand(settings.api_cmds.getmininginfo); // check if the rpc cmd is valid if (!(cmd.method == '' && cmd.parameters.length == 0)) { // check if getting data from wallet rpc or web api request - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { // get data from wallet via rpc cmd rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server @@ -148,13 +148,13 @@ module.exports = { // getmininginfo cmd not set return cb('-'); } - } else if (settings.nethash == 'getnetworkhashps') { + } else if (settings.shared_pages.page_header.panels.network_panel.nethash == 'getnetworkhashps') { // load getnetworkhashps rpc call from settings var cmd = prepareRpcCommand(settings.api_cmds.getnetworkhashps); // check if the rpc cmd is valid if (!(cmd.method == '' && cmd.parameters.length == 0)) { // check if getting data from wallet rpc or web api request - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { // get data from wallet via rpc cmd rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server @@ -196,7 +196,7 @@ module.exports = { var cmd = prepareRpcCommand(settings.api_cmds.getdifficulty); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -224,7 +224,7 @@ module.exports = { var cmd = prepareRpcCommand(settings.api_cmds.getconnectioncount); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -252,7 +252,7 @@ module.exports = { var cmd = prepareRpcCommand(settings.api_cmds.getmasternodelist); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -280,7 +280,7 @@ module.exports = { var cmd = prepareRpcCommand(settings.api_cmds.getmasternodecount); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -308,7 +308,7 @@ module.exports = { var cmd = prepareRpcCommand(settings.api_cmds.getblockcount); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -336,7 +336,7 @@ module.exports = { var cmd = prepareRpcCommand(settings.api_cmds.getblockhash, (height ? [parseInt(height)] : [])); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -364,7 +364,7 @@ module.exports = { var cmd = prepareRpcCommand(settings.api_cmds.getblock, (hash ? [hash] : [])); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -392,7 +392,7 @@ module.exports = { var cmd = prepareRpcCommand(settings.api_cmds.getrawtransaction, (hash ? [hash, 1] : [])); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -417,10 +417,10 @@ module.exports = { }, get_maxmoney: function(cb) { - var cmd = prepareRpcCommand(settings.api_cmds.heavies.getmaxmoney); + var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getmaxmoney); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -445,10 +445,10 @@ module.exports = { }, get_maxvote: function(cb) { - var cmd = prepareRpcCommand(settings.api_cmds.heavies.getmaxvote); + var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getmaxvote); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -473,10 +473,10 @@ module.exports = { }, get_vote: function(cb) { - var cmd = prepareRpcCommand(settings.api_cmds.heavies.getvote); + var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getvote); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -501,10 +501,10 @@ module.exports = { }, get_phase: function(cb) { - var cmd = prepareRpcCommand(settings.api_cmds.heavies.getphase); + var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getphase); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -529,10 +529,10 @@ module.exports = { }, get_reward: function(cb) { - var cmd = prepareRpcCommand(settings.api_cmds.heavies.getreward); + var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getreward); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -557,10 +557,10 @@ module.exports = { }, get_estnext: function(cb) { - var cmd = prepareRpcCommand(settings.api_cmds.heavies.getnextrewardestimate); + var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getnextrewardestimate); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -585,10 +585,10 @@ module.exports = { }, get_nextin: function(cb) { - var cmd = prepareRpcCommand(settings.api_cmds.heavies.getnextrewardwhenstr); + var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getnextrewardwhenstr); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -642,10 +642,10 @@ module.exports = { if(exit) exit(); // Call the callback on exit } }, - iteration:function(){ + iteration:function() { return index - 1; // Return the loop number we're on }, - break:function(end){ + break:function(end) { done = true; // End the loop shouldExit = end; // Passing end as true means we still call the exit callback } @@ -661,19 +661,19 @@ module.exports = { var i = loop.iteration(); count = count + docs[i].balance; loop.next(); - }, function(){ + }, function() { return cb(count); }); }); }, get_supply: function(cb) { - if (settings.supply == 'HEAVY') { + if (settings.sync.supply == 'HEAVY') { // attempt to get the supply from the getsupply or similar api cmd that returns the current money supply as a single positive decimal value - var cmd = prepareRpcCommand(settings.api_cmds.heavies.getsupply); + var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getsupply); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -695,12 +695,12 @@ module.exports = { // cmd not in use. return null. return cb(null); } - } else if (settings.supply == 'GETINFO') { + } else if (settings.sync.supply == 'GETINFO') { // attempt to get the supply from the getinfo or similar api cmd that returns and object containing various state info. Must include a value called "moneysupply" which represents the current running total of coins var cmd = prepareRpcCommand(settings.api_cmds.getinfo); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (!response || !response.moneysupply || response == 'There was an error. Check your console.') @@ -722,17 +722,17 @@ module.exports = { // cmd not in use. return null. return cb(null); } - } else if (settings.supply == 'BALANCES') { + } else if (settings.sync.supply == 'BALANCES') { // get the supply by running a query on the addresses collection and summing up all positive balances (potentially a long running query for blockchains with tons of addresses) module.exports.balance_supply(function(supply) { return cb(supply/100000000); }); - } else if (settings.supply == 'TXOUTSET') { + } else if (settings.sync.supply == 'TXOUTSET') { // attempt to get the supply from the gettxoutsetinfo or similar api cmd that returns an object with statistics about the unspent transaction output set. Must include a value called "total_amount" which represents the current running total of coins var cmd = prepareRpcCommand(settings.api_cmds.gettxoutsetinfo); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (!response || !response.total_amount || response == 'There was an error. Check your console.') @@ -766,7 +766,7 @@ module.exports = { var cmd = prepareRpcCommand(settings.api_cmds.getpeerinfo); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -794,7 +794,7 @@ module.exports = { var cmd = prepareRpcCommand(settings.api_cmds.verifymessage, [address, signature, message]); if (!(cmd.method == '' && cmd.parameters.length == 0)) { - if (settings.use_rpc) { + if (settings.api_cmds.use_rpc) { rpcCommand([{method:cmd.method, parameters: cmd.parameters}], function(response) { // check if an error msg was received from the rpc server if (response == 'There was an error. Check your console.') @@ -864,68 +864,68 @@ module.exports = { // make sure vout has an address if (vout[i].scriptPubKey.type != 'nonstandard' && vout[i].scriptPubKey.type != 'nulldata') { // check if tx is public or private (private = if no out address) - if (vout[i].scriptPubKey.type != 'zerocoinmint' && typeof vout[i].scriptPubKey.addresses != 'undefined') { - // check if vout address is unique, if so add it array, if not add its amount to existing index - module.exports.is_unique(arr_vout, vout[i].scriptPubKey.addresses[0], function(unique, index) { - if (unique == true) { - // unique vout - module.exports.convert_to_satoshi(parseFloat(vout[i].value), function(amount_sat){ - arr_vout.push({addresses: vout[i].scriptPubKey.addresses[0], amount: amount_sat}); - loop.next(); - }); - } else { - // already exists - module.exports.convert_to_satoshi(parseFloat(vout[i].value), function(amount_sat){ - arr_vout[index].amount = arr_vout[index].amount + amount_sat; - loop.next(); - }); - } - }); - } else { - // private tx - // TODO: save this data to be able to show an anon tx - loop.next(); - } + if (vout[i].scriptPubKey.type != 'zerocoinmint' && typeof vout[i].scriptPubKey.addresses != 'undefined') { + // check if vout address is unique, if so add it array, if not add its amount to existing index + module.exports.is_unique(arr_vout, vout[i].scriptPubKey.addresses[0], function(unique, index) { + if (unique == true) { + // unique vout + module.exports.convert_to_satoshi(parseFloat(vout[i].value), function(amount_sat) { + arr_vout.push({addresses: vout[i].scriptPubKey.addresses[0], amount: amount_sat}); + loop.next(); + }); + } else { + // already exists + module.exports.convert_to_satoshi(parseFloat(vout[i].value), function(amount_sat) { + arr_vout[index].amount = arr_vout[index].amount + amount_sat; + loop.next(); + }); + } + }); + } else { + // private tx + // TODO: save this data to be able to show an anon tx + loop.next(); + } } else { // no address, move to next vout loop.next(); } - }, function(){ - // check for hidden/anonymous outputs - vhidden.forEach(function(vanon, i) { - if (vanon.vpub_old > 0) { - module.exports.convert_to_satoshi(parseFloat(vanon.vpub_old), function(amount_sat){ - arr_vout.push({addresses:"private_tx", amount:amount_sat}); - }); - } else { - module.exports.convert_to_satoshi(parseFloat(vanon.vpub_new), function(amount_sat){ - if (vhidden.length > 0 && (!vout || vout.length == 0) && (!vin || vin.length == 0)) { - // hidden sender is sending to hidden recipient - // the sent and received values are not known in this case. only the fee paid is known and subtracted from the sender. - arr_vout.push({addresses:"private_tx", amount:0}); - } - // add a private send address with the known amount sent - arr_vin.push({addresses:"private_tx", amount:amount_sat}); - }); - } - }); + }, function() { + // check if zksnarks is enabled + if (settings.blockchain_specific.zksnarks.enabled == true) { + // check for hidden/anonymous outputs + vhidden.forEach(function(vanon, i) { + if (vanon.vpub_old > 0) { + module.exports.convert_to_satoshi(parseFloat(vanon.vpub_old), function(amount_sat) { + arr_vout.push({addresses: "private_tx", amount: amount_sat}); + }); + } else { + module.exports.convert_to_satoshi(parseFloat(vanon.vpub_new), function(amount_sat) { + if (vhidden.length > 0 && (!vout || vout.length == 0) && (!vin || vin.length == 0)) { + // hidden sender is sending to hidden recipient + // the sent and received values are not known in this case. only the fee paid is known and subtracted from the sender. + arr_vout.push({addresses: "private_tx", amount: 0}); + } + // add a private send address with the known amount sent + arr_vin.push({addresses: "private_tx", amount: amount_sat}); + }); + } + }); + } if (typeof vout[0] !== 'undefined' && vout[0].scriptPubKey.type == 'nonstandard') { - if ( arr_vin.length > 0 && arr_vout.length > 0 ) { + if (arr_vin.length > 0 && arr_vout.length > 0) { if (arr_vin[0].addresses == arr_vout[0].addresses) { //PoS arr_vout[0].amount = arr_vout[0].amount - arr_vin[0].amount; arr_vin.shift(); return cb(arr_vout, arr_vin); - } else { + } else return cb(arr_vout, arr_vin); - } - } else { + } else return cb(arr_vout, arr_vin); - } - } else { + } else return cb(arr_vout, arr_vin); - } }); }, diff --git a/lib/locale.js b/lib/locale.js index 70cacff..0a2145d 100644 --- a/lib/locale.js +++ b/lib/locale.js @@ -56,6 +56,7 @@ exports.total_sent = "Total Sent", exports.total_received = "Total Received", exports.confirmations = "Confirmations", exports.total = "Total", +exports.total_top_100 = "Top 1-100 Total", exports.bits = "Bits", exports.nonce = "Nonce", exports.new_coins = "New Coins", @@ -98,7 +99,7 @@ exports.api_getmasternodelist = "Returns the complete list of masternodes on the exports.api_getmasternodecount = "Returns the total number of masternodes on the network.", exports.api_getvotelist = "Returns the current vote list.", exports.api_getblockcount = "Returns the number of blocks currently in the block chain.", -exports.api_getblockhash = "Returns the hash of the block at ; index 0 is the genesis block.", +exports.api_getblockhash = "Returns the hash of the block at [index]; index 0 is the genesis block.", exports.api_getblock = "Returns information about the block with the given hash.", exports.api_getrawtransaction = "Returns raw transaction representation for given transaction id. decrypt can be set to 0(false) or 1(true).", exports.api_getmaxmoney = 'Returns the maximum possible money supply.', @@ -108,7 +109,7 @@ exports.api_getphase = 'Returns the current voting phase (\'Mint\', \'Limit\' or exports.api_getreward = 'Returns the current block reward, which has been decided democratically in the previous round of block reward voting.', exports.api_getsupply = 'Returns the current money supply.', exports.api_getnextrewardestimate = 'Returns an estimate for the next block reward based on the current state of decentralized voting.', -exports.api_getnextrewardwhenstr = 'Returns string describing how long until the votes are tallied and the next block reward is computed.', +exports.api_getnextrewardwhenstr = 'Returns a string describing how long until the votes are tallied and the next block reward is computed.', // Markets view exports.mkt_hours = "24 hours", @@ -132,12 +133,11 @@ exports.mkt_trade_history = "Trade History", exports.mkt_type = "Type", exports.mkt_time_stamp = "Time Stamp", exports.mkt_select = "Market Select", -// Heavy +// Heavycoin exports.heavy_vote = "Vote", - // Heavy rewards view +// Heavycoin rewards view exports.heavy_title = "Reward/voting information", - exports.heavy_cap = "Coin Cap", exports.heavy_phase = "Phase", exports.heavy_maxvote = "Max Vote", diff --git a/lib/nodeapi.js b/lib/nodeapi.js index c34591b..2f4e24c 100644 --- a/lib/nodeapi.js +++ b/lib/nodeapi.js @@ -82,12 +82,30 @@ module.exports = function() { function hasAccess(req, res, next) { var method = req.path.substring(1, req.path.length); - var method_enabled = settings.public_api.rpc[method]; + var method_enabled = false; + + // check if this is a "normal" api method + if (settings.api_page.public_apis.rpc[method] != null) { + // check the enabled property of this normal method + method_enabled = settings.api_page.public_apis.rpc[method].enabled; + } else { + // look for this method in the list of blockchain specific features + Object.keys(settings.blockchain_specific).forEach(function(key, index, map) { + // check if this feature is enabled and has a definition for this api cmd + if (settings.blockchain_specific[key].enabled == true && settings.blockchain_specific[key]['public_apis'] != null && settings.blockchain_specific[key]['public_apis'][method] != null) { + // check the enabled properly of this blockchain specific method + method_enabled = settings.blockchain_specific[key]['public_apis'][method].enabled; + } + }); + } // only show disabled msg for outside calls. internal calls should always go through - if ((!settings.display.api || method_enabled == null || !method_enabled) && req.headers.host.indexOf('127.0.0.1') == -1) + if ((!settings.api_page.enabled || method_enabled == null || !method_enabled) && req.headers.host.indexOf('127.0.0.1') == -1) res.end('This method is disabled'); - else { + else if (method == 'getnetworkhashps' && !settings.shared_pages.show_hashrate) { + // getnetworkhashps requires show_hashrate to be enabled or else hashrate cannot be returned + res.end('-'); + } else { if (accesslist.type == 'all') return next(); @@ -152,7 +170,7 @@ module.exports = function() { case 'getnextrewardestimate': case 'getnextrewardwhenstr': case 'getsupply': - var cmd = prepareRpcCommand(settings.api_cmds.heavies[method_name]); + var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds[method_name]); method_name = cmd.method; params = cmd.parameters; break; diff --git a/lib/ratelimit.js b/lib/ratelimit.js new file mode 100644 index 0000000..97244d7 --- /dev/null +++ b/lib/ratelimit.js @@ -0,0 +1,52 @@ +// Initialize the rate limiting class from Matteo Agosti via https://www.matteoagosti.com/blog/2013/01/22/rate-limiting-function-calls-in-javascript/ +var RateLimit = (function() { + var RateLimit = function(maxOps, interval, allowBursts) { + this._maxRate = allowBursts ? maxOps : maxOps / interval; + this._interval = interval; + this._allowBursts = allowBursts; + + this._numOps = 0; + this._start = new Date().getTime(); + this._queue = []; + }; + + RateLimit.prototype.schedule = function(fn) { + var that = this, + rate = 0, + now = new Date().getTime(), + elapsed = now - this._start; + + if (elapsed > this._interval) { + this._numOps = 0; + this._start = now; + } + + rate = this._numOps / (this._allowBursts ? 1 : elapsed); + + if (rate < this._maxRate) { + if (this._queue.length === 0) { + this._numOps++; + fn(); + } + else { + if (fn) this._queue.push(fn); + + this._numOps++; + this._queue.shift()(); + } + } + else { + if (fn) this._queue.push(fn); + + setTimeout(function() { + that.schedule(); + }, 1 / this._maxRate); + } + }; + + return RateLimit; +})(); + +module.exports = { + RateLimit: RateLimit +}; \ No newline at end of file diff --git a/lib/settings.js b/lib/settings.js index 06fe419..acb48e8 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -1,277 +1,957 @@ /** -* The Settings Module reads the settings out of settings.json and provides -* this information to the other modules +* The Settings Module reads the settings out of settings.json and provides this information to the other modules */ var fs = require("fs"); var jsonminify = require("jsonminify"); -//The app title, visible e.g. in the browser window -exports.title = "eIquidus"; +// locale: Change language definitions. Only English is supported for now +exports.locale = "locale/en.json"; -//The url it will be accessed from -exports.address = "explorer.example.com"; - -//logo -exports.logo = "/img/logo.png"; -// header logo -exports.headerlogo = "/img/header_logo.png"; - -//The app favicon fully specified url, visible e.g. in the browser window -exports.favicon = "public/favicon.ico"; - -//What is displayed for the home button in the top-left corner (valid options are: title, coin, logo) -exports.homelink = "coin"; - -// home link logo height (value in px, only valid if using homelink = 'logo') -exports.logoheight = 50; - -// set whether page header "sticks" to top of page or not -exports.sticky_header = true; -// set whether page footer "sticks" to bottom of page or not -exports.sticky_footer = false; - -// Footer height -exports.footer_height_desktop = "50px"; -exports.footer_height_tablet = "60px"; -exports.footer_height_mobile = "70px"; - -// Social media link height -exports.social_link_percent_height_desktop = 70; -exports.social_link_percent_height_tablet = 55; -exports.social_link_percent_height_mobile = 40; - -//Theme -exports.theme = "Exor"; - -//The Port ep-lite should listen to -exports.port = process.env.PORT || 3001; - -//coin symbol, visible e.g. MAX, LTC, HVC -exports.symbol = "EXOR"; - -//coin name, visible e.g. in the browser window -exports.coin = "Exor"; - -//This setting is passed to MongoDB to set up the database +// dbsettings: a collection of settings that allow the explorer to connect to MongoDB exports.dbsettings = { + // user: The MongoDB username "user": "eiquidus", + // password: The MongoDB password "password": "Nd^p2d77ceBX!L", - "database": "blockchaindb", - "address" : "localhost", - "port" : 27017 + // database: The MongoDB database name (default: explorerdb) + "database": "explorerdb", + // address: The MongoDB hostname. This should always be 'localhost' if connecting to a local instance, otherwise specify the ip address of a remote instance + "address": "localhost", + // port: The port # that MongoDB is configured to listen for requests on (default: 27017) + "port": 27017 }; -//This setting is passed to the wallet -exports.wallet = { "host" : "127.0.0.1", - "port" : 51573, - "username" : "exorrpc", - "password" : "sSTLyCkrD94Y8&9mr^m6W^Mk367Vr!!K" +// wallet: a collection of settings that allow the explorer to connect to the coin wallet +exports.wallet = { + // host: The hostname or ip address of the wallet to connect to (default: localhost) + "host": "localhost", + // port: The port # that the wallet is configured to listen for RPC requests on (default: 51573 for Exor wallet) + "port": 51573, + // username: The wallet RPC username + "username": "exorrpc", + // password: The wallet RPC password + "password": "sSTLyCkrD94Y8&9mr^m6W^Mk367Vr!!K" }; -//Locale file -exports.locale = "locale/en.json", - -//Menu and panel items to display -// set a number to pnl variables to change the panel display order. lowest # = far left panel, highest # = far right panel, 0 = do not show panel -exports.display = { - "api": true, - "market": true, - "search": true, - "richlist": true, - "movement": true, - "network": true, - "masternodes": true, - "claim_address": true, - "claim_address_header_menu": true, - "page_header_bgcolor": "", - "page_footer_bgcolor": "", - "table_header_bgcolor": "", - "networkpnl": 1, - "difficultypnl": 2, - "masternodespnl": 3, - "coinsupplypnl": 4, - "pricepnl": 5, - "marketcappnl": 0, - "logopnl": 0 -}; - -//API view -exports.api = { - "blockindex": 6415, - "blockhash": "dd17105f9e3d79c553b3670001e0243dd21378f4f90a340d87c0e5eb0b44dfd4", - "txhash": "2af5cc842d18814b45db44b62411c8a47987fc3c56294af38572989de5c1f7d5", - "address": "EaqHssmmgEPCxaeczbZnoqM6vutv9xmhrZ", -}; - -// markets -exports.markets = { - "coin": "EXOR", - "exchange": "BTC", - "enabled": [], - "default": "", - "market_dropdown_menu": true, - "market_select_visible": true -}; - -// richlist/top100 settings -exports.richlist = { - "distribution": true, - "received": true, - "balance": true -}; - -exports.movement = { - "min_amount": 100, - "low_flag": 1000, - "high_flag": 10000 -}, - -//index -exports.index = { - // show_last_updated: determine whether to show a label above the transaction data with the last updated date - "show_last_updated": true, - "show_hashrate": false, - "difficulty": "POS", - "last_txs": 100, - "txs_per_page": 10 -}; - -// reward page -exports.reward_page = { - // show_last_updated: determine whether to show a label above the reward data with the last updated date - "show_last_updated": true -}; - -// masternodes page -exports.masternodes_page = { - // show_last_updated: determine whether to show a label above the masternode data with the last updated date - "show_last_updated": true -}; - -// movement page -exports.movement_page = { - // show_last_updated: determine whether to show a label above the movement data with the last updated date - "show_last_updated": true -}; - -// network page -exports.network_page = { - // show_last_updated: determine whether to show a label above the network data with the last updated date - "show_last_updated": true -}; - -// richlist page -exports.richlist_page = { - // show_last_updated: determine whether to show a label above the richlist data with the last updated date - "show_last_updated": true -}; - -// markets page -exports.markets_page = { - // show_last_updated: determine whether to show a label above the market data with the last updated date - "show_last_updated": true -}; - -// Add as many custom social links to be displayed in the Explorer footer as desired -exports.social_links = []; - -exports.confirmations = 6; - -//timeouts -exports.update_timeout = 125; -exports.check_timeout = 250; -exports.block_parallel_tasks = 1; - -//genesis -exports.genesis_tx = "dd1d332ad2d8d8f49195056d482ae3c96fd2d16e9d166413b27ca7f19775644c"; -exports.genesis_block = "0000860fcf946b44df0e7d85d6757d45f8de6f4c9aacc5c7b6abc13db1f68819"; - -exports.use_rpc = true; -exports.heavy = false; -exports.save_stats_after_sync_blocks = 100; -exports.lock_during_index = false; -exports.txcount = 100; -exports.txcount_per_page = 50; -exports.show_sent_received = true; -exports.supply = "TXOUTSET"; -exports.nethash = "getnetworkhashps"; -exports.nethash_units = "G"; - -// simple Cross-Origin Resource Sharing (CORS) support -// enabling this feature will add a new output header to all requests like this: Access-Control-Allow-Origin: -// corsorigin "*" will allow any origin to access the requested resource while specifying any other value for corsorigin will allow cross-origin requests only when the request is made from a source that matches the corsorigin filter -exports.usecors = false; -exports.corsorigin = "*"; - -exports.labels = {}; -exports.burned_coins = []; - -// Enable/disable the use of specific public apis -exports.public_api = { - "rpc": { - "getdifficulty": true, - "getconnectioncount": true, - "getblockcount": true, - "getblockhash": true, - "getblock": true, - "getrawtransaction": true, - "getnetworkhashps": true, - "getvotelist": true, - "getmasternodecount": true, - "getmaxmoney": true, - "getmaxvote": true, - "getvote": true, - "getphase": true, - "getreward": true, - "getsupply": true, - "getnextrewardestimate": true, - "getnextrewardwhenstr": true - }, - "ext": { - "getmoneysupply": true, - "getdistribution": true, - "getaddress": true, - "getaddresstxs": true, - "gettx": true, - "getbalance": true, - "getlasttxs": true, - "getcurrentprice": true, - "getbasicstats": true, - "getsummary": true, - "getnetworkpeers": true, - "getmasternodelist": true, - "getmasternoderewards": true, - "getmasternoderewardstotal": true +// webserver: a collection of settings that pertain to the node.js express web framework (read more: https://www.npmjs.com/package/express) +exports.webserver = { + // port: Port # to configure the express webserver to listen for requests on + // NOTE: Be sure to configure firewalls to allow traffic through this port or the explorer website may not be accessible remotely + "port": process.env.PORT || 3001, + // cors: a collection of settings that pertain to the cors feature + // Cross-Origin Resource Sharing (CORS) support (read more: https://www.maxcdn.com/one/visual-glossary/cors/) + // Enable this setting to allow another website to access data from the explorer without violating the same-origin policy + "cors": { + // enabled: Enable/disable CORS + // If set to true, a new output header will be added to all http requests like this: Access-Control-Allow-Origin: + // If set to false, the cors feature will be completely disabled + "enabled": false, + // corsorigin: Used to whitelist an http domain name for access to this explorer's resources + // The whitelisted domain must be in the format: https://example.com + // Specifying a "*" for the corsorigin will allow any domain to access the resources of this site + "corsorigin": "*" } }; -// Customized API commands +// coin: a collection of settings that pertain to the cryptocurrency being explored +exports.coin = { + // name: Name of the cryptocurrency coin being explored. This value is displayed in the page header when the "shared_pages.page_header.home_link" setting is set to "coin". + // NOTE: This value acts as a unique identifier for data stored in mongo and therefore cannot be changed without re-syncing all existing data. + "name": "Exor", + // symbol: The cryptocurrency coin ticker/symbol value. This value is displayed anywhere that coin data is displayed including the index, address, block, movement, reward, richlist/top100 and tx pages + "symbol": "EXOR" +}; + +/* Shared page settings */ + +// shared_pages: a collection of settings that pertain to all webpages for the explorer +exports.shared_pages = { + // theme: Change the look & feel of the explorer with a unique theme. Uses bootswatch themes (https://bootswatch.com) + // Valid options: Cerulean, Cosmo, Cyborg, Darkly, Exor, Flatly, Journal, Litera, Lumen, Lux, Materia, Minty, Pulse, Sandstone, Simplex, Sketchy, Slate, Solar, Spacelab, Superhero, United, Yeti + // (see /public/css/themes for available themes) + "theme": "Exor", + // page_title: The text to display in the HTML title tag and also displayed in the page header when the "shared_pages.page_header.home_link" setting is set to "title" + "page_title": "eIquidus", + // favicon: The path to an icon file that is displayed in a browser window/tab and serves as branding for your website. Its main purpose is to help visitors locate your page easier when they have multiple tabs open + // NOTE: The path root is / + "favicon": "public/favicon.ico", + // logo: The path to an image file that is displayed on the api page as well as in one of the top panels when enabled + // This logo can also be displayed in the header when the "shared_pages.page_header.home_link" setting is set to "logo" and the "shared_pages.page_header.home_link_logo" setting is blank or an invalid file + // NOTE: The path root is /public + // The optimum logo size is 128x128 as the image will be forced to 128px high when displayed + "logo": "/img/logo.png", + // table_header_bgcolor: Change the background color of all table headers + // valid options: light, dark or leave blank ( "" ) for default colors + "table_header_bgcolor": "", + // confirmations: Number of confirmations before a block or transaction can be considered valid + // if confirms are >= to this value then the block or tx is considered valid and shows up in green + // if confirms are < this value by more than 50% then the block or tx is considered unconfirmed and shows up in red + // if confirms are < this value by less than 50% then the block or tx is considered unconfirmed and shows up in orange + "confirmations": 40, + // difficulty: Determine which network difficulty value to display (valid options are: POW, POS or Hybrid) + // Some blockchains show different difficulty values depending on available POW/POS options: + // POW: Display the proof-of-work difficulty value + // POS: Display the proof-of-stake difficulty value + // Hybrid: Display both the proof-of-work and proof-of-stake difficulty values + "difficulty": "POS", + // show_hashrate: Determine whether to show network hash rate where applicable (true/false) + // If set to false, the /api/getnetworkhashps and /ext/getsummary apis will no longer show hash rate information + "show_hashrate": true, + // page_header: A collection of settings that pertain to the page header that is displayed at the top of all pages + "page_header": { + // sticky_header: Determine whether page header "sticks" to top of page or not (true/false) + "sticky_header": true, + // bgcolor: Change the background color of the page header + // valid options: light, dark, primary, secondary, success, info, warning, danger or leave blank ( "" ) for default colors + "bgcolor": "", + // home_link: The home link setting determines what is displayed in the top-left corner of the header menu. Valid options: + // title: display "shared_pages.page_title" text setting + // coin: display "coin.name" text setting + // logo: display the "shared_pages.page_header.home_link_logo" image if it's set to a valid image, otherwise display the "shared_pages.logo" image + "home_link": "logo", + // home_link_logo: The path to a logo image that is displayed on page header when the "shared_pages.page_header.home_link" setting is set to "logo" + // If the home_link_logo is left blank or not set to a valid file, the "shared_pages.page_header.home_link" = "logo" setting will automatically default to displaying the original "shared_pages.logo" instead of the "shared_pages.page_header.home_link_logo" + // NOTE: The path root is /public + "home_link_logo": "/img/header_logo.png", + // home_link_logo_height: The max-height value of the "shared_pages.page_header.home_link" logo image (value in px, only valid if "shared_pages.page_header.home_link" = 'logo') + "home_link_logo_height": 50, + // panels: a collection of settings that pertain to the panels displayed on page header of all pages + // A maximum of 5 panels can be shown across the top of the page at any time, so if more than 5 are enabled, only the first 5 will be shown + "panels": { + // network_panel: a collection of settings that pertain to the network panel which displays the current network hash rate (only applicable to POW coins) + "network_panel": { + // enabled: Enable/disable the network panel (true/false) + // If set to false, the network panel will be completely inaccessible + "enabled": false, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 0, + // nethash: Determine how to acquire network hashrate. Valid options: + // getnetworkhashps: retrieved from getnetworkhashps rpc cmd + // netmhashps: retrieved from getmininginfo rpc cmd + "nethash": "getnetworkhashps", + // nethash_units: Determine which units should be used to display the network hashrate. Valid options: + // P: Display value in petahashes (PH/s) + // T: Display value in terahashes (TH/s) + // G: Display value in gigahashes (GH/s) + // M: Display value in megahashes (MH/s) + // K: Display value in kilohashes (KH/s) + // H: Display value in hashes (H/s) + "nethash_units": "G" + }, + // difficulty_panel: a collection of settings that pertain to the difficulty panel which displays the current proof-of-work difficulty (only applicable to POW coins) + "difficulty_panel": { + // enabled: Enable/disable the difficulty panel (true/false) + // If set to false, the difficulty panel will be completely inaccessible + "enabled": false, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 0 + }, + // masternodes_panel: a collection of settings that pertain to the masternode panel which displays a count of online and unreachable masternodes (only applicable to masternode coins) + "masternodes_panel": { + // enabled: Enable/disable the masternode panel (true/false) + // If set to false, the masternode panel will be completely inaccessible + "enabled": true, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 2 + }, + // coin_supply_panel: a collection of settings that pertain to the coin supply panel which displays the current circulating coin supply value + "coin_supply_panel": { + // enabled: Enable/disable the coin supply panel (true/false) + // If set to false, the coin supply panel will be completely inaccessible + "enabled": true, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 1 + }, + // price_panel: a collection of settings that pertain to the price panel which displays the current market price in BTC + "price_panel": { + // enabled: Enable/disable the price panel (true/false) + // If set to false, the price panel will be completely inaccessible + "enabled": true, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 4 + }, + // market_cap_panel: a collection of settings that pertain to the market cap panel which displays the current market cap value in BTC + "market_cap_panel": { + // enabled: Enable/disable the market cap panel (true/false) + // If set to false, the market cap panel will be completely inaccessible + "enabled": true, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 5 + }, + // logo_panel: a collection of settings that pertain to the logo panel which displays the selected "shared_pages.logo" image + "logo_panel": { + // enabled: Enable/disable the logo panel (true/false) + // If set to false, the logo panel will be completely inaccessible + "enabled": true, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 3 + } + }, + // show_search: Enable/disable the ability to search the explorer website (true/false) + // If set to false, the explorer will not display a search box or respond to search queries + "show_search": true + }, + // page_footer: A collection of settings that pertain to the page footer that is displayed at the bottom of all pages + "page_footer": { + // sticky_footer: Determine whether the page footer "sticks" to bottom of the page or not (true/false) + "sticky_footer": false, + // bgcolor: Change the background color of the page footer + // valid options: light, dark, primary, secondary, success, info, warning, danger or leave blank ( "" ) for default colors + "bgcolor": "", + // Customize the height of the footer for the following screen sizes: + // Mobile (0-575px) + // Tablet (576-991px) + // Desktop (>= 992px) + // Supports any valid height value in pixels (Ex: "50px") or percent (Ex: "10%") + // footer_height_desktop: Forced footer height value for desktop screens + "footer_height_desktop": "50px", + // footer_height_tablet: Forced footer height value for tablet screens + "footer_height_tablet": "70px", + // footer_height_mobile: Forced footer height value for mobile screens + "footer_height_mobile": "70px", + // social_links: a collection of settings that pertain to the social links on the page footer + // Add as many custom social links to be displayed in the page footer as desired + // For each entry you must fill in the image_path or fontawesome_class to determine the image or icon to show for the url link. It is not necessary to fill in both as only the 1st filled-in value will be used + "social_links": [], + // Customize the height of the social media links in the footer for the following screen sizes: + // Mobile (0-575px) + // Tablet (576-991px) + // Desktop (>= 992px) + // This is a percentage value and must be a positive number between 1-100 + // social_link_percent_height_desktop: Forced social link height percentage value for desktop screens + "social_link_percent_height_desktop": 70, + // social_link_percent_height_tablet: Forced social link height percentage value for tablet screens + "social_link_percent_height_tablet": 42, + // social_link_percent_height_mobile: Forced social link height percentage value for mobile screens + "social_link_percent_height_mobile": 40 + } +}; + +/* Built-in Pages (cannot be disabled) */ + +// index_page: a collection of settings that pertain to the index page +exports.index_page = { + // show_last_updated: Determine whether to show a label above the transaction data with the last updated date (true/false) + "show_last_updated": true, + // transaction_table: a collection of settings that pertain to the transaction table on the index page + // Table data is populated via the /ext/getlasttxs api + "transaction_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 + // NOTE: Page length options will be limited based on the max_items_per_query for the /ext/getlasttxs api + "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, + // reload_table_seconds: The time in seconds to automatically reload the table data from the server + // Set to 0 to disable automatic reloading of table data + "reload_table_seconds": 60 + } +}; + +// block_page: a collection of settings that pertain to the block page +exports.block_page = { + // genesis_block: Your coins genesis block hash is used to determine the beginning of the blockchain + // For many bitcoin clones you can use the following cmd to get the block hash of the genesis block: coin-cli getblockhash 0 + // NOTE: If this value is not entered correctly it will not be possible for the explorer to find or navigate to the genesis block, neither via block or transaction hash + "genesis_block": "00014f36c648cdbc750f7dd28487a23cd9e0b0f95f5fccc5b5d01367e3f57469" +}; + +// transaction_page: a collection of settings that pertain to the transaction/tx page +exports.transaction_page = { + // genesis_tx: Your coins genesis transaction hash is used to determine the beginning of the blockchain + // For many bitcoin clones you can use the following cmd to find the list of transaction hashes from the genesis block: coin-cli getblock 00014f36c648cdbc750f7dd28487a23cd9e0b0f95f5fccc5b5d01367e3f57469 + // NOTE: If this value is not entered correctly it will not be possible for the explorer to find or navigate to the genesis block by searching for the genesis transaction hash + "genesis_tx": "dd1d332ad2d8d8f49195056d482ae3c96fd2d16e9d166413b27ca7f19775644c" +}; + +// address_page: a collection of settings that pertain to the address page +exports.address_page = { + // show_sent_received: Determine whether to show Total Sent and Total Received columns at the top of the address page + "show_sent_received": false, + // history_table: a collection of settings that pertain to the history table on the address page + // Table data is populated via the /ext/getaddresstxs api + "history_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 + // NOTE: Page length options will be limited based on the max_items_per_query for the /ext/getaddresstxs api + "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": 50 + } +}; + +/* Additional Pages (can be enabled/disabled via settings) */ + +// masternodes_page: a collection of settings that pertain to the masternodes page +exports.masternodes_page = { + // enabled: Enable/disable the masternodes page (true/false) + // If set to false, the masternodes page will be completely inaccessible + "enabled": true, + // show_last_updated: determine whether to show a label above the masternode data with the last updated date (true/false) + "show_last_updated": true, + // masternode_table: a collection of settings that pertain to the masternode table on the masternodes page + // Table data is populated via the /ext/getmasternodelist api + "masternode_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 + } +}; + +// movement_page: a collection of settings that pertain to the movement page +exports.movement_page = { + // enabled: Enable/disable the movement page (true/false) + // If set to false, the movement page will be completely inaccessible + "enabled": true, + // show_last_updated: determine whether to show a label above the movement data with the last updated date (true/false) + "show_last_updated": true, + // movement_table: a collection of settings that pertain to the movement table on the movement page + // Table data is populated via the /ext/getlasttxs api + "movement_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 + // NOTE: Page length options will be limited based on the max_items_per_query for the /ext/getlasttxs api + "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, + // reload_table_seconds: The time in seconds to automatically reload the table data from the server + // Set to 0 to disable automatic reloading of table data + "reload_table_seconds": 45, + // min_amount: The minimum number of coins that need to be received in a single transaction to show up on the movement page + "min_amount": 5000, + // low low_warning_flag: Flag all transactions in yellow/orange that are sent with coin amounts above this value + "low_warning_flag": 50000, + // high_warning_flag: Flag all transactions in red that are sent with coin amounts above this value + "high_warning_flag": 100000 + } +}; + +// network_page: a collection of settings that pertain to the network page +exports.network_page = { + // enabled: Enable/disable the network page (true/false) + // If set to false, the network page will be completely inaccessible + "enabled": true, + // show_last_updated: determine whether to show a label above the network data with the last updated date (true/false) + "show_last_updated": true, + // connections_table: a collection of settings that pertain to the connections table on the network page + // Table data is populated via the /ext/getnetworkpeers api + "connections_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 ], + // items_per_page: The default amount of items/records to display in the table at any given time + "items_per_page": 10 + }, + // addnodes_table: a collection of settings that pertain to the add nodes table on the network page + // Table data is populated via the /ext/getnetworkpeers api + "addnodes_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 ], + // items_per_page: The default amount of items/records to display in the table at any given time + "items_per_page": 10 + }, + // onetry_table: a collection of settings that pertain to the one try table on the network page + // Table data is populated via the /ext/getnetworkpeers api + "onetry_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 ], + // items_per_page: The default amount of items/records to display in the table at any given time + "items_per_page": 10 + } +}; + +// richlist_page: a collection of settings that pertain to the richlist/top100 page +exports.richlist_page = { + // enabled: Enable/disable the richlist/top100 page (true/false) + // If set to false, the richlist/top100 page will be completely inaccessible + "enabled": true, + // show_last_updated: determine whether to show a label above the richlist/top100 data with the last updated date (true/false) + "show_last_updated": true, + // show_current_balance: Determine whether to show the top 100 list of wallet addresses that currently have the most coins in a single wallet (true/false) + "show_current_balance": true, + // show_received_coins: Determine whether to show the top 100 list of wallet addresses that have the highest total number of coins received based on adding up all received transactions (true/false) + "show_received_coins": true, + // wealth_distribution: a collection of settings that pertain to the wealth distribution section of the richlist/top100 page + // This section features a summary table with the breakdown of coins owned by the top 1-25, 26-50, 51-75, 76-100, 101+ wallets and all burned coins plus an associated pie chart + "wealth_distribution": { + // show_distribution_table: Show/hide the wealth distribution summary table with the breakdown of coins owned by the top 1-25, 26-50, 51-75, 76-100, 101+ wallets and all burned coins (true/false) + // If set to false, the wealth distribution table will be completely hidden + "show_distribution_table": true, + // show_distribution_chart: Show/hide the wealth distribution pie chart with the breakdown of coins owned by the top 1-25, 26-50, 51-75, 76-100, 101+ wallets and all burned coins (true/false) + // If set to false, the wealth distribution pie chart will be completely hidden + "show_distribution_chart": true, + // colors: An array of html color codes to represent the top 100 groupings in the wealth distribution table and pie chart + // From left-to-right the 6 colors are represented as the following: "top 1-25", "top 26-50", "top 51-75", "top 76-100", "101+" and "burned coins" - which is used if the include_burned_coins_in_distribution setting is enabled + "colors": [ "#e73cbd", "#00bc8c", "#3498db", "#e3ce3e", "#adb5bd", "#e74c3c" ] + }, + // burned_coins: a collection of settings that pertain to the wallet addresses that should not appear in the richlist/top100 page + // NOTE: These settings won't take effect until after running (and completing) a normal index sync or reindex-rich + "burned_coins": { + // addresses: An array of wallet addresses to exclude from the richlist/top100 page + // Use this setting to prevent specific wallet addresses from being displayed in the rich list and wealth distribution chart sections + // These wallet addresses will be completely removed from the rich list, but will still be viewable and accessible via the rest of the explorer pages as per normal + // Add as many wallet addresses as necessary in the following format: [ "EPUzEEHa45Rsn87WBos6SqkZZ8GrsfgvtZ", "EUzgat1r5AFyoTXK5WgTyM8kABPJY1SX7E" ] + "addresses": [ "EXorBurnAddressXXXXXXXXXXXXXW7cDZQ" ], + // include_burned_coins_in_distribution: Determine whether to include burned coins in the wealth distribution section or not + // This setting will need to be changed depending on whether your main coin supply value already has the burned coins removed from its total or not + // Set this value to false if your blockchain already has a mechanism for removing burned coins from the total supply and the burned coins will not be included in the distribution totals + // Set this value to true if your blockchain still has the burned coins included in its total supply and a 'Burned Coins' section will be added to the distribution table and chart + "include_burned_coins_in_distribution": false + } +}; + +// markets_page: a collection of settings that pertain to the markets page +exports.markets_page = { + // enabled: Enable/disable the markets pages (true/false) + // If set to false, all market pages will be completely inaccessible + "enabled": false, + // show_last_updated: determine whether to show a label above the market data with the last updated date (true/false) + "show_last_updated": true, + // show_market_dropdown_menu: Determine whether the markets menu in the page header will function as a dropdown or a single-click menu item that opens the default market (true/false) + // If set to true, the markets header menu will function as a dropdown that allows selecting from all available markets + // If set to false, the markets header menu will function as a single-click menu item that opens the default market only + // NOTE: The dropdown will only work when 2 or more markets are enabled, otherwise it will default to a single-click menu item automatically + "show_market_dropdown_menu": true, + // show_market_select: Determine whether all market pages will display a clickable list of enabled markets near the top of the page for quick selection or not (true/false) + // If set to true, then all market pages will display a clickable list of enabled markets near the top of the page for quick selection + // If set to false, then no market select box will be shown on market pages + // NOTE: The market select box will only be visible when 2 or more markets are enabled, otherwise it will be hidden automatically + "show_market_select": true, + // exchanges: Enable/disable api integration with any of the available built-in exchanges + // Enabled exchanges display a number of exchange-related metrics including market summary, 24 hour chart, most recent buy/sell orders and latest trade history + // Supported exchanges: altmarkets, bittrex, bleutrade, crex, poloniex, stex, yobit + "exchanges": { + // altmarkets: a collection of settings that pertain to the altmarkets exchange + "altmarkets": { + // enabled: Enable/disable the altmarkets exchange (true/false) + // If set to false, the altmarkets page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC", "LTC/ETH" ] + }, + // bittrex: a collection of settings that pertain to the bittrex exchange + "bittrex": { + // enabled: Enable/disable the bittrex exchange (true/false) + // If set to false, the bittrex page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC" ] + }, + // bleutrade: a collection of settings that pertain to the bleutrade exchange + "bleutrade": { + // enabled: Enable/disable the bleutrade exchange (true/false) + // If set to false, the bleutrade page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC" ] + }, + // crex: a collection of settings that pertain to the crex exchange + "crex": { + // enabled: Enable/disable the crex exchange (true/false) + // If set to false, the crex page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC" ] + }, + // poloniex: a collection of settings that pertain to the poloniex exchange + "poloniex": { + // enabled: Enable/disable the poloniex exchange (true/false) + // If set to false, the poloniex page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC" ] + }, + // stex: a collection of settings that pertain to the stex exchange + "stex": { + // enabled: Enable/disable the stex exchange (true/false) + // If set to false, the stex page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC", "LTC/USDT" ] + }, + // yobit: a collection of settings that pertain to the yobit exchange + // NOTE: yobit does not display a 24-hour chart due to yobit's lack of OHLCV api data + "yobit": { + // enabled: Enable/disable the yobit exchange (true/false) + // If set to false, the yobit page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC" ] + } + }, + // default_exchange: a collection of settings that pertain to the default exchange + // When the "show_market_dropdown_menu" setting is disabled, the market header menu will navigate directly to the default exchange page + // The default exchange is also used to determine the last market price + // If left blank or filled out incorrectly, the first enabled exchange and trading pair will be used as the default exchange + "default_exchange": { + // exchange_name: The name of the default exchange must exactly match the name of an exchange in the "exchanges" setting above + // See the list of supported exchanges above for the list of supported exchange names + "exchange_name": "stex", + // trading_pair: The name of the trading pair for the default exchange must exactly match the name of a trading pair from the "exchanges" setting above + "trading_pair": "LTC/BTC" + } +}; + +// api_page: a collection of settings that pertain to the api page +exports.api_page = { + // enabled: Enable/disable the public api system (true/false) + // If set to false, the entire api page will be disabled and all public api endpoints will show a "This method is disabled" msg when called regardless of their individual enabled statuses + "enabled": true, + // sample_data: a collection of settings that pertain to the sample data that is used to display example api links to real data + "sample_data": { + // blockindex: This value can be any valid block height number from your coins blockchain + // NOTE: This value is only used to build example api links on the api page from the /api/getblockhash api for example + "blockindex": 64152, + // blockhash: This value can be any valid block hash from your coins blockchain + // For many bitcoin clones you can use the following cmd to get the block hash for a given block height: coin-cli getblockhash 64152 + // NOTE: This value is only used to build example api links on the api page from the /api/getblock api for example + "blockhash": "775d67da29dd6553268061f86368d06654944dd5d5c61db4c97e4c7960c11a74", + // txhash: This value can be any valid transaction hash from your coins blockchain + // For many bitcoin clones you can use the following cmd to find a list of tx hashes for a given block hash: coin-cli getblock 000000001ba119a0f6d49ebabd83343b125d7ee3d3184b1b41d6a7f2051153eb + // NOTE: This value is only used to build example api links on the api page from the /api/getrawtransaction api for example + "txhash": "6cb3babd256de253f926f10bc8574dadf0a3e2fc8380107b81eb07c67d1e73ed", + // address: This value can be any valid wallet address from your coins blockchain that has received at least 1 or more coin transactions + // NOTE: This value is only used to build example api links on the api page from the /ext/getaddress api for example + "address": "ELvb8AZRgHmdsDnD1HYFwbSY4UkPhoECCW" + }, + // public_apis: a collection of settings that pertain to the public api command system + // NOTE: Disabling any of these apis will remove the api definition from the api page and will return a "This method is disabled" msg if the api endpoint is called. + // Some public apis are used internally by the explorer such as the /ext/getlasttxs api and even if disabled from here the internal api will still continue to function. + "public_apis": { + // rpc: a collection of settings that pertain to the rpc cmd apis that are retrieved from the coin wallet rpc api + "rpc": { + // getdifficulty: a collection of settings that pertain to the /api/getdifficulty api endpoint + // Returns the proof-of-work difficulty as a multiple of the minimum difficulty + // NOTE: This api is not used internally and is therefore only publicly available + "getdifficulty": { + // enabled: Enable/disable the /api/getdifficulty api endpoint (true/false) + // If set to false, the /api/getdifficulty api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getconnectioncount: a collection of settings that pertain to the /api/getconnectioncount api endpoint + // Returns the number of connections to other nodes + // NOTE: This api is not used internally and is therefore only publicly available + "getconnectioncount": { + // enabled: Enable/disable the /api/getconnectioncount api endpoint (true/false) + // If set to false, the /api/getconnectioncount api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getblockcount: a collection of settings that pertain to the /api/getblockcount api endpoint + // Returns the number of blocks in the longest blockchain + // NOTE: This api is not used internally and is therefore only publicly available + "getblockcount": { + // enabled: Enable/disable the /api/getblockcount api endpoint (true/false) + // If set to false, the /api/getblockcount api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getblockhash: a collection of settings that pertain to the /api/getblockhash api endpoint + // Returns hash of block in best-block-chain at height provided + // NOTE: This api is not used internally and is therefore only publicly available + "getblockhash": { + // enabled: Enable/disable the /api/getblockhash api endpoint (true/false) + // If set to false, the /api/getblockhash api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getblock: a collection of settings that pertain to the /api/getblock api endpoint + // Returns an object with information about the block + // NOTE: This api is not used internally except for a link on the block page to view the raw block data, which will be automatically removed/hidden when this api is disabled + "getblock": { + // enabled: Enable/disable the /api/getblock api endpoint (true/false) + // If set to false, the /api/getblock api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getrawtransaction: a collection of settings that pertain to the /api/getrawtransaction api endpoint + // Returns raw transaction data + // NOTE: This api is not used internally except for a link on the transaction/tx page to view the raw transaction data, which will be automatically removed/hidden when this api is disabled + "getrawtransaction": { + // enabled: Enable/disable the /api/getrawtransaction api endpoint (true/false) + // If set to false, the /api/getrawtransaction api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getnetworkhashps: a collection of settings that pertain to the /api/getnetworkhashps api endpoint + // Returns the estimated network hashes per second + // NOTE: This api is not used internally and is therefore only publicly available + "getnetworkhashps": { + // enabled: Enable/disable the /api/getnetworkhashps api endpoint (true/false) + // If set to false, the /api/getnetworkhashps api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getvotelist: a collection of settings that pertain to the /api/getvotelist api endpoint + // Returns an object with details regarding the current vote list + // NOTE: This api is not used internally and is therefore only publicly available + "getvotelist": { + // enabled: Enable/disable the /api/getvotelist api endpoint (true/false) + // If set to false, the /api/getvotelist api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getmasternodecount: a collection of settings that pertain to the /api/getmasternodecount api endpoint + // Returns a json object containing the total number of masternodes on the network (only applicable to masternode coins) + // NOTE: This api is not used internally and is therefore only publicly available + "getmasternodecount": { + // enabled: Enable/disable the /api/getmasternodecount api endpoint (true/false) + // If set to false, the /api/getmasternodecount api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + } + }, + // ext: a collection of settings that pertain to the extended apis that are retrieved from local mongo database collection + "ext": { + // getmoneysupply: a collection of settings that pertain to the /ext/getmoneysupply api endpoint + // Returns current money supply + // NOTE: This api is not used internally and is therefore only publicly available + "getmoneysupply": { + // enabled: Enable/disable the /ext/getmoneysupply api endpoint (true/false) + // If set to false, the /ext/getmoneysupply api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getdistribution: a collection of settings that pertain to the /ext/getdistribution api endpoint + // Returns wealth distribution stats + // NOTE: This api is not used internally and is therefore only publicly available + "getdistribution": { + // enabled: Enable/disable the /ext/getdistribution api endpoint (true/false) + // If set to false, the /ext/getdistribution api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getaddress: a collection of settings that pertain to the /ext/getaddress api endpoint + // Returns information for given address + // NOTE: This api is not used internally and is therefore only publicly available + "getaddress": { + // enabled: Enable/disable the /ext/getaddress api endpoint (true/false) + // If set to false, the /ext/getaddress api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getaddresstxs: a collection of settings that pertain to the /ext/getaddresstxs api endpoint + // Returns transactions for a wallet address starting from a particular offset + // NOTE: This api is used internally via ajax call to populate the Address History table on the address page. Disabling the api from here will not stop the Address History table from displaying data + "getaddresstxs": { + // enabled: Enable/disable the /ext/getaddresstxs api endpoint (true/false) + // If set to false, the /ext/getaddresstxs api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) but the api will still be available internally to the explorer + "enabled": true, + // max_items_per_query: The maximum # of transactions that can be returned from the /ext/getaddresstxs api endpoint in a single call + "max_items_per_query": 100 + }, + // gettx: a collection of settings that pertain to the /ext/gettx api endpoint + // Returns information for given tx hash + // NOTE: This api is not used internally and is therefore only publicly available + "gettx": { + // enabled: Enable/disable the /ext/gettx api endpoint (true/false) + // If set to false, the /ext/gettx api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getbalance: a collection of settings that pertain to the /ext/getbalance api endpoint + // Returns current balance of given address + // NOTE: This api is not used internally and is therefore only publicly available + "getbalance": { + // enabled: Enable/disable the /ext/getbalance api endpoint (true/false) + // If set to false, the /ext/getbalance api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getlasttxs: a collection of settings that pertain to the /ext/getlasttxs api endpoint + // Returns transactions greater than a specific number of coins, starting from a particular offset + // NOTE: This api is used internally via ajax call to populate the Transaction tables on the index and movement pages. Disabling the api from here will not stop the Transaction tables from displaying data + "getlasttxs": { + // enabled: Enable/disable the /ext/getlasttxs api endpoint (true/false) + // If set to false, the /ext/getlasttxs api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) but the api will still be available internally to the explorer + "enabled": true, + // max_items_per_query: The maximum # of transactions that can be returned from the /ext/getlasttxs api endpoint in a single call + "max_items_per_query": 100 + }, + // getcurrentprice: a collection of settings that pertain to the /ext/getcurrentprice api endpoint + // Returns last known exchange price + // NOTE: This api is not used internally and is therefore only publicly available + "getcurrentprice": { + // enabled: Enable/disable the /ext/getcurrentprice api endpoint (true/false) + // If set to false, the /ext/getcurrentprice api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getnetworkpeers: a collection of settings that pertain to the /ext/getnetworkpeers api endpoint + // Returns the list of network peers that have connected to the explorer node in the last 24 hours + // NOTE: This api is used internally via ajax call to populate the connections, add nodes and one try tables on the network page. Disabling the api from here will not stop the network page tables from displaying data + "getnetworkpeers": { + // enabled: Enable/disable the /ext/getnetworkpeers api endpoint (true/false) + // If set to false, the /ext/getnetworkpeers api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) but the api will still be available internally to the explorer + "enabled": true + }, + // getbasicstats: a collection of settings that pertain to the /ext/getbasicstats api endpoint + // Returns basic statistics about the coin including: block count, circulating supply, USD price, BTC price and # of masternodes (# of masternodes is only applicable to masternode coins) + // NOTE: This api is not used internally and is therefore only publicly available + "getbasicstats": { + // enabled: Enable/disable the /ext/getbasicstats api endpoint (true/false) + // If set to false, the /ext/getbasicstats api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getsummary: a collection of settings that pertain to the /ext/getsummary api endpoint + // Returns a summary of coin data including: difficulty, hybrid difficulty, circulating supply, hash rate, BTC price, network connection count, block count, count of online masternodes and count of offline masternodes (masternode counts are only applicable to masternode coins) + // NOTE: This api is used internally via ajax call to populate many of the panel boxes that are found at the top of all pages. Disabling the api from here will not stop the panel boxes from displaying data + "getsummary": { + // enabled: Enable/disable the /ext/getsummary api endpoint (true/false) + // If set to false, the /ext/getsummary api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) but the api will still be available internally to the explorer + "enabled": true + }, + // getmasternodelist: a collection of settings that pertain to the /ext/getmasternodelist api endpoint + // Returns the complete list of masternodes on the network (only applicable to masternode coins) + // NOTE: This api is used internally via ajax call to populate the Masternodes table on the masternodes page. Disabling the api from here will not stop the Masternodes table from displaying data + "getmasternodelist": { + // enabled: Enable/disable the /ext/getmasternodelist api endpoint (true/false) + // If set to false, the /ext/getmasternodelist api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) but the api will still be available internally to the explorer + "enabled": true + }, + // getmasternoderewards: a collection of settings that pertain to the /ext/getmasternoderewards api endpoint + // Returns a list of masternode reward transactions for a specific address that arrived after a specific block height (only applicable to masternode coins) + // NOTE: This api is not used internally and is therefore only publicly available + "getmasternoderewards": { + // enabled: Enable/disable the /ext/getmasternoderewards api endpoint (true/false) + // If set to false, the /ext/getmasternoderewards api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getmasternoderewardstotal: a collection of settings that pertain to the /ext/getmasternoderewardstotal api endpoint + // 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) + // NOTE: This api is not used internally and is therefore only publicly available + "getmasternoderewardstotal": { + // enabled: Enable/disable the /ext/getmasternoderewardstotal api endpoint (true/false) + // If set to false, the /ext/getmasternoderewardstotal api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + } + } + } +}; + +// claim_address_page: a collection of settings that pertain to the claim address page +exports.claim_address_page = { + // enabled: Enable/disable the ability for users to claim a wallet address (true/false) + // If set to false, the claim page will be completely inaccessible + // NOTE: Disabling this feature after addresses have already been claimed will effectively hide the claimed values and restore the original wallet addresses again + "enabled": true, + // show_header_menu: Show/hide the "Claim Address" header menu item (true/false) + // If set to false, the claim address page can still be accessed via the claim link on each address page + // NOTE: The "claim_address_page.enabled" setting must also be set to true or else the header item will automatically be hidden as well + "show_header_menu": true, + // enable_bad_word_filter: Enable/disable the "bad word" filter for claimed addresses, so that trying to claim an address with a bad word like "ash0le" will fail + // This feature uses the default blacklist from the "bad-words" plugin from here: https://www.npmjs.com/package/bad-words + "enable_bad_word_filter": true +}; + +// 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. + // If you sync using more than 1 parallel task, then historical balance data for wallet addresses can possibly be saved out-of-order and there is currently no workaround for this. + // Therefore, it is recommended to keep this setting to 1 parallel task for now until a proper solution can be procured for the historical balance issue. + "block_parallel_tasks": 1, + // update_timeout: The amount of time to wait (in milliseconds) before moving to the next block or transaction during blockchain sync or reindex (scripts/sync.sh /path/to/nodejs update or scripts/sync.sh /path/to/nodejs reindex) + "update_timeout": 10, + // check_timeout: The amount of time to wait (in milliseconds) before moving to the next block or transaction during a check sync (scripts/sync.sh /path/to/nodejs check) + "check_timeout": 250, + // save_stats_after_sync_blocks: During index syncronization, stats are saved after processing this many blocks to save time by not having to save after each block + "save_stats_after_sync_blocks": 100, + // show_sync_msg_when_syncing_more_than_blocks: Show the sync msg at the top of all pages during index syncronization if there are more than this many blocks to process + "show_sync_msg_when_syncing_more_than_blocks": 1000, + // supply: Determine how to calculate current coin supply + // NOTE: The supply is always retrieved right before doing a normal index sync, reindex or check + // Valid options: + // COINBASE : retrieve the total coins sent from the coinbase (Often used for PoW coins) + // GETINFO : retrieved from getinfo rpc cmd (Often used for PoS coins) + // HEAVY: retrieved from getsupply rpc cmd (The "blockchain_specific.heavycoin.enabled" setting must be set to true and the "blockchain_specific.heavycoin.api_cmds.getsupply" setting must be set up correctly for this option to work properly) + // BALANCES : get the supply by running a query on the addresses collection and summing up all positive balances (potentially a long running query for blockchains with tons of addresses) + // TXOUTSET : retrieved from gettxoutsetinfo rpc cmd + "supply": "GETINFO" +}; + +// labels: a collection of settings that pertain to the list of customized wallet address labels +// Adding entries to this section will display a custom label beside each affected wallet address when displayed in the explorer +// NOTE: You can add as many address labels as desired +exports.labels = {}; + +//api_cmds: A collection of settings that pertain to the list of customizable rpc api commands +// Not all blockchains utilize the same rpc cmds for accessing the internal daemon api. Use these settings to set alternate names for similar api cmds. +// Leaving a cmd value blank ( "" ) will completely disable use of that cmd. +// NOTICE: Some apis such as getblockhash for example, are integral to the functionality of the explorer and will result in a fairly unusable experience if disabled. exports.api_cmds = { + // use_rpc: Determine whether to call rpc api cmds directly using the faster rpc method or using the older method via internal http api (true/false) + // NOTE: This should always be set to true unless there is a specific need to test or log certain apis + "use_rpc": true, + // getnetworkhashps: Returns the estimated network hashes per second. This should be a positive whole number "getnetworkhashps": "getnetworkhashps", + // getmininginfo: Returns a json object containing mining-related information "getmininginfo": "getmininginfo", + // getdifficulty: Returns the proof-of-work difficulty as a multiple of the minimum difficulty. This should be a positive whole or decimal number "getdifficulty": "getdifficulty", + // getconnectioncount: Returns the number of connections to other nodes. This should be a positive whole number "getconnectioncount": "getconnectioncount", + // getblockcount: Returns the number of blocks in the longest blockchain. This should be a positive whole number "getblockcount": "getblockcount", + // getblockhash: Returns hash of block in best-block-chain at height provided. This should be a string value "getblockhash": "getblockhash", + // getblock: Returns an object with information about a particular block "getblock": "getblock", + // getrawtransaction: Returns raw transaction data. Can return a hex-encoded string that is serialized or an object with txid information depending on the decrypt value (0 = false or 1 = true) "getrawtransaction": "getrawtransaction", + // getinfo: Returns an object containing various state info "getinfo": "getinfo", + // getpeerinfo: Returns data about each connected network node as a json array of objects "getpeerinfo": "getpeerinfo", + // gettxoutsetinfo: Returns an object with statistics about the unspent transaction output set "gettxoutsetinfo": "gettxoutsetinfo", + // getvotelist: Returns an object with details regarding the current vote list "getvotelist": "masternodelist votes", + // getmasternodecount: Returns a json object containing the total number of masternodes on the network "getmasternodecount": "getmasternodecount", + // getmasternodelist: Returns a json array containing status information for all masternodes on the network "getmasternodelist": "listmasternodes", - "verifymessage": "verifymessage", - "heavies": { - "getmaxmoney": "getmaxmoney", - "getmaxvote": "getmaxvote", - "getvote": "getvote", - "getphase": "getphase", - "getreward": "getreward", - "getnextrewardestimate": "getnextrewardestimate", - "getnextrewardwhenstr": "getnextrewardwhenstr", - "getsupply": "getsupply" + // verifymessage: Verify a signed message. Must accept the following arguments: + // address: The wallet address to use for the signature + // signature: The signature provided by the signer in base 64 encoding + // message: The message that was signed + "verifymessage": "verifymessage" +}; + +// blockchain_specific: A collection of settings that pertain to non-standard blockchain features that can extend the functionality of the default explorer +exports.blockchain_specific = { + // heavycoin: A collection of settings that pertain to the democratic voting and reward capabilities of the heavycoin blockchain + "heavycoin": { + // enabled: Enable/disable the use of heavycoin features in the explorer (true/false) + // If set to false, all heavycoin features will be completely inaccessible + // If set to true, an additional heavycoin sync will be performed immidiately before any index sync or reindex + "enabled": false, + // reward_page: a collection of settings that pertain to the reward page + "reward_page": { + // enabled: Enable/disable the reward page (true/false) + // If set to false, the reward page will be completely inaccessible + "enabled": true, + // show_last_updated: determine whether to show a label above the reward data with the last updated date (true/false) + "show_last_updated": true + }, + //api_cmds: A collection of settings that pertain to the list of customizable heavycoin rpc api commands + // Not all blockchains utilize the same rpc cmds for accessing the internal daemon api. Use these settings to set alternate names for similar api cmds. + // Leaving a cmd value blank ( "" ) will completely disable use of that cmd. + "api_cmds": { + // getmaxmoney: Returns the number of coins that will be produced in total. This should be a positive whole or decimal number + "getmaxmoney": "getmaxmoney", + // getmaxvote: Returns the maximum allowed vote for the current phase of voting. This should be a positive whole number + "getmaxvote": "getmaxvote", + // getvote: Returns the current block reward vote setting. This should be a positive whole number + "getvote": "getvote", + // getphase: Returns the current voting phase name. This should be a string value + "getphase": "getphase", + // getreward: Returns the current block reward. This should be a positive whole or decimal number + "getreward": "getreward", + // getsupply: Returns the current money supply. This should be a positive whole or decimal number + "getsupply": "getsupply", + // getnextrewardestimate: Returns an estimate for the next block reward based on the current state of decentralized voting. This should be a positive whole or decimal number + "getnextrewardestimate": "getnextrewardestimate", + // getnextrewardwhenstr: Returns a string describing how long until the votes are tallied and the next block reward is computed + "getnextrewardwhenstr": "getnextrewardwhenstr" + }, + // public_apis: a collection of settings that pertain to the heavycoin public api command system + // NOTE: If the "api_page.enabled" setting is set to false, these apis will be completely disabled and will return a "This method is disabled" msg if the api endpoint is called. + // Disabling any of these apis will remove the api definition from the api page and will return a "This method is disabled" msg if the api endpoint is called. + "public_apis": { + // getmaxmoney: a collection of settings that pertain to the /api/getmaxmoney api endpoint + // Returns the number of coins that will be produced in total + // NOTE: This api is not used internally and is therefore only publicly available + "getmaxmoney": { + // enabled: Enable/disable the /api/getmaxmoney api endpoint (true/false) + // If set to false, the /api/getmaxmoney api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getmaxvote: a collection of settings that pertain to the /api/getmaxvote api endpoint + // Returns the maximum allowed vote for the current phase of voting + // NOTE: This api is not used internally and is therefore only publicly available + "getmaxvote": { + // enabled: Enable/disable the /api/getmaxvote api endpoint (true/false) + // If set to false, the /api/getmaxvote api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getvote: a collection of settings that pertain to the /api/getvote api endpoint + // Returns the current block reward vote setting + // NOTE: This api is not used internally and is therefore only publicly available + "getvote": { + // enabled: Enable/disable the /api/getvote api endpoint (true/false) + // If set to false, the /api/getvote api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getphase: a collection of settings that pertain to the /api/getphase api endpoint + // Returns the current voting phase name + // NOTE: This api is not used internally and is therefore only publicly available + "getphase": { + // enabled: Enable/disable the /api/getphase api endpoint (true/false) + // If set to false, the /api/getphase api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getreward: a collection of settings that pertain to the /api/getreward api endpoint + // Returns the current block reward + // NOTE: This api is not used internally and is therefore only publicly available + "getreward": { + // enabled: Enable/disable the /api/getreward api endpoint (true/false) + // If set to false, the /api/getreward api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getsupply: a collection of settings that pertain to the /api/getsupply api endpoint + // Returns the current money supply + // NOTE: This api is not used internally and is therefore only publicly available + "getsupply": { + // enabled: Enable/disable the /api/getsupply api endpoint (true/false) + // If set to false, the /api/getsupply api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getnextrewardestimate: a collection of settings that pertain to the /api/getnextrewardestimate api endpoint + // Returns an estimate for the next block reward based on the current state of decentralized voting + // NOTE: This api is not used internally and is therefore only publicly available + "getnextrewardestimate": { + // enabled: Enable/disable the /api/getnextrewardestimate api endpoint (true/false) + // If set to false, the /api/getnextrewardestimate api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getnextrewardwhenstr: a collection of settings that pertain to the /api/getnextrewardwhenstr api endpoint + // Returns a string describing how long until the votes are tallied and the next block reward is computed + // NOTE: This api is not used internally and is therefore only publicly available + "getnextrewardwhenstr": { + // enabled: Enable/disable the /api/getnextrewardwhenstr api endpoint (true/false) + // If set to false, the /api/getnextrewardwhenstr api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + } + } + }, + // zksnarks: A collection of settings that pertain to Zcash zk-SNARKs private transactions + // NOTE: This is only partial zk-SNARKs private tx support (90% complete) + // While the current implementation should be stable, it does not yet work in 100% of the transaction scenarios + // USE THIS FEATURE AT YOUR OWN RISK. FOR TESTING PURPOSES ONLY! + "zksnarks": { + // enabled: Enable/disable Zcash zk-SNARKs private transaction support (true/false) + // If set to false, zk-SNARKs private txs will not be properly read or saved by the explorer + // NOTE: Enabling this feature will require a full reindex of the blockchain data + "enabled": false } }; diff --git a/locale/en.json b/locale/en.json index 1c5cc0c..6d3f6a3 100644 --- a/locale/en.json +++ b/locale/en.json @@ -56,6 +56,7 @@ "total_received": "Total Received", "confirmations": "Confirmations", "total": "Total", + "total_top_100": "Top 1-100 Total", "bits": "Bits", "nonce": "Nonce", "new_coins": "New Coins", @@ -101,7 +102,7 @@ "api_getmasternodecount": "Returns the total number of masternodes on the network.", "api_getvotelist": "Returns the current vote list.", "api_getblockcount": "Returns the current block index.", - "api_getblockhash": "Returns the hash of the block at ; index 0 is the genesis block.", + "api_getblockhash": "Returns the hash of the block at [index]; index 0 is the genesis block.", "api_getblock": "Returns information about the block with the given hash.", "api_getrawtransaction": "Returns raw transaction representation for given transaction id. decrypt can be set to 0(false) or 1(true).", "api_getmaxmoney": "Returns the maximum possible money supply.", @@ -111,7 +112,7 @@ "api_getreward": "Returns the current block reward, which has been decided democratically in the previous round of block reward voting.", "api_getsupply": "Returns the current money supply.", "api_getnextrewardestimate": "Returns an estimate for the next block reward based on the current state of decentralized voting.", - "api_getnextrewardwhenstr": "Returns string describing how long until the votes are tallied and the next block reward is computed.", + "api_getnextrewardwhenstr": "Returns a string describing how long until the votes are tallied and the next block reward is computed.", // Markets view "mkt_hours": "24 hours", @@ -136,7 +137,7 @@ "mkt_time_stamp": "Time Stamp", "mkt_select": "Market Select", - // Heavy rewards view + // Heavycoin rewards view "heavy_title": "Reward/voting information", "heavy_vote": "Vote", "heavy_cap": "Coin Cap", diff --git a/models/heavy.js b/models/heavy.js index 02a461a..f0cdca5 100644 --- a/models/heavy.js +++ b/models/heavy.js @@ -11,11 +11,7 @@ var HeavySchema = new Schema({ phase: { type: String, default: 'N/A'}, maxvote: { type: Number, default: 0 }, nextin: { type: String, default: 'N/A'}, - votes: { type: Array, default: [] }, + votes: { type: Array, default: [] } }); -module.exports = mongoose.model('Heavy', HeavySchema); - -/* -votes : [{ count: 0, reward: 0, vote: 0}] -*/ +module.exports = mongoose.model('Heavy', HeavySchema); \ No newline at end of file diff --git a/models/markets.js b/models/markets.js index 7f34906..58bc9ce 100644 --- a/models/markets.js +++ b/models/markets.js @@ -3,6 +3,8 @@ var mongoose = require('mongoose') var MarketsSchema = new Schema({ market: { type: String, index: true }, + coin_symbol: { type: String }, + pair_symbol: { type: String }, summary: { type: Object, default: {} }, chartdata: { type: Array, default: [] }, buys: { type: Array, default: [] }, diff --git a/models/richlist.js b/models/richlist.js index ddfbb01..bc3d3b8 100644 --- a/models/richlist.js +++ b/models/richlist.js @@ -1,10 +1,11 @@ var mongoose = require('mongoose') , Schema = mongoose.Schema; - + var RichlistSchema = new Schema({ - coin: { type: String }, - received: { type: Array, default: []}, + coin: { type: String }, + received: { type: Array, default: [] }, balance: { type: Array, default: [] }, + burned: { type: Array, default: [] } }); module.exports = mongoose.model('Richlist', RichlistSchema); \ No newline at end of file diff --git a/public/css/style.scss b/public/css/style.scss index c2b9543..adda88e 100644 --- a/public/css/style.scss +++ b/public/css/style.scss @@ -688,4 +688,10 @@ tr { .vertical-align-middle { vertical-align: middle !important; +} + +.wealth-dist-color-box { + width: 20px; + height: 20px; + margin-right: 6px; } \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index 4b06d16..356d5f0 100644 --- a/routes/index.js +++ b/routes/index.js @@ -9,21 +9,37 @@ var express = require('express') function route_get_block(res, blockhash) { lib.get_block(blockhash, function (block) { if (block && block != 'There was an error. Check your console.') { - if (blockhash == settings.genesis_block) { - res.render('block', { active: 'block', block: block, confirmations: settings.confirmations, txs: 'GENESIS', showSync: db.check_show_sync_message()}); + if (blockhash == settings.block_page.genesis_block) { + res.render('block', { active: 'block', block: block, confirmations: settings.shared_pages.confirmations, txs: 'GENESIS', showSync: db.check_show_sync_message()}); } else { db.get_txs(block, function(txs) { if (txs.length > 0) { - res.render('block', { active: 'block', block: block, confirmations: settings.confirmations, txs: txs, showSync: db.check_show_sync_message()}); + res.render('block', { active: 'block', block: block, confirmations: settings.shared_pages.confirmations, txs: txs, showSync: db.check_show_sync_message()}); } else { - db.create_txs(block, function(){ - db.get_txs(block, function(ntxs) { - if (ntxs.length > 0) { - res.render('block', { active: 'block', block: block, confirmations: settings.confirmations, txs: ntxs, showSync: db.check_show_sync_message()}); - } else { - route_get_index(res, 'Block not found: ' + blockhash); - } + // 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) { + 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) { + 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()}); }); } }); @@ -47,25 +63,25 @@ function route_get_block(res, blockhash) { /* GET functions */ function route_get_tx(res, txid) { - if (txid == settings.genesis_tx) { - route_get_block(res, settings.genesis_block); + if (txid == settings.transaction_page.genesis_tx) { + route_get_block(res, settings.block_page.genesis_block); } else { db.get_tx(txid, function(tx) { if (tx) { lib.get_blockcount(function(blockcount) { - if (settings.display.claim_address) { + if (settings.claim_address_page.enabled == true) { db.populate_claim_address_names(tx, function(tx) { - res.render('tx', { active: 'tx', tx: tx, confirmations: settings.confirmations, blockcount: (blockcount ? blockcount : 0), showSync: db.check_show_sync_message()}); + res.render('tx', { active: 'tx', tx: tx, confirmations: settings.shared_pages.confirmations, blockcount: (blockcount ? blockcount : 0), showSync: db.check_show_sync_message()}); }); } else { - res.render('tx', { active: 'tx', tx: tx, confirmations: settings.confirmations, blockcount: (blockcount ? blockcount : 0), showSync: db.check_show_sync_message()}); + res.render('tx', { active: 'tx', tx: tx, confirmations: settings.shared_pages.confirmations, blockcount: (blockcount ? blockcount : 0), showSync: db.check_show_sync_message()}); } }); } else { lib.get_rawtransaction(txid, function(rtx) { if (rtx && rtx.txid) { lib.prepare_vin(rtx, function(vin) { - lib.prepare_vout(rtx.vout, rtx.txid, vin, ((typeof rtx.vjoinsplit === 'undefined' || rtx.vjoinsplit == null) ? [] : rtx.vjoinsplit), function(rvout, rvin) { + 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) { lib.calculate_total(rvout, function(total){ if (!rtx.confirmations > 0) { var utx = { @@ -78,12 +94,12 @@ function route_get_tx(res, txid) { blockindex: -1, }; - if (settings.display.claim_address) { + if (settings.claim_address_page.enabled == true) { db.populate_claim_address_names(utx, function(utx) { - res.render('tx', { active: 'tx', tx: utx, confirmations: settings.confirmations, blockcount:-1, showSync: db.check_show_sync_message()}); + res.render('tx', { active: 'tx', tx: utx, confirmations: settings.shared_pages.confirmations, blockcount:-1, showSync: db.check_show_sync_message()}); }); } else { - res.render('tx', { active: 'tx', tx: utx, confirmations: settings.confirmations, blockcount:-1, showSync: db.check_show_sync_message()}); + res.render('tx', { active: 'tx', tx: utx, confirmations: settings.shared_pages.confirmations, blockcount:-1, showSync: db.check_show_sync_message()}); } } else { // check if blockheight exists @@ -102,12 +118,12 @@ function route_get_tx(res, txid) { blockindex: block.height, }; lib.get_blockcount(function(blockcount) { - if (settings.display.claim_address) { + if (settings.claim_address_page.enabled == true) { db.populate_claim_address_names(utx, function(utx) { - res.render('tx', { active: 'tx', tx: utx, confirmations: settings.confirmations, blockcount: (blockcount ? blockcount : 0), showSync: db.check_show_sync_message()}); + res.render('tx', { active: 'tx', tx: utx, confirmations: settings.shared_pages.confirmations, blockcount: (blockcount ? blockcount : 0), showSync: db.check_show_sync_message()}); }); } else { - res.render('tx', { active: 'tx', tx: utx, confirmations: settings.confirmations, blockcount: (blockcount ? blockcount : 0), showSync: db.check_show_sync_message()}); + res.render('tx', { active: 'tx', tx: utx, confirmations: settings.shared_pages.confirmations, blockcount: (blockcount ? blockcount : 0), showSync: db.check_show_sync_message()}); } }); } else { @@ -127,12 +143,12 @@ function route_get_tx(res, txid) { blockindex: rtx.blockheight, }; lib.get_blockcount(function(blockcount) { - if (settings.display.claim_address) { + if (settings.claim_address_page.enabled == true) { db.populate_claim_address_names(utx, function(utx) { - res.render('tx', { active: 'tx', tx: utx, confirmations: settings.confirmations, blockcount: (blockcount ? blockcount : 0), showSync: db.check_show_sync_message()}); + res.render('tx', { active: 'tx', tx: utx, confirmations: settings.shared_pages.confirmations, blockcount: (blockcount ? blockcount : 0), showSync: db.check_show_sync_message()}); }); } else { - res.render('tx', { active: 'tx', tx: utx, confirmations: settings.confirmations, blockcount: (blockcount ? blockcount : 0), showSync: db.check_show_sync_message()}); + res.render('tx', { active: 'tx', tx: utx, confirmations: settings.shared_pages.confirmations, blockcount: (blockcount ? blockcount : 0), showSync: db.check_show_sync_message()}); } }); } @@ -151,30 +167,29 @@ function route_get_tx(res, txid) { function route_get_index(res, error) { // check if index page should show last updated date - if (settings.index.show_last_updated == true) { + if (settings.index_page.show_last_updated == true) { // lookup last updated date - db.get_stats(settings.coin, function (stats) { + db.get_stats(settings.coin.name, function (stats) { res.render('index', { active: 'home', error: error, last_updated: stats.blockchain_last_updated, showSync: db.check_show_sync_message()}); }); } else { - // skip lookup up the last updated date and display the page now + // skip lookup of the last updated date and display the page now res.render('index', { active: 'home', error: error, last_updated: null, showSync: db.check_show_sync_message()}); } } -function route_get_address(res, hash, count) { +function route_get_address(res, hash) { db.get_address(hash, false, function(address) { - if (address) { + if (address) res.render('address', { active: 'address', address: address, showSync: db.check_show_sync_message()}); - } else { + else route_get_index(res, hash + ' not found'); - } }); } function route_get_claim_form(res, hash) { // check if claiming addresses is enabled - if (settings.display.claim_address) { + if (settings.claim_address_page.enabled == true) { // check if a hash was passed in if (hash == null || hash == '') { // no hash so just load the claim page without an address @@ -187,7 +202,7 @@ function route_get_claim_form(res, hash) { }); } } else - route_get_address(res, hash, settings.txcount); + route_get_address(res, hash); } /* GET home page. */ @@ -197,36 +212,39 @@ router.get('/', function(req, res) { router.get('/info', function(req, res) { // ensure api page is enabled - if (settings.display.api == true) { + if (settings.api_page.enabled == true) { // load the api page - res.render('info', { active: 'info', address: settings.address, hashes: settings.api, showSync: db.check_show_sync_message() }); + res.render('info', { active: 'info', address: req.headers.host, showSync: db.check_show_sync_message() }); } else { // api page is not enabled so default to the index page route_get_index(res, null); } }); -router.get('/markets/:market', function(req, res) { +router.get('/markets/:market/:coin_symbol/:pair_symbol', function(req, res) { // ensure markets page is enabled - if (settings.display.markets == true) { + if (settings.markets_page.enabled == true) { var market_id = req.params['market']; + var coin_symbol = req.params['coin_symbol']; + var pair_symbol = req.params['pair_symbol']; - if (settings.markets.enabled.indexOf(market_id) != -1) { + // check if the market and trading pair exists and market is enabled in settings.json + if (settings.markets_page.exchanges[market_id] != null && settings.markets_page.exchanges[market_id].enabled == true && settings.markets_page.exchanges[market_id].trading_pairs.findIndex(p => p.toLowerCase() == coin_symbol.toLowerCase() + '/' + pair_symbol.toLowerCase()) > -1) { // lookup market data - db.get_market(market_id, function(data) { + db.get_market(market_id, coin_symbol, pair_symbol, function(data) { // load market data var market_data = require('../lib/markets/' + market_id); // check if markets page should show last updated date if (settings.markets_page.show_last_updated == true) { // lookup last updated date - db.get_stats(settings.coin, function (stats) { + db.get_stats(settings.coin.name, function (stats) { res.render('./market', { active: 'markets', marketdata: { market_name: (market_data.market_name == null ? '' : market_data.market_name), market_logo: (market_data.market_logo == null ? '' : market_data.market_logo), - coin: settings.markets.coin, - exchange: settings.markets.exchange, + coin: coin_symbol, + exchange: pair_symbol, data: data, }, market: market_id, @@ -235,14 +253,14 @@ router.get('/markets/:market', function(req, res) { }); }); } else { - // skip lookup up the last updated date and display the page now + // skip looking up the last updated date and display the page now res.render('./market', { active: 'markets', marketdata: { market_name: (market_data.market_name == null ? '' : market_data.market_name), market_logo: (market_data.market_logo == null ? '' : market_data.market_logo), - coin: settings.markets.coin, - exchange: settings.markets.exchange, + coin: coin_symbol, + exchange: pair_symbol, data: data, }, market: market_id, @@ -252,7 +270,7 @@ router.get('/markets/:market', function(req, res) { } }); } else { - // selected market is not enabled so default to the index page + // selected market does not exist or is not enabled so default to the index page route_get_index(res, null); } } else { @@ -263,24 +281,22 @@ router.get('/markets/:market', function(req, res) { router.get('/richlist', function(req, res) { // ensure richlist page is enabled - if (settings.display.richlist == true) { - db.get_stats(settings.coin, function (stats) { - db.get_richlist(settings.coin, function(richlist) { + if (settings.richlist_page.enabled == true) { + db.get_stats(settings.coin.name, function (stats) { + db.get_richlist(settings.coin.name, function(richlist) { if (richlist) { db.get_distribution(richlist, stats, function(distribution) { res.render('richlist', { active: 'richlist', balance: richlist.balance, received: richlist.received, + burned: richlist.burned, stats: stats, dista: distribution.t_1_25, distb: distribution.t_26_50, distc: distribution.t_51_75, distd: distribution.t_76_100, diste: distribution.t_101plus, - show_dist: settings.richlist.distribution, - show_received: settings.richlist.received, - show_balance: settings.richlist.balance, last_updated: (settings.richlist_page.show_last_updated == true ? stats.richlist_last_updated : null), showSync: db.check_show_sync_message() }); @@ -299,16 +315,16 @@ router.get('/richlist', function(req, res) { router.get('/movement', function(req, res) { // ensure movement page is enabled - if (settings.display.movement == true) { + if (settings.movement_page.enabled == true) { // check if movement page should show last updated date if (settings.movement_page.show_last_updated == true) { // lookup last updated date - db.get_stats(settings.coin, function (stats) { - res.render('movement', {active: 'movement', flaga: settings.movement.low_flag, flagb: settings.movement.high_flag, min_amount:settings.movement.min_amount, last_updated: stats.blockchain_last_updated, showSync: db.check_show_sync_message()}); + db.get_stats(settings.coin.name, function (stats) { + res.render('movement', {active: 'movement', last_updated: stats.blockchain_last_updated, showSync: db.check_show_sync_message()}); }); } else { - // skip lookup up the last updated date and display the page now - res.render('movement', {active: 'movement', flaga: settings.movement.low_flag, flagb: settings.movement.high_flag, min_amount:settings.movement.min_amount, last_updated: null, showSync: db.check_show_sync_message()}); + // skip lookup of the last updated date and display the page now + res.render('movement', {active: 'movement', last_updated: null, showSync: db.check_show_sync_message()}); } } else { // movement page is not enabled so default to the index page @@ -318,15 +334,15 @@ router.get('/movement', function(req, res) { router.get('/network', function(req, res) { // ensure network page is enabled - if (settings.display.network == true) { + if (settings.network_page.enabled == true) { // check if network page should show last updated date if (settings.network_page.show_last_updated == true) { // lookup last updated date - db.get_stats(settings.coin, function (stats) { + db.get_stats(settings.coin.name, function (stats) { res.render('network', {active: 'network', last_updated: stats.network_last_updated, showSync: db.check_show_sync_message()}); }); } else { - // skip lookup up the last updated date and display the page now + // skip lookup of the last updated date and display the page now res.render('network', {active: 'network', last_updated: null, showSync: db.check_show_sync_message()}); } } else { @@ -338,15 +354,15 @@ router.get('/network', function(req, res) { // masternode list page router.get('/masternodes', function(req, res) { // ensure masternode page is enabled - if (settings.display.masternodes == true) { + if (settings.masternodes_page.enabled == true) { // check if masternodes page should show last updated date if (settings.masternodes_page.show_last_updated == true) { // lookup last updated date - db.get_stats(settings.coin, function (stats) { + db.get_stats(settings.coin.name, function (stats) { res.render('masternodes', {active: 'masternodes', last_updated: stats.masternodes_last_updated, showSync: db.check_show_sync_message()}); }); } else { - // skip lookup up the last updated date and display the page now + // skip lookup of the last updated date and display the page now res.render('masternodes', {active: 'masternodes', last_updated: null, showSync: db.check_show_sync_message()}); } } else { @@ -357,11 +373,11 @@ router.get('/masternodes', function(req, res) { router.get('/reward', function(req, res) { // ensure reward page is enabled - if (settings.heavy == true) { - db.get_stats(settings.coin, function (stats) { - db.get_heavy(settings.coin, function (heavy) { + if (settings.blockchain_specific.heavycoin.enabled == true && settings.blockchain_specific.heavycoin.reward_page.enabled == true) { + db.get_stats(settings.coin.name, function (stats) { + db.get_heavy(settings.coin.name, function (heavy) { if (!heavy) - heavy = { coin: settings.coin, lvote: 0, reward: 0, supply: 0, cap: 0, estnext: 0, phase: 'N/A', maxvote: 0, nextin: 'N/A', votes: [] }; + heavy = { coin: settings.coin.name, lvote: 0, reward: 0, supply: 0, cap: 0, estnext: 0, phase: 'N/A', maxvote: 0, nextin: 'N/A', votes: [] }; var votes = heavy.votes; @@ -379,7 +395,7 @@ router.get('/reward', function(req, res) { stats: stats, heavy: heavy, votes: votes, - last_updated: (settings.reward_page.show_last_updated == true ? stats.reward_last_updated : null), + last_updated: (settings.blockchain_specific.heavycoin.reward_page.show_last_updated == true ? stats.reward_last_updated : null), showSync: db.check_show_sync_message() }); }); @@ -407,55 +423,56 @@ router.get('/claim/:hash', function(req, res) { }); router.get('/address/:hash', function(req, res) { - route_get_address(res, req.params.hash, settings.txcount); -}); - -router.get('/address/:hash/:count', function(req, res) { - route_get_address(res, req.params.hash, req.params.count); + route_get_address(res, req.params.hash); }); router.post('/search', function(req, res) { - var query = req.body.search.trim(); - if (query.length == 64) { - if (query == settings.genesis_tx) { - res.redirect('/block/' + settings.genesis_block); + if (settings.shared_pages.page_header.show_search == true) { + var query = req.body.search.trim(); + + if (query.length == 64) { + if (query == settings.transaction_page.genesis_tx) + res.redirect('/block/' + settings.block_page.genesis_block); + else { + db.get_tx(query, function(tx) { + if (tx) + res.redirect('/tx/' + tx.txid); + else { + lib.get_block(query, function(block) { + if (block && block != 'There was an error. Check your console.') + res.redirect('/block/' + query); + else { + // check wallet for transaction + lib.get_rawtransaction(query, function(tx) { + if (tx && tx.txid) + res.redirect('/tx/' + tx.txid); + else { + // search found nothing so display the index page with an error msg + route_get_index(res, locale.ex_search_error + query ); + } + }); + } + }); + } + }); + } } else { - db.get_tx(query, function(tx) { - if (tx) { - res.redirect('/tx/' + tx.txid); - } else { - lib.get_block(query, function(block) { - if (block && block != 'There was an error. Check your console.') { - res.redirect('/block/' + query); - } else { - // check wallet for transaction - lib.get_rawtransaction(query, function(tx) { - if (tx && tx.txid) { - res.redirect('/tx/' + tx.txid); - } else { - // search found nothing so display the index page with an error msg - route_get_index(res, locale.ex_search_error + query ); - } - }); - } + db.get_address(query, false, function(address) { + if (address) + res.redirect('/address/' + address.a_id); + else { + lib.get_blockhash(query, function(hash) { + if (hash && hash != 'There was an error. Check your console.') + res.redirect('/block/' + hash); + else + route_get_index(res, locale.ex_search_error + query); }); } }); } } else { - db.get_address(query, false, function(address) { - if (address) { - res.redirect('/address/' + address.a_id); - } else { - lib.get_blockhash(query, function(hash) { - if (hash && hash != 'There was an error. Check your console.') { - res.redirect('/block/' + hash); - } else { - route_get_index(res, locale.ex_search_error + query ); - } - }); - } - }); + // Search is disabled so load the index page with an error msg + route_get_index(res, 'Search is disabled'); } }); diff --git a/scripts/benchmark.js b/scripts/benchmark.js index 5d1c3ae..d05a543 100644 --- a/scripts/benchmark.js +++ b/scripts/benchmark.js @@ -27,7 +27,7 @@ mongoose.connect(dbString, { useNewUrlParser: true, useCreateIndex: true, useUni Tx.deleteMany({}, function(err) { Address.deleteMany({}, function(err2) { var s_timer = new Date().getTime(); - db.update_tx_db(settings.coin, 1, COUNT, 0, settings.update_timeout, function(){ + db.update_tx_db(settings.coin.name, 1, COUNT, 0, settings.sync.update_timeout, function(){ var e_timer = new Date().getTime(); Tx.countDocuments({}, function(txerr, txcount){ Address.countDocuments({}, function(aerr, acount){ diff --git a/scripts/sass_theme_reader.sh b/scripts/sass_theme_reader.sh index 97e1367..f29ebff 100644 --- a/scripts/sass_theme_reader.sh +++ b/scripts/sass_theme_reader.sh @@ -1,3 +1,3 @@ #!/bin/bash -echo "\$theme-name: \"$(./node_modules/.bin/strip-json-comments settings.json | ./node_modules/.bin/json theme)\";" > ./public/css/_theme-selector.scss +echo "\$theme-name: \"$(./node_modules/.bin/strip-json-comments settings.json | ./node_modules/.bin/json shared_pages.theme)\";" > ./public/css/_theme-selector.scss diff --git a/scripts/sync.js b/scripts/sync.js index 1fa135f..8b85892 100644 --- a/scripts/sync.js +++ b/scripts/sync.js @@ -131,55 +131,8 @@ dbString = dbString + ':' + settings.dbsettings.port; dbString = dbString + '/' + settings.dbsettings.database; if (database == 'peers') { + var rateLimitLib = require('../lib/ratelimit'); console.log('syncing peers.. please wait..'); - // Initialize the rate limiting class from Matteo Agosti via https://www.matteoagosti.com/blog/2013/01/22/rate-limiting-function-calls-in-javascript/ - var RateLimit = (function() { - var RateLimit = function(maxOps, interval, allowBursts) { - this._maxRate = allowBursts ? maxOps : maxOps / interval; - this._interval = interval; - this._allowBursts = allowBursts; - - this._numOps = 0; - this._start = new Date().getTime(); - this._queue = []; - }; - - RateLimit.prototype.schedule = function(fn) { - var that = this, - rate = 0, - now = new Date().getTime(), - elapsed = now - this._start; - - if (elapsed > this._interval) { - this._numOps = 0; - this._start = now; - } - - rate = this._numOps / (this._allowBursts ? 1 : elapsed); - - if (rate < this._maxRate) { - if (this._queue.length === 0) { - this._numOps++; - fn(); - } - else { - if (fn) this._queue.push(fn); - - this._numOps++; - this._queue.shift()(); - } - } - else { - if (fn) this._queue.push(fn); - - setTimeout(function() { - that.schedule(); - }, 1 / this._maxRate); - } - }; - - return RateLimit; - })(); // syncing peers does not require a lock mongoose.connect(dbString, { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true, useFindAndModify: false }, function(err) { if (err) { @@ -193,7 +146,7 @@ if (database == 'peers') { var i = loop.iteration(); var address = body[i].addr.substring(0, body[i].addr.lastIndexOf(":")).replace("[","").replace("]",""); var port = body[i].addr.substring(body[i].addr.lastIndexOf(":") + 1); - var rateLimit = new RateLimit(1, 2000, false); + var rateLimit = new rateLimitLib.RateLimit(1, 2000, false); db.find_peer(address, function(peer) { if (peer) { if (isNaN(peer['port']) || peer['port'].length < 2 || peer['country'].length < 1 || peer['country_code'].length < 1) { @@ -202,6 +155,7 @@ if (database == 'peers') { exit(); }); } + console.log('Updated peer %s [%s/%s]', address, (i + 1).toString(), body.length.toString()); // peer already exists loop.next(); } else { @@ -221,6 +175,7 @@ if (database == 'peers') { country: geo.country_name, country_code: geo.country_code }, function() { + console.log('Added new peer %s [%s/%s]', address, (i + 1).toString(), body.length.toString()); loop.next(); }); } @@ -230,7 +185,7 @@ if (database == 'peers') { }); }, function() { // update network_last_updated value - db.update_last_updated_stats(settings.coin, { network_last_updated: Math.floor(new Date() / 1000) }, function (cb) { + db.update_last_updated_stats(settings.coin.name, { network_last_updated: Math.floor(new Date() / 1000) }, function (cb) { console.log('peer sync complete'); exit(); }); @@ -265,7 +220,7 @@ if (database == 'peers') { }); }, function () { db.remove_old_masternodes(function (cb) { - db.update_last_updated_stats(settings.coin, { masternodes_last_updated: Math.floor(new Date() / 1000) }, function (cb) { + db.update_last_updated_stats(settings.coin.name, { masternodes_last_updated: Math.floor(new Date() / 1000) }, function (cb) { console.log('masternode sync complete'); exit(); }); @@ -293,14 +248,14 @@ if (database == 'peers') { console.log('Aborting'); exit(); } else if (database == 'index') { - db.check_stats(settings.coin, function(exists) { + db.check_stats(settings.coin.name, function(exists) { if (exists == false) { console.log('Run \'npm start\' to create database structures before running this script.'); exit(); } else { - db.update_db(settings.coin, function(stats){ - if (settings.heavy == true) - db.update_heavy(settings.coin, stats.count, 20, function() {}); + db.update_db(settings.coin.name, function(stats){ + if (settings.blockchain_specific.heavycoin.enabled == true) + db.update_heavy(settings.coin.name, stats.count, 20, function() {}); if (mode == 'reindex') { Tx.deleteMany({}, function(err) { console.log('TXs cleared.'); @@ -308,11 +263,11 @@ if (database == 'peers') { console.log('Addresses cleared.'); AddressTx.deleteMany({}, function(err3) { console.log('Address TXs cleared.'); - Richlist.updateOne({coin: settings.coin}, { + Richlist.updateOne({coin: settings.coin.name}, { received: [], balance: [], }, function(err3) { - Stats.updateOne({coin: settings.coin}, { + Stats.updateOne({coin: settings.coin.name}, { last: 0, count: 0, supply: 0 @@ -320,19 +275,19 @@ if (database == 'peers') { console.log('index cleared (reindex)'); }); - // Check if there are more than 1000 blocks to index and show a sync msg + // Check if the sync msg should be shown check_show_sync_message(stats.count); - db.update_tx_db(settings.coin, 1, stats.count, stats.txes, settings.update_timeout, function() { + db.update_tx_db(settings.coin.name, 1, stats.count, stats.txes, settings.sync.update_timeout, function() { db.update_richlist('received', function() { db.update_richlist('balance', function() { - db.get_stats(settings.coin, function(nstats) { + db.get_stats(settings.coin.name, function(nstats) { // always check for and remove the sync msg if exists remove_sync_message(); // update richlist_last_updated value - db.update_last_updated_stats(settings.coin, { richlist_last_updated: Math.floor(new Date() / 1000) }, function (cb) { + db.update_last_updated_stats(settings.coin.name, { richlist_last_updated: Math.floor(new Date() / 1000) }, function (cb) { // update blockchain_last_updated value - db.update_last_updated_stats(settings.coin, { blockchain_last_updated: Math.floor(new Date() / 1000) }, function (cb) { + db.update_last_updated_stats(settings.coin.name, { blockchain_last_updated: Math.floor(new Date() / 1000) }, function (cb) { console.log('reindex complete (block: %s)', nstats.last); exit(); }); @@ -347,8 +302,8 @@ if (database == 'peers') { }); } else if (mode == 'check') { console.log('starting check.. please wait..'); - db.update_tx_db(settings.coin, 1, stats.count, stats.txes, settings.check_timeout, function(){ - db.get_stats(settings.coin, function(nstats){ + db.update_tx_db(settings.coin.name, 1, stats.count, stats.txes, settings.sync.check_timeout, function(){ + db.get_stats(settings.coin.name, function(nstats){ console.log('check complete (block: %s)', nstats.last); exit(); }); @@ -358,19 +313,19 @@ if (database == 'peers') { var last = (stats.last ? stats.last : 0); // Get the total number of blocks var count = (stats.count ? stats.count : 0); - // Check if there are more than 1000 blocks to index and show a sync msg + // Check if the sync msg should be shown check_show_sync_message(count - last); - db.update_tx_db(settings.coin, last, count, stats.txes, settings.update_timeout, function(){ + db.update_tx_db(settings.coin.name, last, count, stats.txes, settings.sync.update_timeout, function(){ db.update_richlist('received', function(){ db.update_richlist('balance', function(){ - db.get_stats(settings.coin, function(nstats){ + db.get_stats(settings.coin.name, function(nstats){ // always check for and remove the sync msg if exists remove_sync_message(); // update richlist_last_updated value - db.update_last_updated_stats(settings.coin, { richlist_last_updated: Math.floor(new Date() / 1000) }, function (cb) { + db.update_last_updated_stats(settings.coin.name, { richlist_last_updated: Math.floor(new Date() / 1000) }, function (cb) { // update blockchain_last_updated value - db.update_last_updated_stats(settings.coin, { blockchain_last_updated: Math.floor(new Date() / 1000) }, function (cb) { + db.update_last_updated_stats(settings.coin.name, { blockchain_last_updated: Math.floor(new Date() / 1000) }, function (cb) { console.log('update complete (block: %s)', nstats.last); exit(); }); @@ -381,17 +336,17 @@ if (database == 'peers') { }); } else if (mode == 'reindex-rich') { console.log('check richlist'); - db.check_richlist(settings.coin, function(exists) { + db.check_richlist(settings.coin.name, function(exists) { if (exists) console.log('richlist entry found, deleting now..'); - db.delete_richlist(settings.coin, function(deleted) { + db.delete_richlist(settings.coin.name, function(deleted) { if (deleted) console.log('richlist entry deleted'); - db.create_richlist(settings.coin, function() { + db.create_richlist(settings.coin.name, function() { console.log('richlist created.'); db.update_richlist('received', function() { console.log('richlist updated received.'); db.update_richlist('balance', function() { // update richlist_last_updated value - db.update_last_updated_stats(settings.coin, { richlist_last_updated: Math.floor(new Date() / 1000) }, function (cb) { + db.update_last_updated_stats(settings.coin.name, { richlist_last_updated: Math.floor(new Date() / 1000) }, function (cb) { console.log('richlist update complete'); exit(); }); @@ -405,7 +360,7 @@ if (database == 'peers') { // Resetting the transaction counter requires a single lookup on the txes collection to find all txes that have a positive or zero total and 1 or more vout Tx.find({'total': {$gte: 0}, 'vout': { $gte: { $size: 1 }}}).countDocuments(function(err, count) { console.log('found tx count: ' + count.toString()); - Stats.updateOne({coin: settings.coin}, { + Stats.updateOne({coin: settings.coin.name}, { txes: count }, function() { console.log('tx count update complete'); @@ -417,7 +372,7 @@ if (database == 'peers') { // Resetting the last counter requires a single lookup on the txes collection to find all txes that have a positive or zero total and 1 or more vout Tx.find({'total': {$gte: 0}, 'vout': { $gte: { $size: 1 }}}).countDocuments(function(err, count) { console.log('found tx count: ' + count.toString()); - Stats.updateOne({coin: settings.coin}, { + Stats.updateOne({coin: settings.coin.name}, { txes: count }, function() { console.log('tx count update complete'); @@ -429,41 +384,95 @@ if (database == 'peers') { } }); } else { - //update markets - var markets = settings.markets.enabled; - var complete = 0; - for (var x = 0; x < markets.length; x++) { - // check if market is installed - if (db.fs.existsSync('./lib/markets/' + markets[x] + '.js')) { - db.check_market(markets[x], function(mkt, exists) { - if (exists) { - db.update_markets_db(mkt, function(err) { - if (!err) { - console.log('%s market data updated successfully.', mkt); - complete++; - if (complete == markets.length) - get_last_usd_price(); - } else { - console.log('%s: %s', mkt, err); - complete++; - if (complete == markets.length) - get_last_usd_price(); - } - }); - } else { - console.log('error: entry for %s does not exists in markets db.', mkt); - complete++; - if (complete == markets.length) - get_last_usd_price(); + // check if market feature is enabled + if (settings.markets_page.enabled == true) { + var complete = 0; + var total_pairs = 0; + var exchanges = Object.keys(settings.markets_page.exchanges); + + // loop through all exchanges to determine how many trading pairs must be updated + exchanges.forEach(function (key, index, map) { + // check if market is enabled via settings + if (settings.markets_page.exchanges[key].enabled == true) { + // check if market is installed/supported + if (db.fs.existsSync('./lib/markets/' + key + '.js')) { + // add trading pairs to total + total_pairs += settings.markets_page.exchanges[key].trading_pairs.length; + + // loop through all trading pairs for this market + for (var i = 0; i < settings.markets_page.exchanges[key].trading_pairs.length; i++) { + // ensure trading pair setting is always uppercase + settings.markets_page.exchanges[key].trading_pairs[i] = settings.markets_page.exchanges[key].trading_pairs[i].toUpperCase(); + } + } + } + }); + + // check if there are any trading pairs to update + if (total_pairs > 0) { + // initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis + var rateLimitLib = require('../lib/ratelimit'); + var rateLimit = new rateLimitLib.RateLimit(1, 2000, false); + // loop through and test all exchanges defined in the settings.json file + exchanges.forEach(function (key, index, map) { + // check if market is enabled via settings + if (settings.markets_page.exchanges[key].enabled == true) { + // check if market is installed/supported + if (db.fs.existsSync('./lib/markets/' + key + '.js')) { + // loop through all trading pairs + settings.markets_page.exchanges[key].trading_pairs.forEach(function (pair_key, pair_index, pair_map) { + // split the pair data + var split_pair = pair_key.split('/'); + // check if this is a valid trading pair + if (split_pair.length == 2) { + // lookup the exchange in the market collection + db.check_market(key, split_pair[0], split_pair[1], function(mkt, exists) { + // check if exchange trading pair exists in the market collection + if (exists) { + // automatically pause for 2 seconds in between requests + rateLimit.schedule(function() { + // update market data + db.update_markets_db(key, split_pair[0], split_pair[1], function(err) { + if (!err) { + console.log('%s: %s market data updated successfully.', key, pair_key); + complete++; + if (complete == total_pairs) + get_last_usd_price(); + } else { + console.log('%s: %s: %s', key, pair_key, err); + complete++; + if (complete == total_pairs) + get_last_usd_price(); + } + }); + }); + } else { + console.log('error: entry for %s does not exist in markets database.', key); + complete++; + if (complete == total_pairs) + get_last_usd_price(); + } + }); + } + }); + } else { + // market not installed + console.log('%s market not installed', key); + complete++; + if (complete == total_pairs) + get_last_usd_price(); + } } }); } else { - // market not installed - console.log('%s %s', markets[x], 'market not installed'); - complete++; - if (complete == markets.length) - get_last_usd_price(); + // no market trading pairs are enabled + console.log('error: no market trading pairs are enabled in settings'); + exit(); } + } else { + // market page is not enabled + console.log('error: market feature is disabled in settings'); + exit(); } } }); @@ -475,8 +484,8 @@ if (database == 'peers') { function check_show_sync_message(blocks_to_sync) { var retVal = false; var filePath = './tmp/show_sync_message.tmp'; - // Check if there are more than 1000 blocks to index - if (blocks_to_sync > 1000) { + // Check if the sync msg should be shown + if (blocks_to_sync > settings.sync.show_sync_msg_when_syncing_more_than_blocks) { // Check if the show sync stub file already exists if (!db.fs.existsSync(filePath)) { // File doesn't exist, so create it now @@ -506,7 +515,7 @@ function get_last_usd_price() { // Get the last usd price for coinstats db.get_last_usd_price(function(retVal) { // update markets_last_updated value - db.update_last_updated_stats(settings.coin, { markets_last_updated: Math.floor(new Date() / 1000) }, function (cb) { + db.update_last_updated_stats(settings.coin.name, { markets_last_updated: Math.floor(new Date() / 1000) }, function (cb) { console.log('market sync complete'); exit(); }); diff --git a/scripts/sync.sh b/scripts/sync.sh index 72487a8..58caa5c 100755 --- a/scripts/sync.sh +++ b/scripts/sync.sh @@ -113,19 +113,6 @@ if [ -n "${MODE}" ]; then rm "${EXPLORER_PATH}/tmp/index.pid" fi fi - # Check if the script is already running (tmp/db_index.pid file already exists) - if [ -f "${EXPLORER_PATH}/tmp/db_index.pid" ]; then - # The tmp/db_index.pid file exists. Check if the process is actually still running - ps -p `cat ${EXPLORER_PATH}/tmp/db_index.pid` > /dev/null - if [ $? -eq 0 ]; then - # Script is running so the data is locked and we must exit now and try again later - echo "Script already running.." - exit 1 - else - # Script is not actually running so we can delete the lock file - rm "${EXPLORER_PATH}/tmp/db_index.pid" - fi - fi fi # Check if the node path was specified if [ -z "${NODE_PATH}" ]; then diff --git a/settings.json.template b/settings.json.template index 3e2f6ef..945029a 100644 --- a/settings.json.template +++ b/settings.json.template @@ -4,437 +4,1071 @@ Please edit settings.json, not settings.json.template */ { - // name your instance! - "title": "eIquidus", + // locale: Change language definitions. Only English is supported for now + "locale": "locale/en.json", - "address": "127.0.0.1:3001", - - // coin name - "coin": "Exor", - - // coin symbol - "symbol": "EXOR", - - // logo - "logo": "/img/logo.png", - // header logo. only displayed if the "homelink" setting is set to "logo" - "headerlogo": "/img/header_logo.png", - - // favicon - "favicon": "public/favicon.ico", - - // home link determines what is displayed in the top-left corner of the header menu (valid options are: title, coin, logo) - // title: display "title" text setting - // coin: display "coin" text setting - // logo: display the "headerlogo" image if it's set to a valid image, otherwise display the "logo" image - "homelink": "coin", - - // home link logo height (value in px, only valid if using homelink = 'logo') - "logoheight": 50, - - // set whether page header "sticks" to top of page or not - "sticky_header": true, - // set whether page footer "sticks" to bottom of page or not - "sticky_footer": false, - - // Customize the height of the footer for the following screen sizes: - // Mobile (0-575px) - // Tablet (576-991px) - // Desktop (>= 992px) - // Supports any valid height value in pixels ("50px") or percent ("10%") - "footer_height_desktop": "50px", - "footer_height_tablet": "60px", - "footer_height_mobile": "70px", - - // Customize the height of the social media links in the footer for the following screen sizes: - // Mobile (0-575px) - // Tablet (576-991px) - // Desktop (>= 992px) - // This is a percentage value and must be a positive number between 1-100 - "social_link_percent_height_desktop": 70, - "social_link_percent_height_tablet": 55, - "social_link_percent_height_mobile": 40, - - // Uses bootswatch themes (http://bootswatch.com/) - // Valid options: - // Cerulean, Cosmo, Cyborg, Darkly, Exor, Flatly, Journal, Litera, Lumen, - // Lux, Materia, Minty, Pulse, Sandstone, Simplex, Sketchy, Slate, - // Solar, Spacelab, Superhero, United, Yeti - // theme (see /public/css/themes for available themes) - "theme": "Exor", - - // port to listen for requests on. - "port" : 3001, - - // database settings (MongoDB) + // dbsettings: a collection of settings that allow the explorer to connect to MongoDB "dbsettings": { + // user: The MongoDB username "user": "eiquidus", + // password: The MongoDB password "password": "Nd^p2d77ceBX!L", + // database: The MongoDB database name (default: explorerdb) "database": "explorerdb", + // address: The MongoDB hostname. This should always be 'localhost' if connecting to a local instance, otherwise specify the ip address of a remote instance "address": "localhost", + // port: The port # that MongoDB is configured to listen for requests on (default: 27017) "port": 27017 }, - //update script settings - "update_timeout": 10, - "check_timeout": 250, - "block_parallel_tasks": 1, - - // wallet settings - "use_rpc": true, - + // wallet: a collection of settings that allow the explorer to connect to the coin wallet "wallet": { + // host: The hostname or ip address of the wallet to connect to (default: localhost) "host": "localhost", + // port: The port # that the wallet is configured to listen for RPC requests on (default: 51573 for Exor wallet) "port": 51573, + // username: The wallet RPC username "username": "exorrpc", + // password: The wallet RPC password "password": "sSTLyCkrD94Y8&9mr^m6W^Mk367Vr!!K" }, - // confirmations - "confirmations": 40, + // webserver: a collection of settings that pertain to the node.js express web framework (read more: https://www.npmjs.com/package/express) + "webserver": { + // port: Port # to configure the express webserver to listen for requests on + // NOTE: Be sure to configure firewalls to allow traffic through this port or the explorer website may not be accessible remotely + "port": 3001, + // cors: a collection of settings that pertain to the cors feature + // Cross-Origin Resource Sharing (CORS) support (read more: https://www.maxcdn.com/one/visual-glossary/cors/) + // Enable this setting to allow another website to access data from the explorer without violating the same-origin policy + "cors": { + // enabled: Enable/disable CORS + // If set to true, a new output header will be added to all http requests like this: Access-Control-Allow-Origin: + // If set to false, the cors feature will be completely disabled + "enabled": false, + // corsorigin: Used to whitelist an http domain name for access to this explorer's resources + // The whitelisted domain must be in the format: https://example.com + // Specifying a "*" for the corsorigin will allow any domain to access the resources of this site + "corsorigin": "*" + } + }, - // language settings - "locale": "locale/en.json", + // coin: a collection of settings that pertain to the cryptocurrency being explored + "coin": { + // name: Name of the cryptocurrency coin being explored. This value is displayed in the page header when the "shared_pages.page_header.home_link" setting is set to "coin". + // NOTE: This value acts as a unique identifier for data stored in mongo and therefore cannot be changed without re-syncing all existing data. + "name": "Exor", + // symbol: The cryptocurrency coin ticker/symbol value. This value is displayed anywhere that coin data is displayed including the index, address, block, movement, reward, richlist/top100 and tx pages + "symbol": "EXOR" + }, - // menu and panel settings - "display": { - "api": true, - "markets": true, - "richlist": true, - "search": true, - "movement": true, - "network": true, - // Show/hide the "Masternodes" header menu item - "masternodes": true, - // Enable/disable the ability for users to claim a wallet address. NOTE: Disabling this feature after addresses have already been claimed will effectively hide the claimed values and restore the original wallet addresses again - "claim_address": true, - // Show/hide the "Claim Address" header menu item. NOTE: "claim_address" setting must also be enabled or else the header item will automatically be hidden as well - "claim_address_header_menu": true, - // page_header_bgcolor: change the background color of the page header - // page_footer_bgcolor: change the background color of the page footer - // valid options: light, dark, primary, secondary, success, info, warning, danger or leave blank ( "" ) for default colors - "page_header_bgcolor": "", - "page_footer_bgcolor": "", - // table_header_bgcolor: change the background color of all table headers - // valid options: light, dark or leave blank ( "" ) for default colors + /* Shared page settings */ + + // shared_pages: a collection of settings that pertain to all webpages for the explorer + "shared_pages": { + // theme: Change the look & feel of the explorer with a unique theme. Uses bootswatch themes (https://bootswatch.com) + // Valid options: Cerulean, Cosmo, Cyborg, Darkly, Exor, Flatly, Journal, Litera, Lumen, Lux, Materia, Minty, Pulse, Sandstone, Simplex, Sketchy, Slate, Solar, Spacelab, Superhero, United, Yeti + // (see /public/css/themes for available themes) + "theme": "Exor", + // page_title: The text to display in the HTML title tag and also displayed in the page header when the "shared_pages.page_header.home_link" setting is set to "title" + "page_title": "eIquidus", + // favicon: The path to an icon file that is displayed in a browser window/tab and serves as branding for your website. Its main purpose is to help visitors locate your page easier when they have multiple tabs open + // NOTE: The path root is / + "favicon": "public/favicon.ico", + // logo: The path to an image file that is displayed on the api page as well as in one of the top panels when enabled + // This logo can also be displayed in the header when the "shared_pages.page_header.home_link" setting is set to "logo" and the "shared_pages.page_header.home_link_logo" setting is blank or an invalid file + // NOTE: The path root is /public + // The optimum logo size is 128x128 as the image will be forced to 128px high when displayed + "logo": "/img/logo.png", + // table_header_bgcolor: Change the background color of all table headers + // valid options: light, dark or leave blank ( "" ) for default colors "table_header_bgcolor": "", - // A maximum of 5 top panels can be shown across the top of the page - // Determine which panels are shown and in what order by giving panels a number from 1-5 - // Lowest # = far left panel, Highest # = far right panel - // Set disabled panels to a value of 0 to prevent them from being shown - "networkpnl": 1, - "difficultypnl": 2, - "masternodespnl": 3, - "coinsupplypnl": 4, - "pricepnl": 5, - "marketcappnl": 0, - "logopnl": 0 - }, - - // index page (valid options for difficulty are POW, POS or Hybrid) - "index": { - // show_last_updated: determine whether to show a label above the transaction data with the last updated date - "show_last_updated": true, - "show_hashrate": true, + // confirmations: Number of confirmations before a block or transaction can be considered valid + // if confirms are >= to this value then the block or tx is considered valid and shows up in green + // if confirms are < this value by more than 50% then the block or tx is considered unconfirmed and shows up in red + // if confirms are < this value by less than 50% then the block or tx is considered unconfirmed and shows up in orange + "confirmations": 40, + // difficulty: Determine which network difficulty value to display (valid options are: POW, POS or Hybrid) + // Some blockchains show different difficulty values depending on available POW/POS options: + // POW: Display the proof-of-work difficulty value + // POS: Display the proof-of-stake difficulty value + // Hybrid: Display both the proof-of-work and proof-of-stake difficulty values "difficulty": "POS", - "last_txs": 100, - "txs_per_page": 10 + // show_hashrate: Determine whether to show network hash rate where applicable (true/false) + // If set to false, the /api/getnetworkhashps and /ext/getsummary apis will no longer show hash rate information + "show_hashrate": true, + // page_header: A collection of settings that pertain to the page header that is displayed at the top of all pages + "page_header": { + // sticky_header: Determine whether page header "sticks" to top of page or not (true/false) + "sticky_header": true, + // bgcolor: Change the background color of the page header + // valid options: light, dark, primary, secondary, success, info, warning, danger or leave blank ( "" ) for default colors + "bgcolor": "", + // home_link: The home link setting determines what is displayed in the top-left corner of the header menu. Valid options: + // title: display "shared_pages.page_title" text setting + // coin: display "coin.name" text setting + // logo: display the "shared_pages.page_header.home_link_logo" image if it's set to a valid image, otherwise display the "shared_pages.logo" image + "home_link": "logo", + // home_link_logo: The path to a logo image that is displayed on page header when the "shared_pages.page_header.home_link" setting is set to "logo" + // If the home_link_logo is left blank or not set to a valid file, the "shared_pages.page_header.home_link" = "logo" setting will automatically default to displaying the original "shared_pages.logo" instead of the "shared_pages.page_header.home_link_logo" + // NOTE: The path root is /public + "home_link_logo": "/img/header_logo.png", + // home_link_logo_height: The max-height value of the "shared_pages.page_header.home_link" logo image (value in px, only valid if "shared_pages.page_header.home_link" = 'logo') + "home_link_logo_height": 50, + // panels: a collection of settings that pertain to the panels displayed on page header of all pages + // A maximum of 5 panels can be shown across the top of the page at any time, so if more than 5 are enabled, only the first 5 will be shown + "panels": { + // network_panel: a collection of settings that pertain to the network panel which displays the current network hash rate (only applicable to POW coins) + "network_panel": { + // enabled: Enable/disable the network panel (true/false) + // If set to false, the network panel will be completely inaccessible + "enabled": false, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 0, + // nethash: Determine how to acquire network hashrate. Valid options: + // getnetworkhashps: retrieved from getnetworkhashps rpc cmd + // netmhashps: retrieved from getmininginfo rpc cmd + "nethash": "getnetworkhashps", + // nethash_units: Determine which units should be used to display the network hashrate. Valid options: + // P: Display value in petahashes (PH/s) + // T: Display value in terahashes (TH/s) + // G: Display value in gigahashes (GH/s) + // M: Display value in megahashes (MH/s) + // K: Display value in kilohashes (KH/s) + // H: Display value in hashes (H/s) + "nethash_units": "G" + }, + // difficulty_panel: a collection of settings that pertain to the difficulty panel which displays the current proof-of-work difficulty (only applicable to POW coins) + "difficulty_panel": { + // enabled: Enable/disable the difficulty panel (true/false) + // If set to false, the difficulty panel will be completely inaccessible + "enabled": false, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 0 + }, + // masternodes_panel: a collection of settings that pertain to the masternode panel which displays a count of online and unreachable masternodes (only applicable to masternode coins) + "masternodes_panel": { + // enabled: Enable/disable the masternode panel (true/false) + // If set to false, the masternode panel will be completely inaccessible + "enabled": true, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 2 + }, + // coin_supply_panel: a collection of settings that pertain to the coin supply panel which displays the current circulating coin supply value + "coin_supply_panel": { + // enabled: Enable/disable the coin supply panel (true/false) + // If set to false, the coin supply panel will be completely inaccessible + "enabled": true, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 1 + }, + // price_panel: a collection of settings that pertain to the price panel which displays the current market price in BTC + "price_panel": { + // enabled: Enable/disable the price panel (true/false) + // If set to false, the price panel will be completely inaccessible + "enabled": true, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 4 + }, + // market_cap_panel: a collection of settings that pertain to the market cap panel which displays the current market cap value in BTC + "market_cap_panel": { + // enabled: Enable/disable the market cap panel (true/false) + // If set to false, the market cap panel will be completely inaccessible + "enabled": true, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 5 + }, + // logo_panel: a collection of settings that pertain to the logo panel which displays the "shared_pages.logo" image + "logo_panel": { + // enabled: Enable/disable the logo panel (true/false) + // If set to false, the logo panel will be completely inaccessible + "enabled": true, + // display_order: Determine which order this panel is shown from 1-5 + // 1 = far left panel, 5 = far right panel + // The panel will be disabled with a value of 0 + "display_order": 3 + } + }, + // show_search: Enable/disable the ability to search the explorer website (true/false) + // If set to false, the explorer will not display a search box or respond to search queries + "show_search": true + }, + // page_footer: A collection of settings that pertain to the page footer that is displayed at the bottom of all pages + "page_footer": { + // sticky_footer: Determine whether the page footer "sticks" to bottom of the page or not (true/false) + "sticky_footer": false, + // bgcolor: Change the background color of the page footer + // valid options: light, dark, primary, secondary, success, info, warning, danger or leave blank ( "" ) for default colors + "bgcolor": "", + // Customize the height of the footer for the following screen sizes: + // Mobile (0-575px) + // Tablet (576-991px) + // Desktop (>= 992px) + // Supports any valid height value in pixels (Ex: "50px") or percent (Ex: "10%") + // footer_height_desktop: Forced footer height value for desktop screens + "footer_height_desktop": "50px", + // footer_height_tablet: Forced footer height value for tablet screens + "footer_height_tablet": "70px", + // footer_height_mobile: Forced footer height value for mobile screens + "footer_height_mobile": "70px", + // social_links: a collection of settings that pertain to the social links on the page footer + // Add as many custom social links to be displayed in the page footer as desired + // For each entry you must fill in the image_path or fontawesome_class to determine the image or icon to show for the url link. It is not necessary to fill in both as only the 1st filled-in value will be used + "social_links": [ + { + // enabled: Enable/disable this particular social link (true/false) + // If set to false, the link will be completely inaccessible + "enabled": true, + // tooltip_text: Social link tooltips are always prefixed by the "coin.name" setting followed by the text from this tooltip_text setting. Ex: Exor Github + "tooltip_text": "Github", + // url: The exact url that the social link should navigate to + "url": "https://github.com/team-exor", + // fontawesome_class: A string of css classes, separated by spaces that can be used to display a fontawesome icon for this social link. See https://fontawesome.com/ for more info + "fontawesome_class": "fab fa-github", + // image_path: The path to an image file that will be displayed for this social link + // NOTE: The path root is /public + "image_path": "" + }, + { + // enabled: Enable/disable this particular social link (true/false) + // If set to false, the link will be completely inaccessible + "enabled": true, + // tooltip_text: Social link tooltips are always prefixed by the "coin.name" setting followed by the text from this tooltip_text setting. Ex: Exor Twitter + "tooltip_text": "Twitter", + // url: The exact url that the social link should navigate to + "url": "https://twitter.com/ExorOfficial", + // fontawesome_class: A string of css classes, separated by spaces that can be used to display a fontawesome icon for this social link. See https://fontawesome.com/ for more info + "fontawesome_class": "fab fa-twitter", + // image_path: The path to an image file that will be displayed for this social link + // NOTE: The path root is /public + "image_path": "" + }, + { + // enabled: Enable/disable this particular social link (true/false) + // If set to false, the link will be completely inaccessible + "enabled": true, + // tooltip_text: Social link tooltips are always prefixed by the "coin.name" setting followed by the text from this tooltip_text setting. Ex: Exor Discord + "tooltip_text": "Discord", + // url: The exact url that the social link should navigate to + "url": "https://discord.gg/dSuGm3y", + // fontawesome_class: A string of css classes, separated by spaces that can be used to display a fontawesome icon for this social link. See https://fontawesome.com/ for more info + "fontawesome_class": "fab fa-discord", + // image_path: The path to an image file that will be displayed for this social link + // NOTE: The path root is /public + "image_path": "" + }, + { + // enabled: Enable/disable this particular social link (true/false) + // If set to false, the link will be completely inaccessible + "enabled": true, + // tooltip_text: Social link tooltips are always prefixed by the "coin.name" setting followed by the text from this tooltip_text setting. Ex: Exor Telegram + "tooltip_text": "Telegram", + // url: The exact url that the social link should navigate to + "url": "https://t.me/Exorofficial", + // fontawesome_class: A string of css classes, separated by spaces that can be used to display a fontawesome icon for this social link. See https://fontawesome.com/ for more info + "fontawesome_class": "fab fa-telegram", + // image_path: The path to an image file that will be displayed for this social link + // NOTE: The path root is /public + "image_path": "" + }, + { + // enabled: Enable/disable this particular social link (true/false) + // If set to false, the link will be completely inaccessible + "enabled": true, + // tooltip_text: Social link tooltips are always prefixed by the "coin.name" setting followed by the text from this tooltip_text setting. Ex: Exor Website + "tooltip_text": "Website", + // url: The exact url that the social link should navigate to + "url": "https://exor.io", + // fontawesome_class: A string of css classes, separated by spaces that can be used to display a fontawesome icon for this social link. See https://fontawesome.com/ for more info + "fontawesome_class": "", + // image_path: The path to an image file that will be displayed for this social link + // NOTE: The path root is /public + "image_path": "/img/external.png" + }, + { + // enabled: Enable/disable this particular social link (true/false) + // If set to false, the link will be completely inaccessible + "enabled": true, + // tooltip_text: Social link tooltips are always prefixed by the "coin.name" setting followed by the text from this tooltip_text setting. Ex: Exor Coingecko + "tooltip_text": "Coingecko", + // url: The exact url that the social link should navigate to + "url": "https://www.coingecko.com/en/coins/exor", + // fontawesome_class: A string of css classes, separated by spaces that can be used to display a fontawesome icon for this social link. See https://fontawesome.com/ for more info + "fontawesome_class": "", + // image_path: The path to an image file that will be displayed for this social link + // NOTE: The path root is /public + "image_path": "/img/coingecko.png" + } + ], + // Customize the height of the social media links in the footer for the following screen sizes: + // Mobile (0-575px) + // Tablet (576-991px) + // Desktop (>= 992px) + // This is a percentage value and must be a positive number between 1-100 + // social_link_percent_height_desktop: Forced social link height percentage value for desktop screens + "social_link_percent_height_desktop": 70, + // social_link_percent_height_tablet: Forced social link height percentage value for tablet screens + "social_link_percent_height_tablet": 42, + // social_link_percent_height_mobile: Forced social link height percentage value for mobile screens + "social_link_percent_height_mobile": 40 + } }, - // reward page - "reward_page": { - // show_last_updated: determine whether to show a label above the reward data with the last updated date - "show_last_updated": true + /* Built-in Pages (cannot be disabled) */ + + // index_page: a collection of settings that pertain to the index page + "index_page": { + // show_last_updated: Determine whether to show a label above the transaction data with the last updated date (true/false) + "show_last_updated": true, + // transaction_table: a collection of settings that pertain to the transaction table on the index page + // Table data is populated via the /ext/getlasttxs api + "transaction_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 + // NOTE: Page length options will be limited based on the max_items_per_query for the /ext/getlasttxs api + "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, + // reload_table_seconds: The time in seconds to automatically reload the table data from the server + // Set to 0 to disable automatic reloading of table data + "reload_table_seconds": 60 + } }, - // masternodes page + // block_page: a collection of settings that pertain to the block page + "block_page": { + // genesis_block: Your coins genesis block hash is used to determine the beginning of the blockchain + // For many bitcoin clones you can use the following cmd to get the block hash of the genesis block: coin-cli getblockhash 0 + // NOTE: If this value is not entered correctly it will not be possible for the explorer to find or navigate to the genesis block, neither via block or transaction hash + "genesis_block": "00014f36c648cdbc750f7dd28487a23cd9e0b0f95f5fccc5b5d01367e3f57469" + }, + + // transaction_page: a collection of settings that pertain to the transaction/tx page + "transaction_page": { + // genesis_tx: Your coins genesis transaction hash is used to determine the beginning of the blockchain + // For many bitcoin clones you can use the following cmd to find the list of transaction hashes from the genesis block: coin-cli getblock 00014f36c648cdbc750f7dd28487a23cd9e0b0f95f5fccc5b5d01367e3f57469 + // NOTE: If this value is not entered correctly it will not be possible for the explorer to find or navigate to the genesis block by searching for the genesis transaction hash + "genesis_tx": "dd1d332ad2d8d8f49195056d482ae3c96fd2d16e9d166413b27ca7f19775644c" + }, + + // address_page: a collection of settings that pertain to the address page + "address_page": { + // show_sent_received: Determine whether to show Total Sent and Total Received columns at the top of the address page + "show_sent_received": false, + // history_table: a collection of settings that pertain to the history table on the address page + // Table data is populated via the /ext/getaddresstxs api + "history_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 + // NOTE: Page length options will be limited based on the max_items_per_query for the /ext/getaddresstxs api + "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": 50 + } + }, + + /* Additional Pages (can be enabled/disabled via settings) */ + + // masternodes_page: a collection of settings that pertain to the masternodes page "masternodes_page": { - // show_last_updated: determine whether to show a label above the masternode data with the last updated date - "show_last_updated": true + // enabled: Enable/disable the masternodes page (true/false) + // If set to false, the masternodes page will be completely inaccessible + "enabled": true, + // show_last_updated: determine whether to show a label above the masternode data with the last updated date (true/false) + "show_last_updated": true, + // masternode_table: a collection of settings that pertain to the masternode table on the masternodes page + // Table data is populated via the /ext/getmasternodelist api + "masternode_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 + } }, - // movement page + // movement_page: a collection of settings that pertain to the movement page "movement_page": { - // show_last_updated: determine whether to show a label above the movement data with the last updated date - "show_last_updated": true + // enabled: Enable/disable the movement page (true/false) + // If set to false, the movement page will be completely inaccessible + "enabled": true, + // show_last_updated: determine whether to show a label above the movement data with the last updated date (true/false) + "show_last_updated": true, + // movement_table: a collection of settings that pertain to the movement table on the movement page + // Table data is populated via the /ext/getlasttxs api + "movement_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 + // NOTE: Page length options will be limited based on the max_items_per_query for the /ext/getlasttxs api + "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, + // reload_table_seconds: The time in seconds to automatically reload the table data from the server + // Set to 0 to disable automatic reloading of table data + "reload_table_seconds": 45, + // min_amount: The minimum number of coins that need to be received in a single transaction to show up on the movement page + "min_amount": 5000, + // low low_warning_flag: Flag all transactions in yellow/orange that are sent with coin amounts above this value + "low_warning_flag": 50000, + // high_warning_flag: Flag all transactions in red that are sent with coin amounts above this value + "high_warning_flag": 100000 + } }, - // network page + // network_page: a collection of settings that pertain to the network page "network_page": { - // show_last_updated: determine whether to show a label above the network data with the last updated date - "show_last_updated": true + // enabled: Enable/disable the network page (true/false) + // If set to false, the network page will be completely inaccessible + "enabled": true, + // show_last_updated: determine whether to show a label above the network data with the last updated date (true/false) + "show_last_updated": true, + // connections_table: a collection of settings that pertain to the connections table on the network page + // Table data is populated via the /ext/getnetworkpeers api + "connections_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 ], + // items_per_page: The default amount of items/records to display in the table at any given time + "items_per_page": 10 + }, + // addnodes_table: a collection of settings that pertain to the add nodes table on the network page + // Table data is populated via the /ext/getnetworkpeers api + "addnodes_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 ], + // items_per_page: The default amount of items/records to display in the table at any given time + "items_per_page": 10 + }, + // onetry_table: a collection of settings that pertain to the one try table on the network page + // Table data is populated via the /ext/getnetworkpeers api + "onetry_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 ], + // items_per_page: The default amount of items/records to display in the table at any given time + "items_per_page": 10 + } }, - // richlist page + // richlist_page: a collection of settings that pertain to the richlist/top100 page "richlist_page": { - // show_last_updated: determine whether to show a label above the richlist data with the last updated date - "show_last_updated": true + // enabled: Enable/disable the richlist/top100 page (true/false) + // If set to false, the richlist/top100 page will be completely inaccessible + "enabled": true, + // show_last_updated: determine whether to show a label above the richlist/top100 data with the last updated date (true/false) + "show_last_updated": true, + // show_current_balance: Determine whether to show the top 100 list of wallet addresses that currently have the most coins in a single wallet (true/false) + "show_current_balance": true, + // show_received_coins: Determine whether to show the top 100 list of wallet addresses that have the highest total number of coins received based on adding up all received transactions (true/false) + "show_received_coins": true, + // wealth_distribution: a collection of settings that pertain to the wealth distribution section of the richlist/top100 page + // This section features a summary table with the breakdown of coins owned by the top 1-25, 26-50, 51-75, 76-100, 101+ wallets and all burned coins plus an associated pie chart + "wealth_distribution": { + // show_distribution_table: Show/hide the wealth distribution summary table with the breakdown of coins owned by the top 1-25, 26-50, 51-75, 76-100, 101+ wallets and all burned coins (true/false) + // If set to false, the wealth distribution table will be completely hidden + "show_distribution_table": true, + // show_distribution_chart: Show/hide the wealth distribution pie chart with the breakdown of coins owned by the top 1-25, 26-50, 51-75, 76-100, 101+ wallets and all burned coins (true/false) + // If set to false, the wealth distribution pie chart will be completely hidden + "show_distribution_chart": true, + // colors: An array of html color codes to represent the top 100 groupings in the wealth distribution table and pie chart + // From left-to-right the 6 colors are represented as the following: "top 1-25", "top 26-50", "top 51-75", "top 76-100", "101+" and "burned coins" - which is used if the include_burned_coins_in_distribution setting is enabled + "colors": [ "#e73cbd", "#00bc8c", "#3498db", "#e3ce3e", "#adb5bd", "#e74c3c" ] + }, + // burned_coins: a collection of settings that pertain to the wallet addresses that should not appear in the richlist/top100 page + // NOTE: These settings won't take effect until after running (and completing) a normal index sync or reindex-rich + "burned_coins": { + // addresses: An array of wallet addresses to exclude from the richlist/top100 page + // Use this setting to prevent specific wallet addresses from being displayed in the rich list and wealth distribution chart sections + // These wallet addresses will be completely removed from the rich list, but will still be viewable and accessible via the rest of the explorer pages as per normal + // Add as many wallet addresses as necessary in the following format: [ "EPUzEEHa45Rsn87WBos6SqkZZ8GrsfgvtZ", "EUzgat1r5AFyoTXK5WgTyM8kABPJY1SX7E" ] + "addresses": [ "EXorBurnAddressXXXXXXXXXXXXXW7cDZQ" ], + // include_burned_coins_in_distribution: Determine whether to include burned coins in the wealth distribution section or not + // This setting will need to be changed depending on whether your main coin supply value already has the burned coins removed from its total or not + // Set this value to false if your blockchain already has a mechanism for removing burned coins from the total supply and the burned coins will not be included in the distribution totals + // Set this value to true if your blockchain still has the burned coins included in its total supply and a 'Burned Coins' section will be added to the distribution table and chart + "include_burned_coins_in_distribution": false + } }, - // markets page + // markets_page: a collection of settings that pertain to the markets page "markets_page": { - // show_last_updated: determine whether to show a label above the market data with the last updated date - "show_last_updated": true - }, - - // ensure links on API page are valid - "api": { - "blockindex": 6415, - "blockhash": "dd17105f9e3d79c553b3670001e0243dd21378f4f90a340d87c0e5eb0b44dfd4", - "txhash": "2af5cc842d18814b45db44b62411c8a47987fc3c56294af38572989de5c1f7d5", - "address": "EaqHssmmgEPCxaeczbZnoqM6vutv9xmhrZ" - }, - - // market settings - //included markets: altmarkets, bittrex, bleutrade, crex, poloniex, stex, yobit - //default market is loaded by default and determines last price in header - "markets": { - "coin": "EXOR", - "exchange": "BTC", - "enabled": [], - "default": "", - // market_dropdown_menu: true/false - // true = Markets header menu will function as a dropdown that allows selecting from all available markets - // false = Markets header menu will function as a single-click menu item that opens the default market only - // NOTE: Dropdown will only work when 2 or more markets are enabled, otherwise it will default to a normal menu item automatically - "market_dropdown_menu": true, - // market_select_visible: true/false - // true = All market pages will display a clickable list of enabled markets near the top of the page for quick selection - // false = No market select box will be shown on market pages - // NOTE: Market select box will only be visible when 2 or more markets are enabled, otherwise it will be hidden automatically - "market_select_visible": true - }, - - // richlist/top100 settings - "richlist": { - "distribution": true, - "received": true, - "balance": true - }, - // movement page settings - // min amount: show transactions greater than this value - // low flag: greater than this value flagged yellow - // high flag: greater than this value flagged red - "movement": { - "min_amount": 100, - "low_flag": 1000, - "high_flag": 5000 - }, - - // Add as many custom social links to be displayed in the Explorer footer as desired - // For each entry you must fill in the fontawesome_class or image_url to determine the image or icon to show for the url link. It is not necessary to fill in both as only the 1st filled-in value will be used - // A few samples have been provided: - "social_links": [ - { - "enabled": true, - "tooltip_text": "Exor Github", - "url": "https://github.com/team-exor", - "fontawesome_class": "fab fa-github", - "image_url": "" + // enabled: Enable/disable the markets pages (true/false) + // If set to false, all market pages will be completely inaccessible + "enabled": false, + // show_last_updated: determine whether to show a label above the market data with the last updated date (true/false) + "show_last_updated": true, + // show_market_dropdown_menu: Determine whether the markets menu in the page header will function as a dropdown or a single-click menu item that opens the default market (true/false) + // If set to true, the markets header menu will function as a dropdown that allows selecting from all available markets + // If set to false, the markets header menu will function as a single-click menu item that opens the default market only + // NOTE: The dropdown will only work when 2 or more markets are enabled, otherwise it will default to a single-click menu item automatically + "show_market_dropdown_menu": true, + // show_market_select: Determine whether all market pages will display a clickable list of enabled markets near the top of the page for quick selection or not (true/false) + // If set to true, then all market pages will display a clickable list of enabled markets near the top of the page for quick selection + // If set to false, then no market select box will be shown on market pages + // NOTE: The market select box will only be visible when 2 or more markets are enabled, otherwise it will be hidden automatically + "show_market_select": true, + // exchanges: Enable/disable api integration with any of the available built-in exchanges + // Enabled exchanges display a number of exchange-related metrics including market summary, 24 hour chart, most recent buy/sell orders and latest trade history + // Supported exchanges: altmarkets, bittrex, bleutrade, crex, poloniex, stex, yobit + "exchanges": { + // altmarkets: a collection of settings that pertain to the altmarkets exchange + "altmarkets": { + // enabled: Enable/disable the altmarkets exchange (true/false) + // If set to false, the altmarkets page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC", "LTC/ETH" ] + }, + // bittrex: a collection of settings that pertain to the bittrex exchange + "bittrex": { + // enabled: Enable/disable the bittrex exchange (true/false) + // If set to false, the bittrex page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC" ] + }, + // bleutrade: a collection of settings that pertain to the bleutrade exchange + "bleutrade": { + // enabled: Enable/disable the bleutrade exchange (true/false) + // If set to false, the bleutrade page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC" ] + }, + // crex: a collection of settings that pertain to the crex exchange + "crex": { + // enabled: Enable/disable the crex exchange (true/false) + // If set to false, the crex page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC" ] + }, + // poloniex: a collection of settings that pertain to the poloniex exchange + "poloniex": { + // enabled: Enable/disable the poloniex exchange (true/false) + // If set to false, the poloniex page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC" ] + }, + // stex: a collection of settings that pertain to the stex exchange + "stex": { + // enabled: Enable/disable the stex exchange (true/false) + // If set to false, the stex page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC", "LTC/USDT" ] + }, + // yobit: a collection of settings that pertain to the yobit exchange + // NOTE: yobit does not display a 24-hour chart due to yobit's lack of OHLCV api data + "yobit": { + // enabled: Enable/disable the yobit exchange (true/false) + // If set to false, the yobit page will be completely inaccessible and no market data will be downloaded for this exchange + "enabled": false, + // trading_pairs: An array of market trading pair symbols + // You can add as many trading pairs as necessary + // All entries must specify your coins symbol as it is displayed on the exchange, followed by a slash (/) and ending with the symbol of the market or asset that is being traded against + // Ex: "LTC/BTC", "LTC/USDT", "LTC/ETH" + "trading_pairs": [ "LTC/BTC" ] + } }, - { - "enabled": true, - "tooltip_text": "Exor Twitter", - "url": "https://twitter.com/ExorOfficial", - "fontawesome_class": "fab fa-twitter", - "image_url": "" - }, - { - "enabled": true, - "tooltip_text": "Exor Discord", - "url": "https://discord.gg/dSuGm3y", - "fontawesome_class": "fab fa-discord", - "image_url": "" - }, - { - "enabled": true, - "tooltip_text": "Exor Telegram", - "url": "https://t.me/Exorofficial", - "fontawesome_class": "fab fa-telegram", - "image_url": "" - }, - { - "enabled": true, - "tooltip_text": "Exor Website", - "url": "https://exor.io", - "fontawesome_class": "", - "image_url": "/img/external.png" - }, - { - "enabled": true, - "tooltip_text": "Exor Coingecko", - "url": "https://www.coingecko.com/en/coins/exor", - "fontawesome_class": "", - "image_url": "/img/coingecko.png" + // default_exchange: a collection of settings that pertain to the default exchange + // When the "show_market_dropdown_menu" setting is disabled, the market header menu will navigate directly to the default exchange page + // The default exchange is also used to determine the last market price + // If left blank or filled out incorrectly, the first enabled exchange and trading pair will be used as the default exchange + "default_exchange": { + // exchange_name: The name of the default exchange must exactly match the name of an exchange in the "exchanges" setting above + // See the list of supported exchanges above for the list of supported exchange names + "exchange_name": "stex", + // trading_pair: The name of the trading pair for the default exchange must exactly match the name of a trading pair from the "exchanges" setting above + "trading_pair": "LTC/BTC" } - ], + }, - //genesis - "genesis_tx": "dd1d332ad2d8d8f49195056d482ae3c96fd2d16e9d166413b27ca7f19775644c", - "genesis_block": "0000860fcf946b44df0e7d85d6757d45f8de6f4c9aacc5c7b6abc13db1f68819", + // api_page: a collection of settings that pertain to the api page + "api_page": { + // enabled: Enable/disable the public api system (true/false) + // If set to false, the entire api page will be disabled and all public api endpoints will show a "This method is disabled" msg when called regardless of their individual enabled statuses + "enabled": true, + // sample_data: a collection of settings that pertain to the sample data that is used to display example api links to real data + "sample_data": { + // blockindex: This value can be any valid block height number from your coins blockchain + // NOTE: This value is only used to build example api links on the api page from the /api/getblockhash api for example + "blockindex": 64152, + // blockhash: This value can be any valid block hash from your coins blockchain + // For many bitcoin clones you can use the following cmd to get the block hash for a given block height: coin-cli getblockhash 64152 + // NOTE: This value is only used to build example api links on the api page from the /api/getblock api for example + "blockhash": "775d67da29dd6553268061f86368d06654944dd5d5c61db4c97e4c7960c11a74", + // txhash: This value can be any valid transaction hash from your coins blockchain + // For many bitcoin clones you can use the following cmd to find a list of tx hashes for a given block hash: coin-cli getblock 000000001ba119a0f6d49ebabd83343b125d7ee3d3184b1b41d6a7f2051153eb + // NOTE: This value is only used to build example api links on the api page from the /api/getrawtransaction api for example + "txhash": "6cb3babd256de253f926f10bc8574dadf0a3e2fc8380107b81eb07c67d1e73ed", + // address: This value can be any valid wallet address from your coins blockchain that has received at least 1 or more coin transactions + // NOTE: This value is only used to build example api links on the api page from the /ext/getaddress api for example + "address": "ELvb8AZRgHmdsDnD1HYFwbSY4UkPhoECCW" + }, + // public_apis: a collection of settings that pertain to the public api command system + // NOTE: Disabling any of these apis will remove the api definition from the api page and will return a "This method is disabled" msg if the api endpoint is called. + // Some public apis are used internally by the explorer such as the /ext/getlasttxs api and even if disabled from here the internal api will still continue to function. + "public_apis": { + // rpc: a collection of settings that pertain to the rpc cmd apis that are retrieved from the coin wallet rpc api + "rpc": { + // getdifficulty: a collection of settings that pertain to the /api/getdifficulty api endpoint + // Returns the proof-of-work difficulty as a multiple of the minimum difficulty + // NOTE: This api is not used internally and is therefore only publicly available + "getdifficulty": { + // enabled: Enable/disable the /api/getdifficulty api endpoint (true/false) + // If set to false, the /api/getdifficulty api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getconnectioncount: a collection of settings that pertain to the /api/getconnectioncount api endpoint + // Returns the number of connections to other nodes + // NOTE: This api is not used internally and is therefore only publicly available + "getconnectioncount": { + // enabled: Enable/disable the /api/getconnectioncount api endpoint (true/false) + // If set to false, the /api/getconnectioncount api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getblockcount: a collection of settings that pertain to the /api/getblockcount api endpoint + // Returns the number of blocks in the longest blockchain + // NOTE: This api is not used internally and is therefore only publicly available + "getblockcount": { + // enabled: Enable/disable the /api/getblockcount api endpoint (true/false) + // If set to false, the /api/getblockcount api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getblockhash: a collection of settings that pertain to the /api/getblockhash api endpoint + // Returns hash of block in best-block-chain at height provided + // NOTE: This api is not used internally and is therefore only publicly available + "getblockhash": { + // enabled: Enable/disable the /api/getblockhash api endpoint (true/false) + // If set to false, the /api/getblockhash api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getblock: a collection of settings that pertain to the /api/getblock api endpoint + // Returns an object with information about the block + // NOTE: This api is not used internally except for a link on the block page to view the raw block data, which will be automatically removed/hidden when this api is disabled + "getblock": { + // enabled: Enable/disable the /api/getblock api endpoint (true/false) + // If set to false, the /api/getblock api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getrawtransaction: a collection of settings that pertain to the /api/getrawtransaction api endpoint + // Returns raw transaction data + // NOTE: This api is not used internally except for a link on the transaction/tx page to view the raw transaction data, which will be automatically removed/hidden when this api is disabled + "getrawtransaction": { + // enabled: Enable/disable the /api/getrawtransaction api endpoint (true/false) + // If set to false, the /api/getrawtransaction api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getnetworkhashps: a collection of settings that pertain to the /api/getnetworkhashps api endpoint + // Returns the estimated network hashes per second + // NOTE: This api is not used internally and is therefore only publicly available + "getnetworkhashps": { + // enabled: Enable/disable the /api/getnetworkhashps api endpoint (true/false) + // If set to false, the /api/getnetworkhashps api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getvotelist: a collection of settings that pertain to the /api/getvotelist api endpoint + // Returns an object with details regarding the current vote list + // NOTE: This api is not used internally and is therefore only publicly available + "getvotelist": { + // enabled: Enable/disable the /api/getvotelist api endpoint (true/false) + // If set to false, the /api/getvotelist api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getmasternodecount: a collection of settings that pertain to the /api/getmasternodecount api endpoint + // Returns a json object containing the total number of masternodes on the network (only applicable to masternode coins) + // NOTE: This api is not used internally and is therefore only publicly available + "getmasternodecount": { + // enabled: Enable/disable the /api/getmasternodecount api endpoint (true/false) + // If set to false, the /api/getmasternodecount api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + } + }, + // ext: a collection of settings that pertain to the extended apis that are retrieved from local mongo database collection + "ext": { + // getmoneysupply: a collection of settings that pertain to the /ext/getmoneysupply api endpoint + // Returns current money supply + // NOTE: This api is not used internally and is therefore only publicly available + "getmoneysupply": { + // enabled: Enable/disable the /ext/getmoneysupply api endpoint (true/false) + // If set to false, the /ext/getmoneysupply api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getdistribution: a collection of settings that pertain to the /ext/getdistribution api endpoint + // Returns wealth distribution stats + // NOTE: This api is not used internally and is therefore only publicly available + "getdistribution": { + // enabled: Enable/disable the /ext/getdistribution api endpoint (true/false) + // If set to false, the /ext/getdistribution api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getaddress: a collection of settings that pertain to the /ext/getaddress api endpoint + // Returns information for given address + // NOTE: This api is not used internally and is therefore only publicly available + "getaddress": { + // enabled: Enable/disable the /ext/getaddress api endpoint (true/false) + // If set to false, the /ext/getaddress api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getaddresstxs: a collection of settings that pertain to the /ext/getaddresstxs api endpoint + // Returns transactions for a wallet address starting from a particular offset + // NOTE: This api is used internally via ajax call to populate the Address History table on the address page. Disabling the api from here will not stop the Address History table from displaying data + "getaddresstxs": { + // enabled: Enable/disable the /ext/getaddresstxs api endpoint (true/false) + // If set to false, the /ext/getaddresstxs api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) but the api will still be available internally to the explorer + "enabled": true, + // max_items_per_query: The maximum # of transactions that can be returned from the /ext/getaddresstxs api endpoint in a single call + "max_items_per_query": 100 + }, + // gettx: a collection of settings that pertain to the /ext/gettx api endpoint + // Returns information for given tx hash + // NOTE: This api is not used internally and is therefore only publicly available + "gettx": { + // enabled: Enable/disable the /ext/gettx api endpoint (true/false) + // If set to false, the /ext/gettx api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getbalance: a collection of settings that pertain to the /ext/getbalance api endpoint + // Returns current balance of given address + // NOTE: This api is not used internally and is therefore only publicly available + "getbalance": { + // enabled: Enable/disable the /ext/getbalance api endpoint (true/false) + // If set to false, the /ext/getbalance api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getlasttxs: a collection of settings that pertain to the /ext/getlasttxs api endpoint + // Returns transactions greater than a specific number of coins, starting from a particular offset + // NOTE: This api is used internally via ajax call to populate the Transaction tables on the index and movement pages. Disabling the api from here will not stop the Transaction tables from displaying data + "getlasttxs": { + // enabled: Enable/disable the /ext/getlasttxs api endpoint (true/false) + // If set to false, the /ext/getlasttxs api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) but the api will still be available internally to the explorer + "enabled": true, + // max_items_per_query: The maximum # of transactions that can be returned from the /ext/getlasttxs api endpoint in a single call + "max_items_per_query": 100 + }, + // getcurrentprice: a collection of settings that pertain to the /ext/getcurrentprice api endpoint + // Returns last known exchange price + // NOTE: This api is not used internally and is therefore only publicly available + "getcurrentprice": { + // enabled: Enable/disable the /ext/getcurrentprice api endpoint (true/false) + // If set to false, the /ext/getcurrentprice api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getnetworkpeers: a collection of settings that pertain to the /ext/getnetworkpeers api endpoint + // Returns the list of network peers that have connected to the explorer node in the last 24 hours + // NOTE: This api is used internally via ajax call to populate the connections, add nodes and one try tables on the network page. Disabling the api from here will not stop the network page tables from displaying data + "getnetworkpeers": { + // enabled: Enable/disable the /ext/getnetworkpeers api endpoint (true/false) + // If set to false, the /ext/getnetworkpeers api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) but the api will still be available internally to the explorer + "enabled": true + }, + // getbasicstats: a collection of settings that pertain to the /ext/getbasicstats api endpoint + // Returns basic statistics about the coin including: block count, circulating supply, USD price, BTC price and # of masternodes (# of masternodes is only applicable to masternode coins) + // NOTE: This api is not used internally and is therefore only publicly available + "getbasicstats": { + // enabled: Enable/disable the /ext/getbasicstats api endpoint (true/false) + // If set to false, the /ext/getbasicstats api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getsummary: a collection of settings that pertain to the /ext/getsummary api endpoint + // Returns a summary of coin data including: difficulty, hybrid difficulty, circulating supply, hash rate, BTC price, network connection count, block count, count of online masternodes and count of offline masternodes (masternode counts are only applicable to masternode coins) + // NOTE: This api is used internally via ajax call to populate many of the panel boxes that are found at the top of all pages. Disabling the api from here will not stop the panel boxes from displaying data + "getsummary": { + // enabled: Enable/disable the /ext/getsummary api endpoint (true/false) + // If set to false, the /ext/getsummary api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) but the api will still be available internally to the explorer + "enabled": true + }, + // getmasternodelist: a collection of settings that pertain to the /ext/getmasternodelist api endpoint + // Returns the complete list of masternodes on the network (only applicable to masternode coins) + // NOTE: This api is used internally via ajax call to populate the Masternodes table on the masternodes page. Disabling the api from here will not stop the Masternodes table from displaying data + "getmasternodelist": { + // enabled: Enable/disable the /ext/getmasternodelist api endpoint (true/false) + // If set to false, the /ext/getmasternodelist api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) but the api will still be available internally to the explorer + "enabled": true + }, + // getmasternoderewards: a collection of settings that pertain to the /ext/getmasternoderewards api endpoint + // Returns a list of masternode reward transactions for a specific address that arrived after a specific block height (only applicable to masternode coins) + // NOTE: This api is not used internally and is therefore only publicly available + "getmasternoderewards": { + // enabled: Enable/disable the /ext/getmasternoderewards api endpoint (true/false) + // If set to false, the /ext/getmasternoderewards api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getmasternoderewardstotal: a collection of settings that pertain to the /ext/getmasternoderewardstotal api endpoint + // 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) + // NOTE: This api is not used internally and is therefore only publicly available + "getmasternoderewardstotal": { + // enabled: Enable/disable the /ext/getmasternoderewardstotal api endpoint (true/false) + // If set to false, the /ext/getmasternoderewardstotal api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + } + } + } + }, - //heavy (enable/disable additional heavy features) - "heavy": false, - - //during index syncronization, stats are saved updated after processing this many blocks to save time - "save_stats_after_sync_blocks": 100, + // claim_address_page: a collection of settings that pertain to the claim address page + "claim_address_page": { + // enabled: Enable/disable the ability for users to claim a wallet address (true/false) + // If set to false, the claim page will be completely inaccessible + // NOTE: Disabling this feature after addresses have already been claimed will effectively hide the claimed values and restore the original wallet addresses again + "enabled": true, + // show_header_menu: Show/hide the "Claim Address" header menu item (true/false) + // If set to false, the claim address page can still be accessed via the claim link on each address page + // NOTE: The "claim_address_page.enabled" setting must also be set to true or else the header item will automatically be hidden as well + "show_header_menu": true, + // enable_bad_word_filter: Enable/disable the "bad word" filter for claimed addresses, so that trying to claim an address with a bad word like "ash0le" will fail + // This feature uses the default blacklist from the "bad-words" plugin from here: https://www.npmjs.com/package/bad-words + "enable_bad_word_filter": true + }, - //disable saving blocks & TXs via API during indexing. - "lock_during_index": false, + // 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. + // If you sync using more than 1 parallel task, then historical balance data for wallet addresses can possibly be saved out-of-order and there is currently no workaround for this. + // Therefore, it is recommended to keep this setting to 1 parallel task for now until a proper solution can be procured for the historical balance issue. + "block_parallel_tasks": 1, + // update_timeout: The amount of time to wait (in milliseconds) before moving to the next block or transaction during blockchain sync or reindex (scripts/sync.sh /path/to/nodejs update or scripts/sync.sh /path/to/nodejs reindex) + "update_timeout": 10, + // check_timeout: The amount of time to wait (in milliseconds) before moving to the next block or transaction during a check sync (scripts/sync.sh /path/to/nodejs check) + "check_timeout": 250, + // save_stats_after_sync_blocks: During index syncronization, stats are saved after processing this many blocks to save time by not having to save after each block + "save_stats_after_sync_blocks": 100, + // show_sync_msg_when_syncing_more_than_blocks: Show the sync msg at the top of all pages during index syncronization if there are more than this many blocks to process + "show_sync_msg_when_syncing_more_than_blocks": 1000, + // supply: Determine how to calculate current coin supply + // NOTE: The supply is always retrieved right before doing a normal index sync, reindex or check + // Valid options: + // COINBASE : retrieve the total coins sent from the coinbase (Often used for PoW coins) + // GETINFO : retrieved from getinfo rpc cmd (Often used for PoS coins) + // HEAVY: retrieved from getsupply rpc cmd (The "blockchain_specific.heavycoin.enabled" setting must be set to true and the "blockchain_specific.heavycoin.api_cmds.getsupply" setting must be set up correctly for this option to work properly) + // BALANCES : get the supply by running a query on the addresses collection and summing up all positive balances (potentially a long running query for blockchains with tons of addresses) + // TXOUTSET : retrieved from gettxoutsetinfo rpc cmd + "supply": "GETINFO" + }, - //amount of txs to index per address (stores latest n txs) - "txcount": 100, - "txcount_per_page": 50, - - //show total sent & received on address page (set false if PoS) - "show_sent_received": true, - - // how to calculate current coin supply - // COINBASE : total sent from coinbase (PoW) - // GETINFO : retreive from getinfo api call (PoS) - // HEAVY: retreive from heavys getsupply api call - // BALANCES : total of all address balances - // TXOUTSET : retreive from gettxoutsetinfo api call - "supply": "TXOUTSET", - - // how to acquire network hashrate - // getnetworkhashps: uses getnetworkhashps api call, returns in GH/s - // netmhashps: uses getmininginfo.netmhashpsm returns in MH/s - "nethash": "getnetworkhashps", - - // nethash_units: sets nethash API return units - // valid options: "P" (PH/s), "T" (TH/s), "G" (GH/s), "M" (MH/s), "K" (KH/s), "H" (H/s) - "nethash_units": "G", - - // simple Cross-Origin Resource Sharing (CORS) support - // enabling this feature will add a new output header to all requests like this: Access-Control-Allow-Origin: - // corsorigin "*" will allow any origin to access the requested resource while specifying any other value for corsorigin will allow cross-origin requests only when the request is made from a source that matches the corsorigin filter - "usecors": false, - "corsorigin": "*", - - // Address labels - // example : "CGTta3M4t3yXu8uRgkKvaWd2d8DQvDPnpL": {"label": "This is a burn address", "type":"danger", "url":"http://example.com"} - // label (required) = test to display - // type (optional) = class of label, valid types: default, primary, warning, danger, success - // url (optional) = url to link to for more information + // labels: a collection of settings that pertain to the list of customized wallet address labels + // Adding entries to this section will display a custom label beside each affected wallet address when displayed in the explorer + // NOTE: You can add as many address labels as desired "labels": { - // "CLkWg5YSLod772uLzsFRxHgHiWVGAJSezm": {"label": "Donation Address", "type":"primary", "url":"http://example.com"}, - // "CaxX1HVWzbQ516w61XbtHR63vNmp2mvLMZ": {"label": "Max Lee War Chest"} - }, - - // Burned coin addresses - // Use this setting to prevent specific wallet addresses from being displayed or calculated in the rich list and wealth distribution chart sections. - // These wallet addresses will still be accessible via the explorer under all other conditions except from the rich list. - // Add as many wallet addresses as necessary in the following format: - //"burned_coins": [ - // { - // "address": "EPUzEEGa45Rsn88WAos6SqkZZ9GrsfpvtZ" - // }, - // { - // "address": "EUzgbt1r5AFzoZXK6WgTzM8kBBPJU1SX8E" - // } - //] - "burned_coins": [], - - // Enable/disable the use of specific public apis - // Setting any of these apis to false will remove the api definition from the /info page and will return a "This method is disabled" msg if the api endpoint is called - "public_api": { - "rpc": { - "getdifficulty": true, - "getconnectioncount": true, - "getblockcount": true, - "getblockhash": true, - "getblock": true, - "getrawtransaction": true, - "getnetworkhashps": true, - "getvotelist": true, - "getmasternodecount": true, - "getmaxmoney": true, - "getmaxvote": true, - "getvote": true, - "getphase": true, - "getreward": true, - "getsupply": true, - "getnextrewardestimate": true, - "getnextrewardwhenstr": true + // A collection of settings that pertain to the EJ6yc47cAZMGWHFccc9gfGbDLYuyNhP6wL wallet address + // NOTE: Change this value to the wallet address that you would like to set a custom label on + "EJ6yc47cAZMGWHFccc9gfGbDLYuyNhP6wL": { + // enabled: Enable/disable this particular wallet address label (true/false) + // If set to false, the label will be completely hidden + "enabled": false, + // label: The text to display in the custom label + "label": "Development Budget", + // type: The bootstrap CSS class suffix for the label. This will change the background color of the label. + // Valid options: primary, secondary, success, danger, warning, info, light, dark + // NOTE: Leave the value blank ( "" ) to use default colors + "type": "success", + // url: The url the label should navigate to when clicked. Ex: http://example.com + // NOTE: Leave the value blank ( "" ) to prevent hyperlinking the label + "url": "" }, - "ext": { - "getmoneysupply": true, - "getdistribution": true, - "getaddress": true, - "getaddresstxs": true, - "gettx": true, - "getbalance": true, - "getlasttxs": true, - "getcurrentprice": true, - "getbasicstats": true, - "getsummary": true, - "getnetworkpeers": true, - "getmasternodelist": true, - "getmasternoderewards": true, - "getmasternoderewardstotal": true + // A collection of settings that pertain to the EXorBurnAddressXXXXXXXXXXXXXW7cDZQ wallet address + // NOTE: Change this value to the wallet address that you would like to set a custom label on + "EXorBurnAddressXXXXXXXXXXXXXW7cDZQ": { + // enabled: Enable/disable this particular wallet address label (true/false) + // If set to false, the label will be completely hidden + "enabled": false, + // label: The text to display in the custom label + "label": "Burn Address", + // type: The bootstrap CSS class suffix for the label. This will change the background color of the label. + // Valid options: primary, secondary, success, danger, warning, info, light, dark + // NOTE: Leave the value blank ( "" ) to use default colors + "type": "danger", + // url: The url the label should navigate to when clicked. Ex: http://example.com + // NOTE: Leave the value blank ( "" ) to prevent hyperlinking the label + "url": "" } }, - // Customized API commands - // Not all blockchains utilize the same rpc cmds for accessing the internal daemon api. - // Leaving a cmd value blank ( "" ) will completely disable use of that cmd. - // NOTICE: Some apis such as getblockhash for example, are integral to the functionality of the explorer and will result in a fairly unusable experience if disabled. - // The following cmd-line calls to the daemon can be overridden: - // - // getnetworkhashps: Returns the estimated network hashes per second. This should be a positive whole number. - // getmininginfo: Returns a json object containing mining-related information. - // getdifficulty: Returns the proof-of-work difficulty as a multiple of the minimum difficulty. This should be a positive whole or decimal number. - // getconnectioncount: Returns the number of connections to other nodes. This should be a positive whole number. - // getblockcount: Returns the number of blocks in the longest blockchain. This should be a positive whole number. - // getblockhash: Returns hash of block in best-block-chain at height provided. This should be a string value. - // getblock: Returns an object with information about the block. - // getrawtransaction: Returns raw transaction data. Can return a hex-encoded string that is serialized or an object with txid information depending on the decrypt value (0(false) or 1(true)) - // getinfo: Returns an object containing various state info. - // getpeerinfo: Returns data about each connected network node as a json array of objects. - // gettxoutsetinfo: Returns an object with statistics about the unspent transaction output set. - // getvotelist: Returns an object with details regarding the current vote list. - // getmasternodecount: Returns a json object containing the total number of masternodes on the network. - // getmasternodelist: Returns a json array containing status information for all masternodes on the network. - // verifymessage: Verify a signed message. Must accept the following arguments: - // address: The wallet address to use for the signature. - // signature: The signature provided by the signer in base 64 encoding. - // message: The message that was signed. - // - // heavies: A collection of commands that are enabled when the "heavy" setting is set to "true" - // getmaxmoney: Returns the number of coins that will be produced in total. This should be a positive whole or decimal number. - // getmaxvote: Returns the maximum allowed vote for the current phase of voting. This should be a positive whole number. - // getvote: Returns the current block reward vote setting. This should be a positive whole number. - // getphase: Returns the current voting phase name. This should be a string value. - // getreward: Returns the current block reward. This should be a positive whole or decimal number. - // getnextrewardestimate: Returns an estimate for the next block reward based on the current state of decentralized voting. This should be a positive whole or decimal number. - // getnextrewardwhenstr: Returns a string describing how long until the votes are tallied and the next block reward is computed. - // getsupply: Returns the current money supply. This should be a positive whole or decimal number. + //api_cmds: A collection of settings that pertain to the list of customizable rpc api commands + // Not all blockchains utilize the same rpc cmds for accessing the internal daemon api. Use these settings to set alternate names for similar api cmds. + // Leaving a cmd value blank ( "" ) will completely disable use of that cmd. + // NOTICE: Some apis such as getblockhash for example, are integral to the functionality of the explorer and will result in a fairly unusable experience if disabled. "api_cmds": { + // use_rpc: Determine whether to call rpc api cmds directly using the faster rpc method or using the older method via internal http api (true/false) + // NOTE: This should always be set to true unless there is a specific need to test or log certain apis + "use_rpc": true, + // getnetworkhashps: Returns the estimated network hashes per second. This should be a positive whole number "getnetworkhashps": "getnetworkhashps", + // getmininginfo: Returns a json object containing mining-related information "getmininginfo": "getmininginfo", + // getdifficulty: Returns the proof-of-work difficulty as a multiple of the minimum difficulty. This should be a positive whole or decimal number "getdifficulty": "getdifficulty", + // getconnectioncount: Returns the number of connections to other nodes. This should be a positive whole number "getconnectioncount": "getconnectioncount", + // getblockcount: Returns the number of blocks in the longest blockchain. This should be a positive whole number "getblockcount": "getblockcount", + // getblockhash: Returns hash of block in best-block-chain at height provided. This should be a string value "getblockhash": "getblockhash", + // getblock: Returns an object with information about a particular block "getblock": "getblock", + // getrawtransaction: Returns raw transaction data. Can return a hex-encoded string that is serialized or an object with txid information depending on the decrypt value (0 = false or 1 = true) "getrawtransaction": "getrawtransaction", + // getinfo: Returns an object containing various state info "getinfo": "getinfo", + // getpeerinfo: Returns data about each connected network node as a json array of objects "getpeerinfo": "getpeerinfo", + // gettxoutsetinfo: Returns an object with statistics about the unspent transaction output set "gettxoutsetinfo": "gettxoutsetinfo", + // getvotelist: Returns an object with details regarding the current vote list "getvotelist": "masternodelist votes", + // getmasternodecount: Returns a json object containing the total number of masternodes on the network "getmasternodecount": "getmasternodecount", + // getmasternodelist: Returns a json array containing status information for all masternodes on the network "getmasternodelist": "listmasternodes", - "verifymessage": "verifymessage", - "heavies": { - "getmaxmoney": "getmaxmoney", - "getmaxvote": "getmaxvote", - "getvote": "getvote", - "getphase": "getphase", - "getreward": "getreward", - "getnextrewardestimate": "getnextrewardestimate", - "getnextrewardwhenstr": "getnextrewardwhenstr", - "getsupply": "getsupply" + // verifymessage: Verify a signed message. Must accept the following arguments: + // address: The wallet address to use for the signature + // signature: The signature provided by the signer in base 64 encoding + // message: The message that was signed + "verifymessage": "verifymessage" + }, + + // blockchain_specific: A collection of settings that pertain to non-standard blockchain features that can extend the functionality of the default explorer + "blockchain_specific": { + // heavycoin: A collection of settings that pertain to the democratic voting and reward capabilities of the heavycoin blockchain + "heavycoin": { + // enabled: Enable/disable the use of heavycoin features in the explorer (true/false) + // If set to false, all heavycoin features will be completely inaccessible + // If set to true, an additional heavycoin sync will be performed immidiately before any index sync or reindex + "enabled": false, + // reward_page: a collection of settings that pertain to the reward page + "reward_page": { + // enabled: Enable/disable the reward page (true/false) + // If set to false, the reward page will be completely inaccessible + "enabled": true, + // show_last_updated: determine whether to show a label above the reward data with the last updated date (true/false) + "show_last_updated": true + }, + //api_cmds: A collection of settings that pertain to the list of customizable heavycoin rpc api commands + // Not all blockchains utilize the same rpc cmds for accessing the internal daemon api. Use these settings to set alternate names for similar api cmds. + // Leaving a cmd value blank ( "" ) will completely disable use of that cmd. + "api_cmds": { + // getmaxmoney: Returns the number of coins that will be produced in total. This should be a positive whole or decimal number + "getmaxmoney": "getmaxmoney", + // getmaxvote: Returns the maximum allowed vote for the current phase of voting. This should be a positive whole number + "getmaxvote": "getmaxvote", + // getvote: Returns the current block reward vote setting. This should be a positive whole number + "getvote": "getvote", + // getphase: Returns the current voting phase name. This should be a string value + "getphase": "getphase", + // getreward: Returns the current block reward. This should be a positive whole or decimal number + "getreward": "getreward", + // getsupply: Returns the current money supply. This should be a positive whole or decimal number + "getsupply": "getsupply", + // getnextrewardestimate: Returns an estimate for the next block reward based on the current state of decentralized voting. This should be a positive whole or decimal number + "getnextrewardestimate": "getnextrewardestimate", + // getnextrewardwhenstr: Returns a string describing how long until the votes are tallied and the next block reward is computed + "getnextrewardwhenstr": "getnextrewardwhenstr" + }, + // public_apis: a collection of settings that pertain to the heavycoin public api command system + // NOTE: If the "api_page.enabled" setting is set to false, these apis will be completely disabled and will return a "This method is disabled" msg if the api endpoint is called. + // Disabling any of these apis will remove the api definition from the api page and will return a "This method is disabled" msg if the api endpoint is called. + "public_apis": { + // getmaxmoney: a collection of settings that pertain to the /api/getmaxmoney api endpoint + // Returns the number of coins that will be produced in total + // NOTE: This api is not used internally and is therefore only publicly available + "getmaxmoney": { + // enabled: Enable/disable the /api/getmaxmoney api endpoint (true/false) + // If set to false, the /api/getmaxmoney api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getmaxvote: a collection of settings that pertain to the /api/getmaxvote api endpoint + // Returns the maximum allowed vote for the current phase of voting + // NOTE: This api is not used internally and is therefore only publicly available + "getmaxvote": { + // enabled: Enable/disable the /api/getmaxvote api endpoint (true/false) + // If set to false, the /api/getmaxvote api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getvote: a collection of settings that pertain to the /api/getvote api endpoint + // Returns the current block reward vote setting + // NOTE: This api is not used internally and is therefore only publicly available + "getvote": { + // enabled: Enable/disable the /api/getvote api endpoint (true/false) + // If set to false, the /api/getvote api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getphase: a collection of settings that pertain to the /api/getphase api endpoint + // Returns the current voting phase name + // NOTE: This api is not used internally and is therefore only publicly available + "getphase": { + // enabled: Enable/disable the /api/getphase api endpoint (true/false) + // If set to false, the /api/getphase api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getreward: a collection of settings that pertain to the /api/getreward api endpoint + // Returns the current block reward + // NOTE: This api is not used internally and is therefore only publicly available + "getreward": { + // enabled: Enable/disable the /api/getreward api endpoint (true/false) + // If set to false, the /api/getreward api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getsupply: a collection of settings that pertain to the /api/getsupply api endpoint + // Returns the current money supply + // NOTE: This api is not used internally and is therefore only publicly available + "getsupply": { + // enabled: Enable/disable the /api/getsupply api endpoint (true/false) + // If set to false, the /api/getsupply api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getnextrewardestimate: a collection of settings that pertain to the /api/getnextrewardestimate api endpoint + // Returns an estimate for the next block reward based on the current state of decentralized voting + // NOTE: This api is not used internally and is therefore only publicly available + "getnextrewardestimate": { + // enabled: Enable/disable the /api/getnextrewardestimate api endpoint (true/false) + // If set to false, the /api/getnextrewardestimate api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + }, + // getnextrewardwhenstr: a collection of settings that pertain to the /api/getnextrewardwhenstr api endpoint + // Returns a string describing how long until the votes are tallied and the next block reward is computed + // NOTE: This api is not used internally and is therefore only publicly available + "getnextrewardwhenstr": { + // enabled: Enable/disable the /api/getnextrewardwhenstr api endpoint (true/false) + // If set to false, the /api/getnextrewardwhenstr api will be completely disabled for public use (no definition on the api page and a disabled error msg if you try to call the endpoint directly) + "enabled": true + } + } + }, + // zksnarks: A collection of settings that pertain to Zcash zk-SNARKs private transactions + // NOTE: This is only partial zk-SNARKs private tx support (90% complete) + // While the current implementation should be stable, it does not yet work in 100% of the transaction scenarios + // USE THIS FEATURE AT YOUR OWN RISK. FOR TESTING PURPOSES ONLY! + "zksnarks": { + // enabled: Enable/disable Zcash zk-SNARKs private transaction support (true/false) + // If set to false, zk-SNARKs private txs will not be properly read or saved by the explorer + // NOTE: Enabling this feature will require a full reindex of the blockchain data + "enabled": false } } } \ No newline at end of file diff --git a/views/address.pug b/views/address.pug index aeaae09..e4f0bf2 100644 --- a/views/address.pug +++ b/views/address.pug @@ -4,15 +4,34 @@ block content include ./includes/common.pug script. var hashAddress = "#{address.a_id}"; - var setting_maxTxCount = parseInt("#{settings.txcount}"); - var setting_txPerPage = parseInt("#{settings.txcount_per_page}"); + var setting_maxTxCount = parseInt("#{settings.api_page.public_apis.ext.getaddresstxs.max_items_per_query}"); + var setting_txPerPage = parseInt("#{settings.address_page.history_table.items_per_page}"); + var lengthMenuOptsAdd = !{JSON.stringify(settings.address_page.history_table.page_length_options)}; var lengthMenuOpts = []; - var lengthMenuOptsAdd = [ 10, 25, 50, 75, 100, 250, 500, 1000 ]; - for (i=0; i < lengthMenuOptsAdd.length; i++) { + var addedLength = false; + for (i = 0; i < lengthMenuOptsAdd.length; i++) { if (setting_maxTxCount >= lengthMenuOptsAdd[i]) { + if (!addedLength) { + if (lengthMenuOptsAdd[i] > setting_txPerPage) { + lengthMenuOpts.push(setting_txPerPage); + addedLength = true; + } + } + lengthMenuOpts.push(lengthMenuOptsAdd[i]); + + if (!addedLength) { + if (lengthMenuOptsAdd[i] > setting_txPerPage) + lengthMenuOpts.push(setting_txPerPage); + if (lengthMenuOptsAdd[i] == setting_txPerPage || lengthMenuOptsAdd[i] > setting_txPerPage) + addedLength = true; + } } } + if (!addedLength && setting_txPerPage <= setting_maxTxCount && setting_txPerPage != lengthMenuOpts[lengthMenuOpts.length - 1]) + lengthMenuOpts.push(setting_txPerPage); + if (!addedLength && setting_txPerPage > setting_maxTxCount && setting_maxTxCount != lengthMenuOpts[lengthMenuOpts.length - 1]) + lengthMenuOpts.push(setting_maxTxCount); if (setting_maxTxCount < setting_txPerPage) { var displayLengthMax = setting_maxTxCount; } else { @@ -94,7 +113,7 @@ block content - var sentParts = sent.split('.'); - var received = Number(address.received / 100000000).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); - var receivedParts = received.split('.'); - if address.a_id !== 'coinbase' || settings.show_sent_received == true + if address.a_id !== 'coinbase' || settings.address_page.show_sent_received == true script. $(document).ready(function() { $('.summary-table').dataTable({ @@ -109,36 +128,36 @@ block content } }) }); + - var theadClasses = []; + if settings.shared_pages.table_header_bgcolor != null && settings.shared_pages.table_header_bgcolor != '' + - theadClasses.push('thead-' + settings.shared_pages.table_header_bgcolor); .col-xs-12.col-md-12 - if address.a_id !== 'coinbase' || settings.show_sent_received == true + if address.a_id !== 'coinbase' || settings.address_page.show_sent_received == true .card.card-default.border-0.card-address-summary.cardSpacer .card-header(style='position:relative;') - if settings.display.claim_address == false || address.name == null || address.name == '' + if settings.claim_address_page.enabled == false || address.name == null || address.name == '' strong #{address.a_id} else strong #{address.name} include ./includes/rl_labels.pug - if !settings.labels[address.a_id] && settings.display.claim_address == true + if (!settings.labels[address.a_id] || !settings.labels[address.a_id].enabled) && settings.claim_address_page.enabled == true a.badge.badge-pill.float-right.d-none.d-sm-block(href='/claim/' + address.a_id, style='font-size:smaller;padding-bottom:0;') if address.name == null || address.name == '' =" Is this yours? Claim it now for free!" else =" Update claimed address" table.table.table-bordered.table-striped.summary-table.mobile-border-right(style='border-top:0;margin-top:0 !important;') - - var theadClasses = []; - if settings.display.table_header_bgcolor != null && settings.display.table_header_bgcolor != '' - - theadClasses.push('thead-' + settings.display.table_header_bgcolor); thead(class=theadClasses) tr if address.a_id !== 'coinbase' th.text-center #{settings.locale.rl_balance} - span.small (#{settings.symbol}) - if settings.show_sent_received == true + span.small (#{settings.coin.symbol}) + if settings.address_page.show_sent_received == true th.text-center #{settings.locale.total_sent} - span.small (#{settings.symbol}) - if address.a_id !== 'coinbase' && settings.show_sent_received == true + span.small (#{settings.coin.symbol}) + if address.a_id !== 'coinbase' && settings.address_page.show_sent_received == true th.text-center #{settings.locale.total_received} - span.small (#{settings.symbol}) + span.small (#{settings.coin.symbol}) if address.a_id !== 'coinbase' th.text-center #{settings.locale.a_qr} tbody @@ -146,10 +165,10 @@ block content if address.a_id !== 'coinbase' td.text-center.addr-summary #{balanceParts[0]}. span.decimal #{balanceParts[1]} - if settings.show_sent_received == true + if settings.address_page.show_sent_received == true td.text-center.addr-summary #{sentParts[0]}. span.decimal #{sentParts[1]} - if address.a_id !== 'coinbase' && settings.show_sent_received == true + if address.a_id !== 'coinbase' && settings.address_page.show_sent_received == true td.text-center.addr-summary #{receivedParts[0]}. span.decimal #{receivedParts[1]} if address.a_id !== 'coinbase' @@ -159,16 +178,13 @@ block content .card-header strong #{settings.locale.ex_latest_transactions} table#address-txs.table.table-bordered.table-striped.table-paging.mobile-border-right - - var theadClasses = []; - if settings.display.table_header_bgcolor != null && settings.display.table_header_bgcolor != '' - - theadClasses.push('thead-' + settings.display.table_header_bgcolor); thead(class=theadClasses) tr th.d-table-cell.d-md-none th.d-none.d-md-table-cell #{settings.locale.tx_hash} th.text-center #{settings.locale.mkt_amount} - span.small (#{settings.symbol}) + span.small (#{settings.coin.symbol}) th.text-center #{settings.locale.rl_balance} - span.small (#{settings.symbol}) + span.small (#{settings.coin.symbol}) th.text-center #{settings.locale.timestamp} tbody \ No newline at end of file diff --git a/views/block.pug b/views/block.pug index 6949c78..68303da 100644 --- a/views/block.pug +++ b/views/block.pug @@ -5,8 +5,8 @@ block content - var time = format_unixtime(block.time); - var block_difficulty = parseFloat(block.difficulty).toFixed(4); - var theadClasses = []; - if settings.display.table_header_bgcolor != null && settings.display.table_header_bgcolor != '' - - theadClasses.push('thead-' + settings.display.table_header_bgcolor); + if settings.shared_pages.table_header_bgcolor != null && settings.shared_pages.table_header_bgcolor != '' + - theadClasses.push('thead-' + settings.shared_pages.table_header_bgcolor); script. $(document).ready(function() { $('#block-summary').dataTable({ @@ -28,23 +28,24 @@ block content if block.previousblockhash != null a(href='/block/' + block.previousblockhash) span.fa.fa-chevron-left.iquidus.block-last(data-toggle='tooltip', data-placement='top', title=settings.locale.block_previous) - strong.d-none.d-md-block #{settings.symbol} block: #{block.hash} + strong.d-none.d-md-block #{settings.coin.symbol} block: #{block.hash} strong.d-block.d-md-none #{settings.locale.ex_summary} else - strong.d-none.d-md-block(style='margin-left:10px;') #{settings.symbol} #{settings.locale.ex_block}: #{block.hash} + strong.d-none.d-md-block(style='margin-left:10px;') #{settings.coin.symbol} #{settings.locale.ex_block}: #{block.hash} strong.d-block.d-md-none(style='margin-left:10px;') #{settings.locale.ex_summary} if block.nextblockhash != null a(href='/block/' + block.nextblockhash) span.fa.fa-chevron-right.iquidus.block-next(data-toggle='tooltip', data-placement='top', title=settings.locale.block_next) - a.d-none.d-md-block(href='/api/getblock?hash=' + block.hash, style='margin-left:auto;', data-toggle='tooltip', data-placement='top', title=settings.locale.view_raw_block_data) - span.fa.fa-info-circle.iquidus + if settings.api_page.public_apis.rpc.getblock.enabled == true + a.d-none.d-md-block(href='/api/getblock?hash=' + block.hash, style='margin-left:auto;', data-toggle='tooltip', data-placement='top', title=settings.locale.view_raw_block_data) + span.fa.fa-info-circle.iquidus table#block-summary.table.table-bordered.summary-table(style='border-top:0;margin-top:0 !important;') thead(class=theadClasses) tr th.text-center #{settings.locale.height} th.text-center #{settings.locale.difficulty} th.text-center #{settings.locale.confirmations} - if settings.heavy == true + if settings.blockchain_specific.heavycoin.enabled == true th.text-center Vote th.text-center #{settings.locale.size} (kB) th.text-center #{settings.locale.bits} @@ -61,7 +62,7 @@ block content td.text-center #{splitDifficulty[0]}. span.decimal #{splitDifficulty[1]} td.text-center=block.confirmations - if settings.heavy == true + if settings.blockchain_specific.heavycoin.enabled == true td.text-center=block.vote td.text-center #{splitBlockSize[0]}. span.decimal #{splitBlockSize[1]} @@ -75,7 +76,7 @@ block content td.text-center #{splitDifficulty[0]}. span.decimal #{splitDifficulty[1]} td.text-center=block.confirmations - if settings.heavy == true + if settings.blockchain_specific.heavycoin.enabled == true td.text-center=block.vote td.text-center #{splitBlockSize[0]}. span.decimal #{splitBlockSize[1]} @@ -88,14 +89,14 @@ block content td.text-center #{splitDifficulty[0]}. span.decimal #{splitDifficulty[1]} td.text-center=block.confirmations - if settings.heavy == true + if settings.blockchain_specific.heavycoin.enabled == true td.text-center=block.vote td.text-center #{splitBlockSize[0]}. span.decimal #{splitBlockSize[1]} td.text-center=block.bits td.text-center=block.nonce td.text-center=time - if block.hash == settings.genesis_block + if block.hash == settings.block_page.genesis_block .alert.alert-info(role='alert', style='text-align:center;') strong #{settings.locale.block_genesis} else @@ -109,7 +110,7 @@ block content th.d-none.d-md-table-cell #{settings.locale.tx_hash} th.text-center #{settings.locale.tx_recipients} th.text-center #{settings.locale.mkt_amount} - span.small (#{settings.symbol}) + span.small (#{settings.coin.symbol}) tbody each txn in txs tr diff --git a/views/claim_address.pug b/views/claim_address.pug index 06bcbef..e8bab36 100644 --- a/views/claim_address.pug +++ b/views/claim_address.pug @@ -77,7 +77,7 @@ block content span Use the span.font-weight-bold Sign Message span feature from your - span.font-weight-bold #{settings.coin} + span.font-weight-bold #{settings.coin.name} span wallet to verify ownership of a wallet address that belongs to you. br div Enter the following data into the wallet software: diff --git a/views/includes/rl_labels.pug b/views/includes/rl_labels.pug index 1452d22..e53cb50 100644 --- a/views/includes/rl_labels.pug +++ b/views/includes/rl_labels.pug @@ -1,6 +1,6 @@ if address.a_id == null - address.a_id = address.addresses; -if settings.labels[address.a_id] +if settings.labels[address.a_id] != null && settings.labels[address.a_id].enabled == true if settings.labels[address.a_id].type label(class='badge badge-' + settings.labels[address.a_id].type + ' float-right d-none d-' + (active == 'richlist' ? 'md' : (active == 'tx' ? 'lg' : 'sm')) + '-block', style='margin-left:15px;margin-bottom:0;') =settings.labels[address.a_id].label diff --git a/views/index.pug b/views/index.pug index 2fcee93..18b88ac 100644 --- a/views/index.pug +++ b/views/index.pug @@ -3,20 +3,38 @@ extends layout block content include ./includes/common.pug script. - var setting_maxTxCount = parseInt("#{settings.index.last_txs}"); - var setting_txPerPage = parseInt("#{settings.index.txs_per_page}"); + var setting_maxTxCount = parseInt("#{settings.api_page.public_apis.ext.getlasttxs.max_items_per_query}"); + var setting_txPerPage = parseInt("#{settings.index_page.transaction_table.items_per_page}"); + var lengthMenuOptsAdd = !{JSON.stringify(settings.index_page.transaction_table.page_length_options)}; var lengthMenuOpts = []; - var lengthMenuOptsAdd = [ 10, 25, 50, 75, 100, 250, 500, 1000 ]; - for (i=0; i < lengthMenuOptsAdd.length; i++) { + var addedLength = false; + for (i = 0; i < lengthMenuOptsAdd.length; i++) { if (setting_maxTxCount >= lengthMenuOptsAdd[i]) { + if (!addedLength) { + if (lengthMenuOptsAdd[i] > setting_txPerPage) { + lengthMenuOpts.push(setting_txPerPage); + addedLength = true; + } + } + lengthMenuOpts.push(lengthMenuOptsAdd[i]); + + if (!addedLength) { + if (lengthMenuOptsAdd[i] > setting_txPerPage) + lengthMenuOpts.push(setting_txPerPage); + if (lengthMenuOptsAdd[i] == setting_txPerPage || lengthMenuOptsAdd[i] > setting_txPerPage) + addedLength = true; + } } } - if (setting_maxTxCount < setting_txPerPage) { + if (!addedLength && setting_txPerPage <= setting_maxTxCount && setting_txPerPage != lengthMenuOpts[lengthMenuOpts.length - 1]) + lengthMenuOpts.push(setting_txPerPage); + if (!addedLength && setting_txPerPage > setting_maxTxCount && setting_maxTxCount != lengthMenuOpts[lengthMenuOpts.length - 1]) + lengthMenuOpts.push(setting_maxTxCount); + if (setting_maxTxCount < setting_txPerPage) var displayLengthMax = setting_maxTxCount; - } else { + else var displayLengthMax = setting_txPerPage; - } $(document).ready(function() { var rtable = $('#recent-table').dataTable({ autoWidth: false, @@ -64,9 +82,12 @@ block content enableTooltips(); } }); - setInterval( function () { - rtable.api().ajax.reload(null, false); - }, 60000 ); + var setting_reload_table_seconds = parseInt("#{settings.index_page.transaction_table.reload_table_seconds}"); + if (setting_reload_table_seconds > 0) { + setInterval( function () { + rtable.api().ajax.reload(null, false); + }, (setting_reload_table_seconds * 1000) ); + } }); if error !== null .col-12 @@ -77,7 +98,7 @@ block content strong #{settings.locale.ex_error} div #{error} .col-md-12.cardSpacer - if settings.index.show_last_updated == true + if settings.index_page.show_last_updated == true div.font-weight-bold(style='margin-bottom:15px;') Blockchain data last updated: span.font-weight-normal=(last_updated == null || last_updated == '0' ? ' N/A' : ' ' + format_unixtime(last_updated)) .card.card-default.border-0.cardSpacer @@ -85,8 +106,8 @@ block content strong #{settings.locale.ex_latest_transactions} table#recent-table.table.table-bordered.table-striped.table-paging - var theadClasses = []; - if settings.display.table_header_bgcolor != null && settings.display.table_header_bgcolor != '' - - theadClasses.push('thead-' + settings.display.table_header_bgcolor); + if settings.shared_pages.table_header_bgcolor != null && settings.shared_pages.table_header_bgcolor != '' + - theadClasses.push('thead-' + settings.shared_pages.table_header_bgcolor); thead(class=theadClasses) tr th.d-table-cell.d-md-none @@ -94,6 +115,6 @@ block content th.text-center.d-none.d-md-table-cell #{settings.locale.tx_hash} th.text-center.d-none.d-sm-table-cell #{settings.locale.tx_recipients} th.text-center #{settings.locale.mkt_amount} - span.small (#{settings.symbol}) + span.small (#{settings.coin.symbol}) th.text-center #{settings.locale.timestamp} tbody.text-center \ No newline at end of file diff --git a/views/info.pug b/views/info.pug index 0fa8c41..c5ac639 100644 --- a/views/info.pug +++ b/views/info.pug @@ -6,134 +6,134 @@ block content .card-header strong #{settings.locale.api_title} .card-body - img(src=settings.logo, style='margin:0;height:128px;') + img(src=settings.shared_pages.logo, style='margin:0;height:128px;') p em #{settings.locale.api_message} hr - - var hide_rpc_api_section = !(settings.public_api.rpc['getdifficulty'] == true && settings.api_cmds['getdifficulty'] != null && settings.api_cmds['getdifficulty'] != '') && !(settings.public_api.rpc['getconnectioncount'] == true && settings.api_cmds['getconnectioncount'] != null && settings.api_cmds['getconnectioncount'] != '') && !(settings.public_api.rpc['getblockcount'] == true && settings.api_cmds['getblockcount'] != null && settings.api_cmds['getblockcount'] != '') && !(settings.public_api.rpc['getblockhash'] == true && settings.api_cmds['getblockhash'] != null && settings.api_cmds['getblockhash'] != '') && !(settings.public_api.rpc['getblock'] == true && settings.api_cmds['getblock'] != null && settings.api_cmds['getblock'] != '') && !(settings.public_api.rpc['getrawtransaction'] == true && settings.api_cmds['getrawtransaction'] != null && settings.api_cmds['getrawtransaction'] != '') && !(settings.public_api.rpc['getnetworkhashps'] == true && settings.index.show_hashrate == true && settings.api_cmds['getnetworkhashps'] != null && settings.api_cmds['getnetworkhashps'] != '') && !(settings.public_api.rpc['getvotelist'] == true && settings.api_cmds['getvotelist'] != null && settings.api_cmds['getvotelist'] != '') && !(settings.public_api.rpc['getmasternodecount'] == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '') && (!settings.heavy || (!(settings.public_api.rpc['getmaxmoney'] == true && settings.api_cmds.heavies['getmaxmoney'] != null && settings.api_cmds.heavies['getmaxmoney'] != '') && !(settings.public_api.rpc['getmaxvote'] == true && settings.api_cmds.heavies['getmaxvote'] != null && settings.api_cmds.heavies['getmaxvote'] != '') && !(settings.public_api.rpc['getvote'] == true && settings.api_cmds.heavies['getvote'] != null && settings.api_cmds.heavies['getvote'] != '') && !(settings.public_api.rpc['getphase'] == true && settings.api_cmds.heavies['getphase'] != null && settings.api_cmds.heavies['getphase'] != '') && !(settings.public_api.rpc['getreward'] == true && settings.api_cmds.heavies['getreward'] != null && settings.api_cmds.heavies['getreward'] != '') && !(settings.public_api.rpc['getsupply'] == true && settings.api_cmds.heavies['getsupply'] != null && settings.api_cmds.heavies['getsupply'] != '') && !(settings.public_api.rpc['getnextrewardestimate'] == true && settings.api_cmds.heavies['getnextrewardestimate'] != null && settings.api_cmds.heavies['getnextrewardestimate'] != '') && !(settings.public_api.rpc['getnextrewardwhenstr'] == true && settings.api_cmds.heavies['getnextrewardwhenstr'] != null && settings.api_cmds.heavies['getnextrewardwhenstr'] != ''))); - - var hide_ext_api_section = !settings.public_api.ext['getmoneysupply'] && !settings.public_api.ext['getdistribution'] && !settings.public_api.ext['getaddress'] && !settings.public_api.ext['getaddresstxs'] && !settings.public_api.ext['gettx'] && !settings.public_api.ext['getbalance'] && !settings.public_api.ext['getlasttxs'] && !settings.public_api.ext['getcurrentprice'] && !settings.public_api.ext['getnetworkpeers'] && !settings.public_api.ext['getbasicstats'] && !settings.public_api.ext['getsummary'] && !(settings.public_api.ext['getmasternodelist'] == true && settings.api_cmds['getmasternodelist'] != null && settings.api_cmds['getmasternodelist'] != '') && !settings.public_api.ext['getmasternoderewards'] && !settings.public_api.ext['getmasternoderewardstotal']; + - var hide_rpc_api_section = !(settings.api_page.public_apis.rpc.getdifficulty.enabled == true && settings.api_cmds['getdifficulty'] != null && settings.api_cmds['getdifficulty'] != '') && !(settings.api_page.public_apis.rpc.getconnectioncount.enabled == true && settings.api_cmds['getconnectioncount'] != null && settings.api_cmds['getconnectioncount'] != '') && !(settings.api_page.public_apis.rpc.getblockcount.enabled == true && settings.api_cmds['getblockcount'] != null && settings.api_cmds['getblockcount'] != '') && !(settings.api_page.public_apis.rpc.getblockhash.enabled == true && settings.api_cmds['getblockhash'] != null && settings.api_cmds['getblockhash'] != '') && !(settings.api_page.public_apis.rpc.getblock.enabled == true && settings.api_cmds['getblock'] != null && settings.api_cmds['getblock'] != '') && !(settings.api_page.public_apis.rpc.getrawtransaction.enabled == true && settings.api_cmds['getrawtransaction'] != null && settings.api_cmds['getrawtransaction'] != '') && !(settings.api_page.public_apis.rpc.getnetworkhashps.enabled == true && settings.shared_pages.show_hashrate == true && settings.api_cmds['getnetworkhashps'] != null && settings.api_cmds['getnetworkhashps'] != '') && !(settings.api_page.public_apis.rpc.getvotelist.enabled == true && settings.api_cmds['getvotelist'] != null && settings.api_cmds['getvotelist'] != '') && !(settings.api_page.public_apis.rpc.getmasternodecount.enabled == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '') && (!settings.blockchain_specific.heavycoin.enabled || (!(settings.blockchain_specific.heavycoin.public_apis.getmaxmoney.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getmaxmoney'] != null && settings.blockchain_specific.heavycoin.api_cmds['getmaxmoney'] != '') && !(settings.blockchain_specific.heavycoin.public_apis.getmaxvote.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getmaxvote'] != null && settings.blockchain_specific.heavycoin.api_cmds['getmaxvote'] != '') && !(settings.blockchain_specific.heavycoin.public_apis.getvote.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getvote'] != null && settings.blockchain_specific.heavycoin.api_cmds['getvote'] != '') && !(settings.blockchain_specific.heavycoin.public_apis.getphase.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getphase'] != null && settings.blockchain_specific.heavycoin.api_cmds['getphase'] != '') && !(settings.blockchain_specific.heavycoin.public_apis.getreward.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getreward'] != null && settings.blockchain_specific.heavycoin.api_cmds['getreward'] != '') && !(settings.blockchain_specific.heavycoin.public_apis.getsupply.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getsupply'] != null && settings.blockchain_specific.heavycoin.api_cmds['getsupply'] != '') && !(settings.blockchain_specific.heavycoin.public_apis.getnextrewardestimate.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getnextrewardestimate'] != null && settings.blockchain_specific.heavycoin.api_cmds['getnextrewardestimate'] != '') && !(settings.blockchain_specific.heavycoin.public_apis.getnextrewardwhenstr.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getnextrewardwhenstr'] != null && settings.blockchain_specific.heavycoin.api_cmds['getnextrewardwhenstr'] != ''))); + - var hide_ext_api_section = !settings.api_page.public_apis.ext.getmoneysupply.enabled && !settings.api_page.public_apis.ext.getdistribution.enabled && !settings.api_page.public_apis.ext.getaddress.enabled && !settings.api_page.public_apis.ext.getaddresstxs.enabled && !settings.api_page.public_apis.ext.gettx.enabled && !settings.api_page.public_apis.ext.getbalance.enabled && !settings.api_page.public_apis.ext.getlasttxs.enabled && !settings.api_page.public_apis.ext.getcurrentprice.enabled && !settings.api_page.public_apis.ext.getnetworkpeers.enabled && !settings.api_page.public_apis.ext.getbasicstats.enabled && !settings.api_page.public_apis.ext.getsummary.enabled && !(settings.api_page.public_apis.ext.getmasternodelist.enabled && settings.api_cmds['getmasternodelist'] != null && settings.api_cmds['getmasternodelist'] != '') && !settings.api_page.public_apis.ext.getmasternoderewards.enabled && !settings.api_page.public_apis.ext.getmasternoderewardstotal.enabled; if !hide_rpc_api_section h3 #{settings.locale.api_calls} p em Return data from coind ul - if settings.public_api.rpc['getdifficulty'] == true && settings.api_cmds['getdifficulty'] != null && settings.api_cmds['getdifficulty'] != '' + if settings.api_page.public_apis.rpc.getdifficulty.enabled == true && settings.api_cmds['getdifficulty'] != null && settings.api_cmds['getdifficulty'] != '' li p div.font-weight-bold getdifficulty div em #{settings.locale.api_getdifficulty} a(href='/api/getdifficulty') #{address}/api/getdifficulty - if settings.public_api.rpc['getconnectioncount'] == true && settings.api_cmds['getconnectioncount'] != null && settings.api_cmds['getconnectioncount'] != '' + if settings.api_page.public_apis.rpc.getconnectioncount.enabled == true && settings.api_cmds['getconnectioncount'] != null && settings.api_cmds['getconnectioncount'] != '' li p div.font-weight-bold getconnectioncount div em #{settings.locale.api_getconnectioncount} a(href='/api/getconnectioncount') #{address}/api/getconnectioncount - if settings.public_api.rpc['getblockcount'] == true && settings.api_cmds['getblockcount'] != null && settings.api_cmds['getblockcount'] != '' + if settings.api_page.public_apis.rpc.getblockcount.enabled == true && settings.api_cmds['getblockcount'] != null && settings.api_cmds['getblockcount'] != '' li p div.font-weight-bold getblockcount div em #{settings.locale.api_getblockcount} a(href='/api/getblockcount') #{address}/api/getblockcount - if settings.public_api.rpc['getblockhash'] == true && settings.api_cmds['getblockhash'] != null && settings.api_cmds['getblockhash'] != '' + if settings.api_page.public_apis.rpc.getblockhash.enabled == true && settings.api_cmds['getblockhash'] != null && settings.api_cmds['getblockhash'] != '' li p div.font-weight-bold getblockhash [index] div em #{settings.locale.api_getblockhash} - a(href='/api/getblockhash?index=' + hashes.blockindex) #{address}/api/getblockhash?index=#{hashes.blockindex} - if settings.public_api.rpc['getblock'] == true && settings.api_cmds['getblock'] != null && settings.api_cmds['getblock'] != '' + a(href='/api/getblockhash?index=' + settings.api_page.sample_data.blockindex) #{address}/api/getblockhash?index=#{settings.api_page.sample_data.blockindex} + if settings.api_page.public_apis.rpc.getblock.enabled == true && settings.api_cmds['getblock'] != null && settings.api_cmds['getblock'] != '' li p div.font-weight-bold getblock [hash] div em #{settings.locale.api_getblock} - a(href='/api/getblock?hash=' + hashes.blockhash) #{address}/api/getblock?hash=#{hashes.blockhash} - if settings.public_api.rpc['getrawtransaction'] == true && settings.api_cmds['getrawtransaction'] != null && settings.api_cmds['getrawtransaction'] != '' + a(href='/api/getblock?hash=' + settings.api_page.sample_data.blockhash) #{address}/api/getblock?hash=#{settings.api_page.sample_data.blockhash} + if settings.api_page.public_apis.rpc.getrawtransaction.enabled == true && settings.api_cmds['getrawtransaction'] != null && settings.api_cmds['getrawtransaction'] != '' li p div.font-weight-bold getrawtransaction [txid] [decrypt] div em #{settings.locale.api_getrawtransaction} div - a(href='/api/getrawtransaction?txid=' + hashes.txhash + '&decrypt=0') #{address}/api/getrawtransaction?txid=#{hashes.txhash}&decrypt=0 + a(href='/api/getrawtransaction?txid=' + settings.api_page.sample_data.txhash + '&decrypt=0') #{address}/api/getrawtransaction?txid=#{settings.api_page.sample_data.txhash}&decrypt=0 div - a(href='/api/getrawtransaction?txid=' + hashes.txhash + '&decrypt=1') #{address}/api/getrawtransaction?txid=#{hashes.txhash}&decrypt=1 - if settings.public_api.rpc['getnetworkhashps'] == true && settings.index.show_hashrate == true && settings.api_cmds['getnetworkhashps'] != null && settings.api_cmds['getnetworkhashps'] != '' + a(href='/api/getrawtransaction?txid=' + settings.api_page.sample_data.txhash + '&decrypt=1') #{address}/api/getrawtransaction?txid=#{settings.api_page.sample_data.txhash}&decrypt=1 + if settings.api_page.public_apis.rpc.getnetworkhashps.enabled == true && settings.shared_pages.show_hashrate == true && settings.api_cmds['getnetworkhashps'] != null && settings.api_cmds['getnetworkhashps'] != '' li p div.font-weight-bold getnetworkhashps div em #{settings.locale.api_getnetworkhashps} a(href='/api/getnetworkhashps') #{address}/api/getnetworkhashps - if settings.public_api.rpc['getvotelist'] == true && settings.api_cmds['getvotelist'] != null && settings.api_cmds['getvotelist'] != '' + if settings.api_page.public_apis.rpc.getvotelist.enabled == true && settings.api_cmds['getvotelist'] != null && settings.api_cmds['getvotelist'] != '' li p div.font-weight-bold getvotelist div em #{settings.locale.api_getvotelist} a(href='/api/getvotelist') #{address}/api/getvotelist - if settings.public_api.rpc['getmasternodecount'] == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '' + if settings.api_page.public_apis.rpc.getmasternodecount.enabled == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '' li p div.font-weight-bold getmasternodecount div em #{settings.locale.api_getmasternodecount} a(href='/api/getmasternodecount') #{address}/api/getmasternodecount - if settings.heavy == true - if settings.public_api.rpc['getmaxmoney'] == true && settings.api_cmds.heavies['getmaxmoney'] != null && settings.api_cmds.heavies['getmaxmoney'] != '' + if settings.blockchain_specific.heavycoin.enabled == true + if settings.blockchain_specific.heavycoin.public_apis.getmaxmoney.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getmaxmoney'] != null && settings.blockchain_specific.heavycoin.api_cmds['getmaxmoney'] != '' li p div.font-weight-bold getmaxmoney div em #{settings.locale.api_getmaxmoney} a(href='/api/getmaxmoney') #{address}/api/getmaxmoney - if settings.public_api.rpc['getmaxvote'] == true && settings.api_cmds.heavies['getmaxvote'] != null && settings.api_cmds.heavies['getmaxvote'] != '' + if settings.blockchain_specific.heavycoin.public_apis.getmaxvote.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getmaxvote'] != null && settings.blockchain_specific.heavycoin.api_cmds['getmaxvote'] != '' li p div.font-weight-bold getmaxvote div em #{settings.locale.api_getmaxvote} a(href='/api/getmaxvote') #{address}/api/getmaxvote - if settings.public_api.rpc['getvote'] == true && settings.api_cmds.heavies['getvote'] != null && settings.api_cmds.heavies['getvote'] != '' + if settings.blockchain_specific.heavycoin.public_apis.getvote.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getvote'] != null && settings.blockchain_specific.heavycoin.api_cmds['getvote'] != '' li p div.font-weight-bold getvote div em #{settings.locale.api_getvote} a(href='/api/getvote') #{address}/api/getvote - if settings.public_api.rpc['getphase'] == true && settings.api_cmds.heavies['getphase'] != null && settings.api_cmds.heavies['getphase'] != '' + if settings.blockchain_specific.heavycoin.public_apis.getphase.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getphase'] != null && settings.blockchain_specific.heavycoin.api_cmds['getphase'] != '' li p div.font-weight-bold getphase div em #{settings.locale.api_getphase} a(href='/api/getphase') #{address}/api/getphase - if settings.public_api.rpc['getreward'] == true && settings.api_cmds.heavies['getreward'] != null && settings.api_cmds.heavies['getreward'] != '' + if settings.blockchain_specific.heavycoin.public_apis.getreward.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getreward'] != null && settings.blockchain_specific.heavycoin.api_cmds['getreward'] != '' li p div.font-weight-bold getreward div em #{settings.locale.api_getreward} a(href='/api/getreward') #{address}/api/getreward - if settings.public_api.rpc['getsupply'] == true && settings.api_cmds.heavies['getsupply'] != null && settings.api_cmds.heavies['getsupply'] != '' + if settings.blockchain_specific.heavycoin.public_apis.getsupply.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getsupply'] != null && settings.blockchain_specific.heavycoin.api_cmds['getsupply'] != '' li p div.font-weight-bold getsupply div em #{settings.locale.api_getsupply} a(href='/api/getsupply') #{address}/api/getsupply - if settings.public_api.rpc['getnextrewardestimate'] == true && settings.api_cmds.heavies['getnextrewardestimate'] != null && settings.api_cmds.heavies['getnextrewardestimate'] != '' + if settings.blockchain_specific.heavycoin.public_apis.getnextrewardestimate.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getnextrewardestimate'] != null && settings.blockchain_specific.heavycoin.api_cmds['getnextrewardestimate'] != '' li p div.font-weight-bold getnextrewardestimate div em #{settings.locale.api_getnextrewardestimate} a(href='/api/getnextrewardestimate') #{address}/api/getnextrewardestimate - if settings.public_api.rpc['getnextrewardwhenstr'] == true && settings.api_cmds.heavies['getnextrewardwhenstr'] != null && settings.api_cmds.heavies['getnextrewardwhenstr'] != '' + if settings.blockchain_specific.heavycoin.public_apis.getnextrewardwhenstr.enabled == true && settings.blockchain_specific.heavycoin.api_cmds['getnextrewardwhenstr'] != null && settings.blockchain_specific.heavycoin.api_cmds['getnextrewardwhenstr'] != '' li p div.font-weight-bold getnextrewardwhenstr @@ -146,105 +146,107 @@ block content p em Return data from local indexes ul - if settings.public_api.ext['getmoneysupply'] == true + if settings.api_page.public_apis.ext.getmoneysupply.enabled == true li p div.font-weight-bold getmoneysupply div em Returns current money supply a(href='/ext/getmoneysupply') #{address}/ext/getmoneysupply - if settings.public_api.ext['getdistribution'] == true + if settings.api_page.public_apis.ext.getdistribution.enabled == true li p div.font-weight-bold getdistribution div em Returns wealth distribution stats a(href='/ext/getdistribution') #{address}/ext/getdistribution - if settings.public_api.ext['getaddress'] == true + if settings.api_page.public_apis.ext.getaddress.enabled == true li p div.font-weight-bold getaddress (/ext/getaddress/hash) div em Returns information for given address - a(href='/ext/getaddress/' + hashes.address) #{address}/ext/getaddress/#{hashes.address} - if settings.public_api.ext['getaddresstxs'] == true + a(href='/ext/getaddress/' + settings.api_page.sample_data.address) #{address}/ext/getaddress/#{settings.api_page.sample_data.address} + if settings.api_page.public_apis.ext.getaddresstxs.enabled == true li p div.font-weight-bold getaddresstxs (/ext/getaddresstxs/hash/start/length) div em Returns last [length] transactions for address [hash], starting from offset [start] - a(href='/ext/getaddresstxs/' + hashes.address + '/0/50') #{address}/ext/getaddresstxs/#{hashes.address}/0/50 - if settings.public_api.ext['gettx'] == true + a(href='/ext/getaddresstxs/' + settings.api_page.sample_data.address + '/0/50') #{address}/ext/getaddresstxs/#{settings.api_page.sample_data.address}/0/50 + if settings.api_page.public_apis.ext.gettx.enabled == true li p div.font-weight-bold gettx (/ext/gettx/hash) div em Returns information for given tx hash - a(href='/ext/gettx/' + hashes.txhash) #{address}/ext/gettx/#{hashes.txhash} - if settings.public_api.ext['getbalance'] == true + a(href='/ext/gettx/' + settings.api_page.sample_data.txhash) #{address}/ext/gettx/#{settings.api_page.sample_data.txhash} + if settings.api_page.public_apis.ext.getbalance.enabled == true li p div.font-weight-bold getbalance (/ext/getbalance/hash) div em Returns current balance of given address - a(href='/ext/getbalance/' + hashes.address) #{address}/ext/getbalance/#{hashes.address} - if settings.public_api.ext['getlasttxs'] == true + a(href='/ext/getbalance/' + settings.api_page.sample_data.address) #{address}/ext/getbalance/#{settings.api_page.sample_data.address} + if settings.api_page.public_apis.ext.getlasttxs.enabled == true li p div.font-weight-bold getlasttxs (/ext/getlasttxs/min/start/length) div em Returns last [length] transactions greater than [min] coins, starting from offset [start] + div + em Note: [length] is limited to returning #{settings.api_page.public_apis.ext.getlasttxs.max_items_per_query} records per query div a(href='/ext/getlasttxs/100/0/100') #{address}/ext/getlasttxs/100/0/100 - if settings.public_api.ext['getcurrentprice'] == true + if settings.api_page.public_apis.ext.getcurrentprice.enabled == true li p div.font-weight-bold getcurrentprice div em Returns last known exchange price a(href='/ext/getcurrentprice') #{address}/ext/getcurrentprice - if settings.public_api.ext['getnetworkpeers'] == true + if settings.api_page.public_apis.ext.getnetworkpeers.enabled == true li p div.font-weight-bold getnetworkpeers div em Returns the list of network peers that have connected to the explorer node in the last 24 hours a(href='/ext/getnetworkpeers') #{address}/ext/getnetworkpeers - if settings.public_api.ext['getbasicstats'] == true + if settings.api_page.public_apis.ext.getbasicstats.enabled == true li p div.font-weight-bold getbasicstats div - em="Returns basic statistics about the coin including: block count, circulating supply, USD price, BTC price" + (settings.public_api.rpc['getmasternodecount'] == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '' ? ', ' + '# of masternodes' : '') + em="Returns basic statistics about the coin including: block count, circulating supply, USD price, BTC price" + (settings.api_page.public_apis.rpc.getmasternodecount.enabled == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '' ? ', ' + '# of masternodes' : '') a(href='/ext/getbasicstats') #{address}/ext/getbasicstats - if settings.public_api.ext['getsummary'] == true + if settings.api_page.public_apis.ext.getsummary.enabled == true li p div.font-weight-bold getsummary div - em="Returns a summary of coin data including: difficulty, hybrid difficulty, circulating supply, hash rate, BTC price, network connection count, block count" + (settings.public_api.rpc['getmasternodecount'] == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '' ? ', ' + 'count of online masternodes' + ', ' + 'count of offline masternodes' : '') + em="Returns a summary of coin data including: difficulty, hybrid difficulty, circulating supply, hash rate, BTC price, network connection count, block count" + (settings.api_page.public_apis.rpc.getmasternodecount.enabled == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '' ? ', ' + 'count of online masternodes' + ', ' + 'count of offline masternodes' : '') a(href='/ext/getsummary') #{address}/ext/getsummary - if settings.public_api.ext['getmasternodelist'] == true && settings.api_cmds['getmasternodelist'] != null && settings.api_cmds['getmasternodelist'] != '' + if settings.api_page.public_apis.ext.getmasternodelist.enabled == true && settings.api_cmds['getmasternodelist'] != null && settings.api_cmds['getmasternodelist'] != '' li p div.font-weight-bold getmasternodelist div em #{settings.locale.api_getmasternodelist} a(href='/ext/getmasternodelist') #{address}/ext/getmasternodelist - if settings.public_api.ext['getmasternoderewards'] == true + if settings.api_page.public_apis.ext.getmasternoderewards.enabled == true li p div.font-weight-bold getmasternoderewards (/ext/getmasternoderewards/hash/since) div em Returns a list of masternode reward transactions for address [hash] that arrived after block height [since] - a(href='/ext/getmasternoderewards/' + hashes.address + '/' + hashes.blockindex) #{address}/ext/getmasternoderewards/#{hashes.address}/#{hashes.blockindex} - if settings.public_api.ext['getmasternoderewardstotal'] == true + a(href='/ext/getmasternoderewards/' + settings.api_page.sample_data.address + '/' + settings.api_page.sample_data.blockindex) #{address}/ext/getmasternoderewards/#{settings.api_page.sample_data.address}/#{settings.api_page.sample_data.blockindex} + if settings.api_page.public_apis.ext.getmasternoderewardstotal.enabled == true li p div.font-weight-bold getmasternoderewardstotal (/ext/getmasternoderewardstotal/hash/since) div em Returns the total number of coins earned in masternode rewards for address [hash] that arrived after block height [since] - a(href='/ext/getmasternoderewardstotal/' + hashes.address + '/' + hashes.blockindex) #{address}/ext/getmasternoderewardstotal/#{hashes.address}/#{hashes.blockindex} + a(href='/ext/getmasternoderewardstotal/' + settings.api_page.sample_data.address + '/' + settings.api_page.sample_data.blockindex) #{address}/ext/getmasternoderewardstotal/#{settings.api_page.sample_data.address}/#{settings.api_page.sample_data.blockindex} hr h3 Linking (GET) p @@ -253,16 +255,16 @@ block content li p div.font-weight-bold transaction (/tx/txid) - a(href='/tx/' + hashes.txhash) #{address}/tx/#{hashes.txhash} + a(href='/tx/' + settings.api_page.sample_data.txhash) #{address}/tx/#{settings.api_page.sample_data.txhash} li p div.font-weight-bold block (/block/hash) - a(href='/block/' + hashes.blockhash) #{address}/block/#{hashes.blockhash} + a(href='/block/' + settings.api_page.sample_data.blockhash) #{address}/block/#{settings.api_page.sample_data.blockhash} li p div.font-weight-bold address (/address/hash) - a(href='/address/' + hashes.address) #{address}/address/#{hashes.address} + a(href='/address/' + settings.api_page.sample_data.address) #{address}/address/#{settings.api_page.sample_data.address} li p div.font-weight-bold qrcode (/qr/hash) - a(href='/qr/' + hashes.address) #{address}/qr/#{hashes.address} \ No newline at end of file + a(href='/qr/' + settings.api_page.sample_data.address) #{address}/qr/#{settings.api_page.sample_data.address} \ No newline at end of file diff --git a/views/layout.pug b/views/layout.pug index d7a7689..7127186 100644 --- a/views/layout.pug +++ b/views/layout.pug @@ -4,8 +4,8 @@ html(lang='en') meta(charset='UTF-8') meta(name='viewport' content='width=device-width, initial-scale=1') meta(http-equiv='Content-Language', content='en') - title=settings.title - link(rel='stylesheet', href='/css/themes/' + settings.theme + '/bootstrap.min.css') + title=settings.shared_pages.page_title + link(rel='stylesheet', href='/css/themes/' + settings.shared_pages.theme + '/bootstrap.min.css') link(rel='stylesheet', href='//use.fontawesome.com/releases/v5.15.1/css/all.css') if active == 'markets' || active == 'richlist' link(rel='stylesheet', href='/css/jquery.jqplot.min.css') @@ -41,16 +41,16 @@ html(lang='en') if (screenWidth <= 575) { // Mobile - $('#footer-container').css('height', '!{settings.footer_height_mobile}'); + $('#footer-container').css('height', '!{settings.shared_pages.page_footer.footer_height_mobile}'); } else if (screenWidth >= 576 && screenWidth <= 991) { // Tablet - $('#footer-container').css('height', '!{settings.footer_height_tablet}'); + $('#footer-container').css('height', '!{settings.shared_pages.page_footer.footer_height_tablet}'); } else { // Desktop - $('#footer-container').css('height', '!{settings.footer_height_desktop}'); + $('#footer-container').css('height', '!{settings.shared_pages.page_footer.footer_height_desktop}'); } - if (!#{settings.sticky_footer}) { + if (!#{settings.shared_pages.page_footer.sticky_footer}) { // Wait a tick before fixing footer position to give time for elements to be rendered var nonStickyFooterSetIntervalID = setInterval(function() { // Stop setInterval from running again @@ -77,13 +77,13 @@ html(lang='en') if (screenWidth <= 575) { // Mobile - retVal = !{settings.social_link_percent_height_mobile}; + retVal = !{settings.shared_pages.page_footer.social_link_percent_height_mobile}; } else if (screenWidth >= 576 && screenWidth <= 991) { // Tablet - retVal = !{settings.social_link_percent_height_tablet}; + retVal = !{settings.shared_pages.page_footer.social_link_percent_height_tablet}; } else { // Desktop - retVal = !{settings.social_link_percent_height_desktop}; + retVal = !{settings.shared_pages.page_footer.social_link_percent_height_desktop}; } return retVal; @@ -136,16 +136,14 @@ html(lang='en') var splitValue, splitParts; if (!isNaN(json.difficulty)) - diffString = Number(json.difficulty).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':true}); + diffString = Number(json.difficulty).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); if (!isNaN(json.supply)) supplyString = parseInt(parseFloat(json.supply).toFixed(0)).toLocaleString('en'); if (!isNaN(json.hashrate)) hashrateString = Number(json.hashrate).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); - $("#lblX1").text(' '); - $("#supply").text(supplyString); - splitValue = Number(parseFloat(json.lastPrice).toFixed(8) * parseInt(parseFloat(json.supply).toFixed(0))).toLocaleString('en'); + splitValue = Number(parseFloat(json.lastPrice).toFixed(8) * parseInt(parseFloat(json.supply).toFixed(0))).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); splitParts = splitValue.split('.'); showTopPanelData('supplypanel', 'supplyPanelLoading'); @@ -155,18 +153,21 @@ html(lang='en') splitParts = diffString.split('.'); $("#difficulty").html(splitParts[0] + '.' + splitParts[1] + ''); - if (json.difficultyHybrid == null || json.difficultyHybrid == '') { - $("#difficultyHybrid").html('0.00'); - } else { - splitValue = Number(json.difficultyHybrid).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); - splitParts = splitValue.split('.'); + if (json.difficultyHybrid == null || json.difficultyHybrid == '') + $("#difficultyHybrid").html('-'); + else { + splitParts = json.difficultyHybrid.split('.'); $("#difficultyHybrid").html(splitParts[0] + '.' + splitParts[1] + ''); } showTopPanelData('difficultypanel', 'difficultyPanelLoading'); - splitParts = hashrateString.split('.'); - $("#hashrate").html(splitParts[0] + '.' + splitParts[1] + ''); + if (hashrateString == null || hashrateString == '' || hashrateString == '-') + $("#hashrate").html('-'); + else { + splitParts = hashrateString.split('.'); + $("#hashrate").html(splitParts[0] + '.' + splitParts[1] + ''); + } showTopPanelData('hashratepanel', 'hashratePanelLoading'); splitValue = Number(json.lastPrice).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); @@ -189,7 +190,7 @@ html(lang='en') update_stats(); function getNetworkPanel() { var networkSuffix=''; - switch ('#{settings.nethash_units}') { + switch ('#{settings.shared_pages.page_header.panels.network_panel.nethash_units}') { case "K": networkSuffix='(KH/s)'; break; @@ -210,55 +211,52 @@ html(lang='en') break; } var hashRateType=''; - if ('#{settings.index.difficulty}' == 'Hybrid') hashRateType+='
'; - return '
#{settings.locale.network} '+networkSuffix+'
'; + return '
#{settings.locale.network} '+networkSuffix+'
'; } function getDifficultyPanel() { var difficultyType=''; - if ('#{settings.index.difficulty}' == 'Hybrid') difficultyType+='
'; - return '
#{settings.locale.difficulty}
'; + if ('#{settings.shared_pages.difficulty}' == 'Hybrid') difficultyType+='
'; + return '
#{settings.locale.difficulty}
'; } function getMasternodesPanel() { - return '
#{settings.locale.masternodecount}
'; + return '
#{settings.locale.masternodecount}
'; } function getCoinSupplyPanel() { var supplyType=''; - if ('#{settings.index.difficulty}' == 'Hybrid') supplyType+='
'; - return '
#{settings.locale.ex_supply} (#{settings.symbol})
'; + return '
#{settings.locale.ex_supply} (#{settings.coin.symbol})
'; } function getPricePanel() { var priceType=''; - if ('#{settings.index.difficulty}' == 'Hybrid') priceType+='
'; - return '
Price (#{settings.markets.exchange})
'; + return '
Price (#{settings.markets_page.default_exchange.trading_pair.split('/')[1]})
'; } function getMarketCapPanel() { - return '
Market Cap (#{settings.markets.exchange})
'; + return '
Market Cap (#{settings.markets_page.default_exchange.trading_pair.split('/')[1]})
'; } function getLogoPanel() { - return '#{settings.coin} Logo'; + return '#{settings.coin.name} Logo'; } function getActivePanel(panelName) { var sReturn=''; switch (panelName) { - case "networkpnl": + case "network_panel": sReturn=getNetworkPanel(); break; - case "difficultypnl": + case "difficulty_panel": sReturn=getDifficultyPanel(); break; - case "masternodespnl": + case "masternodes_panel": sReturn=getMasternodesPanel(); break; - case "coinsupplypnl": + case "coin_supply_panel": sReturn=getCoinSupplyPanel(); break; - case "pricepnl": + case "price_panel": sReturn=getPricePanel(); break; - case "marketcappnl": + case "market_cap_panel": sReturn=getMarketCapPanel(); break; - case "logopnl": + case "logo_panel": sReturn=getLogoPanel(); break; } @@ -269,7 +267,7 @@ html(lang='en') if (typeof(oPanel) != 'undefined' && oPanel != null) { document.getElementById(panelName).innerHTML=getActivePanel(panelID); - if (panelID == 'logopnl') { + if (panelID == 'logo_panel') { // Remove css classes from logo panel $(oPanel).removeClass(); } @@ -290,68 +288,68 @@ html(lang='en') body - var navbarClasses = ['nav','navbar','navbar-expand-lg']; - var footerClasses = ['nav','navbar','navbar-default','d-none','d-md-flex','d-flex','footer']; - if settings.sticky_header == true + if settings.shared_pages.page_header.sticky_header == true - navbarClasses.push('fixed-top'); - if settings.sticky_footer == true + if settings.shared_pages.page_footer.sticky_footer == true - footerClasses.push('fixed-bottom'); - if settings.display.page_header_bgcolor != null && settings.display.page_header_bgcolor != '' - - navbarClasses.push('bg-' + settings.display.page_header_bgcolor); - if settings.display.page_header_bgcolor.toString().toLowerCase() == 'dark' || settings.display.page_header_bgcolor.toString().toLowerCase() == 'light' - - navbarClasses.push('navbar-' + settings.display.page_header_bgcolor); + if settings.shared_pages.page_header.bgcolor != null && settings.shared_pages.page_header.bgcolor != '' + - navbarClasses.push('bg-' + settings.shared_pages.page_header.bgcolor); + if settings.shared_pages.page_header.bgcolor.toString().toLowerCase() == 'dark' || settings.shared_pages.page_header.bgcolor.toString().toLowerCase() == 'light' + - navbarClasses.push('navbar-' + settings.shared_pages.page_header.bgcolor); else - navbarClasses.push('bg-primary'); - navbarClasses.push('navbar-dark'); - if settings.display.page_footer_bgcolor != null && settings.display.page_footer_bgcolor != '' - - footerClasses.push('bg-' + settings.display.page_footer_bgcolor); - if settings.display.page_footer_bgcolor.toString().toLowerCase() == 'dark' || settings.display.page_footer_bgcolor.toString().toLowerCase() == 'light' - - footerClasses.push('navbar-' + settings.display.page_footer_bgcolor); + if settings.shared_pages.page_footer.bgcolor != null && settings.shared_pages.page_footer.bgcolor != '' + - footerClasses.push('bg-' + settings.shared_pages.page_footer.bgcolor); + if settings.shared_pages.page_footer.bgcolor.toString().toLowerCase() == 'dark' || settings.shared_pages.page_footer.bgcolor.toString().toLowerCase() == 'light' + - footerClasses.push('navbar-' + settings.shared_pages.page_footer.bgcolor); else - footerClasses.push('bg-primary'); - footerClasses.push('navbar-dark'); - div(class=navbarClasses, role='navigation', style=settings.homelink == 'logo' ? 'padding-left:0;' : '') + div(class=navbarClasses, role='navigation', style=settings.shared_pages.page_header.home_link == 'logo' ? 'padding-left:0;' : '') .navbar-header button.navbar-toggler(type='button', data-toggle='collapse', data-target='#navbar-collapse') span.navbar-toggler-icon - if settings.homelink == 'title' - a.navbar-brand(href='/', style='order:-1;') #{settings.title} - else if settings.homelink == 'coin' - a.navbar-brand(href='/', style='order:-1;') #{settings.coin} - else if settings.homelink == 'logo' - a(href='/', alt=settings.coin + ' Home', title=settings.coin + ' Home', style='order:-1;', data-toggle='tooltip', data-placement='bottom') - img.logo-main(src=(settings.headerlogo == null || settings.headerlogo == '' ? settings.logo : settings.headerlogo), style='margin:0;max-height:' + settings.logoheight + 'px;') + if settings.shared_pages.page_header.home_link == 'title' + a.navbar-brand(href='/', style='order:-1;') #{settings.shared_pages.page_title} + else if settings.shared_pages.page_header.home_link == 'coin' + a.navbar-brand(href='/', style='order:-1;') #{settings.coin.name} + else if settings.shared_pages.page_header.home_link == 'logo' + a(href='/', alt=settings.coin.name + ' Home', title=settings.coin.name + ' Home', style='order:-1;', data-toggle='tooltip', data-placement='bottom') + img.logo-main(src=(settings.shared_pages.page_header.home_link_logo == null || settings.shared_pages.page_header.home_link_logo == '' ? settings.shared_pages.logo : settings.shared_pages.page_header.home_link_logo), style='margin:0;max-height:' + settings.shared_pages.page_header.home_link_logo_height + 'px;') .collapse.navbar-collapse(id='navbar-collapse') ul.navbar-nav.mr-auto li#home a.nav-link(href='/') span.fa.fa-search span.margin-left-5 #{settings.locale.menu_explorer} - if settings.heavy == true + if settings.blockchain_specific.heavycoin.enabled == true && settings.blockchain_specific.heavycoin.reward_page.enabled == true li#reward a.nav-link(href='/reward') span.fa.fa-star span.margin-left-5 #{settings.locale.menu_reward} - if settings.display.masternodes == true + if settings.masternodes_page.enabled == true li#masternodes a.nav-link(href='/masternodes') span.fa.fa-share-alt span.margin-left-5 Masternodes - if settings.display.movement == true + if settings.movement_page.enabled == true li#movement a.nav-link.loading(href='/movement') span.far.fa-money-bill-alt span.margin-left-5 #{settings.locale.menu_movement} - if settings.display.network == true + if settings.network_page.enabled == true li#network a.nav-link(href='/network') span.fas.fa-network-wired span.margin-left-5 #{settings.locale.menu_network} - if settings.display.richlist == true + if settings.richlist_page.enabled == true li#richlist a.nav-link(href='/richlist') span.fab.fa-btc span.margin-left-5 #{settings.locale.menu_richlist} - if settings.display.markets == true - if settings.markets.market_dropdown_menu == true && settings.market_data.length > 1 + if settings.markets_page.enabled == true + if settings.markets_page.show_market_dropdown_menu == true && settings.market_count > 1 li#markets.dropdown a.nav-link.dropdown-toggle(data-toggle='dropdown', href='#' role='button' aria-haspopup='true' aria-expanded='false') span.fas.fa-chart-line @@ -359,28 +357,30 @@ html(lang='en') div.dropdown-menu each mkt in settings.market_data if mkt != null && mkt.id != null - a.dropdown-item.loading(href='/markets/' + mkt.id) - if mkt.logo != null && mkt.logo != '' - img.market-logo(src='data:image/png;base64,' + mkt.logo, title=mkt.name, alt=mkt.name) - else - i.market-logo.fas.fa-question-circle - span #{mkt.name} + each pair in mkt.trading_pairs + a.dropdown-item.loading(href='/markets/' + mkt.id + '/' + pair) + if mkt.logo != null && mkt.logo != '' + img.market-logo(src='data:image/png;base64,' + mkt.logo, title=mkt.name + ' (' + pair + ')', alt=mkt.name + ' (' + pair + ')') + else + i.market-logo.fas.fa-question-circle + span #{mkt.name} + span.small (#{pair}) else li#markets - a.nav-link.loading(href='/markets/' + settings.markets.default) + a.nav-link.loading(href='/markets/' + settings.markets_page.default_exchange.exchange_name + '/' + settings.markets_page.default_exchange.trading_pair) span.fas.fa-chart-line span.margin-left-5 #{settings.locale.menu_markets} - if settings.display.api == true + if settings.api_page.enabled == true li#info a.nav-link(href='/info') span.fa.fa-info-circle span.margin-left-5 #{settings.locale.menu_api} - if settings.display.claim_address_header_menu == true && settings.display.claim_address == true + if settings.claim_address_page.show_header_menu == true && settings.claim_address_page.enabled == true li#claim-address a.nav-link.loading(href='/claim') span.far.fa-address-card span.margin-left-5 #{settings.locale.menu_claim_address} - div#body-container(style='margin-top:' + (settings.sticky_header == true ? '80px;' : '20px')) + div#body-container(style='margin-top:' + (settings.shared_pages.page_header.sticky_header == true ? '80px;' : '20px')) if showSync != null && showSync == true .col-lg-12 .alert.alert-warning @@ -410,23 +410,24 @@ html(lang='en') .col-lg-2 .card.card-default.border-0.d-none.d-lg-block.d-block.cardSpacer(id='pnlFive') - } - div#search-row.row.text-center - form.form-inline.col-12.d-flex.justify-content-center(method='post', action='/search') - #index-search.form-group.d-flex.justify-content-center - input.form-control(type='text', name='search', placeholder=settings.locale.ex_search_message, style='min-width:80%;margin-right:5px;') - button.btn.btn-success(type='submit') #{settings.locale.ex_search_button} + if settings.shared_pages.page_header.show_search == true + div#search-row.row.text-center + form.form-inline.col-12.d-flex.justify-content-center(method='post', action='/search') + #index-search.form-group.d-flex.justify-content-center + input.form-control(type='text', name='search', placeholder=settings.locale.ex_search_message, style='min-width:80%;margin-right:5px;') + button.btn.btn-success(type='submit') #{settings.locale.ex_search_button} block content div#footer-container(class=footerClasses, role='navigation') .col-4.navbar-nav ul.nav.justify-content-left - each social in settings.social_links + each social in settings.shared_pages.page_footer.social_links if social.enabled li.float-left - a.nav-link.social-link.border-0(href=social.url, target='_blank', alt=social.tooltip_text, title=social.tooltip_text, data-toggle='tooltip', data-placement='top') + a.nav-link.social-link.border-0(href=social.url, target='_blank', alt=settings.coin.name + ' ' + social.tooltip_text, title=settings.coin.name + ' ' + social.tooltip_text, data-toggle='tooltip', data-placement='top') if social.fontawesome_class != null && social.fontawesome_class != '' span(class='vertical-align-middle ' + social.fontawesome_class) else - img(class='vertical-align-middle', src=social.image_url) + img(class='vertical-align-middle', src=social.image_path) .col-4.navbar-nav ul.nav.justify-content-center li.text-center diff --git a/views/market.pug b/views/market.pug index 707a14e..ea7f552 100644 --- a/views/market.pug +++ b/views/market.pug @@ -3,8 +3,8 @@ extends layout block content include ./includes/common.pug - var theadClasses = []; - if settings.display.table_header_bgcolor != null && settings.display.table_header_bgcolor != '' - - theadClasses.push('thead-' + settings.display.table_header_bgcolor); + if settings.shared_pages.table_header_bgcolor != null && settings.shared_pages.table_header_bgcolor != '' + - theadClasses.push('thead-' + settings.shared_pages.table_header_bgcolor); if marketdata.data != null && marketdata.data.buys != null && marketdata.data.buys.length > 0 && marketdata.data.sells != null && marketdata.data.sells.length > 0 && marketdata.data.history != null && marketdata.data.history.length > 0 script. $(document).ready(function() { @@ -53,7 +53,7 @@ block content if settings.markets_page.show_last_updated == true div.font-weight-bold(style='margin-bottom:15px;') Market data last updated: span.font-weight-normal=(last_updated == null || last_updated == '0' ? ' N/A' : ' ' + format_unixtime(last_updated)) - if settings.markets.market_select_visible == true && settings.market_data.length > 1 + if settings.markets_page.show_market_select == true && settings.market_count > 1 .row .col-md-12.cardSpacer .card.card-default.border-0 @@ -63,22 +63,25 @@ block content ul.nav.nav-pills each mkt in settings.market_data if mkt != null && mkt.id != null - if market == mkt.id - li.nav-item - a.nav-link.active(href='/markets/' + mkt.id) - if mkt.logo != null && mkt.logo != '' - img.align-top.market-logo(src='data:image/png;base64,' + mkt.logo, title=mkt.name, alt=mkt.name) - else - i.market-logo.fas.fa-question-circle - span #{mkt.name} - else - li.nav-item - a.nav-link(href='/markets/' + mkt.id) - if mkt.logo != null && mkt.logo != '' - img.align-top.market-logo(src='data:image/png;base64,' + mkt.logo, title=mkt.name, alt=mkt.name) - else - i.market-logo.fas.fa-question-circle - span #{mkt.name} + each pair in mkt.trading_pairs + if market == mkt.id && marketdata.coin.toLowerCase() + '/' + marketdata.exchange.toLowerCase() == pair.toLowerCase() + li.nav-item + a.nav-link.active(href='/markets/' + mkt.id + '/' + pair) + if mkt.logo != null && mkt.logo != '' + img.align-top.market-logo(src='data:image/png;base64,' + mkt.logo, title=mkt.name + ' (' + pair + ')', alt=mkt.name + ' (' + pair + ')') + else + i.market-logo.fas.fa-question-circle + span #{mkt.name} + span.small (#{pair}) + else + li.nav-item + a.nav-link(href='/markets/' + mkt.id + '/' + pair) + if mkt.logo != null && mkt.logo != '' + img.align-top.market-logo(src='data:image/png;base64,' + mkt.logo, title=mkt.name + ' (' + pair + ')', alt=mkt.name + ' (' + pair + ')') + else + i.market-logo.fas.fa-question-circle + span #{mkt.name} + span.small (#{pair}) if marketdata.data != null && marketdata.data.buys != null && marketdata.data.buys.length > 0 && marketdata.data.sells != null && marketdata.data.sells.length > 0 && marketdata.data.history != null && marketdata.data.history.length > 0 block market_view script. @@ -139,7 +142,9 @@ block content .card-header if marketdata.market_logo != null && marketdata.market_logo != '' img.align-top.market-logo(src='data:image/png;base64,' + marketdata.market_logo, title=marketdata.market_name + ' Logo', alt=marketdata.market_name + ' Logo') - strong #{marketdata.market_name} - #{marketdata.coin}/#{marketdata.exchange} - #{settings.locale.mkt_hours} + strong #{marketdata.market_name} + span.small (#{marketdata.coin}/#{marketdata.exchange}) + strong - #{settings.locale.mkt_hours} if marketdata.data.chartdata == 'null' || marketdata.data.chartdata == '' || marketdata.data.chartdata == '[]' span.fas.fa-chart-line.float-right.view-chart-disabled.iquidus.market-toggle(style='cursor: pointer;', data-toggle='tooltip', data-placement='bottom', title=settings.locale.mkt_no_chart) table.table.table-bordered.right-border-0.summary-table(style='border-top:0;margin-top:0 !important;') diff --git a/views/masternodes.pug b/views/masternodes.pug index fb3dbb8..c88e6b1 100644 --- a/views/masternodes.pug +++ b/views/masternodes.pug @@ -3,6 +3,20 @@ extends layout block content include ./includes/common.pug script. + var setting_txPerPage = parseInt("#{settings.masternodes_page.masternode_table.items_per_page}"); + var lengthMenuOpts = !{JSON.stringify(settings.masternodes_page.masternode_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); function secondsToHms(d) { d = Number(d); var h = Math.floor(d / 3600); @@ -22,6 +36,8 @@ block content responsive: true, lengthChange: true, processing: true, + iDisplayLength: setting_txPerPage, + lengthMenu: lengthMenuOpts, scrollX: true, language: { paginate: { @@ -44,9 +60,9 @@ block content json[i]['activetime'] = secondsToHms(json[i]['activetime']); else json[i]['activetime'] = 'N/A'; - json[i]['addr'] = "" + json[i]['addr'] + (json[i]['claim_name'] != null && json[i]['claim_name'] != '' ? ' (' + json[i]['claim_name'] + ')' : '') + ""; + 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) { + if (labels[addr] != null && labels[addr].enabled == true) { if (labels[addr].type) json[i]['addr'] = '
' + json[i]['addr']; else @@ -101,8 +117,8 @@ block content strong Masternodes table#masternodes-table.table.table-bordered.table-striped.table-hover - var theadClasses = []; - if settings.display.table_header_bgcolor != null && settings.display.table_header_bgcolor != '' - - theadClasses.push('thead-' + settings.display.table_header_bgcolor); + if settings.shared_pages.table_header_bgcolor != null && settings.shared_pages.table_header_bgcolor != '' + - theadClasses.push('thead-' + settings.shared_pages.table_header_bgcolor); thead(class=theadClasses) tr th.text-center Pay rank diff --git a/views/movement.pug b/views/movement.pug index 914c9f2..41e15e7 100644 --- a/views/movement.pug +++ b/views/movement.pug @@ -3,22 +3,38 @@ extends layout block content include ./includes/common.pug script. - var setting_maxTxCount = parseInt("#{settings.index.last_txs}"); - var setting_txPerPage = parseInt("#{settings.index.txs_per_page}"); + var setting_maxTxCount = parseInt("#{settings.api_page.public_apis.ext.getlasttxs.max_items_per_query}"); + var setting_txPerPage = parseInt("#{settings.movement_page.movement_table.items_per_page}"); + var lengthMenuOptsAdd = !{JSON.stringify(settings.movement_page.movement_table.page_length_options)}; var lengthMenuOpts = []; - var lengthMenuOptsAdd = [ 10, 25, 50, 75, 100, 250, 500, 1000 ]; - for (i=0; i < lengthMenuOptsAdd.length; i++) { + var addedLength = false; + for (i = 0; i < lengthMenuOptsAdd.length; i++) { if (setting_maxTxCount >= lengthMenuOptsAdd[i]) { + if (!addedLength) { + if (lengthMenuOptsAdd[i] > setting_txPerPage) { + lengthMenuOpts.push(setting_txPerPage); + addedLength = true; + } + } + lengthMenuOpts.push(lengthMenuOptsAdd[i]); + + if (!addedLength) { + if (lengthMenuOptsAdd[i] > setting_txPerPage) + lengthMenuOpts.push(setting_txPerPage); + if (lengthMenuOptsAdd[i] == setting_txPerPage || lengthMenuOptsAdd[i] > setting_txPerPage) + addedLength = true; + } } } - if (setting_maxTxCount < setting_txPerPage) { + if (!addedLength && setting_txPerPage <= setting_maxTxCount && setting_txPerPage != lengthMenuOpts[lengthMenuOpts.length - 1]) + lengthMenuOpts.push(setting_txPerPage); + if (!addedLength && setting_txPerPage > setting_maxTxCount && setting_maxTxCount != lengthMenuOpts[lengthMenuOpts.length - 1]) + lengthMenuOpts.push(setting_maxTxCount); + if (setting_maxTxCount < setting_txPerPage) var displayLengthMax = setting_maxTxCount; - } else { + else var displayLengthMax = setting_txPerPage; - } - var rplot; - var colors = ["#0071bc"]; $(document).ready(function() { var rtable = $('#movement-table').dataTable({ autoWidth: true, @@ -31,7 +47,7 @@ block content lengthMenu: lengthMenuOpts, scrollX: true, ajax: { - url: '/ext/getlasttxs/#{min_amount}', + url: '/ext/getlasttxs/#{settings.movement_page.movement_table.min_amount}', beforeSend: function(jqXHR, settings) { settings.url = settings.url.substring(0, settings.url.indexOf('?')) + '/' + getParameterByName('start', settings.url) + '/' + getParameterByName('length', settings.url) + '/internal'; return true; @@ -52,13 +68,7 @@ block content var amountParts = Number(amount).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}).split('.'); var amountStr = amountParts[0] + '.' + amountParts[1] + ''; var timestamp = new Date(data[5] * 1000).toUTCString(); //variables for better readability - if (amount > '#{flagb}') { - var total = ""; - } else if (amount > '#{flaga}') { - var total = ""; - } else { - var total = ""; - } + var total = ""; $("td:eq(0)", row).html('').addClass('text-center d-table-cell d-md-none'); $("td:eq(1)", row).html('' + txhash + '').addClass('breakWord d-none d-md-table-cell'); $("td:eq(2)", row).html(total).addClass('text-center'); @@ -70,9 +80,12 @@ block content enableTooltips(); } }); - setInterval(function () { - rtable.api().ajax.reload(null, false); - }, 45000); + var setting_reload_table_seconds = parseInt("#{settings.movement_page.movement_table.reload_table_seconds}"); + if (setting_reload_table_seconds > 0) { + setInterval( function () { + rtable.api().ajax.reload(null, false); + }, (setting_reload_table_seconds * 1000) ); + } }); .col-md-12 if settings.movement_page.show_last_updated == true @@ -83,13 +96,13 @@ block content strong="Latest Movement" table#movement-table.table.table-bordered.table-striped.table-paging.mobile-border-right - var theadClasses = []; - if settings.display.table_header_bgcolor != null && settings.display.table_header_bgcolor != '' - - theadClasses.push('thead-' + settings.display.table_header_bgcolor); + if settings.shared_pages.table_header_bgcolor != null && settings.shared_pages.table_header_bgcolor != '' + - theadClasses.push('thead-' + settings.shared_pages.table_header_bgcolor); thead(class=theadClasses) tr th.d-table-cell.d-md-none th.d-none.d-md-table-cell #{settings.locale.tx_hash} th.text-center #{settings.locale.mkt_amount} - span.small (#{settings.symbol}) + span.small (#{settings.coin.symbol}) th.text-center #{settings.locale.timestamp} tbody \ No newline at end of file diff --git a/views/network.pug b/views/network.pug index 3e7873d..cf7760d 100644 --- a/views/network.pug +++ b/views/network.pug @@ -3,7 +3,23 @@ extends layout block content include ./includes/common.pug script. + function generateLengthMenu(setting_txPerPage, lengthMenuOpts) { + 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); + return lengthMenuOpts; + } $(document).ready(function() { + var setting_txPerPage = parseInt("#{settings.network_page.connections_table.items_per_page}"); $('#connections-table').dataTable({ autoWidth: true, searching: false, @@ -11,6 +27,8 @@ block content responsive: true, lengthChange: true, processing: true, + iDisplayLength: setting_txPerPage, + lengthMenu: generateLengthMenu(setting_txPerPage, !{JSON.stringify(settings.network_page.connections_table.page_length_options)}), scrollX: true, language: { paginate: { @@ -45,6 +63,7 @@ block content { data: 'country', width: '25%'} ] }); + setting_txPerPage = parseInt("#{settings.network_page.addnodes_table.items_per_page}"); $('#addnodes-table').dataTable({ autoWidth: true, searching: false, @@ -52,6 +71,8 @@ block content responsive: true, lengthChange: true, processing: true, + iDisplayLength: setting_txPerPage, + lengthMenu: generateLengthMenu(setting_txPerPage, !{JSON.stringify(settings.network_page.addnodes_table.page_length_options)}), scrollX: true, language: { paginate: { @@ -80,13 +101,16 @@ block content {targets: '_all', className: 'text-left'} ] }); - $('#addnodes2-table').dataTable({ + setting_txPerPage = parseInt("#{settings.network_page.onetry_table.items_per_page}"); + $('#onetry-table').dataTable({ autoWidth: true, searching: false, ordering: false, responsive: true, lengthChange: true, processing: true, + iDisplayLength: setting_txPerPage, + lengthMenu: generateLengthMenu(setting_txPerPage, !{JSON.stringify(settings.network_page.onetry_table.page_length_options)}), scrollX: true, language: { paginate: { @@ -121,8 +145,8 @@ block content }); }); - var theadClasses = []; - if settings.display.table_header_bgcolor != null && settings.display.table_header_bgcolor != '' - - theadClasses.push('thead-' + settings.display.table_header_bgcolor); + if settings.shared_pages.table_header_bgcolor != null && settings.shared_pages.table_header_bgcolor != '' + - theadClasses.push('thead-' + settings.shared_pages.table_header_bgcolor); .col-md-12.cardSpacer .text-center(style='margin-bottom:15px;') i #{settings.locale.net_warning} @@ -161,7 +185,7 @@ block content .card-body.border-top-0 :markdown-it Alternatively you can try one of these lines in the coin wallet debug window, or add them with *coindaemon*-cli - table#addnodes2-table.table.table-bordered.table-striped.table-paging.mobile-border-right + table#onetry-table.table.table-bordered.table-striped.table-paging.mobile-border-right thead(class=theadClasses) tr th OneTry Node Lines diff --git a/views/reward.pug b/views/reward.pug index b4346ae..5116eac 100644 --- a/views/reward.pug +++ b/views/reward.pug @@ -14,27 +14,27 @@ block content fnDrawCallback: function(settings) { fixDataTableColumns(); } - }) + }); }); .row(style='margin-left:0;margin-right:0;') .col-xs-12.col-md-12 - if settings.reward_page.show_last_updated == true + if settings.blockchain_specific.heavycoin.reward_page.show_last_updated == true div.font-weight-bold(style='margin-bottom:15px;') Reward data last updated: span.font-weight-normal=(last_updated == null || last_updated == '0' ? ' N/A' : ' ' + format_unixtime(last_updated)) .card.card-default.border-0.card-address-summary .card-header(style='position:relative;') strong #{settings.locale.heavy_title} - span.small (#{settings.symbol}) + span.small (#{settings.coin.symbol}) table.table.table-bordered.table-striped.summary-table(style='border-top:0;border-bottom:0;margin-top:0 !important;') - var theadClasses = []; - if settings.display.table_header_bgcolor != null && settings.display.table_header_bgcolor != '' - - theadClasses.push('thead-' + settings.display.table_header_bgcolor); + if settings.shared_pages.table_header_bgcolor != null && settings.shared_pages.table_header_bgcolor != '' + - theadClasses.push('thead-' + settings.shared_pages.table_header_bgcolor); thead(class=theadClasses) tr th.text-center #{settings.locale.ex_supply} - span.small (#{settings.symbol}) + span.small (#{settings.coin.symbol}) th.text-center #{settings.locale.heavy_cap} - span.small (#{settings.symbol}) + span.small (#{settings.coin.symbol}) th.text-center #{settings.locale.heavy_phase} th.text-center #{settings.locale.heavy_maxvote} th.text-center #{settings.locale.heavy_reward} diff --git a/views/richlist.pug b/views/richlist.pug index 93ebcd8..77437c2 100644 --- a/views/richlist.pug +++ b/views/richlist.pug @@ -2,15 +2,23 @@ extends layout block content include ./includes/common.pug - if show_dist == true + + if settings.richlist_page.wealth_distribution.show_distribution_chart == true script. $(document).ready(function() { var data = [ - ['Top 1-25', !{dista.percent}],['Top 26-50', !{distb.percent}],['Top 51-75', !{distc.percent}],['Top 76-100', !{distd.percent}],['101+', !{diste.percent}] + ['Top 1-25', !{dista.percent}], + ['Top 26-50', !{distb.percent}], + ['Top 51-75', !{distc.percent}], + ['Top 76-100', !{distd.percent}], + ['101+', !{diste.percent}] ]; + var burned = '!{burned}'; + if ('#{settings.richlist_page.burned_coins.include_burned_coins_in_distribution}' == 'true' && burned != 'null' && burned != '' && burned != '0') + data.push(['Burned Coins', parseFloat(((burned / 100000000) / !{stats.supply}) * 100)]); $.jqplot('pieChart', [data], { - seriesColors: [ "#d9534f", "#5cb85c", "#428bca", "#222", "#CCC"], + seriesColors: !{JSON.stringify(settings.richlist_page.wealth_distribution.colors)}, series: [{ renderer: $.jqplot.PieRenderer, rendererOptions: { @@ -33,149 +41,192 @@ block content ); }); - var theadClasses = []; - if settings.display.table_header_bgcolor != null && settings.display.table_header_bgcolor != '' - - theadClasses.push('thead-' + settings.display.table_header_bgcolor); + if settings.shared_pages.table_header_bgcolor != null && settings.shared_pages.table_header_bgcolor != '' + - theadClasses.push('thead-' + settings.shared_pages.table_header_bgcolor); .row(style='margin-left:0;margin-right:0;') - div(class=(show_dist == true ? 'col-xs-12 col-lg-8' : 'col-12')) - .container - if settings.richlist_page.show_last_updated == true - div.font-weight-bold(style='margin-bottom:15px;') Top 100 data last updated: - span.font-weight-normal=(last_updated == null || last_updated == '0' ? ' N/A' : ' ' + format_unixtime(last_updated)) - ul.nav.nav-tabs(role='tablist') - li.nav-item(role='presentation') - a.nav-link.active(href='#balance', aria-controls='balance', role='tab', data-toggle='tab') #{settings.locale.rl_current_balance} - li.nav-item(role='presentation') - a.nav-link(href='#received', aria-controls='received', role='tab', data-toggle='tab') #{settings.locale.rl_received_coins} - .tab-content - #balance.container.tab-pane.active(style='margin-top:0;') - .card.card-default.border-0 - table.table.table-hover.table-bordered.table-striped.summary-table.right-border-0(style='margin-bottom:0;', cellspacing='0') + if settings.richlist_page.show_current_balance == true || settings.richlist_page.show_received_coins == true + div(class=(settings.richlist_page.wealth_distribution.show_distribution_table == true || settings.richlist_page.wealth_distribution.show_distribution_chart == true ? 'col-xs-12 col-lg-8' : 'col-12')) + .container + if settings.richlist_page.show_last_updated == true + div.font-weight-bold(style='margin-bottom:15px;') Top 100 data last updated: + span.font-weight-normal=(last_updated == null || last_updated == '0' ? ' N/A' : ' ' + format_unixtime(last_updated)) + ul.nav.nav-tabs(role='tablist') + if settings.richlist_page.show_current_balance == true + li.nav-item(role='presentation') + a(class='nav-link' + (settings.richlist_page.show_current_balance == true ? ' active' : ''), href='#balance', aria-controls='balance', role='tab', data-toggle='tab') #{settings.locale.rl_current_balance} + if settings.richlist_page.show_received_coins == true + li.nav-item(role='presentation') + a(class='nav-link' + (!settings.richlist_page.show_current_balance ? ' active' : ''), href='#received', aria-controls='received', role='tab', data-toggle='tab') #{settings.locale.rl_received_coins} + .tab-content + if settings.richlist_page.show_current_balance == true + #balance(class='container tab-pane' + (settings.richlist_page.show_current_balance == true ? ' active' : ''), style='margin-top:0;') + .card.card-default.border-0 + table.table.table-hover.table-bordered.table-striped.summary-table.right-border-0(style='margin-bottom:0;', cellspacing='0') + thead(class=theadClasses) + tr + th.text-center + span.fa.fa-flag-checkered + th #{settings.locale.tx_address} + th.text-center #{settings.locale.rl_balance} + span.small (#{settings.coin.symbol}) + th.text-center % + tbody + - var count = 0; + each address in balance + - count = count + 1; + - var itemFixed = (parseInt(address.balance) / 100000000); + - var itemFixedParts = Number(itemFixed).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}).split("."); + - var percent = Number((itemFixed / stats.supply) * 100).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); + - var percentParts = percent.split("."); + tr + td.text-center + =count + td + if settings.claim_address_page.enabled == false || address.name == null || address.name == '' + a.breakWord(href='/address/' + address.a_id) #{address.a_id} + else + a.breakWord(href='/address/' + address.a_id) #{address.name} + include ./includes/rl_labels.pug + td.text-center #{itemFixedParts[0]}. + span.decimal #{itemFixedParts[1]} + td.text-center #{percentParts[0]}. + span.decimal #{percentParts[1]} + if settings.richlist_page.show_received_coins == true + #received(class='container tab-pane' + (!settings.richlist_page.show_current_balance ? ' active' : ''), style='margin-top:0;') + .card.card-default.border-0 + table.table.table-hover.table-bordered.table-striped.summary-table.right-border-0(style='margin-bottom:0;', cellspacing='0') + thead(class=theadClasses) + tr + th.text-center + span.fa.fa-flag-checkered + th #{settings.locale.tx_address} + th.text-center #{settings.locale.rl_received} + span.small (#{settings.coin.symbol}) + tbody + - var count = 0; + each address in received + - count = count + 1; + - var itemFixed = Number(parseInt(address.received) / 100000000).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); + - var itemFixedParts = itemFixed.split("."); + tr + td.text-center + =count + td + if settings.claim_address_page.enabled == false || address.name == null || address.name == '' + a.breakWord(href='/address/' + address.a_id) #{address.a_id} + else + a.breakWord(href='/address/' + address.a_id) #{address.name} + include ./includes/rl_labels.pug + td.text-center #{itemFixedParts[0]}. + span.decimal #{itemFixedParts[1]} + if settings.richlist_page.wealth_distribution.show_distribution_table == true || settings.richlist_page.wealth_distribution.show_distribution_chart == true + div(class=(settings.richlist_page.show_received_coins == true || settings.richlist_page.show_current_balance == true ? 'col-xs-12 col-lg-4' : 'col-12')) + if settings.richlist_page.wealth_distribution.show_distribution_table == true + #summary-panel.card.card-default.border-0(style='margin-top:34px;') + .card-header + strong #{settings.locale.rl_wealth} + table.table.table-hover.table-bordered.summary-table.right-border-0(style='margin-bottom:0;') thead(class=theadClasses) tr - th.text-center - span.fa.fa-flag-checkered - th #{settings.locale.tx_address} - th.text-center #{settings.locale.rl_balance} - span.small (#{settings.symbol}) + th + th.text-center Amount + span.small (#{settings.coin.symbol}) th.text-center % tbody - - var count = 0; - each address in balance - - count = count + 1; - - var itemFixed = (parseInt(address.balance) / 100000000); - - var itemFixedParts = Number(itemFixed).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}).split("."); - - var percent = Number((itemFixed / stats.supply) * 100).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); + tr + td.font-weight-bold + div.float-left.wealth-dist-color-box(style=('background-color:' + settings.richlist_page.wealth_distribution.colors[0] + ';')) + span #{settings.locale.rl_top25} + - var total = Number(dista.total).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); + - var totalParts = total.split("."); + - var percent = parseFloat(dista.percent).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); - var percentParts = percent.split("."); + td.text-center.breakWord #{totalParts[0]}. + span.decimal.breakWord #{totalParts[1]} + td.text-center #{percentParts[0]}. + span.decimal #{percentParts[1]} + tr + td.font-weight-bold + div.float-left.wealth-dist-color-box(style=('background-color:' + settings.richlist_page.wealth_distribution.colors[1] + ';')) + span #{settings.locale.rl_top50} + - var total = Number(distb.total).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); + - var totalParts = total.split("."); + - var percent = parseFloat(distb.percent).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); + - var percentParts = percent.split("."); + td.text-center.breakWord #{totalParts[0]}. + span.decimal.breakWord #{totalParts[1]} + td.text-center #{percentParts[0]}. + span.decimal #{percentParts[1]} + tr + td.font-weight-bold + div.float-left.wealth-dist-color-box(style=('background-color:' + settings.richlist_page.wealth_distribution.colors[2] + ';')) + span #{settings.locale.rl_top75} + - var total = Number(distc.total).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); + - var totalParts = total.split("."); + - var percent = parseFloat(distc.percent).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); + - var percentParts = percent.split("."); + td.text-center.breakWord #{totalParts[0]}. + span.decimal.breakWord #{totalParts[1]} + td.text-center #{percentParts[0]}. + span.decimal #{percentParts[1]} + tr + td.font-weight-bold + div.float-left.wealth-dist-color-box(style=('background-color:' + settings.richlist_page.wealth_distribution.colors[3] + ';')) + span #{settings.locale.rl_top100} + - var total = Number(distd.total).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); + - var totalParts = total.split("."); + - var percent = parseFloat(distd.percent).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); + - var percentParts = percent.split("."); + td.text-center.breakWord #{totalParts[0]}. + span.decimal.breakWord #{totalParts[1]} + td.text-center #{percentParts[0]}. + span.decimal #{percentParts[1]} + tr.text-right + td.font-weight-bold + span #{settings.locale.total_top_100} + - var total = Number(parseFloat(dista.total) + parseFloat(distb.total) + parseFloat(distc.total) + parseFloat(distd.total)).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); + - var totalParts = total.split("."); + - var percent = (parseFloat(dista.percent)+parseFloat(distb.percent)+parseFloat(distc.percent)+parseFloat(distd.percent)).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); + - var percentParts = percent.split("."); + td.text-center.font-weight-bold.breakWord #{totalParts[0]}. + span.decimal.breakWord #{totalParts[1]} + td.font-weight-bold.text-center #{percentParts[0]}. + span.decimal #{percentParts[1]} + tr + td.font-weight-bold + div.float-left.wealth-dist-color-box(style=('background-color:' + settings.richlist_page.wealth_distribution.colors[4] + ';')) + span 101+ + - var total = Number(diste.total).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); + - var totalParts = total.split("."); + - var percent = parseFloat(diste.percent).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); + - var percentParts = percent.split("."); + td.text-center.breakWord #{totalParts[0]}. + span.decimal.breakWord #{totalParts[1]} + td.text-center #{percentParts[0]}. + span.decimal #{percentParts[1]} + if settings.richlist_page.burned_coins.include_burned_coins_in_distribution == true && burned != null && burned > 0 tr - td.text-center - =count - td - if settings.display.claim_address == false || address.name == null || address.name == '' - a.breakWord(href='/address/' + address.a_id) #{address.a_id} - else - a.breakWord(href='/address/' + address.a_id) #{address.name} - include ./includes/rl_labels.pug - td.text-center #{itemFixedParts[0]}. - span.decimal #{itemFixedParts[1]} + td.font-weight-bold + div.float-left.wealth-dist-color-box(style=('background-color:' + settings.richlist_page.wealth_distribution.colors[5] + ';')) + span Burned Coins + - var total = Number(burned / 100000000).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); + - var totalParts = total.split("."); + - var percent = parseFloat(((burned / 100000000) / stats.supply) * 100).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); + - var percentParts = percent.split("."); + td.text-center.breakWord #{totalParts[0]}. + span.decimal.breakWord #{totalParts[1]} td.text-center #{percentParts[0]}. span.decimal #{percentParts[1]} - #received.container.tab-pane(style='margin-top:0;') - .card.card-default.border-0 - table.table.table-hover.table-bordered.table-striped.summary-table.right-border-0(style='margin-bottom:0;', cellspacing='0') - thead(class=theadClasses) - tr - th.text-center - span.fa.fa-flag-checkered - th #{settings.locale.tx_address} - th.text-center #{settings.locale.rl_received} - span.small (#{settings.symbol}) - tbody - - var count = 0; - each address in received - - count = count + 1; - - var itemFixed = Number(parseInt(address.received) / 100000000).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); - - var itemFixedParts = itemFixed.split("."); - tr - td.text-center - =count - td - if settings.display.claim_address == false || address.name == null || address.name == '' - a.breakWord(href='/address/' + address.a_id) #{address.a_id} - else - a.breakWord(href='/address/' + address.a_id) #{address.name} - include ./includes/rl_labels.pug - td.text-center #{itemFixedParts[0]}. - span.decimal #{itemFixedParts[1]} - if show_dist == true - .col-xs-12.col-lg-4 - #summary-panel.card.card-default.border-0(style='margin-top:34px;') - .card-header - strong #{settings.locale.rl_wealth} - table.table.table-hover.table-bordered.summary-table.right-border-0(style='margin-bottom:0;') - thead(class=theadClasses) - tr - th - th.text-center Amount - span.small (#{settings.symbol}) - th.text-center % - tbody - tr - td.font-weight-bold - div.float-left(style='background-color:#d9534f;width:20px;height:20px;margin-right:6px;') - span #{settings.locale.rl_top25} - - var total = Number(dista.total).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); - - var totalParts = total.split("."); - - var percent = parseFloat(dista.percent).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); - - var percentParts = percent.split("."); - td.text-center.breakWord #{totalParts[0]}. - span.decimal.breakWord #{totalParts[1]} - td.text-center #{percentParts[0]}. - span.decimal #{percentParts[1]} - tr - td.font-weight-bold - div.float-left(style='background-color:#5cb85c;width:20px;height:20px;margin-right:6px;') - span #{settings.locale.rl_top50} - - var total = Number(distb.total).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); - - var totalParts = total.split("."); - - var percent = parseFloat(distb.percent).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); - - var percentParts = percent.split("."); - td.text-center.breakWord #{totalParts[0]}. - span.decimal.breakWord #{totalParts[1]} - td.text-center #{percentParts[0]}. - span.decimal #{percentParts[1]} - tr - td.font-weight-bold - div.float-left(style='background-color:#428bca;width:20px;height:20px;margin-right:6px;') - span #{settings.locale.rl_top75} - - var total = Number(distc.total).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); - - var totalParts = total.split("."); - - var percent = parseFloat(distc.percent).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); - - var percentParts = percent.split("."); - td.text-center.breakWord #{totalParts[0]}. - span.decimal.breakWord #{totalParts[1]} - td.text-center #{percentParts[0]}. - span.decimal #{percentParts[1]} - tr - td.font-weight-bold - div.float-left(style='background-color:#222;width:20px;height:20px;margin-right:6px;') - span #{settings.locale.rl_top100} - - var total = Number(distd.total).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); - - var totalParts = total.split("."); - - var percent = parseFloat(distd.percent).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); - - var percentParts = percent.split("."); - td.text-center.breakWord #{totalParts[0]}. - span.decimal.breakWord #{totalParts[1]} - td.text-center #{percentParts[0]}. - span.decimal #{percentParts[1]} - tr - td.font-weight-bold - span #{settings.locale.total} - - var total = Number(parseFloat(dista.total) + parseFloat(distb.total) + parseFloat(distc.total) + parseFloat(distd.total)).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); - - var totalParts = total.split("."); - - var percent = (parseFloat(dista.percent)+parseFloat(distb.percent)+parseFloat(distc.percent)+parseFloat(distd.percent)).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); - - var percentParts = percent.split("."); - td.text-center.font-weight-bold.breakWord #{totalParts[0]}. - span.decimal.breakWord #{totalParts[1]} - td.font-weight-bold.text-center #{percentParts[0]}. - span.decimal #{percentParts[1]} - div#pieChart(style="width:300px;height:305px;margin:0 auto;") \ No newline at end of file + tr.text-right + td.font-weight-bold + span #{settings.locale.total} + - var total = Number(parseFloat(dista.total) + parseFloat(distb.total) + parseFloat(distc.total) + parseFloat(distd.total) + parseFloat(diste.total) + (settings.richlist_page.burned_coins.include_burned_coins_in_distribution == true && burned != null && burned > 0 ? burned / 100000000 : 0)).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':8,'useGrouping':true}); + - var totalParts = total.split("."); + - var percent = (parseFloat(dista.percent) + parseFloat(distb.percent) + parseFloat(distc.percent) + parseFloat(distd.percent) + parseFloat(diste.percent) + parseFloat((settings.richlist_page.burned_coins.include_burned_coins_in_distribution == true && burned != null && burned > 0 ? ((burned / 100000000) / stats.supply) * 100 : 0))).toLocaleString('en',{'minimumFractionDigits':2,'maximumFractionDigits':2,'useGrouping':false}); + - var percentParts = percent.split("."); + td.text-center.font-weight-bold.breakWord #{totalParts[0]}. + span.decimal.breakWord #{totalParts[1]} + td.font-weight-bold.text-center #{percentParts[0]}. + span.decimal #{percentParts[1]} + if settings.richlist_page.wealth_distribution.show_distribution_chart == true + div#pieChart(style="width:300px;height:305px;margin:0 auto;") \ No newline at end of file diff --git a/views/tx.pug b/views/tx.pug index 42aa784..d9a1d15 100644 --- a/views/tx.pug +++ b/views/tx.pug @@ -4,14 +4,15 @@ block content include ./includes/common.pug - var time = format_unixtime(tx.timestamp); - var theadClasses = []; - if settings.display.table_header_bgcolor != null && settings.display.table_header_bgcolor != '' - - theadClasses.push('thead-' + settings.display.table_header_bgcolor); + if settings.shared_pages.table_header_bgcolor != null && settings.shared_pages.table_header_bgcolor != '' + - theadClasses.push('thead-' + settings.shared_pages.table_header_bgcolor); .col-xs-12.col-md-12 .card.card-default.border-0.cardSpacer .card-header - strong=settings.symbol + ' TXid: ' + tx.txid - a.d-none.d-md-inline(href=`/api/getrawtransaction?txid=${tx.txid}&decrypt=1`) - span.fa.fa-info-circle.iquidus.float-right(data-toggle='tooltip', data-placement='top', title=settings.locale.view_raw_tx_data) + strong=settings.coin.symbol + ' TXid: ' + tx.txid + if settings.api_page.public_apis.rpc.getrawtransaction.enabled == true + a.d-none.d-md-inline(href=`/api/getrawtransaction?txid=${tx.txid}&decrypt=1`) + span.fa.fa-info-circle.iquidus.float-right(data-toggle='tooltip', data-placement='top', title=settings.locale.view_raw_tx_data) table.table.table-bordered.table-striped.summary-table.mobile-border-right thead(class=theadClasses) tr @@ -66,7 +67,7 @@ block content if (tx.vin.length > 0) if tx.vin[0].addresses != 'coinbase' th.text-center #{settings.locale.mkt_amount} - span.small (#{settings.symbol}) + span.small (#{settings.coin.symbol}) tbody if tx.vin.length > 0 each address in tx.vin @@ -101,7 +102,7 @@ block content tr th #{settings.locale.tx_address} th.text-center #{settings.locale.mkt_amount} - span.small (#{settings.symbol}) + span.small (#{settings.coin.symbol}) tbody each address in tx.vout if tx.vout.length > 0