Skip to content

Commit

Permalink
more graceful degradation for /address pages
Browse files Browse the repository at this point in the history
I believe we can do "better" than this in some cases but I'm going with this for graceful-degradataion-v1
  • Loading branch information
janoside committed Feb 19, 2021
1 parent 45c768f commit cb9d58b
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 81 deletions.
166 changes: 85 additions & 81 deletions routes/baseRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -991,118 +991,122 @@ router.get("/address/:address", function(req, res, next) {
}

res.locals.txids = txids;

coreApi.getRawTransactionsWithInputs(txids).then(function(rawTxResult) {
res.locals.transactions = rawTxResult.transactions;
res.locals.txInputsByTransaction = rawTxResult.txInputsByTransaction;

// for coinbase txs, we need the block height in order to calculate subsidy to display
var coinbaseTxs = [];
for (var i = 0; i < rawTxResult.transactions.length; i++) {
var tx = rawTxResult.transactions[i];

for (var j = 0; j < tx.vin.length; j++) {
if (tx.vin[j].coinbase) {
// addressApi sometimes has blockHeightByTxid already available, otherwise we need to query for it
if (!blockHeightsByTxid[tx.txid]) {
coinbaseTxs.push(tx);

if (global.txindexAvailable) {
coreApi.getRawTransactionsWithInputs(txids).then(function(rawTxResult) {
res.locals.transactions = rawTxResult.transactions;
res.locals.txInputsByTransaction = rawTxResult.txInputsByTransaction;

// for coinbase txs, we need the block height in order to calculate subsidy to display
var coinbaseTxs = [];
for (var i = 0; i < rawTxResult.transactions.length; i++) {
var tx = rawTxResult.transactions[i];

for (var j = 0; j < tx.vin.length; j++) {
if (tx.vin[j].coinbase) {
// addressApi sometimes has blockHeightByTxid already available, otherwise we need to query for it
if (!blockHeightsByTxid[tx.txid]) {
coinbaseTxs.push(tx);
}
}
}
}
}


var coinbaseTxBlockHashes = [];
var blockHashesByTxid = {};
coinbaseTxs.forEach(function(tx) {
coinbaseTxBlockHashes.push(tx.blockhash);
blockHashesByTxid[tx.txid] = tx.blockhash;
});

var blockHeightsPromises = [];
if (coinbaseTxs.length > 0) {
// we need to query some blockHeights by hash for some coinbase txs
blockHeightsPromises.push(new Promise(function(resolve2, reject2) {
coreApi.getBlocksByHash(coinbaseTxBlockHashes).then(function(blocksByHashResult) {
for (var txid in blockHashesByTxid) {
if (blockHashesByTxid.hasOwnProperty(txid)) {
blockHeightsByTxid[txid] = blocksByHashResult[blockHashesByTxid[txid]].height;
var coinbaseTxBlockHashes = [];
var blockHashesByTxid = {};
coinbaseTxs.forEach(function(tx) {
coinbaseTxBlockHashes.push(tx.blockhash);
blockHashesByTxid[tx.txid] = tx.blockhash;
});

var blockHeightsPromises = [];
if (coinbaseTxs.length > 0) {
// we need to query some blockHeights by hash for some coinbase txs
blockHeightsPromises.push(new Promise(function(resolve2, reject2) {
coreApi.getBlocksByHash(coinbaseTxBlockHashes).then(function(blocksByHashResult) {
for (var txid in blockHashesByTxid) {
if (blockHashesByTxid.hasOwnProperty(txid)) {
blockHeightsByTxid[txid] = blocksByHashResult[blockHashesByTxid[txid]].height;
}
}
}

resolve2();
resolve2();

}).catch(function(err) {
res.locals.pageErrors.push(utils.logError("78ewrgwetg3", err));
}).catch(function(err) {
res.locals.pageErrors.push(utils.logError("78ewrgwetg3", err));

reject2(err);
});
}));
}
reject2(err);
});
}));
}

Promise.all(blockHeightsPromises).then(function() {
var addrGainsByTx = {};
var addrLossesByTx = {};
Promise.all(blockHeightsPromises).then(function() {
var addrGainsByTx = {};
var addrLossesByTx = {};

res.locals.addrGainsByTx = addrGainsByTx;
res.locals.addrLossesByTx = addrLossesByTx;
res.locals.addrGainsByTx = addrGainsByTx;
res.locals.addrLossesByTx = addrLossesByTx;

var handledTxids = [];
var handledTxids = [];

for (var i = 0; i < rawTxResult.transactions.length; i++) {
var tx = rawTxResult.transactions[i];
var txInputs = rawTxResult.txInputsByTransaction[tx.txid];

if (handledTxids.includes(tx.txid)) {
continue;
}
for (var i = 0; i < rawTxResult.transactions.length; i++) {
var tx = rawTxResult.transactions[i];
var txInputs = rawTxResult.txInputsByTransaction[tx.txid];
if (handledTxids.includes(tx.txid)) {
continue;
}

handledTxids.push(tx.txid);
handledTxids.push(tx.txid);

for (var j = 0; j < tx.vout.length; j++) {
if (tx.vout[j].value > 0 && tx.vout[j].scriptPubKey && tx.vout[j].scriptPubKey.addresses && tx.vout[j].scriptPubKey.addresses.includes(address)) {
if (addrGainsByTx[tx.txid] == null) {
addrGainsByTx[tx.txid] = new Decimal(0);
}
for (var j = 0; j < tx.vout.length; j++) {
if (tx.vout[j].value > 0 && tx.vout[j].scriptPubKey && tx.vout[j].scriptPubKey.addresses && tx.vout[j].scriptPubKey.addresses.includes(address)) {
if (addrGainsByTx[tx.txid] == null) {
addrGainsByTx[tx.txid] = new Decimal(0);
}

addrGainsByTx[tx.txid] = addrGainsByTx[tx.txid].plus(new Decimal(tx.vout[j].value));
addrGainsByTx[tx.txid] = addrGainsByTx[tx.txid].plus(new Decimal(tx.vout[j].value));
}
}
}

for (var j = 0; j < tx.vin.length; j++) {
var txInput = txInputs[j];
var vinJ = tx.vin[j];
for (var j = 0; j < tx.vin.length; j++) {
var txInput = txInputs[j];
var vinJ = tx.vin[j];

if (txInput != null) {
if (txInput && txInput.scriptPubKey && txInput.scriptPubKey.addresses && txInput.scriptPubKey.addresses.includes(address)) {
if (addrLossesByTx[tx.txid] == null) {
addrLossesByTx[tx.txid] = new Decimal(0);
}
if (txInput != null) {
if (txInput && txInput.scriptPubKey && txInput.scriptPubKey.addresses && txInput.scriptPubKey.addresses.includes(address)) {
if (addrLossesByTx[tx.txid] == null) {
addrLossesByTx[tx.txid] = new Decimal(0);
}

addrLossesByTx[tx.txid] = addrLossesByTx[tx.txid].plus(new Decimal(txInput.value));
addrLossesByTx[tx.txid] = addrLossesByTx[tx.txid].plus(new Decimal(txInput.value));
}
}
}

//debugLog("tx: " + JSON.stringify(tx));
//debugLog("txInputs: " + JSON.stringify(txInputs));
}

//debugLog("tx: " + JSON.stringify(tx));
//debugLog("txInputs: " + JSON.stringify(txInputs));
}
res.locals.blockHeightsByTxid = blockHeightsByTxid;

resolve();

res.locals.blockHeightsByTxid = blockHeightsByTxid;
}).catch(function(err) {
res.locals.pageErrors.push(utils.logError("230wefrhg0egt3", err));

resolve();
reject(err);
});

}).catch(function(err) {
res.locals.pageErrors.push(utils.logError("230wefrhg0egt3", err));
res.locals.pageErrors.push(utils.logError("asdgf07uh23", err));

reject(err);
});

}).catch(function(err) {
res.locals.pageErrors.push(utils.logError("asdgf07uh23", err));

reject(err);
});
} else {
resolve();
}

} else {
// no addressDetails.txids available
Expand Down
6 changes: 6 additions & 0 deletions views/address.pug
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,12 @@ block content
pre
code.json #{JSON.stringify(err, null, 4)}

else if (!global.txindexAvailable && transactions.length == 0)
ol.text-monospace(start=(offset + 1))
each txid in txids
li
a(href=`./tx/${txid}`) #{txid}

This comment has been minimized.

Copy link
@shesek

shesek Feb 21, 2021

Contributor

Looks like this just needs `@${addressDetails.blockHeightsByTxid[txid]}` (when >0) tucked at the end of the link to work without txindex? :-)

What did you have in mind for graceful-degradataion-v2?


else if (transactions.length == 0)
span No transactions found

Expand Down

3 comments on commit cb9d58b

@janoside
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was imagining it being possible to have detailed tx data displayed inline on /address/xxx for some of the transactions (e.g. recent ones), but the UX for displaying some-but-not-all could be chaotic so I'm unsure whether it's the right choice.

I agree with your addition here and I made that change.

I'm also curious your thoughts on this change. I see some value in giving something in cases where a user, with pruning active or no txindex, clicks through to a /tx/ page from a /address page. It's a bit of a hack - you could alter the URL to use a different blockHeight and the tool would gladly display the height/date for that block - but it gives some helpful context in some situations.

@shesek
Copy link
Contributor

@shesek shesek commented on cb9d58b Feb 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could alter the URL to use a different blockHeight and the tool would gladly display the height/date for that block

Wouldn't a block height that doesn't match the txid result in coreApi.getRawTransactionsWithInputs([txid], -1, block.hash) failing and returning an error message to the user?

@janoside
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, coreApi.getRawTransactionsWithInputs fails, but that happens anyway if the block containing the tx has been pruned; since we "expect" the error, it's handled more gracefully than it would be in, say, a non-pruned environment.

Please sign in to comment.