Browse Source

Lots of error handling improvements:

- RPC api now throws errors up to callers on RpcError results
- More consistent handling of errors from baseActionRouter
- Add some missing rejection handlers
- Tweak UI for display of errors
- Handle missing block data on /block pages (in UI) so that error info can be displayed cleanly (rather than the template error showing because data is missing)
master
Dan Janosik 5 years ago
parent
commit
36e8015b64
No known key found for this signature in database GPG Key ID: C6F8CE9FFDB2CED2
  1. 4
      app/api/coreApi.js
  2. 86
      app/api/rpcApi.js
  3. 25
      routes/baseActionsRouter.js
  4. 2
      views/address.pug
  5. 18
      views/block.pug
  6. 47
      views/includes/page-errors-modal.pug

4
app/api/coreApi.js

@ -802,6 +802,8 @@ function getRawTransactionsWithInputs(txids, maxInputs=-1) {
resolve({ transactions:transactions, txInputsByTransaction:txInputsByTransaction });
});
}).catch(function(err) {
reject(err);
});
});
}
@ -833,6 +835,8 @@ function getBlockByHashWithTransactions(blockHash, txLimit, txOffset) {
resolve({ getblock:block, transactions:txsResult.transactions, txInputsByTransaction:txsResult.txInputsByTransaction });
});
}).catch(function(err) {
reject(err);
});
});
}

86
app/api/rpcApi.js

