Massive commit for majority of v3.0:
- major visual refresh - new design, layout, fonts, colors, icons, etc
- new dark theme, now the default
- new app icon ("Bitcoin Map Marker")
- cleaner, simpler homepage content
- css for light/dark themes built from scss ("npm run css")
- theme-switcher button in footer, instead of checked items in header dropdown
- cleanup header links and dropdowns, and larger search box
- url change: /unconfirmed-tx -> /mempool-tx
- support for "estimated coin supply" used at startup or on slow devices when UTXO set unavailable
- display fee rate along with TX details on /mempool-tx
- copy-to-clipboard added for lots of longer strings
- major code reuse improvements with pug mixins
- simplify userSettings
- minor error handling improvements for /tx pages in prune/noTxIndex situations
- query fewer tx inputs on /address pages for performance
- exponents on /difficulty-history graph labels
- fixed colors of labels/gridlines on graphs (esp in dark theme)
- drop LTC config (no longer maintained)
- /admin/resetUserSettings
31
.env-sample
|
|
@ -5,20 +5,24 @@
|
|||
#DEBUG=btcexp:* # Enable all logging specific to btc-rpc-explorer
|
||||
#DEBUG=btcexp:app,btcexp:error # Default
|
||||
|
||||
|
||||
# The base URL. If you want to run it elsewhere than on /, for example /btc-rpc-explorer/ - note that the value should include starting and ending "/"
|
||||
# Default: /
|
||||
#BTCEXP_BASEURL=/
|
||||
#BTCEXP_BASEURL=/explorer/
|
||||
|
||||
|
||||
# The active coin. Only officially supported value is "BTC".
|
||||
# Default: BTC
|
||||
#BTCEXP_COIN=BTC
|
||||
|
||||
|
||||
# Host/Port to bind to
|
||||
# Defaults: shown
|
||||
#BTCEXP_HOST=127.0.0.1
|
||||
#BTCEXP_PORT=3002
|
||||
|
||||
|
||||
# Bitcoin RPC Credentials (URI -OR- HOST/PORT/USER/PASS)
|
||||
# Defaults:
|
||||
# - [host/port]: 127.0.0.1:8332
|
||||
|
|
@ -33,6 +37,7 @@
|
|||
#BTCEXP_BITCOIND_COOKIE=/path/to/bitcoind/.cookie
|
||||
#BTCEXP_BITCOIND_RPC_TIMEOUT=5000
|
||||
|
||||
|
||||
# Select optional "address API" to display address tx lists and balances
|
||||
# Options: electrumx, blockchain.com, blockchair.com, blockcypher.com
|
||||
# If electrumx set, the BTCEXP_ELECTRUMX_SERVERS variable must also be
|
||||
|
|
@ -40,91 +45,117 @@
|
|||
# Default: none
|
||||
#BTCEXP_ADDRESS_API=(electrumx|blockchain.com|blockchair.com|blockcypher.com)
|
||||
|
||||
|
||||
# Optional ElectrumX Servers. See BTCEXP_ADDRESS_API. This value is only
|
||||
# used if BTCEXP_ADDRESS_API=electrumx
|
||||
#BTCEXP_ELECTRUMX_SERVERS=tls://electrumx.server.com:50002,tcp://127.0.0.1:50001,...
|
||||
|
||||
|
||||
# Use the Electrumx server as an external txindex. This is only available in Electrs.
|
||||
#BTCEXP_ELECTRUM_TXINDEX=true
|
||||
|
||||
|
||||
# Set number of concurrent RPC requests. Should be lower than your node's "rpcworkqueue" value.
|
||||
# Note that Bitcoin Core's default rpcworkqueue=16.
|
||||
# Default: 10
|
||||
#BTCEXP_RPC_CONCURRENCY=10
|
||||
|
||||
|
||||
# Disable app's in-memory RPC caching to reduce memory usage
|
||||
# Default: false (i.e. in-memory cache **enabled**)
|
||||
#BTCEXP_NO_INMEMORY_RPC_CACHE=true
|
||||
|
||||
|
||||
# Optional redis server for RPC caching
|
||||
# Default: none
|
||||
#BTCEXP_REDIS_URL=redis://localhost:6379
|
||||
|
||||
|
||||
# Default: hash of credentials
|
||||
#BTCEXP_COOKIE_SECRET=0000aaaafffffgggggg
|
||||
|
||||
|
||||
# Whether public-demo aspects of the site are active
|
||||
# Default: false
|
||||
#BTCEXP_DEMO=true
|
||||
|
||||
|
||||
# Set to false to enable resource-intensive features, including:
|
||||
# UTXO set summary querying
|
||||
# (default value is true, i.e. resource-intensive features are disabled)
|
||||
#BTCEXP_SLOW_DEVICE_MODE=false
|
||||
|
||||
|
||||
# Privacy mode disables:
|
||||
# Exchange-rate queries, IP-geolocation queries
|
||||
# Default: false
|
||||
#BTCEXP_PRIVACY_MODE=true
|
||||
|
||||
|
||||
# Don't request currency exchange rates
|
||||
# Default: true (i.e. no exchange-rate queries made)
|
||||
#BTCEXP_NO_RATES=true
|
||||
|
||||
|
||||
# Password protection for site via basic auth (enter any username, only the password is checked)
|
||||
# Default: none
|
||||
#BTCEXP_BASIC_AUTH_PASSWORD=mypassword
|
||||
|
||||
|
||||
# File where the SSO token is stored; ignored if BTCEXP_BASIC_AUTH_PASSWORD is provided.
|
||||
# Enables SSO if present.
|
||||
# Default: none
|
||||
#BTCEXP_SSO_TOKEN_FILE=/var/run/btc-rpc-explorer/sso_token
|
||||
|
||||
|
||||
# URL of an optional external SSO provider
|
||||
# This is ignored if SSO is not enabled (see BTCEXP_SSO_TOKEN_FILE)
|
||||
# Default: none
|
||||
#BTCEXP_SSO_LOGIN_REDIRECT_URL=/my-sso-provider/login
|
||||
|
||||
|
||||
# Enable to allow access to all RPC methods
|
||||
# Default: false
|
||||
#BTCEXP_RPC_ALLOWALL=true
|
||||
|
||||
|
||||
# Custom RPC method blacklist
|
||||
# Default: (see config.js)
|
||||
#BTCEXP_RPC_BLACKLIST=signrawtransaction,sendtoaddress,stop,...
|
||||
|
||||
|
||||
# Optional API keys
|
||||
# Default: none
|
||||
#BTCEXP_GANALYTICS_TRACKING=UA-XXXX-X
|
||||
#BTCEXP_SENTRY_URL=https://00000fffffff@sentry.io/XXXX
|
||||
#BTCEXP_IPSTACK_APIKEY=000000fffffaaaaa
|
||||
|
||||
|
||||
# Optional value for "max_old_space_size"
|
||||
# Default: 1024
|
||||
#BTCEXP_OLD_SPACE_MAX_SIZE=2048
|
||||
|
||||
|
||||
# The number of recent blocks to search for transactions when txindex is disabled
|
||||
#BTCEXP_NOTXINDEX_SEARCH_DEPTH=3
|
||||
|
||||
|
||||
# UI Theme
|
||||
# Default: dark
|
||||
#BTCEXP_UI_THEME=(dark|light)
|
||||
|
||||
|
||||
# Show tools list in a sub-nav at top of screen
|
||||
# Default: true
|
||||
#BTCEXP_UI_SHOW_TOOLS_SUBHEADER=true
|
||||
|
||||
|
||||
# Set the number of recent blocks shown on the homepage.
|
||||
# For slow devices reduce this number.
|
||||
# Default: 10
|
||||
#BTCEXP_UI_HOME_PAGE_LATEST_BLOCKS_COUNT=10
|
||||
|
||||
|
||||
# Set the number of blocks per page on the browse-blocks page.
|
||||
# For slow devices reduce this number.
|
||||
# Default: 50
|
||||
|
|
|
|||
19
CHANGELOG.md
|
|
@ -1,11 +1,24 @@
|
|||
##### Unreleased
|
||||
##### v3.0
|
||||
###### Unreleased
|
||||
|
||||
* Major visual refresh!
|
||||
* All new design (layout, fonts, colors, etc)
|
||||
* Redesigned Dark Mode (now the default)
|
||||
* New app icon (this tools needs more of an identity of its own!)
|
||||
* Support for pruned nodes and nodes with disabled `txindex`! (HUGE Thanks to [@shesek](https://github.com/shesek))
|
||||
* Upgraded to Bootstrap 5 (currently beta3...)
|
||||
* Fix for 404 pages hanging (Thanks [@shesek](https://github.com/shesek))
|
||||
* Add convenience redirect for baseUrl (Thanks [@shesek](https://github.com/shesek))
|
||||
* Make url in logs clickable (Thanks [@shesek](https://github.com/shesek))
|
||||
* Caching for static files (maxAge=1hr)
|
||||
* Major code refactoring/modernization
|
||||
* Frontend performance optimizations
|
||||
* Major refactoring, modernization, and code-reuse improvements
|
||||
* UX improvements and polish throughout
|
||||
* `/unconfirmed-tx` URL changed to `/mempool-tx`
|
||||
* Updated dependencies
|
||||
* jQuery: v3.4.1 -> v3.6.0
|
||||
* highlight.js: v9.14.2 -> v10.7.1
|
||||
* fontawesome: v5.7.1 -> v5.15.3
|
||||
|
||||
##### v2.2.0
|
||||
###### 2021-01-22
|
||||
|
|
@ -171,7 +184,7 @@
|
|||
* Show mempool ancestor/descendant txs on tx detail pages
|
||||
* Blacklist 'createwallet' by default
|
||||
* Show RBF status for unconfirmed txs
|
||||
* Faster, more reliable display of `/mempool-summary` and `/unconfirmed-tx` pages
|
||||
* Faster, more reliable display of `/mempool-summary` and `/mempool-tx` pages
|
||||
* Fix for persisting arg values in UI on `/rpc-browser`
|
||||
* Misc minor fixes and ux tweaks
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# BTC RPC Explorer
|
||||
|
||||

|
||||

|
||||
|
||||
[![npm version][npm-ver-img]][npm-ver-url] [![NPM downloads][npm-dl-img]][npm-dl-url]
|
||||
|
||||
|
|
|
|||
61
app.js
|
|
@ -54,6 +54,8 @@ const axios = require("axios");
|
|||
const package_json = require('./package.json');
|
||||
global.appVersion = package_json.version;
|
||||
|
||||
global.btcNodeSemver = "0.0.0";
|
||||
|
||||
|
||||
const baseActionsRouter = require('./routes/baseRouter.js');
|
||||
const apiActionsRouter = require('./routes/apiRouter.js');
|
||||
|
|
@ -610,56 +612,27 @@ expressApp.use(function(req, res, next) {
|
|||
res.locals.pageErrors = [];
|
||||
|
||||
|
||||
if (!req.session.userSettings) {
|
||||
req.session.userSettings = JSON.parse(req.cookies["user-settings"] || "{}");
|
||||
}
|
||||
|
||||
const userSettings = req.session.userSettings;
|
||||
res.locals.userSettings = userSettings;
|
||||
|
||||
|
||||
// currency format type
|
||||
if (!req.session.currencyFormatType) {
|
||||
var cookieValue = req.cookies['user-setting-currencyFormatType'];
|
||||
|
||||
if (cookieValue) {
|
||||
req.session.currencyFormatType = cookieValue;
|
||||
|
||||
} else {
|
||||
req.session.currencyFormatType = "";
|
||||
}
|
||||
if (!userSettings.currencyFormatType) {
|
||||
userSettings.currencyFormatType = "";
|
||||
}
|
||||
|
||||
// theme
|
||||
if (!req.session.uiTheme) {
|
||||
var cookieValue = req.cookies['user-setting-uiTheme'];
|
||||
|
||||
if (cookieValue) {
|
||||
req.session.uiTheme = cookieValue;
|
||||
|
||||
} else {
|
||||
req.session.uiTheme = "";
|
||||
}
|
||||
if (!userSettings.uiTheme) {
|
||||
userSettings.uiTheme = config.defaultTheme;
|
||||
}
|
||||
|
||||
// blockPage.showTechSummary
|
||||
if (!req.session.blockPageShowTechSummary) {
|
||||
var cookieValue = req.cookies['user-setting-blockPageShowTechSummary'];
|
||||
|
||||
if (cookieValue) {
|
||||
req.session.blockPageShowTechSummary = cookieValue;
|
||||
|
||||
} else {
|
||||
req.session.blockPageShowTechSummary = "true";
|
||||
}
|
||||
}
|
||||
|
||||
// homepage banner
|
||||
if (!req.session.hideHomepageBanner) {
|
||||
var cookieValue = req.cookies['user-setting-hideHomepageBanner'];
|
||||
|
||||
if (cookieValue) {
|
||||
req.session.hideHomepageBanner = cookieValue;
|
||||
|
||||
} else {
|
||||
req.session.hideHomepageBanner = "false";
|
||||
}
|
||||
}
|
||||
|
||||
res.locals.currencyFormatType = req.session.currencyFormatType;
|
||||
global.currencyFormatType = req.session.currencyFormatType;
|
||||
res.locals.currencyFormatType = userSettings.currencyFormatType;
|
||||
global.currencyFormatType = userSettings.currencyFormatType;
|
||||
|
||||
|
||||
if (!["/", "/connect"].includes(req.originalUrl)) {
|
||||
|
|
@ -727,7 +700,7 @@ expressApp.use(function(req, res, next) {
|
|||
|
||||
// development error handler
|
||||
// will print stacktrace
|
||||
if (expressApp.get('env') === 'development') {
|
||||
if (expressApp.get("env") === "development" || expressApp.get("env") === "local") {
|
||||
expressApp.use(function(err, req, res, next) {
|
||||
if (err) {
|
||||
utils.logError("3289023yege", err);
|
||||
|
|
|
|||
|
|
@ -277,9 +277,9 @@ function getIndexInfo() {
|
|||
return tryCacheThenRpcApi(miscCache, "getIndexInfo", 10 * ONE_SEC, rpcApi.getIndexInfo);
|
||||
}
|
||||
|
||||
function getMempoolTxids() {
|
||||
function getAllMempoolTxids() {
|
||||
// no caching, that would be dumb
|
||||
return rpcApi.getMempoolTxids();
|
||||
return rpcApi.getAllMempoolTxids();
|
||||
}
|
||||
|
||||
function getMiningInfo() {
|
||||
|
|
@ -568,18 +568,16 @@ function getPeerSummary() {
|
|||
});
|
||||
}
|
||||
|
||||
function getMempoolDetails(start, count) {
|
||||
function getMempoolTxids(limit, offset) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
tryCacheThenRpcApi(miscCache, "getMempoolTxids", ONE_SEC, rpcApi.getMempoolTxids).then(function(resultTxids) {
|
||||
tryCacheThenRpcApi(miscCache, "getMempoolTxids", ONE_SEC, rpcApi.getAllMempoolTxids).then(function(resultTxids) {
|
||||
var txids = [];
|
||||
|
||||
for (var i = start; (i < resultTxids.length && i < (start + count)); i++) {
|
||||
for (var i = offset; (i < resultTxids.length && i < (offset + limit)); i++) {
|
||||
txids.push(resultTxids[i]);
|
||||
}
|
||||
|
||||
getRawTransactionsWithInputs(txids, config.site.txMaxInput).then(function(result) {
|
||||
resolve({ txCount:resultTxids.length, transactions:result.transactions, txInputsByTransaction:result.txInputsByTransaction });
|
||||
});
|
||||
resolve({ txCount:resultTxids.length, txids:txids });
|
||||
|
||||
}).catch(function(err) {
|
||||
reject(err);
|
||||
|
|
@ -1140,7 +1138,7 @@ module.exports = {
|
|||
getNetworkInfo: getNetworkInfo,
|
||||
getNetTotals: getNetTotals,
|
||||
getMempoolInfo: getMempoolInfo,
|
||||
getMempoolTxids: getMempoolTxids,
|
||||
getAllMempoolTxids: getAllMempoolTxids,
|
||||
getMiningInfo: getMiningInfo,
|
||||
getIndexInfo: getIndexInfo,
|
||||
getBlockByHeight: getBlockByHeight,
|
||||
|
|
@ -1162,7 +1160,7 @@ module.exports = {
|
|||
logCacheSizes: logCacheSizes,
|
||||
getPeerSummary: getPeerSummary,
|
||||
getChainTxStats: getChainTxStats,
|
||||
getMempoolDetails: getMempoolDetails,
|
||||
getMempoolTxids: getMempoolTxids,
|
||||
getTxCountStats: getTxCountStats,
|
||||
getSmartFeeEstimates: getSmartFeeEstimates,
|
||||
getSmartFeeEstimate: getSmartFeeEstimate,
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ function getPeerInfo() {
|
|||
return getRpcData("getpeerinfo");
|
||||
}
|
||||
|
||||
function getMempoolTxids() {
|
||||
function getAllMempoolTxids() {
|
||||
return getRpcDataWithParams({method:"getrawmempool", parameters:[false]});
|
||||
}
|
||||
|
||||
|
|
@ -553,7 +553,7 @@ module.exports = {
|
|||
getNetworkInfo: getNetworkInfo,
|
||||
getNetTotals: getNetTotals,
|
||||
getMempoolInfo: getMempoolInfo,
|
||||
getMempoolTxids: getMempoolTxids,
|
||||
getAllMempoolTxids: getAllMempoolTxids,
|
||||
getMiningInfo: getMiningInfo,
|
||||
getIndexInfo: getIndexInfo,
|
||||
getBlockByHeight: getBlockByHeight,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
"use strict";
|
||||
|
||||
const btc = require("./coins/btc.js");
|
||||
const ltc = require("./coins/ltc.js");
|
||||
|
||||
module.exports = {
|
||||
"BTC": btc,
|
||||
"LTC": ltc,
|
||||
|
||||
"coins":["BTC", "LTC"]
|
||||
"coins":["BTC"]
|
||||
};
|
||||
|
|
@ -55,10 +55,21 @@ module.exports = {
|
|||
name:"Bitcoin",
|
||||
ticker:"BTC",
|
||||
logoUrlsByNetwork:{
|
||||
"main":"./img/logo/logo.svg",
|
||||
"test":"./img/logo/logo-testnet.svg",
|
||||
"regtest":"./img/logo/logo-regtest.svg",
|
||||
"signet":"./img/logo/logo-signet.svg"
|
||||
},
|
||||
coinIconUrlsByNetwork:{
|
||||
"main":"./img/logo/btc.svg",
|
||||
"test":"./img/logo/tbtc.svg",
|
||||
"regtest":"./img/logo/tbtc.svg",
|
||||
"signet":"./img/logo/signet.svg"
|
||||
"test":"./img/logo/btc-testnet.svg",
|
||||
"signet":"./img/logo/btc-signet.svg"
|
||||
},
|
||||
coinColorsByNetwork: {
|
||||
"main": "#F7931A",
|
||||
"test": "#1daf00",
|
||||
"signet": "#af008c",
|
||||
"regtest": "#777"
|
||||
},
|
||||
siteTitlesByNetwork: {
|
||||
"main":"Bitcoin Explorer",
|
||||
|
|
@ -69,7 +80,11 @@ module.exports = {
|
|||
siteDescriptionHtml:"<b>BTC Explorer</b> is <a href='https://github.com/janoside/btc-rpc-explorer). If you run your own [Bitcoin Full Node](https://bitcoin.org/en/full-node), **BTC Explorer** can easily run alongside it, communicating via RPC calls. See the project [ReadMe](https://github.com/janoside/btc-rpc-explorer) for a list of features and instructions for running.",
|
||||
nodeTitle:"Bitcoin Full Node",
|
||||
nodeUrl:"https://bitcoin.org/en/full-node",
|
||||
demoSiteUrl: "https://explorer.btc21.org",
|
||||
demoSiteUrlsByNetwork: {
|
||||
"main": "https://explorer.btc21.org",
|
||||
"test": "https://testnet.btc21.org",
|
||||
"signet": "https://signet.btc21.org",
|
||||
},
|
||||
miningPoolsConfigUrls:[
|
||||
"https://raw.githubusercontent.com/btc21/Bitcoin-Known-Miners/master/miners.json",
|
||||
"https://raw.githubusercontent.com/btccom/Blockchain-Known-Pools/master/pools.json",
|
||||
|
|
@ -91,6 +106,21 @@ module.exports = {
|
|||
baseCurrencyUnit:currencyUnits[3],
|
||||
defaultCurrencyUnit:currencyUnits[0],
|
||||
feeSatoshiPerByteBucketMaxima: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 50, 75, 100, 150],
|
||||
|
||||
halvingBlockIntervalsByNetwork: {
|
||||
"main": 210000,
|
||||
"test": 210000,
|
||||
"regtest": 150,
|
||||
"signet": 210000
|
||||
},
|
||||
|
||||
// used for supply estimates that don't need full gettxoutset accuracy
|
||||
coinSupplyCheckpointsByNetwork: {
|
||||
"main": [ 675046, new Decimal(18656332.38) ],
|
||||
"test": [ 1940614, new Decimal(20963051.112) ],
|
||||
"signet": [ 29472, new Decimal(1473600) ]
|
||||
},
|
||||
|
||||
genesisBlockHashesByNetwork:{
|
||||
"main": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
|
||||
"test": "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943",
|
||||
|
|
@ -391,7 +421,7 @@ module.exports = {
|
|||
blockHeight: 0,
|
||||
blockHash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
|
||||
summary: "The Bitcoin Genesis Block.",
|
||||
alertBodyHtml: "This is the first block in the Bitcoin blockchain, known as the 'Genesis Block'. This block was mined by Bitcoin's creator Satoshi Nakamoto. You can read more about <a href='https://en.bitcoin.it/wiki/Genesis_block'>the genesis block</a>.",
|
||||
alertBodyHtml: "This is the first block in the Bitcoin blockchain, known as the <b>Genesis Block</b>. This block was mined by Bitcoin's creator <b>Satoshi Nakamoto</b>.<br/>Read more here: <a href='https://en.bitcoin.it/wiki/Genesis_block'>bitcoin.it/wiki/Genesis_block</a>.",
|
||||
referenceUrl: "https://en.bitcoin.it/wiki/Genesis_block"
|
||||
},
|
||||
{
|
||||
|
|
@ -401,7 +431,7 @@ module.exports = {
|
|||
txid: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
|
||||
blockHeight: 0,
|
||||
summary: "The coinbase transaction of the Genesis Block.",
|
||||
alertBodyHtml: "This transaction doesn't really exist! This is the coinbase transaction of the <a href='./block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'>Bitcoin Genesis Block</a>. For more background about this special-case transaction, you can read <a href='https://github.com/bitcoin/bitcoin/issues/3303'>this brief discussion</a> among some of the <a href='https://bitcoin.org'>Bitcoin</a> developers.",
|
||||
alertBodyHtml: "This transaction doesn't really exist! This is the <b>coinbase transaction</b> of the <a href='./block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'>Bitcoin Genesis Block</a>. For more background about this special-case transaction, you can read <a href='https://github.com/bitcoin/bitcoin/issues/3303'>this brief discussion</a> among some of the <a href='https://bitcoin.org'>Bitcoin</a> developers.",
|
||||
referenceUrl: "https://github.com/bitcoin/bitcoin/issues/3303"
|
||||
},
|
||||
{
|
||||
|
|
@ -690,6 +720,7 @@ module.exports = {
|
|||
date: "2013-03-24",
|
||||
chain: "main",
|
||||
blockHeight: 227835,
|
||||
blockHash: "00000000000001aa077d7aa84c532a4d69bdbff519609d1da0835261b7a74eb6",
|
||||
summary: "The last 'Version 1' block.",
|
||||
alertBodyHtml: "This block was the last 'Version 1' block to be mined. <a href='https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki'>BIP-34</a> defined 'Version 2' blocks and the 'bip34' soft fork was officially locked in 96 blocks after this one, in block #<a href='./block-height/227931'>227,931</a>.",
|
||||
referenceUrl: "https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki"
|
||||
|
|
|
|||
153
app/coins/ltc.js
|
|
@ -1,153 +0,0 @@
|
|||
const Decimal = require("decimal.js");
|
||||
const Decimal8 = Decimal.clone({ precision:8, rounding:8 });
|
||||
|
||||
const currencyUnits = [
|
||||
{
|
||||
type:"native",
|
||||
name:"LTC",
|
||||
multiplier:1,
|
||||
default:true,
|
||||
values:["", "ltc", "LTC"],
|
||||
decimalPlaces:8
|
||||
},
|
||||
{
|
||||
type:"native",
|
||||
name:"lite",
|
||||
multiplier:1000,
|
||||
values:["lite"],
|
||||
decimalPlaces:5
|
||||
},
|
||||
{
|
||||
type:"native",
|
||||
name:"photon",
|
||||
multiplier:1000000,
|
||||
values:["photon"],
|
||||
decimalPlaces:2
|
||||
},
|
||||
{
|
||||
type:"native",
|
||||
name:"litoshi",
|
||||
multiplier:100000000,
|
||||
values:["litoshi", "lit"],
|
||||
decimalPlaces:0
|
||||
},
|
||||
{
|
||||
type:"exchanged",
|
||||
name:"USD",
|
||||
multiplier:"usd",
|
||||
values:["usd"],
|
||||
decimalPlaces:2,
|
||||
symbol:"$"
|
||||
},
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
name:"Litecoin",
|
||||
ticker:"LTC",
|
||||
logoUrl:"/img/logo/ltc.svg",
|
||||
siteTitle:"Litecoin Explorer",
|
||||
nodeTitle:"Litecoin Full Node",
|
||||
nodeUrl:"https://litecoin.org/",
|
||||
demoSiteUrl: "https://ltc.chaintools.io",
|
||||
miningPoolsConfigUrls:[
|
||||
"https://raw.githubusercontent.com/hashstream/pools/master/pools.json",
|
||||
],
|
||||
maxBlockWeight: 4000000,
|
||||
targetBlockTimeSeconds: 150,
|
||||
currencyUnits:currencyUnits,
|
||||
currencyUnitsByName:{"LTC":currencyUnits[0], "lite":currencyUnits[1], "photon":currencyUnits[2], "litoshi":currencyUnits[3]},
|
||||
baseCurrencyUnit:currencyUnits[3],
|
||||
defaultCurrencyUnit:currencyUnits[0],
|
||||
feeSatoshiPerByteBucketMaxima: [5, 10, 25, 50, 100, 150, 200, 250],
|
||||
genesisBlockHash: "12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2",
|
||||
genesisCoinbaseTransactionId: "97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9",
|
||||
genesisCoinbaseTransaction: {
|
||||
"txid":"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9",
|
||||
"hash":"97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9",
|
||||
"blockhash":"12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2",
|
||||
"version":1,
|
||||
"locktime":0,
|
||||
"size":199,
|
||||
"vsize":199,
|
||||
"time":1317972665,
|
||||
"blocktime":1317972665,
|
||||
"vin":[
|
||||
{
|
||||
"prev_out":{
|
||||
"hash":"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"n":4294967295
|
||||
},
|
||||
"coinbase":"04ffff001d0104404e592054696d65732030352f4f63742f32303131205374657665204a6f62732c204170706c65e280997320566973696f6e6172792c2044696573206174203536"
|
||||
}
|
||||
],
|
||||
"vout":[
|
||||
{
|
||||
"value":"50.00000000",
|
||||
"n":0,
|
||||
"scriptPubKey":{
|
||||
"hex":"040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9 OP_CHECKSIG",
|
||||
"type":"pubkey",
|
||||
"reqSigs":1,
|
||||
"addresses":[
|
||||
"Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
historicalData: [
|
||||
{
|
||||
type: "blockheight",
|
||||
date: "2011-10-07",
|
||||
blockHeight: 0,
|
||||
blockHash: "12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2",
|
||||
summary: "The Litecoin genesis block.",
|
||||
alertBodyHtml: "This is the first block in the Litecoin blockchain.",
|
||||
referenceUrl: "https://medium.com/@SatoshiLite/satoshilite-1e2dad89a017"
|
||||
},
|
||||
{
|
||||
type: "tx",
|
||||
date: "2017-05-10",
|
||||
txid: "ce385e55fb2a73fa438426145b074f08314812fa3396472dc572b3079e26e0f9",
|
||||
summary: "First SegWit transaction.",
|
||||
referenceUrl: "https://twitter.com/satoshilite/status/862345830082138113"
|
||||
},
|
||||
{
|
||||
type: "blockheight",
|
||||
date: "2011-10-13",
|
||||
blockHeight: 448,
|
||||
blockHash: "6995d69ce2cb7768ef27f55e02dd1772d452deb44e1716bb1dd9c29409edf252",
|
||||
summary: "The first block containing a (non-coinbase) transaction.",
|
||||
referenceUrl: ""
|
||||
},
|
||||
{
|
||||
type: "link",
|
||||
date: "2016-05-02",
|
||||
url: "/rpc-browser?method=verifymessage&args%5B0%5D=Ler4HNAEfwYhBmGXcFP2Po1NpRUEiK8km2&args%5B1%5D=G7W57QZ1jevRhBp7SajpcUgJiGs998R4AdBjcIgJq5BOECh4jHNatZKCFLQeo9PvZLf60ykR32XjT4IrUi9PtCU%3D&args%5B2%5D=I%2C+Charlie+Lee%2C+am+the+creator+of+Litecoin&execute=Execute",
|
||||
summary: "Litecoin's Proof-of-Creator",
|
||||
referenceUrl: "https://medium.com/@SatoshiLite/satoshilite-1e2dad89a017"
|
||||
}
|
||||
],
|
||||
exchangeRateData:{
|
||||
jsonUrl:"https://api.coinmarketcap.com/v1/ticker/Litecoin/",
|
||||
exchangedCurrencyName:"usd",
|
||||
responseBodySelectorFunction:function(responseBody) {
|
||||
if (responseBody[0] && responseBody[0].price_usd) {
|
||||
return {"usd":responseBody[0].price_usd};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
},
|
||||
blockRewardFunction:function(blockHeight) {
|
||||
var eras = [ new Decimal8(50) ];
|
||||
for (var i = 1; i < 34; i++) {
|
||||
var previous = eras[i - 1];
|
||||
eras.push(new Decimal8(previous).dividedBy(2));
|
||||
}
|
||||
|
||||
var index = Math.floor(blockHeight / 840000);
|
||||
|
||||
return eras[index];
|
||||
}
|
||||
};
|
||||
|
|
@ -19,6 +19,7 @@ const coins = require("./coins.js");
|
|||
const credentials = require("./credentials.js");
|
||||
|
||||
const currentCoin = process.env.BTCEXP_COIN || "BTC";
|
||||
const defaultTheme = process.env.BTCEXP_UI_THEME || "dark";
|
||||
|
||||
const rpcCred = credentials.rpc;
|
||||
|
||||
|
|
@ -84,6 +85,7 @@ module.exports = {
|
|||
baseUrl: baseUrl,
|
||||
|
||||
coin: currentCoin,
|
||||
defaultTheme: defaultTheme,
|
||||
|
||||
cookieSecret: cookieSecret,
|
||||
|
||||
|
|
@ -199,7 +201,6 @@ module.exports = {
|
|||
{name: "Bitcoin Explorer", url:"https://explorer.btc21.org", imgUrl:"./img/logo/btc.svg"},
|
||||
{name: "Testnet Explorer", url:"https://testnet.btc21.org", imgUrl:"./img/logo/tbtc.svg"},
|
||||
{name: "Signet Explorer", url:"https://signet.btc21.org", imgUrl:"./img/logo/signet.svg"},
|
||||
{name: "LND Admin", url:"https://lnd-admin.btc21.org", imgUrl:"./img/logo/lnd-admin.png"},
|
||||
//{name: "Litecoin Explorer", url:"https://ltc.chaintools.io", imgUrl:"/img/logo/ltc.svg"},
|
||||
//{name: "Lightning Explorer", url:"https://lightning.chaintools.io", imgUrl:"/img/logo/lightning.svg"},
|
||||
]
|
||||
|
|
@ -220,12 +221,12 @@ module.exports = {
|
|||
/* 3 */ {name:"Transaction Stats", url:"./tx-stats", desc:"See graphs of total transaction volume and transaction rates.", fontawesome:"fas fa-chart-bar"},
|
||||
|
||||
/* 4 */ {name:"Mempool Summary", url:"./mempool-summary", desc:"Detailed summary of the current mempool for this node.", fontawesome:"fas fa-receipt"},
|
||||
/* 5 */ {name:"Browse Pending Tx", url:"./unconfirmed-tx", desc:"Browse unconfirmed/pending transactions.", fontawesome:"fas fa-unlock"},
|
||||
/* 5 */ {name:"Browse Mempool", url:"./mempool-tx", desc:"Browse unconfirmed/pending transactions.", fontawesome:"fas fa-unlock"},
|
||||
|
||||
/* 6 */ {name:"RPC Browser", url:"./rpc-browser", desc:"Browse the RPC functionality of this node. See docs and execute commands.", fontawesome:"fas fa-book"},
|
||||
/* 7 */ {name:"RPC Terminal", url:"./rpc-terminal", desc:"Directly execute RPCs against this node.", fontawesome:"fas fa-terminal"},
|
||||
|
||||
/* 8 */ {name:(coins[currentCoin].name + " Fun"), url:"./fun", desc:"See fun/interesting historical blockchain data.", fontawesome:"fas fa-certificate"},
|
||||
/* 8 */ {name:(coins[currentCoin].name + " Fun"), url:"./fun", desc:"See fun/interesting historical blockchain data.", fontawesome:"fas fa-flag"},
|
||||
|
||||
/* 9 */ {name:"Mining Summary", url:"./mining-summary", desc:"Summary of recent data about miners.", fontawesome:"fas fa-chart-pie"},
|
||||
/* 10 */ {name:"Block Stats", url:"./block-stats", desc:"Summary data for blocks in configurable range.", fontawesome:"fas fa-layer-group"},
|
||||
|
|
|
|||
71
app/utils.js
|
|
@ -285,11 +285,11 @@ function formatValueInActiveCurrency(amount) {
|
|||
}
|
||||
|
||||
|
||||
function formatValueInGold(amount) {
|
||||
function formatValueInGoldOunces(amount) {
|
||||
var currencyFormat = global.currencyFormatType.toLowerCase() || "usd";
|
||||
|
||||
if (global.exchangeRates[currencyFormat] && global.goldExchangeRates[currencyFormat]) {
|
||||
return formatExchangedCurrency(amount, "au");
|
||||
return formatExchangedCurrency(amount, "au", false);
|
||||
|
||||
} else {
|
||||
return formatExchangedCurrency(amount, "usd");
|
||||
|
|
@ -339,17 +339,17 @@ function satoshisPerUnitOfActiveCurrency() {
|
|||
}
|
||||
}
|
||||
|
||||
function formatExchangedCurrency(amount, exchangeType) {
|
||||
function formatExchangedCurrency(amount, exchangeType, includeUnit=true) {
|
||||
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);
|
||||
|
||||
if (exchangeType == "eur") {
|
||||
return "€" + addThousandsSeparators(exchangedAmt);
|
||||
return (includeUnit ? "€" : "") + addThousandsSeparators(exchangedAmt);
|
||||
|
||||
} else {
|
||||
return "$" + addThousandsSeparators(exchangedAmt);
|
||||
return (includeUnit ? "$" : "") + addThousandsSeparators(exchangedAmt);
|
||||
}
|
||||
|
||||
} else if (exchangeType == "au") {
|
||||
|
|
@ -358,7 +358,7 @@ function formatExchangedCurrency(amount, exchangeType) {
|
|||
dec = dec.times(global.exchangeRates.usd).dividedBy(global.goldExchangeRates.usd);
|
||||
var exchangedAmt = parseFloat(Math.round(dec * 100) / 100).toFixed(2);
|
||||
|
||||
return addThousandsSeparators(exchangedAmt) + "oz";
|
||||
return addThousandsSeparators(exchangedAmt) + (includeUnit ? "oz" : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -384,6 +384,30 @@ function ellipsize(str, length, ending="…") {
|
|||
}
|
||||
}
|
||||
|
||||
function ellipsizeMiddle(str, length, replacement="…", extraCharAtStart=true) {
|
||||
if (str.length <= length) {
|
||||
return str;
|
||||
|
||||
} else {
|
||||
//"abcde"(3)->"a…e"
|
||||
//"abcdef"(3)->"a…f"
|
||||
//"abcdef"(5)->"ab…ef"
|
||||
//"abcdef"(4)->"ab…f"
|
||||
if ((length - replacement.length) % 2 == 0) {
|
||||
return str.substring(0, (length - replacement.length) / 2) + replacement + str.slice(-(length - replacement.length) / 2);
|
||||
|
||||
} else {
|
||||
if (extraCharAtStart) {
|
||||
return str.substring(0, Math.ceil((length - replacement.length) / 2)) + replacement + str.slice(-Math.floor((length - replacement.length) / 2));
|
||||
|
||||
} else {
|
||||
return str.substring(0, Math.floor((length - replacement.length) / 2)) + replacement + str.slice(-Math.ceil((length - replacement.length) / 2));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function shortenTimeDiff(str) {
|
||||
str = str.replace(" years", "y");
|
||||
str = str.replace(" year", "y");
|
||||
|
|
@ -525,6 +549,23 @@ function getBlockTotalFeesFromCoinbaseTxAndBlockHeight(coinbaseTx, blockHeight)
|
|||
}
|
||||
}
|
||||
|
||||
function estimatedSupply(height) {
|
||||
var checkpointData = coinConfig.coinSupplyCheckpointsByNetwork[global.activeBlockchain];
|
||||
var checkpointHeight = checkpointData[0];
|
||||
var checkpointSupply = checkpointData[1];
|
||||
|
||||
var supply = checkpointSupply;
|
||||
|
||||
var i = checkpointHeight;
|
||||
while (i < height) {
|
||||
supply = supply.plus(new Decimal(coinConfig.blockRewardFunction(i, global.activeBlockchain)));
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return supply;
|
||||
}
|
||||
|
||||
function refreshExchangeRates() {
|
||||
if (!config.queryExchangeRates || config.privacyMode) {
|
||||
return;
|
||||
|
|
@ -882,6 +923,17 @@ const dtMillis = (startTimeNanos) => {
|
|||
return parseInt(dtNanos) * 1e-6;
|
||||
};
|
||||
|
||||
function objectProperties(obj) {
|
||||
const props = [];
|
||||
for (const prop in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
|
||||
props.push(prop);
|
||||
}
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
reflectPromise: reflectPromise,
|
||||
redirectToConnectPageIfNeeded: redirectToConnectPageIfNeeded,
|
||||
|
|
@ -894,7 +946,7 @@ module.exports = {
|
|||
formatCurrencyAmountWithForcedDecimalPlaces: formatCurrencyAmountWithForcedDecimalPlaces,
|
||||
formatExchangedCurrency: formatExchangedCurrency,
|
||||
formatValueInActiveCurrency: formatValueInActiveCurrency,
|
||||
formatValueInGold: formatValueInGold,
|
||||
formatValueInGoldOunces: formatValueInGoldOunces,
|
||||
satoshisPerUnitOfActiveCurrency: satoshisPerUnitOfActiveCurrency,
|
||||
addThousandsSeparators: addThousandsSeparators,
|
||||
formatCurrencyAmountInSmallestUnits: formatCurrencyAmountInSmallestUnits,
|
||||
|
|
@ -903,6 +955,7 @@ module.exports = {
|
|||
logMemoryUsage: logMemoryUsage,
|
||||
getMinerFromCoinbaseTx: getMinerFromCoinbaseTx,
|
||||
getBlockTotalFeesFromCoinbaseTxAndBlockHeight: getBlockTotalFeesFromCoinbaseTxAndBlockHeight,
|
||||
estimatedSupply: estimatedSupply,
|
||||
refreshExchangeRates: refreshExchangeRates,
|
||||
parseExponentStringDouble: parseExponentStringDouble,
|
||||
formatLargeNumber: formatLargeNumber,
|
||||
|
|
@ -914,6 +967,7 @@ module.exports = {
|
|||
logError: logError,
|
||||
buildQrCodeUrls: buildQrCodeUrls,
|
||||
ellipsize: ellipsize,
|
||||
ellipsizeMiddle: ellipsizeMiddle,
|
||||
shortenTimeDiff: shortenTimeDiff,
|
||||
outputTypeAbbreviation: outputTypeAbbreviation,
|
||||
outputTypeName: outputTypeName,
|
||||
|
|
@ -924,5 +978,6 @@ module.exports = {
|
|||
getCrawlerFromUserAgentString: getCrawlerFromUserAgentString,
|
||||
timePromise: timePromise,
|
||||
startTimeNanos: startTimeNanos,
|
||||
dtMillis: dtMillis
|
||||
dtMillis: dtMillis,
|
||||
objectProperties: objectProperties
|
||||
};
|
||||
|
|
|
|||
2968
npm-shrinkwrap.json
generated
20
package.json
|
|
@ -6,7 +6,15 @@
|
|||
"bin": "bin/cli.js",
|
||||
"scripts": {
|
||||
"start": "node ./bin/www",
|
||||
"refresh-mining-pool-configs": "node ./bin/refresh-mining-pool-configs.js"
|
||||
"refresh-mining-pool-configs": "node ./bin/refresh-mining-pool-configs.js",
|
||||
|
||||
"css-light-debug": "node-sass --output-style expanded --source-map scss --precision 6 ./public/scss/light.scss ./public/style/light.css",
|
||||
"css-dark-debug": "node-sass --output-style expanded --source-map scss --precision 6 ./public/scss/dark.scss ./public/style/dark.css",
|
||||
"css-debug": "npm-run-all css-light-debug css-dark-debug",
|
||||
|
||||
"css-light": "node-sass --output-style compressed --precision 6 ./public/scss/light.scss ./public/style/light.css",
|
||||
"css-dark": "node-sass --output-style compressed --precision 6 ./public/scss/dark.scss ./public/style/dark.css",
|
||||
"css": "npm-run-all css-light css-dark"
|
||||
},
|
||||
"keywords": [
|
||||
"bitcoin",
|
||||
|
|
@ -27,6 +35,7 @@
|
|||
"bitcoinjs-lib": "^5.2.0",
|
||||
"bluebird": "^3.7.2",
|
||||
"body-parser": "^1.19.0",
|
||||
"bootstrap": "5.0.0-beta3",
|
||||
"cookie-parser": "^1.4.5",
|
||||
"crypto-js": "^4.0.0",
|
||||
"csurf": "^1.11.0",
|
||||
|
|
@ -41,25 +50,26 @@
|
|||
"lru-cache": "6.0.0",
|
||||
"markdown-it": "^12.0.4",
|
||||
"md5": "^2.3.0",
|
||||
"meow": "^5.0.0",
|
||||
"meow": "^9.0.0",
|
||||
"moment": "^2.29.1",
|
||||
"moment-duration-format": "^2.3.2",
|
||||
"morgan": "^1.10.0",
|
||||
"on-headers": "1.0.2",
|
||||
"pidusage": "2.0.21",
|
||||
"pug": "^3.0.0",
|
||||
"pug": "^3.0.2",
|
||||
"qrcode": "^1.4.4",
|
||||
"redis": "^3.0.2",
|
||||
"request": "^2.88.2",
|
||||
"semver": "^7.3.4",
|
||||
"semver": "^7.3.5",
|
||||
"serve-favicon": "^2.5.0",
|
||||
"simple-git": "^2.34.2"
|
||||
"simple-git": "^2.37.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"event-loop-stats": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"less": "3.9.0",
|
||||
"node-sass": "^5.0.0",
|
||||
"npm-run-all": "^4.1.5"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
7
public/css/bootstrap-dark.min.css
vendored
7
public/css/bootstrap.min.css
vendored
|
|
@ -1,36 +0,0 @@
|
|||
hr {
|
||||
background-color: #555555;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link.active {
|
||||
border-color: #9a9b9c #9a9b9c #0c0c0c !important;
|
||||
}
|
||||
|
||||
.data-tag {
|
||||
color: #111 !important;
|
||||
border-color: #cccccc !important;
|
||||
}
|
||||
|
||||
.data-tag.bg-dark {
|
||||
background-color: #cccccc !important;
|
||||
}
|
||||
|
||||
.alert {
|
||||
opacity: 0.8 !important;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
.hljs-attr {
|
||||
color: #eeeeee;
|
||||
}
|
||||
|
||||
.hljs, .hljs-subst {
|
||||
color: #dddddd;
|
||||
}
|
||||
|
||||
.hljs-type, .hljs-string, .hljs-number, .hljs-selector-id, .hljs-selector-class, .hljs-quote, .hljs-template-tag, .hljs-deletion {
|
||||
color: #95dbc6;
|
||||
}
|
||||
1
public/css/highlight.min.css
vendored
|
|
@ -1 +0,0 @@
|
|||
.hljs{display:block;overflow-x:auto;padding:0.5em;background:#F0F0F0}.hljs,.hljs-subst{color:#444}.hljs-comment{color:#888888}.hljs-keyword,.hljs-attribute,.hljs-selector-tag,.hljs-meta-keyword,.hljs-doctag,.hljs-name{font-weight:bold}.hljs-type,.hljs-string,.hljs-number,.hljs-selector-id,.hljs-selector-class,.hljs-quote,.hljs-template-tag,.hljs-deletion{color:#880000}.hljs-title,.hljs-section{color:#880000;font-weight:bold}.hljs-regexp,.hljs-symbol,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-selector-attr,.hljs-selector-pseudo{color:#BC6060}.hljs-literal{color:#78A960}.hljs-built_in,.hljs-bullet,.hljs-code,.hljs-addition{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta-string{color:#4d99bf}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}
|
||||
|
|
@ -1,300 +0,0 @@
|
|||
body {
|
||||
font-size: 14px;
|
||||
font-family: "Ubuntu", sans-serif;
|
||||
/*font: 14px 'Open Sans', "Lucida Grande", Helvetica, Arial, sans-serif;*/
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 5px 0 15px 0;
|
||||
}
|
||||
|
||||
img.header-image {
|
||||
margin-top: -10px;
|
||||
margin-bottom: -5px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
code, .text-monospace {
|
||||
font-family: "Source Code Pro", monospace !important;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
h6, .h6 {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.text-small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.popover {
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
.border-dotted {
|
||||
border-bottom: 1px dotted #aaa;
|
||||
}
|
||||
|
||||
.data-tag {
|
||||
color: white;
|
||||
border-radius: 0.25rem;
|
||||
padding: 3px 6px;
|
||||
}
|
||||
|
||||
.mb-tiny {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.mb-huge {
|
||||
margin-bottom: 200px;
|
||||
}
|
||||
|
||||
.user-message-markdown p {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.nav-tabs .nav-link.active {
|
||||
background-color: transparent;
|
||||
border-color: #dee2e6 #dee2e6 #f8f9fa;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
white-space: -moz-pre-wrap;
|
||||
white-space: -pre-wrap;
|
||||
white-space: -o-pre-wrap;
|
||||
word-wrap: break-word;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.word-wrap {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
#subheader a {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.table th {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.dropdown-item:focus, .dropdown-item:hover {
|
||||
background-color: #e3e3e3;
|
||||
}
|
||||
|
||||
#sub-menu a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.xindex-summary table tbody th, .xindex-summary table tbody td {
|
||||
padding: 0;
|
||||
padding-top: 0.3rem;
|
||||
padding-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.index-summary .summary-icon {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.summary-table-label, .summary-table-content, .summary-split-table-label, .summary-split-table-content {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 1px;
|
||||
padding-right: 5px;
|
||||
padding-left: 15px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.tx-io-label, .tx-io-content, .tx-io-desc, .tx-io-value {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 1px;
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
margin-bottom: 2px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.summary-table-label, .summary-split-table-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.summary-table-content, .summary-split-table-content {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.summary-table-label {
|
||||
max-width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
.summary-table-content {
|
||||
max-width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.summary-split-table-label {
|
||||
max-width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
.summary-split-table-content {
|
||||
max-width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.tx-io-label { max-width: 100%; }
|
||||
.tx-io-content { max-width: 100%; }
|
||||
.tx-io-desc { max-width: 100%; }
|
||||
.tx-io-value { max-width: 100%; }
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.summary-table-label {
|
||||
max-width: 18%;
|
||||
text-align: right;
|
||||
}
|
||||
.summary-table-content {
|
||||
max-width: 82%;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.summary-split-table-label {
|
||||
max-width: 36%;
|
||||
text-align: right;
|
||||
}
|
||||
.summary-split-table-content {
|
||||
max-width: 64%;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.tx-io-label { max-width: 8%; }
|
||||
.tx-io-content { max-width: 92%; }
|
||||
.tx-io-desc { max-width: 65%; }
|
||||
.tx-io-value { max-width: 35%; text-align: right; }
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.summary-table-label {
|
||||
max-width: 15%;
|
||||
text-align: right;
|
||||
}
|
||||
.summary-table-content {
|
||||
max-width: 85%;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.summary-split-table-label {
|
||||
max-width: 30%;
|
||||
text-align: right;
|
||||
}
|
||||
.summary-split-table-content {
|
||||
max-width: 70%;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.tx-io-label { max-width: 11%; }
|
||||
.tx-io-content { max-width: 89%; }
|
||||
.tx-io-desc { max-width: 60%; }
|
||||
.tx-io-value { max-width: 40%; text-align: right; }
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.container {
|
||||
max-width: 1160px;
|
||||
}
|
||||
|
||||
.summary-table-label {
|
||||
max-width: 13%;
|
||||
text-align: right;
|
||||
}
|
||||
.summary-table-content {
|
||||
max-width: 87%;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.summary-split-table-label {
|
||||
max-width: 24%;
|
||||
text-align: right;
|
||||
}
|
||||
.summary-split-table-content {
|
||||
max-width: 76%;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.tx-io-label { max-width: 11%; }
|
||||
.tx-io-content { max-width: 89%; }
|
||||
.tx-io-desc { max-width: 69%; }
|
||||
.tx-io-value { max-width: 31%; text-align: right; }
|
||||
}
|
||||
|
||||
@media (min-width: 1920px) {
|
||||
.container {
|
||||
max-width: 1800px;
|
||||
}
|
||||
|
||||
.summary-table-label {
|
||||
max-width: 8%;
|
||||
text-align: right;
|
||||
}
|
||||
.summary-table-content {
|
||||
max-width: 92%;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.summary-split-table-label {
|
||||
max-width: 16%;
|
||||
text-align: right;
|
||||
}
|
||||
.summary-split-table-content {
|
||||
max-width: 84%;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.tx-io-label { max-width: 7%; }
|
||||
.tx-io-content { max-width: 93%; }
|
||||
.tx-io-desc { max-width: 70%; }
|
||||
.tx-io-value { max-width: 30%; text-align: right; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
footer a {
|
||||
color: #ddd;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
footer a:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.table-striped>tbody>tr:nth-child(odd)>td,
|
||||
.table-striped>tbody>tr:nth-child(odd)>th {
|
||||
/*background-color: #fbfbfb;*/
|
||||
}
|
||||
|
||||
.hljs-type, .hljs-string, .hljs-number, .hljs-selector-id, .hljs-selector-class, .hljs-quote, .hljs-template-tag, .hljs-deletion {
|
||||
color: #3aa54f;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 956 B After Width: | Height: | Size: 956 B |
|
Before Width: | Height: | Size: 956 B After Width: | Height: | Size: 956 B |
|
Before Width: | Height: | Size: 2.3 KiB |
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 64 64" style="enable-background:new 0 0 64 64;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#007bff;}
|
||||
.st1{opacity:0.0;fill:#ffff00;}
|
||||
.st2{fill:#ffcc00;}
|
||||
</style>
|
||||
<circle class="st0" cx="32" cy="32" r="32"/>
|
||||
<path class="st1" d="M46.9,17.5C46.7,17.2,46.4,17,46,17H29c-0.4,0-0.7,0.2-0.9,0.6l-8,16c-0.2,0.3-0.1,0.7,0,1
|
||||
c0.2,0.3,0.5,0.5,0.9,0.5h5.5l-8.4,18.6c-0.2,0.4-0.1,0.9,0.3,1.2c0.2,0.1,0.4,0.2,0.6,0.2c0.2,0,0.5-0.1,0.6-0.2l24-20
|
||||
c0.3-0.3,0.4-0.7,0.3-1.1C43.8,33.3,43.4,33,43,33h-6.1l9.9-14.4C47,18.3,47.1,17.9,46.9,17.5z"/>
|
||||
<path class="st2" d="M46.9,15.5C46.7,15.2,46.4,15,46,15H29c-0.4,0-0.7,0.2-0.9,0.6l-8,16c-0.2,0.3-0.1,0.7,0,1
|
||||
c0.2,0.3,0.5,0.5,0.9,0.5h5.5l-8.4,18.6c-0.2,0.4-0.1,0.9,0.3,1.2c0.2,0.1,0.4,0.2,0.6,0.2c0.2,0,0.5-0.1,0.6-0.2l24-20
|
||||
c0.3-0.3,0.4-0.7,0.3-1.1C43.8,31.3,43.4,31,43,31h-6.1l9.9-14.4C47,16.3,47.1,15.9,46.9,15.5z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
7
public/img/logo/logo-regtest.svg
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<svg aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512">
|
||||
<path fill="#777" d="M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0z"></path>
|
||||
|
||||
<g transform="translate(-83, 40) rotate(-14 0 0) scale(14 14)">
|
||||
<path fill="#FFF" fill-rule="nonzero" d="M23.189 14.02c.314-2.096-1.283-3.223-3.465-3.975l.708-2.84-1.728-.43-.69 2.765c-.454-.114-.92-.22-1.385-.326l.695-2.783L15.596 6l-.708 2.839c-.376-.086-.746-.17-1.104-.26l.002-.009-2.384-.595-.46 1.846s1.283.294 1.256.312c.7.175.826.638.805 1.006l-.806 3.235c.048.012.11.03.18.057l-.183-.045-1.13 4.532c-.086.212-.303.531-.793.41.018.025-1.256-.313-1.256-.313l-.858 1.978 2.25.561c.418.105.828.215 1.231.318l-.715 2.872 1.727.43.708-2.84c.472.127.93.245 1.378.357l-.706 2.828 1.728.43.715-2.866c2.948.558 5.164.333 6.097-2.333.752-2.146-.037-3.385-1.588-4.192 1.13-.26 1.98-1.003 2.207-2.538zm-3.95 5.538c-.533 2.147-4.148.986-5.32.695l.95-3.805c1.172.293 4.929.872 4.37 3.11zm.535-5.569c-.487 1.953-3.495.96-4.47.717l.86-3.45c.975.243 4.118.696 3.61 2.733z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
7
public/img/logo/logo-signet.svg
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<svg aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512">
|
||||
<path fill="#af008c" d="M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0z"></path>
|
||||
|
||||
<g transform="translate(-83, 40) rotate(-14 0 0) scale(14 14)">
|
||||
<path fill="#FFF" fill-rule="nonzero" d="M23.189 14.02c.314-2.096-1.283-3.223-3.465-3.975l.708-2.84-1.728-.43-.69 2.765c-.454-.114-.92-.22-1.385-.326l.695-2.783L15.596 6l-.708 2.839c-.376-.086-.746-.17-1.104-.26l.002-.009-2.384-.595-.46 1.846s1.283.294 1.256.312c.7.175.826.638.805 1.006l-.806 3.235c.048.012.11.03.18.057l-.183-.045-1.13 4.532c-.086.212-.303.531-.793.41.018.025-1.256-.313-1.256-.313l-.858 1.978 2.25.561c.418.105.828.215 1.231.318l-.715 2.872 1.727.43.708-2.84c.472.127.93.245 1.378.357l-.706 2.828 1.728.43.715-2.866c2.948.558 5.164.333 6.097-2.333.752-2.146-.037-3.385-1.588-4.192 1.13-.26 1.98-1.003 2.207-2.538zm-3.95 5.538c-.533 2.147-4.148.986-5.32.695l.95-3.805c1.172.293 4.929.872 4.37 3.11zm.535-5.569c-.487 1.953-3.495.96-4.47.717l.86-3.45c.975.243 4.118.696 3.61 2.733z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
7
public/img/logo/logo-testnet.svg
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<svg aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512">
|
||||
<path fill="#1daf00" d="M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0z"></path>
|
||||
|
||||
<g transform="translate(-83, 40) rotate(-14 0 0) scale(14 14)">
|
||||
<path fill="#FFF" fill-rule="nonzero" d="M23.189 14.02c.314-2.096-1.283-3.223-3.465-3.975l.708-2.84-1.728-.43-.69 2.765c-.454-.114-.92-.22-1.385-.326l.695-2.783L15.596 6l-.708 2.839c-.376-.086-.746-.17-1.104-.26l.002-.009-2.384-.595-.46 1.846s1.283.294 1.256.312c.7.175.826.638.805 1.006l-.806 3.235c.048.012.11.03.18.057l-.183-.045-1.13 4.532c-.086.212-.303.531-.793.41.018.025-1.256-.313-1.256-.313l-.858 1.978 2.25.561c.418.105.828.215 1.231.318l-.715 2.872 1.727.43.708-2.84c.472.127.93.245 1.378.357l-.706 2.828 1.728.43.715-2.866c2.948.558 5.164.333 6.097-2.333.752-2.146-.037-3.385-1.588-4.192 1.13-.26 1.98-1.003 2.207-2.538zm-3.95 5.538c-.533 2.147-4.148.986-5.32.695l.95-3.805c1.172.293 4.929.872 4.37 3.11zm.535-5.569c-.487 1.953-3.495.96-4.47.717l.86-3.45c.975.243 4.118.696 3.61 2.733z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
7
public/img/logo/logo.svg
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<svg aria-hidden="true" focusable="false" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512">
|
||||
<path fill="#F7931A" d="M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0z"></path>
|
||||
|
||||
<g transform="translate(-83, 40) rotate(-14 0 0) scale(14 14)">
|
||||
<path fill="#FFF" fill-rule="nonzero" d="M23.189 14.02c.314-2.096-1.283-3.223-3.465-3.975l.708-2.84-1.728-.43-.69 2.765c-.454-.114-.92-.22-1.385-.326l.695-2.783L15.596 6l-.708 2.839c-.376-.086-.746-.17-1.104-.26l.002-.009-2.384-.595-.46 1.846s1.283.294 1.256.312c.7.175.826.638.805 1.006l-.806 3.235c.048.012.11.03.18.057l-.183-.045-1.13 4.532c-.086.212-.303.531-.793.41.018.025-1.256-.313-1.256-.313l-.858 1.978 2.25.561c.418.105.828.215 1.231.318l-.715 2.872 1.727.43.708-2.84c.472.127.93.245 1.378.357l-.706 2.828 1.728.43.715-2.866c2.948.558 5.164.333 6.097-2.333.752-2.146-.037-3.385-1.588-4.192 1.13-.26 1.98-1.003 2.207-2.538zm-3.95 5.538c-.533 2.147-4.148.986-5.32.695l.95-3.805c1.172.293 4.929.872 4.37 3.11zm.535-5.569c-.487 1.953-3.495.96-4.47.717l.86-3.45c.975.243 4.118.696 3.61 2.733z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 886 B |
|
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<circle cx="16" cy="16" r="16" fill="#BFBBBB"/>
|
||||
<polygon fill="#FFF" points="10.427 19.214 9 19.768 9.688 17.009 11.132 16.429 13.213 8 18.342 8 16.823 14.196 18.233 13.625 17.553 16.375 16.126 16.946 15.278 20.429 23 20.429 22.127 24 9.252 24"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 391 B |
|
Before Width: | Height: | Size: 1.3 KiB |
BIN
public/img/screenshots/homepage-v3.png
Normal file
|
After Width: | Height: | Size: 325 KiB |
7
public/js/bootstrap.bundle.min.js
vendored
Normal file
7
public/js/bootstrap.min.js
vendored
6
public/js/fontawesome.min.js
vendored
3
public/js/highlight.min.js
vendored
655
public/js/highlight.pack.js
Normal file
4
public/js/jquery.min.js
vendored
5
public/js/popper.min.js
vendored
|
|
@ -4,16 +4,23 @@ function updateCurrencyValue(element, val) {
|
|||
|
||||
}).done(function(result) {
|
||||
element.html(result);
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('[data-bs-toggle="tooltip"]').tooltip();
|
||||
});
|
||||
}
|
||||
|
||||
function updateFeeRateValue(element, val, digits) {
|
||||
function updateUserSetting(name, val) {
|
||||
$.ajax({
|
||||
url: `./changeSetting?name=${name}&value=${val}`
|
||||
|
||||
}).done(res => {});
|
||||
}
|
||||
|
||||
function updateFeeRateValue(element, val, digits, showUnit=true) {
|
||||
$.ajax({
|
||||
url: `./api/utils/formatCurrencyAmountInSmallestUnits/${val},${digits}`
|
||||
|
||||
}).done(function(result) {
|
||||
element.html(`<span>${result.val} <small>${result.currencyUnit}/vB</small></span>`);
|
||||
element.html(`<span>${result.val}${showUnit ? ("<small class='ms-2'>" + result.currencyUnit + "/vB</small>") : ""}</span>`);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -24,4 +31,10 @@ function showAllTxOutputs(link, txid) {
|
|||
});
|
||||
|
||||
link.classList.add("d-none");
|
||||
}
|
||||
|
||||
function copyTextToClipboard(text) {
|
||||
navigator.clipboard.writeText(text).then(() => {}, (err) => {
|
||||
console.error('Error copying text: ', err);
|
||||
});
|
||||
}
|
||||
|
|
@ -3,5 +3,5 @@ Disallow: /address/
|
|||
Disallow: /rpc*
|
||||
Disallow: /tx-stats
|
||||
Disallow: /peers
|
||||
Disallow: /unconfirmed-tx
|
||||
Disallow: /mempool-tx
|
||||
Disallow: /block-analysis/
|
||||
132
public/scss/dark.scss
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
$body-bg: #031b40;
|
||||
$body-color: #f7f9fa;
|
||||
|
||||
$main-bg: darken($body-bg, 6%);
|
||||
|
||||
$text-muted: #b7bfc7;
|
||||
|
||||
$dark: #3d454d;
|
||||
|
||||
/*$theme-colors: (
|
||||
"dark": #292e33
|
||||
);*/
|
||||
|
||||
|
||||
|
||||
|
||||
$border-color: lighten($body-bg, 4%);
|
||||
|
||||
$card-border-color: $border-color;
|
||||
|
||||
$link-hover-color: #408cff;
|
||||
|
||||
|
||||
$table-striped-bg: lighten($body-bg, 4%);
|
||||
|
||||
|
||||
$pagination-bg: $body-bg;
|
||||
$pagination-border-color: lighten($border-color, 5%);
|
||||
$pagination-active-bg: $body-bg;
|
||||
$pagination-active-border-color: lighten($border-color, 5%);
|
||||
$pagination-hover-bg: lighten($pagination-bg, 15%);
|
||||
$pagination-hover-border-color: lighten($border-color, 5%);
|
||||
$pagination-disabled-bg: darken($pagination-bg, 3%);
|
||||
$pagination-disabled-border-color: lighten($border-color, 5%);
|
||||
|
||||
|
||||
$tooltip-bg: lighten($body-bg, 15%);
|
||||
|
||||
|
||||
$nav-tabs-link-active-color: darken($body-color, 5%);
|
||||
//$nav-tabs-link-active-bg: $body-bg !default;
|
||||
$nav-tabs-link-active-border-color: #ced4da #ced4da $body-bg !important;
|
||||
|
||||
|
||||
$btn-close-color: #fff;
|
||||
|
||||
|
||||
$tooltip-opacity: 1.0;
|
||||
|
||||
$dropdown-bg: lighten($body-bg, 10%);
|
||||
$dropdown-link-color: $body-color;
|
||||
$dropdown-link-hover-bg: lighten($dropdown-bg, 10%);
|
||||
$dropdown-link-hover-color: $body-color;
|
||||
$dropdown-link-active-bg: lighten($dropdown-bg, 5%);
|
||||
$dropdown-dark-bg: #ff0;
|
||||
$dropdown-dark-link-hover-bg: #0ff;
|
||||
$dropdown-dark-link-active-bg: #f0f;
|
||||
$dropdown-link-active-color: lighten($dropdown-bg, 5%);
|
||||
|
||||
$dropdown-header-color: $body-color;
|
||||
|
||||
$dropdown-box-shadow: 0 1.5rem 1rem rgba(#000, .35);
|
||||
|
||||
|
||||
$input-bg: darken(#fff, 0%);
|
||||
//$input-border-color: lighten($input-bg, 9%);
|
||||
$input-color: #212529;
|
||||
|
||||
|
||||
|
||||
@import "./main";
|
||||
@import "../../node_modules/bootstrap/scss/bootstrap";
|
||||
|
||||
|
||||
|
||||
|
||||
.alert-primary {
|
||||
color: $body-color;
|
||||
background-color: lighten($body-bg, 8%);
|
||||
border-color: lighten($body-bg, 20%);
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
color: $body-color;
|
||||
background-color: #7d323b;
|
||||
border-color: #7d1f29;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.alert-danger a {
|
||||
color: $body-color;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
color: $body-color;
|
||||
background-color: #d9962b;
|
||||
border-color: darken(#d9962b, 10%);
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.bg-main {
|
||||
background-color: $main-bg !important;
|
||||
}
|
||||
|
||||
.bg-header-footer {
|
||||
background-color: #162740 !important;
|
||||
}
|
||||
|
||||
.bg-header-footer-highlight {
|
||||
background-color: lighten(#162740, 15%) !important;
|
||||
}
|
||||
|
||||
.bg-gradient-body-to-main {
|
||||
background: linear-gradient(0deg, $main-bg 0%, $body-bg 100%);
|
||||
}
|
||||
|
||||
.card-highlight {
|
||||
background-color: lighten($card-bg, 5%);
|
||||
border: solid 1px lighten($card-bg, 10%) !important;
|
||||
color: $body-color;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 0px 3px;
|
||||
border-radius: 3px;
|
||||
background-color: lighten($card-bg, 15%);
|
||||
color: #198754;
|
||||
}
|
||||
56
public/scss/light.scss
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
$body-bg: #fff;
|
||||
$body-color: #212529;
|
||||
|
||||
$main-bg: #f2f5f7;
|
||||
|
||||
$border-color: #e4e7eb;
|
||||
$card-border-color: $border-color;
|
||||
|
||||
|
||||
$nav-tabs-border-color: #adb5bd;
|
||||
$nav-tabs-link-active-color: lighten($body-color, 5%);
|
||||
$nav-tabs-link-active-border-color: #adb5bd #adb5bd $body-bg !important;
|
||||
|
||||
|
||||
$alert-bg-scale: -70%;
|
||||
$alert-border-scale: -60%;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@import "./main";
|
||||
@import "../../node_modules/bootstrap/scss/bootstrap";
|
||||
|
||||
|
||||
|
||||
.bg-main {
|
||||
background-color: $main-bg !important;
|
||||
}
|
||||
|
||||
.bg-header-footer {
|
||||
background-color: #212529 !important;
|
||||
}
|
||||
|
||||
.bg-header-footer-highlight {
|
||||
background-color: lighten(#212529, 15%) !important;
|
||||
}
|
||||
|
||||
.bg-header-footer {
|
||||
background-color: #162740 !important;
|
||||
}
|
||||
|
||||
.bg-header-footer-highlight {
|
||||
background-color: lighten(#162740, 15%) !important;
|
||||
}
|
||||
|
||||
.bg-gradient-body-to-main {
|
||||
background: linear-gradient(0deg, $main-bg 0%, $body-bg 100%);
|
||||
}
|
||||
|
||||
.card-highlight {
|
||||
background-color: darken($card-bg, 3%);
|
||||
border: solid 1px darken($card-bg, 10%) !important;
|
||||
color: $body-color;
|
||||
}
|
||||
261
public/scss/main.scss
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
$spacer: 1rem;
|
||||
$spacers: (
|
||||
0: 0,
|
||||
1: $spacer / 4,
|
||||
2: $spacer / 2,
|
||||
3: $spacer,
|
||||
4: $spacer * 1.5,
|
||||
5: $spacer * 2,
|
||||
6: $spacer * 2.5,
|
||||
7: $spacer * 3,
|
||||
tiny: $spacer * 0.15
|
||||
) !default;
|
||||
|
||||
$enable-negative-margins: true;
|
||||
|
||||
|
||||
/*$grid-breakpoints: (
|
||||
xs: 0,
|
||||
sm: 576px,
|
||||
md: 768px,
|
||||
lg: 992px,
|
||||
xl: 1200px,
|
||||
xxl: 1400px,
|
||||
xxxl: 1900px
|
||||
) !default;
|
||||
|
||||
$container-max-widths: (
|
||||
sm: 540px,
|
||||
md: 720px,
|
||||
lg: 960px,
|
||||
xl: 1140px,
|
||||
xxl: 1320px,
|
||||
xxxl: 1600px
|
||||
) !default;*/
|
||||
|
||||
|
||||
$btn-padding-y-sm: 0.2rem;
|
||||
$btn-padding-x-sm: 0.5rem;
|
||||
|
||||
|
||||
$card-bg: $body-bg;
|
||||
|
||||
|
||||
$link-decoration: none !default;
|
||||
$link-hover-decoration: underline !default;
|
||||
|
||||
|
||||
$border-radius: .4rem !default;
|
||||
$border-radius-lg: .5rem !default;
|
||||
|
||||
|
||||
$badge-border-radius: 0.2rem;
|
||||
|
||||
|
||||
$tooltip-max-width: 350px;
|
||||
$tooltip-padding-y: 0.4rem !default;
|
||||
$tooltip-padding-x: 0.8rem !default;
|
||||
|
||||
|
||||
$navbar-padding-y: 1rem;
|
||||
$navbar-padding-x: 1rem;
|
||||
$navbar-brand-font-size: 1.5rem;
|
||||
|
||||
|
||||
code {
|
||||
background-color: $body-bg !important;
|
||||
}
|
||||
|
||||
.fontawesome-shadow {
|
||||
filter: drop-shadow(1px 1px 1px #666);
|
||||
}
|
||||
|
||||
.fontawesome-shadow-dark {
|
||||
filter: drop-shadow(1px 1px 1px #262626);
|
||||
}
|
||||
|
||||
|
||||
.text-twitter {
|
||||
color: #1d9bf0;
|
||||
}
|
||||
|
||||
.mb-large {
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
|
||||
.hljs, .hljs-subst {
|
||||
color: $body-color;
|
||||
}
|
||||
|
||||
.text-small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.text-tiny {
|
||||
font-size: 75% !important;
|
||||
}
|
||||
|
||||
.text-60pct {
|
||||
font-size: 50% !important;
|
||||
}
|
||||
|
||||
.text-50pct {
|
||||
font-size: 50% !important;
|
||||
}
|
||||
|
||||
.border-dotted {
|
||||
border-bottom: 1px dotted #ccc;
|
||||
}
|
||||
|
||||
.border-thick {
|
||||
border-width: 4px !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
body {
|
||||
/*font-size: 14px;*/
|
||||
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;
|
||||
/*font: 14px 'Open Sans', "Lucida Grande", Helvetica, Arial, sans-serif;*/
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 5px 0 15px 0;
|
||||
}
|
||||
|
||||
img.header-image {
|
||||
margin-top: -10px;
|
||||
margin-bottom: -5px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
$font-family-monospace: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;
|
||||
|
||||
.font-monospace {
|
||||
/*font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji !important;*/
|
||||
/*font-family: "Source Code Pro", monospace !important;*/
|
||||
}
|
||||
|
||||
code, .font-json, .font-data, .font-plaintext {
|
||||
font-family: "Source Code Pro", monospace !important;
|
||||
}
|
||||
|
||||
.hr-thick {
|
||||
height: 3px !important;
|
||||
}
|
||||
|
||||
.mb-section {
|
||||
margin-bottom: 1.5rem !important;
|
||||
}
|
||||
|
||||
.mb-tiny {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.mb-huge {
|
||||
margin-bottom: 200px;
|
||||
}
|
||||
|
||||
.user-message-markdown p {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*.nav-tabs .nav-link.active {
|
||||
background-color: transparent;
|
||||
border-color: #dee2e6 #dee2e6 #f8f9fa;
|
||||
}*/
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
white-space: -moz-pre-wrap;
|
||||
white-space: -pre-wrap;
|
||||
white-space: -o-pre-wrap;
|
||||
word-wrap: break-word;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 1rem !important;
|
||||
}
|
||||
|
||||
.word-wrap {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.table th {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.tx-io-label, .tx-io-content, .tx-io-desc, .tx-io-value {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 1px;
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
margin-bottom: 2px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.tx-io-label { max-width: 100%; }
|
||||
.tx-io-content { max-width: 100%; }
|
||||
.tx-io-desc { max-width: 100%; }
|
||||
.tx-io-value { max-width: 100%; }
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.tx-io-label { max-width: 8%; }
|
||||
.tx-io-content { max-width: 92%; }
|
||||
.tx-io-desc { max-width: 65%; }
|
||||
.tx-io-value { max-width: 35%; text-align: right; }
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.tx-io-label { max-width: 11%; }
|
||||
.tx-io-content { max-width: 89%; }
|
||||
.tx-io-desc { max-width: 60%; }
|
||||
.tx-io-value { max-width: 40%; text-align: right; }
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.tx-io-label { max-width: 11%; }
|
||||
.tx-io-content { max-width: 89%; }
|
||||
.tx-io-desc { max-width: 69%; }
|
||||
.tx-io-value { max-width: 31%; text-align: right; }
|
||||
}
|
||||
|
||||
@media (min-width: 1920px) {
|
||||
.tx-io-label { max-width: 7.5%; }
|
||||
.tx-io-content { max-width: 92.5%; }
|
||||
.tx-io-desc { max-width: 70%; }
|
||||
.tx-io-value { max-width: 30%; text-align: right; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.footer-link {
|
||||
color: #ddd;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.footer-link:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.hljs-type, .hljs-string, .hljs-selector-id, .hljs-selector-class, .hljs-quote, .hljs-template-tag, .hljs-deletion {
|
||||
color: #3aa54f;
|
||||
}
|
||||
|
||||
.hljs-literal, .hljs-number {
|
||||
color: #0dcaf0;
|
||||
}
|
||||
6
public/style/dark.css
Normal file
1
public/style/highlight.min.css
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.hljs{display:block;overflow-x:auto;padding:.5em;background:#f0f0f0}.hljs,.hljs-subst{color:#444}.hljs-comment{color:#888}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#800}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-link,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#bc6060}.hljs-literal{color:#78a960}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta-string{color:#4d99bf}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
|
||||
6
public/style/light.css
Normal file
|
|
@ -109,6 +109,17 @@ router.get("/stats", function(req, res, next) {
|
|||
});
|
||||
|
||||
|
||||
router.get('/resetUserSettings', (req, res) => {
|
||||
req.session.userSettings = {};
|
||||
|
||||
var userSettings = {};
|
||||
|
||||
res.cookie("user-settings", JSON.stringify(userSettings));
|
||||
|
||||
res.redirect(req.headers.referer);
|
||||
});
|
||||
|
||||
|
||||
router.get('/heapdump', (req, res) => {
|
||||
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ const rpcApi = require("./../app/api/rpcApi.js");
|
|||
|
||||
const forceCsrf = csurf({ ignoreMethods: [] });
|
||||
|
||||
var noTxIndexMsg = "\n\nYour node does not have `txindex` enabled. Without it, you can only lookup wallet, mempool, and recently confirmed transactions by their `txid`. Searching for non-wallet transactions that were confirmed more than "+config.noTxIndexSearchDepth+" blocks ago is only possible if you provide the confirmed block height in addition to the txid, using `<txid>@<height>` in the search box.";
|
||||
var noTxIndexMsg = "\n\nYour node does not have **txindex** enabled. Without it, you can only lookup wallet, mempool, and recently confirmed transactions by their **txid**. Searching for non-wallet transactions that were confirmed more than "+config.noTxIndexSearchDepth+" blocks ago is only possible if the confirmed block height is available.";
|
||||
|
||||
router.get("/", asyncHandler(async (req, res, next) => {
|
||||
try {
|
||||
|
|
@ -101,13 +101,13 @@ router.get("/", asyncHandler(async (req, res, next) => {
|
|||
}));
|
||||
|
||||
promises.push(new Promise(async (resolve, reject) => {
|
||||
res.locals.hashrate1d = await utils.timePromise("promises.index.getNetworkHashrate-144", coreApi.getNetworkHashrate(144));
|
||||
res.locals.hashrate7d = await utils.timePromise("promises.index.getNetworkHashrate-1008", coreApi.getNetworkHashrate(1008));
|
||||
|
||||
resolve();
|
||||
}));
|
||||
|
||||
promises.push(new Promise(async (resolve, reject) => {
|
||||
res.locals.hashrate7d = await utils.timePromise("promises.index.getNetworkHashrate-1008", coreApi.getNetworkHashrate(1008));
|
||||
res.locals.hashrate30d = await utils.timePromise("promises.index.getNetworkHashrate-4320", coreApi.getNetworkHashrate(4320));
|
||||
|
||||
resolve();
|
||||
}));
|
||||
|
|
@ -163,19 +163,19 @@ router.get("/", asyncHandler(async (req, res, next) => {
|
|||
resolve();
|
||||
}));
|
||||
|
||||
if (getblockchaininfo.chain !== 'regtest') {
|
||||
var targetBlocksPerDay = 24 * 60 * 60 / global.coinConfig.targetBlockTimeSeconds;
|
||||
var targetBlocksPerDay = 24 * 60 * 60 / global.coinConfig.targetBlockTimeSeconds;
|
||||
res.locals.targetBlocksPerDay = targetBlocksPerDay;
|
||||
|
||||
promises.push(new Promise(async (resolve, reject) => {
|
||||
if (getblockchaininfo.chain !== 'regtest') {
|
||||
/*promises.push(new Promise(async (resolve, reject) => {
|
||||
res.locals.txStats = await utils.timePromise("promises.index.getTxCountStats", coreApi.getTxCountStats(targetBlocksPerDay / 4, -targetBlocksPerDay, "latest"));
|
||||
|
||||
resolve();
|
||||
}));
|
||||
}));*/
|
||||
|
||||
var chainTxStatsIntervals = [ [targetBlocksPerDay, "24 hours"], [targetBlocksPerDay * 7, "1 week"], [targetBlocksPerDay * 30, "1 month"], [targetBlocksPerDay * 365, "1 year"] ]
|
||||
var chainTxStatsIntervals = [ [targetBlocksPerDay, "24 hours"], [7 * targetBlocksPerDay, "7 days"], [30 * targetBlocksPerDay, "30 days"] ]
|
||||
.filter(dat => dat[0] <= getblockchaininfo.blocks);
|
||||
|
||||
// promiseResults[8-X] (if not regtest)
|
||||
res.locals.chainTxStats = {};
|
||||
for (var i = 0; i < chainTxStatsIntervals.length; i++) {
|
||||
promises.push(new Promise(async (resolve, reject) => {
|
||||
|
|
@ -195,7 +195,83 @@ router.get("/", asyncHandler(async (req, res, next) => {
|
|||
}));
|
||||
}
|
||||
|
||||
/*promises.push(new Promise(async (resolve, reject) => {
|
||||
global.rpcClient.command('getblocktemplate', {"rules": ["segwit"]}, function(err, result, resHeaders) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
res.locals.nextBlockTemplate = result;
|
||||
|
||||
var minFeeRate = 1000000;
|
||||
var maxFeeRate = 0;
|
||||
var minFeeTxid = null;
|
||||
var maxFeeTxid = null;
|
||||
|
||||
result.transactions.forEach(tx => {
|
||||
var feeRate = tx.fee / tx.weight * 4;
|
||||
|
||||
if (feeRate < minFeeRate) {
|
||||
minFeeRate = feeRate;
|
||||
minFeeTxid = tx.txid;
|
||||
}
|
||||
|
||||
if (feeRate > maxFeeRate) {
|
||||
maxFeeRate = feeRate;
|
||||
maxFeeTxid = tx.txid;
|
||||
}
|
||||
});
|
||||
|
||||
res.locals.nextBlockMinFeeRate = minFeeRate;
|
||||
res.locals.nextBlockMaxFeeRate = maxFeeRate;
|
||||
res.locals.nextBlockMinFeeTxid = minFeeTxid;
|
||||
res.locals.nextBlockMaxFeeTxid = maxFeeTxid;
|
||||
|
||||
resolve();
|
||||
});
|
||||
}));*/
|
||||
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
|
||||
var firstBlockHeader = res.locals.difficultyPeriodFirstBlockHeader;
|
||||
var currentBlock = res.locals.latestBlocks[0];
|
||||
var heightDiff = currentBlock.height - firstBlockHeader.height;
|
||||
var timeDiff = currentBlock.mediantime - firstBlockHeader.mediantime;
|
||||
var timePerBlock = timeDiff / heightDiff;
|
||||
var timePerBlockDuration = moment.duration(timePerBlock * 1000);
|
||||
var daysUntilAdjustment = new Decimal(res.locals.blocksUntilDifficultyAdjustment).times(timePerBlock).dividedBy(60 * 60 * 24);
|
||||
var duaDP1 = daysUntilAdjustment.toDP(1);
|
||||
var daysUntilAdjustmentStr = daysUntilAdjustment > 1 ? `~${duaDP1} day${duaDP1 == "1" ? "" : "s"}` : "< 1 day";
|
||||
|
||||
if (timePerBlock > 600) {
|
||||
var diffAdjPercent = new Decimal(timeDiff / heightDiff / 600).times(100).minus(100);
|
||||
var diffAdjText = `Blocks during the current difficulty epoch have taken this long, on average, to be mined. If this pace continues, then in ${res.locals.blocksUntilDifficultyAdjustment.toLocaleString()} block${res.locals.blocksUntilDifficultyAdjustment == 1 ? "" : "s"} (${daysUntilAdjustmentStr}) the difficulty will adjust downward: -${diffAdjPercent.toDP(1)}%`;
|
||||
var diffAdjSign = "-";
|
||||
var textColorClass = "text-danger";
|
||||
|
||||
} else {
|
||||
var diffAdjPercent = new Decimal(100).minus(new Decimal(timeDiff / heightDiff / 600).times(100));
|
||||
var diffAdjText = `Blocks during the current difficulty epoch have taken this long, on average, to be mined. If this pace continues, then in ${res.locals.blocksUntilDifficultyAdjustment.toLocaleString()} block${res.locals.blocksUntilDifficultyAdjustment == 1 ? "" : "s"} (${daysUntilAdjustmentStr}) the difficulty will adjust upward: +${diffAdjPercent.toDP(1)}%`;
|
||||
var diffAdjSign = "+";
|
||||
var textColorClass = "text-success";
|
||||
}
|
||||
|
||||
res.locals.difficultyAdjustmentData = {
|
||||
estimateAvailable: !isNaN(diffAdjPercent),
|
||||
|
||||
blocksLeft: res.locals.blocksUntilDifficultyAdjustment,
|
||||
daysLeftStr: daysUntilAdjustmentStr,
|
||||
calculationBlockCount: heightDiff,
|
||||
currentEpoch: res.locals.difficultyPeriod,
|
||||
|
||||
delta: diffAdjPercent,
|
||||
sign: diffAdjSign
|
||||
|
||||
//nameDesc: `Estimate for the difficulty adjustment that will occur in ${res.locals.blocksUntilDifficultyAdjustment.toLocaleString()} block${res.locals.blocksUntilDifficultyAdjustment == 1 ? "" : "s"} (${daysUntilAdjustmentStr}). This is calculated using the average block time over the last ${heightDiff} block(s). This estimate becomes more reliable as the difficulty epoch nears its end.`,
|
||||
};
|
||||
|
||||
|
||||
res.render("index");
|
||||
|
||||
|
|
@ -270,7 +346,7 @@ router.get("/mempool-summary", asyncHandler(async (req, res, next) => {
|
|||
}));
|
||||
|
||||
promises.push(new Promise(async (resolve, reject) => {
|
||||
const mempooltxids = await utils.timePromise("promises.mempool-summary.getMempoolTxids", coreApi.getMempoolTxids());
|
||||
const mempooltxids = await utils.timePromise("promises.mempool-summary.getAllMempoolTxids", coreApi.getAllMempoolTxids());
|
||||
|
||||
var debugMaxCount = 0;
|
||||
|
||||
|
|
@ -404,9 +480,16 @@ router.get("/disconnect", function(req, res, next) {
|
|||
|
||||
router.get("/changeSetting", function(req, res, next) {
|
||||
if (req.query.name) {
|
||||
req.session[req.query.name] = req.query.value;
|
||||
if (!req.session.userSettings) {
|
||||
req.session.userSettings = {};
|
||||
}
|
||||
|
||||
res.cookie('user-setting-' + req.query.name, req.query.value);
|
||||
req.session.userSettings[req.query.name] = req.query.value;
|
||||
|
||||
var userSettings = JSON.parse(req.cookies["user-settings"] || "{}");
|
||||
userSettings[req.query.name] = req.query.value;
|
||||
|
||||
res.cookie("user-settings", JSON.stringify(userSettings));
|
||||
}
|
||||
|
||||
res.redirect(req.headers.referer);
|
||||
|
|
@ -878,6 +961,10 @@ router.get("/tx/:transactionId", asyncHandler(async (req, res, next) => {
|
|||
|
||||
var tx = rawTxResult.transactions[0];
|
||||
|
||||
res.locals.tx = tx;
|
||||
res.locals.isCoinbaseTx = tx.vin[0].coinbase;
|
||||
|
||||
|
||||
res.locals.result.getrawtransaction = tx;
|
||||
res.locals.result.txInputs = rawTxResult.txInputsByTransaction[txid] || {};
|
||||
|
||||
|
|
@ -917,12 +1004,22 @@ router.get("/tx/:transactionId", asyncHandler(async (req, res, next) => {
|
|||
next();
|
||||
|
||||
} catch (err) {
|
||||
res.locals.userMessageMarkdown = `Failed to load transaction: txid=**${txid}**`;
|
||||
if (global.prunedBlockchain && res.locals.blockHeight && res.locals.blockHeight < global.pruneHeight) {
|
||||
// Failure to load tx here is expected and a full description of the situation is given to the user
|
||||
// in the UI. No need to also show an error userMessage here.
|
||||
|
||||
if (!global.txindexAvailable) {
|
||||
} else if (!global.txindexAvailable) {
|
||||
res.locals.noTxIndexMsg = noTxIndexMsg;
|
||||
|
||||
// As above, failure to load the tx is expected here and good user feedback is given in the UI.
|
||||
// No need for error userMessage.
|
||||
|
||||
} else {
|
||||
res.locals.userMessageMarkdown = `Failed to load transaction: txid=**${txid}**`;
|
||||
}
|
||||
|
||||
|
||||
|
||||
utils.logError("1237y4ewssgt", err);
|
||||
|
||||
res.render("transaction");
|
||||
|
|
@ -1048,7 +1145,7 @@ router.get("/address/:address", function(req, res, next) {
|
|||
res.locals.txids = txids;
|
||||
|
||||
(global.txindexAvailable
|
||||
? coreApi.getRawTransactionsWithInputs(txids)
|
||||
? coreApi.getRawTransactionsWithInputs(txids, 5)
|
||||
: coreApi.getRawTransactionsByHeights(txids, blockHeightsByTxid)
|
||||
.then(transactions => ({ transactions, txInputsByTransaction: {} }))
|
||||
).then(function(rawTxResult) {
|
||||
|
|
@ -1471,43 +1568,76 @@ router.post("/terminal", function(req, res, next) {
|
|||
}
|
||||
});
|
||||
|
||||
router.get("/unconfirmed-tx", function(req, res, next) {
|
||||
var limit = config.site.browseBlocksPageSize;
|
||||
var offset = 0;
|
||||
var sort = "desc";
|
||||
router.get("/mempool-tx", asyncHandler(async (req, res, next) => {
|
||||
try {
|
||||
var limit = config.site.browseBlocksPageSize;
|
||||
var offset = 0;
|
||||
var sort = "desc";
|
||||
|
||||
if (req.query.limit) {
|
||||
limit = parseInt(req.query.limit);
|
||||
}
|
||||
if (req.query.limit) {
|
||||
limit = parseInt(req.query.limit);
|
||||
}
|
||||
|
||||
if (req.query.offset) {
|
||||
offset = parseInt(req.query.offset);
|
||||
}
|
||||
if (req.query.offset) {
|
||||
offset = parseInt(req.query.offset);
|
||||
}
|
||||
|
||||
if (req.query.sort) {
|
||||
sort = req.query.sort;
|
||||
}
|
||||
if (req.query.sort) {
|
||||
sort = req.query.sort;
|
||||
}
|
||||
|
||||
res.locals.limit = limit;
|
||||
res.locals.offset = offset;
|
||||
res.locals.sort = sort;
|
||||
res.locals.paginationBaseUrl = "./unconfirmed-tx";
|
||||
res.locals.limit = limit;
|
||||
res.locals.offset = offset;
|
||||
res.locals.sort = sort;
|
||||
res.locals.paginationBaseUrl = "./mempool-tx";
|
||||
|
||||
coreApi.getMempoolDetails(offset, limit).then(function(mempoolDetails) {
|
||||
res.locals.mempoolDetails = mempoolDetails;
|
||||
const mempoolData = await utils.timePromise("promises.mempool-tx.getMempoolTxids", coreApi.getMempoolTxids(limit, offset));
|
||||
|
||||
res.render("unconfirmed-transactions");
|
||||
const txids = mempoolData.txids;
|
||||
res.locals.txCount = mempoolData.txCount;
|
||||
|
||||
|
||||
const promises = [];
|
||||
|
||||
promises.push(new Promise(async (resolve, reject) => {
|
||||
const transactionData = await utils.timePromise("promises.mempool-tx.getRawTransactionsWithInputs", coreApi.getRawTransactionsWithInputs(txids, 5));
|
||||
|
||||
res.locals.transactions = transactionData.transactions;
|
||||
res.locals.txInputsByTransaction = transactionData.txInputsByTransaction;
|
||||
|
||||
resolve();
|
||||
}));
|
||||
|
||||
res.locals.mempoolDetailsByTxid = {};
|
||||
|
||||
txids.forEach(txid => {
|
||||
promises.push(new Promise(async (resolve, reject) => {
|
||||
const mempoolTxidDetails = await utils.timePromise("promises.mempool-tx.getMempoolTxDetails", coreApi.getMempoolTxDetails(txid, false));
|
||||
|
||||
res.locals.mempoolDetailsByTxid[txid] = mempoolTxidDetails;
|
||||
|
||||
resolve();
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
|
||||
res.render("mempool-tx");
|
||||
|
||||
next();
|
||||
|
||||
}).catch(function(err) {
|
||||
res.locals.userMessage = "Error: " + err;
|
||||
} catch (err) {
|
||||
utils.logError("3297gfsdyde3q", err);
|
||||
|
||||
res.locals.userMessage = "Error building page: " + err;
|
||||
|
||||
res.render("unconfirmed-transactions");
|
||||
res.render("mempool-tx");
|
||||
|
||||
next();
|
||||
});
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
router.get("/tx-stats", function(req, res, next) {
|
||||
var dataPoints = 100;
|
||||
|
|
|
|||
|
|
@ -11,73 +11,55 @@ block content
|
|||
span.font-monospace #{address}
|
||||
|
||||
else
|
||||
h1.h3 Address
|
||||
br
|
||||
small.font-monospace #{address}
|
||||
.clearfix
|
||||
.float-start
|
||||
+pageTitle("Address", address, true)
|
||||
|
||||
.float-start.float-md-end.mb-3.mb-md-0
|
||||
img(src=addressQrCodeUrl, alt=address, style="border: solid 1px #ccc;")
|
||||
|
||||
|
||||
hr
|
||||
|
||||
if (payoutAddressForMiner)
|
||||
div.alert.alert-primary.shadow-sm.pb-0
|
||||
div.float-start(style="width: 50px; height: 50px; font-size: 18px;")
|
||||
i.fas.fa-certificate.fa-2x(style="margin-top: 10px;")
|
||||
|
||||
h4.alert-heading.h6.fw-bold #{coinConfig.name} Fun
|
||||
|
||||
p
|
||||
span This looks like a miner payout address for
|
||||
span.fw-bold #{payoutAddressForMiner.name}
|
||||
if (coinConfig.miningPoolsConfigUrls.length > 1)
|
||||
span (see the configurations:
|
||||
each item, index in coinConfig.miningPoolsConfigUrls
|
||||
if (index > 0)
|
||||
span ,
|
||||
a(href=item) config ##{index + 1}
|
||||
span )
|
||||
else
|
||||
span (see the configuration
|
||||
a(href=coinConfig.miningPoolsConfigUrls[0]) here
|
||||
span )
|
||||
|
||||
else if (global.specialAddresses[address] && global.specialAddresses[address].type == "fun")
|
||||
div.alert.alert-primary.shadow-sm.pb-0
|
||||
div.float-start(style="width: 50px; height: 50px; font-size: 18px;")
|
||||
i.fas.fa-certificate.fa-2x(style="margin-top: 10px;")
|
||||
|
||||
h4.alert-heading.h6.fw-bold #{coinConfig.name} Fun
|
||||
|
||||
// special address info
|
||||
- var saInfo = global.specialAddresses[address].addressInfo;
|
||||
if (saInfo.alertBodyHtml)
|
||||
p
|
||||
span !{saInfo.alertBodyHtml}
|
||||
|
||||
if (saInfo.referenceUrl && saInfo.referenceUrl.trim().length > 0 && saInfo.alertBodyHtml.indexOf(saInfo.referenceUrl) == -1)
|
||||
span
|
||||
a(href=saInfo.referenceUrl) Read more
|
||||
|
||||
else
|
||||
p
|
||||
span #{saInfo.summary}
|
||||
|
||||
if (saInfo.referenceUrl && saInfo.referenceUrl.trim().length > 0)
|
||||
span
|
||||
a(href=saInfo.referenceUrl) Read more
|
||||
|
||||
|
||||
if (false)
|
||||
pre
|
||||
code.json.bg-light #{JSON.stringify(addressObj, null, 4)}
|
||||
|
||||
ul.nav.nav-tabs.mb-3
|
||||
li.nav-item
|
||||
a.nav-link.active(data-bs-toggle="tab", href="#tab-details", role="tab") Details
|
||||
li.nav-item
|
||||
a.nav-link(data-bs-toggle="tab", href="#tab-json", role="tab") JSON
|
||||
code.json #{JSON.stringify(addressObj, null, 4)}
|
||||
|
||||
|
||||
div.tab-content
|
||||
div.tab-pane.active(id="tab-details", role="tabpanel")
|
||||
+pageTabs(["Details", "JSON"])
|
||||
|
||||
|
||||
.tab-content
|
||||
+pageTab("Details", true)
|
||||
|
||||
if (payoutAddressForMiner)
|
||||
+funAlert
|
||||
span This looks like a miner payout address for
|
||||
span.fw-bold #{payoutAddressForMiner.name}
|
||||
if (coinConfig.miningPoolsConfigUrls.length > 1)
|
||||
span (see the miner-identifications configurations:
|
||||
each item, index in coinConfig.miningPoolsConfigUrls
|
||||
if (index > 0)
|
||||
span ,
|
||||
a(href=item) config ##{index + 1}
|
||||
span )
|
||||
else
|
||||
span (see the configuration
|
||||
a(href=coinConfig.miningPoolsConfigUrls[0]) here
|
||||
span )
|
||||
|
||||
|
||||
else if (global.specialAddresses[address] && global.specialAddresses[address].type == "fun")
|
||||
- var saInfo = global.specialAddresses[address].addressInfo;
|
||||
|
||||
+funAlert(saInfo.alertBodyHtml, saInfo.summary, saInfo.referenceUrl)
|
||||
|
||||
|
||||
.clearfix
|
||||
.float-end
|
||||
if (`${userSettings["addressPageShowTechDetails"]}` == "false")
|
||||
a.btn.btn-primary.btn-sm.me-2(href=`./changeSetting?name=addressPageShowTechDetails&value=true`, title="Display technical details for this address.", data-bs-toggle="tooltip")
|
||||
i.far.fa-plus-square.me-2
|
||||
| Technical Details
|
||||
|
||||
|
||||
if (false && config.electrumXServers && config.electrumXServers.length > 0)
|
||||
if (session.hideElectrumTrustWarnings != "true")
|
||||
|
|
@ -87,219 +69,156 @@ block content
|
|||
a.close(href="./changeSetting?name=hideElectrumTrustWarnings&value=true", aria-label="Close", style="text-decoration: none;")
|
||||
span(aria-hidden="true") ×
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Summary
|
||||
|
||||
- var x = result.validateaddress;
|
||||
- var flags = [];
|
||||
- if (x.ismine) { flags.push(["Mine", "This address is owned by your node."]); }
|
||||
- if (x.iswatchonly) { flags.push(["Watch-Only"]); }
|
||||
|
||||
if (addressDetails || flags.length > 0)
|
||||
.clearfix
|
||||
.float-start
|
||||
+sectionTitle("Summary")
|
||||
.float-start
|
||||
if (config.addressApi)
|
||||
small.text-muted.border-dotted.ms-2(title=`Some details for this address were queried from ${config.addressApi}` data-bs-toggle="tooltip") Trust Note
|
||||
hr
|
||||
|
||||
+contentSection
|
||||
|
||||
|
||||
|
||||
div.row
|
||||
div.col-md-6
|
||||
+summaryRow((addressDetails ? ((addressDetails.txCount != null ? 1 : 0) + (addressDetails.balanceSat ? 1 : 0) + (addressDetails.unconfirmedBalanceSat ? 1 : 0) + (addressDetails.totalReceivedSat ? 1 : 0)) : 0) + (flags.length > 0 ? 1 : 0))
|
||||
if (addressDetails && addressDetails.txCount != null)
|
||||
+summaryItem("Transactions")
|
||||
| #{addressDetails.txCount.toLocaleString()}
|
||||
|
||||
if (addressObj.hash)
|
||||
div.row
|
||||
div.summary-split-table-label Hash 160
|
||||
div.summary-split-table-content.font-monospace #{addressObj.hash.toString("hex")}
|
||||
if (addressDetails && addressDetails.balanceSat)
|
||||
+summaryItem("Balance")
|
||||
span(class=(addressDetails.balanceSat > 0 ? "text-success" : false))
|
||||
- var currencyValue = new Decimal(addressDetails.balanceSat).dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include includes/value-display.pug
|
||||
|
||||
if (result.validateaddress.scriptPubKey)
|
||||
div.row
|
||||
div.summary-split-table-label Script Public Key
|
||||
div.summary-split-table-content.font-monospace #{result.validateaddress.scriptPubKey}
|
||||
|
||||
if (addressObj.hasOwnProperty("version"))
|
||||
div.row
|
||||
div.summary-split-table-label Version
|
||||
div.summary-split-table-content.font-monospace #{addressObj.version}
|
||||
|
||||
if (result.validateaddress.hasOwnProperty("witness_version"))
|
||||
div.row
|
||||
div.summary-split-table-label Witness Version
|
||||
div.summary-split-table-content.font-monospace #{result.validateaddress.witness_version}
|
||||
|
||||
if (result.validateaddress.witness_program)
|
||||
div.row
|
||||
div.summary-split-table-label Witness Program
|
||||
div.summary-split-table-content.font-monospace #{result.validateaddress.witness_program}
|
||||
|
||||
if (firstSeenTransaction && firstSeenTransaction.confirmations > 0)
|
||||
div.row
|
||||
div.summary-split-table-label First Seen
|
||||
div.summary-split-table-content.font-monospace
|
||||
if (getblockchaininfo)
|
||||
span Block ##{(getblockchaininfo.blocks - firstSeenTransaction.confirmations).toLocaleString()}
|
||||
else
|
||||
a(href=`./block/${firstSeenTransaction.blockhash}`) #{firstSeenTransaction.blockhash}
|
||||
|
||||
br
|
||||
|
||||
span #{moment.utc(new Date(firstSeenTransaction.time * 1000)).format("Y-MM-DD HH:mm:ss")} utc
|
||||
- var timeAgoTime = firstSeenTransaction.time;
|
||||
include includes/time-ago.pug
|
||||
|
||||
if (false)
|
||||
pre
|
||||
code.json.bg-light #{JSON.stringify(firstSeenTransaction)}
|
||||
|
||||
if (balance)
|
||||
if (balance.conflictedResults)
|
||||
div.row
|
||||
div.summary-split-table-label Balance
|
||||
div.summary-split-table-content.font-monospace
|
||||
span.text-warning Conflicted ElectrumX Results
|
||||
|
||||
each item in balance.conflictedResults
|
||||
- var currencyValue = item.confirmed / coinConfig.baseCurrencyUnit.multiplier;
|
||||
include includes/value-display.pug
|
||||
|
||||
|
||||
else
|
||||
div.row
|
||||
div.summary-split-table-label Balance
|
||||
div.summary-split-table-content.font-monospace
|
||||
- var currencyValue = balance.result.confirmed / coinConfig.baseCurrencyUnit.multiplier;
|
||||
include includes/value-display.pug
|
||||
|
||||
if (balance.unconfirmed)
|
||||
div.row
|
||||
div.summary-split-table-label Unconfirmed
|
||||
div.summary-split-table-content.font-monospace
|
||||
- var currencyValue = balance.unconfirmed / coinConfig.baseCurrencyUnit.multiplier;
|
||||
include includes/value-display.pug
|
||||
|
||||
if (addressDetails && addressDetails.balanceSat)
|
||||
div.row
|
||||
div.summary-split-table-label Balance
|
||||
div.summary-split-table-content.font-monospace
|
||||
- var currencyValue = new Decimal(addressDetails.balanceSat).dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include includes/value-display.pug
|
||||
|
||||
if (addressDetails && addressDetails.unconfirmedBalanceSat)
|
||||
div.row
|
||||
div.summary-split-table-label Pending Balance
|
||||
div.summary-split-table-content.font-monospace
|
||||
- var currencyValue = new Decimal(addressDetails.unconfirmedBalanceSat).dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include includes/value-display.pug
|
||||
|
||||
if (addressDetails && addressDetails.txCount)
|
||||
div.row
|
||||
div.summary-split-table-label Transactions
|
||||
div.summary-split-table-content.font-monospace #{addressDetails.txCount.toLocaleString()}
|
||||
|
||||
div.row
|
||||
div.summary-split-table-label QR Code
|
||||
div.summary-split-table-content.font-monospace
|
||||
img(src=addressQrCodeUrl, alt=address, style="border: solid 1px #ccc;")
|
||||
|
||||
div.col-md-6
|
||||
if (electrumScripthash)
|
||||
div.row
|
||||
div.summary-split-table-label Scripthash
|
||||
div.summary-split-table-content.font-monospace #{electrumScripthash}
|
||||
|
||||
- var x = result.validateaddress;
|
||||
- var flagNames = ["Is Valid?", "Is Script?", "Is Witness?", "Is Mine?", "Is Watch-Only?"];
|
||||
- var flags = [x.isvalid, x.isscript, x.iswitness, x.ismine, x.iswatchonly];
|
||||
|
||||
each flagName, index in flagNames
|
||||
div.row
|
||||
div.summary-split-table-label #{flagName}
|
||||
div.summary-split-table-content.font-monospace
|
||||
if (flags[index])
|
||||
i.fas.fa-check.text-success
|
||||
else
|
||||
i.fas.fa-times.text-warning
|
||||
|
||||
if (false)
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-header
|
||||
span.h6 Flags
|
||||
div.card-body
|
||||
div.table-responsive
|
||||
table.table.text-center
|
||||
thead
|
||||
tr
|
||||
th Is Valid?
|
||||
th Is Script?
|
||||
th Is Witness?
|
||||
th Is Mine?
|
||||
th Is Watch-Only?
|
||||
tbody
|
||||
tr
|
||||
- var x = result.validateaddress;
|
||||
- var flags = [x.isvalid, x.isscript, x.iswitness, x.ismine, x.iswatchonly];
|
||||
|
||||
each flag in flags
|
||||
td
|
||||
if (flag)
|
||||
i.fas.fa-check.text-success
|
||||
else
|
||||
i.fas.fa-times.text-warning
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
div.clearfix
|
||||
div.float-start
|
||||
h3.h6.mb-0
|
||||
if (addressDetails && addressDetails.txCount)
|
||||
if (addressDetails.txCount == 1)
|
||||
span 1 Transaction
|
||||
if (addressDetails && addressDetails.unconfirmedBalanceSat)
|
||||
+summaryItem("Unconfirmed Balance")
|
||||
span(class=(addressDetails.unconfirmedBalanceSat > 0 ? "text-success" : "text-danger"))
|
||||
if (addressDetails.unconfirmedBalanceSat > 0)
|
||||
span +
|
||||
else
|
||||
span #{addressDetails.txCount.toLocaleString()} Transactions
|
||||
span -
|
||||
|
||||
- var currencyValue = new Decimal(Math.abs(addressDetails.unconfirmedBalanceSat)).dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include includes/value-display.pug
|
||||
|
||||
if (addressDetails && addressDetails.totalReceivedSat)
|
||||
+summaryItem("Total Received / Sent")
|
||||
span(class=(addressDetails.totalReceivedSat > 0 ? "text-success" : false))
|
||||
if (addressDetails.totalReceivedSat)
|
||||
span +
|
||||
|
||||
- var currencyValue = new Decimal(Math.abs(addressDetails.totalReceivedSat)).dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include includes/value-display.pug
|
||||
|
||||
br
|
||||
span(class=(addressDetails.totalSentSat > 0 ? "text-danger" : false))
|
||||
if (addressDetails.totalSentSat > 0)
|
||||
span -
|
||||
|
||||
- var currencyValue = new Decimal(Math.abs(addressDetails.totalSentSat)).dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include includes/value-display.pug
|
||||
|
||||
if (flags.length > 0)
|
||||
+summaryItem("Flags")
|
||||
each flagItem, flagIndex in flags
|
||||
span.badge.bg-primary(class=(flagIndex > 0 ? "ms-1" : false), title=(flagItem.length > 1 ? flagItem[1] : false), data-bs-toggle=(flagItem.length > 1 ? "tooltip" : false)) #{flagItem[0]}
|
||||
|
||||
+contentSection("Technical Details", true, "addressPageShowTechDetails")
|
||||
+summaryRow(1 + (addressObj.hash ? 1 : 0) + (addressObj.hasOwnProperty("version") ? 1 : 0) + (result.validateaddress.hasOwnProperty("witness_version") ? 1 : 0) + (result.validateaddress.witness_program ? 1 : 0) + (electrumScripthash ? 1 : 0))
|
||||
if (addressObj.hasOwnProperty("version"))
|
||||
+summaryItem("Version")
|
||||
| #{addressObj.version}
|
||||
|
||||
if (addressObj.hash)
|
||||
+summaryItem("Hash 160")
|
||||
| #{utils.ellipsizeMiddle(addressObj.hash.toString("hex"), 12)}
|
||||
+copyTextButton(addressObj.hash.toString("hex"))
|
||||
|
||||
+summaryItem("Script Pub Key")
|
||||
| #{utils.ellipsizeMiddle(result.validateaddress.scriptPubKey, 12)}
|
||||
+copyTextButton(result.validateaddress.scriptPubKey)
|
||||
|
||||
if (result.validateaddress.hasOwnProperty("witness_version"))
|
||||
+summaryItem("Witness Version")
|
||||
| #{result.validateaddress.witness_version}
|
||||
|
||||
if (result.validateaddress.witness_program)
|
||||
+summaryItem("Witness Program")
|
||||
| #{utils.ellipsizeMiddle(result.validateaddress.witness_program, 12)}
|
||||
+copyTextButton(result.validateaddress.witness_program)
|
||||
|
||||
if (electrumScripthash)
|
||||
+summaryItem("Script Hash", "Electrum-lookup script hash")
|
||||
| #{utils.ellipsizeMiddle(electrumScripthash, 12)}
|
||||
+copyTextButton(electrumScripthash)
|
||||
|
||||
|
||||
|
||||
.clearfix
|
||||
.float-start
|
||||
+sectionTitle(addressDetails && addressDetails.txCount ? `${addressDetails.txCount.toLocaleString()} Transaction${addressDetails.txCount == 1 ? "" : "s"}` : "Transactions")
|
||||
.float-start
|
||||
if (config.addressApi)
|
||||
if (config.addressApi == "electrumx")
|
||||
small.text-muted.border-dotted.ms-2(title=`The list of transaction IDs for this address was queried from ElectrumX (using the configured server(s))` data-bs-toggle="tooltip") Trust Note
|
||||
else
|
||||
small.text-muted.border-dotted.ms-2(title=`The list of transaction IDs for this address was queried from ${config.addressApi}` data-bs-toggle="tooltip") Trust Note
|
||||
|
||||
.float-end
|
||||
if (!crawlerBot && txids && txids.length > 1 && addressApiSupport.sortDesc && addressApiSupport.sortAsc)
|
||||
div.float-end
|
||||
a.pull-right.dropdown-toggle(href="#", data-bs-toggle="dropdown", aria-haspopup="true", aria-expanded="false")
|
||||
if (sort == "desc")
|
||||
span Newest First
|
||||
else
|
||||
span Transactions
|
||||
span Oldest First
|
||||
|
||||
if (config.addressApi)
|
||||
if (config.addressApi == "electrumx")
|
||||
small.text-muted.border-dotted.ms-2(title=`The list of transaction IDs for this address was queried from ElectrumX (using the configured server(s))` data-bs-toggle="tooltip") Trust Note
|
||||
else
|
||||
small.text-muted.border-dotted.ms-2(title=`The list of transaction IDs for this address was queried from ${config.addressApi}` data-bs-toggle="tooltip") Trust Note
|
||||
|
||||
if (!crawlerBot && txids && txids.length > 1 && addressApiSupport.sortDesc && addressApiSupport.sortAsc)
|
||||
div.float-end
|
||||
a.pull-right.dropdown-toggle(href="#", data-bs-toggle="dropdown", aria-haspopup="true", aria-expanded="false")
|
||||
div.dropdown-menu.dropdown-menu-end
|
||||
a.dropdown-item(href=`./address/${address}`)
|
||||
if (sort == "desc")
|
||||
span Newest First
|
||||
else
|
||||
span Oldest First
|
||||
i.fa.fa-check
|
||||
span Newest First
|
||||
a.dropdown-item(href=`./address/${address}?sort=asc`)
|
||||
if (sort != "desc")
|
||||
i.fa.fa-check
|
||||
span Oldest First
|
||||
|
||||
div.dropdown-menu.dropdown-menu-end
|
||||
a.dropdown-item(href=`./address/${address}`)
|
||||
if (sort == "desc")
|
||||
i.fa.fa-check
|
||||
span Newest First
|
||||
a.dropdown-item(href=`./address/${address}?sort=asc`)
|
||||
if (sort != "desc")
|
||||
i.fa.fa-check
|
||||
span Oldest First
|
||||
else if (txids && txids.length > 1 && addressApiSupport.sortDesc && !addressApiSupport.sortAsc)
|
||||
div.float-end
|
||||
span.text-muted Newest First
|
||||
|
||||
else if (txids && txids.length > 1 && addressApiSupport.sortDesc && !addressApiSupport.sortAsc)
|
||||
div.float-end
|
||||
span.text-muted Newest First
|
||||
|
||||
hr
|
||||
|
||||
if (conflictedTxidResults)
|
||||
div.alert.alert-warning.pb-0
|
||||
div.float-start(style="width: 55px; height: 50px; font-size: 18px;")
|
||||
i.fas.fa-exclamation-triangle.fa-2x(style="margin-top: 10px;")
|
||||
h4.alert-heading.h6.fw-bold Trust Warning
|
||||
p
|
||||
span The transaction history for this address was requested from mulitple ElectrumX servers and the results did not match. The results below were obtained only from
|
||||
span.fw-bold #{electrumHistory.server}
|
||||
+contentSection(null, false, null, true, false)
|
||||
if (conflictedTxidResults)
|
||||
div.alert.alert-warning.pb-0
|
||||
div.float-start(style="width: 55px; height: 50px; font-size: 18px;")
|
||||
i.fas.fa-exclamation-triangle.fa-2x(style="margin-top: 10px;")
|
||||
h4.alert-heading.h6.fw-bold Trust Warning
|
||||
p
|
||||
span The transaction history for this address was requested from mulitple ElectrumX servers and the results did not match. The results below were obtained only from
|
||||
span.fw-bold #{electrumHistory.server}
|
||||
|
||||
|
||||
if (true)
|
||||
if (addressApiError && addressApiError.error && addressApiError.error.code && addressApiError.error.code == -32600)
|
||||
span Failed to retrieve transaction history from ElectrumX. See
|
||||
a(href="https://github.com/janoside/btc-rpc-explorer/issues/67") Issue #67
|
||||
span for more information.
|
||||
if (true)
|
||||
if (addressApiError && addressApiError.error && addressApiError.error.code && addressApiError.error.code == -32600)
|
||||
span Failed to retrieve transaction history from ElectrumX. See
|
||||
a(href="https://github.com/janoside/btc-rpc-explorer/issues/67") Issue #67
|
||||
span for more information.
|
||||
|
||||
|
||||
else if (addressApiError && addressApiError.userText)
|
||||
else if (addressApiError && addressApiError.userText)
|
||||
+contentSection
|
||||
div.text-danger Error: #{addressApiError.userText}
|
||||
|
||||
else if (addressDetailsErrors && addressDetailsErrors.length > 0)
|
||||
else if (addressDetailsErrors && addressDetailsErrors.length > 0)
|
||||
+contentSection
|
||||
each err, errIndex in addressDetailsErrors
|
||||
if (err.e && err.e && err.e.message == "history too large")
|
||||
span Failed to retrieve transaction history from ElectrumX because this address is involved in too many transactions (more than ElectrumX currently supports retrieving). See
|
||||
|
|
@ -307,16 +226,18 @@ block content
|
|||
span for more information.
|
||||
|
||||
else if (err == "No address API configured")
|
||||
span No address API is configured. See
|
||||
a(href="https://github.com/janoside/btc-rpc-explorer/blob/master/.env-sample") the example configuration file
|
||||
span for help setting up an address API if desired.
|
||||
.mb-2 No address API is configured.
|
||||
.mb-0 See
|
||||
| <a href="https://github.com/janoside/btc-rpc-explorer/blob/master/.env-sample">the example configuration file</a>
|
||||
| for help setting up an address API.
|
||||
|
||||
else
|
||||
span.text-danger Error retrieving transaction history (##{errIndex + 1})
|
||||
pre
|
||||
code.json #{JSON.stringify(err, null, 4)}
|
||||
|
||||
else if (!global.txindexAvailable && transactions.length == 0)
|
||||
else if (!global.txindexAvailable && transactions.length == 0)
|
||||
+contentSection
|
||||
table.table.table-striped
|
||||
each txid, txidIndex in txids
|
||||
tr
|
||||
|
|
@ -327,116 +248,29 @@ block content
|
|||
- var blockHeightParam = blockHeight > 0 ? `@${blockHeight}` : "";
|
||||
a(href=`./tx/${txid}${blockHeightParam}`) #{txid}
|
||||
|
||||
else if (transactions.length == 0)
|
||||
else if (transactions.length == 0)
|
||||
+contentSection
|
||||
span No transactions found
|
||||
|
||||
each tx, txIndex in transactions
|
||||
//pre
|
||||
// code.json.bg-light #{JSON.stringify(tx, null, 4)}
|
||||
div.card.shadow-sm(class=((txIndex < (transactions.length - 1) || txids.length > limit) ? "mb-3" : ""))
|
||||
div.card-header.font-monospace.clearfix
|
||||
div.float-start.me-0
|
||||
if (sort == "desc")
|
||||
span ##{(addressDetails.txCount - offset - txIndex).toLocaleString()}
|
||||
else
|
||||
span ##{(offset + txIndex + 1).toLocaleString()}
|
||||
span –
|
||||
|
||||
div.row
|
||||
div.col-md-8
|
||||
if (tx && tx.txid)
|
||||
- var blockHeight = addressDetails.blockHeightsByTxid[tx.txid];
|
||||
- var blockHeightParam = !global.txindexAvailable && blockHeight > 0 ? `@${blockHeight}` : "";
|
||||
a(href=`./tx/${tx.txid}${blockHeightParam}`) #{tx.txid}
|
||||
|
||||
if (global.specialTransactions && global.specialTransactions[tx.txid])
|
||||
span
|
||||
a(data-bs-toggle="tooltip", title=`${coinConfig.name} Fun! See transaction for details`)
|
||||
i.fas.fa-certificate.text-primary
|
||||
|
||||
br
|
||||
|
||||
if (addrGainsByTx[tx.txid])
|
||||
- var currencyValue = addrGainsByTx[tx.txid];
|
||||
span.text-success +
|
||||
include includes/value-display.pug
|
||||
|
||||
if (addrLossesByTx[tx.txid])
|
||||
span /
|
||||
|
||||
if (addrLossesByTx[tx.txid])
|
||||
- var currencyValue = addrLossesByTx[tx.txid];
|
||||
span.text-danger -
|
||||
include includes/value-display.pug
|
||||
|
||||
div.col-md-4
|
||||
div.text-md-end
|
||||
if (tx.time)
|
||||
- var timestampHuman = tx.time;
|
||||
include includes/timestamp-human.pug
|
||||
|
||||
br
|
||||
|
||||
- var timeAgoTime = tx.time;
|
||||
small.text-muted (
|
||||
include includes/time-ago-text.pug
|
||||
span ago)
|
||||
|
||||
else
|
||||
span.text-danger Unconfirmed
|
||||
|
||||
div.card-body
|
||||
if (true)
|
||||
- var txInputs = txInputsByTransaction[tx.txid];
|
||||
- var blockHeight = blockHeightsByTxid[tx.txid];
|
||||
- var txIOHighlightAddress = address;
|
||||
|
||||
include includes/transaction-io-details.pug
|
||||
|
||||
else
|
||||
p Since this explorer is database-free, it doesn't natively support address transaction history. However, you can configure it to communicate with one or more ElectrumX servers to build and display this data. In doing so, you should be aware that you'll be trusting those ElectrumX servers. If you configure multiple servers the results obtained from each will be cross-referenced against the others. Communicating with ElectrumX servers will also impact your privacy since the servers will know what addresses you're interested in. If these tradeoffs are acceptable, you can see a list of public ElectrumX servers here:
|
||||
a(href="https://uasf.saltylemon.org/electrum") https://uasf.saltylemon.org/electrum
|
||||
- var txIOHighlightAddress = address;
|
||||
- var options = {blockHeightsByTxid: blockHeightsByTxid, showDates: true, highlightAddress: address, addrGainsByTxid: addrGainsByTx, addrLossesByTxid: addrLossesByTx};
|
||||
+txList(transactions, addressDetails.txCount, limit, offset, txInputsByTransaction, options)
|
||||
|
||||
|
||||
if (false)
|
||||
pre
|
||||
code.json.bg-light #{JSON.stringify(transactions, null, 4)}
|
||||
|
||||
if (!crawlerBot && addressDetails && addressDetails.txCount > limit)
|
||||
- var txCount = addressDetails.txCount;
|
||||
- var pageNumber = offset / limit + 1;
|
||||
- var pageCount = Math.floor(txCount / limit);
|
||||
- if (pageCount * limit < txCount) {
|
||||
- pageCount++;
|
||||
- }
|
||||
- var paginationUrlFunction = function(x) {
|
||||
- return paginationBaseUrl + "&limit=" + limit + "&offset=" + ((x - 1) * limit);
|
||||
- }
|
||||
|
||||
hr.mt-3
|
||||
|
||||
include includes/pagination.pug
|
||||
|
||||
|
||||
|
||||
|
||||
div.tab-pane(id="tab-json", role="tabpanel")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6.mb-0 validateaddress
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light(data-lang="json") #{JSON.stringify(result.validateaddress, null, 4)}
|
||||
+pageTab("JSON")
|
||||
+contentSection("validateaddress")
|
||||
pre
|
||||
code.json #{JSON.stringify(result.validateaddress, null, 4)}
|
||||
|
||||
|
||||
if (addressDetails)
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6.mb-0 addressDetails
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light #{JSON.stringify(addressDetails, null, 4)}
|
||||
+contentSection("addressDetails")
|
||||
pre
|
||||
code.json #{JSON.stringify(addressDetails, null, 4)}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,137 +4,169 @@ block headContent
|
|||
title Admin Dashboard
|
||||
|
||||
block content
|
||||
h1.h3 Admin Dashboard
|
||||
hr
|
||||
+pageTitle("Admin Dashboard")
|
||||
|
||||
ul.nav.nav-tabs.mb-3
|
||||
li.nav-item
|
||||
a.nav-link.active(data-bs-toggle="tab", href="#tab-details", role="tab") Details
|
||||
li.nav-item
|
||||
a.nav-link(data-bs-toggle="tab", href="#tab-json", role="tab") JSON
|
||||
+pageTabs(["Details", "JSON"])
|
||||
|
||||
div.tab-content
|
||||
div.tab-pane.active(id="tab-details", role="tabpanel")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6 Basics
|
||||
hr
|
||||
.tab-content
|
||||
+pageTab("Details", true)
|
||||
|
||||
div.clearfix
|
||||
div.row
|
||||
div.summary-table-label Uptime
|
||||
div.summary-table-content.font-monospace
|
||||
- var uptime = moment.duration(new Date().getTime() - appStartTime);
|
||||
span #{uptime.format()}
|
||||
+contentSection("Tools")
|
||||
a.btn.btn-primary(href="./admin/resetUserSettings") Reset User Settings
|
||||
|
||||
div.row
|
||||
div.summary-table-label Node Version
|
||||
div.summary-table-content.font-monospace
|
||||
span #{global.nodeVersion}
|
||||
+contentSection("Basics")
|
||||
+summaryRow(3)
|
||||
+summaryItem("Uptime")
|
||||
- var uptime = moment.duration(new Date().getTime() - appStartTime);
|
||||
| #{uptime.format()}
|
||||
|
||||
div.row
|
||||
div.summary-table-label Node Env
|
||||
div.summary-table-content.font-monospace
|
||||
span #{process.env.NODE_ENV || "development"}
|
||||
+summaryItem("Node Version")
|
||||
| #{global.nodeVersion}
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6 App Config
|
||||
hr
|
||||
+summaryItem("Node Env")
|
||||
| #{process.env.NODE_ENV || "development"}
|
||||
|
||||
pre
|
||||
code.json #{JSON.stringify(appConfig, null, 4)}
|
||||
+contentSection("User Settings")
|
||||
pre
|
||||
code.json #{JSON.stringify(userSettings, null, 4)}
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6 Memory Stats
|
||||
hr
|
||||
+contentSection("App Config")
|
||||
pre
|
||||
code.json #{JSON.stringify(appConfig, null, 4)}
|
||||
|
||||
div.table-responsive
|
||||
table.table.table-borderless.table-hover
|
||||
thead
|
||||
tr
|
||||
th.text-end Heap Size
|
||||
th.text-end Used Heap
|
||||
th.text-end Heap Limit
|
||||
th.text-end Physical Size
|
||||
th.text-end Available Size
|
||||
+contentSection("Memory Stats")
|
||||
.table-responsive
|
||||
table.table.table-borderless.table-hover.table-striped
|
||||
thead
|
||||
tr
|
||||
th.text-end Heap Size
|
||||
th.text-end Used Heap
|
||||
th.text-end Heap Limit
|
||||
th.text-end Physical Size
|
||||
th.text-end Available Size
|
||||
|
||||
tbody
|
||||
tr.text-end.font-monospace
|
||||
td
|
||||
- var data = utils.formatLargeNumber(memstats.total_heap_size, 2);
|
||||
span #{data[0]}
|
||||
small #{data[1].abbreviation}B
|
||||
tbody
|
||||
tr.text-end.font-monospace
|
||||
td
|
||||
- var data = utils.formatLargeNumber(memstats.total_heap_size, 2);
|
||||
span #{data[0]}
|
||||
small #{data[1].abbreviation}B
|
||||
|
||||
td
|
||||
- var data = utils.formatLargeNumber(memstats.used_heap_size, 2);
|
||||
span #{data[0]}
|
||||
small #{data[1].abbreviation}B
|
||||
td
|
||||
- var data = utils.formatLargeNumber(memstats.used_heap_size, 2);
|
||||
span #{data[0]}
|
||||
small #{data[1].abbreviation}B
|
||||
|
||||
td
|
||||
- var data = utils.formatLargeNumber(memstats.heap_size_limit, 2);
|
||||
span #{data[0]}
|
||||
small #{data[1].abbreviation}B
|
||||
td
|
||||
- var data = utils.formatLargeNumber(memstats.heap_size_limit, 2);
|
||||
span #{data[0]}
|
||||
small #{data[1].abbreviation}B
|
||||
|
||||
td
|
||||
- var data = utils.formatLargeNumber(memstats.total_physical_size, 2);
|
||||
span #{data[0]}
|
||||
small #{data[1].abbreviation}B
|
||||
td
|
||||
- var data = utils.formatLargeNumber(memstats.total_physical_size, 2);
|
||||
span #{data[0]}
|
||||
small #{data[1].abbreviation}B
|
||||
|
||||
td
|
||||
- var data = utils.formatLargeNumber(memstats.total_available_size, 2);
|
||||
span #{data[0]}
|
||||
small #{data[1].abbreviation}B
|
||||
td
|
||||
- var data = utils.formatLargeNumber(memstats.total_available_size, 2);
|
||||
span #{data[0]}
|
||||
small #{data[1].abbreviation}B
|
||||
|
||||
|
||||
|
||||
if (JSON.stringify(cacheStats) != "{}")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6 Cache Stats
|
||||
hr
|
||||
+contentSection("Cache Stats")
|
||||
.table-responsive
|
||||
table.table.table-borderless.table-hover.table-striped
|
||||
thead
|
||||
tr
|
||||
th Cache
|
||||
th.text-end Hit
|
||||
th.text-end Miss
|
||||
th.text-end Hit Rate
|
||||
|
||||
div.table-responsive
|
||||
table.table.table-borderless.table-hover
|
||||
thead
|
||||
tr
|
||||
th Cache
|
||||
th.text-end Hit
|
||||
th.text-end Miss
|
||||
th.text-end Hit Rate
|
||||
tbody
|
||||
each item, itemName in cacheStats
|
||||
tr.font-monospace
|
||||
td #{itemName}
|
||||
td.text-end #{item.hit.toLocaleString()}
|
||||
td.text-end #{item.miss.toLocaleString()}
|
||||
td.text-end
|
||||
if (item.hit > 0 || item.miss > 0)
|
||||
span #{(100 * item.hit / (item.hit + item.miss)).toLocaleString()}
|
||||
small %
|
||||
else
|
||||
span -
|
||||
|
||||
tbody
|
||||
each item, itemName in cacheStats
|
||||
tr.font-monospace
|
||||
td #{itemName}
|
||||
td.text-end #{item.hit.toLocaleString()}
|
||||
td.text-end #{item.miss.toLocaleString()}
|
||||
td.text-end
|
||||
if (item.hit > 0 || item.miss > 0)
|
||||
span #{(100 * item.hit / (item.hit + item.miss)).toLocaleString()}
|
||||
small %
|
||||
else
|
||||
span -
|
||||
+contentSection("Cache Sizes")
|
||||
pre
|
||||
code.json #{JSON.stringify(cacheSizes, null, 4)}
|
||||
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6 Cache Sizes
|
||||
hr
|
||||
+contentSection("RPC Stats")
|
||||
.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th Method
|
||||
th.text-end Count
|
||||
th.text-end Time
|
||||
small (s)
|
||||
th.text-end Avg Time
|
||||
small (ms)
|
||||
th.text-end Successes / Failures
|
||||
th.text-end Success Rate
|
||||
|
||||
pre
|
||||
code.json #{JSON.stringify(cacheSizes, null, 4)}
|
||||
tbody
|
||||
each item, itemName in rpcStats
|
||||
tr.font-monospace
|
||||
td #{itemName}
|
||||
td.text-end #{item.count.toLocaleString()}
|
||||
td.text-end #{(item.time / 1000).toLocaleString()}
|
||||
td.text-end #{(item.time / item.count).toLocaleString()}
|
||||
td.text-end
|
||||
span.text-success #{item.successes.toLocaleString()}
|
||||
span.mx-1 /
|
||||
span.text-danger #{item.failures.toLocaleString()}
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6 RPC Stats
|
||||
hr
|
||||
td.text-end
|
||||
span #{new Decimal(item.successes).dividedBy(new Decimal(item.successes + item.failures)).times(100).toDP(1)}
|
||||
small %
|
||||
|
||||
div.table-responsive
|
||||
if (electrumStats)
|
||||
+contentSection("Electrum Stats")
|
||||
.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th Method
|
||||
th Action
|
||||
th.text-end Count
|
||||
th.text-end First Seen
|
||||
th.text-end Last Seen
|
||||
|
||||
tbody
|
||||
each item, itemName in electrumStats.base
|
||||
tr.font-monospace
|
||||
td #{itemName}
|
||||
td.text-end #{item.count.toLocaleString()}
|
||||
|
||||
if (item.firstSeenAt)
|
||||
td.text-end #{moment.duration(new Date().getTime() - item.firstSeenAt.getTime()).format()} ago
|
||||
else
|
||||
td.text-end -
|
||||
|
||||
if (item.lastSeenAt)
|
||||
td.text-end #{moment.duration(new Date().getTime() - item.lastSeenAt.getTime()).format()} ago
|
||||
else
|
||||
td.text-end -
|
||||
|
||||
hr
|
||||
|
||||
.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th RPC
|
||||
th.text-end Count
|
||||
th.text-end Time
|
||||
small (s)
|
||||
|
|
@ -144,7 +176,7 @@ block content
|
|||
th.text-end Success Rate
|
||||
|
||||
tbody
|
||||
each item, itemName in rpcStats
|
||||
each item, itemName in electrumStats.rpc
|
||||
tr.font-monospace
|
||||
td #{itemName}
|
||||
td.text-end #{item.count.toLocaleString()}
|
||||
|
|
@ -159,110 +191,38 @@ block content
|
|||
span #{new Decimal(item.successes).dividedBy(new Decimal(item.successes + item.failures)).times(100).toDP(1)}
|
||||
small %
|
||||
|
||||
if (electrumStats)
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6 Electrum Stats
|
||||
hr
|
||||
|
||||
div.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th Action
|
||||
th.text-end Count
|
||||
th.text-end First Seen
|
||||
th.text-end Last Seen
|
||||
+contentSection("Error Stats")
|
||||
if (JSON.stringify(errorStats) == "{}")
|
||||
span.text-success No errors encountered
|
||||
|
||||
tbody
|
||||
each item, itemName in electrumStats.base
|
||||
tr.font-monospace
|
||||
td #{itemName}
|
||||
td.text-end #{item.count.toLocaleString()}
|
||||
else
|
||||
div.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th Error ID
|
||||
th.text-end Count
|
||||
th.text-end First Seen
|
||||
th.text-end Last Seen
|
||||
|
||||
if (item.firstSeenAt)
|
||||
td.text-end #{moment.duration(new Date().getTime() - item.firstSeenAt.getTime()).format()} ago
|
||||
else
|
||||
td.text-end -
|
||||
tbody
|
||||
each item, itemName in errorStats
|
||||
tr.font-monospace
|
||||
td #{itemName}
|
||||
td.text-end #{item.count.toLocaleString()}
|
||||
td.text-end #{moment.duration(new Date().getTime() - item.firstSeen).format()} ago
|
||||
td.text-end #{moment.duration(new Date().getTime() - item.lastSeen).format()} ago
|
||||
|
||||
if (item.lastSeenAt)
|
||||
td.text-end #{moment.duration(new Date().getTime() - item.lastSeenAt.getTime()).format()} ago
|
||||
else
|
||||
td.text-end -
|
||||
|
||||
hr
|
||||
|
||||
div.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th RPC
|
||||
th.text-end Count
|
||||
th.text-end Time
|
||||
small (s)
|
||||
th.text-end Avg Time
|
||||
small (ms)
|
||||
th.text-end Successes / Failures
|
||||
th.text-end Success Rate
|
||||
|
||||
tbody
|
||||
each item, itemName in electrumStats.rpc
|
||||
tr.font-monospace
|
||||
td #{itemName}
|
||||
td.text-end #{item.count.toLocaleString()}
|
||||
td.text-end #{(item.time / 1000).toLocaleString()}
|
||||
td.text-end #{(item.time / item.count).toLocaleString()}
|
||||
td.text-end
|
||||
span.text-success #{item.successes.toLocaleString()}
|
||||
span.mx-1 /
|
||||
span.text-danger #{item.failures.toLocaleString()}
|
||||
|
||||
td.text-end
|
||||
span #{new Decimal(item.successes).dividedBy(new Decimal(item.successes + item.failures)).times(100).toDP(1)}
|
||||
small %
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6 Error Stats
|
||||
hr
|
||||
|
||||
if (JSON.stringify(errorStats) == "{}")
|
||||
span.text-success No errors encountered
|
||||
|
||||
else
|
||||
div.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th Error ID
|
||||
th.text-end Count
|
||||
th.text-end First Seen
|
||||
th.text-end Last Seen
|
||||
|
||||
tbody
|
||||
each item, itemName in errorStats
|
||||
tr.font-monospace
|
||||
td #{itemName}
|
||||
td.text-end #{item.count.toLocaleString()}
|
||||
td.text-end #{moment.duration(new Date().getTime() - item.firstSeen).format()} ago
|
||||
td.text-end #{moment.duration(new Date().getTime() - item.lastSeen).format()} ago
|
||||
|
||||
|
||||
+pageTab("JSON")
|
||||
+contentSection("Memory Stats")
|
||||
pre
|
||||
code.json #{JSON.stringify(memstats, null, 4)}
|
||||
|
||||
+contentSection("Error Stats")
|
||||
pre
|
||||
code.json #{JSON.stringify(errorStats, null, 4)}
|
||||
|
||||
div.tab-pane(id="tab-json", role="tabpanel")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6 Memory Stats
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json #{JSON.stringify(memstats, null, 4)}
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6 Error Stats
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json #{JSON.stringify(errorStats, null, 4)}
|
||||
|
|
|
|||
|
|
@ -4,93 +4,82 @@ block headContent
|
|||
title Stats
|
||||
|
||||
block content
|
||||
h1.h3 Stats
|
||||
hr
|
||||
+pageTitle("Admin Stats")
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6 Performance Stats
|
||||
hr
|
||||
+contentSection("Performance Stats")
|
||||
.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th Name
|
||||
th.text-end Min
|
||||
th.text-end Avg
|
||||
th.text-end Max
|
||||
th.text-end Sum
|
||||
th.text-end Count
|
||||
th.text-end First
|
||||
th.text-end Latest
|
||||
|
||||
div.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th Name
|
||||
th.text-end Min
|
||||
th.text-end Avg
|
||||
th.text-end Max
|
||||
th.text-end Sum
|
||||
th.text-end Count
|
||||
th.text-end First
|
||||
th.text-end Latest
|
||||
|
||||
tbody
|
||||
each item, itemIndex in performanceStats
|
||||
tr.font-monospace
|
||||
td #{item[0]}
|
||||
td.text-end #{Math.round(item[1].min).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].avg).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].max).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].sum).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].count).toLocaleString()}
|
||||
td.text-end
|
||||
- var dt = moment.duration(new Date().getTime() - item[1].firstDate.getTime());
|
||||
span #{dt.format()}
|
||||
td.text-end
|
||||
- var dt = moment.duration(new Date().getTime() - item[1].lastDate.getTime());
|
||||
span #{dt.format()}
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6 Event Stats
|
||||
hr
|
||||
|
||||
div.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th Name
|
||||
th.text-end Count
|
||||
|
||||
tbody
|
||||
each item, itemIndex in eventStats
|
||||
tr.font-monospace
|
||||
td #{item[0]}
|
||||
td.text-end #{item[1].toLocaleString()}
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6 Value Stats
|
||||
hr
|
||||
|
||||
div.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th Name
|
||||
th.text-end Min
|
||||
th.text-end Avg
|
||||
th.text-end Max
|
||||
th.text-end Sum
|
||||
th.text-end Count
|
||||
th.text-end First
|
||||
th.text-end Latest
|
||||
|
||||
tbody
|
||||
each item, itemIndex in valueStats
|
||||
tr.font-monospace
|
||||
td #{item[0]}
|
||||
td.text-end #{Math.round(item[1].min).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].avg).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].max).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].sum).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].count).toLocaleString()}
|
||||
td.text-end
|
||||
- var dt = moment.duration(new Date().getTime() - item[1].firstDate.getTime());
|
||||
span #{dt.format()}
|
||||
td.text-end
|
||||
- var dt = moment.duration(new Date().getTime() - item[1].lastDate.getTime());
|
||||
span #{dt.format()}
|
||||
tbody
|
||||
each item, itemIndex in performanceStats
|
||||
tr.font-monospace
|
||||
td #{item[0]}
|
||||
td.text-end #{Math.round(item[1].min).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].avg).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].max).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].sum).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].count).toLocaleString()}
|
||||
td.text-end
|
||||
- var dt = moment.duration(new Date().getTime() - item[1].firstDate.getTime());
|
||||
span #{dt.format()}
|
||||
td.text-end
|
||||
- var dt = moment.duration(new Date().getTime() - item[1].lastDate.getTime());
|
||||
span #{dt.format()}
|
||||
|
||||
|
||||
+contentSection("Event Stats")
|
||||
.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th Name
|
||||
th.text-end Count
|
||||
|
||||
tbody
|
||||
each item, itemIndex in eventStats
|
||||
tr.font-monospace
|
||||
td #{item[0]}
|
||||
td.text-end #{item[1].toLocaleString()}
|
||||
|
||||
|
||||
+contentSection("Value Stats")
|
||||
.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th Name
|
||||
th.text-end Min
|
||||
th.text-end Avg
|
||||
th.text-end Max
|
||||
th.text-end Sum
|
||||
th.text-end Count
|
||||
th.text-end First
|
||||
th.text-end Latest
|
||||
|
||||
tbody
|
||||
each item, itemIndex in valueStats
|
||||
tr.font-monospace
|
||||
td #{item[0]}
|
||||
td.text-end #{Math.round(item[1].min).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].avg).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].max).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].sum).toLocaleString()}
|
||||
td.text-end #{Math.round(item[1].count).toLocaleString()}
|
||||
td.text-end
|
||||
- var dt = moment.duration(new Date().getTime() - item[1].firstDate.getTime());
|
||||
span #{dt.format()}
|
||||
td.text-end
|
||||
- var dt = moment.duration(new Date().getTime() - item[1].lastDate.getTime());
|
||||
span #{dt.format()}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,20 +4,15 @@ block headContent
|
|||
title Bitcoin Whitepaper
|
||||
|
||||
block content
|
||||
div.row
|
||||
div.col
|
||||
h1.h3 Bitcoin Whitepaper
|
||||
|
||||
hr
|
||||
+pageTitle("Bitcoin Whitepaper", "(Extracted from the blockchain!)")
|
||||
|
||||
p Below is the Bitcoin whitepaper, extracted from data in the Bitcoin blockchain (transaction
|
||||
a.font-monospace(href="./tx/54e48e5f5c656b26c3bca14a8c95aa583d07ebe84dde3b7dd4a78f4e4186e713") 54e48e5f5c6…
|
||||
| to be precise), served by your Bitcoin Core node.
|
||||
+dismissableInfoAlert("whitepaperPageNoteDismissed", "About the Bitcoin Whitepaper Tool...")
|
||||
p Below is the Bitcoin whitepaper, extracted from data in the Bitcoin blockchain (transaction
|
||||
a.font-monospace(href="./tx/54e48e5f5c656b26c3bca14a8c95aa583d07ebe84dde3b7dd4a78f4e4186e713") 54e48e5f5c6…
|
||||
span.ms-2 to be precise), served by your <b>Bitcoin Core</b> node.
|
||||
|
||||
p The data has been decoded by this tool and is displayed in an iframe below. You can view it directly and/or download it at
|
||||
a(href="./bitcoin.pdf") /bitcoin.pdf
|
||||
|.
|
||||
|
||||
hr
|
||||
p The data has been decoded by this tool and is displayed in an iframe below. You can view it directly and/or download it at
|
||||
a(href="./bitcoin.pdf") /bitcoin.pdf
|
||||
|.
|
||||
|
||||
iframe(src="./bitcoin.pdf", style="width: 100%;", height="800")
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ block headContent
|
|||
title Block Analysis
|
||||
|
||||
block content
|
||||
h1.h3 Block Analysis
|
||||
hr
|
||||
+pageTitle("Block Analysis")
|
||||
|
||||
div.card.shadow-sm.mb-huge
|
||||
div.card-body
|
||||
|
|
|
|||
|
|
@ -4,16 +4,21 @@ block headContent
|
|||
title Block Analysis ##{result.getblock.height.toLocaleString()}, #{result.getblock.hash}
|
||||
|
||||
block content
|
||||
h1.h3 Block Analysis
|
||||
small.font-monospace(style="width: 100%;") ##{result.getblock.height.toLocaleString()}
|
||||
br
|
||||
small.font-monospace.word-wrap(style="width: 100%;") #{result.getblock.hash}
|
||||
|
||||
|
||||
.mb-3
|
||||
.clearfix
|
||||
.float-start
|
||||
if (result.getblock)
|
||||
a.btn.btn-sm.btn-primary.ms-2(href=`./block/${result.getblock.hash}`) « Block Details
|
||||
|
||||
.float-end
|
||||
|
||||
hr
|
||||
|
||||
div.mb-2
|
||||
if (result.getblock)
|
||||
a.btn.btn-sm.btn-primary.mb-1(href=`./block/${result.getblock.hash}`) « Block Details:
|
||||
span.font-monospace ##{result.getblock.height.toLocaleString()}
|
||||
|
||||
+pageTitle("Block Analysis", result.getblock.hash, true)
|
||||
|
||||
|
||||
if (block && (!block.tx || block.tx.length == 0) && global.prunedBlockchain)
|
||||
div.alert.alert-warning.pb-0(role="alert")
|
||||
|
|
@ -22,263 +27,207 @@ block content
|
|||
| !{markdown(msgMarkdown)}
|
||||
|
||||
else
|
||||
div.row
|
||||
- var sumTableLabelClass = (result.blockstats != null ? "summary-split-table-label" : "summary-table-label");
|
||||
- var sumTableValueClass = (result.blockstats != null ? "summary-split-table-content" : "summary-table-content");
|
||||
|
||||
div.mb-3.col
|
||||
div.card.shadow-sm(style="height: 100%;")
|
||||
div.card-body.px-2.px-md-3
|
||||
h3.h6.mb-0 Summary
|
||||
hr
|
||||
+contentSection("Summary")
|
||||
+summaryRow(3 + (result.getblock.weight ? 1 : (result.getblock.size ? 1 : 0)))
|
||||
+summaryItem("Date")
|
||||
+timestamp(result.getblock.time, true)
|
||||
|
||||
div.clearfix
|
||||
div.row
|
||||
div.summary-table-label Date
|
||||
div.summary-table-content.font-monospace
|
||||
- var timestampHuman = result.getblock.time;
|
||||
include includes/timestamp-human.pug
|
||||
small.ms-1 utc
|
||||
if (result.getblock.weight)
|
||||
+summaryItem("Weight", null, "wu", "Weight Units")
|
||||
| #{result.getblock.weight.toLocaleString()}
|
||||
|
||||
- var timeAgoTime = result.getblock.time;
|
||||
span.text-muted.ms-2 (
|
||||
include includes/time-ago-text.pug
|
||||
span ago)
|
||||
|
||||
if (result.getblock.weight)
|
||||
div.row
|
||||
div.summary-table-label Weight
|
||||
div.summary-table-content.font-monospace
|
||||
span #{result.getblock.weight.toLocaleString()}
|
||||
small wu
|
||||
|
||||
span.text-muted (#{new Decimal(100 * result.getblock.weight / coinConfig.maxBlockWeight).toDecimalPlaces(2)}% full)
|
||||
|
||||
else if (result.getblock.size)
|
||||
div.row
|
||||
div.summary-table-label Size
|
||||
div.summary-table-content.font-monospace #{result.getblock.size.toLocaleString()}
|
||||
small B
|
||||
|
||||
div.row
|
||||
div.summary-table-label Transactions
|
||||
div.summary-table-content.font-monospace #{result.getblock.nTx.toLocaleString()}
|
||||
|
||||
div.row
|
||||
div.summary-table-label Confirmations
|
||||
div.summary-table-content.font-monospace
|
||||
if (result.getblock.confirmations < 6)
|
||||
span.fw-bold.text-warning #{result.getblock.confirmations.toLocaleString()}
|
||||
a(data-bs-toggle="tooltip", title="Fewer than 6 confirmations is generally considered 'unsettled' for high-value transactions. The applicability of this guidance may vary.")
|
||||
i.fas.fa-unlock-alt
|
||||
else
|
||||
span.fw-bold.text-success #{result.getblock.confirmations.toLocaleString()}
|
||||
a(data-bs-toggle="tooltip", title="6 confirmations is generally considered 'settled'. High-value transactions may require more; low-value transactions may require less.")
|
||||
i.fas.fa-lock
|
||||
else if (result.getblock.size)
|
||||
+summaryItem("Size", null, "B", "Bytes")
|
||||
| #{result.getblock.size.toLocaleString()}
|
||||
|
||||
|
||||
div#progress-wrapper.mb-huge
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6 Loading transactions:
|
||||
+summaryItem("Transactions")
|
||||
| #{result.getblock.nTx.toLocaleString()}
|
||||
|
||||
+summaryItem("Confirmations")
|
||||
+confirmations(result.getblock.confirmations, false)
|
||||
|
||||
#progress-wrapper.mb-huge
|
||||
.card.shadow-sm.mb-3
|
||||
.card-body
|
||||
span Loading transactions:
|
||||
span(id="progress-text")
|
||||
div.progress.mt-2(id="progress-bar", style="height: 7px;")
|
||||
div.progress-bar(id="data-progress", role="progressbar", aria-valuenow="0", aria-valuemin="0" ,aria-valuemax="100")
|
||||
.progress.mt-2(id="progress-bar", style="height: 7px;")
|
||||
.progress-bar(id="data-progress", role="progressbar", aria-valuenow="0", aria-valuemin="0" ,aria-valuemax="100")
|
||||
|
||||
|
||||
div#main-content(style="display: none;")
|
||||
div.row
|
||||
div.col-xl-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Top Value Transactions
|
||||
hr
|
||||
#main-content(style="display: none;")
|
||||
.row
|
||||
.col-xl-6
|
||||
+contentSection("Top Value Transactions")
|
||||
.table-responsive
|
||||
table.table.table-striped.table-borderless.mb-0
|
||||
thead
|
||||
tr
|
||||
th.data-header Transaction
|
||||
th.data-header.text-end Output Value
|
||||
|
||||
div.table-responsive
|
||||
table.table.table-striped.mb-0
|
||||
tbody(id="tbody-top-value-tx")
|
||||
tr.font-monospace.row-prototype(style="display: none;")
|
||||
td.data-tx-link
|
||||
td.text-end.data-tx-value
|
||||
|
||||
tr.hidden-row-to-fix-striping.d-none
|
||||
|
||||
.col-xl-6
|
||||
+contentSection("Top Size Transactions")
|
||||
.table-responsive
|
||||
table.table.table-striped.table-borderless.mb-0
|
||||
thead
|
||||
tr
|
||||
th.data-header Transaction
|
||||
th.data-header.text-end Size
|
||||
small.fw-normal.text-muted.ms-2 (vB)
|
||||
|
||||
tbody(id="tbody-top-size-tx")
|
||||
tr.font-monospace.row-prototype(style="display: none;")
|
||||
td.data-tx-link
|
||||
td.text-end.data-tx-value
|
||||
|
||||
tr.hidden-row-to-fix-striping.d-none
|
||||
|
||||
|
||||
if (global.txindexAvailable)
|
||||
.col-xl-6
|
||||
+contentSection("Top Fee Transactions")
|
||||
.table-responsive
|
||||
table.table.table-striped.table-borderless.mb-0
|
||||
thead
|
||||
tr
|
||||
th.data-header Transaction
|
||||
th.data-header.text-end Output Value
|
||||
th.data-header.text-end Fee
|
||||
|
||||
tbody(id="tbody-top-value-tx")
|
||||
tbody(id="tbody-top-fee-tx")
|
||||
tr.font-monospace.row-prototype(style="display: none;")
|
||||
td.data-tx-link
|
||||
td.text-end.data-tx-value
|
||||
|
||||
div.col-xl-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Top Size Transactions
|
||||
hr
|
||||
tr.hidden-row-to-fix-striping.d-none
|
||||
|
||||
div.table-responsive
|
||||
table.table.table-striped.mb-0
|
||||
|
||||
.col-xl-6
|
||||
+contentSection("Top Fee Rate Transactions")
|
||||
.table-responsive
|
||||
table.table.table-striped.table-borderless.mb-0
|
||||
thead
|
||||
tr
|
||||
th.data-header Transaction
|
||||
th.data-header.text-end Size
|
||||
th.data-header.text-end Fee Rate
|
||||
small.text-muted.fw-normal.ms-2 (sat/vB)
|
||||
|
||||
tbody(id="tbody-top-size-tx")
|
||||
tbody(id="tbody-top-fee-rate-tx")
|
||||
tr.font-monospace.row-prototype(style="display: none;")
|
||||
td.data-tx-link
|
||||
td.text-end.data-tx-value
|
||||
|
||||
if (global.txindexAvailable)
|
||||
div.col-xl-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Top Fee Transactions
|
||||
hr
|
||||
tr.hidden-row-to-fix-striping.d-none
|
||||
|
||||
div.table-responsive
|
||||
table.table.table-striped.mb-0
|
||||
thead
|
||||
tr
|
||||
th.data-header Transaction
|
||||
th.data-header.text-end Fee
|
||||
|
||||
tbody(id="tbody-top-fee-tx")
|
||||
tr.font-monospace.row-prototype(style="display: none;")
|
||||
td.data-tx-link
|
||||
td.text-end.data-tx-value
|
||||
|
||||
div.col-xl-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Top Fee Rate Transactions
|
||||
hr
|
||||
|
||||
div.table-responsive
|
||||
table.table.table-striped.mb-0
|
||||
thead
|
||||
tr
|
||||
th.data-header Transaction
|
||||
th.data-header.text-end Fee Rate
|
||||
|
||||
tbody(id="tbody-top-fee-rate-tx")
|
||||
tr.font-monospace.row-prototype(style="display: none;")
|
||||
td.data-tx-link
|
||||
td.text-end.data-tx-value
|
||||
|
||||
if (global.txindexAvailable)
|
||||
div.col-lg-6.mb-3
|
||||
div.card.shadow-sm(style="height: 100%;")
|
||||
.col-lg-6.mb-3
|
||||
+sectionTitle("Input Types")
|
||||
.card.shadow-sm
|
||||
div.card-body
|
||||
h3.h6.mb-0 Input Types
|
||||
hr
|
||||
|
||||
table.table.table-striped.mb-0
|
||||
span#no-input-types-data.text-muted(style="display: none;") No data
|
||||
table.table.table-striped.table-borderless.mb-0
|
||||
tbody(id="tbody-input-types")
|
||||
tr.font-monospace.row-prototype(style="display: none;")
|
||||
td
|
||||
small.data-tag.bg-dark.data-type
|
||||
span.badge.bg-dark.data-type
|
||||
|
||||
td.data-count
|
||||
|
||||
div.col-lg-6.mb-3(class=(!global.txindexAvailable ? "col-lg-12" : ""))
|
||||
div.card.shadow-sm(style="height: 100%;")
|
||||
div.card-body
|
||||
h3.h6.mb-0 Output Types
|
||||
hr
|
||||
|
||||
table.table.table-striped.mb-0
|
||||
tr.hidden-row-to-fix-striping.d-none
|
||||
|
||||
.col-lg-6.mb-3(class=(!global.txindexAvailable ? "col-lg-12" : ""))
|
||||
+sectionTitle("Output Types")
|
||||
.card.shadow-sm
|
||||
.card-body
|
||||
table.table.table-striped.table-borderless.mb-0
|
||||
tbody(id="tbody-output-types")
|
||||
tr.font-monospace.row-prototype(style="display: none;")
|
||||
td
|
||||
small.data-tag.bg-dark.data-type
|
||||
span.badge.bg-dark.data-type
|
||||
|
||||
td.data-count
|
||||
|
||||
div.row
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transaction Value
|
||||
hr
|
||||
tr.hidden-row-to-fix-striping.d-none
|
||||
|
||||
canvas(id="graph-tx-value")
|
||||
.row
|
||||
.col-lg-6
|
||||
+contentSection("Transaction Value")
|
||||
canvas(id="graph-tx-value")
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transaction Value Distribution
|
||||
hr
|
||||
|
||||
|
||||
canvas(id="chart-tx-value-distribution")
|
||||
.col-lg-6
|
||||
+contentSection("Transaction Value Distribution")
|
||||
canvas(id="chart-tx-value-distribution")
|
||||
|
||||
|
||||
if (global.txindexAvailable)
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transaction Fee
|
||||
hr
|
||||
.col-lg-6
|
||||
+contentSection("Transaction Fee")
|
||||
canvas(id="graph-tx-fee")
|
||||
|
||||
canvas(id="graph-tx-fee")
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transaction Fee Distribution
|
||||
hr
|
||||
.col-lg-6
|
||||
+contentSection("Transaction Fee Distribution")
|
||||
canvas(id="chart-tx-fee-distribution")
|
||||
|
||||
canvas(id="chart-tx-fee-distribution")
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transaction Fee Rate
|
||||
hr
|
||||
.col-lg-6
|
||||
+contentSection("Transaction Fee Rate")
|
||||
canvas(id="graph-tx-fee-rate")
|
||||
|
||||
|
||||
canvas(id="graph-tx-fee-rate")
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transaction Fee Rate Distribution
|
||||
hr
|
||||
.col-lg-6
|
||||
+contentSection("Transaction Fee Rate Distribution")
|
||||
canvas(id="chart-tx-fee-rate-distribution")
|
||||
|
||||
canvas(id="chart-tx-fee-rate-distribution")
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transaction Size
|
||||
hr
|
||||
.col-lg-6
|
||||
+contentSection("Transaction Size")
|
||||
canvas(id="graph-tx-size")
|
||||
|
||||
canvas(id="graph-tx-size")
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transaction Size Distribution
|
||||
hr
|
||||
.col-lg-6
|
||||
+contentSection("Transaction Size Distribution")
|
||||
canvas(id="chart-tx-size-distribution")
|
||||
|
||||
canvas(id="chart-tx-size-distribution")
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transaction Input Count
|
||||
hr
|
||||
.col-lg-6
|
||||
+contentSection("Transaction Input Count")
|
||||
canvas(id="graph-tx-inputs")
|
||||
|
||||
canvas(id="graph-tx-inputs")
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transaction Output Count
|
||||
hr
|
||||
|
||||
canvas(id="graph-tx-outputs")
|
||||
.col-lg-6
|
||||
+contentSection("Transaction Output Count")
|
||||
canvas(id="graph-tx-outputs")
|
||||
|
||||
|
||||
|
||||
block endOfBody
|
||||
- var txidChunkSize = 10;
|
||||
|
||||
script(src="./js/chart.bundle.min.js", integrity="sha384-qgOtiGNaHh9fVWUnRjyHlV39rfbDcvPPkEzL1RHvsHKbuqUqM6uybNuVnghY2z4/")
|
||||
+graphPageScriptSetup
|
||||
|
||||
script(src='./js/decimal.js')
|
||||
|
||||
|
||||
script.
|
||||
var txidChunkSize = !{txidChunkSize};
|
||||
var prunedBlock = !{(block && (!block.tx || block.tx.length == 0) && global.prunedBlockchain)};
|
||||
|
|
@ -288,7 +237,7 @@ block endOfBody
|
|||
var blockHash = "!{result.getblock.hash}";
|
||||
var satsMultiplier = !{coinConfig.baseCurrencyUnit.multiplier};
|
||||
var vByteSizes = false;
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
if (!prunedBlock) {
|
||||
loadTransactions(txidChunks, txidChunkSize, txidChunks.length * txidChunkSize);
|
||||
|
|
@ -375,7 +324,7 @@ block endOfBody
|
|||
|
||||
row.removeClass("row-prototype");
|
||||
|
||||
row.find(".data-tx-link").html(`<a href='./tx/${item.txid}'>${item.txid.substring(0, 32)}…</a>`);
|
||||
row.find(".data-tx-link").html(`<a href='./tx/${item.txid}'>${item.txid.substring(0, 24)}…</a>`);
|
||||
row.find(".data-tx-value").text(item.value);
|
||||
|
||||
updateCurrencyValue(row.find(".data-tx-value"), item.value);
|
||||
|
|
@ -396,7 +345,7 @@ block endOfBody
|
|||
|
||||
row.removeClass("row-prototype");
|
||||
|
||||
row.find(".data-tx-link").html(`<a href='./tx/${item.txid}'>${item.txid.substring(0, 32)}…</a>`);
|
||||
row.find(".data-tx-link").html(`<a href='./tx/${item.txid}'>${item.txid.substring(0, 24)}…</a>`);
|
||||
row.find(".data-tx-value").text(item.value);
|
||||
|
||||
updateCurrencyValue(row.find(".data-tx-value"), item.value);
|
||||
|
|
@ -417,8 +366,8 @@ block endOfBody
|
|||
|
||||
row.removeClass("row-prototype");
|
||||
|
||||
row.find(".data-tx-link").html(`<a href='./tx/${item.txid}'>${item.txid.substring(0, 32)}…</a>`);
|
||||
row.find(".data-tx-value").html(`<span>${parseInt(item.value).toLocaleString()} <small>sat/${vByteSizes ? "v" : ""}B</small></span>`);
|
||||
row.find(".data-tx-link").html(`<a href='./tx/${item.txid}'>${item.txid.substring(0, 24)}…</a>`);
|
||||
row.find(".data-tx-value").html(`<span>${parseInt(item.value).toLocaleString()}</span>`);
|
||||
|
||||
row.show();
|
||||
|
||||
|
|
@ -436,8 +385,8 @@ block endOfBody
|
|||
|
||||
row.removeClass("row-prototype");
|
||||
|
||||
row.find(".data-tx-link").html(`<a href='./tx/${item.txid}'>${item.txid.substring(0, 32)}…</a>`);
|
||||
row.find(".data-tx-value").html(`<span>${parseInt(item.value).toLocaleString()} <small>${vByteSizes ? "v" : ""}B</small></span>`);
|
||||
row.find(".data-tx-link").html(`<a href='./tx/${item.txid}'>${item.txid.substring(0, 24)}…</a>`);
|
||||
row.find(".data-tx-value").html(`<span>${parseInt(item.value).toLocaleString()}</span>`);
|
||||
|
||||
row.show();
|
||||
|
||||
|
|
@ -468,6 +417,10 @@ block endOfBody
|
|||
return b.count - a.count;
|
||||
});
|
||||
|
||||
if (sortedInputs.length == 0) {
|
||||
$("#no-input-types-data").show();
|
||||
}
|
||||
|
||||
for (var i = 0; i < sortedInputs.length; i++) {
|
||||
var item = sortedInputs[i];
|
||||
|
||||
|
|
@ -532,6 +485,9 @@ block endOfBody
|
|||
display: true,
|
||||
labelString: 'Index in Block'
|
||||
},
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
//ticks: {
|
||||
// stepSize: 100,
|
||||
//}
|
||||
|
|
@ -539,7 +495,10 @@ block endOfBody
|
|||
yAxes: [{
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: yLabelStr
|
||||
labelString: yLabelStr,
|
||||
},
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
|
@ -569,9 +528,17 @@ block endOfBody
|
|||
display: false
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero:true
|
||||
},
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ block headContent
|
|||
title Block Block
|
||||
|
||||
block content
|
||||
h1.h3 Block Stats
|
||||
hr
|
||||
+pageTitle("Block Stats")
|
||||
|
||||
if (rpcApiUnsupportedError)
|
||||
div.alert.alert-danger(style="margin-bottom: 200px;")
|
||||
|
|
@ -17,90 +16,64 @@ block content
|
|||
|
||||
else
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Block Range
|
||||
hr
|
||||
+dismissableInfoAlert("blockStatsPageNoteDismissed", "About Block Stats...")
|
||||
| !{markdown("The **Block Stats** tool queries a range of blocks from Bitcoin Core and summarizes the data via graphs. These graphs sometimes expose interesting trends and sometimes show boring, steady-state operation of the network.")}
|
||||
| Use the <b>Filters</b> section below to select the range of blocks to analyze and select the subset of graphs displayed.
|
||||
|
||||
div.clearfix
|
||||
div.float-start.me-4
|
||||
div(id="time-range-buttons")
|
||||
h3.h6 Latest N Blocks
|
||||
div.btn-group
|
||||
a.btn.btn-primary.block-count-btn(href="javascript:void(0)", data-blockCount="144") 144
|
||||
small.ms-2 (~1d)
|
||||
a.btn.btn-outline-primary.block-count-btn(href="javascript:void(0)", data-blockCount="432") 432
|
||||
small.ms-2 (~3d)
|
||||
a.btn.btn-outline-primary.block-count-btn(href="javascript:void(0)", data-blockCount="1008") 1,008
|
||||
small.ms-2 (~7d)
|
||||
a.btn.btn-outline-primary.block-count-btn(href="javascript:void(0)", data-blockCount="4320") 4,320
|
||||
small.ms-2 (~30d)
|
||||
|
||||
|
||||
div.float-start.me-4
|
||||
div(id="block-selections-buttons")
|
||||
h3.h6 Preconfigured
|
||||
|
||||
div.dropdown
|
||||
button.btn.btn-outline-primary.dropdown-toggle(type="button", id="preconfigured-dropdown", data-bs-toggle="dropdown", aria-haspopup="true", aria-expanded="false") Selections
|
||||
div.dropdown-menu(aria-labelledby="preconfigured-dropdown")
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="0-199") First 200 Blocks
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="209900-210100") First Halving ±100
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="419900-420100") Second Halving ±100
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="629900-630100") Third Halving ±100
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="481724-481924") SegWit Activation ±100
|
||||
- var graphIds = ["fee-rates", "max-fee-rates", "total-fee", "min-fees", "max-fees", "inputs-outputs", "tx-sizes", "max-tx-sizes", "volumes", "weights-sizes", "sw-txs", "subsidy", "mediantime", "txs", "utxo_increase"];
|
||||
|
||||
- var graphTitles = ["Fee Rates (avg, median, min)", "Maximum Fee Rate", "Total Fees", "Minimum Tx Fee", "Maximum Tx Fee", "Input / Output Count", "Tx Sizes (avg, median, min)", "Maximum Tx Size", "Output Volume", "Block Weight and Size", "SegWit Tx Count", "Subsidy", "Timestamp", "Tx Count", "UTXO Δ"];
|
||||
|
||||
div.float-start
|
||||
div(id="time-range-buttons")
|
||||
h3.h6 Custom Range
|
||||
+contentSection("Filters")
|
||||
.mb-3
|
||||
+blockRangeFilters
|
||||
|
||||
form.form-inline.me-3(id="custom-range-form")
|
||||
div.input-group
|
||||
input.form-control(type="text", id="custom-range-start", placeholder="min height", style="width: 125px;")
|
||||
input.form-control(type="text", id="custom-range-end", placeholder="max height", style="width: 125px;")
|
||||
|
||||
button.btn.btn-primary(type="submit") Go
|
||||
hr
|
||||
|
||||
div.mb-2
|
||||
span.border-dotted(title="Select the list of graphs to be displayed.", data-bs-toggle="tooltip") Active Graphs
|
||||
|
||||
.clearfix
|
||||
each graphId, graphIndex in graphIds
|
||||
div.float-start.me-3.mb-1
|
||||
div.form-check
|
||||
input.form-check-input.graph-toggle-checkbox(type="checkbox", id=`checkbox-${graphId}` checked="checked", data-graphId=graphId, autocomplete="off")
|
||||
label.form-check-label(for=("checkbox-" + graphId)) #{graphTitles[graphIndex]}
|
||||
|
||||
.float-start.me-3.mb-1
|
||||
a.me-3(id="link-show-all", href="javascript:void(0)") show all
|
||||
a(id="link-hide-all", href="javascript:void(0)") hide all
|
||||
|
||||
|
||||
div#progress-wrapper.mb-huge
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6 Loading blocks:
|
||||
span Loading blocks:
|
||||
span(id="block-progress-text")
|
||||
div.progress.mt-2(id="progress-bar", style="height: 7px;")
|
||||
div.progress-bar(id="data-progress", role="progressbar", aria-valuenow="0", aria-valuemin="0" ,aria-valuemax="100")
|
||||
|
||||
|
||||
- var graphIds = ["fee-rates", "max-fee-rates", "total-fee", "min-fees", "max-fees", "inputs-outputs", "tx-sizes", "max-tx-sizes", "volumes", "weights-sizes", "sw-txs", "subsidy", "mediantime", "txs", "utxo_increase"];
|
||||
|
||||
- var graphTitles = ["Fee Rates (avg, median, min)", "Maximum Fee Rate", "Total Fees", "Minimum Tx Fee", "Maximum Tx Fee", "Input / Output Count", "Tx Sizes (avg, median, min)", "Maximum Tx Size", "Output Volume", "Block Weight and Size", "SegWit Tx Count", "Subsidy", "Timestamp", "Tx Count", "UTXO Δ"];
|
||||
|
||||
div(id="main-content", style="display: none;")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
div.clearfix
|
||||
each graphId, graphIndex in graphIds
|
||||
div.float-start.me-3.mb-1
|
||||
div.form-check
|
||||
input.form-check-input.graph-toggle-checkbox(type="checkbox", id=`checkbox-${graphId}` checked="checked", data-graphId=graphId, autocomplete="off")
|
||||
label.form-check-label(for=("checkbox-" + graphId)) #{graphTitles[graphIndex]}
|
||||
|
||||
div.float-start.me-3.mb-1
|
||||
a.me-3(id="link-show-all", href="javascript:void(0)") show all
|
||||
a(id="link-hide-all", href="javascript:void(0)") hide all
|
||||
|
||||
div.row.clearfix
|
||||
.row.clearfix
|
||||
each graphId, graphIndex in graphIds
|
||||
div.col-lg-6.float-start
|
||||
div.card.shadow-sm.mb-3.graph-wrapper(id=`graph-wrapper-${graphId}`)
|
||||
div.card-body
|
||||
h3.h6.mb-0 #{graphTitles[graphIndex]}
|
||||
hr
|
||||
|
||||
canvas.mb-3(id=graphId)
|
||||
.col-lg-6.float-start
|
||||
.graph-wrapper(id=`graph-wrapper-${graphId}`)
|
||||
+sectionTitle(graphTitles[graphIndex])
|
||||
.card.shadow-sm.mb-3
|
||||
.card-body
|
||||
canvas.mb-3(id=graphId)
|
||||
|
||||
|
||||
block endOfBody
|
||||
script(src="./js/chart.bundle.min.js", integrity="sha384-qgOtiGNaHh9fVWUnRjyHlV39rfbDcvPPkEzL1RHvsHKbuqUqM6uybNuVnghY2z4/")
|
||||
|
||||
+graphPageScriptSetup
|
||||
|
||||
script(src='./js/decimal.js')
|
||||
|
||||
script.
|
||||
|
|
@ -389,6 +362,9 @@ block endOfBody
|
|||
scaleLabel: {
|
||||
display: false,
|
||||
//labelString: names[i]
|
||||
},
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -423,6 +399,19 @@ block endOfBody
|
|||
display: true,
|
||||
labelString: 'Block'
|
||||
},
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
type: 'linear',
|
||||
position: 'left',
|
||||
scaleLabel: {
|
||||
display: false,
|
||||
},
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
278
views/block.pug
|
|
@ -8,10 +8,278 @@ block headContent
|
|||
|
||||
block content
|
||||
if (result.getblock)
|
||||
h1.h3 Block
|
||||
small.font-monospace(style="width: 100%;") ##{result.getblock.height.toLocaleString()}
|
||||
br
|
||||
small.font-monospace.word-wrap(style="width: 100%;") #{result.getblock.hash}
|
||||
|
||||
.mb-3
|
||||
.clearfix
|
||||
.float-start
|
||||
if (result.getblock.previousblockhash)
|
||||
a.btn.btn-sm.btn-primary.ms-2(href=`./block/${result.getblock.previousblockhash}`, title=`Block ${(result.getblock.height - 1).toLocaleString()}`, data-bs-toggle="tooltip") « Prev Block
|
||||
|
||||
else if (result.getblock.hash == genesisBlockHash)
|
||||
span.btn.btn-sm.btn-success.ms-2 Genesis Block!
|
||||
|
||||
if (result.getblock.nextblockhash)
|
||||
a.btn.btn-sm.btn-primary.ms-2(href=`./block/${result.getblock.nextblockhash}`, title=`Block ${(result.getblock.height + 1).toLocaleString()}`, data-bs-toggle="tooltip") Next Block
|
||||
span.ms-1 »
|
||||
else
|
||||
span.btn.btn-sm.btn-success.ms-2 Latest Block!
|
||||
|
||||
.float-end
|
||||
if (result.getblock.tx != null && result.getblock.tx.length > 0)
|
||||
a.btn.btn-primary.btn-sm.me-2(href=`./block-analysis/${result.getblock.hash}`, title="See a summary analysis of all transactions in this block.", data-bs-toggle="tooltip")
|
||||
i.fas.fa-angle-double-down.me-2
|
||||
| Block Analysis
|
||||
|
||||
hr
|
||||
|
||||
include includes/block-content.pug
|
||||
+pageTitle(`Block #${result.getblock.height.toLocaleString()}`, result.getblock.hash, true)
|
||||
|
||||
|
||||
|
||||
+pageTabs(["Details", "JSON"])
|
||||
|
||||
- var txCount = result.getblock.nTx;
|
||||
|
||||
|
||||
.tab-content
|
||||
+pageTab("Details", true)
|
||||
|
||||
|
||||
if (global.specialBlocks && global.specialBlocks[result.getblock.hash])
|
||||
- var sbInfo = global.specialBlocks[result.getblock.hash];
|
||||
|
||||
+funAlert(sbInfo.alertBodyHtml, sbInfo.summary, sbInfo.referenceUrl)
|
||||
|
||||
|
||||
.clearfix
|
||||
.float-end
|
||||
if (`${userSettings["blockPageShowFeeSummary"]}` == "false")
|
||||
a.btn.btn-primary.btn-sm.me-2.mb-2(href=`./changeSetting?name=blockPageShowFeeSummary&value=true`, title="Display fee details for this block.", data-bs-toggle="tooltip")
|
||||
i.far.fa-plus-square.me-2
|
||||
| Fee Details
|
||||
|
||||
if (`${userSettings["blockPageShowTechSummary"]}` == "false")
|
||||
a.btn.btn-primary.btn-sm.me-2.mb-2(href=`./changeSetting?name=blockPageShowTechSummary&value=true`, title="Display technical details for this block.", data-bs-toggle="tooltip")
|
||||
i.far.fa-plus-square.me-2
|
||||
| Technical Details
|
||||
|
||||
|
||||
|
||||
+contentSection("Summary")
|
||||
+summaryRow(2 + (result.getblock.miner ? 1 : 0) + (result.blockstats ? 1 : 0))
|
||||
+summaryItem("Date")
|
||||
+timestamp(result.getblock.time, true)
|
||||
|
||||
|
||||
+summaryItem("Confirmations")
|
||||
+confirmations(result.getblock.confirmations, false)
|
||||
|
||||
|
||||
if (result.getblock.miner)
|
||||
+summaryItem("Miner")
|
||||
if (result.getblock.miner.identifiedBy)
|
||||
span.badge.bg-primary(data-bs-toggle="tooltip", title=`Identified by: ${result.getblock.miner.identifiedBy}`) #{result.getblock.miner.name}
|
||||
|
||||
else
|
||||
small.badge.bg-primary #{result.getblock.miner.name}
|
||||
|
||||
if (result.blockstats)
|
||||
+summaryItem("Total Output", "Total value of all transaction outputs")
|
||||
if (result.blockstats.total_out)
|
||||
- var currencyValue = new Decimal(result.blockstats.total_out).plus(new Decimal(result.blockstats.totalfee)).plus(new Decimal(result.blockstats.subsidy));
|
||||
- currencyValue = currencyValue.dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include ./includes/value-display.pug
|
||||
else
|
||||
span 0
|
||||
|
||||
if (result.blockstats && result.blockstats.ins && result.blockstats.ins > 0)
|
||||
+contentSection("Fee Details", true, "blockPageShowFeeSummary", true)
|
||||
+summaryRow(3 + (result.blockstats.feerate_percentiles ? 1 : 0))
|
||||
+summaryItem("Total Fees")
|
||||
if (result.blockstats.totalfee)
|
||||
- var currencyValue = new Decimal(result.blockstats.totalfee).dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include ./includes/value-display.pug
|
||||
|
||||
else
|
||||
- var currencyValue = new Decimal(result.getblock.totalFees);
|
||||
include ./includes/value-display.pug
|
||||
|
||||
if (result.blockstats.feerate_percentiles)
|
||||
+summaryItem("Rate Percentiles", null, "sat/vB")
|
||||
- var percentiles = [[10, 0], [50, 2], [90, 4]];
|
||||
|
||||
if (true)
|
||||
.d-flex.justify-content-start.justify-content-md-center
|
||||
each item, itemIndex in percentiles
|
||||
.text-start.text-md-center(style="width: 75px;")
|
||||
span.text-muted #{item[0]}
|
||||
sup th
|
||||
|
||||
br
|
||||
| #{result.blockstats.feerate_percentiles[item[1]]}
|
||||
|
||||
|
||||
+summaryItem("Min / Max Rates", null, "sat/vB")
|
||||
if (result.blockstats.minfeerate || result.blockstats.minfeerate == 0)
|
||||
span #{result.blockstats.minfeerate.toLocaleString()}
|
||||
|
||||
else
|
||||
span ?
|
||||
|
||||
span.mx-2 -
|
||||
|
||||
if (result.blockstats.maxfeerate)
|
||||
span #{result.blockstats.maxfeerate.toLocaleString()}
|
||||
|
||||
else
|
||||
span ?
|
||||
|
||||
+summaryItem("Min / Max Values")
|
||||
if (result.blockstats.minfee)
|
||||
- var currencyValue = new Decimal(result.blockstats.minfee).dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include ./includes/value-display.pug
|
||||
else
|
||||
span 0
|
||||
|
||||
br
|
||||
|
||||
if (result.blockstats.maxfee)
|
||||
- var currencyValue = new Decimal(result.blockstats.maxfee).dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include ./includes/value-display.pug
|
||||
else
|
||||
span 0
|
||||
|
||||
+contentSection("Technical Details", true, "blockPageShowTechSummary")
|
||||
+summaryRow(6 + (result.getblock.weight ? 1 : 0) + (result.getblock.size ? 1 : 0) + (result.blockstats ? 1 : 0) + (result.blockstats && result.blockstats.utxo_increase ? 1 : 0) + (result.blockstats && result.blockstats.maxtxsize ? 1 : 0))
|
||||
if (result.getblock.weight)
|
||||
+summaryItem("Weight", null, "wu", "Weight Units")
|
||||
span #{result.getblock.weight.toLocaleString()}
|
||||
|
||||
- var full = new Decimal(result.getblock.weight).dividedBy(coinConfig.maxBlockWeight).times(100);
|
||||
- var full2 = full.toDP(0);
|
||||
|
||||
small.text-muted.ms-1
|
||||
| (
|
||||
span.border-dotted(title=`${full.toDP(2)}% full`, data-bs-toggle="tooltip")
|
||||
if (full >= 99 || full2 == 99)
|
||||
span.text-success 99+%
|
||||
|
||||
else
|
||||
span.text-primary #{full2}%
|
||||
| )
|
||||
|
||||
if (result.getblock.size)
|
||||
+summaryItem("Size", null, "B", "Bytes")
|
||||
| #{result.getblock.size.toLocaleString()}
|
||||
|
||||
if (result.blockstats)
|
||||
+summaryItem("Inputs / Outputs", "Total inputs and outputs across all transactions in the block")
|
||||
if (result.blockstats.ins)
|
||||
| #{result.blockstats.ins.toLocaleString()}
|
||||
else
|
||||
| 0
|
||||
|
||||
span.text-muted.mx-1 /
|
||||
|
||||
if (result.blockstats.outs)
|
||||
| #{result.blockstats.outs.toLocaleString()}
|
||||
else
|
||||
| 1
|
||||
|
||||
+summaryItem("Difficulty")
|
||||
- var difficultyData = utils.formatLargeNumber(result.getblock.difficulty, 3);
|
||||
|
||||
span(title=parseFloat(result.getblock.difficulty).toLocaleString(), data-bs-toggle="tooltip")
|
||||
span #{difficultyData[0]}
|
||||
span x 10
|
||||
sup #{difficultyData[1].exponent}
|
||||
|
||||
if (result.blockstats && result.blockstats.utxo_increase)
|
||||
+summaryItem("UTXO Δ")
|
||||
- var sizePlusMinus = (result.blockstats.utxo_size_inc > 0) ? "+" : "-";
|
||||
- var sizeDeltaData = utils.formatLargeNumber(Math.abs(result.blockstats.utxo_size_inc), 1);
|
||||
- var plusMinus = (result.blockstats.utxo_increase > 0) ? "+" : "";
|
||||
|
||||
span #{plusMinus}#{result.blockstats.utxo_increase.toLocaleString()}
|
||||
|
||||
if (result.blockstats && result.blockstats.maxtxsize)
|
||||
+summaryItem("Min / Max Tx Size", null, "B", "Bytes")
|
||||
if (result.blockstats.mintxsize)
|
||||
span #{result.blockstats.mintxsize.toLocaleString()}
|
||||
else
|
||||
span 0
|
||||
|
||||
span.text-muted.mx-1 -
|
||||
|
||||
if (result.blockstats.maxtxsize)
|
||||
span #{result.blockstats.maxtxsize.toLocaleString()}
|
||||
else
|
||||
span 0
|
||||
|
||||
+summaryItem("Version")
|
||||
| 0x#{result.getblock.versionHex}
|
||||
|
||||
+summaryItem("Nonce")
|
||||
| #{result.getblock.nonce}
|
||||
|
||||
+summaryItem("Bits")
|
||||
| #{result.getblock.bits}
|
||||
|
||||
+summaryItem("Merkle Root")
|
||||
| #{utils.ellipsizeMiddle(result.getblock.merkleroot, 12)}
|
||||
+copyTextButton(result.getblock.merkleroot)
|
||||
|
||||
+summaryItem("Chain Work", null, "hashes")
|
||||
- var chainworkData = utils.formatLargeNumber(parseInt("0x" + result.getblock.chainwork), 2);
|
||||
|
||||
span #{chainworkData[0]}
|
||||
span x 10
|
||||
sup #{chainworkData[1].exponent}
|
||||
|
||||
|
||||
if (!result.getblock.tx || result.getblock.tx.length == 0)
|
||||
+contentSection(`${txCount.toLocaleString()} Transaction${txCount>1?'s':''}`)
|
||||
span.me-2(title="This data is unavailable due to blockchain pruning", data-bs-toggle="tooltip")
|
||||
i.fas.fa-backspace.text-danger
|
||||
|
||||
| Transaction details unavailable due to blockchain pruning
|
||||
|
||||
else
|
||||
+contentSection(`${txCount.toLocaleString()} Transaction${txCount == 1 ? "" : "s"}`, false, "blockPageShowTxDetails", true, false)
|
||||
+txList(result.transactions, txCount, limit, offset, result.txInputsByTransaction, {sharedBlockHeight: result.getblock.height})
|
||||
|
||||
|
||||
|
||||
+pageTab("JSON")
|
||||
- var blockDetails = JSON.parse(JSON.stringify(result.getblock));
|
||||
- blockDetails.tx = "See 'Transaction IDs'";
|
||||
|
||||
- var pillTabs = ["Block Summary", "Transaction IDs"];
|
||||
if (result.blockstats)
|
||||
- pillTabs.push("Block Stats");
|
||||
|
||||
+pillTabs(pillTabs)
|
||||
|
||||
|
||||
div.tab-content
|
||||
+pageTab("Block Summary", true)
|
||||
+contentSection("Block Summary")
|
||||
div.highlight
|
||||
pre
|
||||
code.json #{JSON.stringify(blockDetails, null, 4)}
|
||||
|
||||
|
||||
|
||||
+pageTab("Transaction IDs")
|
||||
+contentSection("Transaction IDs")
|
||||
div.highlight
|
||||
pre
|
||||
code.json #{JSON.stringify(result.getblock.tx, null, 4)}
|
||||
|
||||
if (result.blockstats)
|
||||
+pageTab("Block Stats")
|
||||
+contentSection("Block Stats")
|
||||
div.highlight
|
||||
pre
|
||||
code.json #{JSON.stringify(result.blockstats, null, 4)}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ block headContent
|
|||
title Blocks
|
||||
|
||||
block content
|
||||
h1.h3 Blocks
|
||||
hr
|
||||
+pageTitle("Blocks")
|
||||
|
||||
if (blocks)
|
||||
nav(aria-label="Page navigation")
|
||||
|
|
@ -19,21 +18,15 @@ block content
|
|||
a.page-link(href=(sort == "asc" ? "javascript:void(0)" : `./blocks?limit=${limit}&offset=0&sort=asc`))
|
||||
span(aria-hidden="true") Oldest blocks first
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
include includes/blocks-list.pug
|
||||
|
||||
+contentSection
|
||||
include includes/blocks-list.pug
|
||||
|
||||
if (blockCount > limit)
|
||||
.border.border-2.mt-4
|
||||
|
||||
.mt-4
|
||||
+pagination(limit, offset, sort, blockCount, paginationBaseUrl, "center", true)
|
||||
|
||||
if (blockCount > limit)
|
||||
- var pageNumber = offset / limit + 1;
|
||||
- var pageCount = Math.floor(blockCount / limit);
|
||||
- if (pageCount * limit < blockCount) {
|
||||
- pageCount++;
|
||||
- }
|
||||
- var paginationUrlFunction = function(x) {
|
||||
- return paginationBaseUrl + "?limit=" + limit + "&offset=" + ((x - 1) * limit + "&sort=" + sort);
|
||||
- }
|
||||
|
||||
div.pt-5
|
||||
include includes/pagination.pug
|
||||
else
|
||||
p No blocks found
|
||||
|
|
|
|||
|
|
@ -4,12 +4,9 @@ block headContent
|
|||
title Changelog
|
||||
|
||||
style.
|
||||
code { padding: 0px 3px; border: solid 1px #ccc; border-radius: 3px; background-color: #ccc; color: black; }
|
||||
|
||||
block content
|
||||
h1.h3 Changelog
|
||||
hr
|
||||
+pageTitle("Changelog / Release Notes")
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
| !{changelogHtml}
|
||||
+contentSection
|
||||
| !{changelogHtml}
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
extends layout
|
||||
|
||||
block content
|
||||
h1.h3 RPC Connect
|
||||
hr
|
||||
+pageTitle("RPC Connect")
|
||||
|
||||
form(method="post", action="./connect")
|
||||
input(type="hidden", name="_csrf", value=csrfToken)
|
||||
|
|
|
|||
|
|
@ -4,25 +4,25 @@ block headContent
|
|||
title Difficulty History
|
||||
|
||||
block content
|
||||
h1.h3 Difficulty History
|
||||
hr
|
||||
+pageTitle("Difficulty History")
|
||||
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Explanation
|
||||
hr
|
||||
+dismissableInfoAlert("diffHistPageNoteDismissed", "About the Difficulty Adjustment...")
|
||||
h6.mb-2 About the Difficulty Adjustment
|
||||
|
||||
ul.mb-0
|
||||
li Mining difficulty adjusts automatically every #{coinConfig.difficultyAdjustmentBlockCount.toLocaleString()} blocks.
|
||||
li The adjustment aims to maintain an average block-mining time of #{coinConfig.targetBlockTimeMinutes} minutes.
|
||||
li A growth in the difficulty indicates that the average block-mining time during the previous adjustment epoch was less than #{coinConfig.targetBlockTimeMinutes} minutes (due to more miners joining the network and searching for blocks).
|
||||
li A drop in difficulty indicates miners have left the network so finding each block is adjusted to be easier for the smaller number remaining.
|
||||
li The numeric Difficulty is a multiple of the difficulty of finding the easiest block (Block #0) - e.g. blocks in BTC mainnet epoch 308 are over 16 trillion times harder to mine than those in epoch 0.
|
||||
ul.mb-0.ms-n3
|
||||
li Mining difficulty adjusts automatically every #{coinConfig.difficultyAdjustmentBlockCount.toLocaleString()} blocks.
|
||||
li The adjustment aims to maintain an average block-mining time of #{coinConfig.targetBlockTimeMinutes} minutes.
|
||||
li An increase in the difficulty indicates that the average block-mining time during the previous adjustment epoch was less than #{coinConfig.targetBlockTimeMinutes} minutes (due to more miners joining the network and searching for blocks).
|
||||
li A decrease in difficulty indicates miners have left the network so finding each block is adjusted to be easier for the smaller number remaining.
|
||||
li The numeric Difficulty is a multiple of the difficulty of finding the easiest block (Block #0) - e.g. blocks in BTC mainnet epoch 308 are over 16 trillion times harder to mine than those in epoch 0.
|
||||
|
||||
|
||||
|
||||
div#progress-wrapper.mb-huge
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6 Loading data:
|
||||
span Loading data:
|
||||
span(id="progress-text")
|
||||
div.progress.mt-2(id="progress-bar", style="height: 7px;")
|
||||
div.progress-bar(id="data-progress", role="progressbar", aria-valuenow="0", aria-valuemin="0" ,aria-valuemax="100")
|
||||
|
|
@ -31,27 +31,34 @@ block content
|
|||
div#main-content(style="display: none;")
|
||||
div.row
|
||||
div.col
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Difficulty History
|
||||
hr
|
||||
+contentSection("Difficulty History")
|
||||
canvas(id="graph-diff-hist")
|
||||
|
||||
canvas(id="graph-diff-hist")
|
||||
|
||||
|
||||
div.row
|
||||
div.row
|
||||
div.col
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Difficulty Change (clamped to ±100%)
|
||||
hr
|
||||
.clearfix
|
||||
.float-start
|
||||
+sectionTitle("Difficulty Δ")
|
||||
.float-start
|
||||
small.text-muted.ms-2
|
||||
| (clamped to ±100%)
|
||||
|
||||
canvas(id="graph-diff-change")
|
||||
+contentSection
|
||||
canvas(id="graph-diff-change")
|
||||
|
||||
|
||||
|
||||
block endOfBody
|
||||
script(src="./js/chart.bundle.min.js", integrity="sha384-qgOtiGNaHh9fVWUnRjyHlV39rfbDcvPPkEzL1RHvsHKbuqUqM6uybNuVnghY2z4/")
|
||||
+graphPageScriptSetup
|
||||
|
||||
script(src='./js/decimal.js')
|
||||
|
||||
script.
|
||||
Chart.defaults.global.defaultFontSize = 14;
|
||||
|
||||
|
||||
script.
|
||||
var blockCount = !{blockCount};
|
||||
|
||||
|
|
@ -143,6 +150,9 @@ block endOfBody
|
|||
display: true,
|
||||
labelString: 'Difficulty Epoch'
|
||||
},
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
//ticks: {
|
||||
// stepSize: 100,
|
||||
//}
|
||||
|
|
@ -151,6 +161,20 @@ block endOfBody
|
|||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: yLabelStr
|
||||
},
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
},
|
||||
ticks: {
|
||||
callback: function(value, index, values) {
|
||||
if (value > 1000) {
|
||||
var exp = Math.floor(Math.log10(value));
|
||||
return (value / Math.pow(10, exp)).toLocaleString() + "e" + exp;
|
||||
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
extends layout
|
||||
|
||||
block content
|
||||
h1 Error
|
||||
hr
|
||||
+pageTitle("Error")
|
||||
|
||||
if (message)
|
||||
pre
|
||||
code.json.bg-light !{message}
|
||||
code.json.bg-body !{message}
|
||||
else
|
||||
p Unknown error
|
||||
|
||||
if (error)
|
||||
h2 #{error.status}
|
||||
pre
|
||||
code.json.bg-light #{error.stack}
|
||||
code.json.bg-body #{error.stack}
|
||||
|
|
|
|||
|
|
@ -4,52 +4,57 @@ block headContent
|
|||
title #{coinConfig.name} Fun
|
||||
|
||||
block content
|
||||
h1.h3 #{coinConfig.name} Fun
|
||||
hr
|
||||
+pageTitle(`${coinConfig.name} Fun`)
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
p Below is a list of fun/interesting things in the #{coinConfig.name} blockchain. Some are historical firsts, others are just fun or cool.
|
||||
|
||||
div.table-responsive
|
||||
table.table.table-striped
|
||||
thead
|
||||
tr
|
||||
th.data-header Date
|
||||
th.data-header Description
|
||||
th.data-header Link
|
||||
th.data-header Reference
|
||||
tbody
|
||||
each item, index in coinConfig.historicalData
|
||||
if (item.chain == activeBlockchain)
|
||||
tr
|
||||
td.data-cell #{item.date}
|
||||
|
||||
td.data-cell #{item.summary}
|
||||
|
||||
td.data-cell.font-monospace
|
||||
if (item.type == "tx")
|
||||
a(href=`./tx/${item.txid}@${item.blockHeight}`, title=item.txid, data-bs-toggle="tooltip") Tx #{utils.ellipsize(item.txid, 23)}
|
||||
else if (item.type == "block")
|
||||
a(href=`./block/${item.blockHash}`, title=`Block ${item.blockHash}`, data-bs-toggle="tooltip") Block #{utils.ellipsize(item.blockHash, 20)}
|
||||
else if (item.type == "blockheight")
|
||||
a(href=`./block/${item.blockHash}`) Block ##{item.blockHeight}
|
||||
else if (item.type == "address")
|
||||
a(href=`./address/${item.address}`, title=item.address, data-bs-toggle="tooltip") Address #{utils.ellipsize(item.address, 18)}
|
||||
else if (item.type == "link")
|
||||
a(href=item.url) #{item.url.substring(0, 20)}...
|
||||
+dismissableInfoAlert("funPageNoteDismissed", "About Bitcoin Fun...")
|
||||
.mb-2 This is a curated list of fun and interesting things in the blockchain or related to the underlying data:
|
||||
ul
|
||||
li Historical firsts
|
||||
li Technical quirks and oddities
|
||||
li Cultural references
|
||||
|
||||
.mb-0 Help curating this list is welcome! You can submit new items by opening an issue or PR on <a href="https://github.com/janoside/btc-rpc-explorer">Github</a>.
|
||||
|
||||
|
||||
+contentSection
|
||||
.table-responsive
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th.data-header Date
|
||||
th.data-header Item
|
||||
th.data-header Reference
|
||||
tbody
|
||||
each item, index in coinConfig.historicalData
|
||||
if (item.chain == activeBlockchain)
|
||||
tr
|
||||
td.data-cell #{item.date}
|
||||
|
||||
if (true)
|
||||
td.data-cell
|
||||
if (item.referenceUrl && item.referenceUrl.trim().length > 0)
|
||||
- var matches = item.referenceUrl.match(/^https?\:\/\/([^\/:?#]+)(?:[\/:?#]|$)/i);
|
||||
if (item.type == "tx")
|
||||
a(href=`./tx/${item.txid}@${item.blockHeight}`) #{item.summary}
|
||||
else if (item.type == "block")
|
||||
a(href=`./block/${item.blockHash}`) #{item.summary}
|
||||
else if (item.type == "blockheight")
|
||||
a(href=`./block/${item.blockHash}`) #{item.summary}
|
||||
else if (item.type == "address")
|
||||
a(href=`./address/${item.address}`) #{item.summary}
|
||||
else if (item.type == "link")
|
||||
a(href=item.url) #{item.summary}
|
||||
|
||||
td.data-cell
|
||||
if (item.referenceUrl && item.referenceUrl.trim().length > 0)
|
||||
- var matches = item.referenceUrl.match(/^https?\:\/\/([^\/:?#]+)(?:[\/:?#]|$)/i);
|
||||
|
||||
- var domain = null;
|
||||
- var domain = matches && matches[1];
|
||||
- var domain = null;
|
||||
- var domain = matches && matches[1];
|
||||
|
||||
if (domain)
|
||||
a(href=item.referenceUrl, rel="nofollow") #{domain}
|
||||
i.fas.fa-external-link-alt
|
||||
else
|
||||
a(href=item.referenceUrl, rel="nofollow") Reference
|
||||
if (domain)
|
||||
a(href=item.referenceUrl, rel="nofollow") #{domain}
|
||||
i.fas.fa-external-link-alt
|
||||
else
|
||||
span -
|
||||
a(href=item.referenceUrl, rel="nofollow") Reference
|
||||
else
|
||||
span -
|
||||
|
|
|
|||
|
|
@ -1,483 +0,0 @@
|
|||
div.mb-2
|
||||
if (result.getblock.previousblockhash)
|
||||
a.btn.btn-sm.btn-primary.mb-1(href=`./block/${result.getblock.previousblockhash}`) « Prev Block:
|
||||
span.font-monospace ##{(result.getblock.height - 1).toLocaleString()}
|
||||
|
||||
else if (result.getblock.hash == genesisBlockHash)
|
||||
span.btn.btn-sm.btn-secondary.disabled.mb-1 « Prev Block: none (genesis block)
|
||||
|
||||
span.mx-2
|
||||
|
||||
if (result.getblock.nextblockhash)
|
||||
a.btn.btn-sm.btn-primary.mb-1(href=`./block/${result.getblock.nextblockhash}`) Next Block:
|
||||
span.font-monospace ##{(result.getblock.height + 1).toLocaleString()}
|
||||
span »
|
||||
else
|
||||
a.btn.btn-sm.btn-secondary.disabled.mb-1 Next Block: N/A
|
||||
small (latest block)
|
||||
|
||||
ul.nav.nav-tabs.mb-3
|
||||
li.nav-item
|
||||
a.nav-link.active(data-bs-toggle="tab", href="#tab-details", role="tab") Details
|
||||
li.nav-item
|
||||
a.nav-link(data-bs-toggle="tab", href="#tab-json", role="tab") JSON
|
||||
|
||||
- var txCount = result.getblock.nTx;
|
||||
|
||||
div.tab-content
|
||||
div.tab-pane.active(id="tab-details", role="tabpanel")
|
||||
if (global.specialBlocks && global.specialBlocks[result.getblock.hash])
|
||||
div.alert.alert-primary.shadow-sm.pb-0
|
||||
div.float-start(style="width: 55px; height: 55px; font-size: 18px;")
|
||||
i.fas.fa-certificate.fa-2x(style="margin-top: 10px;")
|
||||
h4.alert-heading.h6.fw-bold #{coinConfig.name} Fun
|
||||
|
||||
// special transaction info
|
||||
- var sbInfo = global.specialBlocks[result.getblock.hash];
|
||||
if (sbInfo.alertBodyHtml)
|
||||
p
|
||||
span !{sbInfo.alertBodyHtml}
|
||||
|
||||
if (sbInfo.referenceUrl && sbInfo.referenceUrl.trim().length > 0 && sbInfo.alertBodyHtml.indexOf(sbInfo.referenceUrl) == -1)
|
||||
span
|
||||
a(href=sbInfo.referenceUrl) Read more
|
||||
|
||||
else
|
||||
p
|
||||
span #{sbInfo.summary}
|
||||
|
||||
if (sbInfo.referenceUrl && sbInfo.referenceUrl.trim().length > 0)
|
||||
span
|
||||
a(href=sbInfo.referenceUrl) Read more
|
||||
|
||||
div.row
|
||||
- var sumTableLabelClass = (result.blockstats != null ? "summary-split-table-label" : "summary-table-label");
|
||||
- var sumTableValueClass = (result.blockstats != null ? "summary-split-table-content" : "summary-table-content");
|
||||
|
||||
div.mb-3(class=(result.blockstats != null ? "col-md-6 pr-0" : "col-md-12"))
|
||||
div.card.shadow-sm(style="height: 100%;")
|
||||
div.card-body.px-2.px-md-3
|
||||
h3.h6.mb-0 Summary
|
||||
hr
|
||||
|
||||
div.clearfix
|
||||
div.row
|
||||
div(class=sumTableLabelClass) Date
|
||||
div.font-monospace(class=sumTableValueClass)
|
||||
- var timestampHuman = result.getblock.time;
|
||||
include ./timestamp-human.pug
|
||||
small.ms-1 utc
|
||||
|
||||
- var timeAgoTime = result.getblock.time;
|
||||
span.text-muted.ms-2 (
|
||||
include ./time-ago-text.pug
|
||||
span ago)
|
||||
|
||||
if (result.blockstats)
|
||||
div.row
|
||||
div(class=sumTableLabelClass)
|
||||
span.border-dotted(title="Total value of all transaction outputs", data-bs-toggle="tooltip")
|
||||
span Total Output
|
||||
div.font-monospace(class=sumTableValueClass)
|
||||
if (result.blockstats.total_out)
|
||||
- var currencyValue = new Decimal(result.blockstats.total_out).plus(new Decimal(result.blockstats.totalfee)).plus(new Decimal(result.blockstats.subsidy));
|
||||
- currencyValue = currencyValue.dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include ./value-display.pug
|
||||
else
|
||||
span 0
|
||||
|
||||
if (result.blockstats)
|
||||
div.row
|
||||
div(class=sumTableLabelClass)
|
||||
span.border-dotted(title="Total number of inputs and outputs", data-toggle="tooltip")
|
||||
span In #
|
||||
span.text-muted.font-weight-normal.mx-1 /
|
||||
span Out #
|
||||
div.text-monospace(class=sumTableValueClass)
|
||||
if (result.blockstats.ins)
|
||||
span #{result.blockstats.ins.toLocaleString()}
|
||||
else
|
||||
span 0
|
||||
|
||||
span.text-muted.mx-1 /
|
||||
|
||||
if (result.blockstats.outs)
|
||||
span #{result.blockstats.outs.toLocaleString()}
|
||||
else
|
||||
span 1
|
||||
|
||||
if (result.blockstats)
|
||||
div.row
|
||||
div(class=sumTableLabelClass)
|
||||
span.border-dotted(title="Change in number (and size) of UTXO set.", data-toggle="tooltip")
|
||||
span UTXO Δ
|
||||
div.text-monospace(class=sumTableValueClass)
|
||||
- var sizePlusMinus = (result.blockstats.utxo_size_inc > 0) ? "+" : "-";
|
||||
- var sizeDeltaData = utils.formatLargeNumber(Math.abs(result.blockstats.utxo_size_inc), 1);
|
||||
- var plusMinus = (result.blockstats.utxo_increase > 0) ? "+" : "";
|
||||
if (result.blockstats.utxo_increase)
|
||||
span #{plusMinus}#{result.blockstats.utxo_increase.toLocaleString()}
|
||||
span.text-muted (#{sizePlusMinus}#{sizeDeltaData[0]}
|
||||
small #{sizeDeltaData[1].abbreviation}B
|
||||
span )
|
||||
else
|
||||
span 0
|
||||
|
||||
if (result.blockstats && result.blockstats.maxtxsize)
|
||||
div.row
|
||||
div(class=sumTableLabelClass) Min, Max Tx Size
|
||||
div.text-monospace(class=sumTableValueClass)
|
||||
if (result.blockstats.mintxsize)
|
||||
span #{result.blockstats.mintxsize.toLocaleString()}
|
||||
else
|
||||
span 0
|
||||
|
||||
span.text-muted.mx-1 -
|
||||
|
||||
if (result.blockstats.maxtxsize)
|
||||
span #{result.blockstats.maxtxsize.toLocaleString()}
|
||||
small B
|
||||
else
|
||||
span 0
|
||||
|
||||
if (result.getblock.coinbaseTx)
|
||||
- var blockRewardMax = coinConfig.blockRewardFunction(result.getblock.height, activeBlockchain);
|
||||
- var coinbaseTxTotalOutputValue = new Decimal(0);
|
||||
each vout in result.getblock.coinbaseTx.vout
|
||||
- coinbaseTxTotalOutputValue = coinbaseTxTotalOutputValue.plus(new Decimal(vout.value));
|
||||
|
||||
if (parseFloat(coinbaseTxTotalOutputValue) < blockRewardMax)
|
||||
div.row
|
||||
div(class=sumTableLabelClass)
|
||||
span.border-dotted(data-bs-toggle="tooltip" title="The miner of this block failed to collect this value. As a result, it is permanently lost.") Value Destroyed
|
||||
div.font-monospace.text-danger(class=sumTableValueClass)
|
||||
- var currencyValue = new Decimal(blockRewardMax).minus(coinbaseTxTotalOutputValue);
|
||||
include ./value-display.pug
|
||||
|
||||
else if (result.getblock.subsidy != null)
|
||||
div.row
|
||||
div(class=sumTableLabelClass)
|
||||
span.border-dotted(title="Value of the block subsidy", data-bs-toggle="tooltip")
|
||||
span Subsidy
|
||||
div.font-monospace(class=sumTableValueClass)
|
||||
- var currencyValue = new Decimal(result.getblock.subsidy);
|
||||
include ./value-display.pug
|
||||
|
||||
if (result.getblock.weight)
|
||||
div.row
|
||||
div(class=sumTableLabelClass) Weight
|
||||
div.text-monospace(class=sumTableValueClass)
|
||||
span #{result.getblock.weight.toLocaleString()}
|
||||
small wu
|
||||
|
||||
span.text-muted (#{new Decimal(100 * result.getblock.weight / coinConfig.maxBlockWeight).toDecimalPlaces(2)}% full)
|
||||
|
||||
if (result.getblock.size)
|
||||
div.row
|
||||
div(class=sumTableLabelClass) Size
|
||||
div.text-monospace(class=sumTableValueClass) #{result.getblock.size.toLocaleString()}
|
||||
small B
|
||||
|
||||
if (result.getblock.miner)
|
||||
div.row
|
||||
div(class=sumTableLabelClass) Miner
|
||||
div.font-monospace(class=sumTableValueClass)
|
||||
if (result.getblock.miner.identifiedBy)
|
||||
span.badge.bg-primary(data-bs-toggle="tooltip", title=`Identified by: ${result.getblock.miner.identifiedBy}`) #{result.getblock.miner.name}
|
||||
|
||||
else
|
||||
small.data-tag.bg-primary #{result.getblock.miner.name}
|
||||
|
||||
div.row
|
||||
div(class=sumTableLabelClass) Confirmations
|
||||
div.font-monospace(class=sumTableValueClass)
|
||||
if (result.getblock.confirmations < 6)
|
||||
span.fw-bold.text-warning #{result.getblock.confirmations.toLocaleString()}
|
||||
a(data-bs-toggle="tooltip", title="Fewer than 6 confirmations is generally considered 'unsettled' for high-value transactions. The applicability of this guidance may vary.")
|
||||
i.fas.fa-unlock-alt
|
||||
else
|
||||
span.fw-bold.text-success #{result.getblock.confirmations.toLocaleString()}
|
||||
a(data-bs-toggle="tooltip", title="6 confirmations is generally considered 'settled'. High-value transactions may require more; low-value transactions may require less.")
|
||||
i.fas.fa-lock
|
||||
|
||||
if (result.blockstats)
|
||||
div.col-md-6.mb-3
|
||||
div.card.shadow-sm(style="height: 100%;")
|
||||
div.card-body.px-2.px-md-3
|
||||
h3.h6.mb-0 Fees Summary
|
||||
hr
|
||||
|
||||
div.clearfix
|
||||
if (result.blockstats.ins == 0 || !result.blockstats.ins)
|
||||
span.font-monospace N/A (no inputs)
|
||||
|
||||
else
|
||||
div.row
|
||||
div.summary-split-table-label Total
|
||||
div.summary-split-table-content.font-monospace
|
||||
if (result.blockstats.totalfee)
|
||||
- var currencyValue = new Decimal(result.blockstats.totalfee).dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include ./value-display.pug
|
||||
|
||||
else
|
||||
- var currencyValue = new Decimal(result.getblock.totalFees);
|
||||
include ./value-display.pug
|
||||
|
||||
if (result.blockstats)
|
||||
div.row
|
||||
div.summary-split-table-label Rate Percentiles
|
||||
br
|
||||
small.fw-normal (sat/vB)
|
||||
div.summary-split-table-content.font-monospace
|
||||
div.clearfix
|
||||
each item, itemIndex in [10, 25, 50, 75, 90]
|
||||
div.float-start.me-3
|
||||
span.fw-bold #{item}%
|
||||
br
|
||||
|
||||
if (result.blockstats.feerate_percentiles)
|
||||
span #{JSON.stringify(result.blockstats.feerate_percentiles[itemIndex])}
|
||||
else
|
||||
span -
|
||||
|
||||
if (result.getblock.totalFees > 0)
|
||||
div.row
|
||||
div.summary-split-table-label
|
||||
span.border-dotted(title="These are the fee rates (fee per tx weight) for transactions in this block - min, avg, and max.", data-bs-toggle="tooltip") Fee Rates
|
||||
br
|
||||
small.fw-normal (min, avg, max)
|
||||
|
||||
div.summary-split-table-content.font-monospace
|
||||
if (result.blockstats.minfeerate)
|
||||
span #{result.blockstats.minfeerate.toLocaleString()}
|
||||
small.ms-1 sat/vB
|
||||
else
|
||||
span ?
|
||||
|
||||
br
|
||||
|
||||
if (result.blockstats.avgfeerate)
|
||||
span #{result.blockstats.avgfeerate.toLocaleString()}
|
||||
small.ms-1 sat/vB
|
||||
|
||||
else
|
||||
- var currencyValue = new Decimal(result.getblock.totalFees).dividedBy(result.getblock.strippedsize).times(coinConfig.baseCurrencyUnit.multiplier).toDecimalPlaces(1);
|
||||
span #{currencyValue}
|
||||
|
||||
br
|
||||
|
||||
if (result.blockstats.maxfeerate)
|
||||
span #{result.blockstats.maxfeerate.toLocaleString()}
|
||||
small.ms-1 sat/vB
|
||||
else
|
||||
span ?
|
||||
|
||||
if (result.blockstats)
|
||||
div.row
|
||||
div.summary-split-table-label
|
||||
span.border-dotted(title="These are the overall fee values (min, avg, max) for transactions included in this block. The min and max values correspond to specific transactions in this block; the avg is an estimate.", data-bs-toggle="tooltip") Fee Values
|
||||
br
|
||||
small.fw-normal (min, avg, max)
|
||||
div.summary-split-table-content.font-monospace
|
||||
if (result.blockstats.minfee)
|
||||
- var currencyValue = new Decimal(result.blockstats.minfee).dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include ./value-display.pug
|
||||
else
|
||||
span 0
|
||||
|
||||
br
|
||||
|
||||
if (result.blockstats.avgfee)
|
||||
- var currencyValue = new Decimal(result.blockstats.avgfee).dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include ./value-display.pug
|
||||
else
|
||||
span 0
|
||||
|
||||
br
|
||||
|
||||
if (result.blockstats.maxfee)
|
||||
- var currencyValue = new Decimal(result.blockstats.maxfee).dividedBy(coinConfig.baseCurrencyUnit.multiplier);
|
||||
include ./value-display.pug
|
||||
else
|
||||
span 0
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-md-3
|
||||
div.clearfix
|
||||
div.float-left.mr-2
|
||||
h3.h6.mb-0 Technical Details
|
||||
|
||||
div.float-right
|
||||
if (!session.blockPageShowTechSummary || session.blockPageShowTechSummary == "true")
|
||||
a(href="./changeSetting?name=blockPageShowTechSummary&value=false") hide
|
||||
else
|
||||
a(href="./changeSetting?name=blockPageShowTechSummary&value=true") show
|
||||
|
||||
div(id="tech-details-wrapper", class=(session.blockPageShowTechSummary == "true" ? "" : "d-none"))
|
||||
hr
|
||||
|
||||
div.row
|
||||
div.col-md-6
|
||||
div.row
|
||||
div.summary-split-table-label Difficulty
|
||||
div.summary-split-table-content.font-monospace
|
||||
- var difficultyData = utils.formatLargeNumber(result.getblock.difficulty, 3);
|
||||
|
||||
span(title=parseFloat(result.getblock.difficulty).toLocaleString(), data-bs-toggle="tooltip")
|
||||
span #{difficultyData[0]}
|
||||
span x 10
|
||||
sup #{difficultyData[1].exponent}
|
||||
|
||||
div.row
|
||||
div.summary-split-table-label Version
|
||||
div.summary-split-table-content.font-monospace 0x#{result.getblock.versionHex}
|
||||
span.text-muted (decimal: #{result.getblock.version})
|
||||
|
||||
div.row
|
||||
div.summary-split-table-label Nonce
|
||||
div.summary-split-table-content.font-monospace #{result.getblock.nonce}
|
||||
|
||||
div.row
|
||||
div.summary-split-table-label Bits
|
||||
div.summary-split-table-content.font-monospace #{result.getblock.bits}
|
||||
|
||||
div.row
|
||||
div.summary-split-table-label Merkle Root
|
||||
div.summary-split-table-content.font-monospace #{result.getblock.merkleroot}
|
||||
|
||||
div.row
|
||||
div.summary-split-table-label Chainwork
|
||||
div.summary-split-table-content.font-monospace
|
||||
- var chainworkData = utils.formatLargeNumber(parseInt("0x" + result.getblock.chainwork), 2);
|
||||
|
||||
span #{chainworkData[0]}
|
||||
span x 10
|
||||
sup #{chainworkData[1].exponent}
|
||||
small hashes
|
||||
|
||||
span.text-muted (#{result.getblock.chainwork.replace(/^0+/, '')})
|
||||
|
||||
|
||||
if (!result.getblock.tx || result.getblock.tx.length == 0)
|
||||
div.card.shadow-sm.mb-3: div.card-body.px-2.px-md-3
|
||||
h2.h6.mb-0.d-inline-block #{txCount.toLocaleString()} Transaction#{txCount>1?'s':''}
|
||||
.text-muted.pt-2
|
||||
span.me-2(title="This data is unavailable due to blockchain pruning", data-bs-toggle="tooltip")
|
||||
i.fas.fa-backspace.text-danger
|
||||
|
||||
| Details unavailable due to blockchain pruning
|
||||
else
|
||||
div.card.shadow-sm.mb-3: div.card-body.px-2.px-md-3
|
||||
div.row
|
||||
div.col-md-4
|
||||
h2.h6.mb-0.d-inline-block #{txCount.toLocaleString()}
|
||||
if (txCount == 1)
|
||||
span Transaction
|
||||
else
|
||||
span Transactions
|
||||
|
||||
if (result.getblock.tx != null && result.getblock.tx.length > 0)
|
||||
a.ms-2.border-dotted(href=`./block-analysis/${result.getblock.hash}`, title="See a summary analysis of all transactions in this block.", data-bs-toggle="tooltip") See Block Analysis »
|
||||
|
||||
if (false || (!config.demoSite && !crawlerBot && txCount > 20))
|
||||
div.col-md-8.text-end
|
||||
small.me-1.text-muted Show
|
||||
div.btn-group(role="group")
|
||||
a.btn.btn-sm.btn-primary.px-2.py-0(href=`${paginationBaseUrl}?limit=20`, class=((limit == 20 && txCount > limit) ? "active" : false)) 20
|
||||
|
||||
if (txCount > 50)
|
||||
a.btn.btn-sm.btn-primary.px-2.py-0(href=`${paginationBaseUrl}?limit=50` class=(limit == 50 ? "active" : false)) 50
|
||||
|
||||
if (txCount > 100)
|
||||
a.btn.btn-sm.btn-primary.px-2.py-0(href=`${paginationBaseUrl}?limit=100`, class=(limit == 100 ? "active" : false)) 100
|
||||
|
||||
a.btn.btn-sm.btn-primary.px-2.py-0(href=`${paginationBaseUrl}?limit=3000`, class=(limit >= txCount ? "active" : false)) all
|
||||
|
||||
hr
|
||||
|
||||
- var fontawesomeInputName = "sign-in-alt";
|
||||
- var fontawesomeOutputName = "sign-out-alt";
|
||||
|
||||
div
|
||||
- tx_height_param = !global.txindexAvailable ? `@${result.getblock.height}` : ''
|
||||
each tx, txIndex in result.transactions
|
||||
div.card.shadow-sm(class=(" " + ((txIndex < (result.transactions.length - 1) || txCount > limit) ? "mb-3" : "")))
|
||||
div.card-header.font-monospace
|
||||
if (tx && tx.txid)
|
||||
span(title=`Index in Block: #${(txIndex + offset).toLocaleString()}`, data-bs-toggle="tooltip") ##{(txIndex + offset).toLocaleString()}
|
||||
span –
|
||||
a(href=`./tx/${tx.txid}${tx_height_param}`) #{tx.txid}
|
||||
|
||||
if (global.specialTransactions && global.specialTransactions[tx.txid])
|
||||
span
|
||||
a(data-bs-toggle="tooltip", title=`${coinConfig.name} Fun! See transaction for details`)
|
||||
i.fas.fa-certificate.text-primary
|
||||
|
||||
div.card-body.px-2.px-md-3
|
||||
if (true)
|
||||
- var txInputs = result.txInputsByTransaction[tx.txid];
|
||||
- var blockHeight = result.getblock.height;
|
||||
|
||||
include ./transaction-io-details.pug
|
||||
|
||||
|
||||
if (!crawlerBot && txCount > limit)
|
||||
- var pageNumber = offset / limit + 1;
|
||||
- var pageCount = Math.floor(txCount / limit);
|
||||
- if (pageCount * limit < txCount) {
|
||||
- pageCount++;
|
||||
- }
|
||||
- var paginationUrlFunction = function(x) {
|
||||
- return paginationBaseUrl + "?limit=" + limit + "&offset=" + ((x - 1) * limit);
|
||||
- }
|
||||
|
||||
hr
|
||||
|
||||
include ./pagination.pug
|
||||
|
||||
div.tab-pane(id="tab-json", role="tabpanel")
|
||||
- var blockDetails = JSON.parse(JSON.stringify(result.getblock));
|
||||
- blockDetails.tx = "See 'Transaction IDs'";
|
||||
|
||||
ul.nav.nav-pills.mb-3
|
||||
li.nav-item
|
||||
a.nav-link.active(data-bs-toggle="tab", href="#tab-json-block-summary", role="tab") Block Summary
|
||||
li.nav-item
|
||||
a.nav-link(data-bs-toggle="tab", href="#tab-json-tx-ids", role="tab") Transaction IDs
|
||||
|
||||
if (result.blockstats)
|
||||
li.nav-item
|
||||
a.nav-link(data-bs-toggle="tab", href="#tab-json-blockstats", role="tab") Block Stats
|
||||
|
||||
div.tab-content
|
||||
div.tab-pane.active(id="tab-json-block-summary", role="tabpanel")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6.mb-0 Block Summary
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light #{JSON.stringify(blockDetails, null, 4)}
|
||||
|
||||
div.tab-pane(id="tab-json-tx-ids", role="tabpanel")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6.mb-0 Transaction IDs
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light #{JSON.stringify(result.getblock.tx, null, 4)}
|
||||
|
||||
if (result.blockstats)
|
||||
div.tab-pane(id="tab-json-blockstats", role="tabpanel")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6.mb-0 Block Stats
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light #{JSON.stringify(result.blockstats, null, 4)}
|
||||
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
div.table-responsive
|
||||
.table-responsive
|
||||
table.table.table-borderless.table-striped.mb-0
|
||||
thead
|
||||
tr
|
||||
//th
|
||||
th
|
||||
if (!hideBlockIndex)
|
||||
th
|
||||
|
||||
th.data-header.text-end Height
|
||||
|
||||
|
|
@ -13,7 +14,7 @@ div.table-responsive
|
|||
|
||||
th.data-header.text-end Age
|
||||
th.data-header.text-end
|
||||
span.border-dotted(title="Time To Mine - The time it took to mine this block after the previous block. 'Fast' blocks (mined in < 5min) are shown in green; 'slow' blocks (mined in > 15min) are shown in red.", data-bs-toggle="tooltip") T.T.M.
|
||||
span.border-dotted(title="<b>Time To Mine</b><br/>The time it took to mine this block after the previous block. <span class='text-success'>Fast</span> blocks (< 5min) and <span class='text-danger'>Slow</span> blocks (> 15min) are highlighted.", data-bs-toggle="tooltip", data-bs-html="true") TTM
|
||||
th.data-header.text-end Miner
|
||||
th.data-header.text-end
|
||||
span.border-dotted(title="The number of transactions included in each block.", data-bs-toggle="tooltip") N(tx)
|
||||
|
|
@ -50,16 +51,18 @@ div.table-responsive
|
|||
|
||||
if (block && ((sort == "desc" && (blockIndex < blocks.length - 1 || block.height == 0)) || (sort == "asc" && (block.height == 0 || blockIndex > 0))))
|
||||
tr
|
||||
td
|
||||
if (sort == "desc")
|
||||
small.text-muted #{(blockIndex + offset + 1).toLocaleString()}
|
||||
else
|
||||
small.text-muted #{(blockIndex + offset).toLocaleString()}
|
||||
if (!hideBlockIndex)
|
||||
td
|
||||
if (sort == "desc")
|
||||
small.text-muted #{(blockIndex + offset + 1).toLocaleString()}
|
||||
else
|
||||
small.text-muted #{(blockIndex + offset).toLocaleString()}
|
||||
|
||||
td.data-cell.font-monospace.text-end
|
||||
if (global.specialBlocks && global.specialBlocks[block.hash])
|
||||
a(data-bs-toggle="tooltip", title=`${coinConfig.name} Fun! See block for details`)
|
||||
i.fas.fa-certificate.text-primary.me-1
|
||||
a(data-bs-toggle="tooltip", title=`<b>${coinConfig.name} Fun!</b><br/>There's something special about this block...<br/>Click to read more.`, data-bs-html="true")
|
||||
span.me-2
|
||||
+funItemIcon
|
||||
|
||||
a(href=`./block-height/${block.height}`) #{block.height.toLocaleString()}
|
||||
|
||||
|
|
@ -78,8 +81,7 @@ div.table-responsive
|
|||
|
||||
if (!hideTimestampColumn)
|
||||
td.data-cell.font-monospace.text-end
|
||||
- var timestampHuman = block.time;
|
||||
include timestamp-human.pug
|
||||
+timestamp(block.time, false)
|
||||
|
||||
|
||||
td.data-cell.font-monospace.text-end
|
||||
|
|
@ -122,9 +124,9 @@ div.table-responsive
|
|||
span.badge.bg-primary(data-bs-toggle="tooltip", title=`Identified by: ${block.miner.identifiedBy}`) #{utils.ellipsize(block.miner.name, 14)}
|
||||
|
||||
else if (block.height < global.pruneHeight)
|
||||
span.border-dotted(title="Determining the miner of a block requires that the block not be pruned. Sadly, this block has been pruned.", data-bs-toggle="tooltip")
|
||||
i.fas.fa-backspace.text-danger.me-2
|
||||
| ?
|
||||
span(title="This data is unavailable due to blockchain pruning", data-bs-toggle="tooltip")
|
||||
i.fas.fa-backspace.text-danger
|
||||
|
||||
else
|
||||
span ?
|
||||
|
||||
|
|
@ -145,9 +147,13 @@ div.table-responsive
|
|||
span 0
|
||||
|
||||
td.data-cell.font-monospace.text-end
|
||||
if block.totalFees && block.strippedsize
|
||||
if (block.totalFees && block.strippedsize)
|
||||
- var currencyValue = new Decimal(block.totalFees).dividedBy(block.strippedsize).times(coinConfig.baseCurrencyUnit.multiplier).toDecimalPlaces(0);
|
||||
span #{currencyValue}
|
||||
if (currencyValue > 0)
|
||||
span #{currencyValue}
|
||||
else
|
||||
span -
|
||||
|
||||
else
|
||||
span(title="This data is unavailable due to blockchain pruning", data-bs-toggle="tooltip")
|
||||
i.fas.fa-backspace.text-danger
|
||||
|
|
|
|||
|
|
@ -4,266 +4,174 @@ if (exchangeRates || networkVolume)
|
|||
|
||||
- var utxoCalculatingDesc = "At startup the app pulls a summary of the UTXO set. Until this summary is retrieved this data can't be displayed. Wait for the summary request to your node to return, then refresh this page.";
|
||||
|
||||
div.row.index-summary
|
||||
div(class=colClass)
|
||||
h5.h6 Mining
|
||||
|
||||
table.table.table-borderless.table-sm.table-hover.mb-lg-0
|
||||
tbody
|
||||
|
||||
if (hashrate1d && hashrate7d)
|
||||
- var hashrate1dayData0 = utils.formatLargeNumber(hashrate1d, 0);
|
||||
- var hashrate7dayData0 = utils.formatLargeNumber(hashrate7d, 0);
|
||||
- var hashrate1dayData1 = utils.formatLargeNumber(hashrate1d, 1);
|
||||
- var hashrate7dayData1 = utils.formatLargeNumber(hashrate7d, 1);
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-tachometer-alt.mr-1.summary-icon
|
||||
span.border-dotted(title="Estimates for global network hashrate for 1 day / 7 days.", data-toggle="tooltip") Hashrate
|
||||
small.ml-1 (d/w)
|
||||
td.text-right.text-monospace
|
||||
span.d-xxl-none #{hashrate1dayData0[0]}
|
||||
span.d-none.d-xxl-inline #{hashrate1dayData1[0]}
|
||||
small.text-muted /
|
||||
span.d-xxl-none #{hashrate7dayData0[0]}
|
||||
span.d-none.d-xxl-inline #{hashrate7dayData1[0]}
|
||||
small.border-dotted(title=`${hashrate1dayData0[1].abbreviation}H = ${hashrate1dayData0[1].name}-hash (x10^${hashrate1dayData0[1].exponent})`, data-toggle="tooltip") #{hashrate1dayData0[1].abbreviation}H/s
|
||||
|
||||
if (!["regtest", "signet"].includes(global.activeBlockchain))
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-edit.mr-1.summary-icon
|
||||
span.border-dotted(title="Estimate of the number of days the current global hashrate would require to produce all the hashes needed to re-write the entire blockchain.", data-toggle="tooltip") Chain Rewrite Days
|
||||
td.text-right.text-monospace
|
||||
- var globalHashCount = parseInt("0x" + getblockchaininfo.chainwork);
|
||||
- var rewriteDays = globalHashCount / hashrate7d / 60 / 60 / 24;
|
||||
span #{new Decimal(rewriteDays).toDecimalPlaces(1)}
|
||||
if (exchangeRates)
|
||||
+contentSection("Market")
|
||||
- var colCount = 3 + (networkVolume ? 1 : 0) + (goldExchangeRates ? 1 : 0);
|
||||
+summaryRow(colCount)
|
||||
+summaryItem("Exchange Rate", `Source: ${new URL(coinConfig.exchangeRateData.jsonUrl).hostname}`)
|
||||
span.text-success #{utils.formatValueInActiveCurrency(1.0)}
|
||||
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-dumbbell.mr-1.summary-icon
|
||||
span Difficulty
|
||||
td.text-right.text-monospace
|
||||
- var difficultyData = utils.formatLargeNumber(getblockchaininfo.difficulty, 2);
|
||||
span.border-dotted(data-toggle="tooltip", title=parseFloat(getblockchaininfo.difficulty).toLocaleString())
|
||||
span #{difficultyData[0]}
|
||||
small.px-2.px-lg-0.px-xl-2 x
|
||||
span 10
|
||||
sup #{difficultyData[1].exponent}
|
||||
+summaryItem("Sats Rate")
|
||||
- var satsRateData = utils.satoshisPerUnitOfActiveCurrency();
|
||||
span #{satsRateData.amt}
|
||||
small #{satsRateData.unit}
|
||||
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-unlock.mr-1.summary-icon
|
||||
span Pending Tx
|
||||
td.text-right.text-monospace
|
||||
if (mempoolInfo)
|
||||
- var colorClass = "text-success";
|
||||
if (mempoolInfo.size > 7000)
|
||||
- colorClass = "text-warning";
|
||||
if (mempoolInfo.size > 11000)
|
||||
- colorClass = "text-danger";
|
||||
+summaryItem("Market Cap")
|
||||
- var supply = utils.estimatedSupply(getblockchaininfo.blocks);
|
||||
- var activeCurrency = global.currencyFormatType.length > 0 ? global.currencyFormatType : "usd";
|
||||
- var xxx = utils.formatLargeNumber(parseFloat(supply) * exchangeRates[activeCurrency], 3);
|
||||
|
||||
span(class=colorClass) #{mempoolInfo.size.toLocaleString()}
|
||||
if (activeCurrency == "eur")
|
||||
span €
|
||||
else
|
||||
span $
|
||||
|
||||
else
|
||||
span.text-danger.border-dotted(title="There was an error getting this data. Check your application logs for possible explanation.", data-toggle="tooltip") Error
|
||||
span #{xxx[0]}
|
||||
if (xxx[1].textDesc)
|
||||
span #{xxx[1].textDesc}
|
||||
else
|
||||
span x 10
|
||||
sup #{xxx[1].exponent}
|
||||
// ["154.9",{"val":1000000000,"name":"giga","abbreviation":"G","exponent":"9"}]
|
||||
|
||||
if (smartFeeEstimates)
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-bullseye.mr-1.summary-icon
|
||||
span.border-dotted(title="Current fee estimates (using 'estimatesmartfee') for getting a transaction included in 1 block, 6 blocks (1 hr), 144 blocks (1 day), or 1,008 blocks (1 week).", data-toggle="tooltip") Fee Targets
|
||||
if (false)
|
||||
small.ml-1 (1/h/d/w)
|
||||
td.text-right.text-monospace
|
||||
if (smartFeeEstimates)
|
||||
span #{smartFeeEstimates[1]}
|
||||
small.d-md-none
|
||||
small.text-muted /
|
||||
span #{smartFeeEstimates[6]}
|
||||
small.text-muted /
|
||||
span #{smartFeeEstimates[144]}
|
||||
small.text-muted /
|
||||
span #{smartFeeEstimates[1008]}
|
||||
small sat/vB
|
||||
if (goldExchangeRates)
|
||||
+summaryItem("Gold Rate", `Source: ${new URL(coinConfig.goldExchangeRateData.jsonUrl).hostname}`)
|
||||
span.text-warning #{utils.formatValueInGoldOunces(1.0)}
|
||||
small.ms-1.text-muted oz
|
||||
|
||||
if (networkVolume)
|
||||
+summaryItem("24hr Volume", `Total output of all transactions over the last 24hrs (blocks: [#${networkVolume.d1.endBlock.toLocaleString()} - #${networkVolume.d1.startBlock.toLocaleString()}]).`)
|
||||
- var currencyValue = parseInt(networkVolume.d1.amt);
|
||||
- var currencyValueDecimals = 0;
|
||||
include ./value-display.pug
|
||||
|
||||
|
||||
|
||||
.clearfix
|
||||
.float-start
|
||||
+sectionTitle("Network Summary")
|
||||
.float-end
|
||||
if (userSettings.homepageShowTechDetails == "true")
|
||||
a.me-2(href="./changeSetting?name=homepageShowTechDetails&value=false", title="Hide technical network details", data-bs-toggle="tooltip", data-bs-placement="bottom")
|
||||
i.fas.fa-server.text-muted
|
||||
|
||||
else
|
||||
a.me-2(href="./changeSetting?name=homepageShowTechDetails&value=true", title="Show technical network details", data-bs-toggle="tooltip", data-bs-placement="bottom")
|
||||
i.fas.fa-server.text-muted
|
||||
|
||||
+contentSection
|
||||
+summaryRow(1 + (hashrate7d ? 1 : 0) + (chainTxStats[7 * targetBlocksPerDay] ? 1 : 0) + (difficultyAdjustmentData ? 1 : 0))
|
||||
if (hashrate7d)
|
||||
+summaryItem("7d Hashrate")
|
||||
- var hashrate7dayData = utils.formatLargeNumber(hashrate7d, 1);
|
||||
|
||||
span.me-2 #{hashrate7dayData[0]}
|
||||
span.border-dotted.me-2(title=`${hashrate7dayData[1].abbreviation}H = ${hashrate7dayData[1].name}-hash (x10^${hashrate7dayData[1].exponent})` data-bs-toggle='tooltip') #{hashrate7dayData[1].abbreviation}H/s
|
||||
|
||||
if (hashrate30d)
|
||||
- var ratio = hashrate7d / hashrate30d;
|
||||
|
||||
small
|
||||
| (
|
||||
span.border-dotted(title='7d hashrate vs 30d hashrate.' data-bs-toggle='tooltip')
|
||||
if (ratio > 1)
|
||||
- var ratioPercent = new Decimal(ratio).times(100).minus(100);
|
||||
span.text-success +#{ratioPercent.toDP(1)}%
|
||||
|
||||
else
|
||||
span.text-danger.border-dotted(title="There was an error getting this data. Check your application logs for possible explanation.", data-toggle="tooltip") Error
|
||||
- var ratioPercent = new Decimal(100).minus(new Decimal(ratio).times(100));
|
||||
span.text-danger -#{ratioPercent.toDP(1)}%
|
||||
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-clock.mr-1.summary-icon
|
||||
span.border-dotted(title=`Average block time for blocks in the current difficulty epoch (#${difficultyPeriod}). The difference between the target (${coinConfig.targetBlockTimeMinutes}min) and this time indicates how the difficulty will adjust for the next epoch.`, data-toggle="tooltip") Block Time
|
||||
small.ml-1 (e#{difficultyPeriod.toLocaleString()})
|
||||
td.text-right.text-monospace
|
||||
- var firstBlockHeader = difficultyPeriodFirstBlockHeader;
|
||||
- var currentBlock = latestBlocks[0];
|
||||
- var heightDiff = currentBlock.height - firstBlockHeader.height;
|
||||
- var timeDiff = currentBlock.mediantime - firstBlockHeader.mediantime;
|
||||
- var timePerBlock = timeDiff / heightDiff;
|
||||
- var timePerBlockDuration = moment.duration(timePerBlock * 1000);
|
||||
- var daysUntilAdjustment = new Decimal(blocksUntilDifficultyAdjustment).times(timePerBlock).dividedBy(60 * 60 * 24);
|
||||
- var duaDP1 = daysUntilAdjustment.toDP(1);
|
||||
- var daysUntilAdjustmentStr = daysUntilAdjustment > 1 ? `~${duaDP1} day${duaDP1 == "1" ? "" : "s"}` : "< 1 day"
|
||||
| )
|
||||
|
||||
if (timePerBlock > 600)
|
||||
- var diffAdjPercent = new Decimal(timeDiff / heightDiff / 600).times(100).minus(100);
|
||||
- var diffAdjText = `Blocks during the current difficulty epoch have taken this long, on average, to be mined. If this pace continues, then in ${blocksUntilDifficultyAdjustment.toLocaleString()} block${blocksUntilDifficultyAdjustment == 1 ? "" : "s"} (${daysUntilAdjustmentStr}) the difficulty will adjust downward: -${diffAdjPercent.toDP(1)}%`;
|
||||
- var diffAdjSign = "-";
|
||||
else
|
||||
- var diffAdjPercent = new Decimal(100).minus(new Decimal(timeDiff / heightDiff / 600).times(100));
|
||||
- var diffAdjText = `Blocks during the current difficulty epoch have taken this long, on average, to be mined. If this pace continues, then in ${blocksUntilDifficultyAdjustment.toLocaleString()} block${blocksUntilDifficultyAdjustment == 1 ? "" : "s"} (${daysUntilAdjustmentStr}) the difficulty will adjust upward: +${diffAdjPercent.toDP(1)}%`;
|
||||
- var diffAdjSign = "+";
|
||||
if (chainTxStats[7 * targetBlocksPerDay])
|
||||
+summaryItem("7d Transactions")
|
||||
| #{chainTxStats[7 * targetBlocksPerDay].window_tx_count.toLocaleString()}
|
||||
|
||||
span.border-dotted(title=diffAdjText, data-toggle="tooltip") #{timePerBlockDuration.format()}
|
||||
if (!isNaN(diffAdjPercent))
|
||||
small.text-muted.ml-1 (#{diffAdjSign}#{diffAdjPercent.toDP(1)}%)
|
||||
|
||||
if (difficultyAdjustmentData)
|
||||
- var desc = `Estimate for the difficulty adjustment that will occur in ${difficultyAdjustmentData.blocksLeft.toLocaleString()} block${difficultyAdjustmentData.blocksLeft == 1 ? "" : "s"} (${difficultyAdjustmentData.daysLeftStr}). This is calculated using the average block time over the last ${difficultyAdjustmentData.calculationBlockCount} block(s). This estimate becomes more reliable as the difficulty epoch nears its end.`;
|
||||
|
||||
+summaryItem("Difficulty Δ", desc)
|
||||
span.me-2(class=(difficultyAdjustmentData.sign == "+" ? "text-success" : "text-danger")) #{difficultyAdjustmentData.sign}#{difficultyAdjustmentData.delta.toDP(2)}
|
||||
small.text-muted
|
||||
| (#{difficultyAdjustmentData.daysLeftStr})
|
||||
|
||||
div(class=colClass)
|
||||
h5.h6 Blockchain
|
||||
+summaryItem("Coins", utxoSetSummary ? null : `This value is estimated.`)
|
||||
- var maxSupply = coinConfig.maxSupplyByNetwork[activeBlockchain];
|
||||
|
||||
table.table.table-borderless.table-sm.table-hover.mb-lg-0
|
||||
tbody
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-sign-out-alt.mr-1.summary-icon
|
||||
//span Total Transactions
|
||||
span Total Txs
|
||||
td.text-right.text-monospace
|
||||
if (txStats && txStats.totalTxCount)
|
||||
span #{txStats.totalTxCount.toLocaleString()}
|
||||
else
|
||||
span ???
|
||||
if (utxoSetSummary)
|
||||
span #{parseFloat(utxoSetSummary.total_amount).toLocaleString()}
|
||||
small.ms-2.text-muted
|
||||
| (
|
||||
span.border-dotted(title=`${new Decimal(utxoSetSummary.total_amount).dividedBy(maxSupply).times(100).toDP(4)}% have been mined into circulation`, data-bs-toggle="tooltip") #{new Decimal(utxoSetSummary.total_amount).dividedBy(maxSupply).times(100).toDP(1)}%
|
||||
| )
|
||||
|
||||
if (getblockchaininfo.size_on_disk)
|
||||
- var sizeData = utils.formatLargeNumber(getblockchaininfo.size_on_disk, 2);
|
||||
else
|
||||
- var estimatedSupply = utils.estimatedSupply(getblockchaininfo.blocks);
|
||||
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-database.mr-1.summary-icon
|
||||
span Data Size
|
||||
td.text-right.text-monospace #{sizeData[0]} #{sizeData[1].abbreviation}B
|
||||
span #{parseFloat(estimatedSupply).toLocaleString()}
|
||||
small.ms-2.text-muted
|
||||
| (
|
||||
span.border-dotted(title=`${estimatedSupply.dividedBy(maxSupply).times(100).toDP(4)}% have been mined into circulation`, data-bs-toggle="tooltip") #{estimatedSupply.dividedBy(maxSupply).times(100).toDP(1)}%
|
||||
| )
|
||||
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-bolt.mr-1.summary-icon
|
||||
span.border-dotted(title="The total amount of work necessary to produce the active chain, approximated in 'hashes'.", data-toggle="tooltip") Chain Work
|
||||
td.text-right.text-monospace
|
||||
- var chainworkData = utils.formatLargeNumber(parseInt("0x" + getblockchaininfo.chainwork), 2);
|
||||
span.border-dotted(data-toggle="tooltip", title=`hex: ${getblockchaininfo.chainwork.replace(/^0+/, '')}`)
|
||||
span #{chainworkData[0]}
|
||||
small.px-2.px-lg-0.px-xl-2 x
|
||||
span 10
|
||||
sup #{chainworkData[1].exponent}
|
||||
|
||||
|
||||
if (false)
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-arrow-circle-up.mr-1.summary-icon
|
||||
span.border-dotted(title="The active 'soft' forks on the network.", data-toggle="tooltip") Soft-Forks
|
||||
td.text-right.text-monospace.word-wrap
|
||||
ul.list-inline.mb-0
|
||||
each softforkData, softforkName in getblockchaininfo.softforks
|
||||
li.list-inline-item
|
||||
small.border-dotted(title=`${JSON.stringify(softforkData)}`, data-toggle="tooltip") #{softforkName}
|
||||
hr.mt-4.mb-4
|
||||
|
||||
+summaryRow(4)
|
||||
+summaryItem("Mempool")
|
||||
span(class=(mempoolInfo.size > 11000) ? "text-danger" : (mempoolInfo.size > 7000 ? "text-warning" : "text-success")) #{mempoolInfo.size.toLocaleString()}
|
||||
|
||||
if (false)
|
||||
+summaryItem("Next Block (est.)")
|
||||
| #{new Decimal(nextBlockMinFeeRate).toDP(0)}
|
||||
a(href=`./tx/${nextBlockMinFeeTxid}`)
|
||||
i.fas.fa-circle
|
||||
| - #{new Decimal(nextBlockMaxFeeRate).toDP(0)}
|
||||
a(href=`./tx/${nextBlockMaxFeeTxid}`)
|
||||
i.fas.fa-circle
|
||||
small.ms-2.text-muted sat/vB
|
||||
|
||||
+summaryItem("Smart Fee (1 block)")
|
||||
| #{smartFeeEstimates[1]}
|
||||
small.ms-2.text-muted sat/vB
|
||||
|
||||
+summaryItem("Smart Fee (1 hr)")
|
||||
| #{smartFeeEstimates[6]}
|
||||
small.ms-2.text-muted sat/vB
|
||||
|
||||
+summaryItem("Smart Fee (1 day)")
|
||||
| #{smartFeeEstimates[144]}
|
||||
small.ms-2.text-muted sat/vB
|
||||
|
||||
if (userSettings.homepageShowTechDetails == "true")
|
||||
hr.mt-4.mb-4
|
||||
|
||||
+summaryRow(1 + (getblockchaininfo.size_on_disk ? 1 : 0) + (utxoSetSummary || utxoSetSummaryPending ? 1 : 0))
|
||||
if (getblockchaininfo.size_on_disk)
|
||||
+summaryItem("Disk Usage")
|
||||
- var sizeData = utils.formatLargeNumber(getblockchaininfo.size_on_disk, 1);
|
||||
| #{sizeData[0]} #{sizeData[1].abbreviation}B
|
||||
|
||||
+summaryItem("Total Hashes", "Estimate of the total work necessary to produce the blockchain, measured in 'hashes'.")
|
||||
- var chainworkData = utils.formatLargeNumber(parseInt("0x" + getblockchaininfo.chainwork), 2);
|
||||
span #{chainworkData[0]}
|
||||
small.px-2.px-lg-0.px-xl-2 x
|
||||
span 10
|
||||
sup #{chainworkData[1].exponent}
|
||||
|
||||
|
||||
if (utxoSetSummary || utxoSetSummaryPending)
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-grip-horizontal.mr-1.summary-icon
|
||||
span.border-dotted(title="The number / data size of 'unspent transaction outputs' (UTXOs) in the blockchain.", data-toggle="tooltip") UTXO Set
|
||||
td.text-right.text-monospace
|
||||
if (utxoSetSummary)
|
||||
- var utxoCount = utils.formatLargeNumber(utxoSetSummary.txouts, 2);
|
||||
- var utxoDataSize = utils.formatLargeNumber(utxoSetSummary.disk_size, 2);
|
||||
span #{utxoCount[0]} #{utxoCount[1].abbreviation}
|
||||
small.text-muted /
|
||||
span #{utxoDataSize[0]} #{utxoDataSize[1].abbreviation}B
|
||||
else
|
||||
small.text-muted.border-dotted(title=utxoCalculatingDesc, data-toggle="tooltip") calculating...
|
||||
if (utxoSetSummary || utxoSetSummaryPending)
|
||||
+summaryItem("UTXOs", "The total number of unspent transaction outputs (spendable coin units).")
|
||||
if (utxoSetSummary)
|
||||
- var utxoCount = utils.formatLargeNumber(utxoSetSummary.txouts, 2);
|
||||
//| #{utxoCount[0]} #{utxoCount[1].abbreviation}
|
||||
| #{utxoSetSummary.txouts.toLocaleString()}
|
||||
else
|
||||
small.text-muted.border-dotted(title=utxoCalculatingDesc, data-bs-toggle="tooltip") calculating...
|
||||
|
||||
if (utxoSetSummary || utxoSetSummaryPending)
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fab.fa-bitcoin.mr-1.summary-icon
|
||||
span Total Supply
|
||||
td.text-right.text-monospace
|
||||
if (utxoSetSummary)
|
||||
- var maxSupply = coinConfig.maxSupplyByNetwork[activeBlockchain];
|
||||
|
||||
span.border-dotted(title=`${new Decimal(utxoSetSummary.total_amount).dividedBy(maxSupply).times(100).toDP(4)}% produced`, data-toggle="tooltip") #{parseFloat(utxoSetSummary.total_amount).toLocaleString()}
|
||||
else
|
||||
small.text-muted.border-dotted(title=utxoCalculatingDesc, data-toggle="tooltip") calculating...
|
||||
|
||||
if (networkVolume || exchangeRates)
|
||||
div(class=colClass)
|
||||
h5.h6 Financials
|
||||
|
||||
table.table.table-borderless.table-sm.table-hover.mb-lg-0
|
||||
tbody
|
||||
if (exchangeRates)
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-money-bill-wave-alt.mr-1.summary-icon
|
||||
span.border-dotted(data-toggle="tooltip", title=`Exchange-rate data from: ${coinConfig.exchangeRateData.jsonUrl}`) Exchange Rate
|
||||
td.text-right.text-monospace
|
||||
span #{utils.formatValueInActiveCurrency(1.0)}
|
||||
|
||||
if (exchangeRates)
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fab.fa-btc.mr-1.summary-icon
|
||||
span Sats Rate
|
||||
td.text-right.text-monospace
|
||||
- var satsRateData = utils.satoshisPerUnitOfActiveCurrency();
|
||||
span #{satsRateData.amt}
|
||||
small #{satsRateData.unit}
|
||||
|
||||
if (exchangeRates && goldExchangeRates)
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-mountain.mr-1.summary-icon
|
||||
span.border-dotted(data-toggle="tooltip", title=`Exchange-rate data from: ${coinConfig.goldExchangeRateData.jsonUrl}`) AU Exchange Rate
|
||||
td.text-right.text-monospace
|
||||
span #{utils.formatValueInGold(1.0)}
|
||||
|
||||
if (exchangeRates)
|
||||
if (utxoSetSummary || utxoSetSummaryPending)
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-globe.mr-1.summary-icon
|
||||
span Market Cap
|
||||
td.text-right.text-monospace
|
||||
if (utxoSetSummary)
|
||||
- var activeCurrency = global.currencyFormatType.length > 0 ? global.currencyFormatType : "usd";
|
||||
- var xxx = utils.formatLargeNumber(parseFloat(utxoSetSummary.total_amount) * exchangeRates[activeCurrency], 1);
|
||||
|
||||
if (activeCurrency == "eur")
|
||||
span €
|
||||
else
|
||||
span $
|
||||
|
||||
span #{xxx[0]}
|
||||
if (xxx[1].textDesc)
|
||||
span #{xxx[1].textDesc}
|
||||
else
|
||||
span x 10
|
||||
sup #{xxx[1].exponent}
|
||||
// ["154.9",{"val":1000000000,"name":"giga","abbreviation":"G","exponent":"9"}]
|
||||
|
||||
else
|
||||
small.text-muted.border-dotted(title=utxoCalculatingDesc, data-toggle="tooltip") calculating...
|
||||
|
||||
if (networkVolume)
|
||||
tr
|
||||
th.px-2.px-lg-0.px-xl-2
|
||||
i.fas.fa-history.mr-1.summary-icon
|
||||
span.border-dotted(title=`Total output of all transactions over the last 24 hrs (blocks: [#${networkVolume.d1.endBlock.toLocaleString()} - #${networkVolume.d1.startBlock.toLocaleString()}]).`, data-toggle="tooltip") Volume
|
||||
small.ml-1 (24h)
|
||||
td.text-right.text-monospace
|
||||
- var currencyValue = parseInt(networkVolume.d1.amt);
|
||||
- var currencyValueDecimals = 0;
|
||||
include ./value-display.pug
|
||||
|
||||
|
|
@ -1,15 +1,7 @@
|
|||
script(src="./js/chart.bundle.min.js", integrity="sha384-qgOtiGNaHh9fVWUnRjyHlV39rfbDcvPPkEzL1RHvsHKbuqUqM6uybNuVnghY2z4/")
|
||||
+graphPageScriptSetup
|
||||
|
||||
canvas.mb-3(id=graphData.id)
|
||||
|
||||
if (session.uiTheme && session.uiTheme == "dark")
|
||||
script.
|
||||
Chart.defaults.global.defaultFontColor='white';
|
||||
else
|
||||
script.
|
||||
Chart.defaults.global.defaultFontColor='black';
|
||||
|
||||
|
||||
script.
|
||||
Chart.defaults.global.elements.point.radius = 1;
|
||||
var ctx = document.getElementById("#{graphData.id}").getContext('2d');
|
||||
|
|
@ -43,6 +35,9 @@ script.
|
|||
display: true,
|
||||
labelString: '#{graphData.xaxisTitle}'
|
||||
},
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
},
|
||||
ticks: {
|
||||
stepSize: #{graphData.xaxisStep},
|
||||
/*callback: function(value, index, values) {
|
||||
|
|
@ -63,6 +58,9 @@ script.
|
|||
display: true,
|
||||
labelString: '#{graphData.yaxisTitle}'
|
||||
},
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
},
|
||||
ticks: {
|
||||
callback: function(value, index, values) {
|
||||
if (value > 1000000) {
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ div.modal.fade(id="pageErrorsModal" role="dialog" aria-hidden="true")
|
|||
h6 Error ##{(itemIndex + 1).toLocaleString()}
|
||||
hr
|
||||
//pre
|
||||
// code.json.bg-light #{JSON.stringify(item.error, null, 4)}
|
||||
// code.json #{JSON.stringify(item.error, null, 4)}
|
||||
|
||||
pre
|
||||
code.json.bg-light #{JSON.stringify(item, null, 4)}
|
||||
code.json #{JSON.stringify(item, null, 4)}
|
||||
|
||||
if (item.error.userData)
|
||||
div.mb-3
|
||||
|
|
@ -30,14 +30,14 @@ div.modal.fade(id="pageErrorsModal" role="dialog" aria-hidden="true")
|
|||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light #{JSON.stringify(item.error.userData, null, 4)}
|
||||
code.json #{JSON.stringify(item.error.userData, null, 4)}
|
||||
|
||||
if (item.error.stack)
|
||||
h6 Stacktrace
|
||||
- var stackFirstNLines = item.error.stack.split("\n").slice(0, 7).join("\n");
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light #{stackFirstNLines}
|
||||
code.json #{stackFirstNLines}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
- var pageNumbers = [];
|
||||
- for (var x = 1; x <= pageCount; x++) {
|
||||
- pageNumbers.push(x);
|
||||
- }
|
||||
|
||||
nav(aria-label="Page navigation")
|
||||
ul.pagination.pagination-lg.justify-content-center.flex-wrap
|
||||
li.page-item(class=(pageNumber == 1 ? "disabled" : false))
|
||||
a.page-link(href=(pageNumber == 1 ? "javascript:void(0)" : paginationUrlFunction(pageNumber - 1)), aria-label="Previous")
|
||||
span(aria-hidden="true") «
|
||||
each x, xIndex in pageNumbers
|
||||
if (x >= (pageNumber - 4) && x <= (pageNumber + 4) || xIndex == 0 || xIndex == (pageNumbers.length - 1))
|
||||
li.page-item(class=(x == pageNumber ? "active" : false))
|
||||
a.page-link(href=(paginationUrlFunction(x))) #{x}
|
||||
|
||||
if (x == 1 && pageNumber > 6)
|
||||
li.page-item.disabled
|
||||
a.page-link(href="javascript:void(0)") ...
|
||||
|
||||
else if (x == (pageCount - 1) && pageNumber < (pageCount - 5))
|
||||
li.page-item.disabled
|
||||
a.page-link(href="javascript:void(0)") ...
|
||||
|
||||
li.page-item(class=(pageNumber == pageCount ? "disabled" : false))
|
||||
a.page-link(href=(pageNumber == pageCount ? "javascript:void(0)" : paginationUrlFunction(pageNumber + 1)), aria-label="Next")
|
||||
span(aria-hidden="true") »
|
||||
425
views/includes/shared-mixins.pug
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
mixin pageTitle(text, subtext, copyableSubtext=false)
|
||||
h1.fw-light.word-wrap.mb-4
|
||||
| #{text}
|
||||
br
|
||||
span.text-tiny #{subtext}
|
||||
if (copyableSubtext)
|
||||
small
|
||||
+copyTextButton(subtext)
|
||||
|
||||
//hr.mb-3
|
||||
|
||||
|
||||
mixin sectionTitle(text, toggle=false, toggleUniqueClass, toggleUserSettingName, toggleOpen)
|
||||
if (false)
|
||||
pre
|
||||
code.json #{JSON.stringify(session.userSettings)}
|
||||
|
||||
h3.h5.mb-1.fw-light(class=(toggle && !toggleOpen ? "mb-section" : false), class=(!toggle || toggleOpen ? "d-block" : "d-none"))
|
||||
| #{text}
|
||||
|
||||
if (toggle)
|
||||
small(title=`Toggle ${text}`, data-bs-toggle="tooltip")
|
||||
a.text-muted.fs-6(href=`./changeSetting?name=${toggleUserSettingName}&value=false`)
|
||||
i.toggle-plus-minus.far.ms-2(class=(toggleOpen ? "fa-minus-square" : "fa-plus-square"))
|
||||
|
||||
|
||||
mixin contentSection(title, toggleable=false, toggleUserSettingName, defaultOpen=true, cardUi=true)
|
||||
if (toggleable)
|
||||
- var toggleUniqueClass = `section-${utils.getRandomString(10, "aA#")}`;
|
||||
- var toggleOpen = userSettings[toggleUserSettingName] == null ? defaultOpen : (userSettings[toggleUserSettingName] == "true" || userSettings[toggleUserSettingName] == true);
|
||||
|
||||
if (title)
|
||||
+sectionTitle(title, toggleable, toggleUniqueClass, toggleUserSettingName, toggleOpen)
|
||||
|
||||
.mb-section(class=toggleUniqueClass, style=(toggleable && !toggleOpen ? "display: none;" : false))
|
||||
if (cardUi)
|
||||
.card.mb-section.shadow-sm
|
||||
.card-body
|
||||
block
|
||||
|
||||
else
|
||||
block
|
||||
|
||||
|
||||
mixin summaryRow(itemCount)
|
||||
- locals.summaryItemCount = itemCount;
|
||||
- locals.summaryItemIndex = 0;
|
||||
|
||||
- locals.colCounts = {"sm": 1, "md": Math.min(itemCount, 3), "lg": Math.min(itemCount, 4), "xl": Math.min(itemCount, 5)};
|
||||
- locals.rowCountsArray = utils.objectProperties(locals.colCounts).map(x => [x, locals.colCounts[x]]).map(x => [x[0], (Math.floor(itemCount / x[1]) + ((itemCount % x[1] > 0) ? 1 : 0))]);
|
||||
- locals.rowCounts = {};
|
||||
- locals.rowCountsArray.forEach(x => locals.rowCounts[x[0]] = x[1]);
|
||||
|
||||
//h1 #{itemCount} #{JSON.stringify(locals.rowCounts)}
|
||||
|
||||
.row.row-cols-1(class=utils.objectProperties(locals.colCounts).map(x => `row-cols-${x}-${locals.colCounts[x]}`).join(" "))
|
||||
block
|
||||
|
||||
|
||||
mixin summaryTitle(title, titleDesc, subtitle, subtitleDesc)
|
||||
span.fs-6.text-uppercase.fw-light.text-muted(class=(titleDesc ? "border-dotted" : false), class=(subtitle ? "me-2" : false), title=titleDesc, data-bs-toggle="tooltip", data-bs-html="true") #{title}
|
||||
if (subtitle)
|
||||
small.text-muted
|
||||
| (
|
||||
span(class=(subtitleDesc ? "border-dotted" : false), title=subtitleDesc, data-bs-toggle="tooltip", data-bs-html="true") #{subtitle}
|
||||
| )
|
||||
|
||||
|
||||
mixin summaryItem(title, titleDesc, subtitle, subtitleDesc)
|
||||
- var rowIndexes = utils.objectProperties(locals.colCounts).map(x => [x, locals.colCounts[x]]).map(x => [x[0], Math.floor(locals.summaryItemIndex / x[1])]);
|
||||
|
||||
.col(class=(locals.summaryItemIndex == (locals.summaryItemCount - 1) ? "mb-0" : "mb-3"), class=rowIndexes.map(x => `mb-${x[0]}-${(x[1] < (locals.rowCounts[x[0]] - 1) ? "4" : "0")}`))
|
||||
//span.text-danger (#{JSON.stringify(locals.rowCounts)})
|
||||
.text-start.text-md-center
|
||||
+summaryTitle(title, titleDesc, subtitle, subtitleDesc)
|
||||
|
||||
|
||||
.lead.text-start.text-md-center
|
||||
block
|
||||
|
||||
- locals.summaryItemIndex++;
|
||||
|
||||
|
||||
// options keys:
|
||||
// - blockHeightsByTxid
|
||||
// - sharedBlockHeight (int)
|
||||
// - showDates (true|false)
|
||||
// - highlightAddress (address)
|
||||
// - addrGainsByTxid (map)
|
||||
// - addrLossesByTxid (map)
|
||||
// - mempoolDetailsByTxid (map)
|
||||
|
||||
// txBlockHeightsByTxid_orSharedBlockHeight, showDates=false, highlightAddress, addrGainsByTxid, addrLossesByTxid)
|
||||
mixin txList(visibleTxs, txCount, limit, offset, inputsByTxid, options)
|
||||
if (txCount > limit)
|
||||
.rounded-0.rounded-top.bg-body.border
|
||||
.p-3
|
||||
h6.fw-normal.mb-2 #{offset.toLocaleString()} - #{Math.min(offset + limit - 1, txCount - 1).toLocaleString()} of #{txCount.toLocaleString()}
|
||||
+pagination(limit, offset, null, txCount, paginationBaseUrl)
|
||||
|
||||
|
||||
.border.border-2
|
||||
|
||||
|
||||
each tx, txIndex in visibleTxs
|
||||
- var txBlockHeight = null;
|
||||
if (options.blockHeightsByTxid)
|
||||
- txBlockHeight = options.blockHeightsByTxid[tx.txid];
|
||||
else if (options.sharedBlockHeight != undefined)
|
||||
- txBlockHeight = options.sharedBlockHeight;
|
||||
|
||||
- var tx_height_param = (!global.txindexAvailable && txBlockHeight) ? `@${txBlockHeight}` : '';
|
||||
|
||||
.border.bg-body.p-3(class=(txIndex == 0 && txCount <= limit ? "rounded-top" : false), class=(txCount <= limit && txIndex == (visibleTxs.length - 1) ? "rounded-bottom" : false))
|
||||
if (tx && tx.txid)
|
||||
.clearfix
|
||||
.float-start
|
||||
.mb-4.word-wrap
|
||||
span.badge.bg-primary.fw-normal.me-2(title=`Index in Block: #${(txIndex + offset).toLocaleString()}`, data-bs-toggle="tooltip") ##{(txIndex + offset).toLocaleString()}
|
||||
a(href=`./tx/${tx.txid}${tx_height_param}`) #{tx.txid}
|
||||
|
||||
if (global.specialTransactions && global.specialTransactions[tx.txid])
|
||||
a.ms-2(data-bs-toggle="tooltip", title=`<b>${coinConfig.name} Fun!</b><br/>There's something special about this transaction...<br/>Click to read more.`, data-bs-html="true")
|
||||
+funItemIcon
|
||||
|
||||
|
||||
.float-end
|
||||
if (options.mempoolDetailsByTxid && options.mempoolDetailsByTxid[tx.txid])
|
||||
- var mempoolDetails = options.mempoolDetailsByTxid[tx.txid].entry;
|
||||
- var feeRate = new Decimal(mempoolDetails.fee).times(coinConfig.baseCurrencyUnit.multiplier).dividedBy(mempoolDetails.vsize);
|
||||
|
||||
span.badge.bg-dark.ms-2
|
||||
| #{feeRate.toDP(0)}
|
||||
span.fw-light.ms-1 sat/vB
|
||||
|
||||
if (options.addrGainsByTxid && options.addrGainsByTxid[tx.txid])
|
||||
- var currencyValue = options.addrGainsByTxid[tx.txid];
|
||||
span.badge.bg-success.ms-2 +
|
||||
include ./value-display.pug
|
||||
|
||||
if (options.addrLossesByTxid && options.addrLossesByTxid[tx.txid])
|
||||
- var currencyValue = options.addrLossesByTxid[tx.txid];
|
||||
span.badge.bg-danger.ms-2 -
|
||||
include ./value-display.pug
|
||||
|
||||
if (options.showDates)
|
||||
span.badge.bg-dark.ms-2
|
||||
i.far.fa-clock.me-1
|
||||
|
||||
if (tx.time)
|
||||
+timeAgo(tx.time, true)
|
||||
span.ms-1 ago
|
||||
|
||||
else
|
||||
| unconfirmed
|
||||
|
||||
|
||||
div
|
||||
- var txInputs = inputsByTxid[tx.txid];
|
||||
- var blockHeight = txBlockHeight != undefined ? txBlockHeight : -1;
|
||||
|
||||
if (options.highlightAddress)
|
||||
- var txIOHighlightAddress = options.highlightAddress;
|
||||
|
||||
include ./transaction-io-details.pug
|
||||
|
||||
if (txIndex < (visibleTxs.length - 1) || txCount > limit)
|
||||
.border.border-2
|
||||
|
||||
|
||||
if (txCount > limit)
|
||||
.rounded-0.rounded-bottom.bg-body.border
|
||||
.p-3
|
||||
if (!crawlerBot && txCount > limit)
|
||||
h6.fw-normal.mb-2 #{offset.toLocaleString()} - #{Math.min(offset + limit - 1, txCount - 1).toLocaleString()} of #{txCount.toLocaleString()}
|
||||
+pagination(limit, offset, null, txCount, paginationBaseUrl)
|
||||
|
||||
|
||||
mixin pageTabs(names)
|
||||
ul.nav.nav-tabs
|
||||
each name, nameIndex in names
|
||||
li.nav-item(style=(nameIndex == 0 ? "margin-left: 10px;" : false))
|
||||
a.nav-link(class=(nameIndex == 0 ? "active" : false), data-bs-toggle="tab", href=`#tab-${name.replace(" ", "-")}`, role="tab") #{name}
|
||||
|
||||
.bg-gradient-body-to-main.pb-4.mb-4
|
||||
|
||||
|
||||
mixin pillTabs(names)
|
||||
ul.nav.nav-pills.mb-3
|
||||
each name, nameIndex in names
|
||||
li.nav-item
|
||||
a.nav-link(class=(nameIndex == 0 ? "active" : false), data-bs-toggle="tab", href=`#tab-${name.replace(" ", "-")}`, role="tab") #{name}
|
||||
|
||||
|
||||
mixin pageTab(name, defaultActive=false)
|
||||
div.tab-pane(id=`tab-${name.replace(" ", "-")}`, class=(defaultActive ? "active" : false), role="tabpanel")
|
||||
block
|
||||
|
||||
|
||||
mixin confirmations(confirmations, abbreviated=true)
|
||||
if (confirmations < 6)
|
||||
span.text-warning.border-dotted(title="Fewer than 6 confirmations is generally considered <b>unsettled</b> for high-value transactions because block <b>re-organizations</b> that could affect them have reasonable probability.", data-bs-toggle="tooltip", data-bs-html="true") #{confirmations.toLocaleString()}
|
||||
i.fas.fa-unlock-alt.ms-1
|
||||
else
|
||||
span.border-dotted.text-success(title="6 confirmations is generally considered <b>settled</b>. High-value transactions may require more;<br/>Low-value transactions may require fewer.", data-bs-toggle="tooltip", data-bs-html="true")
|
||||
| #{abbreviated && confirmations > 1000 ? `${Math.floor(confirmations/1000)}k` : confirmations.toLocaleString()}
|
||||
i.fas.fa-check.ms-1
|
||||
|
||||
|
||||
mixin timestamp(timestamp, includeAgo=true)
|
||||
- var utcMoment = moment.utc(new Date(parseInt(timestamp) * 1000));
|
||||
|
||||
- var yearStr = utcMoment.format("Y");
|
||||
- var nowYearStr = moment.utc(new Date()).format("Y");
|
||||
|
||||
- var dateStr = utcMoment.format("Y-M-D");
|
||||
- var nowDateStr = moment.utc(new Date()).format("Y-M-D");
|
||||
|
||||
- var titleStr = `${utcMoment.format("Y-MM-DD HH:mm:ss")} utc`;
|
||||
|
||||
if (dateStr == nowDateStr)
|
||||
span.border-dotted(title=titleStr, data-bs-toggle="tooltip")
|
||||
| #{utcMoment.format("HH:mm")}
|
||||
small.text-muted.ms-1 utc
|
||||
|
||||
else if (yearStr == nowYearStr)
|
||||
span.border-dotted(title=titleStr, data-bs-toggle="tooltip")
|
||||
| #{utcMoment.format("M/D HH:mm")}
|
||||
small.text-muted.ms-1 utc
|
||||
|
||||
else
|
||||
span.border-dotted(title=titleStr, data-bs-toggle="tooltip")
|
||||
| #{utcMoment.format("YYYY-MM-DD")}
|
||||
|
||||
if (includeAgo)
|
||||
small.text-muted.ms-2 (
|
||||
+timeAgo(timestamp, true)
|
||||
span ago)
|
||||
|
||||
|
||||
mixin funAlert(html, text, referenceUrl)
|
||||
.alert.alert-primary.shadow-sm.pb-0(role="alert", style="padding-left: 4rem;")
|
||||
i.fas.fa-flag.fa-2x.fontawesome-shadow.text-warning.d-inline-block(style="position: absolute; top: 0; left: 0; width: 40px; margin-left: 0.8rem; margin-top: 1.2rem;")
|
||||
|
||||
h5.mb-2.fw-light #{coinConfig.name} Fun
|
||||
|
||||
if (html)
|
||||
p
|
||||
span !{html}
|
||||
|
||||
if (referenceUrl && referenceUrl.trim().length > 0 && html.indexOf(referenceUrl) == -1)
|
||||
span
|
||||
a(href=referenceUrl) Read more
|
||||
|
||||
else if (text)
|
||||
p
|
||||
span #{text}
|
||||
|
||||
if (referenceUrl && referenceUrl.trim().length > 0)
|
||||
span
|
||||
a(href=referenceUrl) Read more
|
||||
|
||||
else if (block)
|
||||
p
|
||||
block
|
||||
|
||||
|
||||
mixin funItemIcon
|
||||
i.fas.fa-flag.text-warning
|
||||
|
||||
|
||||
mixin timeAgo(timeAgoTime, only1Element=false)
|
||||
- var timeAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date(parseInt(timeAgoTime) * 1000))));
|
||||
|
||||
if (timeAgo.asHours() < 1)
|
||||
if (timeAgo.asMinutes() < 1)
|
||||
span #{timeAgo.seconds()}s
|
||||
else
|
||||
span #{timeAgo.minutes()}m
|
||||
|
||||
else
|
||||
if (timeAgo.asHours() >= 1 && timeAgo.asHours() < 24)
|
||||
span #{timeAgo.hours()}h
|
||||
|
||||
if (!only1Element && timeAgo.minutes() > 0)
|
||||
span.ms-1 #{timeAgo.minutes()}m
|
||||
|
||||
else
|
||||
if (only1Element)
|
||||
span #{utils.shortenTimeDiff(timeAgo.format()).split(/,?\s+/)[0]}
|
||||
else
|
||||
span #{utils.shortenTimeDiff(timeAgo.format())}
|
||||
|
||||
|
||||
mixin copyTextButton(text)
|
||||
small.ms-2
|
||||
if (false)
|
||||
a.btn-clipboard(href="javascript:void(0)", title="Copy", data-clipboard-text=text, data-bs-toggle="tooltip", onclick=`copyTextToClipboard("${text}"); $(".icon-copy").toggle(); $(this).find(".icon-copied").toggle(); setTimeout(() => { $(this).find(".icon-copy").toggle(); $(this).find(".icon-copied").toggle(); }, 2000); return false;`)
|
||||
i.far.fa-copy.text-info.icon-copy
|
||||
i.fas.fa-check.text-success.icon-copied(style="display: none;")
|
||||
|
||||
a.btn-clipboard(href="javascript:void(0)", title="Copy", data-clipboard-text=text, data-bs-toggle="tooltip", onclick=`copyTextToClipboard("${text}"); $(this).attr("data-bs-original-title", "Copied!"); $(this).mouseleave(function() { $(this).tooltip("hide"); $(this).attr("data-bs-original-title", "Copy"); }); return false;`)
|
||||
i.far.fa-copy.text-info
|
||||
|
||||
|
||||
mixin dismissableInfoAlert(userSettingDismissedName, textToShowWhenClosed)
|
||||
if (session.userSettings[userSettingDismissedName] != "true")
|
||||
.alert.alert-primary.alert-dismissible.shadow-sm.mb-4(role="alert", style="padding-left: 4rem;")
|
||||
i.fas.fa-info-circle.fa-2x.d-inline-block(style="position: absolute; top: 0; left: 0; width: 40px; margin-left: 0.8rem; margin-top: 1.2rem;")
|
||||
|
||||
block
|
||||
|
||||
a.btn-close(href=`./changeSetting?name=${userSettingDismissedName}&value=true`, aria-label="Close", style="text-decoration: none;", title="Hide this note", data-bs-toggle="tooltip")
|
||||
//button.btn-close.text-muted(type="button", data-bs-dismiss="alert", aria-label="Close", title="Hide this note", data-bs-toggle="tooltip")
|
||||
|
||||
else if (textToShowWhenClosed)
|
||||
.alert.alert-primary.shadow-sm.mb-4(role="alert")
|
||||
.clearfix
|
||||
.float-start
|
||||
i.fas.fa-info-circle.fa-lg.me-3
|
||||
| #{textToShowWhenClosed}
|
||||
|
||||
.float-end
|
||||
a.text-muted(href=`./changeSetting?name=${userSettingDismissedName}&value=false`, aria-label="Close", style="text-decoration: none;", title="Open this note", data-bs-toggle="tooltip")
|
||||
i.far.fa-plus-square.fa-lg
|
||||
|
||||
|
||||
mixin warningAlert
|
||||
.alert.alert-warning.shadow-sm.mb-4(role="alert", style="padding-left: 4rem;")
|
||||
i.fas.fa-exclamation-triangle.fa-2x.d-inline-block(style="position: absolute; top: 0; left: 0; width: 40px; margin-left: 0.8rem; margin-top: 1.2rem;")
|
||||
|
||||
block
|
||||
|
||||
|
||||
mixin blockRangeFilters
|
||||
.clearfix
|
||||
.float-start.me-4
|
||||
div(id="time-range-buttons")
|
||||
div.mb-2
|
||||
span.border-dotted(title="Analyze blocks over the last N days (approximated using average block time).", data-bs-toggle="tooltip") Time Range
|
||||
div.btn-group
|
||||
a.btn.btn-primary.block-count-btn(href="javascript:void(0)", data-blockCount="144") 1 day
|
||||
a.btn.btn-outline-primary.block-count-btn(href="javascript:void(0)", data-blockCount="432") 3 day
|
||||
a.btn.btn-outline-primary.block-count-btn(href="javascript:void(0)", data-blockCount="1008") 7 day
|
||||
a.btn.btn-outline-primary.block-count-btn(href="javascript:void(0)", data-blockCount="4320") 30 day
|
||||
|
||||
.float-start.me-4
|
||||
div(id="block-selections-buttons")
|
||||
div.mb-2
|
||||
span.border-dotted(title="Choose from a list of pre-configured 'interesting' historical block ranges.", data-bs-toggle="tooltip") Interesting History
|
||||
|
||||
div.dropdown
|
||||
button.btn.btn-outline-primary.dropdown-toggle(type="button", id="preconfigured-dropdown", data-bs-toggle="dropdown", aria-haspopup="true", aria-expanded="false") Selections
|
||||
div.dropdown-menu(aria-labelledby="preconfigured-dropdown")
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="0-199") First 200 Blocks
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="209900-210100") First Halving ±100
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="419900-420100") Second Halving ±100
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="629900-630100") Third Halving ±100
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="481724-481924") SegWit Activation ±100
|
||||
|
||||
.float-start
|
||||
div(id="time-range-buttons")
|
||||
div.mb-2
|
||||
span.border-dotted(title="Manually enter a range of blocks to analyze.", data-bs-toggle="tooltip") Custom Block Range
|
||||
|
||||
form.form-inline.me-3(id="custom-range-form")
|
||||
div.input-group
|
||||
input.form-control(type="text", id="custom-range-start", placeholder="min height", style="width: 125px;")
|
||||
input.form-control(type="text", id="custom-range-end", placeholder="max height", style="width: 125px;")
|
||||
|
||||
button.btn.btn-primary(type="submit") Go
|
||||
|
||||
|
||||
|
||||
mixin pagination(limit, offset, sort, itemCount, baseUrl, justification="start", large=false)
|
||||
- var pageNumber = offset / limit + 1;
|
||||
- var pageCount = Math.floor(itemCount / limit);
|
||||
- if (pageCount * limit < itemCount) {
|
||||
- pageCount++;
|
||||
- }
|
||||
- var paginationUrlFunction = function(x) {
|
||||
- return `${baseUrl}?limit=${limit}&offset=${(x - 1) * limit}${sort ? ("&sort=" + sort) : ""}`
|
||||
//- return baseUrl + "?limit=" + limit + "&offset=" + ((x - 1) * limit);
|
||||
//- return baseUrl + "?limit=" + limit + "&offset=" + ((x - 1) * limit + "&sort=" + sort);
|
||||
- }
|
||||
|
||||
- var pageNumbers = [];
|
||||
- for (var x = 1; x <= pageCount; x++) {
|
||||
- pageNumbers.push(x);
|
||||
- }
|
||||
|
||||
nav(aria-label="Page navigation")
|
||||
ul.pagination.flex-wrap.mb-0(class=`justify-content-${justification}`, class=(large ? "pagination-lg" : false))
|
||||
li.page-item(class=(pageNumber == 1 ? "disabled" : false))
|
||||
a.page-link(href=(pageNumber == 1 ? "javascript:void(0)" : paginationUrlFunction(pageNumber - 1)), aria-label="Previous")
|
||||
span(aria-hidden="true") «
|
||||
each x, xIndex in pageNumbers
|
||||
if (x >= (pageNumber - 4) && x <= (pageNumber + 4) || xIndex == 0 || xIndex == (pageNumbers.length - 1))
|
||||
li.page-item(class=(x == pageNumber ? "active" : false))
|
||||
a.page-link(href=(paginationUrlFunction(x))) #{x}
|
||||
|
||||
if (x == 1 && pageNumber > 6)
|
||||
li.page-item.disabled
|
||||
a.page-link(href="javascript:void(0)") ...
|
||||
|
||||
else if (x == (pageCount - 1) && pageNumber < (pageCount - 5))
|
||||
li.page-item.disabled
|
||||
a.page-link(href="javascript:void(0)") ...
|
||||
|
||||
li.page-item(class=(pageNumber == pageCount ? "disabled" : false))
|
||||
a.page-link(href=(pageNumber == pageCount ? "javascript:void(0)" : paginationUrlFunction(pageNumber + 1)), aria-label="Next")
|
||||
span(aria-hidden="true") »
|
||||
|
||||
|
||||
mixin graphPageScriptSetup
|
||||
script(src="./js/chart.bundle.min.js", integrity="sha384-qgOtiGNaHh9fVWUnRjyHlV39rfbDcvPPkEzL1RHvsHKbuqUqM6uybNuVnghY2z4/")
|
||||
|
||||
if (userSettings.uiTheme && userSettings.uiTheme == "dark")
|
||||
script.
|
||||
Chart.defaults.global.defaultFontColor='white';
|
||||
var gridLineColor = "#1a4280";
|
||||
else
|
||||
script.
|
||||
Chart.defaults.global.defaultFontColor='black';
|
||||
var gridLineColor = "#dddddd";
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
- var timeAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date(parseInt(timeAgoTime) * 1000))));
|
||||
|
||||
span
|
||||
span(data-bs-toggle="tooltip", title=`${timeAgo.format()} ago`)
|
||||
i.far.fa-clock
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
- var yearStr = moment.utc(new Date(parseInt(timestampHuman) * 1000)).format("Y");
|
||||
- var nowYearStr = moment.utc(new Date()).format("Y");
|
||||
|
||||
- var dateStr = moment.utc(new Date(parseInt(timestampHuman) * 1000)).format("Y-M-D");
|
||||
- var nowDateStr = moment.utc(new Date()).format("Y-M-D");
|
||||
|
||||
if (dateStr == nowDateStr)
|
||||
else
|
||||
span #{moment.utc(new Date(parseInt(timestampHuman) * 1000)).format("M/D")}
|
||||
if (yearStr != nowYearStr)
|
||||
span , #{yearStr}
|
||||
|
||||
span
|
||||
span.border-dotted(title=`${moment.utc(new Date(parseInt(timestampHuman) * 1000)).format("Y-MM-DD HH:mm:ss")}`, data-bs-toggle="tooltip") #{moment.utc(new Date(parseInt(timestampHuman) * 1000)).format("HH:mm")}
|
||||
|
|
@ -48,45 +48,68 @@ if (false)
|
|||
if (true)
|
||||
div
|
||||
- var priorityList = config.site.prioritizedToolIdsList;
|
||||
- var indexLists2Col = utils.splitArrayIntoChunksByChunkCount(priorityList, 2);
|
||||
- var indexLists3Col = utils.splitArrayIntoChunksByChunkCount(priorityList, 3);
|
||||
- var indexLists4Col = utils.splitArrayIntoChunksByChunkCount(priorityList, 4);
|
||||
- var indexLists5Col = utils.splitArrayIntoChunksByChunkCount(priorityList, 5);
|
||||
- var indexLists1Col = utils.splitArrayIntoChunksByChunkCount(priorityList, 1);
|
||||
- var indexLists2Col = utils.splitArrayIntoChunksByChunkCount(priorityList, 2);
|
||||
- var indexLists3Col = utils.splitArrayIntoChunksByChunkCount(priorityList, 3);
|
||||
|
||||
// xs, sm, xxl
|
||||
div.d-block.d-md-none.d-xxl-block(id="tools-2-col")
|
||||
div.row
|
||||
each indexList in indexLists2Col
|
||||
div.col
|
||||
ul.list-unstyled.mb-0
|
||||
each toolsItemIndex in indexList
|
||||
include tools-card-block.pug
|
||||
// xs
|
||||
div.d-block.d-sm-none(id="tools-1-col")
|
||||
div.row
|
||||
each indexList in indexLists1Col
|
||||
div.col
|
||||
ul.list-unstyled.mb-0
|
||||
each toolsItemIndex in indexList
|
||||
- var item = config.siteTools[toolsItemIndex];
|
||||
|
||||
div.clearfix
|
||||
div.float-start.pt-1(style="width: 38px;")
|
||||
i.fa-lg(class=item.fontawesome, style="width: 20px; margin-right: 10px;")
|
||||
|
||||
// md
|
||||
div.d-none.d-md-block.d-lg-none(id="tools-3-col")
|
||||
div.row
|
||||
each indexList in indexLists3Col
|
||||
div.col
|
||||
ul.list-unstyled.mb-0
|
||||
each toolsItemIndex in indexList
|
||||
include tools-card-block.pug
|
||||
div.float-start
|
||||
div
|
||||
a(href=item.url) #{item.name}
|
||||
|
||||
// lg
|
||||
div.d-none.d-lg-block.d-xl-none(id="tools-4-col")
|
||||
div.row
|
||||
each indexList in indexLists4Col
|
||||
div.col
|
||||
ul.list-unstyled.mb-0
|
||||
each toolsItemIndex in indexList
|
||||
include tools-card-block.pug
|
||||
div(style="padding-left: 39px;")
|
||||
p #{item.desc}
|
||||
|
||||
// xl
|
||||
div.d-none.d-xl-block.d-xxl-none(id="tools-5-col")
|
||||
div.row
|
||||
each indexList in indexLists5Col
|
||||
div.col
|
||||
ul.list-unstyled.mb-0
|
||||
each toolsItemIndex in indexList
|
||||
include tools-card-block.pug
|
||||
// sm, md, lg
|
||||
div.d-none.d-sm-block.d-xl-none(id="tools-2-col")
|
||||
div.row
|
||||
each indexList in indexLists2Col
|
||||
div.col
|
||||
ul.list-unstyled.mb-0
|
||||
each toolsItemIndex in indexList
|
||||
- var item = config.siteTools[toolsItemIndex];
|
||||
|
||||
div.clearfix
|
||||
div.float-start.pt-1(style="width: 38px;")
|
||||
i.fa-lg(class=item.fontawesome, style="width: 20px; margin-right: 10px;")
|
||||
|
||||
div.float-start
|
||||
div
|
||||
a(href=item.url) #{item.name}
|
||||
|
||||
div(style="padding-left: 39px;")
|
||||
p #{item.desc}
|
||||
|
||||
// xl, xxl
|
||||
div.d-none.d-xl-block(id="tools-3-col")
|
||||
div.row
|
||||
each indexList in indexLists3Col
|
||||
div.col
|
||||
ul.list-unstyled.mb-0
|
||||
each toolsItemIndex in indexList
|
||||
- var item = config.siteTools[toolsItemIndex];
|
||||
|
||||
div.clearfix
|
||||
div.float-start.pt-1(style="width: 38px;")
|
||||
i.fa-lg(class=item.fontawesome, style="width: 20px; margin-right: 10px;")
|
||||
|
||||
div.float-start
|
||||
div
|
||||
a(href=item.url) #{item.name}
|
||||
|
||||
div(style="padding-left: 39px;")
|
||||
p #{item.desc}
|
||||
|
||||
|
||||
|
|
@ -1,10 +1,21 @@
|
|||
- var fontawesomeInputName = "sign-in-alt";
|
||||
- var fontawesomeOutputName = "sign-out-alt";
|
||||
|
||||
- var totalIOValues = utils.getTxTotalInputOutputValues(tx, txInputs, blockHeight);
|
||||
|
||||
mixin asciiHexDataDisplay(dataName, uniqueId, hex)
|
||||
div
|
||||
div.d-inline-block.small.border.rounded.p-1.px-2.card-highlight(style="max-width: 90%;")
|
||||
span.fw-bold.border-dotted.me-2(title=`ASCII-encoded ${dataName}`, data-bs-toggle="tooltip") Ascii
|
||||
span.font-plaintext #{utils.hex2ascii(hex)}
|
||||
|
||||
a.text-muted.ms-2(href="javascript:void(0)", onclick=`$('#hex-${uniqueId}').toggle(); $(this).find(".toggle-plus-minus").toggleClass("fa-plus-square"); $(this).find(".toggle-plus-minus").toggleClass("fa-minus-square"); return false;`, title="Toggle Hex Display", data-bs-toggle="tooltip")
|
||||
i.toggle-plus-minus.far.fa-plus-square
|
||||
|
||||
div(id=`hex-${uniqueId}`, style="display: none;")
|
||||
div.small.border.rounded.p-1.px-2.mt-2.word-wrap.card-highlight
|
||||
span.fw-bold.border-dotted.me-2(title=`Hex-encoded ${dataName}`, data-bs-toggle="tooltip") Hex
|
||||
span.font-plaintext #{hex}
|
||||
|
||||
div.row.font-monospace
|
||||
div.col-lg-6
|
||||
div.col-lg-6(class=(tx.vin.length >= tx.vout.length ? "border-lg-end" : false))
|
||||
if (txInputs || !global.txindexAvailable)
|
||||
- var extraInputCount = 0;
|
||||
each txVin, txVinIndex in tx.vin
|
||||
|
|
@ -21,14 +32,14 @@ div.row.font-monospace
|
|||
if (txVin.coinbase || vout || !global.txindexAvailable)
|
||||
div.clearfix
|
||||
div.tx-io-label
|
||||
a(data-bs-toggle="tooltip", title=`Input #${txVinIndex.toLocaleString()}`, style="white-space: nowrap;")
|
||||
span.fw-bold >
|
||||
small.d-inline.d-md-none Input
|
||||
a.badge.fw-normal.card-highlight.border.text-decoration-none(data-bs-toggle="tooltip", title=`Input #${txVinIndex.toLocaleString()}`, style="white-space: nowrap;")
|
||||
span.me-tiny >
|
||||
small.d-inline.d-md-none.me-1 Input
|
||||
|
||||
if (tx.vin.length > 999)
|
||||
small.word-wrap ##{txVinIndex}
|
||||
small.word-wrap #{txVinIndex}
|
||||
else
|
||||
span ##{txVinIndex.toLocaleString()}
|
||||
span #{txVinIndex.toLocaleString()}
|
||||
|
||||
if (tx.vin.length > 0)
|
||||
small.d-inline.d-md-none.fw-light.text-muted / #{(tx.vin.length - 1).toLocaleString()}
|
||||
|
|
@ -37,20 +48,9 @@ div.row.font-monospace
|
|||
div.clearfix
|
||||
div.tx-io-desc
|
||||
if (txVin.coinbase)
|
||||
span.badge.bg-success.me-2(title="Coinbase transactions are special transactions created by the miner of a block. They distribute the block reward (subsidy) as the miner chooses, along with all of the fees paid by transactions included in the block.", data-bs-toggle="tooltip") coinbase
|
||||
span.badge.bg-success.me-2.mb-2(title="Coinbase transactions are special transactions created by the miner of a block. They distribute the block reward (subsidy) as the miner chooses, along with all of the fees paid by transactions included in the block.", data-bs-toggle="tooltip") coinbase
|
||||
|
||||
div.pt-1
|
||||
small.fw-bold(tistle="ASCII encoded", data-bs-toggle="tooltip") data
|
||||
small (ascii) -
|
||||
small #{utils.hex2ascii(txVin.coinbase)}
|
||||
br
|
||||
small
|
||||
a(href="javascript:void(0)" onclick="$('#coinbase-data-hex').show(); $(this).hide(); return false;") show raw
|
||||
|
||||
div(id="coinbase-data-hex", style="display: none;")
|
||||
small.fw-bold data
|
||||
small (hex) -
|
||||
small.word-wrap #{txVin.coinbase}
|
||||
+asciiHexDataDisplay("coinbase data", "coinbase-data", txVin.coinbase)
|
||||
|
||||
|
||||
else
|
||||
|
|
@ -69,24 +69,28 @@ div.row.font-monospace
|
|||
|
||||
if (deltaTYears > 5)
|
||||
span.me-2(title=`This UTXO was very old! It existed for ${parseInt(deltaTYears)}+ years - from ${moment.utc(new Date(vout.utxoTime * 1000)).format('MMM D, Y')} until ${moment.utc(new Date(tx.time * 1000)).format('MMM D, Y')} - before being spent (destroyed) in this transaction!`, data-bs-toggle="tooltip")
|
||||
i.fas.fa-certificate.text-primary
|
||||
+funItemIcon
|
||||
|
||||
|
||||
a(href=`./tx/${txInput.txid}#output-${txVin.vout}`) #{utils.ellipsize(txInput.txid, 26)}
|
||||
a(href=`./tx/${txInput.txid}#output-${txVin.vout}`) #{utils.ellipsizeMiddle(txInput.txid, 22)}
|
||||
span ##{txVin.vout}
|
||||
|
||||
if (vout && vout.scriptPubKey && vout.scriptPubKey.addresses)
|
||||
div.word-wrap
|
||||
small.text-muted
|
||||
span.me-1 (addr:
|
||||
a(href=`./address/${vout.scriptPubKey.addresses[0]}`, class=(txIOHighlightAddress == vout.scriptPubKey.addresses[0] ? "fw-bold" : null)) #{vout.scriptPubKey.addresses[0]}
|
||||
a(href=`./address/${vout.scriptPubKey.addresses[0]}`, class=(txIOHighlightAddress == vout.scriptPubKey.addresses[0] ? "text-info" : null)) #{vout.scriptPubKey.addresses[0]}
|
||||
|
||||
if (txIOHighlightAddress == vout.scriptPubKey.addresses[0])
|
||||
span(title="Current address", data-bs-toggle="tooltip")
|
||||
i.fas.fa-arrow-left.text-warning.ms-1.text-info
|
||||
|
||||
if (global.specialAddresses[vout.scriptPubKey.addresses[0]])
|
||||
- var specialAddressInfo = global.specialAddresses[vout.scriptPubKey.addresses[0]];
|
||||
if (specialAddressInfo.type == "minerPayout")
|
||||
span
|
||||
a(data-bs-toggle="tooltip", title=`Miner payout address: ${specialAddressInfo.minerInfo.name}`)
|
||||
i.fas.fa-certificate.text-primary
|
||||
+funItemIcon
|
||||
|
||||
span )
|
||||
|
||||
|
|
@ -100,15 +104,19 @@ div.row.font-monospace
|
|||
|
||||
|
||||
|
||||
div.tx-io-value
|
||||
div.tx-io-value.mt-3.mt-md-0
|
||||
if (txVin.coinbase)
|
||||
- var currencyValue = coinConfig.blockRewardFunction(blockHeight, activeBlockchain);
|
||||
span.border-dotted(title="This is the <b>block subsidy</b> - newly created coins awarded to the miner that found this block.", data-bs-toggle="tooltip", data-bs-html="true", class=(tx.vin.length == 1 ? "fw-bold" : false))
|
||||
span.border-dotted.me-1(title="This is the <b>block subsidy</b> - newly created coins awarded (automatically, by the network protocol) to the miner that found this block.", data-bs-toggle="tooltip", data-bs-html="true")
|
||||
i.fas.fa-asterisk.text-success
|
||||
|
||||
span(class=(tx.vin.length == 1 ? "fw-bold" : false))
|
||||
- var currencyValue = coinConfig.blockRewardFunction(blockHeight, activeBlockchain);
|
||||
include ./value-display.pug
|
||||
|
||||
else
|
||||
if (vout && vout.value)
|
||||
- var currencyValue = vout.value;
|
||||
span(class=(tx.vin.length == 1 ? "fw-bold" : false))
|
||||
span(class=(tx.vin.length == 1 ? "fw-bold" : "fw-light"))
|
||||
include ./value-display.pug
|
||||
|
||||
else if (!global.txindexAvailable)
|
||||
|
|
@ -124,10 +132,10 @@ div.row.font-monospace
|
|||
if (extraInputCount > 0)
|
||||
div.clearfix
|
||||
div.tx-io-label
|
||||
a(data-bs-toggle="tooltip", title=`Input #${(tx.vin.length - extraInputCount + 1).toLocaleString()} - ${tx.vin.length.toLocaleString()}`, style="white-space: nowrap;")
|
||||
span.fw-bold >
|
||||
span.d-inline.d-md-none Input
|
||||
span #…
|
||||
a.badge.fw-normal.card-highlight.border.text-decoration-none(data-bs-toggle="tooltip", title=`Input #${(tx.vin.length - extraInputCount + 1).toLocaleString()} - ${tx.vin.length.toLocaleString()}`, style="white-space: nowrap;")
|
||||
span.me-1 >
|
||||
span.d-inline.d-md-none.me-1 Input
|
||||
span …
|
||||
|
||||
div.tx-io-content
|
||||
div.clearfix
|
||||
|
|
@ -140,27 +148,33 @@ div.row.font-monospace
|
|||
a(href=`./tx/${tx.txid}`) transaction details
|
||||
span )
|
||||
|
||||
div.tx-io-value
|
||||
div.tx-io-value.mt-3.mt-md-0
|
||||
- var currencyValue = new Decimal(totalIOValues.output).minus(new Decimal(totalIOValues.input));
|
||||
include ./value-display.pug
|
||||
hr
|
||||
|
||||
if (totalIOValues.input && totalIOValues.input > 0 && tx.vin.length > 1)
|
||||
div.row.mb-5.mb-lg-0
|
||||
div.row.mb-3.mb-md-0
|
||||
div.col
|
||||
div.fw-bold.text-start.text-md-end
|
||||
div.text-start.text-md-end
|
||||
if (totalIOValues.input > 0)
|
||||
span.d-block.d-md-none Total Input:
|
||||
|
||||
- var currencyValue = totalIOValues.input;
|
||||
span.fw-bold
|
||||
include ./value-display.pug
|
||||
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
div.d-lg-none
|
||||
div.my-4
|
||||
hr
|
||||
|
||||
div.col-lg-6(class=(tx.vout.length > tx.vin.length ? "border-lg-start" : false))
|
||||
- var maxRegularRowCount = (txIOHighlightAddress != null ? config.site.addressPage.txOutputMaxDefaultDisplay : 10000000);
|
||||
- var regularRowCount = 0;
|
||||
- var hiddenRowCount = 0;
|
||||
- var nonZeroVoutValueCount = tx.vout.filter(vout => { return vout.value > 0; }).length;
|
||||
|
||||
each vout, voutIndex in tx.vout
|
||||
- var highlightRow = false;
|
||||
if (txIOHighlightAddress != null && vout.scriptPubKey && vout.scriptPubKey.addresses && vout.scriptPubKey.addresses[0] == txIOHighlightAddress)
|
||||
|
|
@ -175,16 +189,16 @@ div.row.font-monospace
|
|||
- hiddenRowCount++;
|
||||
|
||||
div(data-txid=tx.txid, class=(hiddenRow ? "d-none" : ""))
|
||||
div.clearfix
|
||||
.clearfix
|
||||
div.tx-io-label
|
||||
a(data-bs-toggle="tooltip", title=`Output #${voutIndex.toLocaleString()}`, style="white-space: nowrap;")
|
||||
span.fw-bold <
|
||||
small.d-inline.d-md-none Output
|
||||
a.badge.card-highlight.border.text-decoration-none.fw-normal(data-bs-toggle="tooltip", title=`Output #${voutIndex.toLocaleString()}`, style="white-space: nowrap;")
|
||||
span.me-tiny <
|
||||
small.d-inline.d-md-none.me-1 Output
|
||||
|
||||
if (tx.vout.length > 999)
|
||||
small.word-wrap ##{voutIndex}
|
||||
small.word-wrap #{voutIndex}
|
||||
else
|
||||
span ##{voutIndex.toLocaleString()}
|
||||
span #{voutIndex.toLocaleString()}
|
||||
|
||||
if (tx.vout.length > 0)
|
||||
small.d-inline.d-md-none.fw-light.text-muted / #{(tx.vout.length - 1).toLocaleString()}
|
||||
|
|
@ -195,89 +209,76 @@ div.row.font-monospace
|
|||
if (vout.scriptPubKey)
|
||||
if (vout.scriptPubKey.addresses)
|
||||
if (true)
|
||||
div.mb-tiny
|
||||
div.mb-1
|
||||
span.badge.bg-dark
|
||||
span(title=`Output Type: ${utils.outputTypeName(vout.scriptPubKey.type)}`, data-bs-toggle="tooltip") #{utils.outputTypeAbbreviation(vout.scriptPubKey.type)}
|
||||
|
||||
each addr in vout.scriptPubKey.addresses
|
||||
a(id=`output-${voutIndex}`, href=`./address/${addr}`)
|
||||
span.font-monospace.word-wrap(class=(highlightRow ? "fw-bold" : "")) #{addr}
|
||||
span.font-monospace.word-wrap(class=(highlightRow ? "text-info" : null)) #{addr}
|
||||
|
||||
if (highlightRow)
|
||||
span(title="Current address", data-bs-toggle="tooltip")
|
||||
i.fas.fa-arrow-left.ms-1.text-warning
|
||||
|
||||
if (global.specialAddresses[addr])
|
||||
- var specialAddressInfo = global.specialAddresses[addr];
|
||||
if (specialAddressInfo.type == "minerPayout")
|
||||
span
|
||||
a(data-bs-toggle="tooltip", title=`Miner payout address: ${specialAddressInfo.minerInfo.name}`)
|
||||
i.fas.fa-certificate.text-primary
|
||||
+funItemIcon
|
||||
|
||||
br
|
||||
|
||||
else if (vout.scriptPubKey.hex && vout.scriptPubKey.hex.startsWith('6a24aa21a9ed'))
|
||||
div.mb-tiny
|
||||
span.badge.bg-primary OP_RETURN
|
||||
|
||||
div
|
||||
small.text-muted (SegWit committment -
|
||||
a(href="https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#commitment-structure", data-bs-toggle="tooltip", title="View developer docs", target="_blank") about
|
||||
span )
|
||||
div.mb-2
|
||||
span.badge.bg-primary.me-2 OP_RETURN
|
||||
|
||||
span.badge.bg-dark.me-2 SegWit commitment
|
||||
a(href="https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#commitment-structure", data-bs-toggle="tooltip", title="Read about the SegWit Commitment", target="_blank")
|
||||
i.fas.fa-external-link-alt
|
||||
|
||||
br
|
||||
small
|
||||
a(href="javascript:void(0)" onclick=`$('#op-return-hex-${tx.txid}-${vout.n}').show(); $(this).hide(); return false;`) show raw
|
||||
|
||||
div(id=`op-return-hex-${tx.txid}-${vout.n}`, style="display: none;")
|
||||
small.fw-bold data
|
||||
small (hex) -
|
||||
small.word-wrap #{vout.scriptPubKey.asm}
|
||||
+asciiHexDataDisplay("OP_RETURN data", `op_return-${tx.txid}-${vout.n}`, vout.scriptPubKey.asm.substring("OP_RETURN ".length))
|
||||
|
||||
|
||||
else if (vout.scriptPubKey.asm && vout.scriptPubKey.asm.startsWith('OP_RETURN '))
|
||||
div.mb-tiny
|
||||
div.mb-2
|
||||
span.badge.bg-primary OP_RETURN
|
||||
|
||||
+asciiHexDataDisplay("OP_RETURN data", `op_return-${tx.txid}-${vout.n}`, vout.scriptPubKey.asm.substring("OP_RETURN ".length))
|
||||
|
||||
div
|
||||
small.fw-bold data
|
||||
small (ascii) -
|
||||
small #{utils.hex2ascii(vout.scriptPubKey.asm.substring("OP_RETURN ".length))}
|
||||
br
|
||||
small
|
||||
a(href="javascript:void(0)" onclick=`$('#op-return-hex-${tx.txid}-${vout.n}').show(); $(this).hide(); return false;`) show raw
|
||||
|
||||
div(id=`op-return-hex-${tx.txid}-${vout.n}`, style="display: none;")
|
||||
small.fw-bold data
|
||||
small (hex) -
|
||||
small.word-wrap #{vout.scriptPubKey.asm}
|
||||
|
||||
|
||||
|
||||
else
|
||||
div.mb-tiny
|
||||
span.badge.bg-dark
|
||||
span(title=`Output Type: ${utils.outputTypeName(vout.scriptPubKey.type)}`, data-bs-toggle="tooltip") #{utils.outputTypeAbbreviation(vout.scriptPubKey.type)}
|
||||
|
||||
div
|
||||
small.fw-bold asm
|
||||
br
|
||||
small.word-wrap #{vout.scriptPubKey.asm}
|
||||
|
||||
div
|
||||
small.fw-bold hex
|
||||
br
|
||||
small.word-wrap #{vout.scriptPubKey.hex}
|
||||
|
||||
div.tx-io-value
|
||||
if (utxos)
|
||||
if (utxos[voutIndex])
|
||||
i.fas.fa-lock.text-success.me-2(title="Unspent output." data-bs-toggle="tooltip")
|
||||
|
||||
else if (utxos[voutIndex] == null)
|
||||
i.fas.fa-lock-open.text-secondary.me-2(title="Spent output." data-bs-toggle="tooltip")
|
||||
|
||||
- var currencyValue = vout.value;
|
||||
span(class=(tx.vout.length == 1 ? "fw-bold" : false))
|
||||
include ./value-display.pug
|
||||
+asciiHexDataDisplay("ASM data", `asm-${tx.txid}-${vout.n}`, vout.scriptPubKey.asm)
|
||||
|
||||
|
||||
if (tx.vout.length > 1)
|
||||
div.tx-io-value.mt-3.mt-md-0
|
||||
if (!vout.scriptPubKey.asm.startsWith('OP_RETURN '))
|
||||
if (utxos)
|
||||
if (utxos[voutIndex])
|
||||
span(title="This output remains unspent (a valid UTXO)." data-bs-toggle="tooltip")
|
||||
i.fas.fa-lock.text-success.me-2
|
||||
|
||||
else if (utxos[voutIndex] == null)
|
||||
span(title="This output has been spent (destroyed)." data-bs-toggle="tooltip")
|
||||
i.fas.fa-lock-open.text-secondary.me-2
|
||||
|
||||
if (vout.value > 0 && vout.scriptPubKey.asm.startsWith('OP_RETURN '))
|
||||
span(title="Burned output - as an OP_RETURN output, this value is provably unspendable." data-bs-toggle="tooltip")
|
||||
i.fas.fa-fire.text-danger.me-2
|
||||
|
||||
if (vout.value > 0)
|
||||
- var currencyValue = vout.value;
|
||||
span(class=(nonZeroVoutValueCount == 1 ? "fw-bold" : "fw-light"))
|
||||
include ./value-display.pug
|
||||
|
||||
|
||||
if (voutIndex < (tx.vout.length - 1) || nonZeroVoutValueCount > 1)
|
||||
hr
|
||||
|
||||
else
|
||||
|
|
@ -286,12 +287,14 @@ div.row.font-monospace
|
|||
if (hiddenRowCount > 0)
|
||||
a(href="javascript:void(0)", onclick=("showAllTxOutputs(this, '" + tx.txid + "');")) Show all #{tx.vout.length.toLocaleString()} outputs
|
||||
|
||||
if (tx.vout.length > 1)
|
||||
if (nonZeroVoutValueCount > 1)
|
||||
div.row.mb-0.mb-lg-0
|
||||
div.col
|
||||
div.fw-bold.text-start.text-md-end
|
||||
div.text-start.text-md-end
|
||||
span.d-block.d-md-none Total Output:
|
||||
- var currencyValue = totalIOValues.output;
|
||||
include ./value-display.pug
|
||||
|
||||
span.fw-bold
|
||||
- var currencyValue = totalIOValues.output;
|
||||
include ./value-display.pug
|
||||
|
||||
|
||||
|
|
|
|||
192
views/index.pug
|
|
@ -1,7 +1,7 @@
|
|||
extends layout
|
||||
|
||||
block headContent
|
||||
title Home
|
||||
title Bitcoin Explorer
|
||||
|
||||
block content
|
||||
if (getblockchaininfo == null)
|
||||
|
|
@ -10,55 +10,53 @@ block content
|
|||
ul
|
||||
li
|
||||
p
|
||||
strong If you just started your node, it may still be initializing.
|
||||
b If you just started your node, it may still be initializing.
|
||||
div At startup, bitcoind verifies its block index before making itself available to serve data. The amount of time the verification process takes depends largely on the speed of the machine bitcoind is running on. If you're running bitcoind on low powered, inexpensive hardware, don't be surprised if this process takes a long time.
|
||||
li
|
||||
p
|
||||
strong If you believe your bitcoind node is already initialized...
|
||||
b If you believe your bitcoind node is already initialized...
|
||||
div Check your RPC connection info and/or check this application's error log for possible hints about the cause of this issue.
|
||||
else
|
||||
|
||||
if (config.demoSite && session.hideHomepageBanner != "true")
|
||||
div.alert.alert-primary.alert-dismissible.shadow-sm.mb-3(role="alert")
|
||||
span
|
||||
span.fw-bold #{coinConfig.siteTitlesByNetwork[activeBlockchain]}
|
||||
span is
|
||||
a(href="https://github.com/janoside/btc-rpc-explorer", target="_blank") open-source
|
||||
span and easy to set up. It can communicate with your
|
||||
a(href=coinConfig.nodeUrl, target="_blank") #{coinConfig.name} Full Node
|
||||
span via RPC. See the
|
||||
a(href="https://github.com/janoside/btc-rpc-explorer", target="_blank") project description
|
||||
span for a list of features and instructions for running.
|
||||
+dismissableInfoAlert("homepageWelcomeBannerDismissed")
|
||||
.clearfix
|
||||
.float-start
|
||||
h4.fw-light.mb-2 Welcome to Bitcoin Explorer!
|
||||
.float-start
|
||||
if (config.demoSite)
|
||||
span.badge.bg-primary.mb-2.ms-3.mt-1 Public Demo
|
||||
|
||||
|
||||
.mb-1 A beautiful, easy-to-use, educational explorer whose <u>only dependency is your <b>Bitcoin Core</b> node</u>!
|
||||
ul.mb-2
|
||||
li Open-Source
|
||||
li Easy to setup / configure
|
||||
li Designed to work well on low-powered devices (e.g. Raspberry Pi)
|
||||
li Available for self-installation, or via several readymade-node integrations
|
||||
|
||||
.mb-2 Check out the code, support development with a donation, and follow the project on Twitter below.
|
||||
|
||||
.mt-2
|
||||
if (global.sourcecodeProjectMetadata)
|
||||
div.mt-2
|
||||
a.btn.btn-primary.btn-sm.me-3.mb-1(href="https://github.com/janoside/btc-rpc-explorer")
|
||||
i.fas.fa-star.me-2
|
||||
span.me-2 Star
|
||||
span.badge.bg-white.text-dark #{global.sourcecodeProjectMetadata.stargazers_count}
|
||||
a.btn.btn-primary.text-white.me-2.mb-1(href="https://github.com/janoside/btc-rpc-explorer", title="View source code on Github", data-bs-toggle="tooltip")
|
||||
i.fab.fa-github.fontawesome-shadow-dark.fa-lg.me-2
|
||||
| View Source
|
||||
|
||||
a.btn.btn-primary.btn-sm.me-3.mb-1(href="https://github.com/janoside/btc-rpc-explorer/fork")
|
||||
i.fas.fa-code-branch.me-2
|
||||
span.me-2 Fork
|
||||
span.badge.bg-white.text-dark #{global.sourcecodeProjectMetadata.forks_count}
|
||||
|
||||
if (!crawlerBot)
|
||||
button.btn.btn-primary.btn-sm.mb-1(type="button", data-bs-toggle="modal", data-target="#exampleModalCenter")
|
||||
i.fas.fa-heart.me-2
|
||||
span Support Project
|
||||
a.btn.btn-primary.me-2.mb-1(href="https://donate.btc21.org", target="_blank", title="Support this project with a donation", data-bs-toggle="tooltip")
|
||||
i.fas.fa-heart.fontawesome-shadow-dark.text-danger.fa-lg.me-2
|
||||
| Support Project
|
||||
|
||||
if (false)
|
||||
div.mt-2
|
||||
a.me-2(href="https://www.npmjs.com/package/btc-rpc-explorer" rel="nofollow" target="_blank")
|
||||
img(src="https://camo.githubusercontent.com/a2a28dff9062102df7988314d014e68d4612bd83/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f6274632d7270632d6578706c6f7265722e7376673f7374796c653d666c6174" alt="npm version" data-canonical-src="https://img.shields.io/npm/v/btc-rpc-explorer.svg?style=flat" style="max-width:100%;")
|
||||
|
||||
a(href="https://npmcharts.com/compare/btc-rpc-explorer?minimal=true" rel="nofollow" target="_blank")
|
||||
img(src="https://camo.githubusercontent.com/07914c9a0c2f22f7493952dc969c57164bb14f77/687474703a2f2f696d672e736869656c64732e696f2f6e706d2f646d2f6274632d7270632d6578706c6f7265722e7376673f7374796c653d666c6174" alt="NPM downloads" data-canonical-src="http://img.shields.io/npm/dm/btc-rpc-explorer.svg?style=flat" style="max-width:100%;")
|
||||
a.btn.btn-primary.me-2.mb-1(href="https://twitter.com/BitcoinExplorer", target="_blank", title="Follow this project on Twitter", data-bs-toggle="tooltip")
|
||||
i.fab.fa-twitter.text-twitter.fontawesome-shadow-dark.fa-lg.me-2
|
||||
| @BitcoinExplorer
|
||||
|
||||
if (config.demoSite)
|
||||
.mt-2
|
||||
i.fas.fa-asterisk.fontawesome-shadow.text-warning.me-2
|
||||
| This is a public demo, but this tool is designed to be run by <b>all</b> Bitcoiners... <i>Don't Trust, Verify</i>!
|
||||
|
||||
|
||||
a.close(href="./changeSetting?name=hideHomepageBanner&value=true", aria-label="Close", style="text-decoration: none;")
|
||||
span(aria-hidden="true") ×
|
||||
|
||||
|
||||
if (getblockchaininfo.initialblockdownload && !["regtest", "signet"].includes(global.activeBlockchain))
|
||||
div.alert.alert-warning.shadow-sm.border.mb-3
|
||||
|
|
@ -66,117 +64,31 @@ block content
|
|||
|
||||
div.mb-1 Your node is currently downloading and verifying blockchain data. Until the process is finished, some features of this tool will be unusable and/or unreliable.
|
||||
|
||||
span.font-weight-bold Progress:
|
||||
span.text-monospace #{new Decimal(getblockchaininfo.verificationprogress).times(100).toDP(3)}%
|
||||
span.fw-bold Progress:
|
||||
span.font-monospace #{new Decimal(getblockchaininfo.verificationprogress).times(100).toDP(3)}%
|
||||
|
||||
|
||||
div.row
|
||||
- var summaryColCount = 8;
|
||||
if (exchangeRates)
|
||||
- summaryColCount = 9;
|
||||
|
||||
div.mb-3(class=`col-xxl-${summaryColCount}`)
|
||||
div.card.shadow-sm(style="height: 100%;")
|
||||
div.card-body.px-2.px-sm-3
|
||||
h3.h6.mb-0 Network Summary
|
||||
hr
|
||||
|
||||
include includes/index-network-summary.pug
|
||||
|
||||
div.mb-3(class=`col-xxl-${12 - summaryColCount}`)
|
||||
div.card.shadow-sm(style="height: 100%;")
|
||||
div.card-body.px-2.px-sm-3
|
||||
div.row
|
||||
div.col
|
||||
h3.h6.mb-0 Tools
|
||||
|
||||
div.col.text-right
|
||||
a(href="./tools") More info »
|
||||
hr
|
||||
|
||||
include includes/tools-card.pug
|
||||
|
||||
include includes/index-network-summary.pug
|
||||
|
||||
|
||||
|
||||
if (latestBlocks)
|
||||
div.row.mb-3
|
||||
div.col
|
||||
div.card.shadow-sm
|
||||
div.card-body.px-2.px-sm-3
|
||||
div.row
|
||||
div.col
|
||||
h3.h6.mb-0 Latest Blocks
|
||||
|
||||
div.col.text-right
|
||||
a(href="./blocks") See more »
|
||||
+contentSection("Latest Blocks")
|
||||
- var blocks = latestBlocks;
|
||||
- var blockOffset = 0;
|
||||
- var hideBlockIndex = true;
|
||||
|
||||
hr
|
||||
include includes/blocks-list.pug
|
||||
|
||||
- var blocks = latestBlocks;
|
||||
- var blockOffset = 0;
|
||||
.text-center
|
||||
.border.border-2.mt-2.mb-3
|
||||
|
||||
include includes/blocks-list.pug
|
||||
a(href="./blocks") Browse Blocks »
|
||||
|
||||
if (false)
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-header
|
||||
div.row
|
||||
div.col
|
||||
h3.h6.mb-0 Latest Blocks
|
||||
if (getblockchaininfo.initialblockdownload)
|
||||
small (#{(getblockchaininfo.headers - getblockchaininfo.blocks).toLocaleString()} behind)
|
||||
|
||||
div.col
|
||||
span(style="float: right;")
|
||||
a(href="./blocks")
|
||||
span Browse Blocks »
|
||||
+contentSection("Tools")
|
||||
include includes/tools-card.pug
|
||||
|
||||
|
||||
div.card-body
|
||||
|
||||
- var blocks = latestBlocks;
|
||||
- var blockOffset = 0;
|
||||
|
||||
include includes/blocks-list.pug
|
||||
|
||||
|
||||
if (txStats)
|
||||
div.row.mb-3
|
||||
div.col
|
||||
div.card.shadow-sm
|
||||
div.card-body.px-2.px-sm-3
|
||||
div.row
|
||||
div.col
|
||||
h3.h6.mb-0 Transaction Stats
|
||||
|
||||
div.col.text-end
|
||||
a(href="./tx-stats") See more »
|
||||
|
||||
hr
|
||||
|
||||
div.row
|
||||
div.col-lg-6
|
||||
div.table-responsive
|
||||
table.table.text-end.mb-3.mb-lg-0
|
||||
thead
|
||||
tr
|
||||
th Period
|
||||
th Transactions
|
||||
th Transactions Per Sec
|
||||
tbody
|
||||
each item, index in chainTxStatsIntervals
|
||||
tr.font-monospace
|
||||
td #{item[1]}
|
||||
td #{chainTxStats[item[0]].window_tx_count.toLocaleString()}
|
||||
td #{new Decimal(chainTxStats[item[0]].txrate).toDecimalPlaces(4)}
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
h4.h6.text-center Tx Rate, 24hr
|
||||
|
||||
script var txRateDataDay = [];
|
||||
each item, index in txStats.txCountStats.txRates
|
||||
script txRateDataDay.push({x:#{item.x}, y:#{item.y}});
|
||||
|
||||
- var graphData = {id:"graphRateDay", dataVar:"txRateDataDay", labels:txStats.txCountStats.txLabels, title:"Tx Rate, 24hr", xaxisTitle:"Block", xaxisStep:5, yaxisTitle:"Tx Per Sec"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
254
views/layout.pug
|
|
@ -6,19 +6,16 @@ html(lang="en")
|
|||
meta(name="csrf-token", content=csrfToken)
|
||||
meta(name="viewport", content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0, shrink-to-fit=no")
|
||||
|
||||
link(rel="stylesheet", href="./css/fonts.css", integrity="sha384-P92dMmtW9S5qrhDNNDr3kcdk00LJDKUy4Do4zFAO0+Br2b7iGHBWSVRgnnBsEpJS")
|
||||
link(rel="stylesheet", href="./css/highlight.min.css", integrity="sha384-zhIsEafzyQWHSoMCQ4BfT8ZlRXQyIFwAHAJn32PNdsb8n6tVysGZSLpEEIvCskw4")
|
||||
link(rel="stylesheet", href="./style/fonts.css", integrity="sha384-P92dMmtW9S5qrhDNNDr3kcdk00LJDKUy4Do4zFAO0+Br2b7iGHBWSVRgnnBsEpJS")
|
||||
link(rel="stylesheet", href="./style/highlight.min.css", integrity="sha384-s4RLYRjGGbVqKOyMGGwfxUTMOO6D7r2eom7hWZQ6BjK2Df4ZyfzLXEkonSm0KLIQ")
|
||||
|
||||
|
||||
if (session.uiTheme && session.uiTheme == "dark")
|
||||
link(rel="stylesheet", href="./css/bootstrap-dark.min.css", integrity="sha384-yHrdw+uFPe64ykHEYlYL2lmT0s+veKi1+lmxNqB3jVMOl9iX0h9xDLxcgtFtiV6M")
|
||||
link(rel="stylesheet", href="./css/dark-touchups.css")
|
||||
if (userSettings.uiTheme == "light")
|
||||
link(rel="stylesheet", href="./style/light.css", integrity="sha384-aUb+tfIBAXpVezvEdnu1PuRqntH8i/XMDZgw543c0vdV/1AjC8xV5JINblNI5GRA")
|
||||
|
||||
else
|
||||
link(rel="stylesheet", href="./css/bootstrap.min.css", integrity="sha384-QO/VzYasHIIVEtFdqGXHU2wxSK0pjVxX4mrM68IQhYpi0vTCM0ZIuV/KQbPZMfXg")
|
||||
|
||||
link(rel="stylesheet", href="./style/dark.css", integrity="sha384-Ow3YhdsFrBZOGX+Z8jwJQKTq1ezm/PS8Jt5ND+g4j9PQkAmTPw3NaiBOIeFU5eLF")
|
||||
|
||||
link(rel='stylesheet', href='./css/styling.css')
|
||||
|
||||
link(rel="icon", type="image/png", href=`./img/logo/${config.coin.toLowerCase()}.png`)
|
||||
|
||||
|
|
@ -26,26 +23,28 @@ html(lang="en")
|
|||
|
||||
block headContent
|
||||
title Explorer
|
||||
|
||||
body.bg-dark
|
||||
nav.navbar.navbar-expand-lg.navbar-dark.bg-dark
|
||||
div.container
|
||||
|
||||
include ./includes/shared-mixins.pug
|
||||
|
||||
body.bg-header-footer
|
||||
nav.navbar.navbar-expand-lg.navbar-dark.bg-header-footer
|
||||
.container
|
||||
a.navbar-brand(href="./")
|
||||
span
|
||||
if (coinConfig.logoUrlsByNetwork && coinConfig.logoUrlsByNetwork[activeBlockchain])
|
||||
img.header-image(src=coinConfig.logoUrlsByNetwork[activeBlockchain], alt="logo")
|
||||
else
|
||||
img.header-image(src="./img/logo/btc.svg", alt="logo")
|
||||
img.header-image(src="./img/logo/logo.svg", alt="logo")
|
||||
|
||||
if (coinConfig.siteTitlesByNetwork && coinConfig.siteTitlesByNetwork[activeBlockchain])
|
||||
span #{coinConfig.siteTitlesByNetwork[activeBlockchain]}
|
||||
span.fw-light #{coinConfig.siteTitlesByNetwork[activeBlockchain]}
|
||||
else
|
||||
span Bitcoin Explorer
|
||||
span.fw-light Bitcoin Explorer
|
||||
|
||||
button.navbar-toggler.navbar-toggler-end(type="button", data-bs-toggle="collapse", data-target="#navbarNav", aria-label="collapse navigation")
|
||||
span.navbar-toggler-icon
|
||||
|
||||
div.collapse.navbar-collapse(id="navbarNav")
|
||||
.collapse.navbar-collapse(id="navbarNav")
|
||||
if (rpcClient)
|
||||
ul.navbar-nav.me-auto
|
||||
if (false)
|
||||
|
|
@ -53,17 +52,45 @@ html(lang="en")
|
|||
a.nav-link(href="./about")
|
||||
span About
|
||||
|
||||
if (activeBlockchain != "main")
|
||||
if (false && activeBlockchain != "main")
|
||||
- var chainName = activeBlockchain == "test" ? "testnet" : activeBlockchain
|
||||
|
||||
li.nav-item
|
||||
a.nav-link.text-warning(title=`Current node's chain: ${activeBlockchain}` data-bs-toggle="tooltip") [#{chainName}]
|
||||
span.badge.bg-primary(style="margin-top: 0.75rem;", title=`Current node's chain: ${activeBlockchain}` data-bs-toggle="tooltip") #{chainName}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ul.navbar-nav
|
||||
if (config.demoSite && homepage)
|
||||
li.nav-item.dropdown.me-2
|
||||
a.nav-link.dropdown-toggle.bg-header-footer-highlight.rounded(href="javascript:void(0)", role="button", data-bs-toggle="dropdown", aria-haspopup="true", aria-expanded="false")
|
||||
span.fa-layers.fa-fw.me-1
|
||||
i.fas.fa-circle.text-white(data-fa-transform="shrink-2")
|
||||
i.fab.fa-bitcoin(style=`color: ${coinConfig.coinColorsByNetwork[activeBlockchain]}`)
|
||||
|
||||
|
||||
div.dropdown-menu.dropdown-menu-end.shadow(aria-label="Tools Items")
|
||||
span.dropdown-header Public Demo Sites
|
||||
|
||||
- var demoSites = ["main", "test", "signet"];
|
||||
|
||||
each demoSite in demoSites
|
||||
a.dropdown-item(href=coinConfig.demoSiteUrlsByNetwork[demoSite])
|
||||
span.fa-layers.fa-fw.ms-2
|
||||
i.fas.fa-circle.fa-lg.me-2.text-white(data-fa-transform="shrink-2")
|
||||
i.fab.fa-bitcoin.fa-lg.me-2(style=`color: ${coinConfig.coinColorsByNetwork[demoSite]}`)
|
||||
|
||||
| #{coinConfig.siteTitlesByNetwork[demoSite].replace("Explorer", "").replace("Bitcoin", "Mainnet")}
|
||||
|
||||
if (config.siteTools)
|
||||
li.nav-item.dropdown
|
||||
a.nav-link.dropdown-toggle(href="javascript:void(0)", role="button", data-bs-toggle="dropdown", aria-haspopup="true", aria-expanded="false")
|
||||
span Tools
|
||||
div.dropdown-menu.shadow(aria-label="Tools Items")
|
||||
li.nav-item.dropdown.me-2
|
||||
a.nav-link.rounded.bg-header-footer-highlight.dropdown-toggle(href="javascript:void(0)", role="button", data-bs-toggle="dropdown", aria-haspopup="true", aria-expanded="false")
|
||||
i.fas.fa-tools.me-1
|
||||
div.dropdown-menu.dropdown-menu-end.shadow(aria-label="Tools Items")
|
||||
span.dropdown-header Tools
|
||||
|
||||
each itemIndex in config.site.prioritizedToolIdsList
|
||||
- var item = config.siteTools[itemIndex];
|
||||
|
||||
|
|
@ -71,37 +98,8 @@ html(lang="en")
|
|||
i(class=item.fontawesome, style="width: 20px; margin-right: 10px;")
|
||||
span #{item.name}
|
||||
|
||||
if (config.site.header.dropdowns)
|
||||
each dropdown, ddIndex in config.site.header.dropdowns
|
||||
li.nav-item.dropdown
|
||||
a.nav-link.dropdown-toggle(href="javascript:void(0)", role="button", data-bs-toggle="dropdown", aria-haspopup="true", aria-expanded="false")
|
||||
span #{dropdown.title}
|
||||
div.dropdown-menu.shadow(aria-label=(dropdown.title + " Items"))
|
||||
each dropdownLink in dropdown.links
|
||||
a.dropdown-item(href=dropdownLink.url)
|
||||
if (dropdownLink.imgUrl)
|
||||
img(src=dropdownLink.imgUrl, style="width: 24px; height: 24px; margin-right: 8px;", alt=dropdownLink.name)
|
||||
span #{dropdownLink.name}
|
||||
|
||||
|
||||
form.form-inline.me-3(method="post", action="./search")
|
||||
input(type="hidden", name="_csrf", value=csrfToken)
|
||||
div.input-group.input-group-sm
|
||||
input.form-control.form-control-sm(type="text", name="query", placeholder="block height/hash, txid, address", value=(query))
|
||||
|
||||
button.btn.btn-primary(type="submit")
|
||||
i.fas.fa-search
|
||||
|
||||
ul.navbar-nav
|
||||
li.nav-item.dropdown
|
||||
a.nav-link.dropdown-toggle(href="javascript:void(0)", role="button", data-bs-toggle="dropdown", aria-haspopup="true", aria-expanded="false")
|
||||
span Admin Tools
|
||||
div.dropdown-menu.dropdown-menu-end.shadow(aria-label="Admin Tools Items")
|
||||
a.dropdown-item(href="./admin/dashboard") Dashboard
|
||||
a.dropdown-item(href="./admin/stats") Stats
|
||||
|
||||
li.nav-item.dropdown
|
||||
a.nav-link.dropdown-toggle(href="javascript:void(0)", id="navbarDropdown", role="button", data-bs-toggle="dropdown", aria-haspopup="true", aria-expanded="false")
|
||||
li.nav-item.dropdown.me-4
|
||||
a.nav-link.rounded.bg-header-footer-highlight.dropdown-toggle(href="javascript:void(0)", id="navbarDropdown", role="button", data-bs-toggle="dropdown", aria-haspopup="true", aria-expanded="false")
|
||||
i.fas.fa-cog.me-1
|
||||
div.dropdown-menu.dropdown-menu-end.shadow(aria-labelledby="navbarDropdown")
|
||||
if (coinConfig.currencyUnits)
|
||||
|
|
@ -114,32 +112,20 @@ html(lang="en")
|
|||
i.fas.fa-check
|
||||
span #{item.name}
|
||||
|
||||
span.dropdown-header Theme
|
||||
a.dropdown-item(href="./changeSetting?name=uiTheme&value=light")
|
||||
if (session.uiTheme == "light" || session.uiTheme == "")
|
||||
i.fas.fa-check
|
||||
span Light
|
||||
a.dropdown-item(href="./changeSetting?name=uiTheme&value=dark")
|
||||
if (session.uiTheme == "dark")
|
||||
i.fas.fa-check
|
||||
span Dark
|
||||
|
||||
if (host && port && !homepage && config.site.header.showToolsSubheader)
|
||||
div.container.mb-2.pt-2.d-lg-block.d-none.border-top(id="sub-menu", style="")
|
||||
ul.nav
|
||||
each itemIndex in config.site.subHeaderToolsList
|
||||
- var item = config.siteTools[itemIndex];
|
||||
li.nav-item
|
||||
a.nav-link.text-white.px-2.text-decoration-underline.me-3(href=item.url)
|
||||
i.me-1(class=item.fontawesome)
|
||||
span #{item.name}
|
||||
|
||||
- var bodyBgColor = "#f8f9fa;";
|
||||
if (session.uiTheme && session.uiTheme == "dark")
|
||||
- bodyBgColor = "#0c0c0c;";
|
||||
|
||||
|
||||
div.pb-4.pt-3.pt-md-4(style=("background-color: " + bodyBgColor))
|
||||
div.container.px-2.px-sm-3
|
||||
form.form-inline(method="post", action="./search", style="width: 325px;")
|
||||
input(type="hidden", name="_csrf", value=csrfToken)
|
||||
.input-group.input-group
|
||||
input.form-control.form-control(type="text", name="query", placeholder="block height/hash, txid, address", value=(query))
|
||||
|
||||
button.btn.btn-primary(type="submit")
|
||||
i.fas.fa-search
|
||||
|
||||
|
||||
|
||||
div.pb-4.pt-3.pt-md-4.bg-main(style=("background-color: " + bodyBgColor))
|
||||
div.container.px-2.px-sm-3.mb-large
|
||||
if (pageErrors && pageErrors.length > 0)
|
||||
include includes/page-errors-modal.pug
|
||||
|
||||
|
|
@ -156,35 +142,29 @@ html(lang="en")
|
|||
if (userMessage)
|
||||
div.alert(class=(userMessageType ? `alert-${userMessageType}` : "alert-warning"), role="alert")
|
||||
span #{userMessage}
|
||||
|
||||
|
||||
|
||||
div(style="min-height: 500px;")
|
||||
block content
|
||||
|
||||
div(style="margin-bottom: 30px;")
|
||||
|
||||
if (config.demoSite && !crawlerBot)
|
||||
include ./includes/donation-modal.pug
|
||||
|
||||
footer.footer.border-top.border-primary.bg-dark.pt-3.pb-1.px-3.text-white(style="border-width: 5px !important;")
|
||||
footer.footer.border-top.border-primary.bg-header-footer.pt-3.pb-1.px-3.text-white(style="border-width: 5px !important;")
|
||||
div.container
|
||||
div.row
|
||||
div.col-md-5
|
||||
dl
|
||||
dt Source
|
||||
dd
|
||||
a(href="https://github.com/janoside/btc-rpc-explorer") github.com/janoside/btc-rpc-explorer
|
||||
a.footer-link(href="https://github.com/janoside/btc-rpc-explorer") github.com/janoside/btc-rpc-explorer
|
||||
|
||||
if (global.sourcecodeProjectMetadata)
|
||||
div.mt-2
|
||||
a.btn.btn-primary.btn-sm.me-3.mb-1.text-decoration-none(href="https://github.com/janoside/btc-rpc-explorer")
|
||||
i.fas.fa-star.me-2
|
||||
span.me-2 Star
|
||||
i.fas.fa-star.fontawesome-shadow.text-warning.me-2
|
||||
span.badge.bg-white.text-dark #{global.sourcecodeProjectMetadata.stargazers_count}
|
||||
|
||||
a.btn.btn-primary.btn-sm.me-3.mb-1.text-decoration-none(href="https://github.com/janoside/btc-rpc-explorer/fork")
|
||||
i.fas.fa-code-branch.me-2
|
||||
span.me-2 Fork
|
||||
i.fas.fa-code-branch.fontawesome-shadow.me-2
|
||||
span.badge.bg-white.text-dark #{global.sourcecodeProjectMetadata.forks_count}
|
||||
|
||||
|
||||
|
|
@ -195,58 +175,98 @@ html(lang="en")
|
|||
if (sourcecodeVersion)
|
||||
br
|
||||
span commit:
|
||||
a(href=`https://github.com/janoside/btc-rpc-explorer/commit/${sourcecodeVersion}`) #{sourcecodeVersion}
|
||||
a.footer-link(href=`https://github.com/janoside/btc-rpc-explorer/commit/${sourcecodeVersion}`) #{sourcecodeVersion}
|
||||
|
||||
br
|
||||
span released: #{sourcecodeDate}
|
||||
span(style="font-size: 0.9em;") (
|
||||
a(href="./changelog") changelog
|
||||
a.footer-link(href="./changelog") changelog
|
||||
span )
|
||||
|
||||
if (config.demoSite)
|
||||
dt Public Demos
|
||||
dd
|
||||
if (coinConfig.demoSiteUrl)
|
||||
a(href=coinConfig.demoSiteUrl) #{coinConfig.demoSiteUrl}
|
||||
if (coinConfig.demoSiteUrlsByNetwork && coinConfig.demoSiteUrlsByNetwork.main)
|
||||
a.footer-link(href=coinConfig.demoSiteUrlsByNetwork.main) #{coinConfig.demoSiteUrlsByNetwork.main}
|
||||
else
|
||||
a(href="https://explorer.btc21.org") https://explorer.btc21.org
|
||||
a.footer-link(href="https://explorer.btc21.org") https://explorer.btc21.org
|
||||
|
||||
div.mt-2
|
||||
- var demoSites = [];
|
||||
- demoSites.push({url:"https://explorer.btc21.org", logoUrl:"./img/logo/btc.svg", title:"Bitcoin Explorer"});
|
||||
- demoSites.push({url:"https://testnet.btc21.org", logoUrl:"./img/logo/tbtc.svg", title:"Testnet Explorer"});
|
||||
- demoSites.push({url:"https://signet.btc21.org", logoUrl:"./img/logo/signet.svg", title:"Signet Explorer"});
|
||||
|
||||
- var demoSites = ["main", "test", "signet"];
|
||||
|
||||
each demoSite in demoSites
|
||||
a.me-2(href=demoSite.url, title=demoSite.title, data-bs-toggle="tooltip")
|
||||
img(src=demoSite.logoUrl, alt=demoSite.title)
|
||||
|
||||
a.me-2(href="https://lnd-admin.btc21.org", title="LND Admin", data-bs-toggle="tooltip")
|
||||
img(src=("./img/logo/lnd-admin.png"), style="width: 32px; height: 32px;", alt="LND Admin")
|
||||
a.me-2(href=coinConfig.demoSiteUrlsByNetwork[demoSite], title=coinConfig.siteTitlesByNetwork[demoSite], data-bs-toggle="tooltip")
|
||||
img(src=coinConfig.logoUrlsByNetwork[demoSite], alt=coinConfig.siteTitlesByNetwork[demoSite], style="width: 40px; height: 40px;")
|
||||
|
||||
div.col-md-7.text-md-end
|
||||
dl
|
||||
|
||||
|
||||
|
||||
dd
|
||||
button.btn.btn-primary(type="button", data-bs-toggle="modal", data-target="#exampleModalCenter")
|
||||
i.fas.fa-heart.me-2
|
||||
span Support Project
|
||||
.btn-group.dropup.me-2
|
||||
button.btn.dropdown-toggle.bg-header-footer-highlight.text-white(type="button" data-bs-toggle="dropdown" aria-expanded="false")
|
||||
i.fas.fa-shield-alt.me-1
|
||||
|
||||
ul.dropdown-menu.dropdown-menu-end.shadow(aria-label="Admin Tools Items")
|
||||
span.dropdown-header Admin Tools
|
||||
|
||||
a.dropdown-item(href="./admin/dashboard") Dashboard
|
||||
a.dropdown-item(href="./admin/stats") Stats
|
||||
|
||||
|
||||
- var darkTheme = (userSettings.uiTheme == "dark");
|
||||
a.btn.btn-lg.fa-lg.bg-header-footer-highlight(href=`./changeSetting?name=uiTheme&value=${darkTheme ? "light" : "dark"}`, title=`Active Theme: <b>${darkTheme ? "Dark" : "Light"}</b><br/>Click to switch to <b>${darkTheme ? "Light" : "Dark"}</b>`, data-bs-toggle="tooltip", data-bs-html="true")
|
||||
|
||||
i.fas.fa-sun.text-warning.me-1
|
||||
|
||||
span.me-1
|
||||
if (darkTheme)
|
||||
i.fas.fa-toggle-on.text-primary
|
||||
else
|
||||
i.fas.fa-toggle-on.fa-rotate-180.text-warning
|
||||
|
||||
i.fas.fa-moon.text-primary
|
||||
|
||||
dd
|
||||
|
||||
|
||||
dd
|
||||
a.btn.btn-primary(href="https://donate.btc21.org", title="Support this project with a donation", data-bs-toggle="tooltip")
|
||||
i.fas.fa-heart.fontawesome-shadow-dark.text-danger
|
||||
|
||||
a.btn.btn-primary.ms-2(href=`https://twitter.com/BitcoinExplorer`, title="Follow this project on Twitter", data-bs-toggle="tooltip")
|
||||
i.fab.fa-twitter.fontawesome-shadow-dark.text-twitter
|
||||
|
||||
|
||||
|
||||
|
||||
script(src="./js/jquery.min.js", integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh")
|
||||
script(src="./js/popper.min.js", integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo")
|
||||
script(src="./js/bootstrap.min.js", integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6")
|
||||
script(defer, src="./js/fontawesome.min.js", integrity="sha384-eVEQC9zshBn0rFj4+TU78eNA19HMNigMviK/PU/FFjLXqa/GKPgX58rvt5Z8PLs7")
|
||||
script(src="./js/jquery.min.js", integrity="sha384-vtXRMe3mGCbOeY7l30aIg8H9p3GdeSe4IFlP6G8JMa7o7lXvnz3GFKzPxzJdPfGK")
|
||||
script(src="./js/bootstrap.bundle.min.js", integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf")
|
||||
script(defer, src="./js/fontawesome.min.js", integrity="sha384-haqrlim99xjfMxRP6EWtafs0sB1WKcMdynwZleuUSwJR0mDeRYbhtY+KPMr+JL6f")
|
||||
|
||||
script(src="./js/highlight.min.js", integrity="sha384-xLrpH5gNLD6HMLgeDH1/p4FXigQ8T9mgNm+EKtCSXL0OJ5i1bnSi57dnwFuUMM9/")
|
||||
script(src="./js/highlight.pack.js", integrity="sha384-OGoFdvlhYqw3L+BFpHxdz5136RO9tUlt7OZ2qQZ0N6Z9Qqx0rCQBsg9ko7X4vC64")
|
||||
|
||||
script(src="./js/site.js", integrity="sha384-VT6URWBBaQ+gBHYtXUO3QP6Rq8DnvRYIWx6nGW5l5u/usDvbitq+MkHc4ZxVTqzT")
|
||||
script(src="./js/site.js", integrity="sha384-lRJsCA6PqJsSsdIfU9CtmBxuoCI2nZMQSphToDThRdHsK/unylcL0y41P/kRd49S")
|
||||
|
||||
script.
|
||||
$(document).ready(function() {
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
$('[data-toggle="popover"]').popover({html:true, container:"body"});
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// enable tooltips everywhere
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||||
});
|
||||
|
||||
// enable popovers everywhere
|
||||
var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
|
||||
var popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
|
||||
return new bootstrap.Popover(popoverTriggerEl);
|
||||
});
|
||||
|
||||
hljs.highlightAll();
|
||||
});
|
||||
|
||||
hljs.initHighlightingOnLoad();
|
||||
|
||||
|
||||
if (config.credentials.sentryUrl && config.credentials.sentryUrl.length > 0)
|
||||
script(src="./js/sentry.min.js", integrity="sha384-da/Bo2Ah6Uw3mlhl6VINMblg2SyGbSnULKrukse3P5D9PTJi4np9HoKvR19D7zOL", crossorigin="anonymous")
|
||||
|
|
|
|||
|
|
@ -4,88 +4,86 @@ block headContent
|
|||
title Mempool Summary
|
||||
|
||||
block content
|
||||
h1.h3 Mempool Summary
|
||||
hr
|
||||
+pageTitle("Mempool Summary")
|
||||
|
||||
|
||||
+dismissableInfoAlert("mempoolSummaryNoteDismissed", "About Mempool Summary...")
|
||||
.mb-2 This tool summarizes data about the transactions in your node's <b>mempool</b> - the set of transactions that your node has received from the network but are not yet confirmed in a block.
|
||||
.mb-2 The fee-rate summary data can be helpful for deciding what fee is necessary to get a transaction included in a future block, depending on its priority.
|
||||
|
||||
|
||||
div#progress-wrapper.mb-huge
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6 Loading mempool transactions:
|
||||
span Loading mempool transactions:
|
||||
span(id="progress-text")
|
||||
div.progress.mt-2(id="progress-bar", style="height: 7px;")
|
||||
div.progress-bar(id="data-progress", role="progressbar", aria-valuenow="0", aria-valuemin="0" ,aria-valuemax="100")
|
||||
|
||||
|
||||
div(id="main-content", style="display: none;")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-md-3
|
||||
h3.h6.mb-0 Summary
|
||||
hr
|
||||
+contentSection("Summary")
|
||||
+summaryRow(5)
|
||||
+summaryItem("Transactions")
|
||||
span#tx-count
|
||||
|
||||
div.clearfix
|
||||
div.row
|
||||
div.summary-table-label Tx Count
|
||||
div.summary-table-content.font-monospace(id="tx-count")
|
||||
+summaryItem("Memory Usage")
|
||||
span#mem-usage
|
||||
|
||||
div.row
|
||||
div.summary-table-label Memory Usage
|
||||
div.summary-table-content.font-monospace(id="mem-usage")
|
||||
+summaryItem("Total Fees")
|
||||
span#total-fees
|
||||
|
||||
div.row
|
||||
div.summary-table-label Total Fees
|
||||
div.summary-table-content.font-monospace(id="total-fees")
|
||||
+summaryItem("Avg Fee")
|
||||
span#avg-fee
|
||||
|
||||
div.row
|
||||
div.summary-table-label Avg Fee
|
||||
div.summary-table-content.font-monospace(id="avg-fee")
|
||||
|
||||
div.row
|
||||
div.summary-table-label Avg Fee Rate
|
||||
div.summary-table-content.font-monospace(id="avg-fee-rate")
|
||||
+summaryItem("Avg Fee Rate", null, "sat/vB")
|
||||
span#avg-fee-rate
|
||||
|
||||
div#detail-charts-and-data
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-md-3
|
||||
h3.h6.mb-0 Transactions by fee rate
|
||||
hr
|
||||
+contentSection("Fee Rate Distribution")
|
||||
canvas.mb-3(id="mempoolBarChart", height="100")
|
||||
|
||||
canvas.mb-3(id="mempoolBarChart", height="100")
|
||||
hr.mt-3
|
||||
|
||||
div.table-responsive
|
||||
table.table.table-striped.mb-3
|
||||
thead
|
||||
tr
|
||||
th Fee Rate
|
||||
th.text-end Tx Count
|
||||
th.text-end Total Fees
|
||||
th.text-end Avg Fee
|
||||
th.text-end Avg Fee Rate
|
||||
tbody(id="fee-rate-table-body")
|
||||
tr(id="fee-rate-table-row-prototype", style="display: none;")
|
||||
td.font-monospace.data-label
|
||||
td.font-monospace.text-end.data-count
|
||||
td.font-monospace.text-end.data-total-fees
|
||||
td.font-monospace.text-end.data-avg-fee
|
||||
td.font-monospace.text-end.data-fee-rate
|
||||
.table-responsive
|
||||
table.table.table-striped.table-borderless.mb-3
|
||||
thead
|
||||
tr
|
||||
th Fee Rate
|
||||
th.text-end Tx Count
|
||||
th.text-end Total Fees
|
||||
th.text-end Avg Fee
|
||||
th.text-end Avg Fee Rate
|
||||
small.fw-normal.text-muted.ms-2 (sat/vB)
|
||||
tbody(id="fee-rate-table-body")
|
||||
tr(id="fee-rate-table-row-prototype", style="display: none;")
|
||||
td.font-monospace.data-label
|
||||
td.font-monospace.text-end.data-count
|
||||
td.font-monospace.text-end.data-total-fees
|
||||
td.font-monospace.text-end.data-avg-fee
|
||||
td.font-monospace.text-end.data-fee-rate
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-md-3
|
||||
h3.h6.mb-0 Transactions by size
|
||||
hr
|
||||
tr(id="empty-row-to-fix-striped-coloring", style="display: none;")
|
||||
|
||||
canvas.mb-3(id="txSizesBarChart", height="100")
|
||||
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-md-3
|
||||
h3.h6.mb-0 Transactions by age
|
||||
hr
|
||||
+contentSection("Size Distribution")
|
||||
canvas.mb-3(id="txSizesBarChart", height="100")
|
||||
|
||||
canvas.mb-3(id="txAgesBarChart", height="100")
|
||||
|
||||
|
||||
+contentSection("Age Distribution")
|
||||
canvas.mb-3(id="txAgesBarChart", height="100")
|
||||
|
||||
|
||||
|
||||
|
||||
block endOfBody
|
||||
script(src="./js/chart.bundle.min.js", integrity="sha384-qgOtiGNaHh9fVWUnRjyHlV39rfbDcvPPkEzL1RHvsHKbuqUqM6uybNuVnghY2z4/")
|
||||
|
||||
+graphPageScriptSetup
|
||||
|
||||
script(src='./js/decimal.js')
|
||||
|
||||
script.
|
||||
var txidChunks = !{JSON.stringify(mempooltxidChunks)};
|
||||
var satoshiPerByteBucketMaxima = !{JSON.stringify(satoshiPerByteBucketMaxima)};
|
||||
|
|
@ -155,7 +153,7 @@ block endOfBody
|
|||
$("#avg-fee-rate").text(summary.averageFeePerByte);
|
||||
|
||||
$.ajax({
|
||||
url: `./api/utils/formatLargeNumber/${summary.totalBytes},2`
|
||||
url: `./api/utils/formatLargeNumber/${summary.totalBytes},1`
|
||||
|
||||
}).done(function(result) {
|
||||
$("#mem-usage").html(`<span>${result[0]} <small>${result[1].abbreviation}B</small></span>`);
|
||||
|
|
@ -164,7 +162,7 @@ block endOfBody
|
|||
updateCurrencyValue($("#total-fees"), summary.totalFees);
|
||||
updateCurrencyValue($("#avg-fee"), summary.averageFee);
|
||||
|
||||
updateFeeRateValue($("#avg-fee-rate"), summary.averageFeePerByte, 2);
|
||||
updateFeeRateValue($("#avg-fee-rate"), summary.averageFeePerByte, 2, false);
|
||||
|
||||
|
||||
//$("#summary-json").text(JSON.stringify(summary, null, 4));
|
||||
|
|
@ -186,9 +184,17 @@ block endOfBody
|
|||
display: false
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero:true
|
||||
},
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
|
@ -211,9 +217,17 @@ block endOfBody
|
|||
display: false
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero:true
|
||||
},
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
|
@ -236,9 +250,17 @@ block endOfBody
|
|||
display: false
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero:true
|
||||
},
|
||||
gridLines: {
|
||||
color: gridLineColor
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
|
@ -264,7 +286,7 @@ block endOfBody
|
|||
updateCurrencyValue(row.find(".data-total-fees"), item.totalFees);
|
||||
updateCurrencyValue(row.find(".data-avg-fee"), item.totalFees / item.count);
|
||||
|
||||
updateFeeRateValue(row.find(".data-fee-rate"), item.totalFees / item.totalBytes, 2);
|
||||
updateFeeRateValue(row.find(".data-fee-rate"), item.totalFees / item.totalBytes, 2, false);
|
||||
}
|
||||
|
||||
row.show();
|
||||
|
|
|
|||
19
views/mempool-tx.pug
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
extends layout
|
||||
|
||||
block headContent
|
||||
title Mempool Transactions
|
||||
|
||||
block content
|
||||
+pageTitle("Mempool Transactions")
|
||||
|
||||
if (false)
|
||||
pre
|
||||
code #{JSON.stringify(transactions, null, 4)}
|
||||
|
||||
if (txCount > 0)
|
||||
+contentSection(`${txCount.toLocaleString()} Transaction${txCount == 1 ? "" : "s"}`, false, null, false, false)
|
||||
+txList(transactions, txCount, limit, offset, txInputsByTransaction, {mempoolDetailsByTxid:mempoolDetailsByTxid})
|
||||
|
||||
|
||||
else
|
||||
p No unconfirmed transactions found
|
||||
|
|
@ -4,65 +4,31 @@ block headContent
|
|||
title Mining Summary
|
||||
|
||||
block content
|
||||
h1.h3 Mining Summary
|
||||
hr
|
||||
+pageTitle("Mining Summary")
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Block Range
|
||||
hr
|
||||
|
||||
div.clearfix
|
||||
div.float-start.me-4
|
||||
div(id="time-range-buttons")
|
||||
h3.h6 Latest N Blocks
|
||||
div.btn-group
|
||||
a.btn.btn-primary.block-count-btn(href="javascript:void(0)", data-blockCount="144") 144
|
||||
small.ms-2 (~1d)
|
||||
a.btn.btn-outline-primary.block-count-btn(href="javascript:void(0)", data-blockCount="432") 432
|
||||
small.ms-2 (~3d)
|
||||
a.btn.btn-outline-primary.block-count-btn(href="javascript:void(0)", data-blockCount="1008") 1,008
|
||||
small.ms-2 (~7d)
|
||||
a.btn.btn-outline-primary.block-count-btn(href="javascript:void(0)", data-blockCount="4320") 4,320
|
||||
small.ms-2 (~30d)
|
||||
+dismissableInfoAlert("miningSummaryPageNoteDismissed", "About Mining Summary...")
|
||||
| !{markdown("The **Mining Summary** tool queries a range of blocks from Bitcoin Core and tries to identify the miner for each block. The identification of a mining entity is an imperfect process, relying on optional flagging by anonymous entities (though, in practice, it tends to work well).")}
|
||||
| Use the <b>Filters</b> section below to select the range of blocks to analyze.
|
||||
|
||||
div.float-start.me-4
|
||||
div(id="block-selections-buttons")
|
||||
h3.h6 Preconfigured
|
||||
|
||||
div.dropdown
|
||||
button.btn.btn-outline-primary.dropdown-toggle(type="button", id="preconfigured-dropdown", data-bs-toggle="dropdown", aria-haspopup="true", aria-expanded="false") Selections
|
||||
div.dropdown-menu(aria-labelledby="preconfigured-dropdown")
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="0-199") First 200 Blocks
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="209900-210100") First Halving ±100
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="419900-420100") Second Halving ±100
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="629900-630100") Third Halving ±100
|
||||
a.dropdown-item(href="javascript:void(0)", data-blocks="481724-481924") SegWit Activation ±100
|
||||
+contentSection("Filters")
|
||||
+blockRangeFilters
|
||||
|
||||
div.float-start
|
||||
div(id="time-range-buttons")
|
||||
h3.h6 Custom Range
|
||||
|
||||
form.form-inline.me-3(id="custom-range-form")
|
||||
div.input-group
|
||||
input.form-control(type="text", id="custom-range-start", placeholder="min height", style="width: 125px;")
|
||||
input.form-control(type="text", id="custom-range-end", placeholder="max height", style="width: 125px;")
|
||||
|
||||
button.btn.btn-primary(type="submit") Go
|
||||
|
||||
div#progress-wrapper.mb-huge
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6 Loading blocks:
|
||||
span Loading blocks:
|
||||
span(id="block-progress-text")
|
||||
div.progress.mt-2(id="progress-bar", style="height: 7px;")
|
||||
div.progress-bar(id="data-progress", role="progressbar", aria-valuenow="0", aria-valuemin="0" ,aria-valuemax="100")
|
||||
|
||||
|
||||
div.card.shadow-sm.mb-3(id="summary-table", style="display: none;")
|
||||
div.card-body
|
||||
div.table-responsive
|
||||
table.table.table-striped.mb-0
|
||||
div#summary-table(style="display: none;")
|
||||
+contentSection("Miner Breakdown")
|
||||
.table-responsive
|
||||
table.table.table-borderless.table-striped.mb-0
|
||||
thead
|
||||
tr
|
||||
th.data-header Miner
|
||||
|
|
@ -73,7 +39,8 @@ block content
|
|||
|
||||
tbody(id="summary-table-body")
|
||||
tr(id="miner-summary-prototype", style="display: none;")
|
||||
td.data-cell.font-monospace.miner-name
|
||||
td.data-cell.font-monospace
|
||||
span.badge.bg-primary.miner-name
|
||||
td.data-cell.font-monospace.text-end
|
||||
span.miner-block-count
|
||||
small.text-muted.miner-block-percent.ms-2
|
||||
|
|
@ -91,6 +58,8 @@ block content
|
|||
//- var currencyValue = new Decimal(summary.totalFeesCollected);
|
||||
//include ./includes/value-display.pug
|
||||
|
||||
tr(id="hidden-row-to-fix-stripe-pattern", style="display: none;")
|
||||
|
||||
tr(id="miner-summary-totals", style="display: none;")
|
||||
th.data-cell.font-monospace.miner-name Total
|
||||
th.data-cell.font-monospace.text-end
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ block headContent
|
|||
title Node Status
|
||||
|
||||
block content
|
||||
h1.h3 Node Status
|
||||
hr
|
||||
+pageTitle("Node Status")
|
||||
|
||||
if (getblockchaininfo)
|
||||
if (false)
|
||||
|
|
@ -18,214 +17,191 @@ block content
|
|||
|
||||
if (false)
|
||||
pre
|
||||
code.json.bg-light #{JSON.stringify(getblockchaininfo, null, 4)}
|
||||
code.json #{JSON.stringify(getblockchaininfo, null, 4)}
|
||||
|
||||
ul.nav.nav-tabs.mb-3
|
||||
li.nav-item
|
||||
a.nav-link.active(data-bs-toggle="tab", href="#tab-details", role="tab") Details
|
||||
li.nav-item
|
||||
a.nav-link(data-bs-toggle="tab", href="#tab-json", role="tab") JSON
|
||||
|
||||
+pageTabs(["Details", "JSON"])
|
||||
|
||||
|
||||
div.tab-content
|
||||
div.tab-pane.active(id="tab-details", role="tabpanel")
|
||||
div.card.rounded-lg.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-sm-3
|
||||
h3.h6.mb-0 Node Summary
|
||||
hr
|
||||
+pageTab("Details", true)
|
||||
|
||||
div.clearfix
|
||||
div.row
|
||||
div.summary-table-label Version
|
||||
div.summary-table-content.font-monospace #{getnetworkinfo.version} (#{getnetworkinfo.subversion})
|
||||
if (getblockchaininfo.warnings && getblockchaininfo.warnings.trim().length > 0)
|
||||
+contentSection("Active Warnings")
|
||||
if (getblockchaininfo.warnings && getblockchaininfo.warnings.trim().length > 0)
|
||||
span.text-danger #{getblockchaininfo.warnings}
|
||||
else
|
||||
span.text-success None
|
||||
|
||||
div.row
|
||||
div.summary-table-label Protocol Version
|
||||
div.summary-table-content.font-monospace #{getnetworkinfo.protocolversion}
|
||||
+contentSection("Node Summary")
|
||||
+summaryRow(4)
|
||||
+summaryItem("Version")
|
||||
| #{getnetworkinfo.version} (#{getnetworkinfo.subversion})
|
||||
|
||||
div.row
|
||||
div.summary-table-label Status
|
||||
div.summary-table-content.font-monospace
|
||||
if (getblockchaininfo.initialblockdownload || getblockchaininfo.headers > getblockchaininfo.blocks)
|
||||
span Initial block download progress #{(100 * getblockchaininfo.verificationprogress).toLocaleString()}%
|
||||
else
|
||||
span.text-success Synchronized with network
|
||||
+summaryItem("Protocol Version")
|
||||
| #{getnetworkinfo.protocolversion}
|
||||
|
||||
div.row
|
||||
div.summary-table-label Uptime
|
||||
div.summary-table-content.font-monospace
|
||||
- var startTimeAgo = moment.duration(uptimeSeconds * 1000);
|
||||
span #{startTimeAgo.format()}
|
||||
+summaryItem("Status")
|
||||
if (getblockchaininfo.initialblockdownload || getblockchaininfo.headers > getblockchaininfo.blocks)
|
||||
span Initial block download progress #{(100 * getblockchaininfo.verificationprogress).toLocaleString()}%
|
||||
else
|
||||
span.text-success Synchronized
|
||||
|
||||
div.row
|
||||
div.summary-table-label Warnings
|
||||
div.summary-table-content.font-monospace
|
||||
if (getblockchaininfo.warnings && getblockchaininfo.warnings.trim().length > 0)
|
||||
span.text-danger #{getblockchaininfo.warnings}
|
||||
else
|
||||
span.text-success None
|
||||
+summaryItem("Uptime")
|
||||
- var startTimeAgo = moment.duration(uptimeSeconds * 1000);
|
||||
span #{startTimeAgo.format()}
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-sm-3
|
||||
h3.h6.mb-0 Blockchain Summary
|
||||
hr
|
||||
+contentSection("Blockchain")
|
||||
+summaryRow(4 + (getblockchaininfo.size_on_disk ? 1 : 0) + (getblockchaininfo.pruned ? 1 : 0))
|
||||
+summaryItem("Chain")
|
||||
if (getblockchaininfo.chain == "main")
|
||||
span.text-success #{getblockchaininfo.chain}
|
||||
else
|
||||
span.text-warning #{getblockchaininfo.chain}
|
||||
|
||||
div.clearfix
|
||||
div.row
|
||||
div.summary-table-label Chain
|
||||
div.summary-table-content.font-monospace #{getblockchaininfo.chain}
|
||||
+summaryItem("Block Count")
|
||||
| #{getblockchaininfo.blocks.toLocaleString()}
|
||||
if (getblockchaininfo.headers != getblockchaininfo.blocks)
|
||||
br
|
||||
small.text-muted (headers: #{getblockchaininfo.headers.toLocaleString()})
|
||||
|
||||
div.row
|
||||
div.summary-table-label Block Count
|
||||
div.summary-table-content.font-monospace #{getblockchaininfo.blocks.toLocaleString()}
|
||||
+summaryItem("Difficulty")
|
||||
- var difficultyData = utils.formatLargeNumber(getblockchaininfo.difficulty, 3);
|
||||
span.border-dotted(title=parseFloat(getblockchaininfo.difficulty).toLocaleString(), data-bs-toggle="tooltip")
|
||||
span #{difficultyData[0]}
|
||||
span x 10
|
||||
sup #{difficultyData[1].exponent}
|
||||
|
||||
if (getblockchaininfo.size_on_disk)
|
||||
+summaryItem("Data Size")
|
||||
- var sizeData = utils.formatLargeNumber(getblockchaininfo.size_on_disk, 1);
|
||||
| #{sizeData[0]} #{sizeData[1].abbreviation}B
|
||||
|
||||
if (getblockchaininfo.pruned)
|
||||
+summaryItem("Pruned?", "Whether your node prunes the blockchain. With pruning active, your node will delete some data that is non-essential for future verification needs, in order to reduce disk usage.")
|
||||
span.text-warning Yes
|
||||
small.ms-2.text-muted
|
||||
| (
|
||||
span.border-dotted(title="This is the latest block for which your node has all block data; blocks older than this one have had some or all non-essential details deleted.", data-bs-toggle="tooltip")
|
||||
| #{getblockchaininfo.pruneheight.toLocaleString()}+
|
||||
| )
|
||||
|
||||
if (false)
|
||||
br
|
||||
span.text-muted (headers: #{getblockchaininfo.headers.toLocaleString()})
|
||||
|
||||
div.row
|
||||
div.summary-table-label Difficulty
|
||||
div.summary-table-content.font-monospace
|
||||
- var difficultyData = utils.formatLargeNumber(getblockchaininfo.difficulty, 3);
|
||||
span.border-dotted(title=parseFloat(getblockchaininfo.difficulty).toLocaleString(), data-bs-toggle="tooltip")
|
||||
span #{difficultyData[0]}
|
||||
span x 10
|
||||
sup #{difficultyData[1].exponent}
|
||||
span.border-dotted(title="This is the approximate amount of non-essential blockchain data that your node will store.", data-bs-toggle="tooltip") Prune target size
|
||||
|
||||
if (getblockchaininfo.softforks)
|
||||
- var forkUrls = {"bip34":"https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki", "bip65":"https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki", "bip66":"https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki", "csv":"https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki", "segwit":"https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki", "taproot":"https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki"};
|
||||
div.row
|
||||
div.summary-table-label Soft Forks
|
||||
div.summary-table-content.font-monospace
|
||||
ul.list-unstyled
|
||||
each item, itemName in getblockchaininfo.softforks
|
||||
li
|
||||
div.d-inline-block.text-end(style="width: 75px;")
|
||||
if (forkUrls[itemName])
|
||||
a.fw-bold(href=forkUrls[itemName]) #{itemName}
|
||||
| :
|
||||
else
|
||||
span.fw-bold #{itemName}
|
||||
| :
|
||||
|
||||
if (item.type == "bip9")
|
||||
span.me-2.ms-2 #{item.type} - #{JSON.stringify(item.bip9)}
|
||||
span :
|
||||
- var pruneTargetSize = utils.formatLargeNumber(getblockchaininfo.prune_target_size, 1);
|
||||
|
||||
span #{pruneTargetSize[0]} #{pruneTargetSize[1].abbreviation}B
|
||||
|
||||
if (item.active)
|
||||
span.me-2
|
||||
span.text-success active
|
||||
small.text-muted.ms-2 (since: #
|
||||
a(href=`./block-height/${item.height}`) #{item.height.toLocaleString()}
|
||||
| )
|
||||
+summaryItem("Data Indexes")
|
||||
ul.list-unstyled.mb-0
|
||||
li
|
||||
span.me-2 txindex
|
||||
if (getindexinfo.txindex)
|
||||
i.fas.fa-check.text-success
|
||||
else
|
||||
span.border-dotted(title="Your node's lack of a 'transaction index' means this explorer will be unable to show all blockchain data. See the project README for more details.", data-bs-toggle="tooltip")
|
||||
i.fas.fa-times.text-danger
|
||||
|
||||
if (getblockchaininfo.size_on_disk)
|
||||
- var sizeData = utils.formatLargeNumber(getblockchaininfo.size_on_disk, 2);
|
||||
li
|
||||
span.me-2 blockfilterindex
|
||||
if (getindexinfo["basic block filter index"])
|
||||
i.fas.fa-check.text-success
|
||||
else
|
||||
i.fas.fa-times.text-danger
|
||||
|
||||
div.row
|
||||
div.summary-table-label Blockchain Size
|
||||
div.summary-table-content.font-monospace #{sizeData[0]} #{sizeData[1].abbreviation}B
|
||||
if (getblockchaininfo.softforks)
|
||||
- var forkUrls = {"bip34":"https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki", "bip65":"https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki", "bip66":"https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki", "csv":"https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki", "segwit":"https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki", "taproot":"https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki"};
|
||||
|
||||
if (getblockchaininfo.pruned)
|
||||
div.row
|
||||
div.summary-table-label
|
||||
span.border-dotted(title="Whether your node prunes the blockchain. With pruning active, your node will delete some data that is non-essential for future verification needs, in order to reduce disk usage.", data-bs-toggle="tooltip") Pruning?
|
||||
div.summary-table-content.font-monospace
|
||||
span.fw-bold Yes
|
||||
br
|
||||
span.border-dotted(title="This is the latest block for which your node has all block data; blocks older than this one have had some or all non-essential details deleted via pruning.", data-bs-toggle="tooltip") Prune height
|
||||
+contentSection("Soft Forks")
|
||||
+summaryRow(utils.objectProperties(getblockchaininfo.softforks).length)
|
||||
each item, itemName in getblockchaininfo.softforks
|
||||
+summaryItem(itemName)
|
||||
if (item.active)
|
||||
span.me-2
|
||||
span.text-success active
|
||||
small.text-muted.ms-2 (
|
||||
a.border-dotted(href=`./block-height/${item.height}`, title=`${itemName} has been active since block ${item.height}`, data-bs-toggle="tooltip") #{item.height.toLocaleString()}
|
||||
| +)
|
||||
|
||||
span : #{getblockchaininfo.pruneheight.toLocaleString()}
|
||||
else if (item.type == "bip9")
|
||||
span.me-2.ms-2 #{item.type} - #{JSON.stringify(item.bip9)}
|
||||
|
||||
br
|
||||
|
||||
span.border-dotted(title="This is the approximate amount of non-essential blockchain data that your node will store.", data-bs-toggle="tooltip") Prune target size
|
||||
|
||||
span :
|
||||
- var pruneTargetSize = utils.formatLargeNumber(getblockchaininfo.prune_target_size, 2);
|
||||
|
||||
span #{pruneTargetSize[0]} #{pruneTargetSize[1].abbreviation}B
|
||||
|
||||
div.row
|
||||
div.summary-table-label Indexes
|
||||
div.summary-table-content.font-monospace
|
||||
ul.list-unstyled
|
||||
li
|
||||
span.fw-bold txindex
|
||||
| :
|
||||
if (getindexinfo.txindex)
|
||||
span.text-success available
|
||||
else
|
||||
span.text-danger.border-dotted(title="Your node's lack of a 'transaction index' means this explorer will be unable to show all blockchain data. See the project README for more details.", data-bs-toggle="tooltip") unavailable
|
||||
|
||||
li
|
||||
span.fw-bold blockfilterindex
|
||||
| :
|
||||
if (getindexinfo["basic block filter index"])
|
||||
span.text-success available
|
||||
else
|
||||
span.text-danger unavailable
|
||||
if (forkUrls[itemName])
|
||||
small
|
||||
a(href=forkUrls[itemName], title=`More info about ${itemName}`, data-bs-toggle="tooltip", target="_blank")
|
||||
i.fas.fa-external-link-alt.small
|
||||
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-sm-3
|
||||
h3.h6.mb-0 Network Summary
|
||||
+contentSection("Network")
|
||||
+summaryRow(3 + (getnetworkinfo.networks ? 1 : 0))
|
||||
+summaryItem("Host")
|
||||
| #{global.rpcClient.host}
|
||||
span.text-muted :#{global.rpcClient.port}
|
||||
|
||||
+summaryItem("Peers")
|
||||
| #{getnetworkinfo.connections.toLocaleString()}
|
||||
|
||||
if (getnetworkinfo.connections_in)
|
||||
br
|
||||
span.text-muted (#{getnetworkinfo.connections_in.toLocaleString()} in; #{getnetworkinfo.connections_out.toLocaleString()} out)
|
||||
|
||||
+summaryItem("Traffic")
|
||||
- var downData = utils.formatLargeNumber(getnettotals.totalbytesrecv, 1);
|
||||
- var downRateData = utils.formatLargeNumber(getnettotals.totalbytesrecv / uptimeSeconds, 1);
|
||||
- var upData = utils.formatLargeNumber(getnettotals.totalbytessent, 1);
|
||||
- var upRateData = utils.formatLargeNumber(getnettotals.totalbytessent / uptimeSeconds, 1);
|
||||
|
||||
i.fas.fa-arrow-down.me-2
|
||||
span.me-2 #{downData[0]} #{downData[1].abbreviation}B
|
||||
small.text-muted (#{downRateData[0]} #{downRateData[1].abbreviation}B/s)
|
||||
br
|
||||
i.fas.fa-arrow-up.me-2
|
||||
span.me-2 #{upData[0]} #{upData[1].abbreviation}B
|
||||
small.text-muted (#{upRateData[0]} #{upRateData[1].abbreviation}B/s)
|
||||
|
||||
if (getnetworkinfo.networks)
|
||||
+summaryItem("Interfaces")
|
||||
each item, index in getnetworkinfo.networks
|
||||
div
|
||||
div.d-inline-block.text-end(style="width: 75px;")
|
||||
span.me-2 #{item.name}
|
||||
|
||||
if (item.proxy)
|
||||
small.text-muted.me-2 (#{item.proxy})
|
||||
|
||||
if (item.reachable)
|
||||
span.border-dotted(title="Reachable", data-bs-toggle="tooltip")
|
||||
i.fas.fa-check.text-success
|
||||
|
||||
else
|
||||
span.border-dotted(title="Unreachable", data-bs-toggle="tooltip")
|
||||
i.fas.fa-times.text-danger
|
||||
|
||||
|
||||
if (getnetworkinfo.localaddresses)
|
||||
hr
|
||||
|
||||
div.clearfix
|
||||
div.row
|
||||
div.summary-table-label Host : Port
|
||||
div.summary-table-content.font-monospace #{global.rpcClient.host + " : " + global.rpcClient.port}
|
||||
.ms-3
|
||||
+summaryTitle("Addresses")
|
||||
.lead
|
||||
ul
|
||||
each item, index in getnetworkinfo.localaddresses
|
||||
li
|
||||
span.me-2 #{item.address}:#{item.port}
|
||||
small.text-muted (score: #{item.score.toLocaleString()})
|
||||
|
||||
div.row
|
||||
div.summary-table-label Peers
|
||||
div.summary-table-content.font-monospace
|
||||
span #{getnetworkinfo.connections.toLocaleString()}
|
||||
|
||||
if (getnetworkinfo.connections_in)
|
||||
br
|
||||
span.text-muted (#{getnetworkinfo.connections_in.toLocaleString()} in; #{getnetworkinfo.connections_out.toLocaleString()} out)
|
||||
|
||||
div.row
|
||||
div.summary-table-label Network Traffic
|
||||
div.summary-table-content.font-monospace
|
||||
- var downData = utils.formatLargeNumber(getnettotals.totalbytesrecv, 2);
|
||||
- var downRateData = utils.formatLargeNumber(getnettotals.totalbytesrecv / uptimeSeconds, 2);
|
||||
- var upData = utils.formatLargeNumber(getnettotals.totalbytessent, 2);
|
||||
- var upRateData = utils.formatLargeNumber(getnettotals.totalbytessent / uptimeSeconds, 2);
|
||||
|
||||
span Total Download: #{downData[0]} #{downData[1].abbreviation}B
|
||||
span.text-muted (avg #{downRateData[0]} #{downRateData[1].abbreviation}B/s)
|
||||
br
|
||||
span Total Upload: #{upData[0]} #{upData[1].abbreviation}B
|
||||
span.text-muted (avg #{upRateData[0]} #{upRateData[1].abbreviation}B/s)
|
||||
|
||||
if (getnetworkinfo.networks)
|
||||
div.row
|
||||
div.summary-table-label Interfaces
|
||||
div.summary-table-content.font-monospace
|
||||
each item, index in getnetworkinfo.networks
|
||||
div
|
||||
div.d-inline-block.text-end(style="width: 75px;")
|
||||
span.fw-bold #{item.name}
|
||||
| :
|
||||
|
||||
if (item.reachable)
|
||||
span.text-success reachable
|
||||
|
||||
else
|
||||
span.text-danger unreachable
|
||||
|
||||
if (item.proxy)
|
||||
span.text-muted.ms-3 (proxy: #{item.proxy})
|
||||
|
||||
if (getnetworkinfo.localaddresses)
|
||||
div.row
|
||||
div.summary-table-label Local Addresses
|
||||
div.summary-table-content.font-monospace
|
||||
each item, index in getnetworkinfo.localaddresses
|
||||
div #{item.address}:#{item.port}
|
||||
span.text-muted.ms-3 (score: #{item.score.toLocaleString()})
|
||||
if (getnetworkinfo.localaddresses.length == 0)
|
||||
li None
|
||||
|
||||
|
||||
|
||||
|
||||
div.tab-pane(id="tab-json", role="tabpanel")
|
||||
+pageTab("JSON")
|
||||
|
||||
ul.nav.nav-pills.mb-3
|
||||
li.nav-item
|
||||
|
|
@ -239,43 +215,26 @@ block content
|
|||
|
||||
div.tab-content
|
||||
div.tab-pane.active(id="tab-getblockchaininfo", role="tabpanel")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6.mb-0 getblockchaininfo
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light(data-lang="json") #{JSON.stringify(getblockchaininfo, null, 4)}
|
||||
+contentSection("getblockchaininfo")
|
||||
pre
|
||||
code.json(data-lang="json") #{JSON.stringify(getblockchaininfo, null, 4)}
|
||||
|
||||
|
||||
div.tab-pane(id="tab-getnettotals", role="tabpanel")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6.mb-0 getnettotals
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light(data-lang="json") #{JSON.stringify(getnettotals, null, 4)}
|
||||
+contentSection("getnettotals")
|
||||
pre
|
||||
code.json(data-lang="json") #{JSON.stringify(getnettotals, null, 4)}
|
||||
|
||||
|
||||
div.tab-pane(id="tab-getnetworkinfo", role="tabpanel")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6.mb-0 getnetworkinfo
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light(data-lang="json") #{JSON.stringify(getnetworkinfo, null, 4)}
|
||||
+contentSection("getnetworkinfo")
|
||||
pre
|
||||
code.json(data-lang="json") #{JSON.stringify(getnetworkinfo, null, 4)}
|
||||
|
||||
|
||||
div.tab-pane(id="tab-getindexinfo", role="tabpanel")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6.mb-0 getindexinfo
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light(data-lang="json") #{JSON.stringify(global.getindexinfo, null, 4)}
|
||||
|
||||
+contentSection("getindexinfo")
|
||||
pre
|
||||
code.json(data-lang="json") #{JSON.stringify(global.getindexinfo, null, 4)}
|
||||
|
||||
|
||||
|
|
|
|||
248
views/peers.pug
|
|
@ -3,7 +3,7 @@ extends layout
|
|||
block headContent
|
||||
title Peers
|
||||
|
||||
link(rel="stylesheet", href="./css/dataTables.bootstrap4.min.css", integrity="sha384-EkHEUZ6lErauT712zSr0DZ2uuCmi3DoQj6ecNdHQXpMpFNGAQ48WjfXCE5n20W+R")
|
||||
link(rel="stylesheet", href="./style/dataTables.bootstrap4.min.css", integrity="sha384-EkHEUZ6lErauT712zSr0DZ2uuCmi3DoQj6ecNdHQXpMpFNGAQ48WjfXCE5n20W+R")
|
||||
|
||||
link(rel="stylesheet", href="./leaflet/leaflet.css", integrity="sha384-6wKUKNzA6h/S6gZ1lWQppeGaVXvK1AUAsEznGBghzlEu1fNcxJGYVRiroSHr+OwU")
|
||||
|
||||
|
|
@ -17,168 +17,134 @@ block headContent
|
|||
#map { height: 700px; }
|
||||
|
||||
block content
|
||||
h1.h3 #{peerSummary.getpeerinfo.length}
|
||||
if (peerSummary.getpeerinfo.length == 1)
|
||||
span Peer
|
||||
else
|
||||
span Peers
|
||||
hr
|
||||
+pageTitle(`${peerSummary.getpeerinfo.length} Peer${peerSummary.getpeerinfo.length == 1 ? "" : "s"}`)
|
||||
|
||||
+pageTabs(["Details", "JSON"])
|
||||
|
||||
ul.nav.nav-tabs.mb-3
|
||||
li.nav-item
|
||||
a.nav-link.active(data-bs-toggle="tab", href="#tab-summary", role="tab") Summary
|
||||
li.nav-item
|
||||
a.nav-link(data-bs-toggle="tab", href="#tab-json", role="tab") JSON
|
||||
|
||||
div.tab-content
|
||||
div.tab-pane.active(id="tab-summary", role="tabpanel")
|
||||
.tab-content
|
||||
+pageTab("Details", true)
|
||||
|
||||
if (peerIpSummary && peerIpSummary.ips)
|
||||
div.mb-3(id="map")
|
||||
|
||||
div.row
|
||||
div.col-md-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Top Versions
|
||||
hr
|
||||
+contentSection("Top Versions")
|
||||
table.table.table-borderless.table-striped.table-responsive-sm
|
||||
thead
|
||||
tr
|
||||
th
|
||||
th.data-header Version
|
||||
th.data-header Count
|
||||
tbody
|
||||
each item, index in peerSummary.versionSummary
|
||||
tr(class=(index >= 5 ? "versions-hidden-rows" : false))
|
||||
td.data-cell.fw-bold #{index + 1}
|
||||
|
||||
table.table.table-striped.table-responsive-sm
|
||||
thead
|
||||
tr
|
||||
th
|
||||
th.data-header Version
|
||||
th.data-header Count
|
||||
tbody
|
||||
each item, index in peerSummary.versionSummary
|
||||
tr(class=(index >= 5 ? "versions-hidden-rows" : false))
|
||||
td.data-cell.fw-bold #{index + 1}
|
||||
|
||||
td.data-cell.font-monospace #{item[0]}
|
||||
td.data-cell.font-monospace #{item[1].toLocaleString()}
|
||||
td.data-cell.font-monospace #{item[0]}
|
||||
td.data-cell.font-monospace #{item[1].toLocaleString()}
|
||||
|
||||
div.col-md-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Top Service Flags
|
||||
hr
|
||||
+contentSection("Top Service Flags")
|
||||
table.table.table-borderless.table-striped.table-responsive-sm
|
||||
thead
|
||||
tr
|
||||
th
|
||||
th.data-header Services
|
||||
th.data-header Count
|
||||
tbody
|
||||
each item, index in peerSummary.servicesSummary
|
||||
tr(class=(index >= 5 ? "services-hidden-rows" : false))
|
||||
td.data-cell.fw-bold #{index + 1}
|
||||
|
||||
table.table.table-striped.table-responsive-sm
|
||||
thead
|
||||
tr
|
||||
th
|
||||
th.data-header Services
|
||||
th.data-header Count
|
||||
tbody
|
||||
each item, index in peerSummary.servicesSummary
|
||||
tr(class=(index >= 5 ? "services-hidden-rows" : false))
|
||||
td.data-cell.fw-bold #{index + 1}
|
||||
|
||||
td.data-cell.font-monospace #{item[0]}
|
||||
td.data-cell.font-monospace #{item[1].toLocaleString()}
|
||||
td.data-cell.font-monospace #{item[0]}
|
||||
td.data-cell.font-monospace #{item[1].toLocaleString()}
|
||||
|
||||
|
||||
div.row
|
||||
if (peerSummary.networkTypeSummary)
|
||||
div.col-md-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Network Types
|
||||
hr
|
||||
|
||||
table.table.table-striped.table-responsive-sm
|
||||
thead
|
||||
+contentSection("Network Types")
|
||||
table.table.table-borderless.table-striped.table-responsive-sm
|
||||
thead
|
||||
tr
|
||||
th
|
||||
th.data-header Network Type
|
||||
th.data-header Count
|
||||
tbody
|
||||
each item, index in peerSummary.networkTypeSummary
|
||||
tr
|
||||
th
|
||||
th.data-header Network Type
|
||||
th.data-header Count
|
||||
tbody
|
||||
each item, index in peerSummary.networkTypeSummary
|
||||
tr
|
||||
td.data-cell.fw-bold #{index + 1}
|
||||
td.data-cell.fw-bold #{index + 1}
|
||||
|
||||
td.data-cell.font-monospace #{item[0]}
|
||||
td.data-cell.font-monospace #{item[1].toLocaleString()}
|
||||
td.data-cell.font-monospace #{item[0]}
|
||||
td.data-cell.font-monospace #{item[1].toLocaleString()}
|
||||
|
||||
if (peerSummary.connectionTypeSummary)
|
||||
div.col-md-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Connection Types
|
||||
hr
|
||||
|
||||
table.table.table-striped.table-responsive-sm
|
||||
thead
|
||||
+contentSection("Connection Types")
|
||||
table.table.table-borderless.table-striped.table-responsive-sm
|
||||
thead
|
||||
tr
|
||||
th
|
||||
th.data-header Connection Type
|
||||
th.data-header Count
|
||||
tbody
|
||||
each item, index in peerSummary.connectionTypeSummary
|
||||
tr
|
||||
th
|
||||
th.data-header Connection Type
|
||||
th.data-header Count
|
||||
tbody
|
||||
each item, index in peerSummary.connectionTypeSummary
|
||||
tr
|
||||
td.data-cell.fw-bold #{index + 1}
|
||||
td.data-cell.fw-bold #{index + 1}
|
||||
|
||||
td.data-cell.font-monospace #{item[0]}
|
||||
td.data-cell.font-monospace #{item[1].toLocaleString()}
|
||||
td.data-cell.font-monospace #{item[0]}
|
||||
td.data-cell.font-monospace #{item[1].toLocaleString()}
|
||||
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 #{peerSummary.getpeerinfo.length}
|
||||
if (peerSummary.getpeerinfo.length == 1)
|
||||
span Peer
|
||||
else
|
||||
span Peers
|
||||
+contentSection(`${peerSummary.getpeerinfo.length.toLocaleString()} Peer${peerSummary.getpeerinfo.length == 1 ? "" : "s"}`)
|
||||
table.table.table-borderless.table-striped.table-responsive-sm.data-table.mt-4
|
||||
thead
|
||||
tr
|
||||
th
|
||||
th.data-header Version
|
||||
th.data-header Address
|
||||
th.data-header Services
|
||||
|
||||
hr
|
||||
if (peerIpSummary && peerIpSummary.ips)
|
||||
th.data-header Location
|
||||
|
||||
th.data-header Last Send / Receive
|
||||
|
||||
tbody
|
||||
each item, index in peerSummary.getpeerinfo
|
||||
- var lastSendAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date(parseInt(item.lastsend) * 1000)))).format().replace("milliseconds", "ms");
|
||||
- var lastRecvAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date(parseInt(item.lastrecv) * 1000)))).format().replace("milliseconds", "ms");
|
||||
|
||||
table.table.table-striped.table-responsive-sm.data-table.mt-4
|
||||
thead
|
||||
tr
|
||||
th
|
||||
th.data-header Version
|
||||
th.data-header Address
|
||||
th.data-header Services
|
||||
th.data-cell #{index + 1}
|
||||
|
||||
if (peerIpSummary && peerIpSummary.ips)
|
||||
th.data-header Location
|
||||
td.data-cell.font-monospace #{item.subver}
|
||||
td.data-cell.font-monospace #{item.addr}
|
||||
td.data-cell.font-monospace #{item.services}
|
||||
|
||||
th.data-header Last Send / Receive
|
||||
if (peerIpSummary.ips)
|
||||
td.data-cell.font-monospace
|
||||
- var ipAddr = item.addr.substring(0, item.addr.lastIndexOf(":"));
|
||||
if (peerIpSummary.ips && peerIpSummary.ips.includes(ipAddr))
|
||||
- var ipDetails = peerIpSummary.detailsByIp[ipAddr];
|
||||
if (ipDetails)
|
||||
if (ipDetails.city)
|
||||
span #{ipDetails.city},
|
||||
if (ipDetails.region_name)
|
||||
span #{ipDetails.region_name},
|
||||
if (ipDetails.country_name)
|
||||
span #{ipDetails.country_name}
|
||||
else
|
||||
span ?
|
||||
|
||||
tbody
|
||||
each item, index in peerSummary.getpeerinfo
|
||||
- var lastSendAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date(parseInt(item.lastsend) * 1000)))).format().replace("milliseconds", "ms");
|
||||
- var lastRecvAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date(parseInt(item.lastrecv) * 1000)))).format().replace("milliseconds", "ms");
|
||||
- var ipAddr = null;
|
||||
|
||||
tr
|
||||
th.data-cell #{index + 1}
|
||||
|
||||
td.data-cell.font-monospace #{item.subver}
|
||||
td.data-cell.font-monospace #{item.addr}
|
||||
td.data-cell.font-monospace #{item.services}
|
||||
|
||||
if (peerIpSummary.ips)
|
||||
td.data-cell.font-monospace
|
||||
- var ipAddr = item.addr.substring(0, item.addr.lastIndexOf(":"));
|
||||
if (peerIpSummary.ips && peerIpSummary.ips.includes(ipAddr))
|
||||
- var ipDetails = peerIpSummary.detailsByIp[ipAddr];
|
||||
if (ipDetails)
|
||||
if (ipDetails.city)
|
||||
span #{ipDetails.city},
|
||||
if (ipDetails.region_name)
|
||||
span #{ipDetails.region_name},
|
||||
if (ipDetails.country_name)
|
||||
span #{ipDetails.country_name}
|
||||
else
|
||||
span ?
|
||||
|
||||
- var ipAddr = null;
|
||||
|
||||
td.data-cell.font-monospace #{lastSendAgo} / #{lastRecvAgo}
|
||||
td.data-cell.font-monospace #{lastSendAgo} / #{lastRecvAgo}
|
||||
|
||||
|
||||
|
||||
div.tab-pane(id="tab-json", role="tabpanel")
|
||||
+pageTab("JSON")
|
||||
each item, index in peerSummary.getpeerinfo
|
||||
div.border-bottom.p-1
|
||||
a(href="javascript:void(0)" onclick=("javascript:var peer = document.getElementById('peerinfo_" + index + "'); peer.style.display = peer.style.display === 'none' ? '' : 'none';"))
|
||||
|
|
@ -186,25 +152,17 @@ block content
|
|||
|
||||
span.font-monospace #{item.addr}
|
||||
|
||||
div.p-3(style="display: none;", id=`peerinfo_${index}`)
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h6.mb-0 Peer Details
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light #{JSON.stringify(item, null, 4)}
|
||||
.p-3(style="display: none;", id=`peerinfo_${index}`)
|
||||
+contentSection("Peer Details")
|
||||
pre
|
||||
code.json #{JSON.stringify(item, null, 4)}
|
||||
|
||||
|
||||
if (peerIpSummary && peerIpSummary.detailsByIp && peerIpSummary.detailsByIp[item.addr.substring(0, item.addr.lastIndexOf(":"))])
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h6.mb-0 IP Geo-Location Info
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light #{JSON.stringify(peerIpSummary.detailsByIp[item.addr.substring(0, item.addr.lastIndexOf(":"))], null, 4)}
|
||||
+contentSection("Location Info")
|
||||
pre
|
||||
code.json #{JSON.stringify(peerIpSummary.detailsByIp[item.addr.substring(0, item.addr.lastIndexOf(":"))], null, 4)}
|
||||
|
||||
|
||||
|
||||
block endOfBody
|
||||
|
|
|
|||
|
|
@ -10,13 +10,14 @@ block headContent
|
|||
}
|
||||
|
||||
block content
|
||||
h1.h3.mb-0 RPC Browser
|
||||
hr
|
||||
+pageTitle("RPC Browser")
|
||||
|
||||
if (gethelp)
|
||||
div.row
|
||||
div.col-md-9
|
||||
if (methodhelp)
|
||||
+contentSection(`Command: ${method}`)
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
div.clearfix
|
||||
|
|
@ -48,7 +49,7 @@ block content
|
|||
h3.h6.mt-3 Result
|
||||
|
||||
pre.border.mb-3
|
||||
code.json.bg-light(data-lang="json") #{JSON.stringify(methodResult, null, 4)}
|
||||
code.json(data-lang="json") #{JSON.stringify(methodResult, null, 4)}
|
||||
|
||||
hr
|
||||
|
||||
|
|
@ -106,31 +107,29 @@ block content
|
|||
input.btn.btn-primary.px-3(type="submit", name="execute", value="Execute")
|
||||
|
||||
div.tab-pane(id="tab-help-content", role="tabpanel")
|
||||
pre.border
|
||||
code.json.bg-light(data-lang="txt") #{methodhelp.string}
|
||||
pre
|
||||
code.json(data-lang="txt") #{methodhelp.string}
|
||||
|
||||
if (methodhelp.args && methodhelp.args.length > 0)
|
||||
div.tab-pane(id="tab-parsed-args", role="tabpanel")
|
||||
pre.border
|
||||
code.json.bg-light(data-lang="json") #{JSON.stringify(methodhelp.args, null, 4)}
|
||||
code.json(data-lang="json") #{JSON.stringify(methodhelp.args, null, 4)}
|
||||
|
||||
|
||||
|
||||
|
||||
else
|
||||
:markdown-it
|
||||
Browse RPC commands from the list. The list is built from the results of the `help` command and organized into sections accordingly.
|
||||
|
||||
div.col-md-3
|
||||
+dismissableInfoAlert("rpcBrowserNoteDismissed", "About RPC Browser...")
|
||||
.mb-2 This tool lists all RPC commands that your node makes publicly visible. Clicking on any command in the list will display additional information about that command and provide an interactive tool for submitting the command to your node.
|
||||
|
||||
.col-md-3
|
||||
each section, sectionIndex in gethelp
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h4.h6.mb-0 #{section.name}
|
||||
small (#{section.methods.length})
|
||||
hr
|
||||
+contentSection(`${section.name} (${section.methods.length})`)
|
||||
ol.mb-0.ps-4
|
||||
each methodX, methodIndex in section.methods
|
||||
li
|
||||
a(href=`./rpc-browser?method=${methodX.name}`, style=(methodX.name == method ? "font-weight: bold; font-style: italic;" : false)) #{methodX.name}
|
||||
|
||||
|
||||
ol(style="padding-left: 30px;")
|
||||
each methodX, methodIndex in section.methods
|
||||
li
|
||||
a.font-monospace(href=`./rpc-browser?method=${methodX.name}`, style=(methodX.name == method ? "font-weight: bold; font-style: italic;" : false)) #{methodX.name}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,19 +4,18 @@ block headContent
|
|||
title RPC Terminal
|
||||
|
||||
block content
|
||||
div.row
|
||||
div.col
|
||||
h1.h3 RPC Terminal
|
||||
+pageTitle("RPC Terminal")
|
||||
|
||||
div.col
|
||||
if (!config.demoSite && (!config.credentials.rpc || !config.credentials.rpc.rpc))
|
||||
span(style="float: right;")
|
||||
a.btn.btn-secondary(href="./disconnect") Disconnect from node
|
||||
|
||||
hr
|
||||
|
||||
:markdown-it
|
||||
Use this interactive terminal to send RPC commands to your node. Results will be shown inline. To browse all available RPC commands you can use the [RPC Browser](./rpc-browser).
|
||||
if (!config.demoSite && (!config.credentials.rpc || !config.credentials.rpc.rpc))
|
||||
.mb-2
|
||||
a.btn.btn-secondary(href="./disconnect") Disconnect from node
|
||||
|
||||
|
||||
+dismissableInfoAlert("rpcTermPageNoteDismissed", "About RPC Terminal...")
|
||||
.mb-2 This tool lets you send custom RPC commands to your node and will display the results below.
|
||||
.mb-2 To browse all available RPC commands you can use the <a href="./rpc-browser">RPC Browser</a>.
|
||||
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
|
|
|
|||
|
|
@ -4,15 +4,14 @@ block headContent
|
|||
title Search
|
||||
|
||||
block content
|
||||
h1.h3 Search
|
||||
hr
|
||||
+pageTitle("Search")
|
||||
|
||||
div.card.shadow-sm.mb-huge
|
||||
div.card-body
|
||||
form.form.form-inline(method="post", action="./search")
|
||||
input(type="hidden", name="_csrf", value=csrfToken)
|
||||
+contentSection
|
||||
form.form.form-inline(method="post", action="./search")
|
||||
input(type="hidden", name="_csrf", value=csrfToken)
|
||||
|
||||
div.input-group
|
||||
input.form-control(type="text", name="query", placeholder="block height/hash, txid, address", value=(query), style="width: 400px;")
|
||||
|
||||
button.btn.btn-primary(type="submit") Search
|
||||
div.input-group
|
||||
input.form-control(type="text", name="query", placeholder="block height/hash, txid, address", value=(query), style="width: 400px;")
|
||||
|
||||
button.btn.btn-primary(type="submit") Search
|
||||
|
||||
|
|
|
|||
|
|
@ -4,23 +4,19 @@ block headContent
|
|||
title Terminal
|
||||
|
||||
block content
|
||||
div.row
|
||||
div.col
|
||||
h1.h3 Terminal
|
||||
|
||||
hr
|
||||
+pageTitle("Terminal")
|
||||
|
||||
:markdown-it
|
||||
Use this interactive terminal to send RPC commands to your node. Results will be shown inline. To browse all available RPC commands you can use the [RPC Browser](/rpc-browser).
|
||||
+dismissableInfoAlert
|
||||
.mb-3 This is an internal developer tool.
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
form(id="terminal-form")
|
||||
.mb-3
|
||||
label(for="input-cmd") Command
|
||||
input.form-control(type="text", id="input-cmd", name="cmd")
|
||||
+contentSection
|
||||
form(id="terminal-form")
|
||||
.mb-3
|
||||
label(for="input-cmd") Command
|
||||
input.form-control(type="text", id="input-cmd", name="cmd")
|
||||
|
||||
input.btn.btn-primary.w-100(type="submit", value="Send")
|
||||
input.btn.btn-primary.w-100(type="submit", value="Send")
|
||||
|
||||
|
||||
hr
|
||||
|
||||
|
|
|
|||
116
views/tools.pug
|
|
@ -4,72 +4,70 @@ block headContent
|
|||
title Tools
|
||||
|
||||
block content
|
||||
h1.h3 Tools
|
||||
hr
|
||||
+pageTitle("Tools")
|
||||
|
||||
div.card.shadow-sm.mb-huge
|
||||
div.card-body
|
||||
- var priorityList = config.site.prioritizedToolIdsList;
|
||||
- var indexLists1Col = utils.splitArrayIntoChunksByChunkCount(priorityList, 1);
|
||||
- var indexLists2Col = utils.splitArrayIntoChunksByChunkCount(priorityList, 2);
|
||||
- var indexLists3Col = utils.splitArrayIntoChunksByChunkCount(priorityList, 3);
|
||||
+contentSection
|
||||
- var priorityList = config.site.prioritizedToolIdsList;
|
||||
- var indexLists1Col = utils.splitArrayIntoChunksByChunkCount(priorityList, 1);
|
||||
- var indexLists2Col = utils.splitArrayIntoChunksByChunkCount(priorityList, 2);
|
||||
- var indexLists3Col = utils.splitArrayIntoChunksByChunkCount(priorityList, 3);
|
||||
|
||||
// xs
|
||||
div.d-block.d-sm-none(id="tools-1-col")
|
||||
div.row
|
||||
each indexList in indexLists1Col
|
||||
div.col
|
||||
ul.list-unstyled.mb-0
|
||||
each toolsItemIndex in indexList
|
||||
- var item = config.siteTools[toolsItemIndex];
|
||||
|
||||
div.clearfix
|
||||
div.float-start.pt-1(style="width: 38px;")
|
||||
i.fa-lg(class=item.fontawesome, style="width: 20px; margin-right: 10px;")
|
||||
// xs
|
||||
div.d-block.d-sm-none(id="tools-1-col")
|
||||
div.row
|
||||
each indexList in indexLists1Col
|
||||
div.col
|
||||
ul.list-unstyled.mb-0
|
||||
each toolsItemIndex in indexList
|
||||
- var item = config.siteTools[toolsItemIndex];
|
||||
|
||||
div.clearfix
|
||||
div.float-start.pt-1(style="width: 38px;")
|
||||
i.fa-lg(class=item.fontawesome, style="width: 20px; margin-right: 10px;")
|
||||
|
||||
div.float-start
|
||||
div.lead
|
||||
a(href=item.url) #{item.name}
|
||||
div.float-start
|
||||
div.lead
|
||||
a(href=item.url) #{item.name}
|
||||
|
||||
div(style="padding-left: 39px;")
|
||||
p #{item.desc}
|
||||
div(style="padding-left: 39px;")
|
||||
p #{item.desc}
|
||||
|
||||
// sm, md, lg
|
||||
div.d-none.d-sm-block.d-xl-none(id="tools-2-col")
|
||||
div.row
|
||||
each indexList in indexLists2Col
|
||||
div.col
|
||||
ul.list-unstyled.mb-0
|
||||
each toolsItemIndex in indexList
|
||||
- var item = config.siteTools[toolsItemIndex];
|
||||
|
||||
div.clearfix
|
||||
div.float-start.pt-1(style="width: 38px;")
|
||||
i.fa-lg(class=item.fontawesome, style="width: 20px; margin-right: 10px;")
|
||||
// sm, md, lg
|
||||
div.d-none.d-sm-block.d-xl-none(id="tools-2-col")
|
||||
div.row
|
||||
each indexList in indexLists2Col
|
||||
div.col
|
||||
ul.list-unstyled.mb-0
|
||||
each toolsItemIndex in indexList
|
||||
- var item = config.siteTools[toolsItemIndex];
|
||||
|
||||
div.clearfix
|
||||
div.float-start.pt-1(style="width: 38px;")
|
||||
i.fa-lg(class=item.fontawesome, style="width: 20px; margin-right: 10px;")
|
||||
|
||||
div.float-start
|
||||
div.lead
|
||||
a(href=item.url) #{item.name}
|
||||
div.float-start
|
||||
div.lead
|
||||
a(href=item.url) #{item.name}
|
||||
|
||||
div(style="padding-left: 39px;")
|
||||
p #{item.desc}
|
||||
div(style="padding-left: 39px;")
|
||||
p #{item.desc}
|
||||
|
||||
// xl, xxl
|
||||
div.d-none.d-xl-block(id="tools-3-col")
|
||||
div.row
|
||||
each indexList in indexLists3Col
|
||||
div.col
|
||||
ul.list-unstyled.mb-0
|
||||
each toolsItemIndex in indexList
|
||||
- var item = config.siteTools[toolsItemIndex];
|
||||
|
||||
div.clearfix
|
||||
div.float-start.pt-1(style="width: 38px;")
|
||||
i.fa-lg(class=item.fontawesome, style="width: 20px; margin-right: 10px;")
|
||||
// xl, xxl
|
||||
div.d-none.d-xl-block(id="tools-3-col")
|
||||
div.row
|
||||
each indexList in indexLists3Col
|
||||
div.col
|
||||
ul.list-unstyled.mb-0
|
||||
each toolsItemIndex in indexList
|
||||
- var item = config.siteTools[toolsItemIndex];
|
||||
|
||||
div.clearfix
|
||||
div.float-start.pt-1(style="width: 38px;")
|
||||
i.fa-lg(class=item.fontawesome, style="width: 20px; margin-right: 10px;")
|
||||
|
||||
div.float-start
|
||||
div.lead
|
||||
a(href=item.url) #{item.name}
|
||||
div.float-start
|
||||
div.lead
|
||||
a(href=item.url) #{item.name}
|
||||
|
||||
div(style="padding-left: 39px;")
|
||||
p #{item.desc}
|
||||
div(style="padding-left: 39px;")
|
||||
p #{item.desc}
|
||||
|
|
@ -10,60 +10,38 @@ block headContent
|
|||
|
||||
block content
|
||||
if (!result || !result.getrawtransaction)
|
||||
h1.h3.word-wrap Transaction
|
||||
br
|
||||
small.font-monospace #{txid}
|
||||
hr
|
||||
+pageTitle("Transaction", txid, true)
|
||||
|
||||
if (block)
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-md-3
|
||||
h2.h6.mb-0 Summary
|
||||
hr
|
||||
+contentSection("Summary")
|
||||
+summaryRow(2)
|
||||
+summaryItem("Block")
|
||||
a(href=`./block/${block.hash}`) ##{block.height.toLocaleString()}
|
||||
|
||||
div.clearfix
|
||||
div.row
|
||||
div.summary-table-label Block
|
||||
div.summary-table-content.font-monospace
|
||||
a(href=`./block/${block.hash}`) ##{block.height.toLocaleString()}
|
||||
+summaryItem("Date")
|
||||
if (block.time)
|
||||
+timestamp(block.time)
|
||||
|
||||
div.row
|
||||
div.summary-table-label Date
|
||||
div.summary-table-content.font-monospace
|
||||
if (block.time)
|
||||
td.font-monospace
|
||||
- var timestampHuman = block.time;
|
||||
include includes/timestamp-human.pug
|
||||
small.ms-1 utc
|
||||
else
|
||||
| ?
|
||||
|
||||
|
||||
- var timeAgoTime = block.time;
|
||||
span.text-muted.ms-2 (
|
||||
include includes/time-ago-text.pug
|
||||
span ago)
|
||||
|
||||
div.alert.alert-warning.pb-0(role="alert")
|
||||
+warningAlert
|
||||
h6.mb-2 Transaction Details Unavailable
|
||||
|
||||
if (blockHeight && global.prunedBlockchain && blockHeight < global.pruneHeight)
|
||||
- var msgMarkdown = "Blockchain `pruning` is enabled on your node. This setting tells your node that after validating transactions it may discard data that is non-essential for future validation needs.\n\nThe block that contains this transaction has been pruned, meaning that non-essential data has been deleted, including the details of this transaction.";
|
||||
| !{markdown(msgMarkdown)}
|
||||
.mb-2 Blockchain <b>pruning</b> is enabled on your node. This setting tells your node that after validating transactions it may discard data that is non-essential for future validation needs.
|
||||
.mb-0 The block that contains this transaction has been pruned, meaning that non-essential data has been deleted, including the details of this transaction.
|
||||
|
||||
|
||||
else if (!global.txindexAvailable)
|
||||
| !{markdown(noTxIndexMsg)}
|
||||
|
||||
if (result && result.getrawtransaction)
|
||||
h1.h3.word-wrap Transaction
|
||||
br
|
||||
small.font-monospace #{txid}
|
||||
hr
|
||||
+pageTitle("Transaction", txid, true, [["coinbase", "This is a coinbase transaction."]])
|
||||
|
||||
+pageTabs(["Details", "Scripts", "JSON"])
|
||||
|
||||
ul.nav.nav-tabs.mb-3
|
||||
li.nav-item
|
||||
a.nav-link.active(data-bs-toggle="tab", href="#tab-details", role="tab") Details
|
||||
li.nav-item
|
||||
a.nav-link(data-bs-toggle="tab", href="#tab-scripts", role="tab") Scripts
|
||||
li.nav-item
|
||||
a.nav-link(data-bs-toggle="tab", href="#tab-json", role="tab") JSON
|
||||
|
||||
- DecimalRounded = Decimal.clone({ precision: 4, rounding: 2 })
|
||||
|
||||
|
|
@ -81,265 +59,170 @@ block content
|
|||
- totalOutputValue = totalOutputValue.plus(new Decimal(vout.value));
|
||||
|
||||
div.tab-content
|
||||
div.tab-pane.active(id="tab-details", role="tabpanel")
|
||||
+pageTab("Details", true)
|
||||
|
||||
if (global.specialTransactions && global.specialTransactions[txid])
|
||||
div.alert.alert-primary.shadow-sm.pb-0
|
||||
div.float-start(style="width: 55px; height: 55px; font-size: 18px;")
|
||||
i.fas.fa-certificate.fa-2x(style="margin-top: 10px;")
|
||||
- var stInfo = global.specialTransactions[txid];
|
||||
|
||||
h4.alert-heading.h6.fw-bold #{coinConfig.name} Fun
|
||||
+funAlert(stInfo.alertBodyHtml, stInfo.summary, stInfo.referenceUrl)
|
||||
|
||||
// special transaction info
|
||||
- var stInfo = global.specialTransactions[txid];
|
||||
if (stInfo.alertBodyHtml)
|
||||
p
|
||||
span !{stInfo.alertBodyHtml}
|
||||
|
||||
if (stInfo.referenceUrl && stInfo.referenceUrl.trim().length > 0 && stInfo.alertBodyHtml.indexOf(stInfo.referenceUrl) == -1)
|
||||
span
|
||||
a(href=stInfo.referenceUrl) Read more
|
||||
else
|
||||
p
|
||||
span #{stInfo.summary}
|
||||
|
||||
if (stInfo.referenceUrl && stInfo.referenceUrl.trim().length > 0)
|
||||
span
|
||||
a(href=stInfo.referenceUrl) Read more
|
||||
.clearfix
|
||||
.float-end
|
||||
if (`${userSettings["txPageShowTechDetails"]}` == "false")
|
||||
a.btn.btn-primary.btn-sm.me-2(href=`./changeSetting?name=txPageShowTechDetails&value=true`, title="Display technical details for this transaction.", data-bs-toggle="tooltip")
|
||||
i.far.fa-plus-square.me-2
|
||||
| Technical Details
|
||||
|
||||
|
||||
- var isTxConfirmed = true;
|
||||
if (!result.getrawtransaction.confirmations || result.getrawtransaction.confirmations == 0)
|
||||
- isTxConfirmed = false;
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-md-3
|
||||
h2.h6.mb-0 Summary
|
||||
hr
|
||||
if (isCoinbaseTx)
|
||||
- var minerInfo = utils.getMinerFromCoinbaseTx(result.getrawtransaction);
|
||||
|
||||
div.clearfix
|
||||
if (!isTxConfirmed)
|
||||
div.row
|
||||
div.summary-table-label Status
|
||||
div.summary-table-content.font-monospace
|
||||
span.text-danger Unconfirmed
|
||||
+contentSection("Summary")
|
||||
+summaryRow((isTxConfirmed ? 2 : 2) + (isCoinbaseTx ? 1 : 2) + (isCoinbaseTx && minerInfo ? 1 : 0))
|
||||
if (!isTxConfirmed)
|
||||
+summaryItem("Status")
|
||||
span.text-danger Unconfirmed
|
||||
|
||||
div.row
|
||||
div.summary-table-label
|
||||
span.border-dotted(title="Whether this unconfirmed transaction is replaceable using replace-by-fee (RBF)", data-bs-toggle="tooltip") RBF
|
||||
div.summary-table-content.font-monospace
|
||||
- var replaceable = false;
|
||||
each vin, vinIndex in result.getrawtransaction.vin
|
||||
// ref: https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki#summary
|
||||
if (vin.sequence < 4294967295 - 1)
|
||||
- replaceable = true;
|
||||
+summaryItem("RBF", "Whether this unconfirmed transaction is replaceable using Replace-By-Fee.")
|
||||
- var replaceable = false;
|
||||
each vin, vinIndex in tx.vin
|
||||
// ref: https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki#summary
|
||||
if (vin.sequence < 4294967295 - 1)
|
||||
- replaceable = true;
|
||||
|
||||
if (replaceable)
|
||||
span.text-success Yes
|
||||
else if (mempoolDetails.ancestors.length > 0)
|
||||
span.border-dotted(title="RBF may be signaled explicitly or implicitly. This transaction does not explicitly opt in, but if any of its unconfirmed ancestor transactions are replaceable then this one is too.", data-bs-toggle="tooltip") No explicit opt-in
|
||||
a.ms-2(href="https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki#summary", data-bs-toggle="tooltip", title="More info about RBF", target="_blank")
|
||||
i.fas.fa-info-circle
|
||||
else
|
||||
span No
|
||||
if (replaceable)
|
||||
span.text-success Yes
|
||||
|
||||
else if (mempoolDetails.ancestors.length > 0)
|
||||
span.border-dotted(title="RBF may be signaled explicitly or implicitly. This transaction does not explicitly opt in, but if any of its unconfirmed ancestor transactions are replaceable then this one is too.", data-bs-toggle="tooltip") No explicit opt-in
|
||||
a.ms-2(href="https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki#summary", data-bs-toggle="tooltip", title="More info about RBF", target="_blank")
|
||||
i.fas.fa-info-circle
|
||||
else
|
||||
span No
|
||||
|
||||
if (isTxConfirmed)
|
||||
div.row
|
||||
div.summary-table-label Block
|
||||
div.summary-table-content.font-monospace
|
||||
a(href=`./block/${result.getrawtransaction.blockhash}`) ##{result.getblock.height.toLocaleString()}
|
||||
else
|
||||
+summaryItem("Block")
|
||||
a(href=`./block/${result.getrawtransaction.blockhash}`) #{result.getblock.height.toLocaleString()}
|
||||
small.ms-2.text-muted
|
||||
| (
|
||||
+confirmations(tx.confirmations)
|
||||
| )
|
||||
|
||||
+summaryItem("Date")
|
||||
if (tx.time)
|
||||
td.font-monospace
|
||||
+timestamp(result.getrawtransaction.time)
|
||||
|
||||
|
||||
if (isTxConfirmed)
|
||||
div.row
|
||||
div.summary-table-label Date
|
||||
div.summary-table-content.font-monospace
|
||||
if (result.getrawtransaction.time)
|
||||
td.font-monospace
|
||||
- var timestampHuman = result.getrawtransaction.time;
|
||||
include includes/timestamp-human.pug
|
||||
small.ms-1 utc
|
||||
|
||||
- var timeAgoTime = result.getrawtransaction.time;
|
||||
span.text-muted.ms-2 (
|
||||
include includes/time-ago-text.pug
|
||||
span ago)
|
||||
|
||||
div.row
|
||||
div.summary-table-label Version
|
||||
div.summary-table-content.font-monospace #{result.getrawtransaction.version}
|
||||
|
||||
div.row
|
||||
div.summary-table-label Size
|
||||
div.summary-table-content.font-monospace
|
||||
if (result.getrawtransaction.vsize != result.getrawtransaction.size)
|
||||
span #{result.getrawtransaction.vsize.toLocaleString()}
|
||||
small vB
|
||||
br
|
||||
span.text-muted (#{result.getrawtransaction.size.toLocaleString()}
|
||||
small B
|
||||
span )
|
||||
if (isCoinbaseTx)
|
||||
if (minerInfo)
|
||||
+summaryItem("Miner")
|
||||
if (minerInfo.identifiedBy)
|
||||
small.badge.bg-primary(data-bs-toggle="tooltip", title=`Identified by: ${minerInfo.identifiedBy}`) #{minerInfo.name}
|
||||
|
||||
else
|
||||
span #{result.getrawtransaction.size.toLocaleString()}
|
||||
small B
|
||||
small.badge.bg-primary #{minerInfo.name}
|
||||
|
||||
|
||||
if (result.getrawtransaction.locktime > 0)
|
||||
div.row
|
||||
div.summary-table-label Locktime
|
||||
div.summary-table-content.font-monospace
|
||||
if (result.getrawtransaction.locktime < 500000000)
|
||||
span Spendable in block
|
||||
a(href=`./block-height/${result.getrawtransaction.locktime}`) ##{result.getrawtransaction.locktime.toLocaleString()}
|
||||
span or later
|
||||
a(href="https://developer.bitcoin.org/devguide/transactions.html#locktime-and-sequence-number", data-bs-toggle="tooltip", title="More info about locktime", target="_blank")
|
||||
i.fas.fa-info-circle
|
||||
else
|
||||
span Spendable after #{moment.utc(new Date(result.getrawtransaction.locktime * 1000)).format("Y-MM-DD HH:mm:ss")}
|
||||
small utc
|
||||
a(href="https://developer.bitcoin.org/devguide/transactions.html#locktime-and-sequence-number", data-bs-toggle="tooltip", title="More info about locktime", target="_blank")
|
||||
i.fas.fa-info-circle
|
||||
+summaryItem("Fees Collected", "The aggregate fees collected by the miner that created this coinbase transaction.")
|
||||
- var currencyValue = new Decimal(totalOutputValue).minus(totalInputValue);
|
||||
include includes/value-display.pug
|
||||
|
||||
if (isTxConfirmed)
|
||||
div.row
|
||||
div.summary-table-label Confirmations
|
||||
div.summary-table-content.font-monospace
|
||||
if (result.getrawtransaction.confirmations < 6)
|
||||
span.fw-bold.text-warning #{result.getrawtransaction.confirmations.toLocaleString()}
|
||||
a(data-bs-toggle="tooltip", title="Fewer than 6 confirmations is generally considered 'unsettled' for high-value transactions. The applicability of this guidance may vary.")
|
||||
i.fas.fa-unlock-alt
|
||||
else
|
||||
+summaryItem("Fee Rate", null, "sat/vB")
|
||||
if (!mempoolDetails && !global.txindexAvailable)
|
||||
span.border-dotted(title="Determining the fee of confirmed transactions requires txindex to be enabled", data-bs-toggle="tooltip")
|
||||
i.fas.fa-backspace.text-danger.me-2
|
||||
| ?
|
||||
|
||||
else
|
||||
span.fw-bold.text-success #{result.getrawtransaction.confirmations.toLocaleString()}
|
||||
a(data-bs-toggle="tooltip", title="6 confirmations is generally considered 'settled'. High-value transactions may require more; low-value transactions may require less.")
|
||||
i.fas.fa-lock
|
||||
|
||||
|
||||
if (result.getrawtransaction.vin[0].coinbase)
|
||||
div.row
|
||||
div.summary-table-label Fees Collected
|
||||
div.summary-table-content.font-monospace
|
||||
- var currencyValue = new Decimal(totalOutputValue).minus(totalInputValue);
|
||||
include includes/value-display.pug
|
||||
|
||||
- var blockRewardMax = coinConfig.blockRewardFunction(result.getblock.height, activeBlockchain);
|
||||
if (parseFloat(totalOutputValue) < parseFloat(blockRewardMax))
|
||||
div.row
|
||||
div.summary-table-label
|
||||
span.border-dotted(data-bs-toggle="tooltip" title="The miner of this transaction's block failed to collect this value. As a result, it is permanently lost.") Value Destroyed
|
||||
div.summary-table-content.font-monospace.text-danger
|
||||
- var currencyValue = new Decimal(blockRewardMax).minus(totalOutputValue);
|
||||
include includes/value-display.pug
|
||||
|
||||
- var minerInfo = utils.getMinerFromCoinbaseTx(result.getrawtransaction);
|
||||
if (minerInfo)
|
||||
div.row
|
||||
div.summary-table-label Miner
|
||||
div.summary-table-content.font-monospace
|
||||
if (minerInfo.identifiedBy)
|
||||
small.data-tag.bg-primary(data-bs-toggle="tooltip", title=`Identified by: ${minerInfo.identifiedBy}`) #{minerInfo.name}
|
||||
|
||||
else
|
||||
small.data-tag.bg-primary #{minerInfo.name}
|
||||
|
||||
else if (!mempoolDetails && !global.txindexAvailable)
|
||||
div.row
|
||||
div.summary-table-label Fee Paid
|
||||
div.summary-table-content.font-monospace
|
||||
span.border-dotted(title="Determining the fee of confirmed transactions requires txindex to be enabled", data-bs-toggle="tooltip")
|
||||
i.fas.fa-backspace.text-danger.me-2
|
||||
| ?
|
||||
else
|
||||
- var feePaid = mempoolDetails ? new Decimal(mempoolDetails.entry.fees.base) : new Decimal(totalInputValue).minus(totalOutputValue);
|
||||
|
||||
div.row
|
||||
div.summary-table-label Fee Paid
|
||||
div.summary-table-content.font-monospace
|
||||
- var currencyValue = feePaid;
|
||||
include includes/value-display.pug
|
||||
|
||||
if (feePaid > 0 && totalInputValue > 0)
|
||||
- var item1 = utils.formatCurrencyAmount(totalInputValue, currencyFormatType);
|
||||
- var item2 = utils.formatCurrencyAmount(totalOutputValue, currencyFormatType);
|
||||
span.ms-2(title=`${item1.simpleVal} - ${item2.simpleVal}`, data-bs-toggle="tooltip")
|
||||
i.fas.fa-ellipsis-h
|
||||
|
||||
if (feePaid > 0)
|
||||
div.row
|
||||
div.summary-table-label Fee Rate
|
||||
div.summary-table-content.font-monospace
|
||||
if (result.getrawtransaction.vsize != result.getrawtransaction.size)
|
||||
span #{utils.addThousandsSeparators(new DecimalRounded(feePaid).dividedBy(result.getrawtransaction.vsize).times(100000000))}
|
||||
small sat/vB
|
||||
br
|
||||
|
||||
span.text-muted (#{utils.addThousandsSeparators(new DecimalRounded(feePaid).dividedBy(result.getrawtransaction.size).times(100000000))}
|
||||
small sat/B
|
||||
span )
|
||||
|
||||
else
|
||||
span #{utils.addThousandsSeparators(new DecimalRounded(feePaid).dividedBy(result.getrawtransaction.size).times(100000000))}
|
||||
small sat/B
|
||||
|
||||
- var daysDestroyed = new Decimal(0);
|
||||
each xInput, xInputIndex in result.getrawtransaction.vin
|
||||
- var vout = null;
|
||||
if (result.txInputs && result.txInputs[xInputIndex])
|
||||
- var vout = result.txInputs[xInputIndex];
|
||||
else
|
||||
- var feePaid = mempoolDetails ? new Decimal(mempoolDetails.entry.fees.base) : new Decimal(totalInputValue).minus(totalOutputValue);
|
||||
|
||||
if (vout.utxoTime)
|
||||
- var dt = result.getrawtransaction.time - vout.utxoTime;
|
||||
- var dtDays = dt / 60 / 60 / 24;
|
||||
- daysDestroyed = daysDestroyed.plus(new Decimal(vout.value).times(dtDays));
|
||||
span #{utils.addThousandsSeparators(new DecimalRounded(feePaid).dividedBy(tx.vsize).times(100000000))}
|
||||
|
||||
if (parseInt(daysDestroyed) > 0)
|
||||
div.row
|
||||
div.summary-table-label
|
||||
span.border-dotted(title=`The sum of all input values multiplied by the number of days that input's UTXO existed before being spent. Large values can sometimes be interesting, indicating the spending of long-dormant coins. A 1 ${coinConfig.ticker} UTXO spent after 7 days dormant results in 7 days destroyed, as does a 7 ${coinConfig.ticker} UTXO spent after 1 day dormant.`, data-bs-toggle="tooltip") Days Destroyed
|
||||
div.summary-table-content.font-monospace
|
||||
span #{utils.addThousandsSeparators(daysDestroyed.toDP(daysDestroyed > 1 ? 0 : 1))}
|
||||
small.ms-1.border-dotted(title=`${coinConfig.name} Days`, data-bs-toggle="tooltip") #{coinConfig.ticker.toLowerCase().substring(0, 1)}d
|
||||
+summaryItem("Total Fee")
|
||||
if (!mempoolDetails && !global.txindexAvailable)
|
||||
span.border-dotted(title="Determining the fee of confirmed transactions requires txindex to be enabled", data-bs-toggle="tooltip")
|
||||
i.fas.fa-backspace.text-danger.me-2
|
||||
| ?
|
||||
|
||||
|
||||
if (result.getrawtransaction.vin[0].coinbase)
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-md-3
|
||||
h3.h6.mb-0 Coinbase
|
||||
hr
|
||||
|
||||
h6 Hex
|
||||
div.bg-light.px-2.py-2.mb-3.border
|
||||
span.font-monospace.word-wrap #{result.getrawtransaction.vin[0].coinbase}
|
||||
|
||||
h6 Decoded
|
||||
div.bg-light.px-2.py-2.border
|
||||
span.text-monospace.word-wrap #{utils.hex2ascii(result.getrawtransaction.vin[0].coinbase)}
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-md-3
|
||||
h2.h6.mb-0
|
||||
span #{result.getrawtransaction.vin.length.toLocaleString()}
|
||||
if (result.getrawtransaction.vin.length == 1)
|
||||
span Input
|
||||
else
|
||||
span Inputs
|
||||
- var feePaid = mempoolDetails ? new Decimal(mempoolDetails.entry.fees.base) : new Decimal(totalInputValue).minus(totalOutputValue);
|
||||
- var currencyValue = feePaid;
|
||||
include includes/value-display.pug
|
||||
|
||||
|
||||
span.mx-2.text-muted.text-small /
|
||||
|
||||
span #{result.getrawtransaction.vout.length.toLocaleString()}
|
||||
if (result.getrawtransaction.vout.length == 1)
|
||||
span Output
|
||||
else
|
||||
span Outputs
|
||||
|
||||
hr
|
||||
|
||||
|
||||
- var daysDestroyed = new Decimal(0);
|
||||
each xInput, xInputIndex in tx.vin
|
||||
- var vout = null;
|
||||
if (result.txInputs && result.txInputs[xInputIndex])
|
||||
- var vout = result.txInputs[xInputIndex];
|
||||
|
||||
if (vout.utxoTime)
|
||||
- var dt = result.getrawtransaction.time - vout.utxoTime;
|
||||
- var dtDays = dt / 60 / 60 / 24;
|
||||
- daysDestroyed = daysDestroyed.plus(new Decimal(vout.value).times(dtDays));
|
||||
|
||||
+contentSection("Technical Details", true, "txPageShowTechDetails")
|
||||
if (isTxConfirmed)
|
||||
- var blockRewardMax = coinConfig.blockRewardFunction(result.getblock.height, activeBlockchain);
|
||||
- var valueDestroyed = (isCoinbaseTx && parseFloat(totalOutputValue) < parseFloat(blockRewardMax));
|
||||
|
||||
+summaryRow(2 + (tx.weight ? 1 : 0) + (valueDestroyed ? 1 : 0) + (tx.locktime > 0 ? 1 : 0) + (parseInt(daysDestroyed) > 0 ? 1 : 0))
|
||||
+summaryItem("Version")
|
||||
| #{result.getrawtransaction.version}
|
||||
|
||||
+summaryItem("Size")
|
||||
span #{tx.vsize.toLocaleString()}
|
||||
small.ms-1 vB
|
||||
|
||||
if (tx.weight)
|
||||
+summaryItem("Weight", null, "wu", "Weight Units")
|
||||
span #{tx.weight.toLocaleString()}
|
||||
|
||||
if (valueDestroyed)
|
||||
+summaryItem("Value Destroyed", "The miner of this transaction's block failed to collect this value. As a result, it is permanently lost.")
|
||||
- var currencyValue = new Decimal(blockRewardMax).minus(totalOutputValue);
|
||||
span.text-danger
|
||||
include includes/value-display.pug
|
||||
|
||||
if (tx.locktime > 0)
|
||||
+summaryItem("Locktime")
|
||||
if (tx.locktime < 500000000)
|
||||
span.me-1 Spendable:
|
||||
a(href=`./block-height/${result.getrawtransaction.locktime}`) #{result.getrawtransaction.locktime.toLocaleString()}
|
||||
span +
|
||||
a.ms-2(href="https://developer.bitcoin.org/devguide/transactions.html#locktime-and-sequence-number", data-bs-toggle="tooltip", title="Read more about locktime", target="_blank")
|
||||
i.fas.fa-external-link-alt.small
|
||||
else
|
||||
span Spendable: #{moment.utc(new Date(result.getrawtransaction.locktime * 1000)).format("Y-MM-DD HH:mm:ss")}
|
||||
small.ms-1 utc
|
||||
a.ms-2(href="https://developer.bitcoin.org/devguide/transactions.html#locktime-and-sequence-number", data-bs-toggle="tooltip", title="Read more about locktime", target="_blank")
|
||||
i.fas.fa-external-link-alt.fs-6
|
||||
|
||||
if (parseInt(daysDestroyed) > 0)
|
||||
- var daysDestroyedDesc = `The sum of all input values multiplied by the number of days that input's UTXO existed before being spent. Large values can sometimes be interesting, indicating the spending of long-dormant coins. A 1 ${coinConfig.ticker} UTXO spent after 7 days dormant results in 7 days destroyed, as does a 7 ${coinConfig.ticker} UTXO spent after 1 day dormant.`;
|
||||
|
||||
+summaryItem("Days Destroyed", daysDestroyedDesc, `${coinConfig.ticker.toLowerCase().substring(0, 1)}d`, `${coinConfig.name} Days`)
|
||||
| #{utils.addThousandsSeparators(daysDestroyed.toDP(daysDestroyed > 1 ? 0 : 1))}
|
||||
|
||||
|
||||
|
||||
- var inputsOutputsSectionTitle = `${tx.vin.length.toLocaleString()} Input${tx.vin.length == 1 ? "" : "s"}, ${tx.vout.length.toLocaleString()} Output${tx.vout.length == 1 ? "" : "s"}`;
|
||||
+contentSection(inputsOutputsSectionTitle)
|
||||
- var tx = result.getrawtransaction;
|
||||
- var txInputs = result.txInputs;
|
||||
- var blockHeight = -1;
|
||||
if (result && result.getblock)
|
||||
- blockHeight = result.getblock.height;
|
||||
include includes/transaction-io-details.pug
|
||||
|
||||
- var tx = result.getrawtransaction;
|
||||
- var txInputs = result.txInputs;
|
||||
- var blockHeight = -1;
|
||||
if (result && result.getblock)
|
||||
- blockHeight = result.getblock.height;
|
||||
include includes/transaction-io-details.pug
|
||||
|
||||
if (mempoolDetails)
|
||||
if (mempoolDetails.ancestors.length > 0)
|
||||
|
|
@ -374,86 +257,103 @@ block content
|
|||
li
|
||||
a.font-monospace(href=`./tx/${descendantTxid}`) #{descendantTxid}
|
||||
|
||||
div.tab-pane(id="tab-scripts", role="tabpanel")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-md-3
|
||||
h3.h6.mb-0 Input Scripts
|
||||
hr
|
||||
|
||||
table.table.table-striped
|
||||
thead
|
||||
|
||||
+pageTab("Scripts")
|
||||
+contentSection("Input Scripts")
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th(style="width: 50px;")
|
||||
th Input
|
||||
tbody
|
||||
each vin, vinIndex in result.getrawtransaction.vin
|
||||
tr
|
||||
th(style="width: 50px;")
|
||||
th Script Sig (asm)
|
||||
tbody
|
||||
each vin, vinIndex in result.getrawtransaction.vin
|
||||
tr
|
||||
th.font-monospace
|
||||
a(data-bs-toggle="tooltip", title=`Input #${vinIndex}`, style="white-space: nowrap;")
|
||||
span >
|
||||
span.fw-normal ##{vinIndex.toLocaleString()}
|
||||
th.font-monospace
|
||||
a.badge.card-highlight.border.fw-normal(data-bs-toggle="tooltip", title=`Input #${vinIndex}`, style="white-space: nowrap;")
|
||||
span.me-1 >
|
||||
| #{vinIndex.toLocaleString()}
|
||||
|
||||
td.word-wrap.text-break.font-monospace
|
||||
if (vin.scriptSig && vin.scriptSig.asm)
|
||||
span #{vin.scriptSig.asm}
|
||||
td.word-wrap.text-break.font-monospace
|
||||
if (vin.coinbase)
|
||||
div.font-monospace(style="line-height: 1.75em;")
|
||||
.badge.bg-success.me-2 coinbase
|
||||
br
|
||||
span.font-data #{vin.coinbase}
|
||||
br
|
||||
span.fw-bold.me-2 Ascii
|
||||
span.font-plaintext #{utils.hex2ascii(vin.coinbase)}
|
||||
|
||||
else if (vin.coinbase)
|
||||
div.font-monospace(style="line-height: 1.75em;")
|
||||
small.rounded.bg-primary.text-white.px-2.py-1.me-2 coinbase
|
||||
br
|
||||
span #{vin.coinbase}
|
||||
br
|
||||
span.text-muted (decoded) #{utils.hex2ascii(vin.coinbase)}
|
||||
if (vin.scriptSig && vin.scriptSig.asm)
|
||||
.mb-2
|
||||
.mb-2
|
||||
span.badge.bg-dark.me-2 scriptSig
|
||||
span.font-data #{vin.scriptSig.asm}
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body.px-2.px-md-3
|
||||
h3.h6.mb-0 Output Scripts
|
||||
hr
|
||||
|
||||
table.table.table-striped
|
||||
thead
|
||||
if (vin.txinwitness && vin.txinwitness.length > 0)
|
||||
.mb-2
|
||||
span.badge.bg-dark.me-2 witness
|
||||
each witnessItem in vin.txinwitness
|
||||
span.font-data.me-3 #{witnessItem}
|
||||
|
||||
|
||||
|
||||
|
||||
+contentSection("Output Scripts")
|
||||
table.table.table-borderless.table-striped
|
||||
thead
|
||||
tr
|
||||
th(style="width: 50px;")
|
||||
th Script Pub Key (asm)
|
||||
tbody
|
||||
each vout, voutIndex in result.getrawtransaction.vout
|
||||
tr
|
||||
th(style="width: 50px;")
|
||||
th Script Pub Key (asm)
|
||||
tbody
|
||||
each vout, voutIndex in result.getrawtransaction.vout
|
||||
tr
|
||||
th.font-monospace
|
||||
a(data-bs-toggle="tooltip", title=`Output #${(voutIndex + 1)}`, style="white-space: nowrap;")
|
||||
span <
|
||||
span.fw-normal ##{voutIndex.toLocaleString()}
|
||||
th.font-monospace
|
||||
a.badge.card-highlight.border.fw-normal(data-bs-toggle="tooltip", title=`Output #${(voutIndex + 1)}`, style="white-space: nowrap;")
|
||||
span.me-1 <
|
||||
span.fw-normal #{voutIndex.toLocaleString()}
|
||||
|
||||
td.font-monospace.word-wrap
|
||||
if (vout.scriptPubKey && vout.scriptPubKey.asm)
|
||||
span #{vout.scriptPubKey.asm}
|
||||
if (vout.scriptPubKey.asm.startsWith("OP_RETURN"))
|
||||
br
|
||||
span.text-muted (decoded) #{utils.hex2ascii(vout.scriptPubKey.asm)}
|
||||
td.font-monospace.word-wrap
|
||||
if (vout.scriptPubKey && vout.scriptPubKey.asm)
|
||||
- var chunks = vout.scriptPubKey.asm.split(" ");
|
||||
each chunk in chunks
|
||||
span.me-2
|
||||
if (chunk.startsWith("OP_"))
|
||||
span.badge.bg-primary #{chunk}
|
||||
else
|
||||
span.font-data #{chunk}
|
||||
|
||||
div.tab-pane(id="tab-json", role="tabpanel")
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transaction
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light(data-lang="json") #{JSON.stringify(result.getrawtransaction, null, 4)}
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 UTXOs
|
||||
hr
|
||||
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light(data-lang="json") #{JSON.stringify(utxos, null, 4)}
|
||||
if (vout.scriptPubKey.asm.startsWith("OP_RETURN"))
|
||||
br
|
||||
span.fw-bold.me-2 Ascii
|
||||
span.font-data #{utils.hex2ascii(vout.scriptPubKey.asm)}
|
||||
|
||||
|
||||
+pageTab("JSON")
|
||||
- var pillTabs = ["Transaction", "UTXOs"];
|
||||
if (mempoolDetails)
|
||||
h3.h5 Mempool Details
|
||||
div.highlight
|
||||
pre
|
||||
code.json.bg-light(data-lang="json") #{JSON.stringify(mempoolDetails, null, 4)}
|
||||
- pillTabs.push("Mempool Details");
|
||||
|
||||
+pillTabs(pillTabs)
|
||||
|
||||
.tab-content
|
||||
+pageTab("Transaction", true)
|
||||
+contentSection("Transaction")
|
||||
pre
|
||||
code.text-json.json.bg-body(data-lang="json") #{JSON.stringify(result.getrawtransaction, null, 4)}
|
||||
|
||||
|
||||
+pageTab("UTXOs")
|
||||
+contentSection("UTXOs")
|
||||
pre
|
||||
code.text-json.json.bg-body(data-lang="json") #{JSON.stringify(utxos, null, 4)}
|
||||
|
||||
|
||||
if (mempoolDetails)
|
||||
+pageTab("Mempool Details")
|
||||
+contentSection("Mempool Details")
|
||||
pre
|
||||
code.json.bg-body(data-lang="json") #{JSON.stringify(mempoolDetails, null, 4)}
|
||||
|
||||
//pre #{JSON.stringify(result.txInputs, null, 4)}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,11 @@ block headContent
|
|||
title Transaction Stats
|
||||
|
||||
block content
|
||||
h1.h3 Transaction Stats
|
||||
hr
|
||||
+pageTitle("Transaction Stats")
|
||||
|
||||
if (false)
|
||||
pre
|
||||
code.json.bg-light #{JSON.stringify(txStatResults, null, 4)}
|
||||
code.json #{JSON.stringify(txStatResults, null, 4)}
|
||||
|
||||
if (true)
|
||||
if (false)
|
||||
|
|
@ -18,109 +17,90 @@ block content
|
|||
if (true)
|
||||
div.row
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transactions, 24hr
|
||||
hr
|
||||
+contentSection("1day Transactions")
|
||||
script var txCountDataDay = [];
|
||||
each item, index in txStatsDay.txCounts
|
||||
script txCountDataDay.push({x:#{item.x}, y:#{item.y}});
|
||||
|
||||
script var txCountDataDay = [];
|
||||
each item, index in txStatsDay.txCounts
|
||||
script txCountDataDay.push({x:#{item.x}, y:#{item.y}});
|
||||
- var graphData = {id:"graphDay", dataVar:"txCountDataDay", labels:txStatsDay.txLabels, title:"Transactions, 24hr", xaxisTitle:"Block", xaxisStep:5, yaxisTitle:"Tx Count"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
- var graphData = {id:"graphDay", dataVar:"txCountDataDay", labels:txStatsDay.txLabels, title:"Transactions, 24hr", xaxisTitle:"Block", xaxisStep:5, yaxisTitle:"Tx Count"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transactions, 7day
|
||||
hr
|
||||
+contentSection("7day Transactions")
|
||||
script var txCountDataWeek = [];
|
||||
each item, index in txStatsWeek.txCounts
|
||||
script txCountDataWeek.push({x:#{item.x}, y:#{item.y}});
|
||||
|
||||
script var txCountDataWeek = [];
|
||||
each item, index in txStatsWeek.txCounts
|
||||
script txCountDataWeek.push({x:#{item.x}, y:#{item.y}});
|
||||
|
||||
- var graphData = {id:"graphWeek", dataVar:"txCountDataWeek", labels:txStatsWeek.txLabels, title:"Transactions, 7day", xaxisTitle:"Block", xaxisStep:100, yaxisTitle:"Tx Count"};
|
||||
include ./includes/line-graph.pug
|
||||
- var graphData = {id:"graphWeek", dataVar:"txCountDataWeek", labels:txStatsWeek.txLabels, title:"Transactions, 7day", xaxisTitle:"Block", xaxisStep:100, yaxisTitle:"Tx Count"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transactions, 30day
|
||||
hr
|
||||
+contentSection("30day Transactions")
|
||||
script var txCountDataMonth = [];
|
||||
each item, index in txStatsMonth.txCounts
|
||||
script txCountDataMonth.push({x:#{item.x}, y:#{item.y}});
|
||||
|
||||
script var txCountDataMonth = [];
|
||||
each item, index in txStatsMonth.txCounts
|
||||
script txCountDataMonth.push({x:#{item.x}, y:#{item.y}});
|
||||
|
||||
- var graphData = {id:"graphMonth", dataVar:"txCountDataMonth", labels:txStatsMonth.txLabels, title:"Transactions, 30day", xaxisTitle:"Block", xaxisStep:500, yaxisTitle:"Tx Count"};
|
||||
include ./includes/line-graph.pug
|
||||
- var graphData = {id:"graphMonth", dataVar:"txCountDataMonth", labels:txStatsMonth.txLabels, title:"Transactions, 30day", xaxisTitle:"Block", xaxisStep:500, yaxisTitle:"Tx Count"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Transactions, All time
|
||||
hr
|
||||
+contentSection("All-Time Transactions")
|
||||
script var txCountDataAlltime = [];
|
||||
each item, index in txStats.txCounts
|
||||
script txCountDataAlltime.push({x:#{item.x}, y:#{item.y}});
|
||||
|
||||
script var txCountDataAlltime = [];
|
||||
each item, index in txStats.txCounts
|
||||
script txCountDataAlltime.push({x:#{item.x}, y:#{item.y}});
|
||||
- var graphData = {id:"graphAlltime", dataVar:"txCountDataAlltime", labels:txStatsMonth.txLabels, title:"Transactions, All time", xaxisTitle:"Block", xaxisStep:500, yaxisTitle:"Tx Count"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
- var graphData = {id:"graphAlltime", dataVar:"txCountDataAlltime", labels:txStatsMonth.txLabels, title:"Transactions, All time", xaxisTitle:"Block", xaxisStep:500, yaxisTitle:"Tx Count"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
|
||||
div.row
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Tx Rate, 24hr
|
||||
hr
|
||||
+contentSection("1day Tx Rate")
|
||||
script var txRateDataDay = [];
|
||||
each item, index in txStatsDay.txRates
|
||||
script txRateDataDay.push({x:#{item.x}, y:#{item.y}});
|
||||
|
||||
script var txRateDataDay = [];
|
||||
each item, index in txStatsDay.txRates
|
||||
script txRateDataDay.push({x:#{item.x}, y:#{item.y}});
|
||||
- var graphData = {id:"graphRateDay", dataVar:"txRateDataDay", labels:txStatsDay.txLabels, title:"Tx Rate, 24hr", xaxisTitle:"Block", xaxisStep:5, yaxisTitle:"Tx Per Sec"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
- var graphData = {id:"graphRateDay", dataVar:"txRateDataDay", labels:txStatsDay.txLabels, title:"Tx Rate, 24hr", xaxisTitle:"Block", xaxisStep:5, yaxisTitle:"Tx Per Sec"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Tx Rate, 7day
|
||||
hr
|
||||
+contentSection("7day Tx Rate")
|
||||
script var txRateDataWeek = [];
|
||||
each item, index in txStatsWeek.txRates
|
||||
script txRateDataWeek.push({x:#{item.x}, y:#{item.y}});
|
||||
|
||||
script var txRateDataWeek = [];
|
||||
each item, index in txStatsWeek.txRates
|
||||
script txRateDataWeek.push({x:#{item.x}, y:#{item.y}});
|
||||
- var graphData = {id:"graphRateWeek", dataVar:"txRateDataWeek", labels:txStatsWeek.txLabels, title:"Tx Rate, 7day", xaxisTitle:"Block", xaxisStep:100, yaxisTitle:"Tx Per Sec"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
- var graphData = {id:"graphRateWeek", dataVar:"txRateDataWeek", labels:txStatsWeek.txLabels, title:"Tx Rate, 7day", xaxisTitle:"Block", xaxisStep:100, yaxisTitle:"Tx Per Sec"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Tx Rate, 30day
|
||||
hr
|
||||
+contentSection("30day Tx Rate")
|
||||
script var txRateDataMonth = [];
|
||||
each item, index in txStatsMonth.txRates
|
||||
script txRateDataMonth.push({x:#{item.x}, y:#{item.y}});
|
||||
|
||||
script var txRateDataMonth = [];
|
||||
each item, index in txStatsMonth.txRates
|
||||
script txRateDataMonth.push({x:#{item.x}, y:#{item.y}});
|
||||
- var graphData = {id:"graphRateMonth", dataVar:"txRateDataMonth", labels:txStatsMonth.txLabels, title:"Tx Rate, 30day", xaxisTitle:"Block", xaxisStep:500, yaxisTitle:"Tx Per Sec"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
- var graphData = {id:"graphRateMonth", dataVar:"txRateDataMonth", labels:txStatsMonth.txLabels, title:"Tx Rate, 30day", xaxisTitle:"Block", xaxisStep:500, yaxisTitle:"Tx Per Sec"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
|
||||
div.col-lg-6
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0 Tx Rate, All time
|
||||
hr
|
||||
+contentSection("All-Time Tx Rate")
|
||||
script var txRateDataAlltime = [];
|
||||
each item, index in txStats.txRates
|
||||
script txRateDataAlltime.push({x:#{item.x}, y:#{item.y}});
|
||||
|
||||
- var graphData = {id:"graphRateAlltime", dataVar:"txRateDataAlltime", labels:txStatsMonth.txLabels, title:"Tx Rate, All time", xaxisTitle:"Block", xaxisStep:500, yaxisTitle:"Tx Per Sec"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
script var txRateDataAlltime = [];
|
||||
each item, index in txStats.txRates
|
||||
script txRateDataAlltime.push({x:#{item.x}, y:#{item.y}});
|
||||
|
||||
- var graphData = {id:"graphRateAlltime", dataVar:"txRateDataAlltime", labels:txStatsMonth.txLabels, title:"Tx Rate, All time", xaxisTitle:"Block", xaxisStep:500, yaxisTitle:"Tx Per Sec"};
|
||||
include ./includes/line-graph.pug
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
extends layout
|
||||
|
||||
block headContent
|
||||
title Unconfirmed Transactions
|
||||
|
||||
block content
|
||||
h1.h3 Unconfirmed Transactions
|
||||
hr
|
||||
|
||||
if (false)
|
||||
pre
|
||||
code #{JSON.stringify(mempoolDetails.txCount, null, 4)}
|
||||
|
||||
if (mempoolDetails)
|
||||
- var txCount = mempoolDetails.txCount;
|
||||
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-body
|
||||
h3.h6.mb-0
|
||||
if (txCount == 1)
|
||||
span 1 Transaction
|
||||
else
|
||||
span #{txCount.toLocaleString()} Transactions
|
||||
|
||||
hr
|
||||
|
||||
each tx, txIndex in mempoolDetails.transactions
|
||||
div.card.shadow-sm.mb-3
|
||||
div.card-header.font-monospace
|
||||
if (tx && tx.txid)
|
||||
span ##{(txIndex + offset).toLocaleString()}
|
||||
span –
|
||||
a(href=`./tx/${tx.txid}`) #{tx.txid}
|
||||
|
||||
div.card-body
|
||||
- var txInputs = mempoolDetails.txInputsByTransaction[tx.txid];
|
||||
- var blockHeight = -1;
|
||||
|
||||
include includes/transaction-io-details.pug
|
||||
|
||||
if (txCount > limit)
|
||||
- var pageNumber = offset / limit + 1;
|
||||
- var pageCount = Math.floor(txCount / limit);
|
||||
- if (pageCount * limit < txCount) {
|
||||
- pageCount++;
|
||||
- }
|
||||
- var paginationUrlFunction = function(x) {
|
||||
- return paginationBaseUrl + "?limit=" + limit + "&offset=" + ((x - 1) * limit + "&sort=" + sort);
|
||||
- }
|
||||
|
||||
hr
|
||||
|
||||
include includes/pagination.pug
|
||||
else
|
||||
p No unconfirmed transactions found
|
||||