diff --git a/.gitignore b/.gitignore index 7eb7357..bddd8a6 100644 --- a/.gitignore +++ b/.gitignore @@ -29,9 +29,13 @@ npm-debug.log .DS_Store public/lib/* db/txs/* +db/txs db/testnet/txs/* +db/testnet/txs db/blocks/* +db/blocks db/testnet/blocks/* +db/testnet/blocks public/js/* public/css/* diff --git a/app/controllers/blocks.js b/app/controllers/blocks.js index 09e90fe..0b471ce 100644 --- a/app/controllers/blocks.js +++ b/app/controllers/blocks.js @@ -3,9 +3,9 @@ /** * Module dependencies. */ -var common = require('./common'), - async = require('async'), - BlockDb = require('../../lib/BlockDb').class(); +var common = require('./common'), + async = require('async'), + BlockDb = require('../../lib/BlockDb').class(); var bdb = new BlockDb(); @@ -14,7 +14,7 @@ var bdb = new BlockDb(); */ exports.block = function(req, res, next, hash) { bdb.fromHashWithInfo(hash, function(err, block) { - if (err || ! block) + if (err || !block) return common.handleErrors(err, res, next); else { req.block = block.info; @@ -41,8 +41,7 @@ exports.blockindex = function(req, res, next, height) { if (err) { console.log(err); res.status(400).send('Bad Request'); // TODO - } - else { + } else { res.jsonp(hashStr); } }); @@ -57,7 +56,7 @@ var getBlock = function(blockhash, cb) { // TODO if (!block.info) { -console.log('[blocks.js.60]: could not get %s from RPC. Orphan? Error?', blockhash); //TODO + console.log('[blocks.js.60]: could not get %s from RPC. Orphan? Error?', blockhash); //TODO // Probably orphan block.info = { hash: blockhash, @@ -75,10 +74,10 @@ exports.list = function(req, res) { var isToday = false; //helper to convert timestamps to yyyy-mm-dd format - var formatTimestamp = function (date) { + var formatTimestamp = function(date) { var yyyy = date.getUTCFullYear().toString(); var mm = (date.getUTCMonth() + 1).toString(); // getMonth() is zero-based - var dd = date.getUTCDate().toString(); + var dd = date.getUTCDate().toString(); return yyyy + '-' + (mm[1] ? mm : '0' + mm[0]) + '-' + (dd[1] ? dd : '0' + dd[0]); //padding }; @@ -107,10 +106,10 @@ exports.list = function(req, res) { res.status(500).send(err); } else { - var limit = parseInt(req.query.limit || blocks.length); - if (blocks.length < limit) { - limit = blocks.length; - } + var l = blocks.length; + var limit = parseInt(req.query.limit || l); + if (l < limit) limit = l; + async.mapSeries(blocks, function(b, cb) { getBlock(b.hash, function(err, info) { @@ -123,18 +122,18 @@ exports.list = function(req, res) { }); }); }, function(err, allblocks) { - res.jsonp({ - blocks: allblocks, - length: allblocks.length, - pagination: { - next: next, - prev: prev, - currentTs: lte-1, - current: dateStr, - isToday: isToday - } + res.jsonp({ + blocks: allblocks, + length: allblocks.length, + pagination: { + next: next, + prev: prev, + currentTs: lte - 1, + current: dateStr, + isToday: isToday + } + }); }); - }); } }); }; diff --git a/app/controllers/socket.js b/app/controllers/socket.js index ebdce59..5175ab5 100644 --- a/app/controllers/socket.js +++ b/app/controllers/socket.js @@ -3,6 +3,7 @@ // server-side socket behaviour // io is a variable already taken in express var ios = null; +var util = require('bitcore/util/util'); module.exports.init = function(app, io_ext) { ios = io_ext; @@ -25,10 +26,10 @@ module.exports.broadcastTx = function(tx) { // Outputs var valueOut = 0; t.vout.forEach( function(o) { - valueOut += o.value * 100000000; + valueOut += o.value * util.COIN; }); - t.valueOut = valueOut / 100000000; + t.valueOut = parseInt(valueOut) / util.COIN; } ios.sockets.in('inv').emit('tx', t); } diff --git a/app/controllers/status.js b/app/controllers/status.js index edc5051..5a509b5 100644 --- a/app/controllers/status.js +++ b/app/controllers/status.js @@ -50,3 +50,8 @@ exports.sync = function(req, res) { if (req.historicSync) res.jsonp(req.historicSync.info()); }; + +exports.peer = function(req, res) { + if (req.peerSync) + res.jsonp(req.peerSync.info()); +}; diff --git a/config/express.js b/config/express.js index 4b96d0f..ae0eae9 100644 --- a/config/express.js +++ b/config/express.js @@ -7,13 +7,17 @@ var express = require('express'), helpers = require('view-helpers'), config = require('./config'); -module.exports = function(app, historicSync) { +module.exports = function(app, historicSync, peerSync) { //custom middleware function setHistoric(req, res, next) { req.historicSync = historicSync; next(); } + function setPeer(req, res, next) { + req.peerSync = peerSync; + next(); + } app.set('showStackError', true); @@ -28,6 +32,7 @@ module.exports = function(app, historicSync) { app.enable('jsonp callback'); app.use('/api/sync', setHistoric); + app.use('/api/peer', setPeer); app.use(express.logger('dev')); app.use(express.json()); app.use(express.urlencoded()); diff --git a/config/routes.js b/config/routes.js index 317e19d..44a3591 100644 --- a/config/routes.js +++ b/config/routes.js @@ -29,6 +29,7 @@ module.exports = function(app) { app.get('/api/status', st.show); app.get('/api/sync', st.sync); + app.get('/api/peer', st.peer); // Currency var currency = require('../app/controllers/currency'); diff --git a/dev-util/get_block.js b/dev-util/get_block.js index 23c5f45..fe3e416 100755 --- a/dev-util/get_block.js +++ b/dev-util/get_block.js @@ -17,7 +17,7 @@ hash = 'e2253359458db3e732c82a43fc62f56979ff59928f25a2df34dfa443e9a41160'; var rpc = new RpcClient(config.bitcoind); -rpc.getRawTransaction( hash, 1, function(err, ret) { +rpc.getBlockCount( function(err, ret) { console.log('Err:'); console.log(err); diff --git a/insight.js b/insight.js index fc0969f..92dbdd7 100644 --- a/insight.js +++ b/insight.js @@ -43,8 +43,11 @@ walk(models_path); /** * p2pSync process */ + +var peerSync = new PeerSync(); + if (!config.disableP2pSync) { - var ps = new PeerSync(); + var ps = peerSync; ps.init({ shouldBroadcast: true, }, function() { @@ -83,7 +86,7 @@ if (!config.disableHistoricSync) { //express settings -require('./config/express')(expressApp, historicSync); +require('./config/express')(expressApp, historicSync, peerSync); //Bootstrap routes require('./config/routes')(expressApp); diff --git a/lib/HistoricSync.js b/lib/HistoricSync.js index 180eb10..753e2de 100644 --- a/lib/HistoricSync.js +++ b/lib/HistoricSync.js @@ -33,7 +33,6 @@ function spec() { this.syncPercentage = 0; this.syncedBlocks = 0; - this.skippedBlocks = 0; this.orphanBlocks = 0; this.type =''; } @@ -88,11 +87,11 @@ function spec() { HistoricSync.prototype.info = function() { + this.updatePercentage(); return { status: this.status, blockChainHeight: this.blockChainHeight, syncPercentage: this.syncPercentage, - skippedBlocks: this.skippedBlocks, syncedBlocks: this.syncedBlocks, orphanBlocks: this.orphanBlocks, syncTipHash: this.sync.tip, @@ -101,20 +100,24 @@ function spec() { }; }; + HistoricSync.prototype.updatePercentage = function() { + var r = this.syncedBlocks / this.blockChainHeight; + this.syncPercentage = parseFloat(100 * r).toFixed(3); + if (this.syncPercentage > 100) this.syncPercentage = 100; + }; + HistoricSync.prototype.showProgress = function() { var self = this; if ( self.status ==='syncing' && - ( self.syncedBlocks + self.skippedBlocks) % self.step !== 1) return; + ( self.syncedBlocks ) % self.step !== 1) return; if (self.error) { p('ERROR: ' + self.error); } else { - self.syncPercentage = parseFloat(100 * self.syncedBlocks / self.blockChainHeight).toFixed(3); - if (self.syncPercentage > 100) self.syncPercentage = 100; - - p(util.format('status: [%d%%] skipped: %d ', self.syncPercentage, self.skippedBlocks)); + self.updatePercentage(); + p(util.format('status: [%d%%]', self.syncPercentage)); } if (self.opts.shouldBroadcastSync) { sockets.broadcastSyncInfo(self.info()); @@ -189,21 +192,21 @@ function spec() { self.status = 'syncing'; } - if ( (scanOpts.upToExisting && existed && - self.syncedBlocks >= self.blockChainHeight) || - (blockEnd && blockEnd === blockHash)) { + if ( blockEnd && blockEnd === blockHash) { + p('blockEnd found!:' + blockEnd); + self.found=1; + } + + if ( self.found && self.syncedBlocks >= self.blockChainHeight ) { self.status = 'finished'; - p('DONE. Found block: ', blockHash); + p('DONE. Height: ' , self.syncedBlocks); return cb(err); } // Continue if (blockInfo) { - if (existed) - self.skippedBlocks++; - else - self.syncedBlocks++; + self.syncedBlocks++; // recursion if (scanOpts.prev && blockInfo.previousblockhash) @@ -337,7 +340,6 @@ function spec() { self.rpc.getBlockHash(self.blockChainHeight, function(err, res) { if (err) return cb(err); lastBlock = res.result; - return cb(); }); }, @@ -353,8 +355,7 @@ function spec() { }, function(cb) { - if (scanOpts.upToExisting) { - // should be isOrphan = true or null to be more accurate. + if (scanOpts.reverse) { self.countNotOrphan(function(err, count) { if (err) return cb(err); @@ -389,7 +390,7 @@ function spec() { if (scanOpts.reverse) { start = lastBlock; - end = tip || self.genesis; + end = tip || self.genesis; scanOpts.prev = true; } else { @@ -460,10 +461,9 @@ function spec() { } } else { - p('Genesis block found. Syncing upto known blocks.'); + p('Genesis block found. Syncing upto old TIP.'); p('Got ' + count + ' out of ' + self.blockChainHeight + ' blocks'); scanOpts.reverse = true; - scanOpts.upToExisting = true; } return self.importHistory(scanOpts, next); }); diff --git a/lib/PeerSync.js b/lib/PeerSync.js index 090b4de..ce1bf1a 100644 --- a/lib/PeerSync.js +++ b/lib/PeerSync.js @@ -12,12 +12,12 @@ function spec() { var networks = require('bitcore/networks'); var peerdb_fn = 'peerdb.json'; - function PeerSync() {} PeerSync.prototype.init = function(opts, cb) { if (!opts) opts = {}; + this.connected = false; this.peerdb = undefined; this.allowReorgs = false; @@ -42,6 +42,12 @@ function spec() { fs.writeFileSync(peerdb_fn, JSON.stringify(this.peerdb)); }; + PeerSync.prototype.info = function() { + return { + connected: this.connected + }; + }; + PeerSync.prototype.handleInv = function(info) { var invs = info.message.invs; invs.forEach(function(inv) { @@ -114,12 +120,17 @@ function spec() { }); this.peerman.on('connection', function(conn) { + self.connected = true; conn.on('inv', self.handleInv.bind(self)); conn.on('block', self.handleBlock.bind(self)); conn.on('tx', self.handleTx.bind(self)); }); this.peerman.on('connect', self.handle_connected.bind(self)); + this.peerman.on('netDisconnected', function() { + self.connected = false; + }); + this.peerman.start(); }; diff --git a/package.json b/package.json index 748d0b4..93e9038 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { - "name": "insight", + "name": "insight-bitcore", "version": "0.0.1", - "private": true, "author": { "name": "Ryan X Charles", "email": "ryan@bitpay.com" diff --git a/public/img/loading.gif b/public/img/loading.gif new file mode 100644 index 0000000..48ee52a Binary files /dev/null and b/public/img/loading.gif differ diff --git a/public/src/css/common.css b/public/src/css/common.css index c8e24c1..dddd70c 100644 --- a/public/src/css/common.css +++ b/public/src/css/common.css @@ -138,6 +138,13 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { font-family: 'Ubuntu', sans-serif; } +#search.loading { + background-image: url('/img/loading.gif'); + background-position: 5px center; + background-repeat: no-repeat; + padding-left: 25px; +} + #search::-webkit-input-placeholder { color: #BCDF7E; font-family: 'Ubuntu', sans-serif; @@ -186,6 +193,7 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { position: fixed; width: 250px; border: 1px solid #eee; + z-index: 1; } @media (max-width: 768px) { @@ -302,27 +310,40 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { border: 2px solid #6C0000; } -.label { +.txvalues { + display: inline-block; padding: .7em 2em; font-size: 13px; text-transform: uppercase; font-weight:100; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; } -.label-primary { +@media (max-width: 768px) { + .txvalues { + display: block; + margin: 5px; + } +} + +.txvalues-primary { background-color: #8DC429; } -.label-default { +.txvalues-default { background-color: #ffffff; color: #333; } -.label-success { +.txvalues-success { background-color: #2FA4D7; } -.label-danger { +.txvalues-danger { background-color: #AC0015; } diff --git a/public/src/js/controllers/blocks.js b/public/src/js/controllers/blocks.js index b4ae5d4..b212c4e 100644 --- a/public/src/js/controllers/blocks.js +++ b/public/src/js/controllers/blocks.js @@ -16,6 +16,27 @@ angular.module('insight.blocks').controller('BlocksController', }); } + //Datepicker + var _formatTimestamp = function (date) { + var yyyy = date.getUTCFullYear().toString(); + var mm = (date.getUTCMonth() + 1).toString(); // getMonth() is zero-based + var dd = date.getUTCDate().toString(); + + return yyyy + '-' + (mm[1] ? mm : '0' + mm[0]) + '-' + (dd[1] ? dd : '0' + dd[0]); //padding + }; + + $scope.$watch('dt', function(newValue, oldValue) { + if (newValue !== oldValue) { + $location.path('/blocks-date/' + _formatTimestamp(newValue)); + } + }); + + $scope.openCalendar = function($event) { + $event.preventDefault(); + $event.stopPropagation(); + + $scope.opened = true; + }; $scope.humanSince = function(time) { var m = moment.unix(time).startOf('day'); diff --git a/public/src/js/controllers/connection.js b/public/src/js/controllers/connection.js index b30850a..2c3198a 100644 --- a/public/src/js/controllers/connection.js +++ b/public/src/js/controllers/connection.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('insight.connection').controller('ConnectionController', -function($scope, $window, Status, Sync, getSocket) { +function($scope, $window, Status, getSocket, PeerSync) { // Set initial values $scope.apiOnline = true; @@ -21,9 +21,9 @@ function($scope, $window, Status, Sync, getSocket) { // Check for the api connection $scope.getConnStatus = function() { - Sync.get({}, - function(sync) { - $scope.apiOnline = (sync.status !== 'aborted' && sync.status !== 'error'); + PeerSync.get({}, + function(peer) { + $scope.apiOnline = peer.connected; }, function() { $scope.apiOnline = false; diff --git a/public/src/js/controllers/index.js b/public/src/js/controllers/index.js index c76f85e..d8b8647 100644 --- a/public/src/js/controllers/index.js +++ b/public/src/js/controllers/index.js @@ -23,7 +23,6 @@ angular.module('insight.system').controller('IndexController', $scope.flashMessage = $rootScope.flashMessage || null; socket.on('tx', function(tx) { - console.log('Transaction received! ' + tx.txid); $scope.txs.unshift(tx); if (parseInt($scope.txs.length, 10) >= parseInt(TRANSACTION_DISPLAYED, 10)) { $scope.txs = $scope.txs.splice(0, TRANSACTION_DISPLAYED); @@ -32,7 +31,6 @@ angular.module('insight.system').controller('IndexController', socket.on('block', function(block) { var blockHash = block.toString(); - console.log('Block received! ' + JSON.stringify(blockHash)); _getBlocks(); }); diff --git a/public/src/js/controllers/search.js b/public/src/js/controllers/search.js index b12f3bb..deab77a 100644 --- a/public/src/js/controllers/search.js +++ b/public/src/js/controllers/search.js @@ -3,6 +3,7 @@ angular.module('insight.search').controller('SearchController', function($scope, $routeParams, $location, $timeout, Global, Block, Transaction, Address, BlockByHeight) { $scope.global = Global; + $scope.loading = false; var _badQuery = function() { $scope.badQuery = true; @@ -12,39 +13,46 @@ angular.module('insight.search').controller('SearchController', }, 2000); }; + var _resetSearch = function() { + $scope.q = ''; + $scope.loading = false; + }; + $scope.search = function() { var q = $scope.q; $scope.badQuery = false; + $scope.loading = true; Block.get({ blockHash: q }, function() { - $scope.q = ''; + _resetSearch(); $location.path('block/' + q); - }, function () { //block not found, search on TX + }, function() { //block not found, search on TX Transaction.get({ txId: q }, function() { - $scope.q = ''; + _resetSearch(); $location.path('tx/' + q); - }, function () { //tx not found, search on Address + }, function() { //tx not found, search on Address Address.get({ addrStr: q }, function() { - $scope.q = ''; + _resetSearch(); $location.path('address/' + q); - }, function () { // block by height not found + }, function() { // block by height not found if (isFinite(q)) { // ensure that q is a finite number. A logical height value. BlockByHeight.get({ blockHeight: q }, function(hash) { - $scope.q = ''; + _resetSearch(); $location.path('/block/' + hash.blockHash); }, function() { //not found, fail :( _badQuery(); }); } else { + $scope.loading = false; _badQuery(); } }); diff --git a/public/src/js/services/status.js b/public/src/js/services/status.js index e8f0f24..307d66d 100644 --- a/public/src/js/services/status.js +++ b/public/src/js/services/status.js @@ -3,11 +3,15 @@ angular.module('insight.status') .factory('Status', function($resource) { - return $resource('/api/status', { - q: '@q' - }); - }) + return $resource('/api/status', { + q: '@q' + }); + }) .factory('Sync', function($resource) { return $resource('/api/sync'); - }); + }) + .factory('PeerSync', + function($resource) { + return $resource('api/peer'); + }); diff --git a/public/views/block_list.html b/public/views/block_list.html index bca47e0..99d9ffd 100644 --- a/public/views/block_list.html +++ b/public/views/block_list.html @@ -8,7 +8,10 @@

Blocks
mined on:

-

{{pagination.current}} UTC

+

+ {{pagination.current}} UTC + +

 

Today

{{humanSince(pagination.currentTs)}} @@ -31,8 +34,8 @@ Height Timestamp - Transactions - Size + Transactions + Size @@ -42,8 +45,8 @@ {{b.height}} {{b.time * 1000 | date:'medium'}} - {{b.txlength}} - {{b.size}} + {{b.txlength}} + {{b.size}} diff --git a/public/views/includes/header.html b/public/views/includes/header.html index f92bdea..53dc0b3 100644 --- a/public/views/includes/header.html +++ b/public/views/includes/header.html @@ -17,7 +17,7 @@

diff --git a/public/views/index.html b/public/views/index.html index b38eb1b..2db48e0 100644 --- a/public/views/index.html +++ b/public/views/index.html @@ -24,7 +24,7 @@ {{humanSince(b.time)}} {{b.txlength}} - {{b.size}} + {{b.size}} bytes diff --git a/public/views/transaction/tx.html b/public/views/transaction/tx.html index 5afaa09..5ec7995 100644 --- a/public/views/transaction/tx.html +++ b/public/views/transaction/tx.html @@ -141,12 +141,12 @@
-
- Fees: {{$root.currency.getConvertion(tx.fees)}} +
+ Fees: {{$root.currency.getConvertion(tx.fees)}}
-
- {{tx.confirmations}} Confirmations - Unconfirmed Transaction! - {{$root.currency.getConvertion(tx.valueOut)}} +
+ {{tx.confirmations}} Confirmations + Unconfirmed Transaction! + {{$root.currency.getConvertion(tx.valueOut)}}
diff --git a/util/sync.js b/util/sync.js index 27aed0d..bfa7c94 100755 --- a/util/sync.js +++ b/util/sync.js @@ -43,7 +43,6 @@ async.series([ historicSync.importHistory({ destroy: program.destroy, reverse: program.reverse, - upToExisting: program.uptoexisting, fromFiles: program.fromfiles, }, cb); }