-more styling tweaks/cleanup/consistency

-new fun item showing example of future-dated timelock (coinbase) tx
-special-case code for mainnet genesis coinbase tx, to avoid indicating that satoshi spent these unspendable coins
-tx details: skip displaying locktime when it's meaningless (the raw data is in the json if anyone wants it); show additional info about locktime meaning
-tx details: show byte-size in addition to vByte size, if applicable
-fix for recently broken donut chart on /mining-summary
-changelog
This commit is contained in:
Dan Janosik 2021-12-06 16:43:10 -05:00
parent 599412e688
commit a678c8a6a9
No known key found for this signature in database
GPG key ID: 70C0B166321C0AF8
28 changed files with 306 additions and 209 deletions

1
.gitignore vendored
View file

@ -60,3 +60,4 @@ typings/
# cache dir
cache/
*.css.map

View file

@ -27,6 +27,7 @@
* BTCEXP_UI_TIMEZONE (utc,local)
* BTCEXP_UI_HIDE_INFO_PANELS (true,false)
* Support for displaying timestamps in local timezone (by using browser default, or setting a manual offset)
* Cleanup treatment of `locktime` on transaction details pages
* Unique favicon color based on the active network (mainnet=orange, testnet=green, signet=magenta, regtest=gray)
* Lots of minor styling improvements
* Error handling improvements

17
TODO.md
View file

@ -1,8 +1,9 @@
MAIN
-look at mempool caching on slow devices
-24hr comparisons for exchange rate/gold rate?
-speed up /diff-hist like /mempool-summ and cache
-/mempool-summary: more granular fee rate bar chart; add line graph on top of bar chart for cumulative blocks
-projected blocks (on homepage, and own tool)
-incoming tx page (live)
-electron: https://gist.github.com/maximilian-lindsey/a446a7ee87838a62099d
* moment -> luxon :/
* value-validation in /changeSetting (like is currently done for userTzOffset)
* 24hr comparisons for exchange rate/gold rate?
* /mempool-summary: more granular fee rate bar chart; add line graph on top of bar chart for cumulative blocks
* incoming tx page (live)
* electron: https://gist.github.com/maximilian-lindsey/a446a7ee87838a62099d
* use flex utilities for "summary rows"?

View file

@ -431,6 +431,15 @@ module.exports = {
alertBodyHtml: "Created LONG before Taproot lock-in, let alone activation, this transaction's #0 output is the first ever P2TR output. It was created by Matthew Zipkin to test sending support for bech32 witness version 1. Interestingly, this output, along with 3 other pre-Activation P2TR outputs, was also SPENT before activation, via special coordination with F2Pool.",
referenceUrl: "https://b10c.me/blog/007-spending-p2tr-pre-activation/"
},
{
type: "tx",
date: "2021-12-06",
chain: "main",
txid: "562ff53512901dfdd0fca0d6b6a79444aad5767db716ece7c0a1bd15482b6384",
blockHeight: 712928,
summary: "Far-future dated Locktime value.",
alertBodyHtml: "The 'locktime' value of a transaction usually specifies the earliest time that a transaction may be mined (included in a block). The value can take one of two forms: a block height (if the value is ≤ 500M), or a unix timestamp. The locktime value of this transaction seemingly indicates that the transaction cannot be mined until the year 2076. But, because this is a coinbase transaction (created by a miner in the process of mining a block), its locktime value does not need to honor the usual purpose, and may instead be representing some other data from the miner. This situation arises fairly regularly in coinbase transactions."
},

View file

@ -1,5 +1,5 @@
$body-bg: #051c3e;
$body-color: #f5f7f7;
$body-color: #f7fafa;
$main-bg: darken($body-bg, 6%);
@ -137,18 +137,32 @@ $toast-header-border-color: rgba(0, 0, 0, .05) !default;
background-color: $main-bg !important;
}
$header-footer-bg: #112138;
.bg-header-footer {
background-color: #162740 !important;
background-color: $header-footer-bg !important;
}
.bg-header-footer-highlight {
background-color: lighten(#162740, 15%) !important;
background-color: lighten($header-footer-bg, 12%) !important;
}
.bg-gradient-body-to-main {
background: linear-gradient(0deg, $main-bg 0%, $body-bg 100%);
}
.bg-card-highlight-badge {
background-color: $body-bg !important;
}
.bg-tx-separator {
background-color: #131a24;
}
.border-card-highlight-badge {
border-color: #183662 !important;
}
.border-dark {
border-color: lighten($dark, 8%) !important;
}

View file

@ -19,12 +19,15 @@ $alert-border-scale: -60%;
$table-striped-bg: rgba(0, 0, 0, 0.04);
@import "./main";
.bg-main {
background-color: $main-bg !important;
}
@ -49,6 +52,18 @@ $alert-border-scale: -60%;
background: linear-gradient(0deg, $main-bg 0%, $body-bg 100%);
}
.bg-card-highlight-badge {
background-color: darken($card-bg, 10%) !important;
}
.bg-tx-separator {
background-color: #dce1e5;
}
.border-card-highlight-badge {
border-color: darken($card-bg, 16%) !important;
}
.text-card-highlight {
color: $card-highlight-color !important;
}

View file

