From a4a0eef2b0cdd00a72c2702c0db543db47b6a074 Mon Sep 17 00:00:00 2001 From: Gustavo Cortez Date: Wed, 12 Feb 2014 11:59:29 -0300 Subject: [PATCH 01/12] fixed rounding btc values on homepages --- app/controllers/socket.js | 5 +++-- public/views/index.html | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/controllers/socket.js b/app/controllers/socket.js index 603c7ee..e0017a7 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/public/views/index.html b/public/views/index.html index ec097d4..c2412a6 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 From 1f2b2be6b70a745a311f1f8defad22fa1a6d7d4b Mon Sep 17 00:00:00 2001 From: Gustavo Cortez Date: Wed, 12 Feb 2014 12:48:03 -0300 Subject: [PATCH 02/12] fix layout: unconfirm txs message is too big --- public/src/css/common.css | 23 ++++++++++++++++++----- public/views/transaction/tx.html | 12 ++++++------ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/public/src/css/common.css b/public/src/css/common.css index 4e8ea71..0f95d22 100644 --- a/public/src/css/common.css +++ b/public/src/css/common.css @@ -302,27 +302,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/views/transaction/tx.html b/public/views/transaction/tx.html index e0cecaa..1a8a9ed 100644 --- a/public/views/transaction/tx.html +++ b/public/views/transaction/tx.html @@ -135,12 +135,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)}}
From 42968ba12e765299ab3d356fd6b539003f43dff2 Mon Sep 17 00:00:00 2001 From: Mario Colque Date: Wed, 12 Feb 2014 12:57:50 -0300 Subject: [PATCH 03/12] fixed #253 --- public/img/loading.gif | Bin 0 -> 1849 bytes public/src/css/common.css | 7 +++++++ public/src/js/controllers/search.js | 7 +++++++ public/views/includes/header.html | 2 +- 4 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 public/img/loading.gif diff --git a/public/img/loading.gif b/public/img/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..48ee52a3ada4aafd79ff4ab21e6909dee2e642d1 GIT binary patch literal 1849 zcmb8weNL>eOXgb*|di3x8Zigh;u1c5Q23N0@q5kn1y8mI_s z5y=Zect@EIr&TxFqKE}lwsi#|a*p=J7S25D>FZGs?X#@ z@jRdN{XM_)r0v*l*ld9aME;H-4a1R7o;-1lYJWG^(muZR)4xn#{kYH9nY}ai;JYth zzivA@UHJWv3l~4A`{(0-++FzS#^(db|5FkFmL%6$E&Hu|q;MB!bsTr6|ge_-YVMF_G7eJwxf? zp4&IP7etq)EhE?)DNZl^nv?!~Jj8haxraSD1KiT@WxHI?OSzH!5AT>9#Yv}c($`|n zix@G!@1rfTa>)UV1C+c$9S4Lo#R6w(BuerSb`NMu0KB;4GWz8Nnzly#mlqUhIpDY0 zIP2!F6eIbr5q6BV%`8m`g0(|oX8T^bxHH)j#Yypw>-X*H=ScDt9I2n!jyk-x&w4_j zE2uuQ8D|0TZo2w~`|$H2!mHvU{w}?V5_MQ4c+JraEUPqy=q4Lc|r9z2-#&M+IoW6I(K1|+t(>#}>IHo6Ecg~!WEbh`imhwqjr3P*#z!cHi5?STXnze^j z#us}J9c`mC`#Rc6jE#Ez8U0EwAdphIJR-3_7a4hdX}yoqvW{jZCJ{{YXM-*sh@7KM z&txZ^WoF+C-sw(Vn1vIe7uSAUy%tLD4g7V~`Wo}iu6>!Yr3HoGebJHcxg1mRLIJRH z`)kv++B)-3nmy%>kw-ko^nFJoR{(e*pwSQbgW3mh%1GCeWJX0DPGanNm!eSjNTiN8 zaKe06Iwje7t*l=$5Q_C>a9sHMt4~c|5rs&!G1E3I9=3YT6Zyju55P=!C-Z@jtv%?L zl@SDP$+l@3qJ&_S%1#YIB3ahTLwtg+vK>SK!B$y|qE|?~K+-S#q#e*l^2*4cey^WV zc?V^QsW*?g9bB41k+tELy}E)cY<|=8=HK#rl7i89JhwM zNV58eTGg6Rg2>xY#)EvqObC@q1w&xO%ZExcdO+*8(qaLzQIJ-ZNOs6qHAJ9hd7+mz zs7l=~Rm`X+6^~5`MWPsS(3te~!m&T?uN-nth>j!o*L-C6VJPpC>`F!>u!bO7yz%ZzgcqW=6VvcI~sg?w^Qn_j& z11-zRC{NB0zP8bLGV|P#w{Cyhss7FQzXaf@C$(5n={k9CLsEjY^EONnrFdq-nsoQp zUy5^DF6cC(_O(4%G~t4|r_WA_`#{$PPuPJ#H(kE2~qj%!&WMHR{Yh)uZtlw0%%_nzo!s`nY{|B!Vj_sr<~p_4b)%+D$KBI3rx$kS3lle{Qu8%D4sPBT=j3J^lH z4dn@KDw?mw@hz}FT8?1{Ry9lxgKVQpnL6q4B$x;oaaTwN(TP_jCuO-%LVAf--2>5CZ From d1ef05812564311cb938b4c60f07b6663fc5d8af Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Wed, 12 Feb 2014 12:57:55 -0300 Subject: [PATCH 04/12] Fix status page: percentage bar shows 100% on complete --- lib/HistoricSync.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/HistoricSync.js b/lib/HistoricSync.js index 4b8dcf3..40706e3 100644 --- a/lib/HistoricSync.js +++ b/lib/HistoricSync.js @@ -90,6 +90,7 @@ function spec() { HistoricSync.prototype.info = function() { + this.updatePercentage(); return { status: this.status, blockChainHeight: this.blockChainHeight, @@ -103,6 +104,12 @@ function spec() { }; }; + HistoricSync.prototype.updatePercentage = function() { + var r = (this.syncedBlocks + this.skippedBlocks) / this.blockChainHeight; + this.syncPercentage = parseFloat(100 * r).toFixed(3); + if (this.syncPercentage > 100) this.syncPercentage = 100; + }; + HistoricSync.prototype.showProgress = function() { var self = this; @@ -112,9 +119,6 @@ function spec() { p('ERROR: ' + self.error); } else { - self.syncPercentage = parseFloat(100 * (self.syncedBlocks + self.skippedBlocks) / self.blockChainHeight).toFixed(3); - if (self.syncPercentage > 100) self.syncPercentage = 100; - p(util.format('status: [%d%%] skipped: %d ', self.syncPercentage, self.skippedBlocks)); } if (self.opts.shouldBroadcastSync) { From d96f60f18b1d275d66d3037489fe6ff5db5d5a65 Mon Sep 17 00:00:00 2001 From: Mario Colque Date: Wed, 12 Feb 2014 13:04:26 -0300 Subject: [PATCH 05/12] added helper to reset serch --- public/src/js/controllers/search.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/public/src/js/controllers/search.js b/public/src/js/controllers/search.js index c41bbb8..deab77a 100644 --- a/public/src/js/controllers/search.js +++ b/public/src/js/controllers/search.js @@ -13,6 +13,11 @@ 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; @@ -21,30 +26,26 @@ angular.module('insight.search').controller('SearchController', Block.get({ blockHash: q }, function() { - $scope.q = ''; - $scope.loading = false; + _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 = ''; - $scope.loading = false; + _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 = ''; - $scope.loading = false; + _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 = ''; - $scope.loading = false; + _resetSearch(); $location.path('/block/' + hash.blockHash); }, function() { //not found, fail :( _badQuery(); From 5d75aa3ef2541c13ef4ca3cd8c2dcd2d916957c4 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Wed, 12 Feb 2014 13:43:12 -0300 Subject: [PATCH 06/12] remove console.log for tx and block recieved --- public/src/js/controllers/index.js | 2 -- 1 file changed, 2 deletions(-) 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(); }); From 39cd42bedc7b7825b4b1830e89fef5b1a176079c Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Wed, 12 Feb 2014 14:02:33 -0300 Subject: [PATCH 07/12] fixed no bitcoind crash --- app/controllers/blocks.js | 47 +++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/app/controllers/blocks.js b/app/controllers/blocks.js index 04a3746..8b0d3d4 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 }; @@ -105,20 +104,20 @@ exports.list = function(req, res) { bdb.getBlocksByDate(gte, lte, function(err, blocks) { if (err) { res.status(500).send(err); - } - else { + } else { var blockshashList = []; var limit = parseInt(req.query.limit || blocks.length); if (blocks.length < limit) { limit = blocks.length; } - for(var i=0;i Date: Wed, 12 Feb 2014 14:16:20 -0300 Subject: [PATCH 08/12] #262 right alignment of numbers on blocks-list --- public/views/block_list.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/public/views/block_list.html b/public/views/block_list.html index bca47e0..24cd74d 100644 --- a/public/views/block_list.html +++ b/public/views/block_list.html @@ -31,8 +31,8 @@ Height Timestamp - Transactions - Size + Transactions + Size @@ -42,8 +42,8 @@ {{b.height}} {{b.time * 1000 | date:'medium'}} - {{b.txlength}} - {{b.size}} + {{b.txlength}} + {{b.size}} From e047b010208f6c729c46098d8073535fb5a16824 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Wed, 12 Feb 2014 14:20:57 -0500 Subject: [PATCH 09/12] update package.json so insight can go on npm --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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" From 956b04b6429cbeb6e4558b72b8699509e1201b21 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Wed, 12 Feb 2014 16:27:18 -0300 Subject: [PATCH 10/12] bitcoind connection status derived from PeerSync --- app/controllers/status.js | 5 +++++ config/express.js | 7 ++++++- config/routes.js | 1 + insight.js | 7 +++++-- lib/PeerSync.js | 13 ++++++++++++- public/src/js/controllers/connection.js | 8 ++++---- public/src/js/services/status.js | 14 +++++++++----- 7 files changed, 42 insertions(+), 13 deletions(-) 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/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/PeerSync.js b/lib/PeerSync.js index c565176..ae9a850 100644 --- a/lib/PeerSync.js +++ b/lib/PeerSync.js @@ -11,12 +11,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; @@ -41,6 +41,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) { @@ -98,12 +104,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/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/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'); + }); From 4e6e1a974c3c0eb91754c3243adebea710f1f4e0 Mon Sep 17 00:00:00 2001 From: Gustavo Cortez Date: Wed, 12 Feb 2014 17:46:51 -0300 Subject: [PATCH 11/12] added db/blocks and txs to ignore symlinks --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) 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/* From be2a4dec85aa23f8744d2ee141c6075cdce26083 Mon Sep 17 00:00:00 2001 From: Mario Colque Date: Wed, 12 Feb 2014 18:01:04 -0300 Subject: [PATCH 12/12] #263 Added a calendar selector for blocks --- public/src/css/common.css | 1 + public/src/js/controllers/blocks.js | 21 +++++++++++++++++++++ public/views/block_list.html | 5 ++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/public/src/css/common.css b/public/src/css/common.css index fef90e8..6c0febf 100644 --- a/public/src/css/common.css +++ b/public/src/css/common.css @@ -193,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) { 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/views/block_list.html b/public/views/block_list.html index 24cd74d..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)}}