diff --git a/server/lib/api/address.js b/server/lib/api/address.js index 722adb2..d9c93c2 100644 --- a/server/lib/api/address.js +++ b/server/lib/api/address.js @@ -1,6 +1,7 @@ const logger = require('../logger'); const request = require('request'); const config = require('../../config'); +const db = require('../db'); const API_URL = `http://${config.bcoin_http}:${config.bcoin['http-port']}`; const TTL = config.api.request_ttl; @@ -8,8 +9,18 @@ const TTL = config.api.request_ttl; module.exports = function AddressAPI(router) { router.get('/addr/:addr', (req, res) => { const addr = req.params.addr || ''; - logger.log('debug', - 'Warning: Requesting data from Bcoin by address, may take some time'); + /* + db.txs.getTxByAddress(addr, 0, 999999999, (error, txs) => { + if (error) { + logger.log('err', + `getTxByBlock ${error}`); + return res.status(404).send(); + } + + console.log(txs.count()); + + }); +*/ // Get Bcoin data return request(`${API_URL}/tx/address/${addr}`, { timeout: TTL }, diff --git a/server/lib/api/transaction.js b/server/lib/api/transaction.js index 1c92b25..26cf635 100644 --- a/server/lib/api/transaction.js +++ b/server/lib/api/transaction.js @@ -19,9 +19,9 @@ module.exports = function transactionAPI(router) { if (err) { logger.log('err', `getTxById: ${err}`); - return res.status(400).send(); + return res.status(404).send(); } - console.log(transaction); + const tx = transaction; return res.send({ txid: tx.hash, @@ -31,6 +31,7 @@ module.exports = function transactionAPI(router) { locktime: tx.locktime, blockhash: tx.block, fees: tx.fee / 1e8, + size: tx.size, confirmations: (height - tx.height) + 1, valueOut: tx.outputs.reduce((sum, output) => sum + output.value, 0) / 1e8, vin: tx.inputs.map(input => ({ @@ -59,43 +60,32 @@ module.exports = function transactionAPI(router) { // get txs for blockhash, start with best height to calc confirmations if (req.query.block) { const height = db.blocks.bestHeight(); - // Get Bcoin data - return request(`${API_URL}/block/${req.query.block}`, - { timeout: TTL }, - (error, localRes, block) => { + + db.txs.getTxCountByBlock(req.query.block, (err, count) => { + if (err) { + logger.log('err', + `getTxByBlock ${err}`); + return res.status(404).send(); + } + const totalPages = Math.ceil(count / MAX_TXS); + + return db.txs.getTxByBlock(req.query.block, pageNum, MAX_TXS, (error, txs) => { if (error) { - logger.log('error', - `${error}`); + logger.log('err', + `getTxByBlock ${error}`); return res.status(404).send(); } - // Catch JSON errors - try { - block = JSON.parse(block); - } catch (e) { - logger.log('error', - `${e}`); - return res.status(404).send(); - } - - if (block.error) { - logger.log('error', - `${'No tx results'}`); - return 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({ pagesTotal: totalPages, - txs: block.txs.map(tx => ({ + txs: txs.map(tx => ({ txid: tx.hash, fees: tx.fee / 1e8, - confirmations: (height - block.height) + 1, + size: tx.size, + 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, + addr: input.address, + value: input.value / 1e8, })), vout: tx.outputs.map(output => ({ scriptPubKey: { @@ -107,47 +97,37 @@ module.exports = function transactionAPI(router) { })), }); }); + }); } else if (req.query.address) { // Get txs by address, start with best height to calc confirmations const height = db.blocks.bestHeight(); const addr = req.query.address || ''; - logger.log('debug', - 'Warning: Requesting data from Bcoin by address, may take some time'); + db.txs.getTxCountByAddress(req.query.address, (err, count) => { + if (err) { + logger.log('err', + `getTxByBlock ${err}`); + return res.status(404).send(); + } + const totalPages = Math.ceil(count / MAX_TXS); - return request(`${API_URL}/tx/address/${addr}`, - { timeout: TTL }, - (error, localRes, txs) => { + return db.txs.getTxByAddress(req.query.address, pageNum, MAX_TXS, (error, txs) => { if (error) { - logger.log('error', - `${error}`); + logger.log('err', + `getTxByBlock ${error}`); return res.status(404).send(); } - // Catch JSON errors - try { - txs = JSON.parse(txs); - } catch (e) { - logger.log('error', - `${e}`); - return res.status(404).send(); - } - // Bcoin returns error as part of data object - if (txs.error) { - logger.log('error', - `${'No tx results'}`); - return res.status(404).send(); - } - // Setup UI JSON return res.send({ - pagesTotal: 1, + pagesTotal: totalPages, txs: txs.map(tx => ({ txid: tx.hash, fees: tx.fee / 1e8, - confirmations: (height - tx.height) + 1, + size: tx.size, + 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, + addr: input.address, + value: input.value / 1e8, })), vout: tx.outputs.map(output => ({ scriptPubKey: { @@ -159,9 +139,11 @@ module.exports = function transactionAPI(router) { })), }); }); + }); + } else { + // Get last n txs + return res.status(404).send({ error: 'Block hash or address expected' }); } - // Get last n txs - return res.status(404).send({ error: 'Block hash or address expected' }); }); router.get('/rawtx/:txid', (req, res) => { @@ -178,7 +160,7 @@ module.exports = function transactionAPI(router) { if (err) { logger.log('error', `${err}`); - res.status(400).send(err); + res.status(404).send(err); return; } diff --git a/server/lib/db/transactions.js b/server/lib/db/transactions.js index 0bbfbd7..c41c9ff 100644 --- a/server/lib/db/transactions.js +++ b/server/lib/db/transactions.js @@ -2,9 +2,11 @@ const Transactions = require('../../models/transaction.js'); const logger = require('../logger'); const config = require('../../config'); +// Will be replaced with a more sophisticated api soon + const MAX_TXS = config.api.max_txs; -function getTransactions(params, options, limit, cb) { +function getTransactions(params, options, limit, skip, cb) { // Do not return mongo ids const defaultOptions = { _id: 0 }; // Copy over mongo options @@ -36,12 +38,13 @@ function getTransactions(params, options, limit, cb) { } return cb(null, txs); }) - .sort({ height: -1 }) + .sort({ height: 1 }) + .skip() .limit(limit); } -function getTransaction(params, options, limit, cb) { - getTransactions(params, options, limit, (err, tx) => { +function getTransaction(params, options, limit, skip, cb) { + getTransactions(params, options, limit, skip, (err, tx) => { if (err) { logger.log('error', `getTransaction: ${err.err}`); @@ -59,6 +62,7 @@ function getTxById(txid, cb) { { hash: txid }, {}, 1, + 0, (err, transaction) => { if (err) { logger.log('err', @@ -69,6 +73,78 @@ function getTxById(txid, cb) { }); } +function getTxByBlock(blockHash, page, limit, cb) { + getTransactions( + { block: blockHash }, + {}, + limit, + page * limit, + (err, tx) => { + if (err) { + logger.log('error', + `getTxByBlock: ${err.err}`); + return cb(err); + } + if (!tx.length > 0) { + return cb({ err: 'Tx not found' }); + } + return cb(null, tx); + }); +} + +function getTxByAddress(address, page, limit, cb) { + getTransactions( + { + $or: [ + { 'inputs.address': address }, + { 'outputs.address': address }], + }, + {}, + limit, + page * limit, + (err, tx) => { + if (err) { + logger.log('error', + `getTxByAddress: ${err.err}`); + return cb(err); + } + if (!tx.length > 0) { + return cb({ err: 'Tx not found' }); + } + return cb(null, tx); + }); +} + +function getTxCountByBlock(blockHash, cb) { + Transactions.count( + { block: blockHash }, + (err, count) => { + if (err) { + logger.log('err', + `getTxCountByBlock ${err}`); + return cb(err); + } + return cb(null, count); + }); +} + +function getTxCountByAddress(address, cb) { + Transactions.count( + { $or: [ + { 'inputs.address': address }, + { 'outputs.address': address }], + }, + (err, count) => { + if (err) { + logger.log('err', + `getTxCountByAddress ${err}`); + return cb(err); + } + return cb(null, count); + }); +} + + function updateInput(txid, inputid, value, address) { Transactions.findOneAndUpdate( { _id: txid, 'inputs._id': inputid }, @@ -91,5 +167,9 @@ module.exports = { getTransaction, getTransactions, getTxById, + getTxByBlock, + getTxCountByBlock, + getTxByAddress, + getTxCountByAddress, updateInput, }; diff --git a/server/lib/node/index.js b/server/lib/node/index.js index c7a2415..2e53167 100644 --- a/server/lib/node/index.js +++ b/server/lib/node/index.js @@ -24,6 +24,10 @@ function start() { db.blocks.bestHeight(entry.height); }); + node.chain.on('full', (block) => { + + }); + node.on('error', (err) => { logger.log('error', `${err}`); diff --git a/server/lib/parser/transaction.js b/server/lib/parser/transaction.js index 993e825..4283d81 100644 --- a/server/lib/parser/transaction.js +++ b/server/lib/parser/transaction.js @@ -6,6 +6,12 @@ const util = require('../../lib/util'); const logger = require('../logger'); const db = require('../db'); +// Bleh, Bcoin pulls in blocks 20 at a time +// Crappy delay for now otherwise async saves +// could miss a tx if an input refs a block within +// the last 20 that hasn't saved. +// Aggregate stuff will replace all of this. + function parse(entry, txs) { txs.forEach((tx) => { const txJSON = tx.toJSON(); @@ -52,23 +58,6 @@ function parse(entry, txs) { if (err) { logger.log('error', err.message); } - - t.inputs.forEach((input) => { - const txid = input.prevout.hash; - const idx = input.prevout.index; - const addr = input.address; - if (txid !== '0000000000000000000000000000000000000000000000000000000000000000') { - db.txs.getTxById(txid, (err, tx) => { - if (err) { - logger.log('err', - `Tx Parser inputs.ForEach: ${err}`); - return; - } - - db.txs.updateInput(t._id, input._id, tx.outputs[idx].value, tx.outputs[idx].address); - }); - } - }); }); }); } diff --git a/server/public/img/leveldb.png b/server/public/img/leveldb.png index da13a67..b4a1777 100644 Binary files a/server/public/img/leveldb.png and b/server/public/img/leveldb.png differ