@ -351,35 +351,44 @@ function getRpcData(cmd) {
var client = (cmd == "gettxoutsetinfo" ? global.rpcClientNoTimeout : global.rpcClient);
client.command(cmd, function(err, result, resHeaders) {
if (err) {
utils.logError("32euofeege", err, {cmd:cmd});
try {
if (err) {
logStats(cmd, false, new Date().getTime() - startTime, false);
reject(err);
throw new Error(`RpcError: type=failure-01`);
}
callback();
if (Array.isArray(result) && result.length == 1) {
var result0 = result[0];
if (result0 && result0.name && result0.name == "RpcError") {
logStats(cmd, false, new Date().getTime() - startTime, false);
logStats(cmd, false, new Date().getTime() - startTime, false);
throw new Error(`RpcError: type=errorResponse-01`);
}
}
return;
}
if (result.name && result.name == "RpcError") {
logStats(cmd, false, new Date().getTime() - startTime, false);
if (result.name && result.name == "RpcError") {
utils.logError("3084yh4r7ge", result, {cmd:cmd});
throw new Error(`RpcError: type=errorResponse-02`);
}
reject(result);
resolve(result);
logStats(cmd, false, new Date().getTime() - startTime, true);
callback();
logStats(cmd, false, new Date().getTime() - startTime, false);
} catch (e) {
e.userData = {error:err, request:cmd, result:result};
return;
}
utils.logError("9u4278t5h7rfhgf", e, {error:err, request:cmd, result:result});
resolve(result);
reject(e);
logStats(cmd, false, new Date().getTime() - startTime, true);
callback();
callback();
}
});
};
@ -395,35 +404,44 @@ function getRpcDataWithParams(request) {
rpcCall = function(callback) {
global.rpcClient.command([request], function(err, result, resHeaders) {
if (err != null) {
utils.logError("38eh39hdee", err, {result:result, headers:resHeaders});
try {
if (err != null) {
logStats(request.method, true, new Date().getTime() - startTime, false);
reject(err);
throw new Error(`RpcError: type=failure-02`);
}
callback();
if (Array.isArray(result) && result.length == 1) {
var result0 = result[0];
logStats(request.method, true, new Date().getTime() - startTime, false);
if (result0 && result0.name && result0.name == "RpcError") {
logStats(request.method, true, new Date().getTime() - startTime, false);
return;
}
throw new Error(`RpcError: type=errorResponse-03`);
}
}
if (result.name && result.name == "RpcError") {
utils.logError("23983euewf8d", result, {result:result, headers:resHeaders});
if (result.name && result.name == "RpcError") {
logStats(request.method, true, new Date().getTime() - startTime, false);
reject(result);
throw new Error(`RpcError: type=errorResponse-04`);
}
callback();
resolve(result[0]);
logStats(request.method, true, new Date().getTime() - startTime, false);
logStats(request.method, true, new Date().getTime() - startTime, true);
return;
}
callback();
resolve(result[0]);
} catch (e) {
e.userData = {error:err, request:request, result:result};
logStats(request.method, true, new Date().getTime() - startTime, true);
utils.logError("283h7ewsede", e, {error:err, request:request, result:result});
callback();
reject(e);
callback();
}
});
};

25
routes/baseActionsRouter.js

@ -646,6 +646,11 @@ router.get("/block-height/:blockHeight", function(req, res, next) {
res.locals.result.txInputsByTransaction = result.txInputsByTransaction;
resolve();
}).catch(function(err) {
res.locals.pageErrors.push(utils.logError("98493y4758h55", err));
reject(err);
});
}));
@ -656,7 +661,7 @@ router.get("/block-height/:blockHeight", function(req, res, next) {
resolve();
}).catch(function(err) {
res.locals.userMessage = "Error getting block stats";
res.locals.pageErrors.push(utils.logError("983yr435r76d", err));
reject(err);
});
@ -668,13 +673,15 @@ router.get("/block-height/:blockHeight", function(req, res, next) {
next();
}).catch(function(err) {
res.locals.pageErrors.push(utils.logError("3249y2ewgfee", err));
res.locals.userMessageMarkdown = `Failed loading block: height=**${blockHeight}**`;
res.render("block");
next();
});
}).catch(function(err) {
res.locals.userMessageMarkdown = `Failed loading block: height=**${blockHeight}**`;
res.locals.pageErrors.push(utils.logError("389wer07eghdd", err));
res.render("block");
@ -723,8 +730,8 @@ router.get("/block/:blockHash", function(req, res, next) {
resolve();
}).catch(function(err) {
res.locals.userMessage = "Error getting block data";
res.locals.pageErrors.push(utils.logError("238h38sse", err));
reject(err);
});
}));
@ -736,8 +743,8 @@ router.get("/block/:blockHash", function(req, res, next) {
resolve();
}).catch(function(err) {
res.locals.userMessage = "Error getting block stats";
res.locals.pageErrors.push(utils.logError("21983ue8hye", err));
reject(err);
});
}));
@ -748,7 +755,7 @@ router.get("/block/:blockHash", function(req, res, next) {
next();
}).catch(function(err) {
res.locals.pageErrors.push(utils.logError("3217wfeghy9sdgs", err));
res.locals.userMessageMarkdown = `Failed to load block: **${blockHash}**`;
res.render("block");
@ -867,7 +874,7 @@ router.get("/tx/:transactionId", function(req, res, next) {
});
}).catch(function(err) {
res.locals.userMessage = "Failed to load transaction with txid=" + txid + ": " + err;
res.locals.userMessageMarkdown = `Failed to load transaction: txid=**${txid}**`;
res.locals.pageErrors.push(utils.logError("1237y4ewssgt", err));
@ -1152,7 +1159,7 @@ router.get("/address/:address", function(req, res, next) {
}).catch(function(err) {
res.locals.pageErrors.push(utils.logError("2108hs0gsdfe", err, {address:address}));
res.locals.userMessage = "Failed to load address " + address + " (" + err + ")";
res.locals.userMessageMarkdown = `Failed to load address: **${address}**`;
res.render("address");

2
views/address.pug

@ -6,7 +6,7 @@ block headContent
block content
if (result && result.validateaddress)
if (!result.validateaddress.isvalid)
div.alert.alert-danger.border-danger.mb-huge
div.alert.alert-danger.mb-huge
h1.h6.font-weight-bold Invalid Address
span.text-monospace #{address}

18
views/block.pug

@ -1,13 +1,17 @@
extends layout
block headContent
title Block ##{result.getblock.height.toLocaleString()}, #{result.getblock.hash}
if (result.getblock)
title Block ##{result.getblock.height.toLocaleString()}, #{result.getblock.hash}
else
title Block: Error
block content
h1.h3 Block
small.text-monospace(style="width: 100%;") ##{result.getblock.height.toLocaleString()}
br
small.text-monospace.word-wrap(style="width: 100%;") #{result.getblock.hash}
hr
if (result.getblock)
h1.h3 Block
small.text-monospace(style="width: 100%;") ##{result.getblock.height.toLocaleString()}
br
small.text-monospace.word-wrap(style="width: 100%;") #{result.getblock.hash}
hr
include includes/block-content.pug
include includes/block-content.pug

47
views/includes/page-errors-modal.pug

@ -8,27 +8,38 @@ div.modal.fade(id="pageErrorsModal" role="dialog" aria-hidden="true")
span(aria-hidden="true") ×
div.modal-body
each item, itemIndex in pageErrors
div.card.shadow-sm(class=(itemIndex < (pageErrors.length - 1) ? "mb-3" : false))
div.card-header
h6.mb-0 Error ##{(itemIndex + 1).toLocaleString()}
div.card-body
h6 Error Details
pre
code.json.bg-light #{JSON.stringify(item.error, null, 4)}
if (item.error.stack)
hr
h6 Stacktrace
pre
code.json.bg-light #{item.error.stack}
if (false)
pre
code.json #{JSON.stringify(pageErrors, null, 4)}
if (item.error.userData)
if (true)
each item, itemIndex in pageErrors
div.card.shadow-sm(class=(itemIndex < (pageErrors.length - 1) ? "mb-3" : false))
div.card-body
h6 Error ##{(itemIndex + 1).toLocaleString()}
hr
//pre
// code.json.bg-light #{JSON.stringify(item.error, null, 4)}
//pre
// code.json.bg-light #{JSON.stringify(item, null, 4)}
if (item.error.userData)
div.mb-3
h4.h6 Error Data
div.highlight
pre
code.json.bg-light #{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}
h4.h6 User Data
pre
code.json.bg-light #{JSON.stringify(item.error.userData, null, 4)}
div.modal-footer
button.btn.btn-secondary(type="button" data-dismiss="modal") Close

Loading…
Cancel
Save