All API but tx & socket cleaned up, blocks db api done

This commit is contained in:
tenthirtyone 2017-08-15 23:14:24 -04:00
parent ecee54c10b
commit b0f95d93ab
10 changed files with 172 additions and 189 deletions

View File

@ -1,66 +1,44 @@
const Block = require('../../models/block.js');
const logger = require('../logger'); const logger = require('../logger');
const db = require('../db');
const MAX_BLOCKS = 100;
function getBlock(params, options, limit, cb) {
const defaultOptions = { _id: 0 };
if (!Number.isInteger(limit)) {
limit = MAX_BLOCKS;
}
Object.assign(defaultOptions, options);
Block.find(
params,
defaultOptions,
cb)
.sort({ height: -1 })
.limit(limit);
}
module.exports = function BlockAPI(router) { module.exports = function BlockAPI(router) {
router.get('/block/:blockHash', (req, res) => { router.get('/block/:blockHash', (req, res) => {
getBlock( db.blocks.getBlock(
{ hash: req.params.blockHash }, { hash: req.params.blockHash },
{ rawBlock: 0 }, { rawBlock: 0 },
MAX_BLOCKS, 1,
(err, block) => { (err, block) => {
if (err) { if (err) {
res.status(501).send();
logger.log('err', err); logger.log('err', err);
return res.status(404).send();
} }
if (block[0]) {
const b = block[0]; return res.json({
res.json({ hash: block.hash,
hash: b.hash, size: block.size,
size: b.size, height: block.height,
height: b.height, version: block.version,
version: b.version, merkleroot: block.merkleRoot,
merkleroot: b.merkleRoot, tx: block.txs,
tx: b.txs, time: block.ts,
time: b.ts, nonce: block.nonce,
nonce: b.nonce, bits: block.bits.toString(16),
bits: b.bits.toString(16), difficulty: 1,
difficulty: 1, chainwork: block.chainwork.toString(16),
chainwork: b.chainwork.toString(16), confirmations: 0,
confirmations: 0, previousblockhash: block.prevBlock,
previousblockhash: b.prevBlock, nextblockhash: 0,
nextblockhash: 0, reward: block.reward / 1e8,
reward: b.reward / 1e8, isMainChain: true,
isMainChain: true, poolInfo: {},
poolInfo: {}, });
});
} else {
res.status(404).send('Not Found');
}
}); });
}); });
router.get('/blocks', (req, res) => { router.get('/blocks', (req, res) => {
const limit = parseInt(req.query.limit) || MAX_BLOCKS; const limit = parseInt(req.query.limit) || 100;
getBlock(
db.blocks.getBlocks(
{}, {},
{ height: 1, { height: 1,
size: 1, size: 1,
@ -72,59 +50,59 @@ module.exports = function BlockAPI(router) {
limit, limit,
(err, blocks) => { (err, blocks) => {
if (err) { if (err) {
res.status(501).send(); logger.log('err',
logger.log('err', err); `/blocks: ${err}`);
return; return res.status(404).send();
} }
res.json({ return res.json({
blocks: blocks.map(block => ({ blocks: blocks.map(block => ({
hash: block.hash, hash: block.hash,
height: block.height, height: block.height,
size: block.size, size: block.size,
time: block.ts, time: block.ts,
txlength: block.txs.length, txlength: block.txs.length,
poolInfo: {}, poolInfo: {},
})), })),
length: blocks.length, length: blocks.length,
pagination: {}, pagination: {},
}); });
}); });
}); });
router.get('/rawblock/:blockHash', (req, res) => { router.get('/rawblock/:blockHash', (req, res) => {
getBlock( const blockHash = req.params.blockHash || '';
{ hash: req.params.blockHash },
db.blocks.getBlock(
{ hash: blockHash },
{ rawBlock: 1 }, { rawBlock: 1 },
MAX_BLOCKS, 1,
(err, block) => { (err, block) => {
if (err) { if (err) {
res.status(501).send(); logger.log('err',
logger.log('err', err); `/rawblock/:blockHash: ${err}`);
return res.status(404).send();
} }
res.json(block[0]); return res.json(block);
}); });
}); });
router.get('/block-index/:height', (req, res) => { router.get('/block-index/:height', (req, res) => {
let blockHeight = parseInt(req.params.height) || 1; const blockHeight = parseInt(req.params.height) || 1;
getBlock( db.blocks.getBlock(
{ height: blockHeight }, { height: blockHeight },
{ hash: 1 }, { hash: 1 },
MAX_BLOCKS, 1,
(err, block) => { (err, block) => {
if (err) { if (err) {
res.status(501).send(); logger.log('err',
logger.log('err', err); `/block-index/:height: ${err}`);
} return res.status(404).send();
if (block[0]) {
res.json({
blockHash: block[0].hash,
});
} else {
res.status(404).send('Not Found');
} }
return res.json({
blockHash: block.hash,
});
}); });
}); });
}; };

View File

@ -13,18 +13,7 @@ app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json()); app.use(bodyParser.json());
// Serve insight ui front end from root dir public folder // Serve insight ui front end from root dir public folder
app.use('/', express.static('./public')); app.use(express.static('./public'));
app.use('/:stuff', express.static('./public'));
app.use('/blocks', express.static('./public'));
app.use('/blocks/:blockhash', express.static('./public'));
app.use('/block-index', express.static('./public'));
app.use('/block-index/:height', express.static('./public'));
app.use('/blocks-date/:date', express.static('./public'));
app.use('/block/:blockhash', express.static('./public'));
app.use('/tx/:txid', express.static('./public'));
app.use('/address/:addr', express.static('./public'));
app.use('/status', express.static('./public'));
app.use('/status/:stuff', express.static('./public'));
app.set('json spaces', config.api.json_spaces); app.set('json spaces', config.api.json_spaces);

View File

@ -1,87 +1,99 @@
const request = require('request'); const request = require('request');
const Block = require('../../models/block');
const pkg = require('../../package.json'); const pkg = require('../../package.json');
const config = require('../../config'); const config = require('../../config');
const netCfg = require('bcoin/lib/net/common'); const netCfg = require('bcoin/lib/net/common');
const logger = require('../logger'); const logger = require('../logger');
const db = require('../db');
const API_URL = `http://${config.bcoin_http}:${config.bcoin['http-port']}/`;
// Here comes the ugly. Moo who haha
function getStatus(cb) { function getStatus(cb) {
request(`http://${config.bcoin_http}:${config.bcoin['http-port']}/`, (err, localRes, body) => { request(`${API_URL}`, (err, localRes, status) => {
if (err) { if (err) {
logger.log('error', logger.log('error',
`${err}`); `getStatus ${err}`);
return cb(err);
} }
try { try {
body = JSON.parse(body); status = JSON.parse(status);
} catch (e) { } catch (e) {
logger.log('error', logger.log('error',
`${err}`); `getStatus JSON.parse: ${e}`);
cb(e); return cb(e);
} }
cb(null, body); return cb(null, status);
}); });
} }
// UI assigns Multiple Responsibilities depending on params
module.exports = function statusAPI(router) { module.exports = function statusAPI(router) {
router.get('/status', (req, res) => { router.get('/status', (req, res) => {
if (req.query.q === 'getLastBlockHash') { if (req.query.q === 'getLastBlockHash') {
Block.findOne({}, { 'hash': 1 }, { sort: { 'height': -1 } }, (err, block) => { db.blocks.getBlock(
if (err) { {},
logger.log('error', { hash: 1 },
`${err}`); 1,
res.status(501).send(err); (err, block) => {
} else { if (err) {
res.send({ logger.log('error',
`${err}`);
return res.status(404).send(err);
}
return res.send({
syncTipHash: block.hash, syncTipHash: block.hash,
lastblockhash: block.hash, lastblockhash: block.hash,
}); });
} });
});
} else { } else {
getStatus((err, status) => { getStatus((err, status) => {
if (err) { if (err) {
res.status(501).send(err); logger.log('err'
} else if (status) { `/status getStatus: ${err}`);
res.json({ return res.status(404).send(err);
info: {
version: status.version,
protocolversion: netCfg.PROTOCOL_VERSION,
blocks: status.chain.height,
timeoffset: status.time.offset,
connections: status.pool.outbound,
proxy: '',
difficulty: 0,
testnet: status.network !== 'main',
relayfee: 0,
errors: '',
network: status.network,
},
});
} else {
res.send();
} }
if (!status) {
logger.log('err'
`/status getStatus: no Status`);
return res.status(404).send();
}
res.json({
info: {
version: status.version,
protocolversion: netCfg.PROTOCOL_VERSION,
blocks: status.chain.height,
timeoffset: status.time.offset,
connections: status.pool.outbound,
proxy: '',
difficulty: 0,
testnet: status.network !== 'main',
relayfee: 0,
errors: '',
network: status.network,
},
});
}); });
} }
}); });
router.get('/sync', (req, res) => { router.get('/sync', (req, res) => {
getStatus((err, status) => { getStatus((err, status) => {
if (err) { if (err) {
res.status(501).send(err); logger.log('err',
} else if (status) { `/sync: ${err}`);
res.json({ return res.status(404).send(err);
status: 'syncing',
blockChainHeight: status.chain.height,
syncPercentage: Math.round(status.chain.progress * 100),
height: status.chain.height,
error: null,
type: 'bcoin node',
});
} else {
res.send();
} }
if (!status) {
logger.log('err',
'/sync: no status');
return res.status(404).send();
}
res.json({
status: status.chain.progress === 100 ? 'synced' : 'syncing',
blockChainHeight: status.chain.height,
syncPercentage: Math.round(status.chain.progress * 100),
height: status.chain.height,
error: null,
type: 'bcoin node',
});
}); });
}); });

View File

@ -47,7 +47,7 @@ module.exports = function transactionAPI(router) {
1, 1,
(err, block) => { (err, block) => {
if (err) { if (err) {
res.status(501).send(); res.status(404).send();
logger.log('err', err); logger.log('err', err);
} }
if (block[0]) { if (block[0]) {
@ -63,7 +63,7 @@ module.exports = function transactionAPI(router) {
} catch (e) { } catch (e) {
logger.log('error', logger.log('error',
`${err}`); `${err}`);
res.status(501).send(); res.status(404).send();
return; return;
} }
if (!body || !body.hash) { if (!body || !body.hash) {
@ -112,7 +112,7 @@ module.exports = function transactionAPI(router) {
1, 1,
(err, block) => { (err, block) => {
if (err) { if (err) {
res.status(501).send(); res.status(404).send();
logger.log('err', err); logger.log('err', err);
} }
if (block[0]) { if (block[0]) {
@ -127,12 +127,12 @@ module.exports = function transactionAPI(router) {
} catch (e) { } catch (e) {
logger.log('error', logger.log('error',
`${err}`); `${err}`);
res.status(501).send(); res.status(404).send();
} }
if (!body.txs.length) { if (!body.txs.length) {
logger.log('error', logger.log('error',
`${'No tx results'}`); `${'No tx results'}`);
res.status(501).send(); res.status(404).send();
} }
const totalPages = Math.ceil(body.txs.length / MAX_TXS); const totalPages = Math.ceil(body.txs.length / MAX_TXS);
body.txs = body.txs.slice(rangeStart, rangeEnd); body.txs = body.txs.slice(rangeStart, rangeEnd);
@ -167,7 +167,7 @@ module.exports = function transactionAPI(router) {
1, 1,
(err, block) => { (err, block) => {
if (err) { if (err) {
res.status(501).send(); res.status(404).send();
logger.log('err', err); logger.log('err', err);
} }
if (block[0]) { if (block[0]) {
@ -212,7 +212,7 @@ module.exports = function transactionAPI(router) {
{}, {},
(err, txs) => { (err, txs) => {
if (err) { if (err) {
res.status(501).send(); res.status(404).send();
} }
res.json({ res.json({
pagesTotal: 1, pagesTotal: 1,

View File

@ -3,7 +3,7 @@ const logger = require('../logger');
const config = require('../../config'); const config = require('../../config');
// move to config // move to config
const MAX_BLOCKS = 200; const MAX_BLOCKS = 50;
const blockTemplate = new Block(); const blockTemplate = new Block();
function getBlocks(params, options, limit, cb) { function getBlocks(params, options, limit, cb) {
@ -12,13 +12,17 @@ function getBlocks(params, options, limit, cb) {
Object.assign(defaultOptions, options); Object.assign(defaultOptions, options);
if (!Number.isInteger(limit)) { if (!Number.isInteger(limit)) {
limit = MAX_BLOCKS; limit = 1;
} }
if (limit > MAX_BLOCKS) { if (limit > MAX_BLOCKS) {
limit = MAX_BLOCKS; limit = MAX_BLOCKS;
} }
if (limit < 1) {
limit = 1;
}
Block.find( Block.find(
params, params,
defaultOptions, defaultOptions,
@ -28,10 +32,10 @@ function getBlocks(params, options, limit, cb) {
`getBlocks: ${err}`); `getBlocks: ${err}`);
return cb(err); return cb(err);
} }
if (blocks.length > 0) { if (!blocks.length > 0) {
return cb(null, blocks); return cb({err: 'Block not found'});
} }
return cb(null, [blockTemplate]); return cb(null, blocks);
}) })
.sort({ height: -1 }) .sort({ height: -1 })
.limit(limit); .limit(limit);

View File

@ -5,9 +5,9 @@ const Output = require('./output');
const Schema = mongoose.Schema; const Schema = mongoose.Schema;
const AddressSchema = new Schema({ const AddressSchema = new Schema({
address: String, address: { type: String, default: '' },
inputs: [Input.schema], inputs: [Input.schema],
outputs: [Output.schema], outputs: [Output.schema],
}); });
const Address = mongoose.model('Address', AddressSchema); const Address = mongoose.model('Address', AddressSchema);

View File

@ -4,21 +4,21 @@ const Transaction = require('./transaction');
const Schema = mongoose.Schema; const Schema = mongoose.Schema;
const BlockSchema = new Schema({ const BlockSchema = new Schema({
hash: String, hash: { type: String, default: '' },
height: Number, height: { type: Number, default: 0 },
size: Number, size: { type: Number, default: 0 },
version: Number, version: { type: Number, default: 0 },
prevBlock: String, prevBlock: { type: String, default: '' },
merkleRoot: String, merkleRoot: { type: String, default: '' },
ts: Number, ts: { type: Number, default: 0 },
bits: Number, bits: { type: Number, default: 0 },
nonce: Number, nonce: { type: Number, default: 0 },
txs: [Transaction.schema], txs: [Transaction.schema],
chainwork: Number, chainwork: { type: Number, default: 0 },
reward: Number, reward: { type: Number, default: 0 },
network: String, network: { type: String, default: '' },
poolInfo: Object, poolInfo: { type: Object, default: {} },
rawBlock: String, rawBlock: { type: String, default: '' },
}, { }, {
toJSON: { toJSON: {
virtuals: true, virtuals: true,

View File

@ -3,11 +3,11 @@ const mongoose = require('mongoose');
const Schema = mongoose.Schema; const Schema = mongoose.Schema;
const InputSchema = new Schema({ const InputSchema = new Schema({
prevout: Object, prevout: { type: Object, default: {} },
script: String, script: { type: String, default: '' },
witness: String, witness: { type: String, default: '' },
sequence: Number, sequence: { type: Number, default: 0 },
address: String, address: { type: String, default: '' },
}); });
const Input = mongoose.model('Input', InputSchema); const Input = mongoose.model('Input', InputSchema);

View File

@ -3,10 +3,10 @@ const mongoose = require('mongoose');
const Schema = mongoose.Schema; const Schema = mongoose.Schema;
const OutputSchema = new Schema({ const OutputSchema = new Schema({
address: String, address: { type: String, default: '' },
script: String, script: { type: String, default: '' },
value: Number, value: { type: Number, default: 0 },
type: String, type: { type: String, default: '' },
}); });
const Output = mongoose.model('Output', OutputSchema); const Output = mongoose.model('Output', OutputSchema);

View File

@ -5,21 +5,21 @@ const Output = require('./output');
const Schema = mongoose.Schema; const Schema = mongoose.Schema;
const TransactionSchema = new Schema({ const TransactionSchema = new Schema({
hash: String, hash: { type: String, default: '' },
witnessHash: String, witnessHash: { type: String, default: '' },
fee: Number, fee: { type: Number, default: 0 },
rate: Number, rate: { type: Number, default: 0 },
ps: Number, ps: { type: Number, default: 0 },
height: Number, height: { type: Number, default: 0 },
block: String, block: { type: String, default: '' },
index: Number, index: { type: Number, default: 0 },
version: Number, version: { type: Number, default: 0 },
flag: Number, flag: { type: Number, default: 0 },
lockTime: Number, lockTime: { type: Number, default: 0 },
inputs: [Input.schema], inputs: [Input.schema],
outputs: [Output.schema], outputs: [Output.schema],
size: Number, size: { type: Number, default: 0 },
network: String, network: { type: String, default: '' },
}); });
const Transaction = mongoose.model('Transaction', TransactionSchema); const Transaction = mongoose.model('Transaction', TransactionSchema);