Browse Source

- fixes for searching

- fix for transaction page/action with invalid txid
fix-133-memory-crash
Dan Janosik 7 years ago
parent
commit
e478c048af
  1. 8
      app/utils.js
  2. 55
      routes/baseActionsRouter.js
  3. 475
      views/transaction.pug

8
app/utils.js

@ -85,11 +85,6 @@ function getRandomString(length, chars) {
return result; return result;
} }
function isHex(h) {
var a = parseInt(h, 16);
return (a.toString(16) === h.toLowerCase());
}
module.exports = { module.exports = {
doSmartRedirect: doSmartRedirect, doSmartRedirect: doSmartRedirect,
@ -97,6 +92,5 @@ module.exports = {
hex2ascii: hex2ascii, hex2ascii: hex2ascii,
getBlockReward: getBlockReward, getBlockReward: getBlockReward,
splitArrayIntoChunks: splitArrayIntoChunks, splitArrayIntoChunks: splitArrayIntoChunks,
getRandomString: getRandomString, getRandomString: getRandomString
isHex: isHex
}; };

55
routes/baseActionsRouter.js

@ -194,48 +194,50 @@ router.post("/search", function(req, res) {
req.session.query = req.body.query; req.session.query = req.body.query;
console.log("query.hex = " + utils.isHex(query));
if (query.length == 64) { if (query.length == 64) {
rpcApi.getBlockByHash(query).then(function(blockByHash) { rpcApi.getRawTransaction(query).then(function(tx) {
if (blockByHash) { if (tx) {
res.redirect("/block/" + query); res.redirect("/tx/" + query);
return; return;
} }
if (utils.isHex(query)) { rpcApi.getBlockByHash(query).then(function(blockByHash) {
rpcApi.getRawTransaction(query).then(function(tx) { if (blockByHash) {
if (tx) { res.redirect("/block/" + query);
res.redirect("/tx/" + query);
return; return;
} }
req.session.userMessage = "No results found for hash: " + query; req.session.userMessage = "No results found for query: " + query;
res.redirect("/"); res.redirect("/");
return; }).catch(function(err) {
req.session.userMessage = "No results found for query: " + query;
res.redirect("/");
});
}).catch(function(err) {
rpcApi.getBlockByHash(query).then(function(blockByHash) {
if (blockByHash) {
res.redirect("/block/" + query);
}).catch(function(err) { return;
res.locals.userMessage = "Error: " + err; }
res.render("index");
});
} else {
req.session.userMessage = "No results found for query: " + query; req.session.userMessage = "No results found for query: " + query;
res.redirect("/"); res.redirect("/");
}
}).catch(function(err) { }).catch(function(err) {
res.locals.userMessage = "Error: " + err; req.session.userMessage = "No results found for query: " + query;
res.render("index"); res.redirect("/");
});
}); });
} else if (!isNaN(query)) { } else if (!isNaN(query)) {
rpcApi.getBlockByHeight(parseInt(query)).then(function(blockByHeight) { rpcApi.getBlockByHeight(parseInt(query)).then(function(blockByHeight) {
if (blockByHeight) { if (blockByHeight) {
@ -346,7 +348,6 @@ router.get("/tx/:transactionId", function(req, res) {
res.locals.result = {}; res.locals.result = {};
// TODO handle RPC error
rpcApi.getRawTransaction(txid).then(function(rawTxResult) { rpcApi.getRawTransaction(txid).then(function(rawTxResult) {
res.locals.result.getrawtransaction = rawTxResult; res.locals.result.getrawtransaction = rawTxResult;
@ -366,6 +367,10 @@ router.get("/tx/:transactionId", function(req, res) {
res.render("transaction"); res.render("transaction");
}); });
}); });
}).catch(function(err) {
res.locals.userMessage = "Failed to load transaction with txid=" + txid + " (" + err + ")";
res.render("transaction");
}); });
}); });

475
views/transaction.pug

@ -9,267 +9,268 @@ block headContent
block content block content
h1(class="h2") Transaction if (result && result.getrawtransaction)
br h1(class="h2") Transaction
small(class="monospace") #{txid} br
hr small(class="monospace") #{txid}
hr
ul(class='nav nav-tabs mb-3')
li(class="nav-item") ul(class='nav nav-tabs mb-3')
a(data-toggle="tab", href="#tab-summary", class="nav-link active", role="tab") Summary li(class="nav-item")
li(class="nav-item") a(data-toggle="tab", href="#tab-summary", class="nav-link active", role="tab") Summary
a(data-toggle="tab", href="#tab-scripts", class="nav-link", role="tab") Scripts li(class="nav-item")
li(class="nav-item") a(data-toggle="tab", href="#tab-scripts", class="nav-link", role="tab") Scripts
a(data-toggle="tab", href="#tab-raw", class="nav-link", role="tab") Raw li(class="nav-item")
a(data-toggle="tab", href="#tab-raw", class="nav-link", role="tab") Raw
- DecimalRounded = Decimal.clone({ precision: 4, rounding: 2 })
- DecimalRounded = Decimal.clone({ precision: 4, rounding: 2 })
- var totalInputValue = new Decimal(0);
if (result.getrawtransaction.vin[0].coinbase) - var totalInputValue = new Decimal(0);
- totalInputValue = totalInputValue.plus(new Decimal(utils.getBlockReward(result.getblock.height))); if (result.getrawtransaction.vin[0].coinbase)
each txInput, txInputIndex in result.txInputs - totalInputValue = totalInputValue.plus(new Decimal(utils.getBlockReward(result.getblock.height)));
if (txInput) each txInput, txInputIndex in result.txInputs
- var vout = txInput.vout[result.getrawtransaction.vin[txInputIndex].vout]; if (txInput)
if (vout.value) - var vout = txInput.vout[result.getrawtransaction.vin[txInputIndex].vout];
- totalInputValue = totalInputValue.plus(new Decimal(vout.value)); if (vout.value)
- totalInputValue = totalInputValue.plus(new Decimal(vout.value));
- var totalOutputValue = new Decimal(0);
each vout, voutIndex in result.getrawtransaction.vout - var totalOutputValue = new Decimal(0);
- totalOutputValue = totalOutputValue.plus(new Decimal(vout.value)); each vout, voutIndex in result.getrawtransaction.vout
- totalOutputValue = totalOutputValue.plus(new Decimal(vout.value));
div(class="tab-content")
div(id="tab-summary", class="tab-pane active", role="tabpanel") div(class="tab-content")
if (txid == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b") div(id="tab-summary", class="tab-pane active", role="tabpanel")
div(class="alert alert-warning", style="padding-bottom: 0;") if (txid == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")
h4(class="alert-heading h5") This transaction doesn't really exist! div(class="alert alert-warning", style="padding-bottom: 0;")
:markdown-it h4(class="alert-heading h5") This transaction doesn't really exist!
This is the coinbase transaction of the [Bitcoin Genesis Block](/block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f). For more background about this special-case transaction, you can read [this brief discussion](https://github.com/bitcoin/bitcoin/issues/3303) among some of the [Bitcoin Core](https://bitcoin.org) developers. :markdown-it
This is the coinbase transaction of the [Bitcoin Genesis Block](/block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f). For more background about this special-case transaction, you can read [this brief discussion](https://github.com/bitcoin/bitcoin/issues/3303) among some of the [Bitcoin Core](https://bitcoin.org) developers.
table(class="table")
tr table(class="table")
th(class="table-active properties-header") Included in Block
td(class="monospace")
if (result.getblock)
a(href=("/block/" + result.getrawtransaction.blockhash)) #{result.getrawtransaction.blockhash}
if (result.getblock.height)
span(class="text-muted") (#{result.getblock.height.toLocaleString()})
else
span N/A
span(class="text-muted") (unconfirmed)
tr
th(class="table-active properties-header") Timestamp
if (result.getrawtransaction.time)
td(class="monospace") #{moment.utc(new Date(result.getrawtransaction["time"] * 1000)).format("Y-MM-DD HH:mm:ss")} (utc)
else
td(class="monospace") N/A
span(class="text-muted") (unconfirmed)
//tr
// th(class="table-active properties-header") Transaction ID
// td #{txid}
tr
th(class="table-active properties-header") Version
td(class="monospace") #{result.getrawtransaction.version}
tr
th(class="table-active properties-header") Size
td(class="monospace")
span #{result.getrawtransaction.size.toLocaleString()} bytes
if (result.getrawtransaction.vsize != result.getrawtransaction.size)
span (
a(href="https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#Transaction_size_calculations") virtual size
span : #{result.getrawtransaction.vsize.toLocaleString()} bytes)
if (result.getrawtransaction.locktime > 0)
tr tr
th(class="table-active properties-header") th(class="table-active properties-header") Included in Block
span Locktime
td(class="monospace") td(class="monospace")
if (result.getrawtransaction.locktime < 500000000) if (result.getblock)
span Spendable in block a(href=("/block/" + result.getrawtransaction.blockhash)) #{result.getrawtransaction.blockhash}
a(href=("/block-height/" + result.getrawtransaction.locktime)) #{result.getrawtransaction.locktime} if (result.getblock.height)
span or later - ( span(class="text-muted") (#{result.getblock.height.toLocaleString()})
a(href="https://bitcoin.org/en/developer-guide#locktime-and-sequence-number", title="Locktime documentation")
span docs
i(class="fa fa-external-link")
span )
else else
span Spendable after #{moment.utc(new Date(result.getrawtransaction.locktime * 1000)).format("Y-MM-DD HH:mm:ss")} (utc) - ( span N/A
a(href="https://bitcoin.org/en/developer-guide#locktime-and-sequence-number", title="Locktime documentation") span(class="text-muted") (unconfirmed)
span docs
i(class="fa fa-external-link") tr
span ) th(class="table-active properties-header") Timestamp
if (result.getrawtransaction.time)
tr td(class="monospace") #{moment.utc(new Date(result.getrawtransaction["time"] * 1000)).format("Y-MM-DD HH:mm:ss")} (utc)
th(class="table-active properties-header") Confirmations
td(class="monospace")
if (!result.getrawtransaction.confirmations || result.getrawtransaction.confirmations == 0)
strong(class="text-danger") 0 (unconfirmed)
else if (result.getrawtransaction.confirmations < 6)
strong(class="text-warning") #{result.getrawtransaction.confirmations}
else else
strong(class="text-success") #{result.getrawtransaction.confirmations.toLocaleString()} td(class="monospace") N/A
span(class="text-muted") (unconfirmed)
//tr
// th(class="table-active properties-header") Transaction ID
// td #{txid}
if (result.getrawtransaction.vin[0].coinbase)
tr tr
th(class="table-active properties-header") Total Network Fees th(class="table-active properties-header") Version
td(class="monospace") #{new Decimal(totalOutputValue).minus(totalInputValue)} td(class="monospace") #{result.getrawtransaction.version}
else
tr tr
th(class="table-active properties-header") Network Fee Paid th(class="table-active properties-header") Size
td(class="monospace") td(class="monospace")
strong #{new Decimal(totalInputValue).minus(totalOutputValue)} span #{result.getrawtransaction.size.toLocaleString()} bytes
span(class="text-muted") (#{totalInputValue} - #{totalOutputValue}) if (result.getrawtransaction.vsize != result.getrawtransaction.size)
br span (
span ~#{new DecimalRounded(totalInputValue).minus(totalOutputValue).dividedBy(result.getrawtransaction.size).times(100000000)} sat/B a(href="https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#Transaction_size_calculations") virtual size
span : #{result.getrawtransaction.vsize.toLocaleString()} bytes)
if (result.getrawtransaction.locktime > 0)
tr
th(class="table-active properties-header")
span Locktime
td(class="monospace")
if (result.getrawtransaction.locktime < 500000000)
span Spendable in block
a(href=("/block-height/" + result.getrawtransaction.locktime)) #{result.getrawtransaction.locktime}
span or later - (
a(href="https://bitcoin.org/en/developer-guide#locktime-and-sequence-number", title="Locktime documentation")
span docs
i(class="fa fa-external-link")
span )
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", title="Locktime documentation")
span docs
i(class="fa fa-external-link")
span )
tr
th(class="table-active properties-header") Confirmations
td(class="monospace")
if (!result.getrawtransaction.confirmations || result.getrawtransaction.confirmations == 0)
strong(class="text-danger") 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)
tr
th(class="table-active properties-header") Total Network Fees
td(class="monospace") #{new Decimal(totalOutputValue).minus(totalInputValue)}
else
tr
th(class="table-active properties-header") Network Fee Paid
td(class="monospace")
strong #{new Decimal(totalInputValue).minus(totalOutputValue)}
span(class="text-muted") (#{totalInputValue} - #{totalOutputValue})
br
span ~#{new DecimalRounded(totalInputValue).minus(totalOutputValue).dividedBy(result.getrawtransaction.size).times(100000000)} sat/B
if (result.getrawtransaction.vin[0].coinbase)
div(class="card mb-3")
div(class="card-header")
h2(class="h5 mb-0") Coinbase
div(class="card-body")
h6 Hex
div(style="background-color: #f0f0f0; padding: 5px 10px;", class="mb-3")
span(class="monospace word-wrap") #{result.getrawtransaction.vin[0].coinbase}
h6 Decoded
div(style="background-color: #f0f0f0; padding: 5px 10px;", class="mb-3")
span(class="monospace word-wrap") #{utils.hex2ascii(result.getrawtransaction.vin[0].coinbase)}
if (result.getrawtransaction.vin[0].coinbase)
div(class="card mb-3") div(class="card mb-3")
div(class="card-header") div(class="card-header")
h2(class="h5 mb-0") Coinbase div(class="row")
div(class="col-md-6")
h2(class="h5 mb-0") Input (#{result.getrawtransaction.vin.length.toLocaleString()})
div(class="col-md-6")
h2(class="h5 mb-0") Output (#{result.getrawtransaction.vout.length.toLocaleString()})
div(class="card-body") div(class="card-body")
h6 Hex div(class="row")
div(style="background-color: #f0f0f0; padding: 5px 10px;", class="mb-3") div(class="col-md-6")
span(class="monospace word-wrap") #{result.getrawtransaction.vin[0].coinbase} if (result.txInputs)
table(class="table mb-0")
h6 Decoded thead
div(style="background-color: #f0f0f0; padding: 5px 10px;", class="mb-3") tr
span(class="monospace word-wrap") #{utils.hex2ascii(result.getrawtransaction.vin[0].coinbase)} th(style="width: 40px;")
th Input
div(class="card mb-3") th Amount
div(class="card-header") tbody
div(class="row")
div(class="col-md-6") if (result.getrawtransaction.vin[0].coinbase)
h2(class="h5 mb-0") Input (#{result.getrawtransaction.vin.length.toLocaleString()}) tr
div(class="col-md-6") th 1
h2(class="h5 mb-0") Output (#{result.getrawtransaction.vout.length.toLocaleString()}) td
div(class="card-body") span(class="tag monospace") coinbase
div(class="row") span(class="monospace") Newly minted BTC
div(class="col-md-6") td(class="monospace") #{utils.getBlockReward(result.getblock.height)}
if (result.txInputs)
table(class="table mb-0") each txInput, txInputIndex in result.txInputs
thead if (txInput)
tr - var vout = txInput.vout[result.getrawtransaction.vin[txInputIndex].vout];
th(style="width: 40px;")
th Input tr
th Amount th #{(txInputIndex + 1)}
tbody //pre
// code #{JSON.stringify(txInput)}
td
if (vout.scriptPubKey && vout.scriptPubKey.addresses)
span(class="monospace") #{vout.scriptPubKey.addresses[0]}
br
span(class="monospace text-muted") via tx
a(href=("/tx/" + txInput.txid + "#output-" + result.getrawtransaction.vin[txInputIndex].vout), class="monospace") #{txInput.txid.substring(0, 14)}..., Output ##{result.getrawtransaction.vin[txInputIndex].vout + 1}
td
if (vout.value)
span(class="monospace") #{vout.value}
if (result.getrawtransaction.vin[0].coinbase)
tr tr
th 1
td td
span(class="tag monospace") coinbase td
span(class="monospace") Newly minted BTC td
td(class="monospace") #{utils.getBlockReward(result.getblock.height)} strong(class="monospace") #{totalInputValue}
each txInput, txInputIndex in result.txInputs
if (txInput)
- var vout = txInput.vout[result.getrawtransaction.vin[txInputIndex].vout];
tr div(class="col-md-6")
th #{(txInputIndex + 1)} table(class="table mb-0")
//pre thead
// code #{JSON.stringify(txInput)} tr
th
th Output
th Amount
tbody
each vout, voutIndex in result.getrawtransaction.vout
tr
th #{(voutIndex + 1)}
td td
if (vout.scriptPubKey && vout.scriptPubKey.addresses) if (vout.scriptPubKey)
span(class="monospace") #{vout.scriptPubKey.addresses[0]} if (vout.scriptPubKey.addresses)
br a(id="output-" + voutIndex)
span(class="monospace text-muted") via tx span(class="monospace") #{vout.scriptPubKey.addresses[0]}
a(href=("/tx/" + txInput.txid + "#output-" + result.getrawtransaction.vin[txInputIndex].vout), class="monospace") #{txInput.txid.substring(0, 14)}..., Output ##{result.getrawtransaction.vin[txInputIndex].vout + 1}
else if (vout.scriptPubKey.hex && vout.scriptPubKey.hex.startsWith('6a24aa21a9ed'))
span(class="monospace") Segregated Witness committment -
a(href="https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#commitment-structure") docs
i(class="fa fa-external-link")
else if (vout.scriptPubKey.asm && vout.scriptPubKey.asm.startsWith('OP_RETURN '))
span(class="monospace") OP_RETURN:
span(class="monospace text-muted") #{utils.hex2ascii(vout.scriptPubKey.asm.substring("OP_RETURN ".length))}
td td
if (vout.value) span(class="monospace") #{vout.value}
span(class="monospace") #{vout.value}
tr
td
td
td
strong(class="monospace") #{totalInputValue}
div(class="col-md-6")
table(class="table mb-0")
thead
tr
th
th Output
th Amount
tbody
each vout, voutIndex in result.getrawtransaction.vout
tr tr
th #{(voutIndex + 1)}
td td
if (vout.scriptPubKey)
if (vout.scriptPubKey.addresses)
a(id="output-" + voutIndex)
span(class="monospace") #{vout.scriptPubKey.addresses[0]}
else if (vout.scriptPubKey.hex && vout.scriptPubKey.hex.startsWith('6a24aa21a9ed'))
span(class="monospace") Segregated Witness committment -
a(href="https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#commitment-structure") docs
i(class="fa fa-external-link")
else if (vout.scriptPubKey.asm && vout.scriptPubKey.asm.startsWith('OP_RETURN '))
span(class="monospace") OP_RETURN:
span(class="monospace text-muted") #{utils.hex2ascii(vout.scriptPubKey.asm.substring("OP_RETURN ".length))}
td td
span(class="monospace") #{vout.value} td
strong(class="monospace") #{totalOutputValue}
tr
td div(id="tab-scripts", class="tab-pane", role="tabpanel")
td h3 Input Scripts
td table(class="table table-striped")
strong(class="monospace") #{totalOutputValue} thead
div(id="tab-scripts", class="tab-pane", role="tabpanel")
h3 Input Scripts
table(class="table table-striped")
thead
tr
th(style="width: 50px;")
th Script Sig (asm)
tbody
each vin, vinIndex in result.getrawtransaction.vin
tr tr
th #{vinIndex + 1} th(style="width: 50px;")
td th Script Sig (asm)
if (vin.scriptSig && vin.scriptSig.asm) tbody
span(class="word-wrap monospace") #{vin.scriptSig.asm} each vin, vinIndex in result.getrawtransaction.vin
tr
else if (vin.coinbase) th #{vinIndex + 1}
div(style="line-height: 1.75em;") td
span(class="tag") coinbase if (vin.scriptSig && vin.scriptSig.asm)
br span(class="word-wrap monospace") #{vin.scriptSig.asm}
span(class="word-wrap monospace") #{vin.coinbase}
br else if (vin.coinbase)
span(class="word-wrap monospace text-muted") (decoded) #{utils.hex2ascii(vin.coinbase)} div(style="line-height: 1.75em;")
span(class="tag") coinbase
h3 Output Scripts br
table(class="table table-striped") span(class="word-wrap monospace") #{vin.coinbase}
thead br
tr span(class="word-wrap monospace text-muted") (decoded) #{utils.hex2ascii(vin.coinbase)}
th(style="width: 50px;")
th Script Pub Key (asm) h3 Output Scripts
tbody table(class="table table-striped")
each vout, voutIndex in result.getrawtransaction.vout thead
tr tr
th #{voutIndex + 1} th(style="width: 50px;")
td th Script Pub Key (asm)
if (vout.scriptPubKey && vout.scriptPubKey.asm) tbody
span(class="word-wrap monospace") #{vout.scriptPubKey.asm} each vout, voutIndex in result.getrawtransaction.vout
if (vout.scriptPubKey.asm.startsWith("OP_RETURN")) tr
br th #{voutIndex + 1}
span(class="word-wrap monospace text-muted") (decoded) #{utils.hex2ascii(vout.scriptPubKey.asm)} td
if (vout.scriptPubKey && vout.scriptPubKey.asm)
div(id="tab-raw", class="tab-pane", role="tabpanel") span(class="word-wrap monospace") #{vout.scriptPubKey.asm}
div(class="highlight") if (vout.scriptPubKey.asm.startsWith("OP_RETURN"))
pre br
code(class="language-json", data-lang="json") #{JSON.stringify(result.getrawtransaction, null, 4)} span(class="word-wrap monospace text-muted") (decoded) #{utils.hex2ascii(vout.scriptPubKey.asm)}
//pre #{JSON.stringify(result.txInputs, null, 4)} div(id="tab-raw", class="tab-pane", role="tabpanel")
div(class="highlight")
pre
code(class="language-json", data-lang="json") #{JSON.stringify(result.getrawtransaction, null, 4)}
//pre #{JSON.stringify(result.txInputs, null, 4)}

Loading…
Cancel
Save