You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
390 lines
14 KiB
390 lines
14 KiB
extends layout
|
|
|
|
block headContent
|
|
title Transaction #{txid}
|
|
style.
|
|
.field {
|
|
word-wrap: break-word;
|
|
}
|
|
|
|
|
|
block content
|
|
if (result && result.getrawtransaction)
|
|
h1.h3.word-wrap Transaction
|
|
br
|
|
small.text-monospace #{txid}
|
|
hr
|
|
|
|
ul.nav.nav-tabs.mb-3
|
|
li.nav-item
|
|
a.nav-link.active(data-toggle="tab", href="#tab-details", role="tab") Details
|
|
li.nav-item
|
|
a.nav-link(data-toggle="tab", href="#tab-scripts", role="tab") Scripts
|
|
li.nav-item
|
|
a.nav-link(data-toggle="tab", href="#tab-json", role="tab") JSON
|
|
|
|
- DecimalRounded = Decimal.clone({ precision: 4, rounding: 2 })
|
|
|
|
- var totalInputValue = new Decimal(0);
|
|
if (result.getrawtransaction.vin[0].coinbase)
|
|
- totalInputValue = totalInputValue.plus(new Decimal(coinConfig.blockRewardFunction(result.getblock.height, global.activeBlockchain)));
|
|
each txInput, txInputIndex in result.txInputs
|
|
if (txInput)
|
|
- var vout = txInput.vout[result.getrawtransaction.vin[txInputIndex].vout];
|
|
if (vout.value)
|
|
- totalInputValue = totalInputValue.plus(new Decimal(vout.value));
|
|
|
|
- var totalOutputValue = new Decimal(0);
|
|
each vout, voutIndex in result.getrawtransaction.vout
|
|
- totalOutputValue = totalOutputValue.plus(new Decimal(vout.value));
|
|
|
|
div.tab-content
|
|
div(id="tab-details", class="tab-pane active", role="tabpanel")
|
|
if (global.specialTransactions && global.specialTransactions[txid])
|
|
div(class="alert alert-primary shadow-sm", style="padding-bottom: 0;")
|
|
div(class="float-left", style="width: 55px; height: 55px; font-size: 18px;")
|
|
i(class="fas fa-certificate fa-2x", style="margin-top: 10px;")
|
|
|
|
h4(class="alert-heading h6 font-weight-bold") #{coinConfig.name} Fun
|
|
|
|
// 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
|
|
|
|
- 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
|
|
|
|
div.clearfix
|
|
if (!isTxConfirmed)
|
|
div.row
|
|
div.summary-table-label Status
|
|
div.summary-table-content.text-monospace
|
|
span(class="text-warning") Unconfirmed
|
|
|
|
div.row
|
|
div.summary-table-label
|
|
span.border-dotted(title="Whether this unconfirmed transaction is replaceable using replace-by-fee (RBF)", data-toggle="tooltip") RBF
|
|
div.summary-table-content.text-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;
|
|
|
|
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-toggle="tooltip") No explicit opt-in
|
|
a.ml-2(href="https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki#summary", data-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.text-monospace
|
|
a(href=("/block/" + result.getrawtransaction.blockhash)) ##{result.getblock.height.toLocaleString()}
|
|
|
|
if (isTxConfirmed)
|
|
div.row
|
|
div.summary-table-label Date
|
|
div.summary-table-content.text-monospace
|
|
if (result.getrawtransaction.time)
|
|
td.text-monospace
|
|
- var timestampHuman = result.getrawtransaction.time;
|
|
include includes/timestamp-human.pug
|
|
small.ml-1 utc
|
|
|
|
- var timeAgoTime = result.getrawtransaction.time;
|
|
span.text-muted.ml-2 (
|
|
include includes/time-ago-text.pug
|
|
span ago)
|
|
|
|
div.row
|
|
div.summary-table-label Version
|
|
div.summary-table-content.text-monospace #{result.getrawtransaction.version}
|
|
|
|
div.row
|
|
div.summary-table-label Size
|
|
div.summary-table-content.text-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 )
|
|
|
|
else
|
|
span #{result.getrawtransaction.size.toLocaleString()}
|
|
small B
|
|
|
|
if (result.getrawtransaction.locktime > 0)
|
|
div.row
|
|
div.summary-table-label Locktime
|
|
div.summary-table-content.text-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://bitcoin.org/en/developer-guide#locktime-and-sequence-number", data-toggle="tooltip", title="More info about locktime", target="_blank")
|
|
i(class="fas fa-info-circle")
|
|
else
|
|
span Spendable after #{moment.utc(new Date(result.getrawtransaction.locktime * 1000)).format("Y-MM-DD HH:mm:ss")} (utc)
|
|
a(href="https://bitcoin.org/en/developer-guide#locktime-and-sequence-number", data-toggle="tooltip", title="More info about locktime", target="_blank")
|
|
i(class="fas fa-info-circle")
|
|
|
|
if (isTxConfirmed)
|
|
div.row
|
|
div.summary-table-label Confirmations
|
|
div.summary-table-content.text-monospace
|
|
if (!result.getrawtransaction.confirmations || result.getrawtransaction.confirmations == 0)
|
|
strong(class="text-warning") 0 (unconfirmed)
|
|
|
|
else if (result.getrawtransaction.confirmations < 6)
|
|
strong(class="text-warning") #{result.getrawtransaction.confirmations}
|
|
|
|
else
|
|
strong(class="text-success") #{result.getrawtransaction.confirmations.toLocaleString()}
|
|
|
|
|
|
if (result.getrawtransaction.vin[0].coinbase)
|
|
div.row
|
|
div.summary-table-label Fees Collected
|
|
div.summary-table-content.text-monospace
|
|
- var currencyValue = new Decimal(totalOutputValue).minus(totalInputValue);
|
|
include includes/value-display.pug
|
|
|
|
- var blockRewardMax = coinConfig.blockRewardFunction(result.getblock.height, global.activeBlockchain);
|
|
if (parseFloat(totalOutputValue) < parseFloat(blockRewardMax))
|
|
div.row
|
|
div.summary-table-label
|
|
span.border-dotted(data-toggle="tooltip" title="The miner of this transaction's block failed to collect this value. As a result, it is permanently lost.") Fees Destroyed
|
|
div.summary-table-content.text-monospace.text-danger
|
|
- var currencyValue = new Decimal(blockRewardMax).minus(totalOutputValue);
|
|
include includes/value-display.pug
|
|
|
|
if (minerInfo)
|
|
- var minerInfo = utils.getMinerFromCoinbaseTx(result.getrawtransaction);
|
|
div.row
|
|
div.summary-table-label Miner
|
|
div.summary-table-content.text-monospace
|
|
if (minerInfo)
|
|
span #{minerInfo.name}
|
|
if (minerInfo.identifiedBy)
|
|
span(data-toggle="tooltip", title=("Identified by: " + minerInfo.identifiedBy))
|
|
i.fas.fa-info-circle
|
|
else
|
|
span ?
|
|
span(data-toggle="tooltip", title="Unable to identify miner")
|
|
i.fas.fa-info-circle
|
|
|
|
else
|
|
|
|
- var feePaid = new Decimal(totalInputValue).minus(totalOutputValue);
|
|
|
|
div.row
|
|
div.summary-table-label Fee Paid
|
|
div.summary-table-content.text-monospace
|
|
- var currencyValue = feePaid;
|
|
include includes/value-display.pug
|
|
|
|
if (feePaid > 0)
|
|
- var item1 = utils.formatCurrencyAmount(totalInputValue, currencyFormatType);
|
|
- var item2 = utils.formatCurrencyAmount(totalOutputValue, currencyFormatType);
|
|
span.ml-2(title=(item1.simpleVal + " - " + item2.simpleVal), data-toggle="tooltip")
|
|
i(class="fas fa-ellipsis-h")
|
|
|
|
if (feePaid > 0)
|
|
div.row
|
|
div.summary-table-label Fee Rate
|
|
div.summary-table-content.text-monospace
|
|
if (result.getrawtransaction.vsize != result.getrawtransaction.size)
|
|
span #{utils.addThousandsSeparators(new DecimalRounded(totalInputValue).minus(totalOutputValue).dividedBy(result.getrawtransaction.vsize).times(100000000))}
|
|
small sat/vB
|
|
br
|
|
|
|
span.text-muted (#{utils.addThousandsSeparators(new DecimalRounded(totalInputValue).minus(totalOutputValue).dividedBy(result.getrawtransaction.size).times(100000000))}
|
|
small sat/B
|
|
span )
|
|
|
|
else
|
|
span #{utils.addThousandsSeparators(new DecimalRounded(totalInputValue).minus(totalOutputValue).dividedBy(result.getrawtransaction.size).times(100000000))}
|
|
small sat/B
|
|
|
|
|
|
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.text-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
|
|
|
|
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 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)
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body.px-2.px-md-3
|
|
h3.h6.mb-0
|
|
span #{mempoolDetails.ancestors.length.toLocaleString()}
|
|
if (mempoolDetails.ancestors.length == 1)
|
|
span Ancestor
|
|
else
|
|
span Ancestors
|
|
hr
|
|
|
|
ol.mb-0
|
|
each ancestorTxid, ancestorIndex in mempoolDetails.ancestors
|
|
li
|
|
a.text-monospace(href=("/tx/" + ancestorTxid)) #{ancestorTxid}
|
|
|
|
if (mempoolDetails.descendants.length > 0)
|
|
div.card.shadow-sm.mb-3
|
|
div.card-body.px-2.px-md-3
|
|
h3.h6.mb-0
|
|
span #{mempoolDetails.descendants.length.toLocaleString()}
|
|
if (mempoolDetails.descendants.length == 1)
|
|
span Descendant
|
|
else
|
|
span Descendants
|
|
hr
|
|
|
|
ol.mb-0
|
|
each descendantTxid, descendantIndex in mempoolDetails.descendants
|
|
li
|
|
a.text-monospace(href=("/tx/" + descendantTxid)) #{descendantTxid}
|
|
|
|
- var fontawesomeInputName = "sign-in-alt";
|
|
- var fontawesomeOutputName = "sign-out-alt";
|
|
|
|
div(id="tab-scripts", class="tab-pane", 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
|
|
tr
|
|
th(style="width: 50px;")
|
|
th Script Sig (asm)
|
|
tbody
|
|
each vin, vinIndex in result.getrawtransaction.vin
|
|
tr
|
|
th(class="pl-0")
|
|
a(data-toggle="tooltip", title=("Input #" + vinIndex), style="white-space: nowrap;")
|
|
i(class=("fas fa-" + fontawesomeInputName + " mr-2"))
|
|
small ##{vinIndex.toLocaleString()}
|
|
|
|
td.word-wrap.text-break.text-monospace
|
|
if (vin.scriptSig && vin.scriptSig.asm)
|
|
span #{vin.scriptSig.asm}
|
|
|
|
else if (vin.coinbase)
|
|
div.text-monospace(style="line-height: 1.75em;")
|
|
small.rounded.bg-primary.text-white.px-2.py-1.mr-2 coinbase
|
|
br
|
|
span #{vin.coinbase}
|
|
br
|
|
span.text-muted (decoded) #{utils.hex2ascii(vin.coinbase)}
|
|
|
|
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
|
|
tr
|
|
th(style="width: 50px;")
|
|
th Script Pub Key (asm)
|
|
tbody
|
|
each vout, voutIndex in result.getrawtransaction.vout
|
|
tr
|
|
th(class="pl-0")
|
|
a(data-toggle="tooltip", title=("Output #" + (voutIndex + 1)), style="white-space: nowrap;")
|
|
i(class=("fas fa-" + fontawesomeOutputName + " mr-2"))
|
|
small ##{voutIndex.toLocaleString()}
|
|
|
|
td(class="word-wrap text-monospace")
|
|
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)}
|
|
|
|
div(id="tab-json", class="tab-pane", role="tabpanel")
|
|
h3.h5 Transaction
|
|
div(class="highlight")
|
|
pre
|
|
code(class="json bg-light", data-lang="json") #{JSON.stringify(result.getrawtransaction, null, 4)}
|
|
|
|
h3.h5 UTXOs
|
|
div(class="highlight")
|
|
pre
|
|
code(class="json bg-light", data-lang="json") #{JSON.stringify(utxos, null, 4)}
|
|
|
|
if (mempoolDetails)
|
|
h3.h5 Mempool Details
|
|
div(class="highlight")
|
|
pre
|
|
code(class="json bg-light", data-lang="json") #{JSON.stringify(mempoolDetails, null, 4)}
|
|
|
|
//pre #{JSON.stringify(result.txInputs, null, 4)}
|
|
|
|
|
|
|