Files
purple-explorer/lib/explorer.js
T
joeuhren 4790764e2c 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
2021-01-22 15:04:32 -07:00

998 lines
37 KiB
JavaScript

var request = require('postman-request')
, settings = require('./settings')
, Address = require('../models/address');
var base_server = 'http://127.0.0.1:' + settings.webserver.port + "/";
var base_url = base_server + 'api/';
const onode = require('./node');
const client = new onode.Client(settings.wallet);
// returns coinbase total sent as current coin supply
function coinbase_supply(cb) {
Address.findOne({a_id: 'coinbase'}, function(err, address) {
if (address) {
return cb(address.sent);
} else {
return cb(0);
}
});
}
function rpcCommand(params, cb) {
client.cmd([{method: params[0].method, params: params[0].parameters}], function(err, response) {
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
}
function prepareRpcCommand(cmd, addParams) {
var method_name = '';
var params = addParams || [];
// Check for null/blank string
if (cmd != null && cmd.trim() != '') {
// Split cmd by spaces
var split = cmd.split(' ');
for (i=0; i<split.length; i++) {
if (i==0)
method_name = split[i];
else
params.push(split[i]);
}
}
return { method: method_name, parameters: params };
}
function convertHashUnits(hashes) {
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.shared_pages.page_header.panels.network_panel.nethash_units == 'M') {
// return units in MH/s
return (hashes / 1000000).toFixed(4);
} 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.shared_pages.page_header.panels.network_panel.nethash_units == 'T') {
// return units in TH/s
return (hashes / 1000000000000).toFixed(4);
} else if (settings.shared_pages.page_header.panels.network_panel.nethash_units == 'P') {
// return units in PH/s
return (hashes / 1000000000000000).toFixed(4);
} else {
// return units in H/s
return hashes.toFixed(4);
}
}
module.exports = {
convert_to_satoshi: function(amount, cb) {
// fix to 8dp & convert to string
var fixed = amount.toFixed(8).toString();
// remove decimal (.) and return integer
return cb(parseInt(fixed.replace('.', '')));
},
get_hashrate: function(cb) {
// check if hash rate should be hidden
if (settings.shared_pages.show_hashrate == false) return cb('-');
// check how to acquire network hashrate
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.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
if (response == 'There was an error. Check your console.') return cb('-');
var net_hash = null;
// check for different implementations of the net has value
if (response.netmhashps) {
// value returned in MH/s so convert to H/s
net_hash = (response.netmhashps * 1000000);
} else if (response.networkhashps)
net_hash = response.networkhashps;
else if (response.hashespersec)
net_hash = response.hashespersec;
// check if netmhashps has a value
if (net_hash) {
// return hash value with proper units
return cb(convertHashUnits(net_hash));
} else {
// netmhashps is blank/null
return cb('-');
}
});
} else {
// get data via internal web api request
var uri = base_url + 'getmininginfo';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.') {
// return a blank value
return cb('-');
} else {
var net_hash = null;
// check for different implementations of the net has value
if (body.netmhashps) {
// value returned in MH/s so convert to H/s
net_hash = (body.netmhashps * 1000000);
} else if (body.networkhashps)
net_hash = body.networkhashps;
else if (body.hashespersec)
net_hash = body.hashespersec;
// check if there is a net hash value
if (net_hash) {
// return hash value with proper units
return cb(convertHashUnits(net_hash));
} else {
// netmhashps is blank/null
return cb('-');
}
}
});
}
} else {
// getmininginfo cmd not set
return cb('-');
}
} 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.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
if (response == 'There was an error. Check your console.') return cb('-');
// check if the response has a value
if (response) {
// return hash value with proper units
return cb(convertHashUnits(response));
} else {
// response is blank/null
return cb('-');
}
});
} else {
// get data via internal web api request
var uri = base_url + 'getnetworkhashps';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.') {
// return a blank value
return cb('-');
} else {
// return hash value with proper units
return cb(convertHashUnits(body));
}
});
}
} else {
// getnetworkhashps cmd not set
return cb('-');
}
} else {
// Invalid network hashrate setting value
return cb('-');
}
},
get_difficulty: function(cb) {
var cmd = prepareRpcCommand(settings.api_cmds.getdifficulty);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getdifficulty';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_connectioncount: function(cb) {
var cmd = prepareRpcCommand(settings.api_cmds.getconnectioncount);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getconnectioncount';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_masternodelist: function(cb) {
var cmd = prepareRpcCommand(settings.api_cmds.getmasternodelist);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getmasternodelist';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_masternodecount: function(cb) {
var cmd = prepareRpcCommand(settings.api_cmds.getmasternodecount);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getmasternodecount';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_blockcount: function(cb) {
var cmd = prepareRpcCommand(settings.api_cmds.getblockcount);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getblockcount';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_blockhash: function(height, cb) {
var cmd = prepareRpcCommand(settings.api_cmds.getblockhash, (height ? [parseInt(height)] : []));
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getblockhash?height=' + (height ? height : '');
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_block: function(hash, cb) {
var cmd = prepareRpcCommand(settings.api_cmds.getblock, (hash ? [hash] : []));
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getblock?hash=' + hash;
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_rawtransaction: function(hash, cb) {
var cmd = prepareRpcCommand(settings.api_cmds.getrawtransaction, (hash ? [hash, 1] : []));
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getrawtransaction?txid=' + hash + '&decrypt=1';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_maxmoney: function(cb) {
var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getmaxmoney);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getmaxmoney';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_maxvote: function(cb) {
var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getmaxvote);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getmaxvote';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_vote: function(cb) {
var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getvote);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getvote';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_phase: function(cb) {
var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getphase);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getphase';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_reward: function(cb) {
var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getreward);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getreward';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_estnext: function(cb) {
var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getnextrewardestimate);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getnextrewardestimate';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_nextin: function(cb) {
var cmd = prepareRpcCommand(settings.blockchain_specific.heavycoin.api_cmds.getnextrewardwhenstr);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getnextrewardwhenstr';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
// synchonous loop used to interate through an array,
// avoid use unless absolutely neccessary
syncLoop: function(iterations, process, exit){
var index = 0,
done = false,
shouldExit = false;
var loop = {
next:function(){
if(done){
if(shouldExit && exit){
exit(); // Exit if we're done
}
return; // Stop the loop if we're done
}
// If we're not finished
if(index < iterations){
index++; // Increment our index
if (index % 100 === 0) { //clear stack
setTimeout(function() {
process(loop); // Run our process, pass in the loop
}, 1);
} else {
process(loop); // Run our process, pass in the loop
}
// Otherwise we're done
} else {
done = true; // Make sure we say we're done
if(exit) exit(); // Call the callback on exit
}
},
iteration:function() {
return index - 1; // Return the loop number we're on
},
break:function(end) {
done = true; // End the loop
shouldExit = end; // Passing end as true means we still call the exit callback
}
};
loop.next();
return loop;
},
balance_supply: function(cb) {
Address.find({}, 'balance').where('balance').gt(0).exec(function(err, docs) {
var count = 0;
module.exports.syncLoop(docs.length, function (loop) {
var i = loop.iteration();
count = count + docs[i].balance;
loop.next();
}, function() {
return cb(count);
});
});
},
get_supply: function(cb) {
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.blockchain_specific.heavycoin.api_cmds.getsupply);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getsupply';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
} 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.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.')
return cb(null);
else
return cb(response.moneysupply);
});
} else {
var uri = base_url + 'getinfo';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (!body || !body.moneysupply ||body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body.moneysupply);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
} 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.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.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.')
return cb(null);
else
return cb(response.total_amount);
});
} else {
var uri = base_url + 'gettxoutsetinfo';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (!body || !body.total_amount ||body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body.total_amount);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
} else {
// returns coinbase total sent as current coin supply
coinbase_supply(function(supply) {
return cb(supply/100000000);
});
}
},
get_peerinfo: function(cb) {
var cmd = prepareRpcCommand(settings.api_cmds.getpeerinfo);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'getpeerinfo';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
verify_message: function(address, signature, message, cb) {
var cmd = prepareRpcCommand(settings.api_cmds.verifymessage, [address, signature, message]);
if (!(cmd.method == '' && cmd.parameters.length == 0)) {
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.')
return cb(null);
else
return cb(response);
});
} else {
var uri = base_url + 'verifymessage?address=' + address + '&signature=' + signature + '&message=' + message;
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
// check if an error msg was received from the web api server
if (body == 'There was an error. Check your console.')
return cb(null);
else
return cb(body);
});
}
} else {
// cmd not in use. return null.
return cb(null);
}
},
get_geo_location: function(address, cb) {
request({uri: 'https://freegeoip.app/json/' + address, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, geo) {
return cb(error, geo);
});
},
is_unique: function(array, object, cb) {
var unique = true;
var index = null;
module.exports.syncLoop(array.length, function (loop) {
var i = loop.iteration();
if (array[i].addresses == object) {
unique = false;
index = i;
loop.break(true);
loop.next();
} else {
loop.next();
}
}, function(){
return cb(unique, index);
});
},
calculate_total: function(vout, cb) {
var total = 0;
module.exports.syncLoop(vout.length, function (loop) {
var i = loop.iteration();
//module.exports.convert_to_satoshi(parseFloat(vout[i].amount), function(amount_sat){
total = total + vout[i].amount;
loop.next();
//});
}, function(){
return cb(total);
});
},
prepare_vout: function(vout, txid, vin, vhidden, cb) {
var arr_vout = [];
var arr_vin = [];
arr_vin = vin;
module.exports.syncLoop(vout.length, function (loop) {
var i = loop.iteration();
// 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();
}
} else {
// no address, move to next vout
loop.next();
}
}, 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[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
return cb(arr_vout, arr_vin);
} else
return cb(arr_vout, arr_vin);
} else
return cb(arr_vout, arr_vin);
});
},
get_input_addresses: function(input, vout, cb) {
var addresses = [];
if (input.coinbase) {
var amount = 0;
module.exports.syncLoop(vout.length, function (loop) {
var i = loop.iteration();
amount = amount + parseFloat(vout[i].value);
loop.next();
}, function(){
addresses.push({hash: 'coinbase', amount: amount});
return cb(addresses);
});
} else {
module.exports.get_rawtransaction(input.txid, function(tx){
if (tx) {
module.exports.syncLoop(tx.vout.length, function (loop) {
var i = loop.iteration();
if (tx.vout[i].n == input.vout) {
//module.exports.convert_to_satoshi(parseFloat(tx.vout[i].value), function(amount_sat){
if (tx.vout[i].scriptPubKey.addresses) {
addresses.push({hash: tx.vout[i].scriptPubKey.addresses[0], amount:tx.vout[i].value});
}
loop.break(true);
loop.next();
//});
} else {
loop.next();
}
}, function(){
return cb(addresses);
});
} else {
return cb();
}
});
}
},
prepare_vin: function(tx, cb) {
var arr_vin = [];
module.exports.syncLoop(tx.vin.length, function (loop) {
var i = loop.iteration();
module.exports.get_input_addresses(tx.vin[i], tx.vout, function(addresses){
if (addresses && addresses.length) {
//console.log('vin');
module.exports.is_unique(arr_vin, addresses[0].hash, function(unique, index) {
if (unique == true) {
module.exports.convert_to_satoshi(parseFloat(addresses[0].amount), function(amount_sat){
arr_vin.push({addresses:addresses[0].hash, amount:amount_sat});
loop.next();
});
} else {
module.exports.convert_to_satoshi(parseFloat(addresses[0].amount), function(amount_sat){
arr_vin[index].amount = arr_vin[index].amount + amount_sat;
loop.next();
});
}
});
} else {
loop.next();
}
});
}, function(){
return cb(arr_vin);
});
}
};