Files
purple-explorer/lib/explorer.js
T
2020-11-22 16:06:53 -07:00

654 lines
22 KiB
JavaScript

var request = require('postman-request')
, settings = require('./settings')
, Address = require('../models/address');
var base_server = 'http://127.0.0.1:' + settings.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();
}
});
}
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) {
if (settings.index.show_hashrate == false) return cb('-');
if (settings.use_rpc) {
if (settings.nethash == 'netmhashps') {
client.cmd([{method:'getmininginfo', params: []}], function(err, response) {
if (err)
return cb('There was an error. Check your console.');
else {
if (response.netmhashps) {
if (settings.nethash_units == 'K') {
return cb((response.netmhashps * 1000).toFixed(4));
} else if (settings.nethash_units == 'G') {
return cb((response.netmhashps / 1000).toFixed(4));
} else if (settings.nethash_units == 'H') {
return cb((response.netmhashps * 1000000).toFixed(4));
} else if (settings.nethash_units == 'T') {
return cb((response.netmhashps / 1000000).toFixed(4));
} else if (settings.nethash_units == 'P') {
return cb((response.netmhashps / 1000000000).toFixed(4));
} else {
return cb(response.netmhashps.toFixed(4));
}
} else {
return cb('-');
}
}
});
} else {
client.cmd([{method:'getnetworkhashps', params: []}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else {
if (response) {
if (settings.nethash_units == 'K') {
return cb((response * 1000).toFixed(4));
} else if (settings.nethash_units == 'G') {
return cb((response / 1000).toFixed(4));
} else if (settings.nethash_units == 'H') {
return cb((response * 1000000).toFixed(4));
} else if (settings.nethash_units == 'T') {
return cb((response / 1000000).toFixed(4));
} else if (settings.nethash_units == 'P') {
return cb((response / 1000000000).toFixed(4));
} else {
return cb(response.toFixed(4));
}
} else {
return cb('-');
}
}
});
}
}else{
if (settings.nethash == 'netmhashps') {
var uri = base_url + 'getmininginfo';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) { //returned in mhash
if (body.netmhashps) {
if (settings.nethash_units == 'K') {
return cb((body.netmhashps * 1000).toFixed(4));
} else if (settings.nethash_units == 'G') {
return cb((body.netmhashps / 1000).toFixed(4));
} else if (settings.nethash_units == 'H') {
return cb((body.netmhashps * 1000000).toFixed(4));
} else if (settings.nethash_units == 'T') {
return cb((body.netmhashps / 1000000).toFixed(4));
} else if (settings.nethash_units == 'P') {
return cb((body.netmhashps / 1000000000).toFixed(4));
} else {
return cb(body.netmhashps.toFixed(4));
}
} else {
return cb('-');
}
});
} else {
var uri = base_url + 'getnetworkhashps';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
if (body == 'There was an error. Check your console.') {
return cb('-');
} else {
if (settings.nethash_units == 'K') {
return cb((body / 1000).toFixed(4));
} else if (settings.nethash_units == 'M'){
return cb((body / 1000000).toFixed(4));
} else if (settings.nethash_units == 'G') {
return cb((body / 1000000000).toFixed(4));
} else if (settings.nethash_units == 'T') {
return cb((body / 1000000000000).toFixed(4));
} else if (settings.nethash_units == 'P') {
return cb((body / 1000000000000000).toFixed(4));
} else {
return cb((body).toFixed(4));
}
}
});
}
}
},
get_difficulty: function(cb) {
if (settings.use_rpc) {
client.cmd([{method:'getdifficulty', params: [parseInt(height)]}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else {
var uri = base_url + 'getdifficulty';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body);
});
}
},
get_connectioncount: function(cb) {
if (settings.use_rpc) {
client.cmd([{method:'getconnectioncount', params: []}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else {
var uri = base_url + 'getconnectioncount';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body);
});
}
},
get_masternodecount: function(cb) {
if (settings.api_cmds.masternode_count != '') {
if (settings.use_rpc) {
// split cmd by spaces
var split = settings.api_cmds.masternode_count.split(' ');
var method_name = '';
var params = [];
for (i=0; i<split.length; i++) {
if (i==0)
method_name = split[i];
else
params.push(split[i]);
}
client.cmd([{method:method_name, params: params}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else {
var uri = base_url + 'getmasternodecount';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body);
});
}
} else
return cb({"total":0,"enabled":0});
},
get_blockcount: function(cb) {
if (settings.use_rpc) {
client.cmd([{method:'getblockcount', params: []}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else {
var uri = base_url + 'getblockcount';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body);
});
}
},
get_blockhash: function(height, cb) {
if (settings.use_rpc) {
var uri = base_url + 'getblockhash?height=' + height;
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body);
});
} else {
client.cmd([{method:'getblockhash', params: [parseInt(height)]}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
}
},
get_block: function(hash, cb) {
if (settings.use_rpc) {
client.cmd([{method:'getblock', params: [hash]}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
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) {
return cb(body);
});
}
},
get_rawtransaction: function(hash, cb) {
if (settings.use_rpc) {
client.cmd([{method:'getrawtransaction', params: [hash, 1]}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
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) {
return cb(body);
});
}
},
get_maxmoney: function(cb) {
if (settings.use_rpc) {
client.cmd([{method:'getmaxmoney', params: []}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else {
var uri = base_url + 'getmaxmoney';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body);
});
}
},
get_maxvote: function(cb) {
if (settings.use_rpc) {
client.cmd([{method:'getmaxvote', params: []}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else {
var uri = base_url + 'getmaxvote';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body);
});
}
},
get_vote: function(cb) {
if (settings.use_rpc) {
client.cmd([{method:'getvote', params: []}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else {
var uri = base_url + 'getvote';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body);
});
}
},
get_phase: function(cb) {
if (settings.use_rpc) {
client.cmd([{method:'getphase', params: []}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else {
var uri = base_url + 'getphase';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body);
});
}
},
get_reward: function(cb) {
if (settings.use_rpc) {
client.cmd([{method:'getreward', params: []}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else {
var uri = base_url + 'getreward';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body);
});
}
},
get_estnext: function(cb) {
if (settings.use_rpc) {
client.cmd([{method:'getnextrewardestimate', params: []}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else {
var uri = base_url + 'getnextrewardestimate';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body);
});
}
},
get_nextin: function(cb) {
if (settings.use_rpc) {
client.cmd([{method:'getnextrewardwhenstr', params: []}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else {
var uri = base_url + 'getnextrewardwhenstr';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body);
});
}
},
// 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.use_rpc) {
if ( settings.supply == 'HEAVY' ) {
client.cmd([{method:'getsupply', params: []}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else if (settings.supply == 'GETINFO') {
client.cmd([{method:'getinfo', params: []}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else if (settings.supply == 'BALANCES') {
module.exports.balance_supply(function(supply) {
return cb(supply/100000000);
});
} else if (settings.supply == 'TXOUTSET') {
client.cmd([{method:'gettxoutsetinfo', params: []}], function(err, response){
if (err)
return cb('There was an error. Check your console.');
else
return cb(response);
});
} else {
coinbase_supply(function(supply) {
return cb(supply/100000000);
});
}
} else {
if ( settings.supply == 'HEAVY' ) {
var uri = base_url + 'getsupply';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body);
});
} else if (settings.supply == 'GETINFO') {
var uri = base_url + 'getinfo';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body.moneysupply);
});
} else if (settings.supply == 'BALANCES') {
module.exports.balance_supply(function(supply) {
return cb(supply/100000000);
});
} else if (settings.supply == 'TXOUTSET') {
var uri = base_url + 'gettxoutsetinfo';
request({uri: uri, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) {
return cb(body.total_amount);
});
} else {
coinbase_supply(function(supply) {
return cb(supply/100000000);
});
}
}
},
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 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);
});
}
};