From 5edaf2469da49a372fb16cd453ce4461194e6407 Mon Sep 17 00:00:00 2001 From: Conrad Date: Mon, 17 Dec 2018 17:39:20 -0500 Subject: [PATCH 01/11] fixed table loading ui, working on new api --- app.js | 64 ++++++---- config/default.json | 9 +- lib/api.js | 69 +++++++++++ lib/database.js | 42 +------ lib/explorer.js | 49 -------- lib/settings.js | 9 +- package-lock.json | 228 +++++++++++++++++++++++++++++++++++ package.json | 1 + public/stylesheets/style.css | 15 +++ views/index.jade | 29 +---- 10 files changed, 366 insertions(+), 149 deletions(-) create mode 100644 lib/api.js diff --git a/app.js b/app.js index dcc2f258b..4fa5f40a0 100644 --- a/app.js +++ b/app.js @@ -1,7 +1,7 @@ const express = require('express'), debug = require('debug')('explorer'), path = require('path'), - bitcoinapi = require('bitcoin-node-api'), + { Api, AccessTypes } = require('./lib/api'), favicon = require('static-favicon'), logger = require('morgan'), cookieParser = require('cookie-parser'), @@ -31,30 +31,23 @@ setInterval(function () { const info = require('./info'); info(app) -// bitcoinapi -bitcoinapi.setWalletDetails(settings.wallet); -if (settings.heavy != true) { - bitcoinapi.setAccess('only', [ 'getinfo', 'getnetworkhashps', 'getmininginfo','getdifficulty', 'getconnectioncount', - 'getblockcount', 'getblockhash', 'getblock', 'getrawtransaction', 'getpeerinfo', 'gettxoutsetinfo', 'getmempoolinfo', 'getrawmempool' ]); -} else { - // enable additional heavy api calls - /* - getvote - Returns the current block reward vote setting. - getmaxvote - Returns the maximum allowed vote for the current phase of voting. - getphase - Returns the current voting phase ('Mint', 'Limit' or 'Sustain'). - getreward - Returns the current block reward, which has been decided democratically in the previous round of block reward voting. - getnextrewardestimate - Returns an estimate for the next block reward based on the current state of decentralized voting. - getnextrewardwhenstr - Returns string describing how long until the votes are tallied and the next block reward is computed. - getnextrewardwhensec - Same as above, but returns integer seconds. - getsupply - Returns the current money supply. - getmaxmoney - Returns the maximum possible money supply. - */ - bitcoinapi.setAccess('only', [ 'getinfo', 'getstakinginfo', 'getnetworkhashps', 'getdifficulty', 'getconnectioncount', - 'getblockcount', 'getblockhash', 'getblock', 'getrawtransaction','getmaxmoney', 'getvote', - 'getmaxvote', 'getphase', 'getreward', 'getnextrewardestimate', 'getnextrewardwhenstr', - 'getnextrewardwhensec', 'getsupply', 'gettxoutsetinfo', 'getmempoolinfo', 'getrawmempool' ]); -} -// view engine setup +// bitcoinapi.setWalletDetails(settings.wallet); +// bitcoinapi.setAccess('only', [ +// 'getnetworkhashps', +// 'getmininginfo', +// 'getdifficulty', +// 'getconnectioncount', +// 'getblockcount', +// 'getblockhash', +// 'getblock', +// 'getrawtransaction', +// 'getpeerinfo', +// 'gettxoutsetinfo', +// 'getmempoolinfo', +// 'getrawmempool' +// ]); + + // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); @@ -66,7 +59,26 @@ app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); // routes -app.use('/api', bitcoinapi.app); +app.use('/api', (new Api({ + rpcConfig: { + type: AccessTypes.ONLY, + rpc: [ + 'getnetworkhashps', + 'getmininginfo', + 'getdifficulty', + 'getconnectioncount', + 'getblockcount', + 'getblockhash', + 'getblock', + 'getrawtransaction', + 'getpeerinfo', + 'gettxoutsetinfo', + 'getmempoolinfo', + 'getrawmempool' + ] + }, + wallet: settings.wallet +})).app); app.use('/', routes); app.use('/ext/getmoneysupply', function(req,res){ lib.get_supply(function(supply){ diff --git a/config/default.json b/config/default.json index 67a682bfd..e0fbb0cf3 100644 --- a/config/default.json +++ b/config/default.json @@ -8,7 +8,12 @@ "wallet": { "url": "http://localhost:18332", "username": "undefined", - "password": "undefined" + "password": "undefined", + "network": "testnet", + "ssl": { + "enabled": false, + "strict": false + } }, "title": "Equibit", "address": "http://127.0.0.1:3001", @@ -72,7 +77,7 @@ "youtube": "UCBWEY89pt-DpPYyPedqGWEg", "genesis_tx": "ea914133c255e8b47fb99d26b8627f90e12f5a9c3bc86269652d474d9814aaca", "genesis_block": "0000e9b3a79f70fb0be95b38604636441323450731e9ee1b5ef410791dac7184", - "heavy": false, + "heavy": true, "txcount": 100, "show_sent_received": true, "supply": "COINBASE", diff --git a/lib/api.js b/lib/api.js new file mode 100644 index 000000000..22b0441ad --- /dev/null +++ b/lib/api.js @@ -0,0 +1,69 @@ +const express = require('express') +const debug = require('debug')('explorer:api') +const Client = require('bitcoin-core') +const settings = require('./settings') +const db = require('./database') + +const AccessTypes = Object.freeze({ 'ALL': 0, 'ONLY': 1, 'EXCEPT': 2 }) + +class Api { + + constructor ({ rpcConfig, wallet }) { + this.app = express() + this.allowedRpc = rpcConfig + this.walletDetails = wallet + this.client = new Client(wallet) + + this.app.get('*', this.hasAccess.bind(this), (req, res) => { + const method = req.path.substr(1) + if (Api.requiresCredentials.includes(method) && !this.client.password) { + return res.send('A wallet password is required and has not been set.') + } + const params = (req.query instanceof Array ? req.query : Object.values(req.query)).map(param => isNaN(param) ? param : parseFloat(param)) + // res.send(await this.client[method](...params)) + this.client.command([ { method, params } ]).then(([ resp, err ]) => { + if (err) { + console.log(err) + res.send('There was an error, check your console.') + } else res.send(resp) + }) + }) + } + + hasAccess(req, res, next) { + if (this.allowedRpc.type === AccessTypes.ALL) return next() + + const method = req.path.substr(1) + if ( + (this.allowedRpc.type === AccessTypes.ONLY && this.allowedRpc.rpc.includes(method)) + || (this.allowedRpc.type === AccessTypes.EXCEPT && !this.allowedRpc.rpc.includes(method)) + ) { + return next() + } else { + res.end('This method is restricted') + } + } + + setCredentials(creds) { + this.client = new Client({ ...this.walletDetails, creds }) + } + + static get requiresCredentials() { + return [ + 'dumpprivkey', + 'importprivkey', + 'keypoolrefill', + 'sendfrom', + 'sendmany', + 'sendtoaddress', + 'signmessage', + 'signrawtransaction' + ] + } + +} + +module.exports = { + Api, + AccessTypes +} diff --git a/lib/database.js b/lib/database.js index 30cf7076d..68378e3eb 100644 --- a/lib/database.js +++ b/lib/database.js @@ -529,47 +529,7 @@ module.exports = { // height: current block height, count: amount of votes to store update_heavy: function(coin, height, count, cb) { var newVotes = []; - lib.get_maxmoney( function (maxmoney) { - lib.get_maxvote( function (maxvote) { - lib.get_vote( function (vote) { - lib.get_phase( function (phase) { - lib.get_reward( function (reward) { - lib.get_supply( function (supply) { - lib.get_estnext( function (estnext) { - lib.get_nextin( function (nextin) { - lib.syncLoop(count, function (loop) { - var i = loop.iteration(); - lib.get_blockhash(height-i, function (hash) { - lib.getBlock(hash, function (block) { - newVotes.push({count:height-i,reward:block.reward,vote:block.vote}); - loop.next(); - }); - }); - }, function(){ - console.log(newVotes); - Heavy.update({coin: coin}, { - lvote: vote, - reward: reward, - supply: supply, - cap: maxmoney, - estnext: estnext, - phase: phase, - maxvote: maxvote, - nextin: nextin, - votes: newVotes, - }, function() { - //console.log('address updated: %s', hash); - return cb(); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); + return cb(); }, // updates market data for given market; called by sync.js diff --git a/lib/explorer.js b/lib/explorer.js index c588b7a9d..091511d2b 100644 --- a/lib/explorer.js +++ b/lib/explorer.js @@ -137,55 +137,6 @@ module.exports = { }) }, - get_maxmoney: function (cb) { - var uri = base_url + 'getmaxmoney' - request({uri: uri, json: true}, function (error, response, body) { - return cb(body) - }) - }, - - get_maxvote: function (cb) { - var uri = base_url + 'getmaxvote' - request({uri: uri, json: true}, function (error, response, body) { - return cb(body) - }) - }, - - get_vote: function (cb) { - var uri = base_url + 'getvote' - request({uri: uri, json: true}, function (error, response, body) { - return cb(body) - }) - }, - - get_phase: function (cb) { - var uri = base_url + 'getphase' - request({uri: uri, json: true}, function (error, response, body) { - return cb(body) - }) - }, - - get_reward: function (cb) { - var uri = base_url + 'getreward' - request({uri: uri, json: true}, function (error, response, body) { - return cb(body) - }) - }, - - get_estnext: function (cb) { - var uri = base_url + 'getnextrewardestimate' - request({uri: uri, json: true}, function (error, response, body) { - return cb(body) - }) - }, - - get_nextin: function (cb) { - var uri = base_url + 'getnextrewardwhenstr' - request({uri: uri, json: true}, function (error, response, body) { - return cb(body) - }) - }, - // synchonous loop used to interate through an array, // avoid use unless absolutely neccessary syncLoop: function (iterations, process, exit) { diff --git a/lib/settings.js b/lib/settings.js index fbe0c7e98..5039a39c7 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -50,16 +50,15 @@ exports.dbsettings = safeGet('dbsettings') || { //This setting is passed to the wallet -// must be of this format in order for bitcoin-node-api to accept it -const cleanupValue = value => value.replace(/[^\w\.\:\/\=]/g, '') +// must be of this format in order for bitcoin-core to accept it const savedWallet = safeGet('wallet') || { url: '' }; -const [host, port] = cleanupValue(savedWallet.url).split('://').slice(-1)[0].split(':') || [] +const [ host, port ] = savedWallet.url.split('://').slice(-1)[0].split(':') || [] console.log(`- settings: host=${host}, port=${port}`) +delete savedWallet['url'] exports.wallet = { + ...savedWallet, 'host' : host || '127.0.0.1', 'port' : port || 8669, - 'user' : cleanupValue(savedWallet.username) || 'bitcoinrpc', - 'pass' : cleanupValue(savedWallet.password) || 'password' }; diff --git a/package-lock.json b/package-lock.json index 1bbbc3c9d..3afb1c889 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,21 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@uphold/request-logger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@uphold/request-logger/-/request-logger-2.0.0.tgz", + "integrity": "sha1-xYXAvblCEBmJRcZZfk/iPW5j4IQ=", + "requires": { + "uuid": "^3.0.1" + }, + "dependencies": { + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + } + } + }, "accepts": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.0.1.tgz", @@ -56,6 +71,12 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "optional": true + }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -64,6 +85,11 @@ "tweetnacl": "^0.14.3" } }, + "bignumber.js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.1.0.tgz", + "integrity": "sha512-eJzYkFYy9L4JzXsbymsFn3p54D+llV27oTQ+ziJG7WFRheJcNZilgVXMG0LoZtlQSKBsJdWtLFqOD0u+U0jZKA==" + }, "bitcoin": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/bitcoin/-/bitcoin-1.7.0.tgz", @@ -72,6 +98,21 @@ "deprecate": "~0.1.0" } }, + "bitcoin-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bitcoin-core/-/bitcoin-core-2.0.0.tgz", + "integrity": "sha512-I6I7ejzbXfyMtR5/z0BhfjTeN8PMQGD+1B1rpu6IoLcwqoybaSa+P4zYnja/p2xdqjdctmgbOtAaCaaqyVCycQ==", + "requires": { + "@uphold/request-logger": "^2.0.0", + "bluebird": "^3.4.1", + "debugnyan": "^1.0.0", + "json-bigint": "^0.2.0", + "lodash": "^4.0.0", + "request": "^2.53.0", + "semver": "^5.1.0", + "standard-error": "^1.1.0" + } + }, "bitcoin-node-api": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bitcoin-node-api/-/bitcoin-node-api-0.1.0.tgz", @@ -129,6 +170,11 @@ } } }, + "bluebird": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" + }, "body-parser": { "version": "1.0.2", "resolved": "http://registry.npmjs.org/body-parser/-/body-parser-1.0.2.tgz", @@ -154,11 +200,32 @@ "hoek": "2.x.x" } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "buffer-crc32": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz", "integrity": "sha1-vj5TgvwCttYySVasGvmKqYsIU0w=" }, + "bunyan": { + "version": "1.8.12", + "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", + "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", + "requires": { + "dtrace-provider": "~0.8", + "moment": "^2.10.6", + "mv": "~2", + "safe-json-stringify": "~1" + } + }, "bytes": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz", @@ -207,6 +274,12 @@ "keypress": "0.1.x" } }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "optional": true + }, "config": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/config/-/config-3.0.0.tgz", @@ -320,6 +393,25 @@ "resolved": "http://registry.npmjs.org/debug/-/debug-0.7.4.tgz", "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" }, + "debugnyan": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/debugnyan/-/debugnyan-1.0.0.tgz", + "integrity": "sha1-kDhtXrwsY1iPF/Jyvlwqk7dmXYM=", + "requires": { + "bunyan": "^1.8.1", + "debug": "^2.2.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -335,6 +427,15 @@ "resolved": "http://registry.npmjs.org/deprecate/-/deprecate-0.1.0.tgz", "integrity": "sha1-xJBYYS3GyOUUXq/kg5uMLH0EHBQ=" }, + "dtrace-provider": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.7.tgz", + "integrity": "sha1-3JObTT4GIM/gwc2APQ0tftBP/QQ=", + "optional": true, + "requires": { + "nan": "^2.10.0" + } + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -572,6 +673,16 @@ "sshpk": "^1.7.0" } }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -656,6 +767,14 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, + "json-bigint": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.2.3.tgz", + "integrity": "sha1-EY1/b/HThlnxn5TPc+ZKdaP5iKg=", + "requires": { + "bignumber.js": "^4.0.0" + } + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -783,6 +902,12 @@ "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=" }, + "moment": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz", + "integrity": "sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA==", + "optional": true + }, "mongodb": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.10.tgz", @@ -929,6 +1054,46 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "mv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "optional": true, + "requires": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "optional": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "optional": true, + "requires": { + "minimist": "0.0.8" + } + } + } + }, + "nan": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.0.tgz", + "integrity": "sha512-zT5nC0JhbljmyEf+Z456nvm7iO7XgRV2hYxoBtPpnyp+0Q4aCoP6uWNn76v/I6k2kCYNLWqWbwBWQcjsNI/bjw==", + "optional": true + }, + "ncp": { + "version": "2.0.0", + "resolved": "http://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "optional": true + }, "negotiator": { "version": "0.4.9", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.4.9.tgz", @@ -944,6 +1109,14 @@ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, "optimist": { "version": "0.3.7", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", @@ -957,6 +1130,12 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.0.1.tgz", "integrity": "sha1-Llfc5u/dN8NRhwEDCUTCK/OIt7Q=" }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "optional": true + }, "path-to-regexp": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.2.tgz", @@ -1091,11 +1270,50 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" }, + "rimraf": { + "version": "2.4.5", + "resolved": "http://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "optional": true, + "requires": { + "glob": "^6.0.1" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "optional": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safe-json-stringify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", + "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", + "optional": true + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -1217,6 +1435,11 @@ } } }, + "standard-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/standard-error/-/standard-error-1.1.0.tgz", + "integrity": "sha1-I+UWj6HAggGJ5YEnAaeQWFENDTQ=" + }, "static-favicon": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/static-favicon/-/static-favicon-1.0.2.tgz", @@ -1373,6 +1596,11 @@ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", diff --git a/package.json b/package.json index cf7937ab6..deec74f4f 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "debug": "node --inspect --stack-size=10000 ./bin/cluster" }, "dependencies": { + "bitcoin-core": "^2.0.0", "bitcoin-node-api": "0.1.0", "body-parser": "~1.0.0", "config": "^3.0.0", diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css index d58cb4b5d..0e6eccd93 100644 --- a/public/stylesheets/style.css +++ b/public/stylesheets/style.css @@ -159,3 +159,18 @@ tr { bottom: 0px; } +/* Override DataTables ugly gradient processing overlay */ +div#blocks-table_processing.dataTables_processing { + position: absolute; + top: 50%; + left: 50%; + width: 100%; + height: 40px; + margin-left: -50%; + margin-top: -25px; + padding-top: 20px; + text-align: center; + font-size: 1.2em; + background-color: transparent; + background: transparent; +} diff --git a/views/index.jade b/views/index.jade index aa82f28da..2f9d400ed 100644 --- a/views/index.jade +++ b/views/index.jade @@ -3,31 +3,6 @@ extends layout block content script. $(document).ready(function () { - var stable = $('#block-table').dataTable( { - autoWidth: true, - searching: true, - ordering: false, - responsive: true, - lengthChange: false, - processing: true, - paging: false, - info: false, - ajax: { - url: '/ext/summary', - dataSrc: function (json) { - json.data[0]['height'] = "" + json.data[0]['height'] + "" - return json.data - } - }, - columns: [ - { data: 'blockcount', width: '8%' }, - { data: 'difficulty', width: '10%' }, - //- { data: 'size', width:'10%' }, - //- { data: 'txs', width: '10%' }, - { data: 'supply', width: '15%' }, - //- { data: 'time', width: '20%' }, - ] - }) var btable = $('#blocks-table').dataTable({ autoWidth: true, searching: false, @@ -35,6 +10,9 @@ block content responsive: true, lengthChange: true, processing: true, + language: { + processing: 'Loading...' + }, serverSide: true, ajax: function (data, cb, settings) { $.ajax({ @@ -60,7 +38,6 @@ block content ] }) setInterval(function () { - stable.api().ajax.reload(null, false) btable.api().ajax.reload(null, false) }, 30000) }); From bd1d4151680fb31f1d34eb4b96acf180c2a5678f Mon Sep 17 00:00:00 2001 From: Conrad Date: Tue, 18 Dec 2018 11:06:45 -0500 Subject: [PATCH 02/11] got rid of bitcoin-node-api --- app.js | 3 +- lib/api.js | 10 +- package-lock.json | 613 ++++++++++++++++------------------------------ package.json | 1 - routes/index.js | 1 + views/block.jade | 8 - views/info.jade | 38 +-- views/layout.jade | 5 - 8 files changed, 215 insertions(+), 464 deletions(-) diff --git a/app.js b/app.js index 4fa5f40a0..ac3a169a4 100644 --- a/app.js +++ b/app.js @@ -160,7 +160,7 @@ app.use('/ext/getblocks/:start/:end', function (req, res) { const infoReq = (blockcount) => Promise.all(heights.map(i => promisify(lib.get_blockhash, i) .then(hash => - hash.includes('There was an error') ? null : lib.getBlock(hash, undefined, blockcount) + hash.name === 'RpcError' ? null : lib.getBlock(hash, undefined, blockcount) ) )).then(infos => strip ? infos.filter(info => info !== null) : infos) const onErr = err => { @@ -212,7 +212,6 @@ app.set('googleplus', settings.googleplus); app.set('youtube', settings.youtube); app.set('genesis_block', settings.genesis_block); app.set('index', settings.index); -app.set('heavy', settings.heavy); app.set('txcount', settings.txcount); app.set('nethash', settings.nethash); app.set('nethash_units', settings.nethash_units); diff --git a/lib/api.js b/lib/api.js index 22b0441ad..8dd446fe9 100644 --- a/lib/api.js +++ b/lib/api.js @@ -19,13 +19,17 @@ class Api { if (Api.requiresCredentials.includes(method) && !this.client.password) { return res.send('A wallet password is required and has not been set.') } - const params = (req.query instanceof Array ? req.query : Object.values(req.query)).map(param => isNaN(param) ? param : parseFloat(param)) + const parameters = (req.query instanceof Array ? req.query : Object.values(req.query)).map(param => isNaN(param) ? param : parseFloat(param)) // res.send(await this.client[method](...params)) - this.client.command([ { method, params } ]).then(([ resp, err ]) => { + this.client.command([ { method, parameters } ]).then(([ resp, err ]) => { if (err) { console.log(err) res.send('There was an error, check your console.') - } else res.send(resp) + } else { + // if its an object just send it as is, otherwise cast to string + if (resp instanceof Object) res.send(resp) + else res.send(''+resp) + } }) }) } diff --git a/package-lock.json b/package-lock.json index 3afb1c889..b700b1fbe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,13 +10,6 @@ "integrity": "sha1-xYXAvblCEBmJRcZZfk/iPW5j4IQ=", "requires": { "uuid": "^3.0.1" - }, - "dependencies": { - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - } } }, "accepts": { @@ -61,6 +54,14 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" }, + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "requires": { + "lodash": "^4.17.10" + } + }, "aws-sign2": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", @@ -74,8 +75,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "optional": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -90,14 +90,6 @@ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.1.0.tgz", "integrity": "sha512-eJzYkFYy9L4JzXsbymsFn3p54D+llV27oTQ+ziJG7WFRheJcNZilgVXMG0LoZtlQSKBsJdWtLFqOD0u+U0jZKA==" }, - "bitcoin": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/bitcoin/-/bitcoin-1.7.0.tgz", - "integrity": "sha1-OeVzZG9NiBeYmODOhuNcs538afE=", - "requires": { - "deprecate": "~0.1.0" - } - }, "bitcoin-core": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/bitcoin-core/-/bitcoin-core-2.0.0.tgz", @@ -113,61 +105,12 @@ "standard-error": "^1.1.0" } }, - "bitcoin-node-api": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/bitcoin-node-api/-/bitcoin-node-api-0.1.0.tgz", - "integrity": "sha1-3r88cxzRAnckoI3ovTKMY2Tr6O4=", - "requires": { - "bitcoin": "1.7.0", - "express": "3.3.x" - }, - "dependencies": { - "express": { - "version": "3.3.8", - "resolved": "http://registry.npmjs.org/express/-/express-3.3.8.tgz", - "integrity": "sha1-jpisMNgfTJW4XXHSr2z4T2LvGb0=", - "requires": { - "buffer-crc32": "0.2.1", - "commander": "1.2.0", - "connect": "2.8.8", - "cookie": "0.1.0", - "cookie-signature": "1.0.1", - "debug": "*", - "fresh": "0.2.0", - "methods": "0.0.1", - "mkdirp": "0.3.5", - "range-parser": "0.0.4", - "send": "0.1.4" - } - } - } - }, "bl": { "version": "1.1.2", "resolved": "http://registry.npmjs.org/bl/-/bl-1.1.2.tgz", "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", "requires": { "readable-stream": "~2.0.5" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.0.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - } } }, "bluebird": { @@ -187,7 +130,7 @@ "dependencies": { "qs": { "version": "0.6.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz", + "resolved": "http://registry.npmjs.org/qs/-/qs-0.6.6.tgz", "integrity": "sha1-bgFQmP9RlouKPIGQAdXyyJvEsQc=" } } @@ -204,12 +147,16 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, + "bson": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.0.tgz", + "integrity": "sha512-9Aeai9TacfNtWXOYarkFJRW2CWo+dRon+fuLZYJmvLV3+MiUp0bEI6IAZfXEIg7/Pl/7IWlLaDnhzTsD81etQA==" + }, "buffer-crc32": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz", @@ -227,9 +174,9 @@ } }, "bytes": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz", - "integrity": "sha1-qtM+wU49wsp06OfUUfm6BTrU96A=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", + "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=" }, "camelcase": { "version": "1.2.1", @@ -267,46 +214,23 @@ } }, "commander": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/commander/-/commander-1.2.0.tgz", - "integrity": "sha1-/VcTv6FTx9bMWZN4patMRcU1Ap4=", - "requires": { - "keypress": "0.1.x" - } + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "optional": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "config": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/config/-/config-3.0.0.tgz", - "integrity": "sha512-QMr3BCOcHdgXx8t8cLfBhWtHcIAAMikaxUc2XASuH2A93g9kOIRch7sXFQdSvdMxhQobnctWm2y68YJYRttJlw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/config/-/config-3.0.1.tgz", + "integrity": "sha512-TBNrrk2b6AybUohqXw2AydglFBL9b/+1GG93Di6Fm6x1SyVJ5PYgo+mqY2X0KpU9m0PJDSbFaC5H95utSphtLw==", "requires": { "json5": "^1.0.1" } }, - "connect": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/connect/-/connect-2.8.8.tgz", - "integrity": "sha1-uav4yvC9l3PLPeopNEEZhyWCRG0=", - "requires": { - "buffer-crc32": "0.2.1", - "bytes": "0.2.0", - "cookie": "0.1.0", - "cookie-signature": "1.0.1", - "debug": "*", - "formidable": "1.0.14", - "fresh": "0.2.0", - "methods": "0.0.1", - "pause": "0.0.1", - "qs": "0.6.5", - "send": "0.1.4", - "uid2": "0.0.2" - } - }, "constantinople": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-2.0.1.tgz", @@ -327,19 +251,12 @@ "requires": { "cookie": "0.1.0", "cookie-signature": "1.0.3" - }, - "dependencies": { - "cookie-signature": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.3.tgz", - "integrity": "sha1-kc2ZfMUftkFZVzjGnNoCAyj1D/k=" - } } }, "cookie-signature": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz", - "integrity": "sha1-ROByFIrwHm6OJK+/EmkNaK5pjss=" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.3.tgz", + "integrity": "sha1-kc2ZfMUftkFZVzjGnNoCAyj1D/k=" }, "core-util-is": { "version": "1.0.2", @@ -422,11 +339,6 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, - "deprecate": { - "version": "0.1.0", - "resolved": "http://registry.npmjs.org/deprecate/-/deprecate-0.1.0.tgz", - "integrity": "sha1-xJBYYS3GyOUUXq/kg5uMLH0EHBQ=" - }, "dtrace-provider": { "version": "0.8.7", "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.7.tgz", @@ -484,54 +396,15 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.2.tgz", "integrity": "sha1-cv7D0k5Io0Mgc9kMEmQgBQYQBLE=" }, - "cookie-signature": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.3.tgz", - "integrity": "sha1-kc2ZfMUftkFZVzjGnNoCAyj1D/k=" - }, "debug": { "version": "0.8.1", "resolved": "http://registry.npmjs.org/debug/-/debug-0.8.1.tgz", "integrity": "sha1-IP9NJvXkIstoobrLu2EDmtjBwTA=" }, - "fresh": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.2.tgz", - "integrity": "sha1-lzHc9WeMf660T7kDxPct9VGH+nc=" - }, - "methods": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.0.0.tgz", - "integrity": "sha1-mnPYY3XfzvJu9hyj5Lii4lOKgOM=" - }, "qs": { "version": "0.6.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz", + "resolved": "http://registry.npmjs.org/qs/-/qs-0.6.6.tgz", "integrity": "sha1-bgFQmP9RlouKPIGQAdXyyJvEsQc=" - }, - "range-parser": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.0.tgz", - "integrity": "sha1-pLJkz+C+XONqvjdlrJwqJIdG28A=" - }, - "send": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.3.0.tgz", - "integrity": "sha1-lxgyRjSAb8dbxPj15R9X2dZmBuc=", - "requires": { - "buffer-crc32": "0.2.1", - "debug": "0.8.0", - "fresh": "~0.2.1", - "mime": "1.2.11", - "range-parser": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "0.8.0", - "resolved": "http://registry.npmjs.org/debug/-/debug-0.8.0.tgz", - "integrity": "sha1-BUHqkfDlA/3wxe7UGKMlUCNJZ/A=" - } - } } } }, @@ -558,27 +431,12 @@ "async": "^2.0.1", "combined-stream": "^1.0.5", "mime-types": "^2.1.11" - }, - "dependencies": { - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "requires": { - "lodash": "^4.17.10" - } - } } }, - "formidable": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz", - "integrity": "sha1-Kz9MQRy7X91pXESEPiojUUpDIxo=" - }, "fresh": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.0.tgz", - "integrity": "sha1-v9lALPPfEsSkwxDHn5mj3eE9NKc=" + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.2.tgz", + "integrity": "sha1-lzHc9WeMf660T7kDxPct9VGH+nc=" }, "generate-function": { "version": "2.3.1", @@ -612,13 +470,16 @@ } }, "glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", - "dev": true, + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "optional": true, "requires": { + "inflight": "^1.0.4", "inherits": "2", - "minimatch": "0.3" + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "har-validator": { @@ -630,13 +491,6 @@ "commander": "^2.9.0", "is-my-json-valid": "^2.12.4", "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" - } } }, "has-ansi": { @@ -720,6 +574,11 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -743,6 +602,11 @@ "version": "2.1.0", "resolved": "http://registry.npmjs.org/commander/-/commander-2.1.0.tgz", "integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=" + }, + "mkdirp": { + "version": "0.3.5", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=" } } }, @@ -754,6 +618,28 @@ "requires": { "glob": "^3.2.11", "jasmine-core": "~2.1.0" + }, + "dependencies": { + "glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "dev": true, + "requires": { + "inherits": "2", + "minimatch": "0.3" + } + }, + "minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "dev": true, + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + } } }, "jasmine-core": { @@ -791,6 +677,13 @@ "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "requires": { "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } } }, "jsonminify": { @@ -821,10 +714,10 @@ } } }, - "keypress": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz", - "integrity": "sha1-SjGI1CkbZrT2XtuZ+AaqmuKTWSo=" + "kareem": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.0.tgz", + "integrity": "sha512-6hHxsp9e6zQU8nXsP+02HGWXwTkOEw6IROhF2ZA28cYbUk4eJ6QbtZvdqZOdD9YPKghG3apk5eOCvs+tLl3lRg==" }, "lodash": { "version": "4.17.11", @@ -839,7 +732,8 @@ "lru-cache": { "version": "2.7.3", "resolved": "http://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=" + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true }, "markdown-js": { "version": "0.0.3", @@ -850,9 +744,9 @@ } }, "memory-pager": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.1.0.tgz", - "integrity": "sha512-Mf9OHV/Y7h6YWDxTzX/b4ZZ4oh9NSXblQL8dtPCOomOtZciEHxePR78+uHFLLlsk01A6jVHhHsQZZ/WcIPpnzg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.3.1.tgz", + "integrity": "sha512-pUf/sGkym2WqFZYTVmdASnSbNfpGc9rwxEHOePx4lT/fD+NHGL1U16Uy4o6PMiVcDv4mp6MI/vaF0c/Kd1QEUQ==", "optional": true }, "merge-descriptors": { @@ -861,13 +755,13 @@ "integrity": "sha1-w2pSp4FDdRPFcnXzndnTF1FKyMc=" }, "methods": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz", - "integrity": "sha1-J3yQ+L7zlwlkWoNxxRw7bGSOBow=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.0.0.tgz", + "integrity": "sha1-mnPYY3XfzvJu9hyj5Lii4lOKgOM=" }, "mime": { "version": "1.2.11", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "resolved": "http://registry.npmjs.org/mime/-/mime-1.2.11.tgz", "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=" }, "mime-db": { @@ -884,23 +778,27 @@ } }, "minimatch": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" + "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + "version": "0.0.8", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "optional": true }, "mkdirp": { - "version": "0.3.5", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=" + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "optional": true, + "requires": { + "minimist": "0.0.8" + } }, "moment": { "version": "2.23.0", @@ -915,30 +813,23 @@ "requires": { "mongodb-core": "3.1.9", "safe-buffer": "^5.1.2" - }, - "dependencies": { - "bson": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.0.tgz", - "integrity": "sha512-9Aeai9TacfNtWXOYarkFJRW2CWo+dRon+fuLZYJmvLV3+MiUp0bEI6IAZfXEIg7/Pl/7IWlLaDnhzTsD81etQA==" - }, - "mongodb-core": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.1.9.tgz", - "integrity": "sha512-MJpciDABXMchrZphh3vMcqu8hkNf/Mi+Gk6btOimVg1XMxLXh87j6FAvRm+KmwD1A9fpu3qRQYcbQe4egj23og==", - "requires": { - "bson": "^1.1.0", - "require_optional": "^1.0.1", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" - } - } + } + }, + "mongodb-core": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.1.9.tgz", + "integrity": "sha512-MJpciDABXMchrZphh3vMcqu8hkNf/Mi+Gk6btOimVg1XMxLXh87j6FAvRm+KmwD1A9fpu3qRQYcbQe4egj23og==", + "requires": { + "bson": "^1.1.0", + "require_optional": "^1.0.1", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" } }, "mongoose": { - "version": "5.3.14", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.3.14.tgz", - "integrity": "sha512-Vt7uC0+/SuPb+x6IwbtXl4tkUER1xU9INlfrDK1RdfsvvEMfG3FJUGNPVGeTWQaj8xqMBtZKIdUNt58rIAsCYg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.4.0.tgz", + "integrity": "sha512-pFKa6askJ6xwZT6mWuYBwa2R9ryd1+JrXUhKuAUxEGrUMTi8ADcJC/RgBg4fZ1lL6VPVVChsc9wpVn4X6gcWlg==", "requires": { "async": "2.6.1", "bson": "~1.1.0", @@ -953,72 +844,6 @@ "regexp-clone": "0.0.1", "safe-buffer": "5.1.2", "sliced": "1.0.1" - }, - "dependencies": { - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "requires": { - "lodash": "^4.17.10" - } - }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" - }, - "bson": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.0.tgz", - "integrity": "sha512-9Aeai9TacfNtWXOYarkFJRW2CWo+dRon+fuLZYJmvLV3+MiUp0bEI6IAZfXEIg7/Pl/7IWlLaDnhzTsD81etQA==" - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "kareem": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.0.tgz", - "integrity": "sha512-6hHxsp9e6zQU8nXsP+02HGWXwTkOEw6IROhF2ZA28cYbUk4eJ6QbtZvdqZOdD9YPKghG3apk5eOCvs+tLl3lRg==" - }, - "mongodb-core": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.1.9.tgz", - "integrity": "sha512-MJpciDABXMchrZphh3vMcqu8hkNf/Mi+Gk6btOimVg1XMxLXh87j6FAvRm+KmwD1A9fpu3qRQYcbQe4egj23og==", - "requires": { - "bson": "^1.1.0", - "require_optional": "^1.0.1", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" - } - }, - "mpath": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.5.1.tgz", - "integrity": "sha512-H8OVQ+QEz82sch4wbODFOz+3YQ61FYz/z3eJ5pIdbMEaUzDqA268Wd+Vt4Paw9TJfvDgVKaayC0gBzMIw2jhsg==" - }, - "mquery": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.0.tgz", - "integrity": "sha512-qPJcdK/yqcbQiKoemAt62Y0BAc0fTEKo1IThodBD+O5meQRJT/2HSe5QpBNwaa4CjskoGrYWsEyjkqgiE0qjhg==", - "requires": { - "bluebird": "3.5.1", - "debug": "3.1.0", - "regexp-clone": "0.0.1", - "safe-buffer": "5.1.2", - "sliced": "1.0.1" - } - }, - "sliced": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", - "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" - } } }, "mongoose-legacy-pluralize": { @@ -1049,6 +874,38 @@ } } }, + "mpath": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.5.1.tgz", + "integrity": "sha512-H8OVQ+QEz82sch4wbODFOz+3YQ61FYz/z3eJ5pIdbMEaUzDqA268Wd+Vt4Paw9TJfvDgVKaayC0gBzMIw2jhsg==" + }, + "mquery": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.0.tgz", + "integrity": "sha512-qPJcdK/yqcbQiKoemAt62Y0BAc0fTEKo1IThodBD+O5meQRJT/2HSe5QpBNwaa4CjskoGrYWsEyjkqgiE0qjhg==", + "requires": { + "bluebird": "3.5.1", + "debug": "3.1.0", + "regexp-clone": "0.0.1", + "safe-buffer": "5.1.2", + "sliced": "1.0.1" + }, + "dependencies": { + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -1063,23 +920,6 @@ "mkdirp": "~0.5.1", "ncp": "~2.0.0", "rimraf": "~2.4.0" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "optional": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "optional": true, - "requires": { - "minimist": "0.0.8" - } - } } }, "nan": { @@ -1099,11 +939,6 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.4.9.tgz", "integrity": "sha1-kuRrbbU8fkIe1koryU8IvnYw3z8=" }, - "node-uuid": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", - "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" - }, "oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", @@ -1141,11 +976,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.2.tgz", "integrity": "sha1-mysVH5zDAYye6lDKlXKeBXgXErQ=" }, - "pause": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", - "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" - }, "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", @@ -1183,14 +1013,14 @@ "integrity": "sha1-984WQaxdwZUExBqGnfHEuCfXjg0=" }, "qs": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.5.tgz", - "integrity": "sha1-KUsmjksNQlD23eGbO4s0k13/FO8=" + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", + "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=" }, "range-parser": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz", - "integrity": "sha1-wEJ//vUcEKy6B4KkbJYC50T/Ygs=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.0.tgz", + "integrity": "sha1-pLJkz+C+XONqvjdlrJwqJIdG28A=" }, "raw-body": { "version": "1.1.7", @@ -1199,13 +1029,19 @@ "requires": { "bytes": "1", "string_decoder": "0.10" - }, - "dependencies": { - "bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", - "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=" - } + } + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" } }, "readdirp": { @@ -1249,10 +1085,10 @@ "tunnel-agent": "~0.4.1" }, "dependencies": { - "qs": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", - "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=" + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" } } }, @@ -1277,30 +1113,6 @@ "optional": true, "requires": { "glob": "^6.0.1" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "optional": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } } }, "safe-buffer": { @@ -1334,14 +1146,22 @@ "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" }, "send": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/send/-/send-0.1.4.tgz", - "integrity": "sha1-vnDY0b4B3mGCGvE3gLUDRaT3Gr0=", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.3.0.tgz", + "integrity": "sha1-lxgyRjSAb8dbxPj15R9X2dZmBuc=", "requires": { - "debug": "*", - "fresh": "0.2.0", - "mime": "~1.2.9", - "range-parser": "0.0.4" + "buffer-crc32": "0.2.1", + "debug": "0.8.0", + "fresh": "~0.2.1", + "mime": "1.2.11", + "range-parser": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "0.8.0", + "resolved": "http://registry.npmjs.org/debug/-/debug-0.8.0.tgz", + "integrity": "sha1-BUHqkfDlA/3wxe7UGKMlUCNJZ/A=" + } } }, "serve-static": { @@ -1351,41 +1171,18 @@ "requires": { "parseurl": "1.0.1", "send": "0.3.0" - }, - "dependencies": { - "debug": { - "version": "0.8.0", - "resolved": "http://registry.npmjs.org/debug/-/debug-0.8.0.tgz", - "integrity": "sha1-BUHqkfDlA/3wxe7UGKMlUCNJZ/A=" - }, - "fresh": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.4.tgz", - "integrity": "sha1-NYJJkgbJcjcUGQ7ddLRgT+tKYUw=" - }, - "range-parser": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.3.tgz", - "integrity": "sha1-aHKCNTXGkuLCoBA4Jq/YLC4P8XU=" - }, - "send": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.3.0.tgz", - "integrity": "sha1-lxgyRjSAb8dbxPj15R9X2dZmBuc=", - "requires": { - "buffer-crc32": "0.2.1", - "debug": "0.8.0", - "fresh": "~0.2.1", - "mime": "1.2.11", - "range-parser": "~1.0.0" - } - } } }, "sigmund": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" }, "sntp": { "version": "1.0.9", @@ -1447,7 +1244,7 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" }, "stringstream": { @@ -1478,7 +1275,7 @@ }, "tough-cookie": { "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "resolved": "http://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", "requires": { "punycode": "^1.4.1" @@ -1546,11 +1343,6 @@ "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=" }, - "uid2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.2.tgz", - "integrity": "sha1-EH+xVcgsETZiB5ftTIjPKwj2qrg=" - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -1561,6 +1353,11 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", diff --git a/package.json b/package.json index deec74f4f..8124dd152 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ }, "dependencies": { "bitcoin-core": "^2.0.0", - "bitcoin-node-api": "0.1.0", "body-parser": "~1.0.0", "config": "^3.0.0", "cookie-parser": "~1.0.1", diff --git a/routes/index.js b/routes/index.js index dd19000aa..c88bfcf97 100644 --- a/routes/index.js +++ b/routes/index.js @@ -8,6 +8,7 @@ var express = require('express') function route_get_block(res, blockhash) { lib.getBlock(blockhash, function (block) { + console.log(block) const safeRender = list => list && list.length > 0 && list.filter(l => l).length ? list : [] if (block) { if (blockhash === settings.genesis_block) { diff --git a/views/block.jade b/views/block.jade index 2ce7ba956..c9b0197fc 100644 --- a/views/block.jade +++ b/views/block.jade @@ -25,8 +25,6 @@ block content th #{settings.locale.height} th #{settings.locale.difficulty} th #{settings.locale.confirmations} - if settings.heavy == true - th Vote th.hidden-xs #{settings.locale.size} (kB) th.hidden-xs #{settings.locale.bits} th.hidden-xs #{settings.locale.nonce} @@ -38,8 +36,6 @@ block content td #{block.height} td #{block.difficulty.toFixed(4)} td #{block.confirmations} - if settings.heavy == true - td #{block.vote} td.hidden-xs #{block_size.toFixed(2)} td.hidden-xs #{block.bits} td.hidden-xs #{block.nonce} @@ -51,8 +47,6 @@ block content td #{block.height} td #{block.difficulty.toFixed(4)} td #{block.confirmations} - if settings.heavy == true - td #{block.vote} td.hidden-xs #{block_size.toFixed(2)} td.hidden-xs #{block.bits} td.hidden-xs #{block.nonce} @@ -63,8 +57,6 @@ block content td #{block.height} td #{block.difficulty.toFixed(4)} td #{block.confirmations} - if settings.heavy == true - td #{block.vote} td.hidden-xs #{block_size.toFixed(2)} td.hidden-xs #{block.bits} td.hidden-xs #{block.nonce} diff --git a/views/info.jade b/views/info.jade index 079d7389f..28ada562d 100644 --- a/views/info.jade +++ b/views/info.jade @@ -44,43 +44,7 @@ block content :markdown * **getnetworkhashps** *#{settings.locale.api_getnetworkhashps}* - [#{address}/api/getnetworkhashps](/api/getnetworkhashps) - - - - if settings.heavy == true - :markdown - * **getmaxmoney** - *#{settings.locale.api_getmaxmoney}* - [#{address}/api/getmaxmoney](/api/getmaxmoney) - - * **getmaxvote** - *#{settings.locale.api_getmaxvote}* - [#{address}/api/getmaxvote](/api/getmaxvote) - - * **getvote** - *#{settings.locale.api_getvote}* - [#{address}/api/getvote](/api/getvote) - - * **getphase** - *#{settings.locale.api_getphase}* - [#{address}/api/getphase](/api/getphase) - - * **getreward** - *#{settings.locale.api_getreward}* - [#{address}/api/getreward](/api/getreward) - - * **getsupply** - *#{settings.locale.api_getsupply}* - [#{address}/api/getsupply](/api/getsupply) - - * **getnextrewardestimate** - *#{settings.locale.api_getnextrewardestimate}* - [#{address}/api/getnextrewardestimate](/api/getnextrewardestimate) - - * **getnextrewardwhenstr** - *#{settings.locale.api_getnextrewardwhenstr}* - [#{address}/api/getnextrewardwhenstr](/api/getnextrewardwhenstr) + [#{address}/api/getnetworkhashps](/api/getnetworkhashps) :markdown ------ diff --git a/views/layout.jade b/views/layout.jade index 091a9a1bd..8ce3fc910 100644 --- a/views/layout.jade +++ b/views/layout.jade @@ -97,11 +97,6 @@ html a.navbar-link(href='/') span.glyphicon.glyphicon-search span.menu-text #{settings.locale.menu_explorer} - if settings.heavy == true - li#reward - a.navbar-link(href='/reward') - span.fa.fa-star - span.menu-text #{settings.locale.menu_reward} if settings.display.movement == true li#movement a.navbar-link.loading(href='/movement') From b053248379c5809ff265445b34f5184977d66bb2 Mon Sep 17 00:00:00 2001 From: Conrad Date: Tue, 18 Dec 2018 11:53:37 -0500 Subject: [PATCH 03/11] removed heavy stuff --- app.js | 16 ----- config/default.json | 1 - lib/database.js | 54 ---------------- lib/locale.js | 15 ----- lib/settings.js | 1 - locale/en.json | 15 +---- models/heavy.js | 21 ------- public/stylesheets/style.css | 10 --- routes/index.js | 21 ------- scripts/sync.js | 6 +- views/reward.jade | 119 ----------------------------------- 11 files changed, 2 insertions(+), 277 deletions(-) delete mode 100644 models/heavy.js delete mode 100644 views/reward.jade diff --git a/app.js b/app.js index ac3a169a4..b7d55ee15 100644 --- a/app.js +++ b/app.js @@ -31,22 +31,6 @@ setInterval(function () { const info = require('./info'); info(app) -// bitcoinapi.setWalletDetails(settings.wallet); -// bitcoinapi.setAccess('only', [ -// 'getnetworkhashps', -// 'getmininginfo', -// 'getdifficulty', -// 'getconnectioncount', -// 'getblockcount', -// 'getblockhash', -// 'getblock', -// 'getrawtransaction', -// 'getpeerinfo', -// 'gettxoutsetinfo', -// 'getmempoolinfo', -// 'getrawmempool' -// ]); - // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); diff --git a/config/default.json b/config/default.json index e0fbb0cf3..50e54cdd1 100644 --- a/config/default.json +++ b/config/default.json @@ -77,7 +77,6 @@ "youtube": "UCBWEY89pt-DpPYyPedqGWEg", "genesis_tx": "ea914133c255e8b47fb99d26b8627f90e12f5a9c3bc86269652d474d9814aaca", "genesis_block": "0000e9b3a79f70fb0be95b38604636441323450731e9ee1b5ef410791dac7184", - "heavy": true, "txcount": 100, "show_sent_received": true, "supply": "COINBASE", diff --git a/lib/database.js b/lib/database.js index 68378e3eb..7b03494b9 100644 --- a/lib/database.js +++ b/lib/database.js @@ -7,7 +7,6 @@ const mongoose = require('mongoose'), Tx = require('../models/tx'), Richlist = require('../models/richlist'), Peers = require('../models/peers'), - Heavy = require('../models/heavy'), lib = require('./explorer'), settings = require('./settings'), poloniex = require('./markets/poloniex'), @@ -446,41 +445,6 @@ module.exports = { }); }, - create_heavy: function(coin, cb) { - var newHeavy = new Heavy({ - coin: coin, - }); - newHeavy.save(function(err) { - if (err) { - console.log(err); - return cb(); - } else { - console.log("initial heavy entry created for %s", coin); - console.log(newHeavy); - return cb(); - } - }); - }, - - check_heavy: function(coin, cb) { - Heavy.findOne({coin: coin}, function(err, exists) { - if(exists) { - return cb(true); - } else { - return cb(false); - } - }); - }, - - get_heavy: function(coin, cb) { - Heavy.findOne({coin: coin}, function(err, heavy) { - if(heavy) { - return cb(heavy); - } else { - return cb(null); - } - }); - }, get_distribution: function(richlist, stats, cb){ var distribution = { supply: stats.supply, @@ -525,12 +489,6 @@ module.exports = { return cb(distribution); }); }, - // updates heavy stats for coin - // height: current block height, count: amount of votes to store - update_heavy: function(coin, height, count, cb) { - var newVotes = []; - return cb(); - }, // updates market data for given market; called by sync.js update_markets_db: function(market, cb) { @@ -694,18 +652,6 @@ module.exports = { debug(`no richlist entry found, creating...`) return promisify(this.create_richlist, settings.coin) } - }).then(() => { - // check heavy - if (settings.heavy) { - return promisify(this.check_heavy, settings.coin) - } - }).then(exists => { - // create heavy - // must be strong check because exists could be undefined - if (exists === false) { - debug(`no heavy entry found, creating...`) - return promisify(this.create_heavy, settings.coin) - } }) } }; diff --git a/lib/locale.js b/lib/locale.js index 6f98aaf4f..e00a43ccf 100644 --- a/lib/locale.js +++ b/lib/locale.js @@ -123,21 +123,6 @@ exports.mkt_total = "Total", exports.mkt_trade_history = "Trade History", exports.mkt_type = "Type", exports.mkt_time_stamp = "Time Stamp", -// Heavy - -exports.heavy_vote = "Vote", - // Heavy rewards view -exports.heavy_title = "Reward/voting information", - -exports.heavy_cap = "Coin Cap", -exports.heavy_phase = "Phase", -exports.heavy_maxvote = "Max Vote", -exports.heavy_reward = "Reward", -exports.heavy_current = "Current Reward", -exports.heavy_estnext = "Est. Next", -exports.heavy_changein = "Reward change in approximately", -exports.heavy_key = "Key", -exports.heavy_lastxvotes = "Last 20 votes", exports.poloniex = "Poloniex", exports.bittrex = "Bittrex", diff --git a/lib/settings.js b/lib/settings.js index 5039a39c7..0914b3474 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -136,7 +136,6 @@ exports.peer_timeout = safeGet('peer_timeout') || 240000; exports.genesis_tx = safeGet('genesis_tx') || '65f705d2f385dc85763a317b3ec000063003d6b039546af5d8195a5ec27ae410'; exports.genesis_block = safeGet('genesis_block') || 'b2926a56ca64e0cd2430347e383f63ad7092f406088b9b86d6d68c2a34baef51'; -exports.heavy = safeGet('heavy') || false; exports.txcount = safeGet('txcount') || 100; exports.show_sent_received = safeGet('show_sent_received') || true; exports.supply = safeGet('supply') || 'COINBASE'; diff --git a/locale/en.json b/locale/en.json index ca5d3b442..b2c05c7fd 100644 --- a/locale/en.json +++ b/locale/en.json @@ -137,18 +137,5 @@ "empoex": "Empoex", "cryptsy": "Cryptsy", "cryptopia": "Cryptopia", - "ccex": "C-Cex", - - // Heavy rewards view - "heavy_title": "Reward/voting information", - "heavy_vote": "Vote", - "heavy_cap": "Coin Cap", - "heavy_phase": "Phase", - "heavy_maxvote": "Max Vote", - "heavy_reward": "Reward", - "heavy_current": "Current Reward", - "heavy_estnext": "Est. Next", - "heavy_changein": "Reward change in approximately", - "heavy_key": "Key", - "heavy_lastxvotes": "Last 20 votes" + "ccex": "C-Cex" } diff --git a/models/heavy.js b/models/heavy.js deleted file mode 100644 index 02a461a4d..000000000 --- a/models/heavy.js +++ /dev/null @@ -1,21 +0,0 @@ -var mongoose = require('mongoose') - , Schema = mongoose.Schema; - -var HeavySchema = new Schema({ - coin: { type: String }, - lvote: { type: Number, default: 0 }, - reward: { type: Number, default: 0 }, - supply: { type: Number, default: 0 }, - cap: { type: Number, default: 0 }, - estnext: { type: Number, default: 0 }, - phase: { type: String, default: 'N/A'}, - maxvote: { type: Number, default: 0 }, - nextin: { type: String, default: 'N/A'}, - votes: { type: Array, default: [] }, -}); - -module.exports = mongoose.model('Heavy', HeavySchema); - -/* -votes : [{ count: 0, reward: 0, vote: 0}] -*/ diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css index 0e6eccd93..eff52f852 100644 --- a/public/stylesheets/style.css +++ b/public/stylesheets/style.css @@ -161,16 +161,6 @@ tr { /* Override DataTables ugly gradient processing overlay */ div#blocks-table_processing.dataTables_processing { - position: absolute; - top: 50%; - left: 50%; - width: 100%; - height: 40px; - margin-left: -50%; - margin-top: -25px; - padding-top: 20px; - text-align: center; - font-size: 1.2em; background-color: transparent; background: transparent; } diff --git a/routes/index.js b/routes/index.js index c88bfcf97..48471053b 100644 --- a/routes/index.js +++ b/routes/index.js @@ -196,27 +196,6 @@ router.get('/network', function(req, res) { res.render('network', {active: 'network'}); }); -router.get('/reward', function(req, res){ - //db.get_stats(settings.coin, function (stats) { - console.log(stats); - db.get_heavy(settings.coin, function (heavy) { - //heavy = heavy; - var votes = heavy.votes; - votes.sort(function (a,b) { - if (a.count < b.count) { - return -1; - } else if (a.count > b.count) { - return 1; - } else { - return 0; - } - }); - - res.render('reward', { active: 'reward', stats: stats, heavy: heavy, votes: heavy.votes }); - }); - //}); -}); - router.get('/tx/:txid', function(req, res) { route_get_tx(res, req.param('txid')); }); diff --git a/scripts/sync.js b/scripts/sync.js index 0576be88a..7e053739f 100644 --- a/scripts/sync.js +++ b/scripts/sync.js @@ -179,11 +179,7 @@ function main() { } }).then(() => promisify(db.update_db, settings.coin) - ).then(() => - promisify(db.get_stats, settings.coin) - ).then(stats => { - if (settings.heavy) return promisify(db.update_heavy, settings.coin, stats.count, 20) - }).then(() => exit(database)) + ).then(() => exit(database)) } else { return settings.markets.enabled.reduce((complete, m, _, markets) => { return promisify(db.check_market, m).then(([m, exists]) => { diff --git a/views/reward.jade b/views/reward.jade deleted file mode 100644 index 93eccf381..000000000 --- a/views/reward.jade +++ /dev/null @@ -1,119 +0,0 @@ -extends layout - -block content - .row(style='margin-top:5px;') - .col-md-12(style='text-align:center;') - img(src='/images/logo.png' style='width:80px;margin: 0px auto 15px auto;') - .row - .col-xs-12.col-md-10.col-md-offset-1 - .panel.panel-default.panel-address-summary - .panel-heading(style='position:relative;') - strong #{settings.locale.heavy_title} (#{settings.symbol}) - - table.table.table-bordered.table-striped.summary-table - thead - tr - th #{settings.locale.ex_supply} (#{settings.symbol}) - th #{settings.locale.heavy_cap} (#{settings.symbol}) - th #{settings.locale.heavy_phase} - th #{settings.locale.heavy_maxvote} - th #{settings.locale.heavy_reward} - th #{settings.locale.heavy_estnext} - tbody - tr - td - =heavy.supply - td - =heavy.cap - td - =heavy.phase - td - =heavy.maxvote - td - =heavy.reward - td - =heavy.estnext - .row - .col-md-10.col-md-offset-1 - .panel.panel-defual - .panel-body - .col-md-3 - center - canvas(id="myChart2", width="150", height="150") - script. - var ctx = document.getElementById("myChart2").getContext("2d"); - var data = [ - { - value: ((#{stats.count}/3600)%1)*100, - //color: "rgba(151,187,205,0.5)" - color: "rgba(92,184,92,1.0)" - }, - { - value : (1-((#{stats.count}/3600)%1))*100, - color : "#222" - } - ] - new Chart(ctx).Doughnut(data); - h5 #{settings.locale.heavy_changein} - h5 - =heavy.nextin - - form - table.table - thead - tbody - tr - th #{settings.locale.heavy_key} - td - tr - th #{settings.locale.heavy_vote} - td - div(style="width:20px;height:20px;background-color:#428bca") - tr - th #{settings.locale.heavy_current} - td - div(style="width:20px;height:20px;background-color:#222") - tr - th #{settings.locale.heavy_estnext} - td - div(style="width:20px;height:20px;background-color:rgba(92,184,92,1.0)") - - .col-md-9 - center - .row - strong #{settings.locale.heavy_lastxvotes} - .row - canvas(id="myChart", width="800", height="300", style="margin-left:-30px;margin-top:30px;") - script. - - var ctx = document.getElementById("myChart").getContext("2d"); - var options = { - scaleOverride : true, - scaleSteps : 8, - scaleStepWidth : 1, - scaleStartValue : 0, - bezierCurve : false, - } - var data = { - labels : [#{votes[0].count},#{votes[1].count},#{votes[2].count},#{votes[3].count},#{votes[4].count},#{votes[5].count},#{votes[6].count},#{votes[7].count},#{votes[8].count},#{votes[9].count},#{votes[10].count},#{votes[11].count},#{votes[12].count},#{votes[13].count},#{votes[14].count},#{votes[15].count},#{votes[16].count},#{votes[17].count},#{votes[18].count},#{votes[19].count}], - datasets : [ - { - fillColor : "rgba(66,139,202,0.5)", - strokeColor : "rgba(66,139,202,0.8)", - pointColor : '#428bca', - pointStrokeColor : "#fff", - data : [#{votes[0].vote},#{votes[1].vote},#{votes[2].vote},#{votes[3].vote},#{votes[4].vote},#{votes[5].vote},#{votes[6].vote},#{votes[7].vote},#{votes[8].vote},#{votes[9].vote},#{votes[10].vote},#{votes[11].vote},#{votes[12].vote},#{votes[13].vote},#{votes[14].vote},#{votes[15].vote},#{votes[16].vote},#{votes[17].vote},#{votes[18].vote},#{votes[19].vote}] - }, - { - fillColor : "rgba(151,187,205,0.0)", - strokeColor : '#222', - pointColor : "rgba(0,0,0,0)", - pointStrokeColor : "rgba(0,0,0,0.0)", - data : [#{votes[0].reward},#{votes[1].reward},#{votes[2].reward},#{votes[3].reward},#{votes[4].reward},#{votes[5].reward},#{votes[6].reward},#{votes[7].reward},#{votes[8].reward},#{votes[9].reward},#{votes[10].reward},#{votes[11].reward},#{votes[12].reward},#{votes[13].reward},#{votes[14].reward},#{votes[15].reward},#{votes[16].reward},#{votes[17].reward},#{votes[18].reward},#{votes[19].reward}] - }, - ] - } - var myNewChart = new Chart(ctx).Line(data,options); - - - From 3b21d8f239f7ae2fe7cac871a4bcab797018e634 Mon Sep 17 00:00:00 2001 From: Conrad Date: Tue, 18 Dec 2018 17:08:38 -0500 Subject: [PATCH 04/11] implemented caching of all rpc, now have to use it --- app.js | 19 ++------ bin/cluster.js | 19 +++++++- config/default.json | 1 + lib/api.js | 50 ++++++++++++++------- lib/database.js | 104 +++++++++++++++++++++++++++++++++++++++++++- lib/settings.js | 2 +- lib/util.js | 4 ++ models/stats.js | 21 ++++++--- routes/index.js | 2 +- scripts/sync.js | 6 +-- views/index.jade | 12 ++--- views/layout.jade | 3 +- 12 files changed, 191 insertions(+), 52 deletions(-) diff --git a/app.js b/app.js index b7d55ee15..c5e278f10 100644 --- a/app.js +++ b/app.js @@ -1,7 +1,7 @@ const express = require('express'), debug = require('debug')('explorer'), path = require('path'), - { Api, AccessTypes } = require('./lib/api'), + { Api, SpecTypes, CacheTypes } = require('./lib/api'), favicon = require('static-favicon'), logger = require('morgan'), cookieParser = require('cookie-parser'), @@ -12,22 +12,10 @@ const express = require('express'), lib = require('./lib/explorer'), db = require('./lib/database'), locale = require('./lib/locale'), - { promisify, spawnCmd, requestp } = require('./lib/util') + { promisify } = require('./lib/util') const app = express(); -// set database update intervals -spawnCmd('node', [ 'scripts/sync.js', 'index', settings.index.index_mode || 'update' ]) -setInterval(function () { - spawnCmd('node', [ 'scripts/sync.js', 'index', 'update' ]) -}, settings.sync_timeout) -setInterval(function () { - spawnCmd('node', [ 'scripts/sync.js', 'market' ]) -}, settings.market_timeout) -setInterval(function () { - spawnCmd('node', [ 'scripts/peers.js' ]) -}, settings.peer_timeout) - const info = require('./info'); info(app) @@ -45,7 +33,8 @@ app.use(express.static(path.join(__dirname, 'public'))); // routes app.use('/api', (new Api({ rpcConfig: { - type: AccessTypes.ONLY, + type: SpecTypes.ONLY, + cacheDefault: CacheTypes.FORCE, rpc: [ 'getnetworkhashps', 'getmininginfo', diff --git a/bin/cluster.js b/bin/cluster.js index 61c1aeb92..54fef3f42 100644 --- a/bin/cluster.js +++ b/bin/cluster.js @@ -3,7 +3,7 @@ const cluster = require('cluster') const fs = require('fs') const settings = require('../lib/settings') const db = require('../lib/database') -const { prettyPrint } = require('../lib/util') +const { prettyPrint, spawnCmd } = require('../lib/util') if (cluster.isMaster) { fs.writeFile('./tmp/cluster.pid', process.pid, function (err) { @@ -12,6 +12,9 @@ if (cluster.isMaster) { process.exit(1) } else { debug('Starting cluster with pid: ' + process.pid) + + const updateIntervals = [] + // ensure workers exit cleanly process.on('SIGINT', () => { debug('Cluster shutting down...') @@ -19,6 +22,7 @@ if (cluster.isMaster) { worker.kill() } // exit the master process + // updateIntervals.forEach(i => clearInterval(i)) process.exit(0) }) @@ -26,6 +30,18 @@ if (cluster.isMaster) { db.connect(settings.dbsettings).then(() => db.setupSchema() ).then(() => { + // set database update intervals + spawnCmd('node', [ 'scripts/sync.js', 'index', settings.index.index_mode || 'update' ]) + updateIntervals.push(setInterval(function () { + spawnCmd('node', [ 'scripts/sync.js', 'index', 'update' ]) + }, settings.sync_timeout)) + updateIntervals.push(setInterval(function () { + spawnCmd('node', [ 'scripts/sync.js', 'market' ]) + }, settings.market_timeout)) + updateIntervals.push(setInterval(function () { + spawnCmd('node', [ 'scripts/peers.js' ]) + }, settings.peer_timeout)) + // spawn a worker for each cpu core require('os').cpus().forEach(_ => { cluster.fork() @@ -33,6 +49,7 @@ if (cluster.isMaster) { }).catch(err => { debug(`An error occured setting up cluster: ${prettyPrint(err)}`) debug('Aborting...') + // updateIntervals.forEach(i => clearInterval(i)) process.exit(1) }) diff --git a/config/default.json b/config/default.json index 50e54cdd1..9c7202904 100644 --- a/config/default.json +++ b/config/default.json @@ -28,6 +28,7 @@ "sync_timeout": 60000, "market_timeout": 120000, "peer_timeout": 240000, + "ui_interval": 30000, "confirmations": 40, "locale": "locale/en.json", "display": { diff --git a/lib/api.js b/lib/api.js index 8dd446fe9..6b11ff0b1 100644 --- a/lib/api.js +++ b/lib/api.js @@ -4,7 +4,8 @@ const Client = require('bitcoin-core') const settings = require('./settings') const db = require('./database') -const AccessTypes = Object.freeze({ 'ALL': 0, 'ONLY': 1, 'EXCEPT': 2 }) +const SpecTypes = Object.freeze({ 'ALL': 0, 'ONLY': 1, 'EXCEPT': 2 }) +const CacheTypes = Object.freeze({ 'FORCE': 0, 'NEVER': 1 }) class Api { @@ -20,27 +21,43 @@ class Api { return res.send('A wallet password is required and has not been set.') } const parameters = (req.query instanceof Array ? req.query : Object.values(req.query)).map(param => isNaN(param) ? param : parseFloat(param)) - // res.send(await this.client[method](...params)) - this.client.command([ { method, parameters } ]).then(([ resp, err ]) => { - if (err) { - console.log(err) - res.send('There was an error, check your console.') - } else { - // if its an object just send it as is, otherwise cast to string - if (resp instanceof Object) res.send(resp) - else res.send(''+resp) - } - }) + + switch (this.getCacheType(method)) { + case CacheTypes.FORCE: + return db[method](...parameters).then(this.handle).then(resp => res.send(resp)) + case CacheTypes.NEVER: + return this.client.command([ { method, parameters } ]).then(([ resp, err ]) => { + res.send(this.handle(resp, err)) + }) + } }) } + getCacheType(method) { + if (this.allowedRpc.type === SpecTypes.ONLY) { + return Object.values(CacheTypes).includes(this.allowedRpc.rpc[method]) + ? this.allowedRpc.rpc[method] + : this.allowedRpc.cacheDefault + } + return this.allowedRpc.cacheDefault + } + + handle(data, err) { + if (err) { + console.log(err) + return 'There was an error, check your console.' + } + // if its an object just send it as is, otherwise cast to string + return (data instanceof Object) ? data : (''+data) + } + hasAccess(req, res, next) { - if (this.allowedRpc.type === AccessTypes.ALL) return next() + if (this.allowedRpc.type === SpecTypes.ALL) return next() const method = req.path.substr(1) if ( - (this.allowedRpc.type === AccessTypes.ONLY && this.allowedRpc.rpc.includes(method)) - || (this.allowedRpc.type === AccessTypes.EXCEPT && !this.allowedRpc.rpc.includes(method)) + (this.allowedRpc.type === SpecTypes.ONLY && this.allowedRpc.rpc.includes(method)) + || (this.allowedRpc.type === SpecTypes.EXCEPT && !this.allowedRpc.rpc.includes(method)) ) { return next() } else { @@ -69,5 +86,6 @@ class Api { module.exports = { Api, - AccessTypes + SpecTypes, + CacheTypes } diff --git a/lib/database.js b/lib/database.js index 7b03494b9..a8bf0b2e5 100644 --- a/lib/database.js +++ b/lib/database.js @@ -17,7 +17,7 @@ const mongoose = require('mongoose'), yobit = require('./markets/yobit'), empoex = require('./markets/empoex'), ccex = require('./markets/ccex'), - { promisify, prettyPrint } = require('../lib/util') + { promisify, prettyPrint, renameProp } = require('../lib/util') function find_address(hash, cb) { Address.findOne({a_id: hash}, function(err, address) { @@ -232,7 +232,105 @@ function get_market_data(market, cb) { } } +const rpcOnError = (method, err) => { + debug(`An error occurred while trying access cache of ${method}: ${err}`) + return null +} +const rpcGetters = { + + getnetworkhashps () { + return promisify(Stats.findOne.bind(Stats), { coin: settings.coin }, { networkhashps: 1, _id: 0 }).then(([ err, res ]) => { + if (err) return rpcOnError('getnetworkhashps', err) + return res.networkhashps + }) + }, + + getmininginfo () { + return promisify(Stats.findOne.bind(Stats), { coin: settings.coin }, { _id: 0 }).then(([ err, res ]) => { + if (err) return rpcOnError('getmininginfo', err) + return res + }) + }, + + getdifficulty () { + return promisify(Stats.findOne.bind(Stats), { coin: settings.coin }, { difficulty: 1, _id: 0 }).then(([ err, res ]) => { + if (err) return rpcOnError('getdifficulty', err) + return res.difficulty + }) + }, + + getconnectioncount () { + return promisify(Stats.findOne.bind(Stats), { coin: settings.coin }, { connections: 1, _id: 0 }).then(([ err, res ]) => { + if (err) return rpcOnError('getconnectioncount', err) + return res.connections + }) + }, + + getblockcount () { + return promisify(Stats.findOne.bind(Stats), { coin: settings.coin }, { blocks: 1, _id: 0 }).then(([ err, res ]) => { + if (err) return rpcOnError('getdifficulty', err) + return res.blocks + }) + }, + + getblockhash (height) { + return promisify(Block.findOne.bind(Block), { height }, { hash: 1, _id: 0 }).then(([ err, res ]) => { + if (err) return rpcOnError('getblockhash', err) + return res.blocks + }) + }, + + getblock (hash) { + return promisify(Block.findOne.bind(Block), { hash }, { _id: 0 }).then(([ err, res ]) => { + if (err) return rpcOnError('getblock', err) + return res.blocks + }) + }, + + getrawtransaction (txid, format) { + return promisify(Block.findOne.bind(Block), { 'tx': { $elemMatch: { txid } } }, { tx: 1, _id: 0 }).then(([ err, res ]) => { + if (err) return rpcOnError('getrawtransaction', err) + return format ? res.tx : res.tx.hex + }) + }, + + getpeerinfo () { + return promisify(Peers.find.bind(Peers), {}, { _id: 0 }).then(([ err, res ]) => { + if (err) return rpcOnError('getpeerinfo', err) + return res + }) + }, + + gettxoutsetinfo () { + return promisify(Stats.findOne.bind(Stats), { coin: settings.coin }, { + blocks: 1, + bestblock: 1, + transactions: 1, + txouts: 1, + bogosize: 1, + hash_serialized_2: 1, + disk_size: 1, + supply: 1, + _id: 0 + }).then(([ err, res ]) => { + if (err) return rpcOnError('getdifficulty', err) + return renameProp('supply', 'total_amount', renameProp('blocks', 'height', res)) + }) + }, + + getmempoolinfo () { + + }, + + getrawmempool () { + + } + +} + module.exports = { + ...rpcGetters, + connect (dbSettings) { return mongoose.connect(dbSettings.uri, dbSettings.options).catch(err => { console.log(`Unable to connect to database: ${dbSettings.uri}`); @@ -532,6 +630,10 @@ module.exports = { }); }, + update_blocks(coin) { + + }, + // updates tx, address & richlist db's; called by sync.js update_tx_db: function(coin, start, end, timeout, cb) { var complete = false; diff --git a/lib/settings.js b/lib/settings.js index 0914b3474..da4a90233 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -131,7 +131,7 @@ exports.check_timeout = safeGet('check_timeout') || 250; exports.sync_timeout = safeGet('sync_timeout') || 60000; exports.market_timeout = safeGet('market_timeout') || 120000; exports.peer_timeout = safeGet('peer_timeout') || 240000; - +exports.ui_interval = safeGet('ui_interval') || 30000; //genesis exports.genesis_tx = safeGet('genesis_tx') || '65f705d2f385dc85763a317b3ec000063003d6b039546af5d8195a5ec27ae410'; exports.genesis_block = safeGet('genesis_block') || 'b2926a56ca64e0cd2430347e383f63ad7092f406088b9b86d6d68c2a34baef51'; diff --git a/lib/util.js b/lib/util.js index 2a674fae8..b169f79ef 100644 --- a/lib/util.js +++ b/lib/util.js @@ -71,5 +71,9 @@ module.exports = { prettyPrint(obj) { return JSON.stringify(obj, null, 2) + }, + + renameProp(oldProp, newProp, { [oldProp]: old, ...others }) { + return { [newProp]: old, ...others } } } \ No newline at end of file diff --git a/models/stats.js b/models/stats.js index 6d2f21788..4973464ce 100644 --- a/models/stats.js +++ b/models/stats.js @@ -3,13 +3,22 @@ var mongoose = require('mongoose') var StatsSchema = new Schema({ coin: { type: String }, - count: { type: Number, default: 1 }, - last: { type: Number, default: 1 }, - //difficulty: { type: Object, default: {} }, - //hashrate: { type: String, default: 'N/A' }, + blocks: { type: Number, default: 1 }, + currentblockweight: { type: Number, default: 4000 }, + currentblocktx: { type: Number, default: 0 }, + difficulty: { type: Object, default: 1 }, + networkhashps: { type: String, default: 'N/A' }, + pooledtx: { type: Number, default: 0 }, + chain: { type: String }, + warnings: { type: String, default: "" }, supply: { type: Number, default: 0 }, connections: { type: Number, default: 0 }, - last_price: { type: Number, default: 0 }, + bestblock: { type: String, lowercase: true }, + transactions: { type: Number, default: 0 }, + txouts: { type: Number, default: 0 }, + bogosize: { type: Number, default: 0 }, + hash_serialized_2: { type: String, lowercase: true }, + disk_size: { type: Number, default: 0 } }); -module.exports = mongoose.model('coinstats', StatsSchema); \ No newline at end of file +module.exports = mongoose.model('stats', StatsSchema); \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index 48471053b..a39339c40 100644 --- a/routes/index.js +++ b/routes/index.js @@ -91,7 +91,7 @@ function route_get_tx(res, txid) { } function route_get_index(res, error) { - res.render('index', { active: 'home', error: error, warning: null }); + res.render('index', { active: 'home', error: error, warning: null, ui_interval: settings.ui_interval }); } function route_get_address(res, hash, count) { diff --git a/scripts/sync.js b/scripts/sync.js index 7e053739f..5fffe13b3 100644 --- a/scripts/sync.js +++ b/scripts/sync.js @@ -131,11 +131,9 @@ function main() { return mongoose.connect(settings.dbsettings.uri, settings.dbsettings.options) }).then(() => { if (database === 'index') { - return promisify(db.get_stats, settings.coin).then(() => - promisify(db.check_stats, settings.coin) - ).then(exists => { + return promisify(db.check_stats, settings.coin).then(exists => { if (!exists) { - debug('Run \'npm start\' to create database structure before running this script.') + debug(`Run 'npm start' to create database structure before running this script.`) exit(database) } return promisify(db.get_stats, settings.coin) diff --git a/views/index.jade b/views/index.jade index 2f9d400ed..779c4bd3c 100644 --- a/views/index.jade +++ b/views/index.jade @@ -31,15 +31,15 @@ block content }) }, columns: [ - { data: 'height', width: '15%' }, - { data: 'hash', width: '45%' }, - { data: 'nTx', width: '10%' }, - { data: 'timestamp', width: '20%' }, + { data: 'height', width: '12%' }, + { data: 'hash', width: '48%' }, + { data: 'nTx', width: '8%' }, + { data: 'timestamp', width: '24%' }, ] }) setInterval(function () { btable.api().ajax.reload(null, false) - }, 30000) + }, parseInt(#{ui_interval}) || 30000) }); .row .col-md-12 @@ -56,7 +56,7 @@ block content .panel.panel-default .panel-heading strong #{settings.locale.ex_latest_blocks} - table#blocks-table.table.table-bordered.table-striped + table#blocks-table.table.table-bordered.table-striped(style='font-family: "B612 Mono"') thead tr th.text-center #{settings.locale.height} diff --git a/views/layout.jade b/views/layout.jade index 8ce3fc910..8b7d4e4cc 100644 --- a/views/layout.jade +++ b/views/layout.jade @@ -6,6 +6,7 @@ html link(rel='stylesheet', href='/vendor/jqplot/jquery.jqplot.css') link(rel='stylesheet', href='//cdn.datatables.net/plug-ins/725b2a2115b/integration/bootstrap/3/dataTables.bootstrap.css') link(rel='stylesheet', href='//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css') + link(rel='stylesheet', href='https://fonts.googleapis.com/css?family=B612+Mono') link(rel='stylesheet', href='/stylesheets/style.css') script(src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js') script(src='//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js') @@ -53,7 +54,7 @@ html }); setInterval( function() { update_stats(); - }, 30000); + }, parseInt(#{ui_interval}) || 30000); update_stats(); }); body From bdbc5bb0113a71fa13c0d692e558c6b41a2c6cfc Mon Sep 17 00:00:00 2001 From: Conrad Date: Wed, 19 Dec 2018 17:00:09 -0500 Subject: [PATCH 05/11] getting close --- app.js | 57 ++++------ bin/cluster.js | 20 ++-- bin/instance.js | 28 ++++- lib/api.js | 41 +++++-- lib/database.js | 291 +++++++++++++++-------------------------------- lib/explorer.js | 54 ++++----- lib/util.js | 6 + models/block.js | 17 ++- models/tx.js | 14 --- scripts/sync.js | 65 ++++------- views/index.jade | 2 +- views/info.jade | 9 +- 12 files changed, 254 insertions(+), 350 deletions(-) delete mode 100644 models/tx.js diff --git a/app.js b/app.js index c5e278f10..3be15b711 100644 --- a/app.js +++ b/app.js @@ -1,7 +1,7 @@ const express = require('express'), debug = require('debug')('explorer'), path = require('path'), - { Api, SpecTypes, CacheTypes } = require('./lib/api'), + { Api } = require('./lib/api'), favicon = require('static-favicon'), logger = require('morgan'), cookieParser = require('cookie-parser'), @@ -12,7 +12,7 @@ const express = require('express'), lib = require('./lib/explorer'), db = require('./lib/database'), locale = require('./lib/locale'), - { promisify } = require('./lib/util') + { promisify, requestp } = require('./lib/util') const app = express(); @@ -31,27 +31,7 @@ app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); // routes -app.use('/api', (new Api({ - rpcConfig: { - type: SpecTypes.ONLY, - cacheDefault: CacheTypes.FORCE, - rpc: [ - 'getnetworkhashps', - 'getmininginfo', - 'getdifficulty', - 'getconnectioncount', - 'getblockcount', - 'getblockhash', - 'getblock', - 'getrawtransaction', - 'getpeerinfo', - 'gettxoutsetinfo', - 'getmempoolinfo', - 'getrawmempool' - ] - }, - wallet: settings.wallet -})).app); +app.use('/api', Api().app); app.use('/', routes); app.use('/ext/getmoneysupply', function(req,res){ lib.get_supply(function(supply){ @@ -96,21 +76,11 @@ app.use('/ext/getdistribution', function(req,res){ }); }); -app.use('/ext/getlasttxs', function (req, res) { - return db.get_last_txs(parseInt(req.query.count), req.query.minAmount * 100000000, req.query.start).then(txs => - res.send({data: txs}) - ).catch(err => { - debug(err) - res.send({ error: `An error occurred: ${err}` }) - }) -}); - -app.use('/ext/getblocks/:start/:end', function (req, res) { +app.use('/ext/getblocks/:start/:end', async function (req, res) { const endpoint = settings.address || `http://${req.headers.host}` const start = parseInt(req.param('start')) const end = parseInt(req.param('end')) const reverse = req.query.reverse && req.query.reverse.toLowerCase() === 'true' - const strip = req.query.strip && req.query.strip.toLowerCase() === 'true' if (start > end) { res.send({ error: `End blockheight must be greater than or equal to the start blockheight.` }) @@ -118,6 +88,20 @@ app.use('/ext/getblocks/:start/:end', function (req, res) { } let heights = Array(end - start + 1).fill(undefined).map((_, i) => start + i) + if (reverse) { + const height = await requestp(`${endpoint}/api/getblockcount`) + heights = heights.map(h => height - h + 1) + } + + const flds = req.query.flds == 'summary' + ? { fulltx: 0, _id: 0 } + : req.query.flds == 'tx' + ? { fulltx: 1, _id: 0 } + : req.query.flds.reduce((acc, fld) => ({ ...acc, [fld]: 1 }), { _id: 0 }) + const blocks = await lib.getBlocksDb(heights, flds) + res.send(blocks) + + /* const txReq = () => Promise.all(heights.map(i => db.getTxs({ height: i }).then(txs => { // sorts transactions from newest to oldest @@ -145,9 +129,9 @@ app.use('/ext/getblocks/:start/:end', function (req, res) { if (reverse) heights = heights.map(h => height - h + 1) return height }).then(blockcount => { - if (req.query.flds === 'summary') { + if (req.query.flds == 'summary') { infoReq(blockcount).then(infos => res.send({ data: { blockcount, blocks: infos } })).catch(onErr) - } else if (req.query.flds && req.query.flds.length === 1 && req.query.flds[0] === 'tx') { + } else if (req.query.flds == 'tx') { txReq().then(txs => res.send({ data: { blockcount, blocks: txs } })).catch(onErr) } else { Promise.all([ txReq(), infoReq(blockcount) ]).then(([ txs, infos ]) => { @@ -164,6 +148,7 @@ app.use('/ext/getblocks/:start/:end', function (req, res) { }).catch(onErr) } }).catch(onErr) + */ }) app.use('/ext/connections', function(req,res){ diff --git a/bin/cluster.js b/bin/cluster.js index 54fef3f42..41e47fb95 100644 --- a/bin/cluster.js +++ b/bin/cluster.js @@ -31,16 +31,16 @@ if (cluster.isMaster) { db.setupSchema() ).then(() => { // set database update intervals - spawnCmd('node', [ 'scripts/sync.js', 'index', settings.index.index_mode || 'update' ]) - updateIntervals.push(setInterval(function () { - spawnCmd('node', [ 'scripts/sync.js', 'index', 'update' ]) - }, settings.sync_timeout)) - updateIntervals.push(setInterval(function () { - spawnCmd('node', [ 'scripts/sync.js', 'market' ]) - }, settings.market_timeout)) - updateIntervals.push(setInterval(function () { - spawnCmd('node', [ 'scripts/peers.js' ]) - }, settings.peer_timeout)) + // spawnCmd('node', [ 'scripts/sync.js', 'index', settings.index.index_mode || 'update' ]) + // updateIntervals.push(setInterval(function () { + // spawnCmd('node', [ 'scripts/sync.js', 'index', 'update' ]) + // }, settings.sync_timeout)) + // updateIntervals.push(setInterval(function () { + // spawnCmd('node', [ 'scripts/sync.js', 'market' ]) + // }, settings.market_timeout)) + // updateIntervals.push(setInterval(function () { + // spawnCmd('node', [ 'scripts/peers.js' ]) + // }, settings.peer_timeout)) // spawn a worker for each cpu core require('os').cpus().forEach(_ => { diff --git a/bin/instance.js b/bin/instance.js index 477114613..aba9cf684 100755 --- a/bin/instance.js +++ b/bin/instance.js @@ -1,6 +1,32 @@ #!/usr/bin/env node -const debug = require('debug')('explorer') + +// ensure the api singleton has been initialized before anything else const settings = require('../lib/settings') +const { Api, SpecTypes, CacheTypes } = require('../lib/api') +const api = new Api({ + allowRawRpc: true, + rpcConfig: { + type: SpecTypes.ONLY, + cacheDefault: CacheTypes.FORCE, + rpc: [ + 'getnetworkhashps', + 'getmininginfo', + 'getdifficulty', + 'getconnectioncount', + 'getblockcount', + 'getblockhash', + 'getblock', + 'getrawtransaction', + 'getpeerinfo', + 'gettxoutsetinfo', + 'getmempoolinfo', + 'getrawmempool' + ] + }, + wallet: settings.wallet +}) + +const debug = require('debug')('explorer') const db = require('../lib/database') const app = require('../app') const { promisify } = require('../lib/util') diff --git a/lib/api.js b/lib/api.js index 6b11ff0b1..545355fcf 100644 --- a/lib/api.js +++ b/lib/api.js @@ -5,35 +5,47 @@ const settings = require('./settings') const db = require('./database') const SpecTypes = Object.freeze({ 'ALL': 0, 'ONLY': 1, 'EXCEPT': 2 }) -const CacheTypes = Object.freeze({ 'FORCE': 0, 'NEVER': 1 }) +const CacheTypes = Object.freeze({ 'FORCE': 0, 'NEVER': 1, 'AS_NEEDED': 2 }) -class Api { - - constructor ({ rpcConfig, wallet }) { +class PrivApi { + + constructor ({ rpcConfig, wallet, allowRawRpc = false }) { this.app = express() this.allowedRpc = rpcConfig this.walletDetails = wallet this.client = new Client(wallet) + this.allowRawRpc = allowRawRpc this.app.get('*', this.hasAccess.bind(this), (req, res) => { const method = req.path.substr(1) - if (Api.requiresCredentials.includes(method) && !this.client.password) { + if (PrivApi.requiresCredentials.includes(method) && !this.client.password) { return res.send('A wallet password is required and has not been set.') } const parameters = (req.query instanceof Array ? req.query : Object.values(req.query)).map(param => isNaN(param) ? param : parseFloat(param)) switch (this.getCacheType(method)) { case CacheTypes.FORCE: - return db[method](...parameters).then(this.handle).then(resp => res.send(resp)) + return db.rpc[method](...parameters).then(this.handle).then(resp => res.send(resp)) case CacheTypes.NEVER: return this.client.command([ { method, parameters } ]).then(([ resp, err ]) => { res.send(this.handle(resp, err)) }) + case CacheTypes.AS_NEEDED: + return db.rpc[method](...parameters).then(this.handle).then(resp => resp.includes('There was an error') + ? this.client.command([ { method, parameters } ]).then(([ resp, err ]) => this.handle(resp, err)) + : resp + ).then(resp => res.send(resp)) } }) } - getCacheType(method) { + callRawRpc (method, parameters) { + if (this.allowRawRpc) + return this.client.command([ { method, parameters } ]).then(([ resp, err ]) => this.handle(resp, err)) + else return 'Direct RPC calls are not enabled.' + } + + getCacheType (method) { if (this.allowedRpc.type === SpecTypes.ONLY) { return Object.values(CacheTypes).includes(this.allowedRpc.rpc[method]) ? this.allowedRpc.rpc[method] @@ -42,7 +54,7 @@ class Api { return this.allowedRpc.cacheDefault } - handle(data, err) { + handle (data, err) { if (err) { console.log(err) return 'There was an error, check your console.' @@ -51,7 +63,7 @@ class Api { return (data instanceof Object) ? data : (''+data) } - hasAccess(req, res, next) { + hasAccess (req, res, next) { if (this.allowedRpc.type === SpecTypes.ALL) return next() const method = req.path.substr(1) @@ -65,11 +77,11 @@ class Api { } } - setCredentials(creds) { + setCredentials (creds) { this.client = new Client({ ...this.walletDetails, creds }) } - static get requiresCredentials() { + static get requiresCredentials () { return [ 'dumpprivkey', 'importprivkey', @@ -84,6 +96,13 @@ class Api { } +let instance +function Api (...args) { + console.log(args) + if (!instance) instance = new PrivApi(...args) + return instance +} + module.exports = { Api, SpecTypes, diff --git a/lib/database.js b/lib/database.js index a8bf0b2e5..9c23ef309 100644 --- a/lib/database.js +++ b/lib/database.js @@ -4,7 +4,6 @@ const mongoose = require('mongoose'), Markets = require('../models/markets'), Address = require('../models/address'), Block = require('../models/block'), - Tx = require('../models/tx'), Richlist = require('../models/richlist'), Peers = require('../models/peers'), lib = require('./explorer'), @@ -17,7 +16,7 @@ const mongoose = require('mongoose'), yobit = require('./markets/yobit'), empoex = require('./markets/empoex'), ccex = require('./markets/ccex'), - { promisify, prettyPrint, renameProp } = require('../lib/util') + { promisify, prettyPrint, renameProp, wait } = require('../lib/util') function find_address(hash, cb) { Address.findOne({a_id: hash}, function(err, address) { @@ -122,67 +121,29 @@ function update_address(hash, txid, amount, type, cb) { }); } -function findTx (txid) { - return new Promise((resolve, reject) => Tx.findOne({txid: txid}, (err, tx) => { - if (err) reject(err) - else resolve(tx) - })) +async function findTx (txid) { + const [ err, block ] = await promisify(Block.findOne.bind(Block), { tx: { $elemMatch: txid } }) + if (err) throw new Error(err) + else return parseTx(block, txid) } -function save_tx(txid, cb) { - lib.get_rawtransaction(txid, function(tx){ - if (tx != 'There was an error. Check your console.') { - lib.getBlock(tx.blockhash, function (block) { - if (block) { - lib.prepare_vin(tx, function(vin) { - lib.prepare_vout(tx.vout, txid, vin, function(vout, nvin) { - lib.syncLoop(vin.length, function (loop) { - var i = loop.iteration(); - update_address(nvin[i].addresses, txid, nvin[i].amount, 'vin', function(){ - loop.next(); - }); - }, function(){ - lib.syncLoop(vout.length, function (subloop) { - var t = subloop.iteration(); - if (vout[t].addresses) { - update_address(vout[t].addresses, txid, vout[t].amount, 'vout', function(){ - subloop.next(); - }); - } else { - subloop.next(); - } - }, function(){ - lib.calculate_total(vout, function(total){ - var newTx = new Tx({ - txid: tx.txid, - vin: nvin, - vout: vout, - total: total.toFixed(8), - timestamp: tx.time, - blockhash: tx.blockhash, - blockindex: block.height, - }); - newTx.save(function(err) { - if (err) { - return cb(err); - } else { - //console.log('txid: '); - return cb(); - } - }); - }); - }); - }); - }); - }); - } else { - return cb('block not found: ' + tx.blockhash); - } - }); - } else { - return cb('tx not found: ' + txid); - } - }); +async function parseTx(block, i) { + const tx = /[a-z]/i.test(i) ? block.tx.find(tx => tx.txid === i) : block.tx[i] + const [ vout, vin ] = await lib.prepare_vin(tx).then(vin => promisify(lib.prepare_vout, tx.vout, tx.txid, vin)) + for (const v of vin) await promisify(update_address, v.addresses, tx.txid, v.amount, 'vin') + for (const v of vout) { + if (v.addresses) await update_address(v.addresses, tx.txid, v.amount, 'vout') + } + const total = await promisify(lib.calculate_total, vout) + return { + txid: tx.txid, + vin, + vout, + total, + timestamp: tx.time, + blockhash: block.hash, + blockindex: block.height + } } function get_market_data(market, cb) { @@ -236,7 +197,7 @@ const rpcOnError = (method, err) => { debug(`An error occurred while trying access cache of ${method}: ${err}`) return null } -const rpcGetters = { +const rpc = { getnetworkhashps () { return promisify(Stats.findOne.bind(Stats), { coin: settings.coin }, { networkhashps: 1, _id: 0 }).then(([ err, res ]) => { @@ -276,21 +237,32 @@ const rpcGetters = { getblockhash (height) { return promisify(Block.findOne.bind(Block), { height }, { hash: 1, _id: 0 }).then(([ err, res ]) => { if (err) return rpcOnError('getblockhash', err) - return res.blocks + return res.hash }) }, - getblock (hash) { - return promisify(Block.findOne.bind(Block), { hash }, { _id: 0 }).then(([ err, res ]) => { + async getblock (hash) { + const blockcount = await promisify(Stats.findOne.bind(Stats), { coin: settings.coin }, { blocks: 1, _id: 0 }).then(([ err, stats ]) => { if (err) return rpcOnError('getblock', err) - return res.blocks + return stats.blocks + }) + return promisify(Block.findOne.bind(Block), { hash }, { fulltx: 0, _id: 0 }).then(([ err, res ]) => { + if (err) return rpcOnError('getblock', err) + return { + ...res._doc, + confirmations: blockcount - res.height, + strippedsize: res.size, + versionHex: res.version.toString(16), + nTx: res.tx.length + } }) }, getrawtransaction (txid, format) { - return promisify(Block.findOne.bind(Block), { 'tx': { $elemMatch: { txid } } }, { tx: 1, _id: 0 }).then(([ err, res ]) => { + return promisify(Block.findOne.bind(Block), { fulltx: { $elemMatch: { txid } } }, { fulltx: 1, _id: 0 }).then(([ err, res ]) => { if (err) return rpcOnError('getrawtransaction', err) - return format ? res.tx : res.tx.hex + const tx = res.fulltx.find(tx => tx.txid === txid) + return format ? tx : tx.hex }) }, @@ -329,7 +301,7 @@ const rpcGetters = { } module.exports = { - ...rpcGetters, + rpc, connect (dbSettings) { return mongoose.connect(dbSettings.uri, dbSettings.options).catch(err => { @@ -409,70 +381,15 @@ module.exports = { } }, - get_tx (txid, cb) { - findTx(txid).then(tx => { - return cb(tx) - }) + async get_tx (txid, cb) { + const tx = findTx(txid) + return cb ? cb(await tx) : tx }, - getTxs (block) { - return new Promise((resolve, reject) => { - if (block.tx && block.tx.length) { - Promise.all(block.tx.map(tx => findTx(tx))) - .then(txs => resolve(txs)) - .catch(err => reject(err)) - } else if (block.hash) { - Tx.find({ 'blockhash': block.hash }, (err, res) => { - if (err) reject(err) - else resolve(res) - }) - } else if (block.height) { - Tx.find({ 'blockindex': block.height }, (err, res) => { - if (err) reject(err) - else resolve(res) - }) - } - - }) - }, - - create_tx: function(txid, cb) { - save_tx(txid, function(err){ - if (err) { - return cb(err); - } else { - //console.log('tx stored: %s', txid); - return cb(); - } - }); - }, - - create_txs: function(block, cb) { - lib.syncLoop(block.tx.length, function (loop) { - var i = loop.iteration(); - save_tx(block.tx[i], function(err){ - if (err) { - loop.next(); - } else { - //console.log('tx stored: %s', block.tx[i]); - loop.next(); - } - }); - }, function(){ - return cb(); - }); - }, - - get_last_txs (count, minAmount, start) { - return new Promise((resolve, reject) => { - Tx.find(Object.assign({ 'total': { $gt: minAmount } }, start ? { '_id': { $lt: start } } : {} )) - .sort({ '_id': 'desc' }) - .limit(count) - .exec((err, txs) => { - if (err) reject(err) - else resolve(txs) - }) - }) + async getTxs (block) { + return promisify(Block.findOne.bind(Block), block, { tx: 1 }).then(block => + block.tx.map(tx => parseTx(block, tx)) + ) }, create_market: function(coin, exchange, market, cb) { @@ -615,80 +532,52 @@ module.exports = { }); }, - // updates stats data for given coin; called by sync.js - update_db: function(coin, cb) { - lib.getBlockcount().then(count => { - if (!count) { - console.log('Unable to connect to explorer API'); - return cb(false); - } - return lib.get_supply(supply => - lib.get_connectioncount(connections => - Stats.update({ coin }, { coin, count, supply, connections }, () => cb(true)) - ) - ); - }); + async updateStats (coin) { + const txoutinfo = await lib.getRawRpc('gettxoutsetinfo') + const mininginfo = await lib.getRawRpc('getmininginfo') + + // Although schema queries return a thenable Query object, they are not full promises and + // thus cannot be used with async/await syntax. + return promisify(Stats.update.bind(Stats), { coin }, { + blocks: txoutinfo.height, + currentblockweight: mininginfo.currentblockweight, + currentblocktx: mininginfo.currentblocktx, + difficulty: mininginfo.difficulty, + networkhashps: mininginfo.networkhashps, + pooledtx: mininginfo.pooledtx, + chain: mininginfo.chain, + warnings: mininginfo.warnings, + supply: txoutinfo.total_amount, + connections: await lib.getRawRpc('getconnectioncount'), + bestblock: txoutinfo.bestblock, + transactions: txoutinfo.bestblock, + txouts: txoutinfo.txouts, + bogosize: txoutinfo.bogosize, + hash_serialized_2: txoutinfo.hash_serialized_2, + disk_size: txoutinfo.disk_size, + }) }, - update_blocks(coin) { + async updateDb (stats, start, end, timeout) { + for (const i = start; i < end; i++) { + const [ err, block ] = await promisify(Block.findOne.bind(Block), { height: i }) + if (block) continue - }, - - // updates tx, address & richlist db's; called by sync.js - update_tx_db: function(coin, start, end, timeout, cb) { - var complete = false; - lib.syncLoop((end - start) + 1, function (loop) { - var x = loop.iteration(); - if (x % 5000 === 0) { - Stats.update({coin: coin}, { - last: start + x - 1, - }, function () {}); + const block = await lib.getBlock(await promisify(lib.get_blockhash, i), undefined, stats.blocks) + if (!block) { + debug(`Block #${i} could not be found, skipping.`) + continue + } else if (!block.tx) { + debug(`Block #${i} does not have any transactions, skipping.`) + continue } - lib.get_blockhash(start + x, function(blockhash){ - if (blockhash) { - lib.getBlock(blockhash, function(block) { - if (block && block.tx) { - lib.syncLoop(block.tx.length, function (subloop) { - var i = subloop.iteration(); - Tx.findOne({txid: block.tx[i]}, function(err, tx) { - if(tx) { - tx = null; - subloop.next(); - } else { - save_tx(block.tx[i], function(err){ - if (err) { - console.log(err); - } else { - console.log('%s: %s', block.height, block.tx[i]); - } - setTimeout( function(){ - tx = null; - subloop.next(); - }, timeout); - }); - } - }); - }, function(){ - blockhash = null; - block = null; - loop.next(); - }); - } else { - console.log('block not found: %s', blockhash); - loop.next(); - } - }); - } else { - loop.next(); - } - }); - }, function(){ - Stats.update({coin: coin}, { - last: end, - }, function() { - return cb(); - }); - }); + + debug(`Caching #${i}: ${block.hash}`) + block.fulltx = await Promise.all(block.tx.map(txid => promisify(lib.get_rawtransaction, txid))) + await Block.create([ block ]) + if (timeout) await wait(timeout) + } + }, create_peer: function(params, cb) { diff --git a/lib/explorer.js b/lib/explorer.js index 091511d2b..0ba49a50f 100644 --- a/lib/explorer.js +++ b/lib/explorer.js @@ -2,9 +2,8 @@ const request = require('request'), debug = require('debug')('explorer:lib'), settings = require('./settings'), Address = require('../models/address'), - Tx = require('../models/tx'), - Block = require('../models/block'), - { promisify, requestp, deepEqual } = require('./util') + { promisify, requestp, deepEqual } = require('./util'), + { Api } = require('./api') const base_url = 'http://127.0.0.1:' + settings.port + '/api/' @@ -20,16 +19,21 @@ function verifyCoinbaseSupply () { } function coinbase_supply () { - return promisify( - Tx.find.bind(Tx), - { 'vin': { $elemMatch: { 'addresses': 'coinbase', 'amount': { $gt: 0 } } } } - ).then(([ err, txes ]) => - txes.reduce((sum, tx) => sum + tx.vin.find(vin => vin.addresses === 'coinbase').amount, 0) - ) + return requestp(base_url + 'gettxoutsetinfo').then(info => info.total_amount) + // return promisify( + // Tx.find.bind(Tx), + // { 'vin': { $elemMatch: { 'addresses': 'coinbase', 'amount': { $gt: 0 } } } } + // ).then(([ err, txes ]) => + // txes.reduce((sum, tx) => sum + tx.vin.find(vin => vin.addresses === 'coinbase').amount, 0) + // ) } module.exports = { + getRawRpc (method, params) { + return Api().callRawRpc(method, params) + }, + convert_to_satoshi (amount, cb) { const ret = amount.toFixed(8) * 100000000 return cb ? cb(ret) : ret @@ -111,24 +115,20 @@ module.exports = { }) }, - async getBlock (hash, cb, blockcount) { - blockcount = blockcount || await this.getBlockcount() - const ret = Block.findOne({ hash }).then(block => block - ? { - ...block._doc, - confirmations: blockcount - block.height, - strippedsize: block.size, - versionHex: block.version.toString(16), - nTx: block.tx.length - } - : requestp(`${base_url}getblock?hash=${hash}`).then(body => Promise.all([ - body, - Block.create([ body ]) - ])).then(([ body ]) => body) - ) - + async getBlock (hash, cb) { + const ret = requestp(`${base_url}getblock?hash=${hash}`) return cb ? cb(await ret) : ret }, + + getBlocksDb (searchParams, flds) { + const params = (searchParams.length ? searchParams : [ searchParams ]) + const mode = params.find(param => /[a-z]/i.test(param)) !== undefined ? 'hash' : 'height' + return promisify( + Block[params.length > 1 ? 'find' : 'findOne'].bind(Block), + { [mode]: { $in: params } }, + flds || { } + ) + }, get_rawtransaction: function (hash, cb) { var uri = base_url + 'getrawtransaction?txid=' + hash + '&decrypt=1' @@ -206,7 +206,7 @@ module.exports = { return cb(body.total_amount) }) } else { - return coinbase_supply().then(supply => cb(supply / 100000000)) + return coinbase_supply() } }, @@ -257,7 +257,7 @@ module.exports = { else acc[index].amount += vin.amount return acc }, [])).then(vins => { - if (tx.vin.filter(vin => vin.coinbase).length) { + if (tx.vin.find(vin => vin.coinbase)) { vins.push({ addresses: 'coinbase', amount: tx.vout.reduce((acc, vout) => acc + vout.value * 1e8, 0) - vins.reduce((acc, vin) => acc + vin.amout, 0) diff --git a/lib/util.js b/lib/util.js index b169f79ef..443dc0ba6 100644 --- a/lib/util.js +++ b/lib/util.js @@ -75,5 +75,11 @@ module.exports = { renameProp(oldProp, newProp, { [oldProp]: old, ...others }) { return { [newProp]: old, ...others } + }, + + wait(millis) { + return new Promise((resolve, reject) => { + setTimeout(() => resolve(), millis) + }) } } \ No newline at end of file diff --git a/models/block.js b/models/block.js index fccc010ce..aa222c985 100644 --- a/models/block.js +++ b/models/block.js @@ -1,5 +1,19 @@ const mongoose = require('mongoose') +const TxSchema = new mongoose.Schema({ + txid: { type: String, lowercase: true, unique: true }, + version: { type: Number }, + size: { type: Number }, + vsize: { type: Number }, + locktime: { type: Number, default: 0 }, + vin: { type: Array, default: [] }, + vout: { type: Array, default: [] }, + EQB_type: { type: Number }, + EQB_payload: { type: String }, + hex: { type: String, lowercase: true, unique: true }, + time: { type: Number }, +}) + const BlockSchema = new mongoose.Schema({ hash: { type: String, lowercase: true, unique: true, index: true }, size: { type: Number }, @@ -7,7 +21,8 @@ const BlockSchema = new mongoose.Schema({ height: { type: Number }, version: { type: Number }, merkleroot: { type: String, lowercase: true }, - tx: { type: Array, default: [] }, + tx: { type: Array }, + fulltx: [ TxSchema ], time: { type: Number }, mediantime: { type: Number }, bits: { type: String, lowercase: true }, diff --git a/models/tx.js b/models/tx.js deleted file mode 100644 index 3d2a0a39e..000000000 --- a/models/tx.js +++ /dev/null @@ -1,14 +0,0 @@ -var mongoose = require('mongoose') - , Schema = mongoose.Schema; - -var TxSchema = new Schema({ - txid: { type: String, lowercase: true, unique: true, index: true}, - vin: { type: Array, default: [] }, - vout: { type: Array, default: [] }, - total: { type: Number, default: 0 }, - timestamp: { type: Number, default: 0 }, - blockhash: { type: String }, - blockindex: {type: Number, default: 0}, -}, {id: false}); - -module.exports = mongoose.model('Tx', TxSchema); diff --git a/scripts/sync.js b/scripts/sync.js index 5fffe13b3..abdd94b24 100644 --- a/scripts/sync.js +++ b/scripts/sync.js @@ -1,6 +1,6 @@ const mongoose = require('mongoose'), db = require('../lib/database'), - Tx = require('../models/tx'), + Block = require('../models/block'), Address = require('../models/address'), Richlist = require('../models/richlist'), Stats = require('../models/stats'), @@ -136,48 +136,31 @@ function main() { debug(`Run 'npm start' to create database structure before running this script.`) exit(database) } - return promisify(db.get_stats, settings.coin) - }).then(stats => { + }).then(async () => { + await db.updateStats(settings.coin) + const stats = await promisify(Stats.findOne.bind(Stats), { coin: settings.coin }) + if (mode === 'reindex') { - return promisify(Tx.remove.bind(Tx), {}).then(err => - promisify(Address.remove.bind(Address), {}) - ).then(err => - promisify(Richlist.update.bind(Richlist), { coin: settings.coin }, { received: [], balance: [] }) - ).then(err => - promisify(Stats.update.bind(Stats), { coin: settings.coin }, { last: 0 }) - ).then(() => { - debug(`\n\n${stats.count}\n\n`) - debug('index cleared (reindex)') - return promisify(db.update_tx_db, settings.coin, 1, stats.count, settings.update_timeout) - }).then(() => - promisify(db.update_richlist, 'received') - ).then(() => - promisify(db.update_richlist, 'balance') - ).then(() => - promisify(db.get_stats, settings.coin) - ).then(nstats => { - debug(`reindex complete (block: ${nstats.last})`) - }) - } else if (mode === 'check') { - return promisify(db.update_tx_db, settings.coin, 1, stats.count, settings.check_timeout).then(() => - promisify(db.get_stats, settings.coin) - ).then(nstats => { - debug(`check complete (block: ${nstats.last})`) - }) - } else if (mode === 'update') { - return promisify(db.update_tx_db, settings.coin, stats.last, stats.count, settings.update_timeout).then(() => - promisify(db.update_richlist, 'received') - ).then(() => - promisify(db.update_richlist, 'balance') - ).then(() => - promisify(db.get_stats, settings.coin) - ).then(nstats => { - debug(`update complete (block: ${nstats.last})`) - }) + await promisify(Block.remove.bind(Block), {}) + await promisify(Address.remove.bind(Address), {}) + await promisify(Richlist.update.bind(Richlist), { coin: settings.coin }, { received: [], balance: [] }) + + debug('[reindex]: index cleared') + } + + await db.updateDb(stats, 0, stats.blocks, settings.update_timeout) + + if (mode === 'check') { + debug(`[check]: complete`) + return } - }).then(() => - promisify(db.update_db, settings.coin) - ).then(() => exit(database)) + + await promisify(db.update_richlist, 'received') + await promisify(db.update_richlist, 'balance') + + debug(`[${mode}]: index complete (${stats.blocks})`) + exit(database) + }) } else { return settings.markets.enabled.reduce((complete, m, _, markets) => { return promisify(db.check_market, m).then(([m, exists]) => { diff --git a/views/index.jade b/views/index.jade index 779c4bd3c..e0723a1b8 100644 --- a/views/index.jade +++ b/views/index.jade @@ -9,7 +9,7 @@ block content ordering: false, responsive: true, lengthChange: true, - processing: true, + processing: parseInt(#{ui_interval}) > 10000, // only display loading indicator if update interval is long enough language: { processing: 'Loading...' }, diff --git a/views/info.jade b/views/info.jade index 28ada562d..3685ea8bb 100644 --- a/views/info.jade +++ b/views/info.jade @@ -68,13 +68,8 @@ block content *Returns current balance of given address* [#{address}/ext/getbalance/#{hashes.address}](/ext/getbalance/#{hashes.address}) - * **getlasttxs (/ext/getlasttxs?count=[number\_of\_txs]&minAmount=[min\_amount\_in\_#{settings.symbol}]&start=[most\_recent\_tx\_objectid])** - *Returns last [count] transactions with amounts (measured in #{settings.symbol}) greater than [minAmount]. Start is mainly used for paging results such that if specified, only transactions with objectIds less than [start] will be returned. Since objectIds are created according to when the transaction was added to the database, they essentially serve as a unique timestamp to query by.* - *Note: returned values are in satoshis* - [#{address}/ext/getlasttxs?count=10&minAmount=5](/ext/getlasttxs?count=10&minAmount=5) - - * **getblocks (/ext/getblocks/start/end?flds=[fields]&reverse=[true|false]&strip=[true|false])** - *Returns a list of blocks found from [start] to [end] block height (inclusive, indexed from 1). \[reverse\] can be set to read from the most recent blocks first (e.g. /ext/getblocks/1/10?reverse=true will return the 10 most recent blocks). A list of length end - start will always be returned and blocks not found will simply be set to null, however if [strip] is true, all invalid blockheights will be removed from the returned results.* + * **getblocks (/ext/getblocks/start/end?flds=[fields]&reverse=[true|false])** + *Returns a list of blocks found from [start] to [end] block height (inclusive, indexed from 1). \[reverse\] can be set to read from the most recent blocks first (e.g. /ext/getblocks/1/10?reverse=true will return the 10 most recent blocks). A list of all blocks found within the specified height range will be returned.* *[flds] is a list of fields to return, if set to "summary" it will only return block info, ["tx"] is commonly used to only return transactions in the block.* [#{address}/ext/getblocks/1/10](/ext/getblocks/1/10) From f790e674b854c6e7616daa4d7c1abd6041524663 Mon Sep 17 00:00:00 2001 From: Conrad Date: Thu, 20 Dec 2018 10:55:02 -0500 Subject: [PATCH 06/11] some bizzare db bugs --- app.js | 4 +- bin/instance.js | 23 -------- lib/api.js | 26 ++++++++- lib/database.js | 12 +++-- lib/explorer.js | 5 +- models/stats.js | 3 +- scripts/sync.js | 141 ++++++++++++++++++++++++------------------------ 7 files changed, 107 insertions(+), 107 deletions(-) diff --git a/app.js b/app.js index 3be15b711..37d99012d 100644 --- a/app.js +++ b/app.js @@ -1,7 +1,7 @@ const express = require('express'), debug = require('debug')('explorer'), path = require('path'), - { Api } = require('./lib/api'), + { api } = require('./lib/api'), favicon = require('static-favicon'), logger = require('morgan'), cookieParser = require('cookie-parser'), @@ -31,7 +31,7 @@ app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); // routes -app.use('/api', Api().app); +app.use('/api', api.app); app.use('/', routes); app.use('/ext/getmoneysupply', function(req,res){ lib.get_supply(function(supply){ diff --git a/bin/instance.js b/bin/instance.js index aba9cf684..abec43a06 100755 --- a/bin/instance.js +++ b/bin/instance.js @@ -2,29 +2,6 @@ // ensure the api singleton has been initialized before anything else const settings = require('../lib/settings') -const { Api, SpecTypes, CacheTypes } = require('../lib/api') -const api = new Api({ - allowRawRpc: true, - rpcConfig: { - type: SpecTypes.ONLY, - cacheDefault: CacheTypes.FORCE, - rpc: [ - 'getnetworkhashps', - 'getmininginfo', - 'getdifficulty', - 'getconnectioncount', - 'getblockcount', - 'getblockhash', - 'getblock', - 'getrawtransaction', - 'getpeerinfo', - 'gettxoutsetinfo', - 'getmempoolinfo', - 'getrawmempool' - ] - }, - wallet: settings.wallet -}) const debug = require('debug')('explorer') const db = require('../lib/database') diff --git a/lib/api.js b/lib/api.js index 545355fcf..b4fa64ba8 100644 --- a/lib/api.js +++ b/lib/api.js @@ -98,13 +98,35 @@ class PrivApi { let instance function Api (...args) { - console.log(args) if (!instance) instance = new PrivApi(...args) return instance } +const api = new Api({ + allowRawRpc: true, + rpcConfig: { + type: SpecTypes.ONLY, + cacheDefault: CacheTypes.FORCE, + rpc: [ + 'getnetworkhashps', + 'getmininginfo', + 'getdifficulty', + 'getconnectioncount', + 'getblockcount', + 'getblockhash', + 'getblock', + 'getrawtransaction', + 'getpeerinfo', + 'gettxoutsetinfo', + 'getmempoolinfo', + 'getrawmempool' + ] + }, + wallet: settings.wallet +}) + module.exports = { - Api, + api, SpecTypes, CacheTypes } diff --git a/lib/database.js b/lib/database.js index 9c23ef309..fe55d1906 100644 --- a/lib/database.js +++ b/lib/database.js @@ -535,11 +535,13 @@ module.exports = { async updateStats (coin) { const txoutinfo = await lib.getRawRpc('gettxoutsetinfo') const mininginfo = await lib.getRawRpc('getmininginfo') + const connections = await lib.getRawRpc('getconnectioncount') + console.log(`\n\nIN STATS: ${prettyPrint(txoutinfo)}\n`) // Although schema queries return a thenable Query object, they are not full promises and // thus cannot be used with async/await syntax. - return promisify(Stats.update.bind(Stats), { coin }, { - blocks: txoutinfo.height, + return promisify(Stats.update.bind(Stats), { coin: coin }, { + blocks: mininginfo.blocks, currentblockweight: mininginfo.currentblockweight, currentblocktx: mininginfo.currentblocktx, difficulty: mininginfo.difficulty, @@ -548,7 +550,7 @@ module.exports = { chain: mininginfo.chain, warnings: mininginfo.warnings, supply: txoutinfo.total_amount, - connections: await lib.getRawRpc('getconnectioncount'), + connections, bestblock: txoutinfo.bestblock, transactions: txoutinfo.bestblock, txouts: txoutinfo.txouts, @@ -560,10 +562,10 @@ module.exports = { async updateDb (stats, start, end, timeout) { for (const i = start; i < end; i++) { - const [ err, block ] = await promisify(Block.findOne.bind(Block), { height: i }) + let [ err, block ] = await promisify(Block.findOne.bind(Block), { height: i }) if (block) continue - const block = await lib.getBlock(await promisify(lib.get_blockhash, i), undefined, stats.blocks) + block = await lib.getBlock(await promisify(lib.get_blockhash, i), undefined, stats.blocks) if (!block) { debug(`Block #${i} could not be found, skipping.`) continue diff --git a/lib/explorer.js b/lib/explorer.js index 0ba49a50f..30e336299 100644 --- a/lib/explorer.js +++ b/lib/explorer.js @@ -2,8 +2,9 @@ const request = require('request'), debug = require('debug')('explorer:lib'), settings = require('./settings'), Address = require('../models/address'), + Block = require('../models/block'), { promisify, requestp, deepEqual } = require('./util'), - { Api } = require('./api') + { api } = require('./api') const base_url = 'http://127.0.0.1:' + settings.port + '/api/' @@ -31,7 +32,7 @@ function coinbase_supply () { module.exports = { getRawRpc (method, params) { - return Api().callRawRpc(method, params) + return api.callRawRpc(method, params) }, convert_to_satoshi (amount, cb) { diff --git a/models/stats.js b/models/stats.js index 4973464ce..05609a28a 100644 --- a/models/stats.js +++ b/models/stats.js @@ -18,7 +18,8 @@ var StatsSchema = new Schema({ txouts: { type: Number, default: 0 }, bogosize: { type: Number, default: 0 }, hash_serialized_2: { type: String, lowercase: true }, - disk_size: { type: Number, default: 0 } + disk_size: { type: Number, default: 0 }, + last_price: { type: Number, default: 0 } }); module.exports = mongoose.model('stats', StatsSchema); \ No newline at end of file diff --git a/scripts/sync.js b/scripts/sync.js index abdd94b24..3d2f08d9f 100644 --- a/scripts/sync.js +++ b/scripts/sync.js @@ -5,7 +5,7 @@ const mongoose = require('mongoose'), Richlist = require('../models/richlist'), Stats = require('../models/stats'), settings = require('../lib/settings'), - { promisify, prettyPrint } = require('../lib/util'), + { promisify, prettyPrint, wait } = require('../lib/util'), fs = require('fs'), debug = require('debug')('explorer:sync') @@ -113,84 +113,81 @@ function exit(database) { //////// MAIN ENTRYPOINT //////// const { database, mode } = parseArgs(process.argv.slice(2)) -function main() { +async function main() { debug(`- database=${database}, mode=${mode}`) - isLocked(database).then(exists => { - // if there's a lock file, exit - if (exists) { - debug('Script already running.') - process.exit() - } - }).then(() => - createLock(database).catch(e => { - debug('Error: unable to create lock file.') - process.exit(1) - }) - ).then(() => { - debug('Script launched with pid: ' + process.pid) - return mongoose.connect(settings.dbsettings.uri, settings.dbsettings.options) - }).then(() => { - if (database === 'index') { - return promisify(db.check_stats, settings.coin).then(exists => { - if (!exists) { - debug(`Run 'npm start' to create database structure before running this script.`) - exit(database) - } - }).then(async () => { - await db.updateStats(settings.coin) - const stats = await promisify(Stats.findOne.bind(Stats), { coin: settings.coin }) - - if (mode === 'reindex') { - await promisify(Block.remove.bind(Block), {}) - await promisify(Address.remove.bind(Address), {}) - await promisify(Richlist.update.bind(Richlist), { coin: settings.coin }, { received: [], balance: [] }) - - debug('[reindex]: index cleared') - } - - await db.updateDb(stats, 0, stats.blocks, settings.update_timeout) - - if (mode === 'check') { - debug(`[check]: complete`) - return - } - - await promisify(db.update_richlist, 'received') - await promisify(db.update_richlist, 'balance') - - debug(`[${mode}]: index complete (${stats.blocks})`) - exit(database) - }) - } else { - return settings.markets.enabled.reduce((complete, m, _, markets) => { - return promisify(db.check_market, m).then(([m, exists]) => { - complete++ - if (exists) { - return promisify(db.update_markets_db, m).then(err => { - if (err) debug(`${m}: ${err}`) - else debug(`${m} market data updated successfully.`) - if (complete === markets.length) exit() - return complete - }) - } - debug(`Error: entry for ${m} does not exist in markets db.`) - if (complete === markets.length) exit() - return complete - }) - }, 0) - } - }).catch(err => { + + // watch for concurrent execution with lockfiles + if (await isLocked(database)) { + debug('Script already running.') + process.exit() + } + await createLock(database).catch(e => { + debug('Error: unable to create lock file.') + process.exit(1) + }) + + debug('Script launched with pid: ' + process.pid) + await promisify(mongoose.connect, settings.dbsettings.uri, settings.dbsettings.options).catch(err => { console.log(err) console.log(`Unable to connect to database: ${settings.dbsettings.uri}.`) console.log(`With options: ${prettyPrint(settings.dbsettings.options, null, 2)}`) console.log('Aborting') return exit(database) }) + + if (database === 'index') { + if (!(await promisify(db.check_stats, settings.coin))) { + debug(`Run 'npm start' to create database structure before running this script.`) + exit(database) + } + + console.log(`\n\nBEFORE STAT\n`) + await db.updateStats(settings.coin).then(() => promisify(Stats.findOne.bind(Stats), { coin: settings.coin })) + .then(([ err, stats ]) => console.log(stats)) + // const [ err, stats ] = await promisify(Stats.findOne.bind(Stats), { coin: settings.coin }) + // console.log(`\n\nAFTER STAT: ${stats}\n`) + + if (mode === 'reindex') { + await promisify(Block.remove.bind(Block), {}) + await promisify(Address.remove.bind(Address), {}) + await promisify(Richlist.update.bind(Richlist), { coin: settings.coin }, { received: [], balance: [] }) + + debug('[reindex]: index cleared') + } + + await db.updateDb(stats, 0, stats.blocks, settings.update_timeout) + + if (mode === 'check') { + debug(`[check]: complete`) + return + } + + await promisify(db.update_richlist, 'received') + await promisify(db.update_richlist, 'balance') + + debug(`[${mode}]: index complete (${stats.blocks})`) + exit(database) + } else { + await settings.markets.enabled.reduce((complete, m, _, markets) => { + return promisify(db.check_market, m).then(([m, exists]) => { + complete++ + if (exists) { + return promisify(db.update_markets_db, m).then(err => { + if (err) debug(`${m}: ${err}`) + else debug(`${m} market data updated successfully.`) + if (complete === markets.length) exit() + return complete + }) + } + debug(`Error: entry for ${m} does not exist in markets db.`) + if (complete === markets.length) exit() + return complete + }) + }, 0) + } } -try { - main() -} catch (err) { - console.log(`An error occurred: ${prettyPrint(err)}`) +main().catch(err => { + console.log(`An error occurred: ${err}`) exit(database) -} +}) From 3c1b873d02ddf1af529c5c6eef91e85c501f762c Mon Sep 17 00:00:00 2001 From: Conrad Date: Thu, 20 Dec 2018 12:35:58 -0500 Subject: [PATCH 07/11] indexing now works as intended, some api calls are erroring though --- app.js | 12 +++++------- lib/api.js | 2 +- lib/database.js | 13 ++++++------- models/stats.js | 2 +- scripts/sync.js | 7 ++----- views/info.jade | 2 +- 6 files changed, 16 insertions(+), 22 deletions(-) diff --git a/app.js b/app.js index 37d99012d..964fc95aa 100644 --- a/app.js +++ b/app.js @@ -87,19 +87,17 @@ app.use('/ext/getblocks/:start/:end', async function (req, res) { return } + const blockcount = await requestp(`${endpoint}/api/getblockcount`) let heights = Array(end - start + 1).fill(undefined).map((_, i) => start + i) - if (reverse) { - const height = await requestp(`${endpoint}/api/getblockcount`) - heights = heights.map(h => height - h + 1) - } + if (reverse) heights = heights.map(h => blockcount - h + 1) const flds = req.query.flds == 'summary' ? { fulltx: 0, _id: 0 } : req.query.flds == 'tx' ? { fulltx: 1, _id: 0 } - : req.query.flds.reduce((acc, fld) => ({ ...acc, [fld]: 1 }), { _id: 0 }) - const blocks = await lib.getBlocksDb(heights, flds) - res.send(blocks) + : req.query.flds ? req.query.flds.reduce((acc, fld) => ({ ...acc, [fld]: 1 }), { _id: 0 }) : [] + const [ err, blocks ] = await lib.getBlocksDb(heights, flds) + res.send({ data: { blockcount, blocks } }) /* const txReq = () => Promise.all(heights.map(i => diff --git a/lib/api.js b/lib/api.js index b4fa64ba8..dc97c7e2f 100644 --- a/lib/api.js +++ b/lib/api.js @@ -39,7 +39,7 @@ class PrivApi { }) } - callRawRpc (method, parameters) { + async callRawRpc (method, parameters) { if (this.allowRawRpc) return this.client.command([ { method, parameters } ]).then(([ resp, err ]) => this.handle(resp, err)) else return 'Direct RPC calls are not enabled.' diff --git a/lib/database.js b/lib/database.js index fe55d1906..71439f210 100644 --- a/lib/database.js +++ b/lib/database.js @@ -535,8 +535,6 @@ module.exports = { async updateStats (coin) { const txoutinfo = await lib.getRawRpc('gettxoutsetinfo') const mininginfo = await lib.getRawRpc('getmininginfo') - const connections = await lib.getRawRpc('getconnectioncount') - console.log(`\n\nIN STATS: ${prettyPrint(txoutinfo)}\n`) // Although schema queries return a thenable Query object, they are not full promises and // thus cannot be used with async/await syntax. @@ -550,9 +548,9 @@ module.exports = { chain: mininginfo.chain, warnings: mininginfo.warnings, supply: txoutinfo.total_amount, - connections, + connections: await lib.getRawRpc('getconnectioncount'), bestblock: txoutinfo.bestblock, - transactions: txoutinfo.bestblock, + transactions: txoutinfo.transactions, txouts: txoutinfo.txouts, bogosize: txoutinfo.bogosize, hash_serialized_2: txoutinfo.hash_serialized_2, @@ -561,11 +559,11 @@ module.exports = { }, async updateDb (stats, start, end, timeout) { - for (const i = start; i < end; i++) { + for (let i = start; i < end; i++) { let [ err, block ] = await promisify(Block.findOne.bind(Block), { height: i }) if (block) continue - block = await lib.getBlock(await promisify(lib.get_blockhash, i), undefined, stats.blocks) + block = await lib.getRawRpc('getblock', [ await lib.getRawRpc('getblockhash', [ i ]) ]) if (!block) { debug(`Block #${i} could not be found, skipping.`) continue @@ -575,7 +573,8 @@ module.exports = { } debug(`Caching #${i}: ${block.hash}`) - block.fulltx = await Promise.all(block.tx.map(txid => promisify(lib.get_rawtransaction, txid))) + block.fulltx = await Promise.all(block.tx.map(txid => lib.getRawRpc('getrawtransaction', [ txid, 1 ]))) + .then(txs => txs.map((tx, t) => ({ txid: block.tx[t], ...tx })).filter(tx => !tx.code && !tx.name)) await Block.create([ block ]) if (timeout) await wait(timeout) } diff --git a/models/stats.js b/models/stats.js index 05609a28a..ff0363d8e 100644 --- a/models/stats.js +++ b/models/stats.js @@ -6,7 +6,7 @@ var StatsSchema = new Schema({ blocks: { type: Number, default: 1 }, currentblockweight: { type: Number, default: 4000 }, currentblocktx: { type: Number, default: 0 }, - difficulty: { type: Object, default: 1 }, + difficulty: { type: String, default: 1 }, networkhashps: { type: String, default: 'N/A' }, pooledtx: { type: Number, default: 0 }, chain: { type: String }, diff --git a/scripts/sync.js b/scripts/sync.js index 3d2f08d9f..f6bc2c9a5 100644 --- a/scripts/sync.js +++ b/scripts/sync.js @@ -141,11 +141,8 @@ async function main() { exit(database) } - console.log(`\n\nBEFORE STAT\n`) - await db.updateStats(settings.coin).then(() => promisify(Stats.findOne.bind(Stats), { coin: settings.coin })) - .then(([ err, stats ]) => console.log(stats)) - // const [ err, stats ] = await promisify(Stats.findOne.bind(Stats), { coin: settings.coin }) - // console.log(`\n\nAFTER STAT: ${stats}\n`) + await db.updateStats(settings.coin) + const [ err, stats ] = await promisify(Stats.findOne.bind(Stats), { coin: settings.coin }) if (mode === 'reindex') { await promisify(Block.remove.bind(Block), {}) diff --git a/views/info.jade b/views/info.jade index 3685ea8bb..6a2718d1f 100644 --- a/views/info.jade +++ b/views/info.jade @@ -71,7 +71,7 @@ block content * **getblocks (/ext/getblocks/start/end?flds=[fields]&reverse=[true|false])** *Returns a list of blocks found from [start] to [end] block height (inclusive, indexed from 1). \[reverse\] can be set to read from the most recent blocks first (e.g. /ext/getblocks/1/10?reverse=true will return the 10 most recent blocks). A list of all blocks found within the specified height range will be returned.* *[flds] is a list of fields to return, if set to "summary" it will only return block info, ["tx"] is commonly used to only return transactions in the block.* - [#{address}/ext/getblocks/1/10](/ext/getblocks/1/10) + [#{address}/ext/getblocks/0/10](/ext/getblocks/1/10) ------ From 578d53f7c5e91ec195018495b4c8d0cc60d0306a Mon Sep 17 00:00:00 2001 From: Conrad Date: Thu, 20 Dec 2018 17:37:02 -0500 Subject: [PATCH 08/11] ui starting to work, still need sorting --- app.js | 19 ++++--- bin/cluster.js | 20 +++---- bin/instance.js | 4 +- lib/api.js | 67 +++++++++++++----------- lib/database.js | 135 ++++++++++++++++++++++++++++-------------------- lib/explorer.js | 10 ---- lib/util.js | 16 +++--- routes/index.js | 13 +---- scripts/sync.js | 11 ++-- views/info.jade | 2 +- 10 files changed, 153 insertions(+), 144 deletions(-) diff --git a/app.js b/app.js index 964fc95aa..db3eaea17 100644 --- a/app.js +++ b/app.js @@ -6,18 +6,18 @@ const express = require('express'), logger = require('morgan'), cookieParser = require('cookie-parser'), bodyParser = require('body-parser'), - request = require('request'), settings = require('./lib/settings'), routes = require('./routes/index'), lib = require('./lib/explorer'), db = require('./lib/database'), locale = require('./lib/locale'), - { promisify, requestp } = require('./lib/util') + { requestp } = require('./lib/util'), + info = require('./info') -const app = express(); - -const info = require('./info'); +const app = express() info(app) +api.setCredentials(settings.wallet) +api.setCachers(db.rpc) // view engine setup app.set('views', path.join(__dirname, 'views')); @@ -81,6 +81,7 @@ app.use('/ext/getblocks/:start/:end', async function (req, res) { const start = parseInt(req.param('start')) const end = parseInt(req.param('end')) const reverse = req.query.reverse && req.query.reverse.toLowerCase() === 'true' + const flds = typeof req.query.flds === 'string' ? req.query.flds.split(',') : req.query.flds if (start > end) { res.send({ error: `End blockheight must be greater than or equal to the start blockheight.` }) @@ -91,12 +92,10 @@ app.use('/ext/getblocks/:start/:end', async function (req, res) { let heights = Array(end - start + 1).fill(undefined).map((_, i) => start + i) if (reverse) heights = heights.map(h => blockcount - h + 1) - const flds = req.query.flds == 'summary' + const searchFlds = flds && flds[0] === 'summary' ? { fulltx: 0, _id: 0 } - : req.query.flds == 'tx' - ? { fulltx: 1, _id: 0 } - : req.query.flds ? req.query.flds.reduce((acc, fld) => ({ ...acc, [fld]: 1 }), { _id: 0 }) : [] - const [ err, blocks ] = await lib.getBlocksDb(heights, flds) + : flds ? flds.reduce((acc, fld) => ({ ...acc, [fld]: 1 }), { _id: 0 }) : [] + const blocks = await db.getBlocks(heights, searchFlds) res.send({ data: { blockcount, blocks } }) /* diff --git a/bin/cluster.js b/bin/cluster.js index 41e47fb95..54fef3f42 100644 --- a/bin/cluster.js +++ b/bin/cluster.js @@ -31,16 +31,16 @@ if (cluster.isMaster) { db.setupSchema() ).then(() => { // set database update intervals - // spawnCmd('node', [ 'scripts/sync.js', 'index', settings.index.index_mode || 'update' ]) - // updateIntervals.push(setInterval(function () { - // spawnCmd('node', [ 'scripts/sync.js', 'index', 'update' ]) - // }, settings.sync_timeout)) - // updateIntervals.push(setInterval(function () { - // spawnCmd('node', [ 'scripts/sync.js', 'market' ]) - // }, settings.market_timeout)) - // updateIntervals.push(setInterval(function () { - // spawnCmd('node', [ 'scripts/peers.js' ]) - // }, settings.peer_timeout)) + spawnCmd('node', [ 'scripts/sync.js', 'index', settings.index.index_mode || 'update' ]) + updateIntervals.push(setInterval(function () { + spawnCmd('node', [ 'scripts/sync.js', 'index', 'update' ]) + }, settings.sync_timeout)) + updateIntervals.push(setInterval(function () { + spawnCmd('node', [ 'scripts/sync.js', 'market' ]) + }, settings.market_timeout)) + updateIntervals.push(setInterval(function () { + spawnCmd('node', [ 'scripts/peers.js' ]) + }, settings.peer_timeout)) // spawn a worker for each cpu core require('os').cpus().forEach(_ => { diff --git a/bin/instance.js b/bin/instance.js index abec43a06..1f7d69558 100755 --- a/bin/instance.js +++ b/bin/instance.js @@ -12,9 +12,11 @@ app.set('port', process.env.PORT || settings.port) db.connect(settings.dbsettings).then(() => promisify(db.get_stats, settings.coin) -).then((stats) => { +).then(stats => { app.locals.stats = stats const server = app.listen(app.get('port'), () => { debug('Express server listening on port ' + server.address().port) }) +}).catch(err => { + process.exit(1) }) diff --git a/lib/api.js b/lib/api.js index dc97c7e2f..7d232a953 100644 --- a/lib/api.js +++ b/lib/api.js @@ -1,57 +1,69 @@ const express = require('express') const debug = require('debug')('explorer:api') const Client = require('bitcoin-core') -const settings = require('./settings') -const db = require('./database') const SpecTypes = Object.freeze({ 'ALL': 0, 'ONLY': 1, 'EXCEPT': 2 }) const CacheTypes = Object.freeze({ 'FORCE': 0, 'NEVER': 1, 'AS_NEEDED': 2 }) -class PrivApi { +class Api { - constructor ({ rpcConfig, wallet, allowRawRpc = false }) { + constructor ({ + rpcConfig = { + type: SpecTypes.ALL, + cacheDefault: CacheTypes.FORCE, + allowRaw: false, + rpc: [] + }, + cachers, + wallet + }) { this.app = express() - this.allowedRpc = rpcConfig + this.rpcConfig = rpcConfig this.walletDetails = wallet this.client = new Client(wallet) - this.allowRawRpc = allowRawRpc + this.cachers = cachers this.app.get('*', this.hasAccess.bind(this), (req, res) => { const method = req.path.substr(1) - if (PrivApi.requiresCredentials.includes(method) && !this.client.password) { + if (Api.requiresCredentials.includes(method) && !this.client.password) { return res.send('A wallet password is required and has not been set.') } const parameters = (req.query instanceof Array ? req.query : Object.values(req.query)).map(param => isNaN(param) ? param : parseFloat(param)) switch (this.getCacheType(method)) { case CacheTypes.FORCE: - return db.rpc[method](...parameters).then(this.handle).then(resp => res.send(resp)) + return this.cachers.hasOwnProperty(method) + ? this.cachers[method](...parameters).then(this.handle).then(resp => res.send(resp)) + : res.send(`No caching method was supplied for ${method}.`) case CacheTypes.NEVER: return this.client.command([ { method, parameters } ]).then(([ resp, err ]) => { res.send(this.handle(resp, err)) }) case CacheTypes.AS_NEEDED: + if (!this.cachers.hasOwnProperty(method)) return res.send(this.rawRpc(method, parameters)) return db.rpc[method](...parameters).then(this.handle).then(resp => resp.includes('There was an error') - ? this.client.command([ { method, parameters } ]).then(([ resp, err ]) => this.handle(resp, err)) + ? this.rawRpc(method, parameters) : resp ).then(resp => res.send(resp)) } }) } + async rawRpc (method, parameters) { + return this.client.command([ { method, parameters } ]).then(([ resp, err ]) => this.handle(resp, err)) + } + async callRawRpc (method, parameters) { - if (this.allowRawRpc) - return this.client.command([ { method, parameters } ]).then(([ resp, err ]) => this.handle(resp, err)) - else return 'Direct RPC calls are not enabled.' + return this.rpcConfig.allowRaw ? this.rawRpc(method, parameters) : 'Direct RPC calls are not enabled.' } getCacheType (method) { - if (this.allowedRpc.type === SpecTypes.ONLY) { - return Object.values(CacheTypes).includes(this.allowedRpc.rpc[method]) - ? this.allowedRpc.rpc[method] - : this.allowedRpc.cacheDefault + if (this.rpcConfig.type === SpecTypes.ONLY) { + return Object.values(CacheTypes).includes(this.rpcConfig.rpc[method]) + ? this.rpcConfig.rpc[method] + : this.rpcConfig.cacheDefault } - return this.allowedRpc.cacheDefault + return this.rpcConfig.cacheDefault } handle (data, err) { @@ -64,12 +76,12 @@ class PrivApi { } hasAccess (req, res, next) { - if (this.allowedRpc.type === SpecTypes.ALL) return next() + if (this.rpcConfig.type === SpecTypes.ALL) return next() const method = req.path.substr(1) if ( - (this.allowedRpc.type === SpecTypes.ONLY && this.allowedRpc.rpc.includes(method)) - || (this.allowedRpc.type === SpecTypes.EXCEPT && !this.allowedRpc.rpc.includes(method)) + (this.rpcConfig.type === SpecTypes.ONLY && this.rpcConfig.rpc.includes(method)) + || (this.rpcConfig.type === SpecTypes.EXCEPT && !this.rpcConfig.rpc.includes(method)) ) { return next() } else { @@ -81,6 +93,10 @@ class PrivApi { this.client = new Client({ ...this.walletDetails, creds }) } + setCachers (cachers) { + this.cachers = cachers + } + static get requiresCredentials () { return [ 'dumpprivkey', @@ -96,17 +112,11 @@ class PrivApi { } -let instance -function Api (...args) { - if (!instance) instance = new PrivApi(...args) - return instance -} - const api = new Api({ - allowRawRpc: true, rpcConfig: { type: SpecTypes.ONLY, cacheDefault: CacheTypes.FORCE, + allowRaw: true, rpc: [ 'getnetworkhashps', 'getmininginfo', @@ -121,8 +131,7 @@ const api = new Api({ 'getmempoolinfo', 'getrawmempool' ] - }, - wallet: settings.wallet + } }) module.exports = { diff --git a/lib/database.js b/lib/database.js index 71439f210..e6b49b252 100644 --- a/lib/database.js +++ b/lib/database.js @@ -6,7 +6,6 @@ const mongoose = require('mongoose'), Block = require('../models/block'), Richlist = require('../models/richlist'), Peers = require('../models/peers'), - lib = require('./explorer'), settings = require('./settings'), poloniex = require('./markets/poloniex'), bittrex = require('./markets/bittrex'), @@ -16,7 +15,8 @@ const mongoose = require('mongoose'), yobit = require('./markets/yobit'), empoex = require('./markets/empoex'), ccex = require('./markets/ccex'), - { promisify, prettyPrint, renameProp, wait } = require('../lib/util') + lib = require('./explorer'), + { promisify, prettyPrint, renameProp, wait } = require('./util') function find_address(hash, cb) { Address.findOne({a_id: hash}, function(err, address) { @@ -128,11 +128,11 @@ async function findTx (txid) { } async function parseTx(block, i) { - const tx = /[a-z]/i.test(i) ? block.tx.find(tx => tx.txid === i) : block.tx[i] + const tx = i instanceof Object ? i : /[a-z]/i.test(i) ? block.fulltx.find(tx => tx.txid === i) : block.fulltx[i] const [ vout, vin ] = await lib.prepare_vin(tx).then(vin => promisify(lib.prepare_vout, tx.vout, tx.txid, vin)) for (const v of vin) await promisify(update_address, v.addresses, tx.txid, v.amount, 'vin') for (const v of vout) { - if (v.addresses) await update_address(v.addresses, tx.txid, v.amount, 'vout') + if (v.addresses) await promisify(update_address, v.addresses, tx.txid, v.amount, 'vout') } const total = await promisify(lib.calculate_total, vout) return { @@ -193,6 +193,17 @@ function get_market_data(market, cb) { } } +function dbToRpcBlock (block, blockcount, include) { + return Object.entries({ + confirmations: block.height ? blockcount - block.height : undefined, + strippedsize: block.size, + versionHex: block.version ? block.version.toString(16) : undefined, + nTx: block.tx ? block.tx.length : undefined + }) + .filter(([ key, value ]) => value !== undefined && (!include || include.includes(key))) + .reduce((acc, [ key, value ]) => ({ ...acc, [key]: value }), { ...block }) +} + const rpcOnError = (method, err) => { debug(`An error occurred while trying access cache of ${method}: ${err}`) return null @@ -248,13 +259,7 @@ const rpc = { }) return promisify(Block.findOne.bind(Block), { hash }, { fulltx: 0, _id: 0 }).then(([ err, res ]) => { if (err) return rpcOnError('getblock', err) - return { - ...res._doc, - confirmations: blockcount - res.height, - strippedsize: res.size, - versionHex: res.version.toString(16), - nTx: res.tx.length - } + return dbToRpcBlock(res._doc, blockcount) }) }, @@ -304,11 +309,11 @@ module.exports = { rpc, connect (dbSettings) { - return mongoose.connect(dbSettings.uri, dbSettings.options).catch(err => { + return promisify(mongoose.connect, dbSettings.uri, dbSettings.options).catch(err => { console.log(`Unable to connect to database: ${dbSettings.uri}`); console.log(`With options: ${prettyPrint(dbSettings.options, null, 2)}`); console.log(`Aborting with ERROR: ${prettyPrint(err)}`) - process.exit(1); + throw new Error(err) }); }, @@ -387,8 +392,8 @@ module.exports = { }, async getTxs (block) { - return promisify(Block.findOne.bind(Block), block, { tx: 1 }).then(block => - block.tx.map(tx => parseTx(block, tx)) + return promisify(Block.findOne.bind(Block), block).then(([ err, block ]) => + err || !block ? null : block.tx.map(tx => parseTx(block, tx)) ) }, @@ -532,6 +537,58 @@ module.exports = { }); }, + create_peer: function(params, cb) { + var newPeer = new Peers(params); + newPeer.save(function(err) { + if (err) { + console.log(err); + return cb(); + } else { + return cb(); + } + }); + }, + + find_peer: function(address, cb) { + Peers.findOne({address: address}, function(err, peer) { + if (err) { + return cb(null); + } else { + if (peer) { + return cb(peer); + } else { + return cb (null) + } + } + }) + }, + + get_peers: function(cb) { + Peers.find({}, function(err, peers) { + if (err) { + return cb([]); + } else { + return cb(peers); + } + }); + }, + + async getBlocks (searchParams, flds) { + const params = (searchParams.length ? searchParams : [ searchParams ]) + const mode = params.find(param => /[a-z]/i.test(param)) !== undefined ? 'hash' : 'height' + const blockheight = await rpc.getblockcount() + return promisify( + Block[params.length > 1 ? 'find' : 'findOne'].bind(Block), + { [mode]: { $in: params } }, + flds || { } + ).then(([ err, blocks ]) => err + ? null + : blocks.length + ? blocks.map(block => dbToRpcBlock(block._doc, blockheight, flds.fulltx === 0 ? null : Object.keys(flds))) + : dbToRpcBlock(blocks._doc, blockheight, params) + ) + }, + async updateStats (coin) { const txoutinfo = await lib.getRawRpc('gettxoutsetinfo') const mininginfo = await lib.getRawRpc('getmininginfo') @@ -557,12 +614,12 @@ module.exports = { disk_size: txoutinfo.disk_size, }) }, - - async updateDb (stats, start, end, timeout) { + + async updateDb (start, end, timeout) { for (let i = start; i < end; i++) { let [ err, block ] = await promisify(Block.findOne.bind(Block), { height: i }) if (block) continue - + block = await lib.getRawRpc('getblock', [ await lib.getRawRpc('getblockhash', [ i ]) ]) if (!block) { debug(`Block #${i} could not be found, skipping.`) @@ -571,53 +628,17 @@ module.exports = { debug(`Block #${i} does not have any transactions, skipping.`) continue } - + debug(`Caching #${i}: ${block.hash}`) block.fulltx = await Promise.all(block.tx.map(txid => lib.getRawRpc('getrawtransaction', [ txid, 1 ]))) .then(txs => txs.map((tx, t) => ({ txid: block.tx[t], ...tx })).filter(tx => !tx.code && !tx.name)) await Block.create([ block ]) if (timeout) await wait(timeout) } - - }, - - create_peer: function(params, cb) { - var newPeer = new Peers(params); - newPeer.save(function(err) { - if (err) { - console.log(err); - return cb(); - } else { - return cb(); - } - }); - }, - - find_peer: function(address, cb) { - Peers.findOne({address: address}, function(err, peer) { - if (err) { - return cb(null); - } else { - if (peer) { - return cb(peer); - } else { - return cb (null) - } - } - }) - }, - - get_peers: function(cb) { - Peers.find({}, function(err, peers) { - if (err) { - return cb([]); - } else { - return cb(peers); - } - }); + }, - setupSchema() { + setupSchema () { return promisify(this.check_stats, settings.coin).then(exists => { // setup stats if (!exists) { diff --git a/lib/explorer.js b/lib/explorer.js index 30e336299..0970a5459 100644 --- a/lib/explorer.js +++ b/lib/explorer.js @@ -120,16 +120,6 @@ module.exports = { const ret = requestp(`${base_url}getblock?hash=${hash}`) return cb ? cb(await ret) : ret }, - - getBlocksDb (searchParams, flds) { - const params = (searchParams.length ? searchParams : [ searchParams ]) - const mode = params.find(param => /[a-z]/i.test(param)) !== undefined ? 'hash' : 'height' - return promisify( - Block[params.length > 1 ? 'find' : 'findOne'].bind(Block), - { [mode]: { $in: params } }, - flds || { } - ) - }, get_rawtransaction: function (hash, cb) { var uri = base_url + 'getrawtransaction?txid=' + hash + '&decrypt=1' diff --git a/lib/util.js b/lib/util.js index 443dc0ba6..b7b900511 100644 --- a/lib/util.js +++ b/lib/util.js @@ -2,7 +2,7 @@ const request = require('request') const spawn = require('child_process').spawn module.exports = { - deepEqual(a, b) { + deepEqual (a, b) { if (!(a instanceof Object) || !(b instanceof Object)) return a === b if (Object.keys(a).filter(k => !b.hasOwnProperty(k)).length || Object.keys(b).filter(k => !a.hasOwnProperty(k)).length) return false return !Object.keys(a).concat(Object.keys(b)).map(k => module.exports.deepEqual(a[k], b[k])).includes(false) @@ -20,7 +20,7 @@ module.exports = { * @param {...any} args arguments for the function * @returns {Promise} promise that resolves with returned values when async task is complete (i.e. the callback is called) */ - promisify(func, ...args) { + promisify (func, ...args) { return new Promise((resolve, reject) => { func(...args, (...cbArgs) => resolve(cbArgs.length > 1 ? cbArgs : cbArgs[0])) }) @@ -33,20 +33,20 @@ module.exports = { * @param {...any} args remaining arguments passed to the function * @returns {Promise} promise that resolves with returned values when async task is complete */ - promisifyPos(func, cbPos, ...args) { + promisifyPos (func, cbPos, ...args) { return new Promise((resolve, reject) => { func(...args.slice(0, cbPos), (...cbArgs) => resolve(cbArgs.length > 1 ? cbArgs : cbArgs[0]), ...args.slice(cbPos)) }) }, - requestp(uri, { json = true, simple = true } = {}) { + requestp (uri, { json = true, simple = true } = {}) { const promise = module.exports.promisify(request, uri, { json }) return simple ? promise.then(([error, response, body]) => error ? Promise.reject(error) : body) : promise }, - spawnCmd(cmd, options, hooks = {}) { + spawnCmd (cmd, options, hooks = {}) { return new Promise((resolve, reject) => { const child = spawn(cmd, options) child.stdout.setEncoding('utf-8') @@ -69,15 +69,15 @@ module.exports = { }) }, - prettyPrint(obj) { + prettyPrint (obj) { return JSON.stringify(obj, null, 2) }, - renameProp(oldProp, newProp, { [oldProp]: old, ...others }) { + renameProp (oldProp, newProp, { [oldProp]: old, ...others }) { return { [newProp]: old, ...others } }, - wait(millis) { + wait (millis) { return new Promise((resolve, reject) => { setTimeout(() => resolve(), millis) }) diff --git a/routes/index.js b/routes/index.js index a39339c40..9155424ac 100644 --- a/routes/index.js +++ b/routes/index.js @@ -8,25 +8,16 @@ var express = require('express') function route_get_block(res, blockhash) { lib.getBlock(blockhash, function (block) { - console.log(block) const safeRender = list => list && list.length > 0 && list.filter(l => l).length ? list : [] if (block) { if (blockhash === settings.genesis_block) { res.render('block', { active: 'block', block: block, confirmations: settings.confirmations, txs: 'GENESIS'}); } else { - db.getTxs(block).then(txs => { + db.getTxs({ hash: blockhash }).then(txs => { if (txs && txs.length > 0) { res.render('block', { active: 'block', block: block, confirmations: settings.confirmations, txs: safeRender(txs) }); } else { - db.create_txs(block, function () { - db.getTxs(block).then(ntxs => { - if (ntxs && ntxs.length > 0) { - res.render('block', { active: 'block', block: block, confirmations: settings.confirmations, txs: safeRender(ntxs) }); - } else { - route_get_index(res, 'Block not found: ' + blockhash); - } - }); - }); + route_get_index(res, 'Block not found: ' + blockhash); } }); } diff --git a/scripts/sync.js b/scripts/sync.js index f6bc2c9a5..e1a02e447 100644 --- a/scripts/sync.js +++ b/scripts/sync.js @@ -1,5 +1,6 @@ const mongoose = require('mongoose'), db = require('../lib/database'), + lib = require('../lib/explorer'), Block = require('../models/block'), Address = require('../models/address'), Richlist = require('../models/richlist'), @@ -127,11 +128,7 @@ async function main() { }) debug('Script launched with pid: ' + process.pid) - await promisify(mongoose.connect, settings.dbsettings.uri, settings.dbsettings.options).catch(err => { - console.log(err) - console.log(`Unable to connect to database: ${settings.dbsettings.uri}.`) - console.log(`With options: ${prettyPrint(settings.dbsettings.options, null, 2)}`) - console.log('Aborting') + await db.connect(settings.dbsettings).catch(err => { return exit(database) }) @@ -142,7 +139,7 @@ async function main() { } await db.updateStats(settings.coin) - const [ err, stats ] = await promisify(Stats.findOne.bind(Stats), { coin: settings.coin }) + const stats = await promisify(db.get_stats, settings.coin) if (mode === 'reindex') { await promisify(Block.remove.bind(Block), {}) @@ -152,7 +149,7 @@ async function main() { debug('[reindex]: index cleared') } - await db.updateDb(stats, 0, stats.blocks, settings.update_timeout) + await db.updateDb(0, stats.blocks, settings.update_timeout) if (mode === 'check') { debug(`[check]: complete`) diff --git a/views/info.jade b/views/info.jade index 6a2718d1f..7dcfd0283 100644 --- a/views/info.jade +++ b/views/info.jade @@ -70,7 +70,7 @@ block content * **getblocks (/ext/getblocks/start/end?flds=[fields]&reverse=[true|false])** *Returns a list of blocks found from [start] to [end] block height (inclusive, indexed from 1). \[reverse\] can be set to read from the most recent blocks first (e.g. /ext/getblocks/1/10?reverse=true will return the 10 most recent blocks). A list of all blocks found within the specified height range will be returned.* - *[flds] is a list of fields to return, if set to "summary" it will only return block info, ["tx"] is commonly used to only return transactions in the block.* + *[flds] is a list of fields to return, if set to "summary" it will only return block info, "fulltx" is commonly used to only return the fully decoded transactions in the block.* [#{address}/ext/getblocks/0/10](/ext/getblocks/1/10) ------ From 9f2ba071ea9c27c413eb9546ec8c91cab0c4c841 Mon Sep 17 00:00:00 2001 From: Conrad Date: Fri, 21 Dec 2018 12:49:32 -0500 Subject: [PATCH 09/11] everything should be working now --- app.js | 66 +--- lib/api.js | 58 ++-- lib/database.js | 10 +- lib/explorer.js | 17 - log.txt | 820 +++++++++++++++++++++++++++++++++++++++++++++++ scripts/sync.js | 4 +- views/index.jade | 2 +- 7 files changed, 870 insertions(+), 107 deletions(-) create mode 100644 log.txt diff --git a/app.js b/app.js index db3eaea17..1ce12475f 100644 --- a/app.js +++ b/app.js @@ -16,7 +16,6 @@ const express = require('express'), const app = express() info(app) -api.setCredentials(settings.wallet) api.setCachers(db.rpc) // view engine setup @@ -81,7 +80,7 @@ app.use('/ext/getblocks/:start/:end', async function (req, res) { const start = parseInt(req.param('start')) const end = parseInt(req.param('end')) const reverse = req.query.reverse && req.query.reverse.toLowerCase() === 'true' - const flds = typeof req.query.flds === 'string' ? req.query.flds.split(',') : req.query.flds + const flds = typeof req.query.flds === 'string' ? req.query.flds.split(',') : req.query.flds || [] if (start > end) { res.send({ error: `End blockheight must be greater than or equal to the start blockheight.` }) @@ -92,60 +91,19 @@ app.use('/ext/getblocks/:start/:end', async function (req, res) { let heights = Array(end - start + 1).fill(undefined).map((_, i) => start + i) if (reverse) heights = heights.map(h => blockcount - h + 1) - const searchFlds = flds && flds[0] === 'summary' + const searchFlds = flds[0] === 'summary' ? { fulltx: 0, _id: 0 } - : flds ? flds.reduce((acc, fld) => ({ ...acc, [fld]: 1 }), { _id: 0 }) : [] - const blocks = await db.getBlocks(heights, searchFlds) - res.send({ data: { blockcount, blocks } }) - - /* - const txReq = () => Promise.all(heights.map(i => - db.getTxs({ height: i }).then(txs => { - // sorts transactions from newest to oldest - txs.sort((a, b) => { - if (a.blockindex !== b.blockindex) return a.blockindex > b.blockindex ? -1 : 1 - if (a.timestamp !== b.timestamp) return a.timestamp > b.timestamp ? -1 : 1 - return a._id > b._id ? -1 : 1 - }) - // since reverse means to go from newest to oldest - return reverse ? txs : txs.reverse() - }) - )) - const infoReq = (blockcount) => Promise.all(heights.map(i => - promisify(lib.get_blockhash, i) - .then(hash => - hash.name === 'RpcError' ? null : lib.getBlock(hash, undefined, blockcount) - ) - )).then(infos => strip ? infos.filter(info => info !== null) : infos) - const onErr = err => { - debug(err) - res.send({ error: `An error occurred: ${err}` }) + : flds ? flds.reduce((acc, fld) => ({ ...acc, [fld]: 1 }), { _id: 0, height: 1 }) : [] + let blocks = await db.getBlocks(heights, searchFlds) + if (!blocks) { + blocks = await Promise.all(heights.map(h => lib.getRawRpc('getblockhash', [ h ]).then(hash => lib.getRawRpc('getblock', [ hash ])))) + } else { + blocks = blocks.sort((a, b) => (reverse ? -1 : 1) * (a.height <= b.height ? -1 : 1)) } - - promisify(request, `${endpoint}/api/getblockcount`, { json: true }).then(([ err, resp, height ]) => { - if (reverse) heights = heights.map(h => height - h + 1) - return height - }).then(blockcount => { - if (req.query.flds == 'summary') { - infoReq(blockcount).then(infos => res.send({ data: { blockcount, blocks: infos } })).catch(onErr) - } else if (req.query.flds == 'tx') { - txReq().then(txs => res.send({ data: { blockcount, blocks: txs } })).catch(onErr) - } else { - Promise.all([ txReq(), infoReq(blockcount) ]).then(([ txs, infos ]) => { - res.send({ - data: { blockcount, blocks: infos.map((info, i) => ({ ...info, tx: txs[i] })).map(block => { - if (req.query.flds && req.query.flds.length) { - Object.keys(block).forEach(key => { - if (!req.query.flds.includes(key)) delete block[key] - }) - } - return block - }) } - }) - }).catch(onErr) - } - }).catch(onErr) - */ + blocks.forEach(block => { + if (!flds.includes('height') && flds[0] !== 'summary') delete block['height'] + }) + res.send({ data: { blockcount, blocks } }) }) app.use('/ext/connections', function(req,res){ diff --git a/lib/api.js b/lib/api.js index 7d232a953..20bc5cd42 100644 --- a/lib/api.js +++ b/lib/api.js @@ -1,6 +1,7 @@ const express = require('express') const debug = require('debug')('explorer:api') const Client = require('bitcoin-core') +const settings = require('./settings') const SpecTypes = Object.freeze({ 'ALL': 0, 'ONLY': 1, 'EXCEPT': 2 }) const CacheTypes = Object.freeze({ 'FORCE': 0, 'NEVER': 1, 'AS_NEEDED': 2 }) @@ -15,13 +16,12 @@ class Api { rpc: [] }, cachers, - wallet + wallet = {} }) { this.app = express() this.rpcConfig = rpcConfig - this.walletDetails = wallet - this.client = new Client(wallet) this.cachers = cachers + this.setWalletDetails(wallet) this.app.get('*', this.hasAccess.bind(this), (req, res) => { const method = req.path.substr(1) @@ -89,8 +89,9 @@ class Api { } } - setCredentials (creds) { - this.client = new Client({ ...this.walletDetails, creds }) + setWalletDetails (details) { + this.walletDetails = details + this.client = new Client(details) } setCachers (cachers) { @@ -112,30 +113,33 @@ class Api { } -const api = new Api({ - rpcConfig: { - type: SpecTypes.ONLY, - cacheDefault: CacheTypes.FORCE, - allowRaw: true, - rpc: [ - 'getnetworkhashps', - 'getmininginfo', - 'getdifficulty', - 'getconnectioncount', - 'getblockcount', - 'getblockhash', - 'getblock', - 'getrawtransaction', - 'getpeerinfo', - 'gettxoutsetinfo', - 'getmempoolinfo', - 'getrawmempool' - ] - } -}) +function api () { + return new Api({ + rpcConfig: { + type: SpecTypes.ONLY, + cacheDefault: CacheTypes.FORCE, + allowRaw: true, + rpc: [ + 'getnetworkhashps', + 'getmininginfo', + 'getdifficulty', + 'getconnectioncount', + 'getblockcount', + 'getblockhash', + 'getblock', + 'getrawtransaction', + 'getpeerinfo', + 'gettxoutsetinfo', + 'getmempoolinfo', + 'getrawmempool' + ] + }, + wallet: settings.wallet + }) +} module.exports = { - api, + api: api(), SpecTypes, CacheTypes } diff --git a/lib/database.js b/lib/database.js index e6b49b252..4cc18ad63 100644 --- a/lib/database.js +++ b/lib/database.js @@ -122,7 +122,7 @@ function update_address(hash, txid, amount, type, cb) { } async function findTx (txid) { - const [ err, block ] = await promisify(Block.findOne.bind(Block), { tx: { $elemMatch: txid } }) + const [ err, block ] = await promisify(Block.findOne.bind(Block), { tx: txid }) if (err) throw new Error(err) else return parseTx(block, txid) } @@ -387,13 +387,13 @@ module.exports = { }, async get_tx (txid, cb) { - const tx = findTx(txid) + const tx = await findTx(txid) return cb ? cb(await tx) : tx }, async getTxs (block) { return promisify(Block.findOne.bind(Block), block).then(([ err, block ]) => - err || !block ? null : block.tx.map(tx => parseTx(block, tx)) + err || !block ? null : Promise.all(block.tx.map(tx => parseTx(block, tx))) ) }, @@ -581,7 +581,7 @@ module.exports = { Block[params.length > 1 ? 'find' : 'findOne'].bind(Block), { [mode]: { $in: params } }, flds || { } - ).then(([ err, blocks ]) => err + ).then(([ err, blocks ]) => err || !blocks._doc ? null : blocks.length ? blocks.map(block => dbToRpcBlock(block._doc, blockheight, flds.fulltx === 0 ? null : Object.keys(flds))) @@ -611,7 +611,7 @@ module.exports = { txouts: txoutinfo.txouts, bogosize: txoutinfo.bogosize, hash_serialized_2: txoutinfo.hash_serialized_2, - disk_size: txoutinfo.disk_size, + disk_size: txoutinfo.disk_size }) }, diff --git a/lib/explorer.js b/lib/explorer.js index 0970a5459..f1186cf28 100644 --- a/lib/explorer.js +++ b/lib/explorer.js @@ -8,25 +8,8 @@ const request = require('request'), const base_url = 'http://127.0.0.1:' + settings.port + '/api/' -// there are two ways of calculating coinbase supply -// we can use the coinbase address that accumulates a record of all coinbase transactions -// or we can add up all coinbase transactions in the database. -// TODO: Add test to check that both results are equal - -function verifyCoinbaseSupply () { - return promisify(Address.findOne.bind(Address), { a_id: 'coinbase' }).then(([ err, addr ]) => - addr ? addr.balance > 0 ? addr.balance : addr.sent : undefined - ) -} - function coinbase_supply () { return requestp(base_url + 'gettxoutsetinfo').then(info => info.total_amount) - // return promisify( - // Tx.find.bind(Tx), - // { 'vin': { $elemMatch: { 'addresses': 'coinbase', 'amount': { $gt: 0 } } } } - // ).then(([ err, txes ]) => - // txes.reduce((sum, tx) => sum + tx.vin.find(vin => vin.addresses === 'coinbase').amount, 0) - // ) } module.exports = { diff --git a/log.txt b/log.txt new file mode 100644 index 000000000..e9e95e91c --- /dev/null +++ b/log.txt @@ -0,0 +1,820 @@ + +> explorer@1.6.2-equibit start /home/eternali/equibit/explorer +> node --stack-size=10000 ./bin/cluster + +- settings: host=169.53.165.114, port=18331 + + +Run again + + +Fri, 21 Dec 2018 16:26:59 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:26:59 GMT express:router:layer new +Fri, 21 Dec 2018 16:26:59 GMT express:router use / query +Fri, 21 Dec 2018 16:26:59 GMT express:router:layer new +Fri, 21 Dec 2018 16:26:59 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:26:59 GMT express:router:route new * +Fri, 21 Dec 2018 16:26:59 GMT express:router:layer new * +Fri, 21 Dec 2018 16:26:59 GMT express:router:route get * +Fri, 21 Dec 2018 16:26:59 GMT express:router:route get * +- settings: host=169.53.165.114, port=18331 +- settings: host=169.53.165.114, port=18331 +- settings: host=169.53.165.114, port=18331 +- settings: host=169.53.165.114, port=18331 +- settings: host=169.53.165.114, port=18331 +- settings: host=169.53.165.114, port=18331 +- settings: host=169.53.165.114, port=18331 +- settings: host=169.53.165.114, port=18331 +- settings: host=169.53.165.114, port=18331 + + + +Run again + + + +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode + +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new + +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query + +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new + +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit + +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new * + +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new * + +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * + +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * + + + +Run again + + +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +ERROR: Fri, 21 Dec 2018 16:27:00 GMT explorer:sync args:: [ 'index', 'update' ] + + + +Run again + + +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +ERROR: Fri, 21 Dec 2018 16:27:00 GMT explorer:sync - database=index, mode=update + +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * + + +Run again + + +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route post /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /version +Fri, 21 Dec 2018 16:27:00 GMT express:router use /version anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / favicon +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / logger +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / jsonParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / urlencodedParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / cookieParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get / +Fri, 21 Dec 2018 16:27:00 GMT express:router use / staticMiddleware +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /info +Fri, 21 Dec 2018 16:27:00 GMT express:application .use app under /api +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /api +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /info +Fri, 21 Dec 2018 16:27:00 GMT express:router use /api fn +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / router +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getmoneysupply +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getmoneysupply anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getaddress/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getaddress/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getbalance/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getbalance/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getdistribution +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getdistribution anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getblocks/:start/:end +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getblocks/:start/:end anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/connections +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/connections anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route post /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /version +Fri, 21 Dec 2018 16:27:00 GMT express:router use /version anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / favicon +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / logger +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / jsonParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / urlencodedParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / cookieParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / staticMiddleware +Fri, 21 Dec 2018 16:27:00 GMT express:application .use app under /api +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /api +Fri, 21 Dec 2018 16:27:00 GMT express:router use /api fn +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / router +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getmoneysupply +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getmoneysupply anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getaddress/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getaddress/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getbalance/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getbalance/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getdistribution +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getdistribution anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getblocks/:start/:end +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getblocks/:start/:end anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/connections +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/connections anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous + + +Run again + + +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route post /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /ext/summary +ERROR: Fri, 21 Dec 2018 16:27:00 GMT explorer:sync Script already running. + +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /version +Fri, 21 Dec 2018 16:27:00 GMT express:router use /version anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / favicon +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / logger +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / jsonParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / urlencodedParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router use / cookieParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router use / staticMiddleware +Fri, 21 Dec 2018 16:27:00 GMT express:application .use app under /api +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /api +Fri, 21 Dec 2018 16:27:00 GMT express:router use /api fn +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / router +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getmoneysupply +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getmoneysupply anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getaddress/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getaddress/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getbalance/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getbalance/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getdistribution +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getdistribution anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getblocks/:start/:end +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getblocks/:start/:end anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/connections +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/connections anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Process exited with code 0 + + +Run again + + +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route post /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /version +Fri, 21 Dec 2018 16:27:00 GMT express:router use /version anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / favicon +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / logger +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / jsonParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / urlencodedParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / cookieParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / staticMiddleware +Fri, 21 Dec 2018 16:27:00 GMT express:application .use app under /api +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /api +Fri, 21 Dec 2018 16:27:00 GMT express:router use /api fn +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / router +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getmoneysupply +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getmoneysupply anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getaddress/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getaddress/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getbalance/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getbalance/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getdistribution +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getdistribution anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getblocks/:start/:end +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getblocks/:start/:end anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/connections +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/connections anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route post /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /version +Fri, 21 Dec 2018 16:27:00 GMT express:router use /version anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / favicon +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / logger +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / jsonParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new + + +Run again + + +Fri, 21 Dec 2018 16:27:00 GMT express:router use / urlencodedParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / cookieParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / staticMiddleware +Fri, 21 Dec 2018 16:27:00 GMT express:application .use app under /api +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /api +Fri, 21 Dec 2018 16:27:00 GMT express:router use /api fn +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / router +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getmoneysupply +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getmoneysupply anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getaddress/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getaddress/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getbalance/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getbalance/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getdistribution +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getdistribution anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getblocks/:start/:end +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getblocks/:start/:end anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/connections +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/connections anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route post /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /version +Fri, 21 Dec 2018 16:27:00 GMT express:router use /version anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / favicon +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / logger +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / jsonParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / urlencodedParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / cookieParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / staticMiddleware +Fri, 21 Dec 2018 16:27:00 GMT express:application .use app under /api +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /api +Fri, 21 Dec 2018 16:27:00 GMT express:router use /api fn +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / router +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getmoneysupply +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getmoneysupply anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getaddress/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getaddress/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getbalance/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getbalance/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getdistribution +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getdistribution anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getblocks/:start/:end +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getblocks/:start/:end anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/connections +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/connections anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous + + +Run again + + +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route post /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /version +Fri, 21 Dec 2018 16:27:00 GMT express:router use /version anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / favicon +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / logger +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / jsonParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / urlencodedParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / cookieParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / staticMiddleware +Fri, 21 Dec 2018 16:27:00 GMT express:application .use app under /api +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /api +Fri, 21 Dec 2018 16:27:00 GMT express:router use /api fn +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / router +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getmoneysupply +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getmoneysupply anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getaddress/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getaddress/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getbalance/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getbalance/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getdistribution +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getdistribution anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getblocks/:start/:end +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getblocks/:start/:end anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/connections +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/connections anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous + + +Run again + + +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get * +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get / +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /info +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /markets/:market +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /richlist +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /movement +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /network +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /tx/:txid +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /block/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /address/:hash/:count +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route post /search +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /qr/:string +Fri, 21 Dec 2018 16:27:00 GMT express:router:route new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:router:route get /ext/summary +Fri, 21 Dec 2018 16:27:00 GMT express:application booting in development mode +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / query +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / expressInit +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /version +Fri, 21 Dec 2018 16:27:00 GMT express:router use /version anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / favicon +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / logger +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / jsonParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / urlencodedParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / cookieParser +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / staticMiddleware +Fri, 21 Dec 2018 16:27:00 GMT express:application .use app under /api +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /api +Fri, 21 Dec 2018 16:27:00 GMT express:router use /api fn +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / router +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getmoneysupply +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getmoneysupply anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getaddress/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getaddress/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getbalance/:hash +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getbalance/:hash anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getdistribution +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getdistribution anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/getblocks/:start/:end +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/getblocks/:start/:end anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new /ext/connections +Fri, 21 Dec 2018 16:27:00 GMT express:router use /ext/connections anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous +Fri, 21 Dec 2018 16:27:00 GMT express:router:layer new +Fri, 21 Dec 2018 16:27:00 GMT express:router use / anonymous diff --git a/scripts/sync.js b/scripts/sync.js index e1a02e447..75f952ed9 100644 --- a/scripts/sync.js +++ b/scripts/sync.js @@ -1,12 +1,10 @@ const mongoose = require('mongoose'), db = require('../lib/database'), - lib = require('../lib/explorer'), Block = require('../models/block'), Address = require('../models/address'), Richlist = require('../models/richlist'), - Stats = require('../models/stats'), settings = require('../lib/settings'), - { promisify, prettyPrint, wait } = require('../lib/util'), + { promisify } = require('../lib/util'), fs = require('fs'), debug = require('debug')('explorer:sync') diff --git a/views/index.jade b/views/index.jade index e0723a1b8..545a66240 100644 --- a/views/index.jade +++ b/views/index.jade @@ -16,7 +16,7 @@ block content serverSide: true, ajax: function (data, cb, settings) { $.ajax({ - url: `/ext/getblocks/${data.start}/${data.start + data.length}?flds=summary&reverse=true&strip=true` + url: `/ext/getblocks/${data.start + 1}/${data.start + data.length}?flds=summary&reverse=true&strip=true` }).done((res) => { cb({ draw: data.draw, From aa7af7bf5a9478181fb745b61b8d1694e2cc7a65 Mon Sep 17 00:00:00 2001 From: Conrad Date: Mon, 21 Jan 2019 13:19:11 -0500 Subject: [PATCH 10/11] checkpoint --- config/default.json | 2 +- lib/api.js | 10 ++++------ lib/database.js | 1 + models/address.js | 6 +++--- models/block.js | 4 ++-- views/block.jade | 6 +++--- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/config/default.json b/config/default.json index 9c7202904..42387b321 100644 --- a/config/default.json +++ b/config/default.json @@ -1,7 +1,7 @@ { "dbsettings": { "uri": "mongodb://localhost:27017/blockchain-explorer", - "options": { "useNewUrlParser": true }, + "options": { "useNewUrlParser": true, "autoIndex": false }, "benchmark_uri": "mongodb://localhost:27017/explorer-benchmark", "benchmark_options": { "useNewUrlParser": true } }, diff --git a/lib/api.js b/lib/api.js index 20bc5cd42..e2a0641a4 100644 --- a/lib/api.js +++ b/lib/api.js @@ -36,12 +36,10 @@ class Api { ? this.cachers[method](...parameters).then(this.handle).then(resp => res.send(resp)) : res.send(`No caching method was supplied for ${method}.`) case CacheTypes.NEVER: - return this.client.command([ { method, parameters } ]).then(([ resp, err ]) => { - res.send(this.handle(resp, err)) - }) + return res.send(this.rawRpc(method, parameters)) case CacheTypes.AS_NEEDED: if (!this.cachers.hasOwnProperty(method)) return res.send(this.rawRpc(method, parameters)) - return db.rpc[method](...parameters).then(this.handle).then(resp => resp.includes('There was an error') + return this.cachers[method](...parameters).then(this.handle).then(resp => resp === 'There was an error.' ? this.rawRpc(method, parameters) : resp ).then(resp => res.send(resp)) @@ -69,7 +67,7 @@ class Api { handle (data, err) { if (err) { console.log(err) - return 'There was an error, check your console.' + return 'There was an error.' } // if its an object just send it as is, otherwise cast to string return (data instanceof Object) ? data : (''+data) @@ -117,7 +115,7 @@ function api () { return new Api({ rpcConfig: { type: SpecTypes.ONLY, - cacheDefault: CacheTypes.FORCE, + cacheDefault: CacheTypes.NEVER, allowRaw: true, rpc: [ 'getnetworkhashps', diff --git a/lib/database.js b/lib/database.js index 4cc18ad63..7d98982c3 100644 --- a/lib/database.js +++ b/lib/database.js @@ -632,6 +632,7 @@ module.exports = { debug(`Caching #${i}: ${block.hash}`) block.fulltx = await Promise.all(block.tx.map(txid => lib.getRawRpc('getrawtransaction', [ txid, 1 ]))) .then(txs => txs.map((tx, t) => ({ txid: block.tx[t], ...tx })).filter(tx => !tx.code && !tx.name)) + console.log(`${block.height}: ${block.hash}`) await Block.create([ block ]) if (timeout) await wait(timeout) } diff --git a/models/address.js b/models/address.js index 348fc8b5b..779b7883a 100644 --- a/models/address.js +++ b/models/address.js @@ -2,12 +2,12 @@ var mongoose = require('mongoose') , Schema = mongoose.Schema; var AddressSchema = new Schema({ - a_id: { type: String, unique: true, index: true}, + a_id: { type: String, unique: true, index: false }, txs: { type: Array, default: [] }, received: { type: Number, default: 0 }, sent: { type: Number, default: 0 }, - balance: {type: Number, default: 0}, -}, {id: false}); + balance: {type: Number, default: 0 }, +}, { id: false }); module.exports = mongoose.model('Address', AddressSchema); diff --git a/models/block.js b/models/block.js index aa222c985..ca2307c66 100644 --- a/models/block.js +++ b/models/block.js @@ -15,7 +15,7 @@ const TxSchema = new mongoose.Schema({ }) const BlockSchema = new mongoose.Schema({ - hash: { type: String, lowercase: true, unique: true, index: true }, + hash: { type: String, lowercase: true, unique: true }, size: { type: Number }, weight: { type: Number }, height: { type: Number }, @@ -31,6 +31,6 @@ const BlockSchema = new mongoose.Schema({ chainwork: { type: String, lowercase: true }, previousblockhash: { type: String, lowercase: true }, nextblockhash: { type: String, lowercase: true }, -}, { id: false }) +}) module.exports = mongoose.model('Block', BlockSchema) diff --git a/views/block.jade b/views/block.jade index c9b0197fc..6251eac5b 100644 --- a/views/block.jade +++ b/views/block.jade @@ -34,7 +34,7 @@ block content tr.success - var block_size = block.size/1024 td #{block.height} - td #{block.difficulty.toFixed(4)} + td #{parseFloat(block.difficulty).toFixed(4)} td #{block.confirmations} td.hidden-xs #{block_size.toFixed(2)} td.hidden-xs #{block.bits} @@ -45,7 +45,7 @@ block content tr.danger - var block_size = block.size/1024 td #{block.height} - td #{block.difficulty.toFixed(4)} + td #{parseFloat(block.difficulty).toFixed(4)} td #{block.confirmations} td.hidden-xs #{block_size.toFixed(2)} td.hidden-xs #{block.bits} @@ -55,7 +55,7 @@ block content tr.warning - var block_size = block.size/1024 td #{block.height} - td #{block.difficulty.toFixed(4)} + td #{parseFloat(block.difficulty).toFixed(4)} td #{block.confirmations} td.hidden-xs #{block_size.toFixed(2)} td.hidden-xs #{block.bits} From 5ba00469f92e458232dae62630662b7f92b5aacf Mon Sep 17 00:00:00 2001 From: Conrad Date: Wed, 23 Jan 2019 00:30:39 -0500 Subject: [PATCH 11/11] working on indexing issue --- lib/api.js | 15 +++++++++------ lib/database.js | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/api.js b/lib/api.js index e2a0641a4..fc8190390 100644 --- a/lib/api.js +++ b/lib/api.js @@ -64,13 +64,16 @@ class Api { return this.rpcConfig.cacheDefault } - handle (data, err) { - if (err) { - console.log(err) - return 'There was an error.' + handle (success, fail) { + + return (data) => { + if (data instanceof Error) { + console.log(err) + return 'There was an error.' + } + // if its an object just send it as is, otherwise cast to string + return (data instanceof Object) ? data : (''+data) } - // if its an object just send it as is, otherwise cast to string - return (data instanceof Object) ? data : (''+data) } hasAccess (req, res, next) { diff --git a/lib/database.js b/lib/database.js index 7d98982c3..e46064b93 100644 --- a/lib/database.js +++ b/lib/database.js @@ -206,7 +206,7 @@ function dbToRpcBlock (block, blockcount, include) { const rpcOnError = (method, err) => { debug(`An error occurred while trying access cache of ${method}: ${err}`) - return null + return new Error(`Caching ${method} resulted in: ${err}`) } const rpc = {