Fixed Bcoin error returned as data, fixed dead /txs endpoint missing error, added ttl to bcoin requests but large addrs still take too long

This commit is contained in:
tenthirtyone 2017-08-16 16:30:33 -04:00
parent c47f58f8e8
commit 2ac70bc9a2
5 changed files with 141 additions and 155 deletions

View File

@ -29,6 +29,7 @@ const config = {
ticker_prop: 'bitstamp', ticker_prop: 'bitstamp',
max_blocks: 72, max_blocks: 72,
max_txs: 10, max_txs: 10,
request_ttl: 100000,
}, },
}; };

View File

@ -3,12 +3,14 @@ const request = require('request');
const config = require('../../config'); const config = require('../../config');
const API_URL = `http://${config.bcoin_http}:${config.bcoin['http-port']}`; const API_URL = `http://${config.bcoin_http}:${config.bcoin['http-port']}`;
const TTL = config.api.request_ttl;
module.exports = function AddressAPI(router) { module.exports = function AddressAPI(router) {
router.get('/addr/:addr', (req, res) => { router.get('/addr/:addr', (req, res) => {
const addr = req.params.addr || ''; const addr = req.params.addr || '';
// Get Bcoin data // Get Bcoin data
return request(`${API_URL}/tx/address/${addr}`, return request(`${API_URL}/tx/address/${addr}`,
{ timeout: TTL },
(error, bcoinRes, bcoinTxs) => { (error, bcoinRes, bcoinTxs) => {
if (error) { if (error) {
logger.log('error', logger.log('error',

View File

@ -5,6 +5,7 @@ const db = require('../db');
const API_URL = `http://${config.bcoin_http}:${config.bcoin['http-port']}`; const API_URL = `http://${config.bcoin_http}:${config.bcoin['http-port']}`;
const MAX_TXS = config.api.max_txs; const MAX_TXS = config.api.max_txs;
const TTL = config.api.request_ttl;
module.exports = function transactionAPI(router) { module.exports = function transactionAPI(router) {
// Txs by txid // Txs by txid
@ -18,50 +19,52 @@ module.exports = function transactionAPI(router) {
} }
const height = blockHeight; const height = blockHeight;
// Bcoin transaction data // Bcoin transaction data
return request(`${API_URL}/tx/${req.params.txid}`, (error, localRes, tx) => { return request(`${API_URL}/tx/${req.params.txid}`,
if (error) { { timeout: TTL },
logger.log('error', (error, localRes, tx) => {
`${error}`); if (error) {
return res.status(404).send(); logger.log('error',
} `${error}`);
// Catch JSON errors return res.status(404).send();
try { }
tx = JSON.parse(tx); // Catch JSON errors
} catch (e) { try {
logger.log('error', tx = JSON.parse(tx);
`${e}`); } catch (e) {
return res.status(404).send(); logger.log('error',
} `${e}`);
if (!tx || !tx.hash) { return res.status(404).send();
logger.log('error', }
'No results found'); if (!tx || !tx.hash) {
return res.status(404).send(); logger.log('error',
} 'No results found');
return res.status(404).send();
}
// Return UI JSON // Return UI JSON
return res.send({ return res.send({
txid: tx.hash, txid: tx.hash,
version: tx.version, version: tx.version,
time: tx.ps, time: tx.ps,
blocktime: tx.ps, blocktime: tx.ps,
locktime: tx.locktime, locktime: tx.locktime,
blockhash: tx.block, blockhash: tx.block,
fees: tx.fee / 1e8, fees: tx.fee / 1e8,
confirmations: (height - tx.height) + 1, confirmations: (height - tx.height) + 1,
valueOut: tx.outputs.reduce((sum, output) => sum + output.value, 0) / 1e8, valueOut: tx.outputs.reduce((sum, output) => sum + output.value, 0) / 1e8,
vin: tx.inputs.map(input => ({ vin: tx.inputs.map(input => ({
addr: input.coin ? input.coin.address : '', addr: input.coin ? input.coin.address : '',
value: input.coin ? input.coin.value / 1e8 : 0, value: input.coin ? input.coin.value / 1e8 : 0,
})), })),
vout: tx.outputs.map(output => ({ vout: tx.outputs.map(output => ({
scriptPubKey: { scriptPubKey: {
addresses: [output.address], addresses: [output.address],
}, },
value: output.value / 1e8, value: output.value / 1e8,
})), })),
isCoinBase: tx.inputs[0].prevout.hash === '0000000000000000000000000000000000000000000000000000000000000000', isCoinBase: tx.inputs[0].prevout.hash === '0000000000000000000000000000000000000000000000000000000000000000',
});
}); });
});
}); });
}); });
@ -83,49 +86,53 @@ module.exports = function transactionAPI(router) {
} }
const height = blockHeight; const height = blockHeight;
// Get Bcoin data // Get Bcoin data
return request(`${API_URL}/block/${req.query.block}`, (error, localRes, block) => { return request(`${API_URL}/block/${req.query.block}`,
if (error) { { timeout: TTL },
logger.log('error', (error, localRes, block) => {
`${error}`); if (error) {
} logger.log('error',
// Catch JSON errors `${error}`);
try { return res.status(404).send();
block = JSON.parse(block); }
} catch (e) { // Catch JSON errors
logger.log('error', try {
`${e}`); block = JSON.parse(block);
return res.status(404).send(); } catch (e) {
} logger.log('error',
if (!block.txs.length) { `${e}`);
logger.log('error', return res.status(404).send();
`${'No tx results'}`); }
res.status(404).send();
}
// Setup UI JSON
const totalPages = Math.ceil(block.txs.length / MAX_TXS);
block.txs = block.txs.slice(rangeStart, rangeEnd);
return res.send({ if (block.error) {
pagesTotal: totalPages, logger.log('error',
txs: block.txs.map(tx => ({ `${'No tx results'}`);
txid: tx.hash, return res.status(404).send();
fees: tx.fee / 1e8, }
confirmations: (height - block.height) + 1, // Setup UI JSON
valueOut: tx.outputs.reduce((sum, output) => sum + output.value, 0) / 1e8, const totalPages = Math.ceil(block.txs.length / MAX_TXS);
vin: tx.inputs.map(input => ({ block.txs = block.txs.slice(rangeStart, rangeEnd);
addr: input.coin ? input.coin.address : '',
value: input.coin ? input.coin.value / 1e8 : 0, return res.send({
pagesTotal: totalPages,
txs: block.txs.map(tx => ({
txid: tx.hash,
fees: tx.fee / 1e8,
confirmations: (height - block.height) + 1,
valueOut: tx.outputs.reduce((sum, output) => sum + output.value, 0) / 1e8,
vin: tx.inputs.map(input => ({
addr: input.coin ? input.coin.address : '',
value: input.coin ? input.coin.value / 1e8 : 0,
})),
vout: tx.outputs.map(output => ({
scriptPubKey: {
addresses: [output.address],
},
value: output.value / 1e8,
})),
isCoinBase: tx.inputs[0].prevout.hash === '0000000000000000000000000000000000000000000000000000000000000000',
})), })),
vout: tx.outputs.map(output => ({ });
scriptPubKey: {
addresses: [output.address],
},
value: output.value / 1e8,
})),
isCoinBase: tx.inputs[0].prevout.hash === '0000000000000000000000000000000000000000000000000000000000000000',
})),
}); });
});
}); });
} else if (req.query.address) { } else if (req.query.address) {
// Get txs by address, start with best height to calc confirmations // Get txs by address, start with best height to calc confirmations
@ -139,83 +146,57 @@ module.exports = function transactionAPI(router) {
const height = blockHeight; const height = blockHeight;
const addr = req.query.address || ''; const addr = req.query.address || '';
return request(`${API_URL}/tx/address/${addr}`, (error, localRes, txs) => { logger.log('debug',
if (error) { 'Warning: Requesting data from Bcoin, may take some time');
logger.log('error',
`${error}`); return request(`${API_URL}/tx/address/${addr}`,
return res.status(404).send(); { timeout: TTL },
} (error, localRes, txs) => {
// Catch JSON errors if (error) {
try { logger.log('error',
txs = JSON.parse(txs); `${error}`);
} catch (e) { return res.status(404).send();
logger.log('error', }
`${e}`); // Catch JSON errors
return res.status(404).send(); try {
} txs = JSON.parse(txs);
// Setup UI JSON } catch (e) {
return res.send({ logger.log('error',
pagesTotal: 1, `${e}`);
txs: txs.map(tx => ({ return res.status(404).send();
txid: tx.hash, }
fees: tx.fee / 1e8, // Bcoin returns error as part of data object
confirmations: (height - tx.height) + 1, if (txs.error) {
valueOut: tx.outputs.reduce((sum, output) => sum + output.value, 0) / 1e8, logger.log('error',
vin: tx.inputs.map(input => ({ `${'No tx results'}`);
addr: input.coin ? input.coin.address : '', return res.status(404).send();
value: input.coin ? input.coin.value / 1e8 : 0, }
// Setup UI JSON
return res.send({
pagesTotal: 1,
txs: txs.map(tx => ({
txid: tx.hash,
fees: tx.fee / 1e8,
confirmations: (height - tx.height) + 1,
valueOut: tx.outputs.reduce((sum, output) => sum + output.value, 0) / 1e8,
vin: tx.inputs.map(input => ({
addr: input.coin ? input.coin.address : '',
value: input.coin ? input.coin.value / 1e8 : 0,
})),
vout: tx.outputs.map(output => ({
scriptPubKey: {
addresses: [output.address],
},
value: output.value / 1e8,
})),
isCoinBase: tx.inputs[0].prevout.hash === '0000000000000000000000000000000000000000000000000000000000000000',
})), })),
vout: tx.outputs.map(output => ({ });
scriptPubKey: {
addresses: [output.address],
},
value: output.value / 1e8,
})),
isCoinBase: tx.inputs[0].prevout.hash === '0000000000000000000000000000000000000000000000000000000000000000',
})),
}); });
});
}); });
} else { } else {
// Get last n txs // Get last n txs
db.txs.getTransactions( return res.status(404).send({ error: 'Block hash or address expected' });
{},
{},
MAX_TXS,
(err, txs) => {
if (err) {
logger.log('err',
`getTransactions: ${err}`);
res.status(404).send();
}
return res.json({
pagesTotal: 1,
txs: txs.map(tx => ({
txid: tx.hash,
version: tx.version,
locktime: tx.locktime,
vin: tx.inputs.map(input => ({
coinbase: input.script,
sequence: input.sequence,
n: 0,
})),
vout: tx.outputs.map(output => ({
value: output.value,
n: 0,
scriptPubKey: {
hex: '',
asm: '',
addresses: [output.address],
type: output.type,
},
spentTxid: '',
spentIndex: 0,
spentHeight: 0,
})),
})),
});
},
);
} }
}); });

View File

@ -21,6 +21,7 @@ function getBlocks(params, options, limit, cb) {
if (limit < 1) { if (limit < 1) {
limit = 1; limit = 1;
} }
// Query mongo // Query mongo
Block.find( Block.find(
params, params,
@ -59,7 +60,7 @@ function getBestHeight(cb) {
if (err) { if (err) {
logger.log('error', logger.log('error',
`getBlock: ${err.err}`); `getBlock: ${err.err}`);
return cb(err); return cb(err, null);
} }
return cb(null, block.height); return cb(null, block.height);
}); });

View File

@ -26,6 +26,7 @@ function getTransactions(params, options, limit, cb) {
params, params,
defaultOptions, defaultOptions,
(err, txs) => { (err, txs) => {
console.log(txs)
if (err) { if (err) {
logger.log('error', logger.log('error',
`getTransactions: ${err}`); `getTransactions: ${err}`);