@ -77,6 +77,11 @@ $dropdown-min-width: 11rem;
@import "../../node_modules/bootstrap/scss/bootstrap";
.table > :not(:first-child) {
border-top: 0px;
}
.bg-content {
background-color: $body-bg !important;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -9,6 +9,7 @@
* Holidays
* Genesis Day
* Pizza Day
* https://twitter.com/nvk/status/1463857031551541260
* Countdown to halving
* Countdown to difficulty change
* Historical mining config:
@ -31,4 +32,4 @@
* cache miner data on /mining-summary page, so subsequent runs are super fast (tiny amt of data to cache)
* UTXO status on outputs on all txLists (transaction page is done, need to add block page, address page, test/tx-list page)
* UTXO status on outputs on all txLists (transaction page is done, need to add block page, address page, test/tx-list page)

View file

@ -1,6 +1,6 @@
mixin adminNav
.card.mb-3.mt-n3.p-0
nav.navbar.navbar-expand.p-0
.card.mb-3.mt-n2.p-0
nav.navbar.navbar-expand.p-1
.container-fluid
.collapse.navbar-collapse
ul.navbar-nav

View file

@ -16,9 +16,6 @@ block content
.tab-content
+pageTab("Details", true)
+contentSection("Tools")
a.btn.btn-primary(href="./admin/resetUserSettings") Reset User Settings
+contentSection("Basics")
+summaryRow(3)
+summaryItem("Uptime")
@ -31,10 +28,6 @@ block content
+summaryItem("Node Env")
| #{process.env.NODE_ENV || "development"}
+contentSection("User Settings")
pre
code.json #{JSON.stringify(userSettings, null, 4)}
+contentSection("App Config")
pre
code.json #{JSON.stringify(appConfig, null, 4)}

View file

@ -65,8 +65,8 @@ block content
table.table.table-striped.table-borderless.mb-0
thead
tr
th Transaction
th.text-end Output Value
th.text-card-highlight.text-uppercase.fw-light Transaction
th.text-end.text-card-highlight.text-uppercase.fw-light Output Value
tbody(id="tbody-top-value-tx")
tr.row-prototype(style="display: none;")
@ -81,9 +81,10 @@ block content
table.table.table-striped.table-borderless.mb-0
thead
tr
th Transaction
th.text-end Size
small.fw-normal.text-muted.ms-2 (vB)
th.text-card-highlight.text-uppercase.fw-light Transaction
th.text-end.text-card-highlight.fw-light
span.text-uppercase Size
small.ms-2 (vB)
tbody(id="tbody-top-size-tx")
tr.row-prototype(style="display: none;")
@ -100,8 +101,8 @@ block content
table.table.table-striped.table-borderless.mb-0
thead
tr
th Transaction
th.text-end Fee
th.text-card-highlight.text-uppercase.fw-light Transaction
th.text-end.text-card-highlight.text-uppercase.fw-light Fee
tbody(id="tbody-top-fee-tx")
tr.row-prototype(style="display: none;")
@ -117,9 +118,10 @@ block content
table.table.table-striped.table-borderless.mb-0
thead
tr
th Transaction
th.text-end Fee Rate
small.text-muted.fw-normal.ms-2 (sat/vB)
th.text-card-highlight.text-uppercase.fw-light Transaction
th.text-end.text-card-highlight.fw-light
span.text-uppercase Fee Rate
small.ms-2 (sat/vB)
tbody(id="tbody-top-fee-rate-tx")
tr.row-prototype(style="display: none;")

View file

@ -34,7 +34,7 @@ block content
hr
div.mb-2
span.border-dotted(title="Select the list of graphs to be displayed.", data-bs-toggle="tooltip") Active Graphs
span.border-dotted.text-card-highlight.text-uppercase.fw-light(title="Select the list of graphs to be displayed.", data-bs-toggle="tooltip") Active Graphs
.clearfix
each graphId, graphIndex in graphIds

View file

@ -24,7 +24,7 @@ block content
if (result.getblock.tx != null && result.getblock.tx.length > 0)
a.btn.btn-secondary.btn-sm.ms-4(href=`./block-analysis/${result.getblock.hash}`, title="See a summary analysis of all transactions in this block.", data-bs-toggle="tooltip")
a.btn.btn-primary.btn-sm.ms-4(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

View file

@ -69,15 +69,16 @@ block content
table.table.table-striped.table-borderless.mb-3
thead
tr
th.text-end Epoch
th.text-end Start Block
th.text-end Start Date
small.text-muted.ms-1.fw-light (utc)
th.text-end.text-card-highlight.text-uppercase.fw-light Epoch
th.text-end.text-card-highlight.text-uppercase.fw-light Start Block
th.text-end.text-card-highlight.fw-light
span.text-uppercase Start Date
small.ms-1 (utc)
//th Date
//th.text-end Block Start
th.text-end Difficulty
th.text-end Difficulty Δ
small.text-muted.ms-1.fw-light (%)
th.text-end.text-card-highlight.text-uppercase.fw-light Difficulty
th.text-end.text-card-highlight.text-uppercase.fw-light Difficulty Δ
small.ms-1 (%)
tbody(id="difficulty-table-body")
tr(id="difficulty-table-row-prototype", style="display: none;")

View file

@ -22,9 +22,9 @@ block content
table.table.table-borderless.table-striped
thead
tr
th Date
th Item
th Reference
th.text-card-highlight.text-uppercase.fw-light Date
th.text-card-highlight.text-uppercase.fw-light Item
th.text-card-highlight.text-uppercase.fw-light Reference
tbody
each item, index in coinConfig.historicalData
if (item.chain == activeBlockchain)

View file

@ -4,41 +4,41 @@
tr
//th
th.text-end Height
th.text-end.text-card-highlight.fw-normal.text-uppercase Height
//if (!hideTimestampColumn)
th.text-end.d-none.d-md-table-cell
th.text-end.text-card-highlight.fw-normal.text-uppercase.d-none.d-md-table-cell
span.border-dotted(title="Timestamp of the block.", data-bs-toggle="tooltip") Time
th.text-end Age
th.text-end.text-card-highlight.fw-normal.text-uppercase Age
th.text-end.d-none.d-sm-table-cell
th.text-end.text-card-highlight.fw-normal.text-uppercase.d-none.d-sm-table-cell
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.text-start Miner
th.text-end
th.text-start.text-card-highlight.fw-normal.text-uppercase Miner
th.text-end.text-card-highlight.fw-normal.text-uppercase
span.border-dotted(title="The number of transactions included in each block.", data-bs-toggle="tooltip") N(tx)
if (blockstatsByHeight)
th.text-end.d-none.d-lg-table-cell
th.text-end.text-card-highlight.fw-normal.text-uppercase.d-none.d-lg-table-cell
span.border-dotted(title="The total output of all transactions in each block.", data-bs-toggle="tooltip") Volume
if (blockstatsByHeight)
th.text-end.d-none.d-md-table-cell
th.text-end.text-card-highlight.fw-normal.text-uppercase.d-none.d-md-table-cell
span.border-dotted(title="The min/avg/max fee rates (sat/vB) for transactions in this block.", data-bs-toggle="tooltip") Fee Rates
else
th.text-end
th.text-end.text-card-highlight.fw-normal.text-uppercase
span.border-dotted(title="The average fee (sat/vB) for all block transactions.", data-bs-toggle="tooltip") Avg Fee
th.text-end.d-none.d-lg-table-cell Σ Fees
th.text-end.text-card-highlight.fw-normal.text-uppercase.d-none.d-lg-table-cell Σ Fees
//th.text-end Size (kB)
if (blocks && blocks.length > 0 && blocks[0].weight)
th.text-end.d-none.d-lg-table-cell % Full
th.text-end.text-card-highlight.fw-normal.text-uppercase.d-none.d-lg-table-cell % Full
else
th.text-end.d-none.d-lg-table-cell Size
th.text-end.text-card-highlight.fw-normal.text-uppercase.d-none.d-lg-table-cell Size
small (kB)
tbody

View file

@ -78,24 +78,21 @@ if (exchangeRates)
- var hashrate7dayData = utils.formatLargeNumber(hashrate7d, 1);
span.me-1 #{hashrate7dayData[0]}
small.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
span.small.text-muted.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 (new Decimal(ratio).toDP(1) == "1")
span.text-muted +0%
else if (ratio > 1)
if (ratio > 1)
- var ratioPercent = new Decimal(ratio).times(100).minus(100);
span.text-success +#{ratioPercent.toDP(1)}%
span.text-success +#{ratioPercent.toDP(2)}%
else
- var ratioPercent = new Decimal(100).minus(new Decimal(ratio).times(100));
span.text-danger -#{ratioPercent.toDP(1)}%
span.text-danger -#{ratioPercent.toDP(2)}%
| )
@ -163,13 +160,20 @@ if (exchangeRates)
- smartFeeEstimateBlocks.push(144);
- smartFeeEstimateStrings.push(smartFeeEstimates[144]);
+summaryRow((mempoolInfo == undefined ? 0 : 2) + (smartFeeEstimateStrings.length > 0 ? 1 : 0))
+summaryRow((mempoolInfo == undefined ? 0 : 1) + (smartFeeEstimateStrings.length > 0 ? 1 : 0))
if (mempoolInfo)
+summaryItem("Mempool N(Tx)", "The number of unconfirmed transactions in your node's mempool")
span(class=(mempoolInfo.size > 11000) ? "text-danger" : (mempoolInfo.size > 7000 ? "text-warning" : "text-success")) #{mempoolInfo.size.toLocaleString()}
- var thresholds = [11000, 7000];
- var colorClass = (mempoolInfo.size > 11000) ? "text-danger" : (mempoolInfo.size > 7000 ? "text-warning" : "text-success");
+summaryItem("Mempool", "The number of unconfirmed transactions in your node's mempool, and the number of blocks needed to confirm those transactions")
span(class=colorClass) #{mempoolInfo.size.toLocaleString()}
span.text-tiny.text-muted.ms-1 tx
span.fw-light.text-muted.mx-2 &ndash;
span(class=colorClass) #{new Decimal(mempoolInfo.bytes / coinConfig.maxBlockSize).toDP(2)}
span.text-tiny.text-muted.ms-1 block
+summaryItem("Mempool N(Block)", "The number of blocks needed to confirm all mempool transactions")
| #{new Decimal(mempoolInfo.bytes / coinConfig.maxBlockSize).toDP(1)}
if (false)
+summaryItem("Next Block (est.)")

View file

@ -1,6 +1,6 @@
mixin themeCss
link(id="light-theme-link-tag", rel="stylesheet", href=`./style/light.css?v=${cacheId}`, integrity="sha384-PIEdZ5ZghkulWtuedysHXrLithKg0Cf8CNyi1VZFeLghI3x2KiIcBUXj2ZlmHmeq")
link(id="dark-theme-link-tag", rel=(userSettings.uiTheme == "dark" ? "stylesheet" : false), href=`./style/dark.css?v=${cacheId}`, integrity="sha384-ox1rEDWY1FjZnNlAWpElsdN71dPIkCcHnCYtcPF9Be7qYp6NnWLDvIZUaGFN7cvU")
link(id="light-theme-link-tag", rel="stylesheet", href=`./style/light.css?v=${cacheId}`, integrity="sha384-G+XehzyDofsc9ZlqIF7hYXsaYijKshaTro74HxGnvEmvNiv2lRjGxO8g8HShNBQG")
link(id="dark-theme-link-tag", rel=(userSettings.uiTheme == "dark" ? "stylesheet" : false), href=`./style/dark.css?v=${cacheId}`, integrity="sha384-xjIBl325k0VYsT0wAem/8jzIxea9FDLsVmHZG8STGMhLu+rDq/xlWxo/iR6oJQ6w")
mixin sharedScriptTags
@ -86,7 +86,7 @@ mixin summaryRow(itemCount)
mixin summaryTitle(title, titleDesc, subtitle, subtitleDesc)
span.fs-6.text-uppercase.fw-light.text-muted.text-card-highlight(class=(titleDesc ? "border-dotted" : false), class=(subtitle ? "me-2" : false), title=titleDesc, data-bs-toggle="tooltip", data-bs-html="true") #{title}
span.fs-6.text-uppercase.fw-light.text-card-highlight(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-card-highlight.fw-light
| (
@ -127,7 +127,8 @@ mixin txList(visibleTxs, txCount, limit, offset, inputsByTxid, options={})
+pagination(limit, offset, null, txCount, paginationBaseUrl)
.mb-4.mb-md-3
//.mb-4.mb-md-3
.pb-4.pb-md-3.bg-tx-separator
each tx, txIndex in visibleTxs
@ -247,7 +248,7 @@ mixin txList(visibleTxs, txCount, limit, offset, inputsByTxid, options={})
include ./transaction-io-details.pug
if (txIndex < (visibleTxs.length - 1) || txCount > limit)
.mb-4.mb-lg-3
.pb-4.pb-md-3.bg-tx-separator
if (txCount > limit && !options.hidePagination)
@ -420,8 +421,10 @@ mixin confirmations(confirmations, abbreviated=true)
mixin dataEncodingBadge(encodingType)
span.small.badge.bg-dark.text-light.border.border-dark.mb-tiny.me-1 #{encodingType}
mixin cardHighlightBadge(text)
span.small.badge.bg-card-highlight-badge.border.border-card-highlight-badge.text-reset.mb-tiny.me-1 #{text ? text : ""}
if (block)
block
@ -429,31 +432,30 @@ mixin hexDataDisplay(hex, order="utf8,ascii,hex")
- var items = order.split(",");
- var uniqueId = utils.getRandomString(12, "aA");
div
.d-inline-block.small.border.rounded-1.p-1.px-2.card-highlight.word-wrap
+dataEncodingBadge(items[0])
span #{utils.formatHex(hex, items[0])}
.d-inline-block.small.border.rounded-1.p-1.px-2.card-highlight.word-wrap
+cardHighlightBadge(items[0])
span.small #{utils.formatHex(hex, items[0])}
if (items[0] == "hex")
.d-none.d-md-inline
+copyTextButton(hex)
+copyTextButton(hex)
div(id=`hex-display-expanded-${uniqueId}`, style="display: none;")
each item, itemIndex in items
if (itemIndex > 0)
if (itemIndex > 1)
br
+cardHighlightBadge(item)
span.small #{utils.formatHex(hex, item)}
if (item == "hex")
.d-inline.d-md-inline
+copyTextButton(hex)
a.text-muted.ms-2(href="javascript:void(0)", onclick=`$('#hex-display-expanded-${uniqueId}').toggle(); $(this).find(".toggle-plus-minus").toggleClass("fa-plus-square"); $(this).find(".toggle-plus-minus").toggleClass("fa-minus-square"); return false;`, title="Toggle More Encodings")
i.toggle-plus-minus.far.fa-plus-square.text-card-highlight
div(id=`hex-display-expanded-${uniqueId}`, style="display: none;")
each item, itemIndex in items
if (itemIndex > 0)
if (itemIndex > 1)
br
.d-inline-block.small.border.rounded-1.p-1.px-2.mt-2.word-wrap.card-highlight
+dataEncodingBadge(item)
span #{utils.formatHex(hex, item)}
a.text-muted.ms-2(href="javascript:void(0)", onclick=`$('#hex-display-expanded-${uniqueId}').toggle(); $(this).find(".toggle-plus-minus").toggleClass("fa-plus-square"); $(this).find(".toggle-plus-minus").toggleClass("fa-minus-square"); return false;`, title="Toggle More Encodings")
i.toggle-plus-minus.far.fa-plus-square.text-card-highlight
if (false)
.d-inline-block.small.border.rounded-1.p-1.px-2.mt-2.word-wrap.card-highlight
+dataEncodingBadge("hex")
span #{hex}
mixin timestamp(timestamp, includeAgo=true, formatString)
@ -514,9 +516,18 @@ mixin timestamp(timestamp, includeAgo=true, formatString)
span #{momentObj.format("YYYY-MM-DD")}
if (includeAgo)
small.text-muted.ms-2 (
+timeAgo(timestamp, true)
span ago)
- var timeAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date(parseInt(timestamp) * 1000))));
if (timeAgo.asSeconds() < 0)
- timeAgo = moment.duration(moment.utc(new Date(parseInt(timestamp) * 1000)).diff(moment.utc(new Date())));
small.text-muted.ms-2 (+
| #{timeAgo.format()}
span )
else
small.text-muted.ms-2 (
+timeAgo(timestamp, true)
span ago)
mixin darkBadge(text)
@ -738,7 +749,7 @@ mixin blockRangeFilters
.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
span.border-dotted.text-uppercase.fw-light.text-card-highlight(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
@ -748,7 +759,7 @@ mixin blockRangeFilters
.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
span.border-dotted.text-uppercase.fw-light.text-card-highlight(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
@ -762,7 +773,7 @@ mixin blockRangeFilters
.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
span.border-dotted.text-uppercase.fw-light.text-card-highlight(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

View file

@ -21,7 +21,7 @@ mixin inputValueDisplay(tx, txVin, vout)
i.fas.fa-backspace.text-danger
mixin outputValueDisplay(vout, voutIndex)
mixin outputValueDisplay(tx, vout, voutIndex)
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
@ -37,8 +37,13 @@ mixin outputValueDisplay(vout, voutIndex)
i.far.fa-check-circle.fa-sm.text-success.ms-2
else if (utxos[voutIndex] == null)
span(title="This output has been spent (destroyed)." data-bs-toggle="tooltip")
i.far.fa-times-circle.fa-sm.text-danger.ms-2
if (tx.txid == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")
span(title="This output is UNSPENDABLE, and therefore these coins do not exist!" data-bs-toggle="tooltip")
i.fas.fa-flag.fa-sm.text-warning.ms-2
else
span(title="This output has been spent (destroyed)." data-bs-toggle="tooltip")
i.far.fa-times-circle.fa-sm.text-danger.ms-2
.row
@ -88,7 +93,7 @@ mixin outputValueDisplay(vout, voutIndex)
+hexDataDisplay(txVin.coinbase)
// xs only
.d-inline-block.d-sm-none.small.border.rounded-1.px-1.card-highlight.ms-3.mt-1
.d-inline-block.d-sm-none.small.border.rounded-1.px-1.card-highlight.mt-1
span.text-tiny.fw-light #{utils.formatHex(txVin.coinbase, "utf8")}
@ -246,7 +251,6 @@ mixin outputValueDisplay(vout, voutIndex)
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")
+darkBadge("SegWit")
i.fas.fa-flag.fa-sm.ms-1
i.fas.fa-external-link-alt.fa-sm.ms-1
.my-2.d-none.d-md-block
@ -273,7 +277,7 @@ mixin outputValueDisplay(vout, voutIndex)
span.small.xs-only.d-inline.d-sm-none
+primaryBadge("OP_RETURN")
.xs-sm.d-inline-block.d-md-none.small.border.rounded-1.px-1.card-highlight.ms-3.mt-1
.xs-sm.d-inline-block.d-md-none.small.border.rounded-1.px-1.card-highlight.mt-1
- var asm = vout.scriptPubKey.asm.substring("OP_RETURN ".length);
span.text-tiny.fw-light #{utils.formatHex(asm, "utf8")}
@ -284,7 +288,7 @@ mixin outputValueDisplay(vout, voutIndex)
span.ms-2.float-end
+outputValueDisplay(vout, voutIndex)
+outputValueDisplay(tx, vout, voutIndex)
if (vout && vout.scriptPubKey.asm && !vout.scriptPubKey.asm.startsWith("OP_RETURN "))
if (voutAddresses.length == 0)

View file

@ -79,13 +79,13 @@ block content
pre
code.json #{JSON.stringify(nextBlockFeeRateGroups, null, 4)}
.d-flex.flex-row
.d-flex.justify-content-between
div
- var desc = "Prediction for the next block, based on the output of the getblocktemplate command";
+sectionTitle("Predicted Next Block", false, null, null, null, desc)
div
a.ms-2(href="./mining-template") See details
a.small.ms-2(href="./mining-template") Next block details &raquo;
#index-next-block
+contentSection
@ -121,21 +121,18 @@ block content
if (latestBlocks)
+contentSection("Latest Blocks")
.d-flex.justify-content-between
div
+sectionTitle("Latest Blocks")
div
a.small.ms-2(href="./blocks") Browse blocks &raquo;
+contentSection
- var blocks = latestBlocks;
- var blockOffset = 0;
include includes/blocks-list.pug
if (blocks.length % 2 == 1)
hr
else
.mb-2
.text-center.pt-1
a.btn.btn-primary.btn-sm(href="./blocks")
i.fas.fa-cubes.me-2
| Browse Blocks &raquo;
+contentSection("Tools")

View file

@ -50,8 +50,9 @@ block content
.clearfix
.float-start
.me-4.d-inline-block.mb-3
h6 Fee Rate
small.fw-light.ms-1 (sat/vB)
h6.text-card-highlight.fw-light
span.text-uppercase Fee Rate
small.ms-1 (sat/vB)
- var feeRatesToEstimate = [1, 2, 3, 4, 5, 15, 25, 50, 75, 100, 150];
@ -60,7 +61,7 @@ block content
a.btn.btn-outline-primary.fee-rate-btn(href="javascript:void(0)", onclick=`estimateMempoolDepth(parseInt($(this).attr("data-fee-rate"))); return false;`, data-fee-rate=feeRateToEstimate) #{feeRateToEstimate}
.me-4.d-inline-block.mb-3
h6 Transaction ID
h6.text-card-highlight.text-uppercase.fw-light Transaction ID
form.form-inline(method="post", action="javascript:void(0)", onsubmit=`estimateTransactionMempoolDepth($("#mempoolquery").val()); return false;` style="width: 325px;")
.input-group.input-group
@ -70,8 +71,9 @@ block content
i.fas.fa-search
.me-4.d-inline-block.mb-3
h6 Custom Fee Rate
small.fw-light.ms-1 (sat/vB)
h6.text-card-highlight.fw-light
span.text-uppercase Custom Fee Rate
small.ms-1 (sat/vB)
form.form-inline(method="post", action="javascript:void(0)", onsubmit=`estimateMempoolDepth($("#customFeeRate").val()); return false;` style="width: 200px;")
.input-group.input-group
@ -104,17 +106,18 @@ block content
table.table.table-striped.table-borderless.mb-3
thead
tr
th Fee Rate
th.text-end N(tx)
th.text-end
th.text-card-highlight.text-uppercase.fw-light Fee Rate
th.text-end.text-card-highlight.text-uppercase.fw-light N(tx)
th.text-end.text-card-highlight.text-uppercase.fw-light
span.border-dotted(title="The number of blocks filled by all transactions in this fee-rate bucket.", data-bs-toggle="tooltip") N(blocks)
th.text-end
th.text-end.text-card-highlight.text-uppercase.fw-light
span.border-dotted(title="The running total of the number of blocks filled by transactions at this fee-rate and higher.", data-bs-toggle="tooltip") Σ N(blocks)
th.text-end Σ Fees
th.text-end Avg Fee
th.text-end Avg Fee Rate
small.fw-normal.text-muted.ms-2 (sat/vB)
th.text-end.text-card-highlight.text-uppercase.fw-light Σ Fees
th.text-end.text-card-highlight.text-uppercase.fw-light Avg Fee
th.text-end.text-card-highlight.fw-light
span.text-uppercase Avg Fee Rate
small.ms-1 (sat/vB)
tbody(id="fee-rate-table-body")
tr(id="fee-rate-table-row-prototype", style="display: none;")
td.data-label
@ -144,8 +147,10 @@ block content
table.table.table-striped.table-borderless.mb-3
thead
tr
th Txid
th.text-end Fee Rate (sat/vB)
th.text-card-highlight.text-uppercase.fw-light Txid
th.text-end.text-card-highlight.fw-light
span.text-uppercase Fee Rate
span.ms-2 (sat/vB)
tbody(id="topfee-tx-table-body")
tr(id="topfee-tx-table-row-prototype", style="display: none;")
@ -160,8 +165,8 @@ block content
table.table.table-striped.table-borderless.mb-3
thead
tr
th Txid
th.text-end
th.text-card-highlight.text-uppercase.fw-light Txid
th.text-end.text-card-highlight.text-uppercase.fw-light
span.border-dotted(title="How long ago this transaction was first seen by your node.", data-bs-toggle="tooltip")
| Age
@ -178,8 +183,8 @@ block content
table.table.table-striped.table-borderless.mb-3
thead
tr
th Txid
th.text-end Size
th.text-card-highlight.text-uppercase.fw-light Txid
th.text-end.text-card-highlight.text-uppercase.fw-light Size
tbody(id="largest-tx-table-body")
tr(id="largest-tx-table-row-prototype", style="display: none;")

View file

@ -40,11 +40,11 @@ block content
table.table.table-borderless.table-striped.mb-0
thead
tr
th Miner
th.text-end Blocks
th.text-end
th.text-card-highlight.text-uppercase.fw-light Miner
th.text-end.text-card-highlight.text-uppercase.fw-light Blocks
th.text-end.text-card-highlight.text-uppercase.fw-light
span.border-dotted(title="Σ (Subsidy + Fees)", data-bs-toggle="tooltip") Revenue
th.text-end
th.text-end.text-card-highlight.text-uppercase.fw-light
span.border-dotted(title="Percent of total subsidy plus fees", data-bs-toggle="tooltip") % Revenue
tbody(id="summary-table-body")
@ -222,7 +222,7 @@ block endOfBody
pieChartData.labels.push(minerName);
}
pieChartData.datasets[0].data.push(revenuePercent.toDP(2));
pieChartData.datasets[0].data.push(revenuePercent.toNumber());
pieChartData.datasets[0].backgroundColor.push(colors[colorIndex++ % colors.length]);
pieChartTotalPercent = pieChartTotalPercent.plus(revenuePercent);
@ -238,7 +238,7 @@ block endOfBody
}
pieChartData.labels.push("Other");
pieChartData.datasets[0].data.push(new Decimal(100).minus(pieChartTotalPercent).toDP(2));
pieChartData.datasets[0].data.push(new Decimal(100).minus(pieChartTotalPercent).toNumber());
pieChartData.datasets[0].backgroundColor.push("#aaaaaa");

View file

@ -34,14 +34,16 @@ block content
table.table.table-borderless.table-striped.mb-0
thead
tr
th #
th ID
th.text-end Fee Rate
small.text-muted.fw-light.ms-1 (sat/vB)
th.text-card-highlight.text-uppercase.fw-light #
th.text-card-highlight.text-uppercase.fw-light ID
th.text-end.text-card-highlight.fw-light
span.text-uppercase Fee Rate
small.ms-1 (sat/vB)
th.text-end Fee
th.text-end Weight
small.text-muted.fw-light.ms-1 (wu)
th.text-end.text-card-highlight.text-uppercase.fw-light Fee
th.text-end.text-card-highlight.fw-light
span.text-uppercase Weight
small.ms-1 (wu)
//th Depends
tbody

View file

@ -34,8 +34,8 @@ block content
thead
tr
th
th Version
th.text-end Count
th.text-card-highlight.text-uppercase.fw-light Version
th.text-end.text-card-highlight.text-uppercase.fw-light Count
tbody
each item, index in peerSummary.versionSummary
tr(class=(index >= 5 ? "versions-hidden-rows" : false))
@ -50,8 +50,8 @@ block content
thead
tr
th
th Services
th.text-end Count
th.text-card-highlight.text-uppercase.fw-light Services
th.text-end.text-card-highlight.text-uppercase.fw-light Count
tbody
each item, index in peerSummary.servicesSummary
tr(class=(index >= 5 ? "services-hidden-rows" : false))
@ -73,8 +73,8 @@ block content
thead
tr
th
th Network Type
th.text-end Count
th.text-card-highlight.text-uppercase.fw-light Network Type
th.text-end.text-card-highlight.text-uppercase.fw-light Count
tbody
each item, index in peerSummary.networkTypeSummary
tr
@ -90,8 +90,8 @@ block content
thead
tr
th
th Connection Type
th.text-end Count
th.text-card-highlight.text-uppercase.fw-light Connection Type
th.text-end.text-card-highlight.text-uppercase.fw-light Count
tbody
each item, index in peerSummary.connectionTypeSummary
tr
@ -106,15 +106,15 @@ block content
thead
tr
th
th Version
th Address
th Services
th Conn. Type
th.text-card-highlight.text-uppercase.fw-light Version
th.text-card-highlight.text-uppercase.fw-light Address
th.text-card-highlight.text-uppercase.fw-light Services
th.text-card-highlight.text-uppercase.fw-light Conn. Type
if (peerIpSummary && peerIpSummary.ips)
th Location
th.text-card-highlight.text-uppercase.fw-light Location
th Last Send / Receive
th.text-card-highlight.text-uppercase.fw-light Last Send / Receive
tbody
each item, index in peerSummary.getpeerinfo

View file

@ -61,8 +61,9 @@ block content
div.tab-content
+pageTab("Details", true)
#alert-included-next-block.alert.alert-info(style="display: none;")
h6 Confirmation Predicted in Next Block
#alert-included-next-block.alert.alert-primary(style="display: none;")
h6 Confirmation: Predicted in Next Block
i.fas.fa-check.text-success.ms-1
.mb-2 This transaction is currently unconfirmed but, with the current mempool, it's predicted to be confirmed in the next block.
span It's currently transaction #<span id='next-block-index'></span> of <span id='next-block-count'></span>.
@ -187,13 +188,26 @@ block content
- var blockRewardMax = coinConfig.blockRewardFunction(result.getblock.height, activeBlockchain);
- var valueDestroyed = (isCoinbaseTx && parseFloat(totalOutputValue) < parseFloat(blockRewardMax));
+summaryRow(3 + (tx.weight ? 1 : 0) + (valueDestroyed ? 1 : 0) + (tx.locktime > 0 ? 1 : 0) + (parseInt(daysDestroyed) > 0 ? 1 : 0))
- var showLocktime = false;
if (tx.locktime > 500000000 && result.getrawtransaction.locktime > (new Date().getTime() / 1000))
// future-dated locktime date
- showLocktime = true;
if (tx.locktime > 0 && !isTxConfirmed)
// unconfirmed locktime block height
- showLocktime = true;
+summaryRow(3 + (tx.weight ? 1 : 0) + (valueDestroyed ? 1 : 0) + (showLocktime ? 1 : 0) + (parseInt(daysDestroyed) > 0 ? 1 : 0))
+summaryItem("Version")
| #{result.getrawtransaction.version}
+summaryItem("Size")
+summaryItem("Size", null, "vB")
span #{tx.vsize.toLocaleString()}
small.ms-1 vB
if (tx.size != tx.vsize)
span.small.text-muted.ms-2 (
span.border-dotted(title=`Raw size: ${tx.size} B`, data-bs-toggle="tooltip") #{tx.size.toLocaleString()}
| )
+summaryItem("Raw Data", `The raw transaction consisting of ${result.getrawtransaction.hex.length.toLocaleString()} hexadecimal bytes.`, "hex")
| #{utils.ellipsizeMiddle(result.getrawtransaction.hex, 12)}
@ -209,19 +223,17 @@ block content
span.text-danger
+valueDisplay(currencyValue)
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
if (showLocktime)
+summaryItem("Locktime", "A specification of the earliest that a transaction may be mined. If this value is &leq; 500M, the value is interpreted as a block height; otherwise, it is interpreted as a unix timestamp.")
if (tx.locktime < 500000000 && !isTxConfirmed)
span.me-1
a.border-dotted(href=`./block-height/${result.getrawtransaction.locktime}`, title=`May be mined at this block height, or later`, data-bs-toggle="tooltip") #{result.getrawtransaction.locktime.toLocaleString()}
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
+timestamp(result.getrawtransaction.locktime)
if (result.getrawtransaction.locktime > (new Date().getTime() / 1000))
span.border-dotted.ms-1(title=`This future-dated 'locktime' value is only possible because this is a coinbase transaction. Normally, locktime specifies the earliest that a transaction may be mined (included in a block). But, because this transaction was created by the miner in the process of mining a block, it is able to bypass some of the normal validity checks that nodes on the network perform on transactions.`, data-bs-toggle="tooltip")
i.fas.fa-flag.fa-sm.text-warning
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.`;
@ -279,7 +291,7 @@ block content
thead
tr
th(style="width: 50px;")
th Input
th.text-card-highlight.text-uppercase.fw-normal Input
tbody
each vin, vinIndex in result.getrawtransaction.vin
tr
@ -309,6 +321,7 @@ block content
+darkBadge("witness")
each witnessItem, witnessIndex in vin.txinwitness
div(class=(witnessIndex > 0 ? "mt-2" : false))
+hexDataDisplay(witnessItem)
//.d-inline-block.small.border.rounded-1.p-1.px-2.card-highlight.word-wrap(class=(witnessIndex < (vin.txinwitness.length - 1) ? "mb-2" : false)) #{witnessItem}
@ -320,7 +333,7 @@ block content
thead
tr
th(style="width: 50px;")
th Script Pub Key
th.text-card-highlight.text-uppercase.fw-normal Script Pub Key
tbody
each vout, voutIndex in result.getrawtransaction.vout
tr

View file

@ -19,8 +19,9 @@ block content
.row
.col-lg-6.mb-3
.d-flex.flex-row
h6.mb-3 Last ~24 Hrs
div.small.text-muted.ms-1 (#{new Decimal(txStatsDay.avgTimespan).dividedBy(60).toDP(1)} min/pt)
h6.text-card-highlight.fw-light.mb-3
span.text-uppercase Last ~24 Hrs
span.small.ms-2 (#{new Decimal(txStatsDay.avgTimespan).dividedBy(60).toDP(1)} min/pt)
script var txCountDataDay = [];
each item, index in txStatsDay.txCounts
script txCountDataDay.push({x:#{item.x}, y:#{item.y}});
@ -30,8 +31,9 @@ block content
.col-lg-6.mb-3
.d-flex.flex-row
h6.mb-3 Last ~7 Days
div.small.text-muted.ms-1 (#{new Decimal(txStatsWeek.avgTimespan).dividedBy(60).toDP(1)} min/pt)
h6.text-card-highlight.fw-light.mb-3
span.text-uppercase Last ~7 Days
span.small.ms-2 (#{new Decimal(txStatsWeek.avgTimespan).dividedBy(60).toDP(1)} min/pt)
script var txCountDataWeek = [];
each item, index in txStatsWeek.txCounts
@ -42,8 +44,10 @@ block content
.col-lg-6.mb-3
.d-flex.flex-row
h6.mb-3 Last ~30 Days
div.small.text-muted.ms-1 (#{new Decimal(txStatsMonth.avgTimespan).dividedBy(60).dividedBy(60).toDP(1)} hr/pt)
h6.text-card-highlight.fw-light.mb-3
span.text-uppercase Last ~30 Days
span.small.ms-2 (#{new Decimal(txStatsMonth.avgTimespan).dividedBy(60).dividedBy(60).toDP(1)} hr/pt)
script var txCountDataMonth = [];
each item, index in txStatsMonth.txCounts
script txCountDataMonth.push({x:#{item.x}, y:#{item.y}});
@ -53,8 +57,10 @@ block content
.col-lg-6.mb-3
.d-flex.flex-row
h6.mb-3 Last ~365 Days
div.small.text-muted.ms-1 (#{new Decimal(txStatsYear.avgTimespan).dividedBy(60).dividedBy(60).dividedBy(24).toDP(1)} day/pt)
h6.text-card-highlight.fw-light.mb-3
span.text-uppercase Last ~365 Days
span.small.ms-2 (#{new Decimal(txStatsYear.avgTimespan).dividedBy(60).dividedBy(60).dividedBy(24).toDP(1)} day/pt)
script var txCountDataYear = [];
each item, index in txStatsYear.txCounts
script txCountDataYear.push({x:#{item.x}, y:#{item.y}});
@ -64,8 +70,10 @@ block content
.col
.d-flex.flex-row
h6.mb-3 All Time
div.small.text-muted.ms-1 (#{new Decimal(txStats.avgTimespan).dividedBy(60).dividedBy(60).dividedBy(24).toDP(1)} day/pt)
h6.text-card-highlight.fw-light.mb-3
span.text-uppercase All Time
span.small.ms-2 (#{new Decimal(txStats.avgTimespan).dividedBy(60).dividedBy(60).dividedBy(24).toDP(1)} day/pt)
script var txCountDataAlltime = [];
each item, index in txStats.txCounts
script txCountDataAlltime.push({x:#{item.x}, y:#{item.y}});
@ -84,8 +92,10 @@ block content
.row
.col-lg-6.mb-3
.d-flex.flex-row
h6.mb-3 Last ~24 Hrs
div.small.text-muted.ms-1 (#{new Decimal(txStatsDay.avgTimespan).dividedBy(60).toDP(1)} min/pt)
h6.text-card-highlight.fw-light.mb-3
span.text-uppercase Last ~24 Hrs
span.small.ms-2 (#{new Decimal(txStatsDay.avgTimespan).dividedBy(60).toDP(1)} min/pt)
script var txRateDataDay = [];
each item, index in txStatsDay.txRates
script txRateDataDay.push({x:#{item.x}, y:#{item.y}});
@ -95,8 +105,10 @@ block content
.col-lg-6.mb-3
.d-flex.flex-row
h6.mb-3 Last ~7 Days
div.small.text-muted.ms-1 (#{new Decimal(txStatsWeek.avgTimespan).dividedBy(60).toDP(1)} min/pt)
h6.text-card-highlight.fw-light.mb-3
span.text-uppercase Last ~7 Days
span.small.ms-2 (#{new Decimal(txStatsWeek.avgTimespan).dividedBy(60).toDP(1)} min/pt)
script var txRateDataWeek = [];
each item, index in txStatsWeek.txRates
script txRateDataWeek.push({x:#{item.x}, y:#{item.y}});
@ -106,8 +118,10 @@ block content
.col-lg-6.mb-3
.d-flex.flex-row
h6.mb-3 Last ~30 Days
div.small.text-muted.ms-1 (#{new Decimal(txStatsMonth.avgTimespan).dividedBy(60).dividedBy(60).toDP(1)} hr/pt)
h6.text-card-highlight.fw-light.mb-3
span.text-uppercase Last ~30 Days
span.small.ms-2 (#{new Decimal(txStatsMonth.avgTimespan).dividedBy(60).dividedBy(60).toDP(1)} hr/pt)
script var txRateDataMonth = [];
each item, index in txStatsMonth.txRates
script txRateDataMonth.push({x:#{item.x}, y:#{item.y}});
@ -117,8 +131,10 @@ block content
.col-lg-6.mb-3
.d-flex.flex-row
h6.mb-3 Last ~365 Days
div.small.text-muted.ms-1 (#{new Decimal(txStatsYear.avgTimespan).dividedBy(60).dividedBy(60).dividedBy(24).toDP(1)} day/pt)
h6.text-card-highlight.fw-light.mb-3
span.text-uppercase Last ~365 Days
span.small.ms-2 (#{new Decimal(txStatsYear.avgTimespan).dividedBy(60).dividedBy(60).dividedBy(24).toDP(1)} day/pt)
script var txRateDataYear = [];
each item, index in txStatsYear.txRates
script txRateDataYear.push({x:#{item.x}, y:#{item.y}});
@ -128,8 +144,10 @@ block content
.col
.d-flex.flex-row
h6.mb-3 All Time
div.small.text-muted.ms-1 (#{new Decimal(txStats.avgTimespan).dividedBy(60).dividedBy(60).dividedBy(24).toDP(1)} day/pt)
h6.text-card-highlight.fw-light.mb-3
span.text-uppercase All Time
span.small.ms-2 (#{new Decimal(txStats.avgTimespan).dividedBy(60).dividedBy(60).dividedBy(24).toDP(1)} day/pt)
script var txRateDataAlltime = [];
each item, index in txStats.txRates
script txRateDataAlltime.push({x:#{item.x}, y:#{item.y}});