From 1b0c1b1250d706f0a9766cf7a80af5db93ec5c85 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Wed, 16 Aug 2017 22:49:13 -0400 Subject: [PATCH 01/20] Bringing back other parsers --- server/config/index.js | 2 +- server/lib/api/transaction.js | 77 ++++++++++++++--------------------- server/lib/db/blocks.js | 21 +++++++++- server/lib/parser/block.js | 9 ++++ server/models/input.js | 1 + 5 files changed, 62 insertions(+), 48 deletions(-) diff --git a/server/config/index.js b/server/config/index.js index 827006d..4c45558 100644 --- a/server/config/index.js +++ b/server/config/index.js @@ -4,7 +4,7 @@ const config = { bcoin_http: 'localhost', bcoin: { network: 'main', - db: 'mem', + db: 'leveldb', prefix: '.', checkpoints: true, workers: false, diff --git a/server/lib/api/transaction.js b/server/lib/api/transaction.js index c834902..535ada3 100644 --- a/server/lib/api/transaction.js +++ b/server/lib/api/transaction.js @@ -13,65 +13,50 @@ module.exports = function transactionAPI(router) { // Get max block height for calculating confirmations const height = db.blocks.bestHeight(); // Bcoin transaction data - return request(`${API_URL}/tx/${req.params.txid}`, - { timeout: TTL }, - (error, localRes, tx) => { - if (error) { - logger.log('error', - `${error}`); - return res.status(404).send(); - } - // Catch JSON errors - try { - tx = JSON.parse(tx); - } catch (e) { - logger.log('error', - `${e}`); - return res.status(404).send(); - } - if (!tx || !tx.hash) { - logger.log('error', - 'No results found'); - return res.status(404).send(); - } + const txid = req.params.txid || ''; - // Return UI JSON - return res.send({ - txid: tx.hash, - version: tx.version, - time: tx.ps, - blocktime: tx.ps, - locktime: tx.locktime, - blockhash: tx.block, - 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', - }); + db.blocks.getTxById(txid, (err, transaction) => { + if (err) { + logger.log('err', + `getTxById: ${err}`); + return err; + } + const tx = transaction; + return res.send({ + txid: tx.hash, + version: tx.version, + time: tx.ps, + blocktime: tx.ps, + locktime: tx.locktime, + blockhash: tx.block, + 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', }); + }); }); // /txs is overloaded. Next ver separate concerns // query by block // query by address - // last n txs + // last n txs - haha jk YOU 404 router.get('/txs', (req, res) => { const pageNum = parseInt(req.query.pageNum, 10) || 0; const rangeStart = pageNum * MAX_TXS; const rangeEnd = rangeStart + MAX_TXS; // 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}`, diff --git a/server/lib/db/blocks.js b/server/lib/db/blocks.js index 5659d34..0cdba0c 100644 --- a/server/lib/db/blocks.js +++ b/server/lib/db/blocks.js @@ -6,6 +6,8 @@ const MAX_BLOCKS = config.api.max_blocks; // ~ 12 hours let bestBlockHeight = 0; +// This naive querying will be replaced by more advanced mongo + function getBlocks(params, options, limit, cb) { // Do not return mongo ids const defaultOptions = { _id: 0 }; @@ -56,7 +58,7 @@ function getBlock(params, options, limit, cb) { return cb(null, blocks[0]); }); } -// Highest known height in mongo +// Highest known height in mongo - Not Used function getBestHeight() { getBlock({}, {}, 1, (err, block) => { if (err) { @@ -79,8 +81,25 @@ function bestHeight(height) { return bestBlockHeight; } +function getTxById(txid, cb) { + getBlock( + { 'txs.hash': txid }, + {}, + 1, + (err, block) => { + if (err) { + logger.log('err', + `/rawblock/:blockHash: ${err}`); + return cb(err); + } + const transaction = block.txs.filter(tx => tx.hash === txid).reduce(a => a[0]); + return cb(null, transaction); + }); +} + module.exports = { getBlock, getBlocks, bestHeight, + getTxById, }; diff --git a/server/lib/parser/block.js b/server/lib/parser/block.js index b19b2b9..34b3d3d 100644 --- a/server/lib/parser/block.js +++ b/server/lib/parser/block.js @@ -23,11 +23,13 @@ function parse(entry, block) { nonce: blockJSON.nonce, txs: block.txs.map((tx) => { const txJSON = tx.toJSON(); + const txRAW = tx.toRaw(); return { hash: txJSON.hash, witnessHash: txJSON.witnessHash, fee: txJSON.fee, rate: txJSON.rate, + size: txRAW.length, ps: txJSON.ps, height: entry.height, block: util.revHex(entry.hash), @@ -71,6 +73,13 @@ function parse(entry, block) { } }); } +// Fill in behind blocks and update tx inputs +function updateInputs(txid, address) { + // Use txid and output address to get value + // Get addr / value from prev out + // update input + +} module.exports = { parse, diff --git a/server/models/input.js b/server/models/input.js index a6ebc1b..dc29b43 100644 --- a/server/models/input.js +++ b/server/models/input.js @@ -3,6 +3,7 @@ const mongoose = require('mongoose'); const Schema = mongoose.Schema; const InputSchema = new Schema({ + value: { type: Number, default: 0 }, prevout: { type: Object, default: {} }, script: { type: String, default: '' }, witness: { type: String, default: '' }, From a5d74393d190fbb830a8647e019d759b2e9c7876 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Wed, 16 Aug 2017 23:07:06 -0400 Subject: [PATCH 02/20] tx size, tx parser, mongo replies for tx by hash --- server/lib/api/transaction.js | 5 +-- server/lib/db/blocks.js | 17 --------- server/lib/db/transactions.js | 21 ++++++++++-- server/lib/node/index.js | 2 ++ server/lib/parser/index.js | 2 ++ server/lib/parser/transaction.js | 59 ++++++++++++++++++++++++++++++++ 6 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 server/lib/parser/transaction.js diff --git a/server/lib/api/transaction.js b/server/lib/api/transaction.js index 535ada3..d7dc1e3 100644 --- a/server/lib/api/transaction.js +++ b/server/lib/api/transaction.js @@ -15,12 +15,13 @@ module.exports = function transactionAPI(router) { // Bcoin transaction data const txid = req.params.txid || ''; - db.blocks.getTxById(txid, (err, transaction) => { + db.txs.getTxById(txid, (err, transaction) => { if (err) { logger.log('err', `getTxById: ${err}`); - return err; + return res.status(400).send(); } + const tx = transaction; return res.send({ txid: tx.hash, diff --git a/server/lib/db/blocks.js b/server/lib/db/blocks.js index 0cdba0c..0b8cd88 100644 --- a/server/lib/db/blocks.js +++ b/server/lib/db/blocks.js @@ -81,25 +81,8 @@ function bestHeight(height) { return bestBlockHeight; } -function getTxById(txid, cb) { - getBlock( - { 'txs.hash': txid }, - {}, - 1, - (err, block) => { - if (err) { - logger.log('err', - `/rawblock/:blockHash: ${err}`); - return cb(err); - } - const transaction = block.txs.filter(tx => tx.hash === txid).reduce(a => a[0]); - return cb(null, transaction); - }); -} - module.exports = { getBlock, getBlocks, bestHeight, - getTxById, }; diff --git a/server/lib/db/transactions.js b/server/lib/db/transactions.js index bfd90c3..9b7ec2c 100644 --- a/server/lib/db/transactions.js +++ b/server/lib/db/transactions.js @@ -2,9 +2,6 @@ const Transactions = require('../../models/transaction.js'); const logger = require('../logger'); const config = require('../../config'); -// For now, blocks handles these calls. -// These will be replaced with more advanced mongo - const MAX_TXS = config.api.max_txs; function getTransactions(params, options, limit, cb) { @@ -57,7 +54,25 @@ function getTransaction(params, options, limit, cb) { }); } + +function getTxById(txid, cb) { + getTransaction( + { hash: txid }, + {}, + 1, + (err, transaction) => { + if (err) { + logger.log('err', + `/rawblock/:blockHash: ${err}`); + return cb(err); + } + console.log(transaction); + return cb(null, transaction); + }); +} + module.exports = { getTransaction, getTransactions, + getTxById, }; diff --git a/server/lib/node/index.js b/server/lib/node/index.js index bea48c0..c7a2415 100644 --- a/server/lib/node/index.js +++ b/server/lib/node/index.js @@ -1,6 +1,7 @@ const FullNode = require('bcoin/lib/node/fullnode'); const logger = require('../../lib/logger'); const BlockParser = require('../parser').Block; +const TxParser = require('../parser').Transaction; const config = require('../../config'); const socket = require('../../lib/api/socket'); const db = require('../../lib/db'); @@ -18,6 +19,7 @@ function start() { node.chain.on('connect', (entry, block) => { BlockParser.parse(entry, block); + TxParser.parse(entry, block.txs); socket.processBlock(entry, block); db.blocks.bestHeight(entry.height); }); diff --git a/server/lib/parser/index.js b/server/lib/parser/index.js index 13c2d5b..8989195 100644 --- a/server/lib/parser/index.js +++ b/server/lib/parser/index.js @@ -1,5 +1,7 @@ const Block = require('./block'); +const Transaction = require('./transaction'); module.exports = { Block, + Transaction, }; diff --git a/server/lib/parser/transaction.js b/server/lib/parser/transaction.js new file mode 100644 index 0000000..b727417 --- /dev/null +++ b/server/lib/parser/transaction.js @@ -0,0 +1,59 @@ +const TxModel = require('../../models/transaction'); +const InputModel = require('../../models/input'); +const OutputModel = require('../../models/output'); +const config = require('../../config'); +const util = require('../../lib/util'); +const logger = require('../logger'); + +function parse(entry, txs) { + txs.forEach((tx) => { + const txJSON = tx.toJSON(); + const txRAW = tx.toRaw(); + + const t = new TxModel({ + hash: txJSON.hash, + witnessHash: txJSON.witnessHash, + fee: txJSON.fee, + rate: txJSON.rate, + size: txRAW.length, + ps: txJSON.ps, + height: entry.height, + block: util.revHex(entry.hash), + ts: entry.ts, + date: txJSON.date, + index: txJSON.index, + version: txJSON.version, + flag: txJSON.flag, + inputs: tx.inputs.map((input) => { + const inputJSON = input.toJSON(); + return new InputModel({ + prevout: inputJSON.prevout, + script: inputJSON.script, + witness: inputJSON.witness, + sequence: inputJSON.sequence, + address: inputJSON.address, + }); + }), + outputs: tx.outputs.map((output) => { + const outputJSON = output.toJSON(); + return new OutputModel({ + address: outputJSON.address, + script: outputJSON.script, + value: outputJSON.value, + }); + }), + lockTime: txJSON.locktime, + chain: config.bcoin.network, + }); + + t.save((err) => { + if (err) { + logger.log('error', err.message); + } + }); + }); +} + +module.exports = { + parse, +}; From 8d733df278bb36c9f514564471c435484255a8c1 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Thu, 17 Aug 2017 00:26:32 -0400 Subject: [PATCH 03/20] Tx Parsing and updating input values --- server/lib/api/transaction.js | 6 +++--- server/lib/db/transactions.js | 21 +++++++++++++++++++-- server/lib/parser/block.js | 7 ------- server/lib/parser/transaction.js | 19 +++++++++++++++++++ 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/server/lib/api/transaction.js b/server/lib/api/transaction.js index d7dc1e3..1c92b25 100644 --- a/server/lib/api/transaction.js +++ b/server/lib/api/transaction.js @@ -21,7 +21,7 @@ module.exports = function transactionAPI(router) { `getTxById: ${err}`); return res.status(400).send(); } - + console.log(transaction); const tx = transaction; return res.send({ txid: tx.hash, @@ -34,8 +34,8 @@ module.exports = function transactionAPI(router) { 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: { diff --git a/server/lib/db/transactions.js b/server/lib/db/transactions.js index 9b7ec2c..0bbfbd7 100644 --- a/server/lib/db/transactions.js +++ b/server/lib/db/transactions.js @@ -54,7 +54,6 @@ function getTransaction(params, options, limit, cb) { }); } - function getTxById(txid, cb) { getTransaction( { hash: txid }, @@ -66,13 +65,31 @@ function getTxById(txid, cb) { `/rawblock/:blockHash: ${err}`); return cb(err); } - console.log(transaction); return cb(null, transaction); }); } +function updateInput(txid, inputid, value, address) { + Transactions.findOneAndUpdate( + { _id: txid, 'inputs._id': inputid }, + { + $set: { + 'inputs.$.value': value, + 'inputs.$.address': address, + }, + }, + (err, tx) => { + if (err) { + logger.log('err', + `updateInput: ${err}`); + } + }, + ); +} + module.exports = { getTransaction, getTransactions, getTxById, + updateInput, }; diff --git a/server/lib/parser/block.js b/server/lib/parser/block.js index 34b3d3d..7ea44aa 100644 --- a/server/lib/parser/block.js +++ b/server/lib/parser/block.js @@ -73,13 +73,6 @@ function parse(entry, block) { } }); } -// Fill in behind blocks and update tx inputs -function updateInputs(txid, address) { - // Use txid and output address to get value - // Get addr / value from prev out - // update input - -} module.exports = { parse, diff --git a/server/lib/parser/transaction.js b/server/lib/parser/transaction.js index b727417..993e825 100644 --- a/server/lib/parser/transaction.js +++ b/server/lib/parser/transaction.js @@ -4,6 +4,7 @@ const OutputModel = require('../../models/output'); const config = require('../../config'); const util = require('../../lib/util'); const logger = require('../logger'); +const db = require('../db'); function parse(entry, txs) { txs.forEach((tx) => { @@ -46,10 +47,28 @@ function parse(entry, txs) { chain: config.bcoin.network, }); + t.save((err) => { 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); + }); + } + }); }); }); } From 31eecc5afe1492396d7dd07924da1b272abaf9b6 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Thu, 17 Aug 2017 00:44:50 -0400 Subject: [PATCH 04/20] reduced block model and parsing. --- server/lib/parser/block.js | 37 +------------------------------------ server/models/block.js | 2 +- 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/server/lib/parser/block.js b/server/lib/parser/block.js index 7ea44aa..c8221ef 100644 --- a/server/lib/parser/block.js +++ b/server/lib/parser/block.js @@ -23,42 +23,7 @@ function parse(entry, block) { nonce: blockJSON.nonce, txs: block.txs.map((tx) => { const txJSON = tx.toJSON(); - const txRAW = tx.toRaw(); - return { - hash: txJSON.hash, - witnessHash: txJSON.witnessHash, - fee: txJSON.fee, - rate: txJSON.rate, - size: txRAW.length, - ps: txJSON.ps, - height: entry.height, - block: util.revHex(entry.hash), - ts: entry.ts, - date: txJSON.date, - index: txJSON.index, - version: txJSON.version, - flag: txJSON.flag, - inputs: tx.inputs.map((input) => { - const inputJSON = input.toJSON(); - return new InputModel({ - prevout: inputJSON.prevout, - script: inputJSON.script, - witness: inputJSON.witness, - sequence: inputJSON.sequence, - address: inputJSON.address, - }); - }), - outputs: tx.outputs.map((output) => { - const outputJSON = output.toJSON(); - return new OutputModel({ - address: outputJSON.address, - script: outputJSON.script, - value: outputJSON.value, - }); - }), - lockTime: txJSON.locktime, - chain: config.bcoin.network, - }; + return txJSON.hash; }), chainwork: entry.chainwork, reward, diff --git a/server/models/block.js b/server/models/block.js index 38ba3aa..5f5aa34 100644 --- a/server/models/block.js +++ b/server/models/block.js @@ -13,7 +13,7 @@ const BlockSchema = new Schema({ ts: { type: Number, default: 0 }, bits: { type: Number, default: 0 }, nonce: { type: Number, default: 0 }, - txs: [Transaction.schema], + txs: [{ type: String, default: '' }], chainwork: { type: Number, default: 0 }, reward: { type: Number, default: 0 }, network: { type: String, default: '' }, From 5a89cf17d268478b82fa35953175bfde1d80a00e Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Thu, 17 Aug 2017 11:25:58 -0400 Subject: [PATCH 05/20] All routes replaced. Stable but no tx inputs working. --- server/lib/api/address.js | 15 ++++- server/lib/api/transaction.js | 100 +++++++++++++------------------ server/lib/db/transactions.js | 88 +++++++++++++++++++++++++-- server/lib/node/index.js | 4 ++ server/lib/parser/transaction.js | 23 ++----- server/public/img/leveldb.png | Bin 12009 -> 12077 bytes 6 files changed, 148 insertions(+), 82 deletions(-) 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 da13a671aaabef5febe267d4d10fa663fbbab21a..b4a177783a10958445412037a502b87023eed70c 100644 GIT binary patch literal 12077 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 oOf!h%@6PfbDF|I^_*KF`54E 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 From 14cb4e33325e4d1a3e40c8f7da81327449e97877 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Fri, 18 Aug 2017 14:17:15 -0400 Subject: [PATCH 06/20] clean up console log and fix return statements --- server/lib/api/message.js | 6 ++---- server/lib/api/transaction.js | 4 +--- server/lib/db/blocks.js | 3 +-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/server/lib/api/message.js b/server/lib/api/message.js index 27c0703..a15802a 100644 --- a/server/lib/api/message.js +++ b/server/lib/api/message.js @@ -13,21 +13,19 @@ function verifyMessage(req, res) { } if (!address || !signature || !message) { - res.json({ + return res.json({ message: 'Missing parameters (expected "address", "signature" and "message")', code: 1, }); - return; } let valid; try { valid = new Message(message).verify(address, signature); } catch (err) { - res.json({ + return res.json({ message: `Unexpected error: ${err.message}`, code: 1, }); - return; } res.json({ result: valid }); } diff --git a/server/lib/api/transaction.js b/server/lib/api/transaction.js index da19698..5a93f14 100644 --- a/server/lib/api/transaction.js +++ b/server/lib/api/transaction.js @@ -210,7 +210,6 @@ module.exports = function transactionAPI(router) { `/txs getTopTransactions ${err}`); return res.status(404).send(err); } - console.log(txs.length); return res.json(txs); }); }); @@ -229,8 +228,7 @@ module.exports = function transactionAPI(router) { if (err) { logger.log('error', `${err}`); - res.status(400).send(err); - return; + return res.status(400).send(err); } res.json(true); diff --git a/server/lib/db/blocks.js b/server/lib/db/blocks.js index 5659d34..2b3bb75 100644 --- a/server/lib/db/blocks.js +++ b/server/lib/db/blocks.js @@ -60,9 +60,8 @@ function getBlock(params, options, limit, cb) { function getBestHeight() { getBlock({}, {}, 1, (err, block) => { if (err) { - logger.log('error', + return logger.log('error', `getBestHeight: ${err.err}`); - return; } bestBlockHeight = block.height; }); From 697388f1cebf1957c3e20b2530ba5baffacaa36e Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Sat, 19 Aug 2017 02:57:09 -0400 Subject: [PATCH 07/20] pre cleanup. Running entirely on mongo. --- server/config/index.js | 2 +- server/lib/api/block.js | 6 ++--- server/lib/api/status.js | 8 +++---- server/lib/api/transaction.js | 12 +++++----- server/lib/db/transactions.js | 14 +++++------ server/lib/parser/transaction.js | 41 ++++++++++++++++++++++++++++++++ 6 files changed, 62 insertions(+), 21 deletions(-) diff --git a/server/config/index.js b/server/config/index.js index 4c45558..4f873dd 100644 --- a/server/config/index.js +++ b/server/config/index.js @@ -28,7 +28,7 @@ const config = { ticker_url: 'https://www.bitstamp.net/api/ticker/', ticker_prop: 'bitstamp', max_blocks: 72, - max_txs: 10, + max_txs: 100, request_ttl: 100000, }, }; diff --git a/server/lib/api/block.js b/server/lib/api/block.js index 482ea0e..a766244 100644 --- a/server/lib/api/block.js +++ b/server/lib/api/block.js @@ -51,7 +51,7 @@ module.exports = function BlockAPI(router) { limit, (err, blocks) => { if (err) { - logger.log('err', + logger.log('error', `/blocks: ${err}`); return res.status(404).send(); } @@ -80,7 +80,7 @@ module.exports = function BlockAPI(router) { 1, (err, block) => { if (err) { - logger.log('err', + logger.log('error', `/rawblock/:blockHash: ${err}`); return res.status(404).send(); } @@ -97,7 +97,7 @@ module.exports = function BlockAPI(router) { 1, (err, block) => { if (err) { - logger.log('err', + logger.log('error', `/block-index/:height: ${err}`); return res.status(404).send(); } diff --git a/server/lib/api/status.js b/server/lib/api/status.js index 514d5db..4ae3db6 100644 --- a/server/lib/api/status.js +++ b/server/lib/api/status.js @@ -48,12 +48,12 @@ module.exports = function statusAPI(router) { } else { getStatus((err, status) => { if (err) { - logger.log('err', + logger.log('error', `/status getStatus: ${err}`); return res.status(404).send(err); } if (!status) { - logger.log('err', + logger.log('error', '/status getStatus: no Status'); return res.status(404).send(); } @@ -79,12 +79,12 @@ module.exports = function statusAPI(router) { router.get('/sync', (req, res) => { getStatus((err, status) => { if (err) { - logger.log('err', + logger.log('error', `/sync: ${err}`); return res.status(404).send(err); } if (!status) { - logger.log('err', + logger.log('error', '/sync: no status'); return res.status(404).send(); } diff --git a/server/lib/api/transaction.js b/server/lib/api/transaction.js index 26cf635..822085b 100644 --- a/server/lib/api/transaction.js +++ b/server/lib/api/transaction.js @@ -17,8 +17,8 @@ module.exports = function transactionAPI(router) { db.txs.getTxById(txid, (err, transaction) => { if (err) { - logger.log('err', - `getTxById: ${err}`); + logger.log('error', + `/tx/:tid getTxById: ${err.err}`); return res.status(404).send(); } @@ -63,7 +63,7 @@ module.exports = function transactionAPI(router) { db.txs.getTxCountByBlock(req.query.block, (err, count) => { if (err) { - logger.log('err', + logger.log('error', `getTxByBlock ${err}`); return res.status(404).send(); } @@ -71,7 +71,7 @@ module.exports = function transactionAPI(router) { return db.txs.getTxByBlock(req.query.block, pageNum, MAX_TXS, (error, txs) => { if (error) { - logger.log('err', + logger.log('error', `getTxByBlock ${error}`); return res.status(404).send(); } @@ -105,7 +105,7 @@ module.exports = function transactionAPI(router) { db.txs.getTxCountByAddress(req.query.address, (err, count) => { if (err) { - logger.log('err', + logger.log('error', `getTxByBlock ${err}`); return res.status(404).send(); } @@ -113,7 +113,7 @@ module.exports = function transactionAPI(router) { return db.txs.getTxByAddress(req.query.address, pageNum, MAX_TXS, (error, txs) => { if (error) { - logger.log('err', + logger.log('error', `getTxByBlock ${error}`); return res.status(404).send(); } diff --git a/server/lib/db/transactions.js b/server/lib/db/transactions.js index c41c9ff..ecb1acb 100644 --- a/server/lib/db/transactions.js +++ b/server/lib/db/transactions.js @@ -8,7 +8,7 @@ const MAX_TXS = config.api.max_txs; function getTransactions(params, options, limit, skip, cb) { // Do not return mongo ids - const defaultOptions = { _id: 0 }; + const defaultOptions = { }; // Copy over mongo options Object.assign(defaultOptions, options); // Simple sanitizing @@ -60,13 +60,13 @@ function getTransaction(params, options, limit, skip, cb) { function getTxById(txid, cb) { getTransaction( { hash: txid }, - {}, + { }, 1, 0, (err, transaction) => { if (err) { - logger.log('err', - `/rawblock/:blockHash: ${err}`); + logger.log('error', + `getTxById: ${txid} ${err.err}`); return cb(err); } return cb(null, transaction); @@ -120,7 +120,7 @@ function getTxCountByBlock(blockHash, cb) { { block: blockHash }, (err, count) => { if (err) { - logger.log('err', + logger.log('error', `getTxCountByBlock ${err}`); return cb(err); } @@ -136,7 +136,7 @@ function getTxCountByAddress(address, cb) { }, (err, count) => { if (err) { - logger.log('err', + logger.log('error', `getTxCountByAddress ${err}`); return cb(err); } @@ -156,7 +156,7 @@ function updateInput(txid, inputid, value, address) { }, (err, tx) => { if (err) { - logger.log('err', + logger.log('error', `updateInput: ${err}`); } }, diff --git a/server/lib/parser/transaction.js b/server/lib/parser/transaction.js index 4283d81..51f853e 100644 --- a/server/lib/parser/transaction.js +++ b/server/lib/parser/transaction.js @@ -12,7 +12,10 @@ const db = require('../db'); // the last 20 that hasn't saved. // Aggregate stuff will replace all of this. +let counter = 0; + function parse(entry, txs) { + counter++; txs.forEach((tx) => { const txJSON = tx.toJSON(); const txRAW = tx.toRaw(); @@ -58,10 +61,48 @@ function parse(entry, txs) { if (err) { logger.log('error', err.message); } + // As long as this modulo is divisible by 20 we should be OK for now. + // Closer to 20 = chattier at start but ideal later on + if (counter % 20 === 0) { + findEmptyInputs(); + counter = 0; + } }); }); } +function findEmptyInputs() { + db.txs.getTransactions( + { + 'inputs.prevout.hash': { $ne: '0000000000000000000000000000000000000000000000000000000000000000' }, + 'inputs.address': '', + }, + {}, + 100, + 0, + (err, txs) => { + if (err) { + return logger.log('error', + `No Empty Inputs found: ${err.err}`); + } + // For each tx with unmarked inputs + return txs.forEach((inputTx) => { + inputTx.inputs.forEach((input) => { + const txHash = input.prevout.hash; + const outIdx = input.prevout.index; + + return db.txs.getTxById(txHash, (err, tx) => { + if (err) { + return logger.log('error', + `No Tx found: ${txHash} ${err.err}`); + } + return db.txs.updateInput(inputTx._id, input._id, tx.outputs[outIdx].value, tx.outputs[outIdx].address); + }); + }); + }); + }); +} + module.exports = { parse, }; From 46842c9cc5e3856a963cdc1ef0579e770607d26e Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Sat, 19 Aug 2017 04:07:09 -0400 Subject: [PATCH 08/20] tx by address wired up --- server/lib/api/address.js | 80 ++++++++++++++------------------------- 1 file changed, 29 insertions(+), 51 deletions(-) diff --git a/server/lib/api/address.js b/server/lib/api/address.js index d9c93c2..4f3610f 100644 --- a/server/lib/api/address.js +++ b/server/lib/api/address.js @@ -9,67 +9,45 @@ const TTL = config.api.request_ttl; module.exports = function AddressAPI(router) { router.get('/addr/:addr', (req, res) => { const addr = req.params.addr || ''; - /* + db.txs.getTxByAddress(addr, 0, 999999999, (error, txs) => { if (error) { - logger.log('err', + logger.log('error', `getTxByBlock ${error}`); return res.status(404).send(); } - console.log(txs.count()); - - }); -*/ - // Get Bcoin data - return request(`${API_URL}/tx/address/${addr}`, - { timeout: TTL }, - (error, bcoinRes, bcoinTxs) => { - if (error) { - logger.log('error', - `${error}`); - return res.status(404).send({}); + // Sum the matching outputs for every tx + const totalReceived = txs.reduce((total, tx) => total + tx.outputs.reduce((sum, output) => { + if (output.address === req.params.addr) { + return sum + output.value; } - let txs = {}; - try { - txs = JSON.parse(bcoinTxs); - } catch (e) { - logger.log('error', - `${e}`); - return res.status(404).send({}); + return sum; + }, 0), 0) || 0; + + // Sum the matching inputs for every tx + const totalSpent = txs.reduce((total, tx) => total + tx.inputs.reduce((sum, input) => { + if (input.coin && input.coin.address === req.params.addr) { + return sum + input.coin.value; } + return sum; + }, 0), 0) || 0; - // Sum the matching outputs for every tx - const totalReceived = txs.reduce((total, tx) => total + tx.outputs.reduce((sum, output) => { - if (output.address === req.params.addr) { - return sum + output.value; - } - return sum; - }, 0), 0) || 0; - - // Sum the matching inputs for every tx - const totalSpent = txs.reduce((total, tx) => total + tx.inputs.reduce((sum, input) => { - if (input.coin && input.coin.address === req.params.addr) { - return sum + input.coin.value; - } - return sum; - }, 0), 0) || 0; - - // Match Insight API - return res.json({ - addrStr: req.params.addr, - balance: (totalReceived - totalSpent) / 1e8, - balanceSat: totalReceived - totalSpent, - totalReceived: totalReceived / 1e8, - totalReceivedSat: totalReceived, - totalSent: totalSpent / 1e8, - totalSentSat: totalSpent, - unconfirmedBalance: 0, - unconfirmedBalanceSat: 0, - unconfirmedTxApperances: 0, - txApperances: txs.length, - }); + // Match Insight API + return res.json({ + addrStr: req.params.addr, + balance: (totalReceived - totalSpent) / 1e8, + balanceSat: totalReceived - totalSpent, + totalReceived: totalReceived / 1e8, + totalReceivedSat: totalReceived, + totalSent: totalSpent / 1e8, + totalSentSat: totalSpent, + unconfirmedBalance: 0, + unconfirmedBalanceSat: 0, + unconfirmedTxApperances: 0, + txApperances: txs.length, }); + }); }); // Stubbed by # to help with tasking From 801fbf62e8b04a6be6a8e9f1743ad5a8f2e3bdb5 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Mon, 21 Aug 2017 14:01:08 -0400 Subject: [PATCH 09/20] Change FE to relative request paths. --- app/src/providers/api/api.ts | 2 +- app/src/services/blocksService.ts | 2 +- server/lib/api/index.js | 35 ++++++++++++++++--------------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/app/src/providers/api/api.ts b/app/src/providers/api/api.ts index a15b48e..0c14cf6 100644 --- a/app/src/providers/api/api.ts +++ b/app/src/providers/api/api.ts @@ -11,7 +11,7 @@ import 'rxjs/add/operator/map'; @Injectable() export class ApiProvider { - public apiPrefix: string = 'https://insight.bitpay.com/api/'; + public apiPrefix: string = '/api/'; constructor(public http: Http) { } diff --git a/app/src/services/blocksService.ts b/app/src/services/blocksService.ts index 724b593..6ebd7d3 100644 --- a/app/src/services/blocksService.ts +++ b/app/src/services/blocksService.ts @@ -11,7 +11,7 @@ export class BlocksService { constructor(private http: Http) {} public getLatestBlocks(): void { - this.http.request('https://insight.bitpay.com/api/blocks').subscribe((res: Response) => { + this.http.request('/api/blocks').subscribe((res: Response) => { const data: { blocks: InsightBlockObject[], length: number, diff --git a/server/lib/api/index.js b/server/lib/api/index.js index f857182..0a1caf1 100644 --- a/server/lib/api/index.js +++ b/server/lib/api/index.js @@ -11,18 +11,19 @@ app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); // Serve insight ui front end from root dir public folder -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.use(express.static('../app/www')); +app.use('/:stuff', express.static('../app/www')); +app.use('/blocks', express.static('../app/www')); +app.use('/blocks/:blockhash', express.static('../app/www')); +app.use('/block-index', express.static('../app/www')); +app.use('/block-index/:height', express.static('../app/www')); +app.use('/blocks-date/:date', express.static('../app/www')); +app.use('/block/:blockhash', express.static('../app/www')); +app.use('/tx/:txid', express.static('../app/www')); +app.use('/address/:addr', express.static('../app/www')); +app.use('/status', express.static('../app/www')); +app.use('/status/:stuff', express.static('../app/www')); +app.use('/status/:stuff', express.static('../app/www')); app.set('json spaces', config.api.json_spaces); @@ -34,14 +35,14 @@ const StatusAPI = require('./status')(api); const TransactionAPI = require('./transaction')(api); const MessageAPI = require('./message')(api); -app.use('/insight-api', api); +app.use('/api', api); // 404 app.use((req, res) => res.status(404).send({ - status: 404, - url: req.originalUrl, - error: 'Not found', - })); + status: 404, + url: req.originalUrl, + error: 'Not found', +})); // Socket server const server = require('http').Server(app); From efe19444d5807ff75b566aed7a16e892149e31d1 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Mon, 21 Aug 2017 21:08:41 -0400 Subject: [PATCH 10/20] getTxById added to model --- server/lib/db/transactions.js | 8 +++----- server/models/transaction.js | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/server/lib/db/transactions.js b/server/lib/db/transactions.js index fe12e0b..af02bb5 100644 --- a/server/lib/db/transactions.js +++ b/server/lib/db/transactions.js @@ -2,6 +2,8 @@ const Transactions = require('../../models/transaction.js'); const logger = require('../logger'); const config = require('../../config'); +const txs = new Transactions(); + // For now, blocks handles these calls. // These will be replaced with more advanced mongo // No optimization yet. @@ -84,11 +86,7 @@ function getTopTransactions(cb) { } function getTxById(txid, cb) { - getTransaction( - { hash: txid }, - { }, - 1, - 0, + txs.byId(txid, (err, transaction) => { if (err) { logger.log('error', diff --git a/server/models/transaction.js b/server/models/transaction.js index e4e3416..1d5c842 100644 --- a/server/models/transaction.js +++ b/server/models/transaction.js @@ -1,6 +1,7 @@ const mongoose = require('mongoose'); const Input = require('./input'); const Output = require('./output'); +const logger = require('../lib/logger'); const Schema = mongoose.Schema; @@ -24,6 +25,18 @@ const TransactionSchema = new Schema({ TransactionSchema.index({ hash: 1 }); -const Transaction = mongoose.model('Transaction', TransactionSchema); +TransactionSchema.methods.byId = function txById(txid, cb) { + return this.model('Transaction').findOne( + { hash: txid }, + (err, tx) => { + if (err) { + logger.log('error', + `TransactionSchema.methods.byId: ${err}`); + return cb(err); + } + return cb(null, tx); + }); +}; -module.exports = Transaction; + +module.exports = mongoose.model('Transaction', TransactionSchema); From 050f45015acebd44c0d92338d2e096055f6cd4c0 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Mon, 21 Aug 2017 21:55:09 -0400 Subject: [PATCH 11/20] cleaned up tx db. Moved logic to models. API next --- server/lib/db/transactions.js | 131 +++---------------------------- server/lib/parser/transaction.js | 9 +-- server/models/transaction.js | 116 ++++++++++++++++++++++++++- 3 files changed, 129 insertions(+), 127 deletions(-) diff --git a/server/lib/db/transactions.js b/server/lib/db/transactions.js index af02bb5..b00a21b 100644 --- a/server/lib/db/transactions.js +++ b/server/lib/db/transactions.js @@ -2,10 +2,8 @@ const Transactions = require('../../models/transaction.js'); const logger = require('../logger'); const config = require('../../config'); -const txs = new Transactions(); +const Txs = new Transactions(); -// For now, blocks handles these calls. -// These will be replaced with more advanced mongo // No optimization yet. // Will be replaced with a more sophisticated api soon @@ -49,147 +47,44 @@ function getTransactions(params, options, limit, skip, cb) { .limit(limit); } -function getTransaction(params, options, limit, skip, cb) { - getTransactions(params, options, limit, skip, (err, tx) => { - if (err) { - logger.log('error', - `getTransaction: ${err.err}`); - return cb(err); - } - if (!tx.length > 0) { - return cb({ err: 'Tx not found' }); - } - return cb(null, tx[0]); - }); +function getEmptyInputs(cb) { + return Txs.getEmptyInputs(cb); } -// Req Change, refactor above function getTopTransactions(cb) { - // Do not return mongo ids - const defaultOptions = { _id: 0 }; - // Query mongo - Transactions.find( - {}, - (err, txs) => { - if (err) { - logger.log('error', - `getTransactions: ${err}`); - return cb(err); - } - if (!txs.length > 0) { - return cb({ err: 'Tx not found' }); - } - return cb(null, txs); - }) - .sort({ height: -1 }) + return Txs.last(cb) .limit(MAX_TXS); } function getTxById(txid, cb) { - txs.byId(txid, - (err, transaction) => { - if (err) { - logger.log('error', - `getTxById: ${txid} ${err.err}`); - return cb(err); - } - return cb(null, transaction); - }); + return Txs.byId(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); - }); + return Txs.byBlockHash(blockHash, cb) + .limit(MAX_TXS); } 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); - }); + return Txs.byAddress(address, cb) + .limit(MAX_TXS); } function getTxCountByBlock(blockHash, cb) { - Transactions.count( - { block: blockHash }, - (err, count) => { - if (err) { - logger.log('error', - `getTxCountByBlock ${err}`); - return cb(err); - } - return cb(null, count); - }); + return Txs.countByBlock(blockHash, cb); } function getTxCountByAddress(address, cb) { - Transactions.count( - { $or: [ - { 'inputs.address': address }, - { 'outputs.address': address }], - }, - (err, count) => { - if (err) { - logger.log('error', - `getTxCountByAddress ${err}`); - return cb(err); - } - return cb(null, count); - }); + return Txs.countByAddress(address, cb); } - function updateInput(txid, inputid, value, address) { - Transactions.findOneAndUpdate( - { _id: txid, 'inputs._id': inputid }, - { - $set: { - 'inputs.$.value': value, - 'inputs.$.address': address, - }, - }, - (err, tx) => { - if (err) { - logger.log('error', - `updateInput: ${err}`); - } - }, - ); + return Txs.updateInput(txid, inputid, value, address); } module.exports = { - getTransaction, getTransactions, + getEmptyInputs, getTopTransactions, getTxById, getTxByBlock, diff --git a/server/lib/parser/transaction.js b/server/lib/parser/transaction.js index 51f853e..febef6f 100644 --- a/server/lib/parser/transaction.js +++ b/server/lib/parser/transaction.js @@ -72,14 +72,7 @@ function parse(entry, txs) { } function findEmptyInputs() { - db.txs.getTransactions( - { - 'inputs.prevout.hash': { $ne: '0000000000000000000000000000000000000000000000000000000000000000' }, - 'inputs.address': '', - }, - {}, - 100, - 0, + db.txs.getEmptyInputs( (err, txs) => { if (err) { return logger.log('error', diff --git a/server/models/transaction.js b/server/models/transaction.js index 1d5c842..d39855a 100644 --- a/server/models/transaction.js +++ b/server/models/transaction.js @@ -31,12 +31,126 @@ TransactionSchema.methods.byId = function txById(txid, cb) { (err, tx) => { if (err) { logger.log('error', - `TransactionSchema.methods.byId: ${err}`); + `byId: ${err}`); return cb(err); } return cb(null, tx); }); }; +TransactionSchema.methods.byHash = function txByHash(hash, cb) { + return this.byId(hash, cb); +}; + +TransactionSchema.methods.byBlockHash = function txByBlockHash(hash, cb) { + return this.model('Transaction').find( + { block: hash }, + (err, txs) => { + if (err) { + logger.log('error', + `byBlockHash: ${err}`); + return cb(err); + } + return cb(null, txs); + }, + ); +}; + +TransactionSchema.methods.byAddress = function txByAddress(address, cb) { + return this.model('Transaction').find( + { + $or: [ + { 'inputs.address': address }, + { 'outputs.address': address }], + }, + (err, tx) => { + if (err) { + logger.log('error', + `byAddress: ${err.err}`); + return cb(err); + } + if (!tx.length > 0) { + return cb({ err: 'Tx not found' }); + } + return cb(null, tx); + }, + ); +}; + +TransactionSchema.methods.countByBlock = function txByAddress(hash, cb) { + return this.model('Transaction').count( + { block: hash }, + (err, count) => { + if (err) { + logger.log('error', + `countByBlock ${err}`); + return cb(err); + } + return cb(null, count); + }, + ); +}; + +TransactionSchema.methods.countByAddress = function txByAddress(address, cb) { + return this.model('Transaction').count( + { + $or: [ + { 'inputs.address': address }, + { 'outputs.address': address }], + }, + (err, count) => { + if (err) { + logger.log('error', + `countByAddress ${err}`); + return cb(err); + } + return cb(null, count); + }, + ); +}; + +TransactionSchema.methods.updateInput = function updateInput(txid, inputid, value, address) { + return this.model('Transaction').findOneAndUpdate( + { _id: txid, 'inputs._id': inputid }, + { + $set: { + 'inputs.$.value': value, + 'inputs.$.address': address, + }, + }, + (err, tx) => { + if (err) { + logger.log('error', + `updateInput: ${err}`); + } + }, + ); +}; + +TransactionSchema.methods.last = function lastTx(cb) { + return this.model('Transaction').find( + {}, + (err, txs) => { + if (err) { + logger.log('error', + `TransactionSchema last: ${err}`); + return cb(err); + } + if (!txs.length > 0) { + return cb({ err: 'Tx not found' }); + } + return cb(null, txs); + }, + ); +}; + +TransactionSchema.methods.getEmptyInputs = function findEmptyInputs(cb) { + return this.model('Transaction').find({ + 'inputs.prevout.hash': { $ne: '0000000000000000000000000000000000000000000000000000000000000000' }, + 'inputs.address': '', + }, + cb); +}; + module.exports = mongoose.model('Transaction', TransactionSchema); From cae4a455724fd022a9c87bfe05001fe84dfa6383 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Mon, 21 Aug 2017 22:38:20 -0400 Subject: [PATCH 12/20] Massive debug/dev code cleanup. Most db logic moved to models. --- server/lib/api/block.js | 28 ++------ server/lib/api/status.js | 17 ++--- server/lib/db/blocks.js | 93 ++++++++---------------- server/lib/db/transactions.js | 44 ++---------- server/lib/parser/transaction.js | 2 +- server/models/block.js | 28 +++++++- server/models/transaction.js | 118 +++++++++---------------------- 7 files changed, 105 insertions(+), 225 deletions(-) diff --git a/server/lib/api/block.js b/server/lib/api/block.js index 18f499a..5aac849 100644 --- a/server/lib/api/block.js +++ b/server/lib/api/block.js @@ -13,10 +13,7 @@ module.exports = function BlockAPI(router) { } // Pass Mongo params, fields and limit to db api. - db.blocks.getBlock( - { hash: blockHash }, - { rawBlock: 0 }, - 1, + return db.blocks.getByHash(blockHash, (err, block) => { if (err) { logger.log('err', err); @@ -48,16 +45,7 @@ module.exports = function BlockAPI(router) { router.get('/blocks', (req, res) => { const limit = parseInt(req.query.limit, 10) || 100; // Pass Mongo params, fields and limit to db api. - db.blocks.getBlocks( - {}, - { height: 1, - size: 1, - hash: 1, - ts: 1, - txs: 1, - poolInfo: 1, - }, - limit, + db.blocks.getTopBlocks( (err, blocks) => { if (err) { logger.log('error', @@ -90,10 +78,7 @@ module.exports = function BlockAPI(router) { } // Pass Mongo params, fields and limit to db api. - db.blocks.getBlock( - { hash: blockHash }, - { rawBlock: 1 }, - 1, + return db.blocks.getRawBlock(blockHash, (err, block) => { if (err) { logger.log('error', @@ -105,12 +90,9 @@ module.exports = function BlockAPI(router) { }); router.get('/block-index/:height', (req, res) => { - const blockHeight = parseInt(req.params.height, 10) || 1; + const height = parseInt(req.params.height, 10) || 1; // Pass Mongo params, fields and limit to db api. - db.blocks.getBlock( - { height: blockHeight }, - { hash: 1 }, - 1, + return db.blocks.byHeight(height, (err, block) => { if (err) { logger.log('error', diff --git a/server/lib/api/status.js b/server/lib/api/status.js index 3cf26ba..725eca1 100644 --- a/server/lib/api/status.js +++ b/server/lib/api/status.js @@ -30,10 +30,7 @@ module.exports = function statusAPI(router) { // Get last block hash or node status router.get('/status', (req, res) => { if (req.query.q === 'getLastBlockHash') { - db.blocks.getBlock( - {}, - { hash: 1 }, - 1, + db.blocks.getLastBlock( (err, block) => { if (err) { logger.log('error', @@ -99,17 +96,13 @@ module.exports = function statusAPI(router) { }); }); // Copied from previous source - router.get('/peer', (req, res) => { - return res.json({ + router.get('/peer', (req, res) => res.json({ connected: true, host: '127.0.0.1', port: null, - }); - }); + })); - router.get('/version', (req, res) => { - return res.json({ + router.get('/version', (req, res) => res.json({ version: pkg.version, - }); - }); + })); }; diff --git a/server/lib/db/blocks.js b/server/lib/db/blocks.js index 3037fbd..4c4ef25 100644 --- a/server/lib/db/blocks.js +++ b/server/lib/db/blocks.js @@ -2,72 +2,12 @@ const Block = require('../../models/block.js'); const logger = require('../logger'); const config = require('../../config'); +const block = new Block(); + const MAX_BLOCKS = config.api.max_blocks; // ~ 12 hours let bestBlockHeight = 0; -// This naive querying will be replaced by more advanced mongo - -function getBlocks(params, options, limit, cb) { - // Do not return mongo ids - const defaultOptions = { _id: 0 }; - // Copy over mongo options - Object.assign(defaultOptions, options); - // Simple sanitizing - if (!Number.isInteger(limit)) { - limit = 1; - } - - if (limit > MAX_BLOCKS) { - limit = MAX_BLOCKS; - } - - if (limit < 1) { - limit = 1; - } - - // Query mongo - Block.find( - params, - defaultOptions, - (err, blocks) => { - if (err) { - logger.log('error', - `getBlocks: ${err}`); - return cb(err); - } - if (!blocks.length > 0) { - return cb({ err: 'Block not found' }); - } - return cb(null, blocks); - }) - .sort({ height: -1 }) - .limit(limit); -} -// Retrieve a single block. For convenience mostly -function getBlock(params, options, limit, cb) { - getBlocks(params, options, limit, (err, blocks) => { - if (err) { - logger.log('error', - `getBlock: ${err.err}`); - return cb(err); - } - if (!blocks.length > 0) { - return cb({ err: 'Block not found' }); - } - return cb(null, blocks[0]); - }); -} -// Highest known height in mongo - Not Used -function getBestHeight() { - getBlock({}, {}, 1, (err, block) => { - if (err) { - return logger.log('error', - `getBestHeight: ${err.err}`); - } - bestBlockHeight = block.height; - }); -} // 1e9 limit = ~2M years from now // Mostly for sync to set height function bestHeight(height) { @@ -80,8 +20,33 @@ function bestHeight(height) { return bestBlockHeight; } +function getRawBlock(hash, cb) { + return block.getRawBlock(hash, cb); +} + +function byHeight(height, cb) { + return block.byHeight(height, cb); +} + +function getTopBlocks(cb) { + return block.last(cb) + .limit(MAX_BLOCKS); +} + +function getByHash(hash, cb) { + return block.byHash(hash, cb); +} + +function getLastBlock(cb) { + return block.last(cb) + .limit(1); +} + module.exports = { - getBlock, - getBlocks, + getRawBlock, + getTopBlocks, + getLastBlock, + getByHash, + byHeight, bestHeight, }; diff --git a/server/lib/db/transactions.js b/server/lib/db/transactions.js index b00a21b..72e3a2b 100644 --- a/server/lib/db/transactions.js +++ b/server/lib/db/transactions.js @@ -10,43 +10,6 @@ const Txs = new Transactions(); const MAX_TXS = config.api.max_txs; const MAX_PAGE_TXS = config.api.max_page_txs; -function getTransactions(params, options, limit, skip, cb) { - // Do not return mongo ids - const defaultOptions = { }; - // Copy over mongo options - Object.assign(defaultOptions, options); - // Simple sanitizing - if (!Number.isInteger(limit)) { - limit = 1; - } - - if (limit > MAX_PAGE_TXS) { - limit = MAX_PAGE_TXS; - } - - if (limit < 1) { - limit = 1; - } - // Query mongo - Transactions.find( - params, - defaultOptions, - (err, txs) => { - if (err) { - logger.log('error', - `getTransactions: ${err}`); - return cb(err); - } - if (!txs.length > 0) { - return cb({ err: 'Tx not found' }); - } - return cb(null, txs); - }) - .sort({ height: 1 }) - .skip() - .limit(limit); -} - function getEmptyInputs(cb) { return Txs.getEmptyInputs(cb); } @@ -62,12 +25,14 @@ function getTxById(txid, cb) { function getTxByBlock(blockHash, page, limit, cb) { return Txs.byBlockHash(blockHash, cb) - .limit(MAX_TXS); + .limit(MAX_PAGE_TXS) + .skip(MAX_PAGE_TXS * page); } function getTxByAddress(address, page, limit, cb) { return Txs.byAddress(address, cb) - .limit(MAX_TXS); + .limit(MAX_PAGE_TXS) + .skip(MAX_PAGE_TXS * page); } function getTxCountByBlock(blockHash, cb) { @@ -83,7 +48,6 @@ function updateInput(txid, inputid, value, address) { } module.exports = { - getTransactions, getEmptyInputs, getTopTransactions, getTxById, diff --git a/server/lib/parser/transaction.js b/server/lib/parser/transaction.js index febef6f..4a1ebd2 100644 --- a/server/lib/parser/transaction.js +++ b/server/lib/parser/transaction.js @@ -62,7 +62,7 @@ function parse(entry, txs) { logger.log('error', err.message); } // As long as this modulo is divisible by 20 we should be OK for now. - // Closer to 20 = chattier at start but ideal later on + // Closer to 20 = chattier at start and less ideal later on if (counter % 20 === 0) { findEmptyInputs(); counter = 0; diff --git a/server/models/block.js b/server/models/block.js index 8c86062..6aa0d1e 100644 --- a/server/models/block.js +++ b/server/models/block.js @@ -29,6 +29,30 @@ const BlockSchema = new Schema({ BlockSchema.index({ hash: 1 }); BlockSchema.index({ height: 1 }); -const Block = mongoose.model('Block', BlockSchema); +BlockSchema.methods.byHeight = function blockByHeight(height, cb) { + return this.model('Block').findOne( + { height }, + cb); +}; -module.exports = Block; +BlockSchema.methods.byHash = function byHash(hash, cb) { + return this.model('Block').findOne( + { hash }, + cb); +}; + +BlockSchema.methods.getRawBlock = function getRawBlock(hash, cb) { + return this.model('Block').findOne( + { hash }, + { rawBlock: 1 }, + cb); +}; + +BlockSchema.methods.last = function lastTx(cb) { + return this.model('Block').find( + {}, + cb) + .sort({ height: -1 }); +}; + +module.exports = mongoose.model('Block', BlockSchema); diff --git a/server/models/transaction.js b/server/models/transaction.js index d39855a..284b4a0 100644 --- a/server/models/transaction.js +++ b/server/models/transaction.js @@ -6,21 +6,21 @@ const logger = require('../lib/logger'); const Schema = mongoose.Schema; const TransactionSchema = new Schema({ - hash: { type: String, default: '' }, + hash: { type: String, default: '' }, witnessHash: { type: String, default: '' }, - fee: { type: Number, default: 0 }, - rate: { type: Number, default: 0 }, - ps: { type: Number, default: 0 }, - height: { type: Number, default: 0 }, - block: { type: String, default: '' }, - index: { type: Number, default: 0 }, - version: { type: Number, default: 0 }, - flag: { type: Number, default: 0 }, - lockTime: { type: Number, default: 0 }, - inputs: [Input.schema], - outputs: [Output.schema], - size: { type: Number, default: 0 }, - network: { type: String, default: '' }, + fee: { type: Number, default: 0 }, + rate: { type: Number, default: 0 }, + ps: { type: Number, default: 0 }, + height: { type: Number, default: 0 }, + block: { type: String, default: '' }, + index: { type: Number, default: 0 }, + version: { type: Number, default: 0 }, + flag: { type: Number, default: 0 }, + lockTime: { type: Number, default: 0 }, + inputs: [Input.schema], + outputs: [Output.schema], + size: { type: Number, default: 0 }, + network: { type: String, default: '' }, }); TransactionSchema.index({ hash: 1 }); @@ -28,14 +28,7 @@ TransactionSchema.index({ hash: 1 }); TransactionSchema.methods.byId = function txById(txid, cb) { return this.model('Transaction').findOne( { hash: txid }, - (err, tx) => { - if (err) { - logger.log('error', - `byId: ${err}`); - return cb(err); - } - return cb(null, tx); - }); + cb); }; TransactionSchema.methods.byHash = function txByHash(hash, cb) { @@ -45,14 +38,7 @@ TransactionSchema.methods.byHash = function txByHash(hash, cb) { TransactionSchema.methods.byBlockHash = function txByBlockHash(hash, cb) { return this.model('Transaction').find( { block: hash }, - (err, txs) => { - if (err) { - logger.log('error', - `byBlockHash: ${err}`); - return cb(err); - } - return cb(null, txs); - }, + cb, ); }; @@ -63,31 +49,14 @@ TransactionSchema.methods.byAddress = function txByAddress(address, cb) { { 'inputs.address': address }, { 'outputs.address': address }], }, - (err, tx) => { - if (err) { - logger.log('error', - `byAddress: ${err.err}`); - return cb(err); - } - if (!tx.length > 0) { - return cb({ err: 'Tx not found' }); - } - return cb(null, tx); - }, + cb, ); }; TransactionSchema.methods.countByBlock = function txByAddress(hash, cb) { return this.model('Transaction').count( { block: hash }, - (err, count) => { - if (err) { - logger.log('error', - `countByBlock ${err}`); - return cb(err); - } - return cb(null, count); - }, + cb, ); }; @@ -98,17 +67,26 @@ TransactionSchema.methods.countByAddress = function txByAddress(address, cb) { { 'inputs.address': address }, { 'outputs.address': address }], }, - (err, count) => { - if (err) { - logger.log('error', - `countByAddress ${err}`); - return cb(err); - } - return cb(null, count); - }, + cb, ); }; +TransactionSchema.methods.last = function lastTx(cb) { + return this.model('Transaction').find( + {}, + cb, + ) + .sort({ height: -1 }); +}; + +TransactionSchema.methods.getEmptyInputs = function findEmptyInputs(cb) { + return this.model('Transaction').find({ + 'inputs.prevout.hash': { $ne: '0000000000000000000000000000000000000000000000000000000000000000' }, + 'inputs.address': '', + }, + cb); +}; + TransactionSchema.methods.updateInput = function updateInput(txid, inputid, value, address) { return this.model('Transaction').findOneAndUpdate( { _id: txid, 'inputs._id': inputid }, @@ -127,30 +105,4 @@ TransactionSchema.methods.updateInput = function updateInput(txid, inputid, valu ); }; -TransactionSchema.methods.last = function lastTx(cb) { - return this.model('Transaction').find( - {}, - (err, txs) => { - if (err) { - logger.log('error', - `TransactionSchema last: ${err}`); - return cb(err); - } - if (!txs.length > 0) { - return cb({ err: 'Tx not found' }); - } - return cb(null, txs); - }, - ); -}; - -TransactionSchema.methods.getEmptyInputs = function findEmptyInputs(cb) { - return this.model('Transaction').find({ - 'inputs.prevout.hash': { $ne: '0000000000000000000000000000000000000000000000000000000000000000' }, - 'inputs.address': '', - }, - cb); -}; - - module.exports = mongoose.model('Transaction', TransactionSchema); From 98164e4447d691d06f30b98731afef3fb74b4318 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Mon, 21 Aug 2017 22:53:04 -0400 Subject: [PATCH 13/20] paging added back. Going over max config limit will default to config limit and still support paging. --- server/lib/db/blocks.js | 5 +---- server/lib/db/transactions.js | 15 ++++----------- server/models/block.js | 6 ++++-- server/models/transaction.js | 20 ++++++++++---------- 4 files changed, 19 insertions(+), 27 deletions(-) diff --git a/server/lib/db/blocks.js b/server/lib/db/blocks.js index 4c4ef25..623dcde 100644 --- a/server/lib/db/blocks.js +++ b/server/lib/db/blocks.js @@ -4,8 +4,6 @@ const config = require('../../config'); const block = new Block(); -const MAX_BLOCKS = config.api.max_blocks; // ~ 12 hours - let bestBlockHeight = 0; // 1e9 limit = ~2M years from now @@ -29,8 +27,7 @@ function byHeight(height, cb) { } function getTopBlocks(cb) { - return block.last(cb) - .limit(MAX_BLOCKS); + return block.last(cb); } function getByHash(hash, cb) { diff --git a/server/lib/db/transactions.js b/server/lib/db/transactions.js index 72e3a2b..8ea5d1f 100644 --- a/server/lib/db/transactions.js +++ b/server/lib/db/transactions.js @@ -3,11 +3,6 @@ const logger = require('../logger'); const config = require('../../config'); const Txs = new Transactions(); - -// No optimization yet. -// Will be replaced with a more sophisticated api soon - -const MAX_TXS = config.api.max_txs; const MAX_PAGE_TXS = config.api.max_page_txs; function getEmptyInputs(cb) { @@ -15,8 +10,7 @@ function getEmptyInputs(cb) { } function getTopTransactions(cb) { - return Txs.last(cb) - .limit(MAX_TXS); + return Txs.last(cb); } function getTxById(txid, cb) { @@ -25,14 +19,13 @@ function getTxById(txid, cb) { function getTxByBlock(blockHash, page, limit, cb) { return Txs.byBlockHash(blockHash, cb) - .limit(MAX_PAGE_TXS) - .skip(MAX_PAGE_TXS * page); + .skip(limit * page); } function getTxByAddress(address, page, limit, cb) { return Txs.byAddress(address, cb) - .limit(MAX_PAGE_TXS) - .skip(MAX_PAGE_TXS * page); + .limit(limit) + .skip(limit * page); } function getTxCountByBlock(blockHash, cb) { diff --git a/server/models/block.js b/server/models/block.js index 6aa0d1e..22ef2c3 100644 --- a/server/models/block.js +++ b/server/models/block.js @@ -1,7 +1,8 @@ const mongoose = require('mongoose'); -const Transaction = require('./transaction'); +const config = require('../config'); const Schema = mongoose.Schema; +const MAX_BLOCKS = config.api.max_blocks; // ~ 12 hours const BlockSchema = new Schema({ hash: { type: String, default: '' }, @@ -48,10 +49,11 @@ BlockSchema.methods.getRawBlock = function getRawBlock(hash, cb) { cb); }; -BlockSchema.methods.last = function lastTx(cb) { +BlockSchema.methods.last = function lastBlocks(cb) { return this.model('Block').find( {}, cb) + .limit(MAX_BLOCKS) .sort({ height: -1 }); }; diff --git a/server/models/transaction.js b/server/models/transaction.js index 284b4a0..e199330 100644 --- a/server/models/transaction.js +++ b/server/models/transaction.js @@ -2,8 +2,11 @@ const mongoose = require('mongoose'); const Input = require('./input'); const Output = require('./output'); const logger = require('../lib/logger'); +const config = require('../config'); const Schema = mongoose.Schema; +const MAX_TXS = config.api.max_txs; +const MAX_PAGE_TXS = config.api.max_page_txs; const TransactionSchema = new Schema({ hash: { type: String, default: '' }, @@ -38,8 +41,8 @@ TransactionSchema.methods.byHash = function txByHash(hash, cb) { TransactionSchema.methods.byBlockHash = function txByBlockHash(hash, cb) { return this.model('Transaction').find( { block: hash }, - cb, - ); + cb) + .limit(MAX_PAGE_TXS); }; TransactionSchema.methods.byAddress = function txByAddress(address, cb) { @@ -49,15 +52,13 @@ TransactionSchema.methods.byAddress = function txByAddress(address, cb) { { 'inputs.address': address }, { 'outputs.address': address }], }, - cb, - ); + cb); }; TransactionSchema.methods.countByBlock = function txByAddress(hash, cb) { return this.model('Transaction').count( { block: hash }, - cb, - ); + cb); }; TransactionSchema.methods.countByAddress = function txByAddress(address, cb) { @@ -67,15 +68,14 @@ TransactionSchema.methods.countByAddress = function txByAddress(address, cb) { { 'inputs.address': address }, { 'outputs.address': address }], }, - cb, - ); + cb); }; TransactionSchema.methods.last = function lastTx(cb) { return this.model('Transaction').find( {}, - cb, - ) + cb) + .limit(MAX_TXS) .sort({ height: -1 }); }; From e5ad52f55d3758aec683465b896477515490484c Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Mon, 21 Aug 2017 22:57:43 -0400 Subject: [PATCH 14/20] fixed search by addr checking for address. Eventually move these to middleware --- server/lib/api/address.js | 8 +++++++- server/lib/api/block.js | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/server/lib/api/address.js b/server/lib/api/address.js index 5b19c4a..dfec674 100644 --- a/server/lib/api/address.js +++ b/server/lib/api/address.js @@ -11,7 +11,13 @@ module.exports = function AddressAPI(router) { router.get('/addr/:addr', (req, res) => { const addr = req.params.addr || ''; - db.txs.getTxByAddress(addr, 0, 999999999, (error, txs) => { + if (!util.isBitcoinAddress(addr)) { + return res.status(404).send({ + error: 'Invalid bitcoin address', + }); + } + + return db.txs.getTxByAddress(addr, 0, 999999999, (error, txs) => { if (error) { logger.log('error', `getTxByBlock ${error}`); diff --git a/server/lib/api/block.js b/server/lib/api/block.js index 5aac849..ee541e4 100644 --- a/server/lib/api/block.js +++ b/server/lib/api/block.js @@ -7,7 +7,7 @@ module.exports = function BlockAPI(router) { const blockHash = req.params.blockHash; if (!util.isBlockHash(blockHash)) { - return res.status(400).send({ + return res.status(404).send({ error: 'Invalid bitcoin address', }); } From c2c51e709abbda72e5be09f18784321c46525a01 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Tue, 22 Aug 2017 00:29:10 -0400 Subject: [PATCH 15/20] more cleaning up --- server/config/index.js | 2 +- server/lib/api/address.js | 5 ----- server/lib/api/status.js | 12 ++++++------ server/models/block.js | 3 ++- server/models/input.js | 2 -- server/models/output.js | 2 -- server/models/transaction.js | 4 ++++ 7 files changed, 13 insertions(+), 17 deletions(-) diff --git a/server/config/index.js b/server/config/index.js index 50638e3..011f3d8 100644 --- a/server/config/index.js +++ b/server/config/index.js @@ -28,7 +28,7 @@ const config = { ticker_url: 'https://www.bitstamp.net/api/ticker/', ticker_prop: 'bitstamp', max_blocks: 72, - max_txs: 50, + max_txs: 10, max_page_txs: 10, request_ttl: 100000, }, diff --git a/server/lib/api/address.js b/server/lib/api/address.js index dfec674..cc9c077 100644 --- a/server/lib/api/address.js +++ b/server/lib/api/address.js @@ -1,12 +1,7 @@ const logger = require('../logger'); -const request = require('request'); -const config = require('../../config'); const util = require('../util'); const db = require('../db'); -const API_URL = `http://${config.bcoin_http}:${config.bcoin['http-port']}`; -const TTL = config.api.request_ttl; - module.exports = function AddressAPI(router) { router.get('/addr/:addr', (req, res) => { const addr = req.params.addr || ''; diff --git a/server/lib/api/status.js b/server/lib/api/status.js index 725eca1..bc0cfa3 100644 --- a/server/lib/api/status.js +++ b/server/lib/api/status.js @@ -97,12 +97,12 @@ module.exports = function statusAPI(router) { }); // Copied from previous source router.get('/peer', (req, res) => res.json({ - connected: true, - host: '127.0.0.1', - port: null, - })); + connected: true, + host: '127.0.0.1', + port: null, + })); router.get('/version', (req, res) => res.json({ - version: pkg.version, - })); + version: pkg.version, + })); }; diff --git a/server/models/block.js b/server/models/block.js index 22ef2c3..9c18bc7 100644 --- a/server/models/block.js +++ b/server/models/block.js @@ -2,7 +2,8 @@ const mongoose = require('mongoose'); const config = require('../config'); const Schema = mongoose.Schema; -const MAX_BLOCKS = config.api.max_blocks; // ~ 12 hours +// These limits can be overriden higher up the stack +const MAX_BLOCKS = config.api.max_blocks; const BlockSchema = new Schema({ hash: { type: String, default: '' }, diff --git a/server/models/input.js b/server/models/input.js index dc29b43..77f115c 100644 --- a/server/models/input.js +++ b/server/models/input.js @@ -11,8 +11,6 @@ const InputSchema = new Schema({ address: { type: String, default: '' }, }); -InputSchema.index({ address: 1 }); - const Input = mongoose.model('Input', InputSchema); module.exports = Input; diff --git a/server/models/output.js b/server/models/output.js index 56694eb..65f2194 100644 --- a/server/models/output.js +++ b/server/models/output.js @@ -9,8 +9,6 @@ const OutputSchema = new Schema({ type: { type: String, default: '' }, }); -OutputSchema.index({ address: 1 }); - const Output = mongoose.model('Output', OutputSchema); module.exports = Output; diff --git a/server/models/transaction.js b/server/models/transaction.js index e199330..2b2358a 100644 --- a/server/models/transaction.js +++ b/server/models/transaction.js @@ -5,6 +5,7 @@ const logger = require('../lib/logger'); const config = require('../config'); const Schema = mongoose.Schema; +// These limits can be overriden higher up the stack const MAX_TXS = config.api.max_txs; const MAX_PAGE_TXS = config.api.max_page_txs; @@ -27,6 +28,9 @@ const TransactionSchema = new Schema({ }); TransactionSchema.index({ hash: 1 }); +TransactionSchema.index({ 'outputs.address': 1 }); +TransactionSchema.index({ 'inputs.address': 1 }); + TransactionSchema.methods.byId = function txById(txid, cb) { return this.model('Transaction').findOne( From 479d55de4aba1b6a73648c57eea7636020ecdc12 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Tue, 22 Aug 2017 01:17:44 -0400 Subject: [PATCH 16/20] check for findOne null --- server/lib/api/block.js | 7 +++---- server/lib/db/transactions.js | 1 - server/lib/node/index.js | 8 -------- server/lib/parser/transaction.js | 23 +++++------------------ server/models/transaction.js | 2 +- 5 files changed, 9 insertions(+), 32 deletions(-) diff --git a/server/lib/api/block.js b/server/lib/api/block.js index ee541e4..3041c2c 100644 --- a/server/lib/api/block.js +++ b/server/lib/api/block.js @@ -15,7 +15,7 @@ module.exports = function BlockAPI(router) { // Pass Mongo params, fields and limit to db api. return db.blocks.getByHash(blockHash, (err, block) => { - if (err) { + if (err || !block) { logger.log('err', err); return res.status(404).send(); } @@ -43,7 +43,6 @@ module.exports = function BlockAPI(router) { }); router.get('/blocks', (req, res) => { - const limit = parseInt(req.query.limit, 10) || 100; // Pass Mongo params, fields and limit to db api. db.blocks.getTopBlocks( (err, blocks) => { @@ -80,7 +79,7 @@ module.exports = function BlockAPI(router) { // Pass Mongo params, fields and limit to db api. return db.blocks.getRawBlock(blockHash, (err, block) => { - if (err) { + if (err || !block) { logger.log('error', `/rawblock/:blockHash: ${err}`); return res.status(404).send(); @@ -94,7 +93,7 @@ module.exports = function BlockAPI(router) { // Pass Mongo params, fields and limit to db api. return db.blocks.byHeight(height, (err, block) => { - if (err) { + if (err || !block) { logger.log('error', `/block-index/:height: ${err}`); return res.status(404).send(); diff --git a/server/lib/db/transactions.js b/server/lib/db/transactions.js index 8ea5d1f..9c7b724 100644 --- a/server/lib/db/transactions.js +++ b/server/lib/db/transactions.js @@ -1,5 +1,4 @@ const Transactions = require('../../models/transaction.js'); -const logger = require('../logger'); const config = require('../../config'); const Txs = new Transactions(); diff --git a/server/lib/node/index.js b/server/lib/node/index.js index 2e53167..2f73f29 100644 --- a/server/lib/node/index.js +++ b/server/lib/node/index.js @@ -24,18 +24,10 @@ function start() { db.blocks.bestHeight(entry.height); }); - node.chain.on('full', (block) => { - - }); - node.on('error', (err) => { logger.log('error', `${err}`); }); - - node.mempool.on('tx', (tx) => { - socket.emitTx(tx); - }); } module.exports = { diff --git a/server/lib/parser/transaction.js b/server/lib/parser/transaction.js index 4a1ebd2..73c559e 100644 --- a/server/lib/parser/transaction.js +++ b/server/lib/parser/transaction.js @@ -6,16 +6,7 @@ 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. - -let counter = 0; - function parse(entry, txs) { - counter++; txs.forEach((tx) => { const txJSON = tx.toJSON(); const txRAW = tx.toRaw(); @@ -61,12 +52,8 @@ function parse(entry, txs) { if (err) { logger.log('error', err.message); } - // As long as this modulo is divisible by 20 we should be OK for now. - // Closer to 20 = chattier at start and less ideal later on - if (counter % 20 === 0) { - findEmptyInputs(); - counter = 0; - } + + findEmptyInputs(); }); }); } @@ -84,10 +71,10 @@ function findEmptyInputs() { const txHash = input.prevout.hash; const outIdx = input.prevout.index; - return db.txs.getTxById(txHash, (err, tx) => { - if (err) { + return db.txs.getTxById(txHash, (error, tx) => { + if (error || !tx) { return logger.log('error', - `No Tx found: ${txHash} ${err.err}`); + `No Tx found: ${txHash} ${error}`); } return db.txs.updateInput(inputTx._id, input._id, tx.outputs[outIdx].value, tx.outputs[outIdx].address); }); diff --git a/server/models/transaction.js b/server/models/transaction.js index 2b2358a..318613a 100644 --- a/server/models/transaction.js +++ b/server/models/transaction.js @@ -83,7 +83,7 @@ TransactionSchema.methods.last = function lastTx(cb) { .sort({ height: -1 }); }; -TransactionSchema.methods.getEmptyInputs = function findEmptyInputs(cb) { +TransactionSchema.methods.getEmptyInputs = function getEmptyInputs(cb) { return this.model('Transaction').find({ 'inputs.prevout.hash': { $ne: '0000000000000000000000000000000000000000000000000000000000000000' }, 'inputs.address': '', From a9493190c218f042a746d2ec5d0d29d9f3237be1 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Tue, 22 Aug 2017 01:23:12 -0400 Subject: [PATCH 17/20] fix max tx --- server/models/transaction.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/server/models/transaction.js b/server/models/transaction.js index 318613a..6a03caf 100644 --- a/server/models/transaction.js +++ b/server/models/transaction.js @@ -46,7 +46,7 @@ TransactionSchema.methods.byBlockHash = function txByBlockHash(hash, cb) { return this.model('Transaction').find( { block: hash }, cb) - .limit(MAX_PAGE_TXS); + .limit(MAX_TXS); }; TransactionSchema.methods.byAddress = function txByAddress(address, cb) { @@ -56,7 +56,8 @@ TransactionSchema.methods.byAddress = function txByAddress(address, cb) { { 'inputs.address': address }, { 'outputs.address': address }], }, - cb); + cb) + .limit(MAX_TXS); }; TransactionSchema.methods.countByBlock = function txByAddress(hash, cb) { @@ -88,7 +89,8 @@ TransactionSchema.methods.getEmptyInputs = function getEmptyInputs(cb) { 'inputs.prevout.hash': { $ne: '0000000000000000000000000000000000000000000000000000000000000000' }, 'inputs.address': '', }, - cb); + cb) + .limit(MAX_TXS); }; TransactionSchema.methods.updateInput = function updateInput(txid, inputid, value, address) { From 067592df50dde0681017dd7ceee3ad2322c2b49b Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Tue, 22 Aug 2017 01:44:51 -0400 Subject: [PATCH 18/20] helmet and static expires header --- server/lib/api/index.js | 16 +++------------- server/package.json | 1 + 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/server/lib/api/index.js b/server/lib/api/index.js index 0a1caf1..27692f6 100644 --- a/server/lib/api/index.js +++ b/server/lib/api/index.js @@ -1,29 +1,19 @@ const express = require('express'); const config = require('../../config'); const bodyParser = require('body-parser'); +const helmet = require('helmet'); const app = express(); const api = express.Router(); const cors = require('./cors'); app.use(cors); +app.use(helmet()); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); // Serve insight ui front end from root dir public folder -app.use(express.static('../app/www')); -app.use('/:stuff', express.static('../app/www')); -app.use('/blocks', express.static('../app/www')); -app.use('/blocks/:blockhash', express.static('../app/www')); -app.use('/block-index', express.static('../app/www')); -app.use('/block-index/:height', express.static('../app/www')); -app.use('/blocks-date/:date', express.static('../app/www')); -app.use('/block/:blockhash', express.static('../app/www')); -app.use('/tx/:txid', express.static('../app/www')); -app.use('/address/:addr', express.static('../app/www')); -app.use('/status', express.static('../app/www')); -app.use('/status/:stuff', express.static('../app/www')); -app.use('/status/:stuff', express.static('../app/www')); +app.use(express.static('../app/www', { maxage: '1w' })); app.set('json spaces', config.api.json_spaces); diff --git a/server/package.json b/server/package.json index 7a31453..acdc50d 100644 --- a/server/package.json +++ b/server/package.json @@ -17,6 +17,7 @@ "bitcore-message": "^1.0.4", "body-parser": "^1.17.2", "express": "^4.15.3", + "helmet": "^3.8.1", "mongoose": "^4.11.5", "request": "^2.81.0", "socket.io": "^2.0.3", From d86cdd3678959627e850a50e6344110d8ef21419 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Tue, 22 Aug 2017 10:34:55 -0400 Subject: [PATCH 19/20] Fix /txs default return to return the properly transformed response --- server/lib/api/transaction.js | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/server/lib/api/transaction.js b/server/lib/api/transaction.js index 6d6c4a4..ea0ef2b 100644 --- a/server/lib/api/transaction.js +++ b/server/lib/api/transaction.js @@ -64,6 +64,7 @@ module.exports = function transactionAPI(router) { const pageNum = parseInt(req.query.pageNum, 10) || 0; const rangeStart = pageNum * MAX_TXS; const rangeEnd = rangeStart + MAX_TXS; + const height = db.blocks.bestHeight(); // get txs for blockhash, start with best height to calc confirmations if (req.query.block) { if (!util.isBlockHash(req.query.block)) { @@ -71,7 +72,6 @@ module.exports = function transactionAPI(router) { error: 'Invalid block hash', }); } - const height = db.blocks.bestHeight(); return db.txs.getTxCountByBlock(req.query.block, (err, count) => { if (err) { @@ -87,6 +87,7 @@ module.exports = function transactionAPI(router) { `getTxByBlock ${error}`); return res.status(404).send(); } + return res.send({ pagesTotal: totalPages, txs: txs.map(tx => ({ @@ -122,7 +123,6 @@ module.exports = function transactionAPI(router) { } // Get txs by address, start with best height to calc confirmations - const height = db.blocks.bestHeight(); const addr = req.query.address || ''; db.txs.getTxCountByAddress(req.query.address, (err, count) => { @@ -174,7 +174,30 @@ module.exports = function transactionAPI(router) { `/txs getTopTransactions ${err}`); return res.status(404).send(err); } - return res.json(txs); + return res.json({ + txs: txs.map(tx => ({ + txid: tx.hash, + 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 => ({ + scriptSig: { + asm: input.script, + }, + addr: input.address, + value: input.value / 1e8, + })), + vout: tx.outputs.map(output => ({ + scriptPubKey: { + asm: output.script, + addresses: [output.address], + }, + value: output.value / 1e8, + })), + isCoinBase: tx.inputs[0].prevout.hash === '0000000000000000000000000000000000000000000000000000000000000000', + })), + }); }); } }); From 52ebe7dde0f6523666851b572b95287fdddec9a8 Mon Sep 17 00:00:00 2001 From: tenthirtyone Date: Tue, 22 Aug 2017 14:10:19 -0400 Subject: [PATCH 20/20] bugfix, return array instead of object --- server/index.js | 2 +- server/lib/api/index.js | 7 +++++- server/lib/api/transaction.js | 46 +++++++++++++++++------------------ 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/server/index.js b/server/index.js index 47b2141..6cf93ad 100644 --- a/server/index.js +++ b/server/index.js @@ -1,7 +1,7 @@ const Bcoin = require('./lib/node'); const config = require('./config'); const logger = require('./lib/logger'); -const Api = require('./lib/api'); +const Api = require('./lib/api').server; const db = require('./lib/db'); logger.log('debug', diff --git a/server/lib/api/index.js b/server/lib/api/index.js index 27692f6..c8aced1 100644 --- a/server/lib/api/index.js +++ b/server/lib/api/index.js @@ -14,6 +14,8 @@ app.use(bodyParser.json()); // Serve insight ui front end from root dir public folder app.use(express.static('../app/www', { maxage: '1w' })); +// Legacy UI - useful for 1:1 compares +// app.use(express.static('./public', { maxage: '1w' })); app.set('json spaces', config.api.json_spaces); @@ -37,4 +39,7 @@ app.use((req, res) => res.status(404).send({ // Socket server const server = require('http').Server(app); -module.exports = server; +module.exports = { + server, + api, +}; diff --git a/server/lib/api/transaction.js b/server/lib/api/transaction.js index ea0ef2b..a882ced 100644 --- a/server/lib/api/transaction.js +++ b/server/lib/api/transaction.js @@ -59,7 +59,6 @@ module.exports = function transactionAPI(router) { // /txs is overloaded. Next ver separate concerns // query by block // query by address - // last n txs - haha jk YOU 404 router.get('/txs', (req, res) => { const pageNum = parseInt(req.query.pageNum, 10) || 0; const rangeStart = pageNum * MAX_TXS; @@ -174,30 +173,29 @@ module.exports = function transactionAPI(router) { `/txs getTopTransactions ${err}`); return res.status(404).send(err); } - return res.json({ - txs: txs.map(tx => ({ - txid: tx.hash, - 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 => ({ - scriptSig: { - asm: input.script, - }, - addr: input.address, - value: input.value / 1e8, - })), - vout: tx.outputs.map(output => ({ - scriptPubKey: { - asm: output.script, - addresses: [output.address], - }, - value: output.value / 1e8, - })), - isCoinBase: tx.inputs[0].prevout.hash === '0000000000000000000000000000000000000000000000000000000000000000', + return res.send(txs.map(tx => ({ + txid: tx.hash, + 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 => ({ + scriptSig: { + asm: input.script, + }, + addr: input.address, + value: input.value / 1e8, })), - }); + vout: tx.outputs.map(output => ({ + scriptPubKey: { + asm: output.script, + addresses: [output.address], + }, + value: output.value / 1e8, + })), + isCoinBase: tx.inputs[0].prevout.hash === '0000000000000000000000000000000000000000000000000000000000000000', + })), + ); }); } });