diff --git a/README.md b/README.md
index 46bba08de..eb55d3992 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,16 @@
-# Bitcoin Royale RPC Explorer
+# Bitcoin Vault RPC Explorer
-This is a fork of [BTC RPC Explorer](https://github.com/janoside/btc-rpc-explorer) with minor modifications to adapt it to Bitcoin Royale.
+This is a fork of [BTC RPC Explorer](https://github.com/janoside/btc-rpc-explorer) with minor modifications to adapt it to Bitcoin Vault.
---
-Simple, database-free Bitcoin Royale blockchain explorer, via RPC. Built with Node.js, express, bootstrap-v4.
+Simple, database-free Bitcoin Vault blockchain explorer, via RPC. Built with Node.js, express, bootstrap-v4.
-This tool is intended to be a simple, self-hosted explorer for the Bitcoin Royale blockchain, driven by RPC calls to your own broyaled node. This tool is easy to run but currently lacks features compared to database-backed explorers.
+This tool is intended to be a simple, self-hosted explorer for the Bitcoin Vault blockchain, driven by RPC calls to your own bvaultd node. This tool is easy to run but currently lacks features compared to database-backed explorers.
Whatever reasons one might have for running a full node (trustlessness, technical curiosity, supporting the network, etc) it's helpful to appreciate the "fullness" of your node. With this explorer, you can not only explore the blockchain (in the traditional sense of the term "explorer"), but also explore the functional capabilities of your own node.
-Live demo available at: [http://explorer.bitcoinroyale.org](http://explorer.bitcoinroyale.org)
+Live demo available at: [http://explorer.bitcoinvault.global](http://explorer.bitcoinvault.global)
# Features
@@ -25,19 +25,19 @@ Live demo available at: [http://explorer.bitcoinroyale.org](http://explorer.bitc
# Getting started
-The below instructions are geared toward BTCR, but can be adapted easily to other coins.
+The below instructions are geared toward BTCV, but can be adapted easily to other coins.
## Prerequisites
-1. Install and run a full, archiving [node](https://github.com/bitcoinroyale/bitcoinroyale/blob/master/INSTALL.md). Ensure that your bitcoin node has full transaction indexing enabled (`txindex=1`) and the RPC server enabled (`server=1`).
-2. Synchronize your node with the Bitcoin Royale network.
+1. Install and run a full, archiving [node](https://github.com/bitcoinvault/bitcoinvault/blob/master/INSTALL.md). Ensure that your bitcoin node has full transaction indexing enabled (`txindex=1`) and the RPC server enabled (`server=1`).
+2. Synchronize your node with the Bitcoin Vault network.
3. "Recent" version of Node.js (8+ recommended).
## Instructions
```bash
apt-get install node npm
-git clone https://github.com/bitcoinroyale/explorer
+git clone https://github.com/bitcoinvault/explorer
cd explorer
npm install
./bin/cli.js
@@ -52,7 +52,7 @@ See [configuration](#configuration) for details.
### Configuration
Configuration options may be passed as environment variables
-or by creating an env file at `~/.config/btcr-rpc-explorer.env`
+or by creating an env file at `~/.config/btcv-rpc-explorer.env`
or at `.env` in the working directory.
See [.env-sample](.env-sample) for a list of the options and details for formatting `.env`.
@@ -69,15 +69,15 @@ BTCEXP_UI_SHOW_TOOLS_SUBHEADER=false
You may also pass options as CLI arguments, for example:
```bash
-./bin/cli.js --port 8080 --bitcoind-port 18443 --bitcoind-cookie ~/.broyale/regtest/.cookie
+./bin/cli.js --port 8080 --bitcoind-port 18443 --bitcoind-cookie ~/.bvault/regtest/.cookie
```
See `./bin/cli.js --help` for the full list of CLI options.
## Run via Docker
-1. `docker build -t btcr-rpc-explorer .`
-2. `docker run -p 3002:3002 -it btcr-rpc-explorer`
+1. `docker build -t btcv-rpc-explorer .`
+2. `docker run -p 3002:3002 -it btcv-rpc-explorer`
# Support
diff --git a/app.js b/app.js
index 81f2f8c4a..edb8c7d16 100755
--- a/app.js
+++ b/app.js
@@ -7,7 +7,7 @@ var path = require('path');
var dotenv = require("dotenv");
var fs = require('fs');
-var configPaths = [ path.join(os.homedir(), '.config', 'btcr-rpc-explorer.env'), path.join(process.cwd(), '.env') ];
+var configPaths = [ path.join(os.homedir(), '.config', 'btcv-rpc-explorer.env'), path.join(process.cwd(), '.env') ];
configPaths.filter(fs.existsSync).forEach(path => {
console.log('Loading env file:', path);
dotenv.config({ path });
@@ -69,8 +69,8 @@ if (process.env.BTCEXP_BASIC_AUTH_PASSWORD) {
}
// uncomment after placing your favicon in /public
-//app.use(favicon(__dirname + '/public/favicon.ico'));
-//app.use(logger('dev'));
+app.use(favicon(__dirname + '/public/favicon.png'));
+app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
@@ -118,7 +118,7 @@ function loadMiningPoolConfigs() {
function getSourcecodeProjectMetadata() {
var options = {
- url: "https://api.github.com/repos/bitcoinroyale/explorer",
+ url: "https://api.github.com/repos/bitcoinvault/explorer",
headers: {
'User-Agent': 'request'
}
@@ -241,12 +241,32 @@ app.runOnStartup = function() {
setInterval(getSourcecodeProjectMetadata, 3600000);
}
- if (global.exchangeRates == null) {
+ if (!global.exchangeRates) {
utils.refreshExchangeRates();
}
+ if (!global.totalCoinSupply) {
+ utils.refreshCoinSupply();
+ }
+
+ if (!global.totalWalletsNumber) {
+ utils.refreshWalletsNumber();
+ }
+
+ if (!global.txAvgVolume24h) {
+ utils.refreshTxVolume();
+ }
+
+ if (!global.miningPools) {
+ utils.refreshMiningPoolsData();
+ }
+
// refresh exchange rate periodically
setInterval(utils.refreshExchangeRates, 1800000);
+ setInterval(utils.refreshCoinSupply, 60000);
+ setInterval(utils.refreshWalletsNumber, 60000);
+ setInterval(utils.refreshTxVolume, 60000);
+ setInterval(utils.refreshMiningPoolsData, 60000);
utils.logMemoryUsage();
setInterval(utils.logMemoryUsage, 5000);
diff --git a/app/api/electrumAddressApi.js b/app/api/electrumAddressApi.js
index cb72ced00..c722768c0 100644
--- a/app/api/electrumAddressApi.js
+++ b/app/api/electrumAddressApi.js
@@ -41,7 +41,7 @@ function connectToServer(host, port, protocol) {
var defaultProtocol = port === 50001 ? 'tcp' : 'tls';
var electrumClient = new ElectrumClient(port, host, protocol || defaultProtocol);
- electrumClient.initElectrum({client:"btcr-rpc-explorer-v1.1", version:"1.4"}).then(function(res) {
+ electrumClient.initElectrum({client:"btcv-rpc-explorer-v1.1", version:"1.4"}).then(function(res) {
debugLog("Connected to ElectrumX Server: " + host + ":" + port + ", versions: " + JSON.stringify(res));
electrumClients.push(electrumClient);
diff --git a/app/coins.js b/app/coins.js
index 302d04d60..27d42eeeb 100644
--- a/app/coins.js
+++ b/app/coins.js
@@ -2,9 +2,9 @@ var btc = require("./coins/btc.js");
var ltc = require("./coins/ltc.js");
module.exports = {
- "BTCR": btc,
+ "BTCV": btc,
"BTC": btc,
"LTC": ltc,
- "coins":["BTCR", "BTC", "LTC"]
+ "coins":["BTCV", "BTC", "LTC"]
};
\ No newline at end of file
diff --git a/app/coins/btc.js b/app/coins/btc.js
index d2cb1c496..d98be354e 100644
--- a/app/coins/btc.js
+++ b/app/coins/btc.js
@@ -4,17 +4,17 @@ Decimal8 = Decimal.clone({ precision:8, rounding:8 });
var currencyUnits = [
{
type:"native",
- name:"BTCR",
+ name:"BTCV",
multiplier:1,
default:true,
- values:["", "btcr", "BTCR"],
+ values:["", "btcv", "BTCV"],
decimalPlaces:8
},
{
type:"native",
- name:"mBTCR",
+ name:"mBTCV",
multiplier:1000,
- values:["mbtcr"],
+ values:["mbtcv"],
decimalPlaces:5
},
{
@@ -50,14 +50,14 @@ var currencyUnits = [
];
module.exports = {
- name:"Bitcoin Royale",
- ticker:"BTCR",
+ name:"Bitcoin Vault",
+ ticker:"BTCV",
logoUrl:"/img/logo/btc.svg",
- siteTitle:"Bitcoin Royale Explorer",
- siteDescriptionHtml:"BTCR Explorer is BIP30) allowed identical coinbase transactions - a newer duplicate would overwrite older copies. This transaction was the coinbase transaction for Block #91,812 and, ~3 hours later, Block #91,842. The 50 BTC claimed as the coinbase for block 91,812 were also overwritten and lost."
}
],
- exchangeRateData:{
- jsonUrl:"https://api.coindesk.com/v1/bpi/currentprice.json",
+ exchangeRateDataUSD:{
+ jsonUrl:"https://api.liquid.com/products/618",
responseBodySelectorFunction:function(responseBody) {
//console.log("Exchange Rate Response: " + JSON.stringify(responseBody));
-
- var exchangedCurrencies = ["USD", "GBP", "EUR"];
-
- if (responseBody.bpi) {
- var exchangeRates = {};
-
- for (var i = 0; i < exchangedCurrencies.length; i++) {
- if (responseBody.bpi[exchangedCurrencies[i]]) {
- exchangeRates[exchangedCurrencies[i].toLowerCase()] = responseBody.bpi[exchangedCurrencies[i]].rate_float;
- }
- }
-
- return exchangeRates;
+ if (responseBody.last_traded_price) {
+ return responseBody.last_traded_price;
+ }
+ return null;
+ }
+ },
+ exchangeRateDataBTC:{
+ jsonUrl:"https://api.liquid.com/products/619",
+ responseBodySelectorFunction:function(responseBody) {
+ //console.log("Exchange Rate Response: " + JSON.stringify(responseBody));
+ if (responseBody.last_traded_price) {
+ return responseBody.last_traded_price;
}
-
return null;
}
},
diff --git a/app/config.js b/app/config.js
index ab9d71bfa..e9bfacac0 100644
--- a/app/config.js
+++ b/app/config.js
@@ -5,7 +5,7 @@ var url = require('url');
var coins = require("./coins.js");
var credentials = require("./credentials.js");
-var currentCoin = process.env.BTCEXP_COIN || "BTC"; // BTC is the same as BTCR
+var currentCoin = process.env.BTCEXP_COIN || "BTC"; // BTC is the same as BTCV
var rpcCred = credentials.rpc;
@@ -156,8 +156,13 @@ module.exports = {
{name:"Mempool Summary", url:"/mempool-summary", desc:"Detailed summary of the current mempool for this node.", fontawesome:"fas fa-clipboard-list"},
{name:"Unconfirmed Transactions", url:"/unconfirmed-tx", desc:"Browse unconfirmed/pending transactions.", fontawesome:"fas fa-unlock-alt"},
+<<<<<<< HEAD
{name:"RPC Browser", url:"/rpc-browser", desc:"Browse the RPC functionality of this node. See docs and execute commands.", fontawesome:"fas fa-book"},
+ {name:"Hashrate distribution", url:"/mining-pools", desc:"Estimated hashrate of mining pools.", fontawesome:"fas fa-chart-pie"}
+=======
+ {name:"Pool share chart", url:"/pool-share", desc:"The hashpower of top mining pools.", fontawesome:"fas fa-book"},
{name:"RPC Terminal", url:"/rpc-terminal", desc:"Directly execute RPCs against this node.", fontawesome:"fas fa-terminal"}
+>>>>>>> dev
],
donations:{
diff --git a/app/helpers/colorGenerator.js b/app/helpers/colorGenerator.js
new file mode 100644
index 000000000..58fb552a4
--- /dev/null
+++ b/app/helpers/colorGenerator.js
@@ -0,0 +1,35 @@
+function calculatePoint(i, intervalSize, colorRangeInfo) {
+ var {
+ colorStart,
+ colorEnd,
+ useEndAsStart
+ } = colorRangeInfo;
+ return (useEndAsStart ?
+ (colorEnd - (i * intervalSize)) :
+ (colorStart + (i * intervalSize)));
+};
+
+ /**
+ * @description Must use an interpolated color scale, which has a range of [0, 1]
+ */
+function generateColors(dataLength, colorScale, colorRangeInfo) {
+ var {
+ colorStart,
+ colorEnd
+ } = colorRangeInfo;
+ var colorRange = colorEnd - colorStart;
+ var intervalSize = colorRange / dataLength;
+ var i, colorPoint;
+ var colorArray = [];
+
+ for (i = 0; i < dataLength; i++) {
+ colorPoint = calculatePoint(i, intervalSize, colorRangeInfo);
+ colorArray.push(colorScale(colorPoint));
+ }
+
+ return colorArray;
+};
+
+module.exports = {
+ generateColors
+};
diff --git a/app/utils.js b/app/utils.js
index 0efaab9e1..63c4f84f4 100644
--- a/app/utils.js
+++ b/app/utils.js
@@ -202,9 +202,14 @@ function formatExchangedCurrency(amount, exchangeType) {
if (global.exchangeRates != null && global.exchangeRates[exchangeType.toLowerCase()] != null) {
var dec = new Decimal(amount);
dec = dec.times(global.exchangeRates[exchangeType.toLowerCase()]);
- var exchangedAmt = parseFloat(Math.round(dec * 100) / 100).toFixed(2);
-
- return "$" + addThousandsSeparators(exchangedAmt);
+ if (exchangeType.toLowerCase() === 'usd') {
+ var exchangedAmt = parseFloat(Math.round(dec * 100) / 100).toFixed(2);
+ return "$" + addThousandsSeparators(exchangedAmt);
+ }
+ if (exchangeType.toLowerCase() === 'btc') {
+ var exchangedAmt = parseFloat(dec).toFixed(4);
+ return exchangedAmt + " BTC";
+ }
}
return "";
@@ -277,6 +282,26 @@ function getMinerFromCoinbaseTx(tx) {
return null;
}
+function getNameFromAddress(address) {
+ if (global.miningPoolsConfigs) {
+ for (var i = 0; i < global.miningPoolsConfigs.length; i++) {
+ var miningPoolsConfig = global.miningPoolsConfigs[i];
+ for (var payoutAddress in miningPoolsConfig.payout_addresses) {
+ if (miningPoolsConfig.payout_addresses.hasOwnProperty(payoutAddress)) {
+ if (payoutAddress === address) {
+ var findedAddress = miningPoolsConfig.payout_addresses[payoutAddress];
+ if (findedAddress && findedAddress.name) {
+ return findedAddress.name;
+ }
+ }
+ }
+ }
+ }
+ }
+ return null;
+}
+
+
function getTxTotalInputOutputValues(tx, txInputs, blockHeight) {
var totalInputValue = new Decimal(0);
var totalOutputValue = new Decimal(0);
@@ -335,14 +360,35 @@ function refreshExchangeRates() {
return;
}
- if (coins[config.coin].exchangeRateData) {
- request(coins[config.coin].exchangeRateData.jsonUrl, function(error, response, body) {
+ if (coins[config.coin].exchangeRateDataUSD) {
+ request(coins[config.coin].exchangeRateDataUSD.jsonUrl, function(error, response, body) {
if (error == null && response && response.statusCode && response.statusCode == 200) {
var responseBody = JSON.parse(body);
+ var exchangeRate = coins[config.coin].exchangeRateDataUSD.responseBodySelectorFunction(responseBody);
+ if (exchangeRate != null) {
+ if (global.exchangeRates === undefined) global.exchangeRates = {};
+ global.exchangeRates["usd"] = exchangeRate;
+ global.exchangeRatesUpdateTime = new Date();
+
+ debugLog("Using exchange rates: " + JSON.stringify(global.exchangeRates) + " starting at " + global.exchangeRatesUpdateTime);
+
+ } else {
+ debugLog("Unable to get exchange rate data");
+ }
+ } else {
+ logError("39r7h2390fgewfgds", {error:error, response:response, body:body});
+ }
+ });
+ }
- var exchangeRates = coins[config.coin].exchangeRateData.responseBodySelectorFunction(responseBody);
- if (exchangeRates != null) {
- global.exchangeRates = exchangeRates;
+ if (coins[config.coin].exchangeRateDataBTC) {
+ request(coins[config.coin].exchangeRateDataBTC.jsonUrl, function(error, response, body) {
+ if (error == null && response && response.statusCode && response.statusCode == 200) {
+ var responseBody = JSON.parse(body);
+ var exchangeRate = coins[config.coin].exchangeRateDataBTC.responseBodySelectorFunction(responseBody);
+ if (exchangeRate != null) {
+ if (global.exchangeRates === undefined) global.exchangeRates = {};
+ global.exchangeRates['btc'] = exchangeRate;
global.exchangeRatesUpdateTime = new Date();
debugLog("Using exchange rates: " + JSON.stringify(global.exchangeRates) + " starting at " + global.exchangeRatesUpdateTime);
@@ -357,6 +403,77 @@ function refreshExchangeRates() {
}
}
+function refreshCoinSupply() {
+ request("http://api.bitcoinvault.global/status", function(error, response, body) {
+ if (error == null && response && response.statusCode && response.statusCode == 200) {
+ var responseBody = JSON.parse(body);
+ var coinsupply = null;
+ if (responseBody.total_coin_supply) {
+ coinsupply = responseBody.total_coin_supply;
+ }
+ if (responseBody.total_coin_supply) {
+ global.totalCoinSupply = responseBody.total_coin_supply;
+ global.totalCoinSupplyUpdateTime = new Date();
+
+ debugLog("Got total coin supply: " + global.totalCoinSupply);
+
+ } else {
+ debugLog("Unable to get total coin supply");
+ }
+ } else {
+ logError("39r7h2390fgewfgds", {error:error, response:response, body:body});
+ }
+ });
+}
+
+function refreshWalletsNumber() {
+ request("http://api.bitcoinvault.global/nonemptywalletsnumber", function(error, response, body) {
+ if (error == null && response && response.statusCode && response.statusCode == 200) {
+ var responseBody = JSON.parse(body);
+ if (responseBody) {
+ global.totalWalletsNumber = responseBody;
+ global.totalWalletsNumberUpdateTime = new Date();
+
+ debugLog("Got total wallets number: " + global.totalWalletsNumber);
+
+ } else {
+ debugLog("Unable to get total wallets number");
+ }
+ } else {
+ logError("35tsdgdfu4567ehbn", {error:error, response:response, body:body});
+ }
+ });
+}
+
+function refreshTxVolume() {
+ request("http://api.bitcoinvault.global/transactionvolume?period=month", function(error, response, body) {
+ if (error == null && response && response.statusCode && response.statusCode == 200) {
+ var responseBody = JSON.parse(body);
+ if (responseBody[responseBody.length - 1].avg) {
+ global.txAvgVolume24h = responseBody[responseBody.length - 1].avg;
+ global.txAvgVolume24hUpdateTime = new Date();
+ debugLog("Got 24h avg tx volume: " + global.txAvgVolume24h);
+ } else {
+ debugLog("Unable to get 24h avg tx volume.");
+ }
+ } else {
+ logError("35tsdgdfu4567ehbn", {error:error, response:response, body:body});
+ }
+ });
+}
+
+function refreshMiningPoolsData() {
+ request("http://api.bitcoinvault.global/piechartdata", function(error, response, body) {
+ if (error == null && response && response.statusCode && response.statusCode == 200) {
+ var responseBody = JSON.parse(body);
+ global.miningPools = responseBody;
+ debugLog("Got mining pools data: " + global.miningPools);
+ } else {
+ logError("39r7h2390fgewfgds", {error:error, response:response, body:body});
+ }
+ });
+}
+
// Uses ipstack.com API
function geoLocateIpAddresses(ipAddresses, provider) {
return new Promise(function(resolve, reject) {
@@ -574,6 +691,9 @@ module.exports = {
getMinerFromCoinbaseTx: getMinerFromCoinbaseTx,
getBlockTotalFeesFromCoinbaseTxAndBlockHeight: getBlockTotalFeesFromCoinbaseTxAndBlockHeight,
refreshExchangeRates: refreshExchangeRates,
+ refreshCoinSupply: refreshCoinSupply,
+ refreshWalletsNumber: refreshWalletsNumber,
+ refreshTxVolume: refreshTxVolume,
parseExponentStringDouble: parseExponentStringDouble,
formatLargeNumber: formatLargeNumber,
geoLocateIpAddresses: geoLocateIpAddresses,
@@ -583,5 +703,7 @@ module.exports = {
colorHexToHsl: colorHexToHsl,
logError: logError,
buildQrCodeUrls: buildQrCodeUrls,
- ellipsize: ellipsize
+ ellipsize: ellipsize,
+ refreshMiningPoolsData,
+ getNameFromAddress
};
diff --git a/bin/cli.js b/bin/cli.js
index 55bb7e8a7..e17b57dcd 100755
--- a/bin/cli.js
+++ b/bin/cli.js
@@ -2,20 +2,20 @@
const args = require('meow')(`
Usage
- $ btcr-rpc-explorer [options]
+ $ btcv-rpc-explorer [options]
Options
-p, --port port to bind http server [default: 3002]
-i, --host host to bind http server [default: 127.0.0.1]
-a, --basic-auth-password <..> protect web interface with a password [default: no password]
- -C, --coin crypto-coin to enable [default: BTCR]
+ -C, --coin crypto-coin to enable [default: BTCV]
- -b, --bitcoind-uri connection URI for broyaled rpc (overrides the options below)
- -H, --bitcoind-host hostname for broyaled rpc [default: 127.0.0.1]
- -P, --bitcoind-port port for broyaled rpc [default: 8332]
- -c, --bitcoind-cookie path to broyaled cookie file [default: ~/.bitcoin/.cookie]
- -u, --bitcoind-user username for broyaled rpc [default: none]
- -w, --bitcoind-pass password for broyaled rpc [default: none]
+ -b, --bitcoind-uri connection URI for bvaultd rpc (overrides the options below)
+ -H, --bitcoind-host hostname for bvaultd rpc [default: 127.0.0.1]
+ -P, --bitcoind-port port for bvaultd rpc [default: 8332]
+ -c, --bitcoind-cookie path to bvaultd cookie file [default: ~/.bitcoin/.cookie]
+ -u, --bitcoind-user username for bvaultd rpc [default: none]
+ -w, --bitcoind-pass password for bvaultd rpc [default: none]
--address-api