Merge branch 'master' of github.com:bitpay/insight into process-friendly
This commit is contained in:
commit
1b32e63cb2
30
README.md
30
README.md
|
@ -57,36 +57,6 @@ $ npm install -g bower
|
||||||
|
|
||||||
If you get an error, please check the next section "Post-install"
|
If you get an error, please check the next section "Post-install"
|
||||||
|
|
||||||
### Post-install (post-dependecies)
|
|
||||||
|
|
||||||
Get bufferput package from Github repository:
|
|
||||||
|
|
||||||
$ git clone git@github.com:gasteve/node-bufferput.git
|
|
||||||
|
|
||||||
Create symbolic link of node-bufferput in your insight folder:
|
|
||||||
|
|
||||||
$ cd <your_path_to>/insight/node_modules
|
|
||||||
$ ln -s <path_to>/node-bufferput bufferput
|
|
||||||
|
|
||||||
Get bitcore from github repository:
|
|
||||||
|
|
||||||
Get bitcore from github repository:
|
|
||||||
|
|
||||||
$ git clone https://github.com/bitpay/bitcore.git
|
|
||||||
|
|
||||||
$ cd bitcore
|
|
||||||
|
|
||||||
$ npm install
|
|
||||||
|
|
||||||
Then create a symbolic link from this to your insight repository. We need to
|
|
||||||
use bitcore from github, not with npm for now:
|
|
||||||
|
|
||||||
$ cd insight/node_modules
|
|
||||||
|
|
||||||
$ rm -R bitcore
|
|
||||||
|
|
||||||
$ ln -s <path-to-your-clone-repositoy>/bitcore
|
|
||||||
|
|
||||||
## Syncing old blockchain data
|
## Syncing old blockchain data
|
||||||
|
|
||||||
Run sync from insight repository (to save old blocks and transactions in MongoDB):
|
Run sync from insight repository (to save old blocks and transactions in MongoDB):
|
||||||
|
|
|
@ -32,6 +32,20 @@ exports.show = function(req, res) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show block by Height
|
||||||
|
*/
|
||||||
|
exports.blockindex = function(req, res, next, height) {
|
||||||
|
Block.fromHeight(height, function(err, hash) {
|
||||||
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
res.status(400).send('Bad Request'); // TODO
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.jsonp(hash);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of blocks by date
|
* List of blocks by date
|
||||||
|
|
|
@ -26,6 +26,6 @@ module.exports.broadcast_address_tx = function(address, tx) {
|
||||||
ios.sockets.in(address).emit('atx', tx);
|
ios.sockets.in(address).emit('atx', tx);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.broadcastSyncInfo = function(syncInfo) {
|
module.exports.broadcastSyncInfo = function(historicSync) {
|
||||||
ios.sockets.emit('sync', syncInfo);
|
ios.sockets.in('sync').emit('status', historicSync);
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ var Status = require('../models/Status'),
|
||||||
/**
|
/**
|
||||||
* Status
|
* Status
|
||||||
*/
|
*/
|
||||||
exports.show = function(req, res, next) {
|
exports.show = function(req, res) {
|
||||||
|
|
||||||
if (! req.query.q) {
|
if (! req.query.q) {
|
||||||
res.status(400).send('Bad Request');
|
res.status(400).send('Bad Request');
|
||||||
|
@ -50,6 +50,6 @@ exports.show = function(req, res, next) {
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.sync = function(req, res) {
|
exports.sync = function(req, res) {
|
||||||
if (req.syncInfo)
|
if (req.historicSync)
|
||||||
res.jsonp(req.syncInfo);
|
res.jsonp(req.historicSync.info());
|
||||||
};
|
};
|
||||||
|
|
|
@ -52,8 +52,12 @@ var getTransaction = function(txid, cb) {
|
||||||
*/
|
*/
|
||||||
exports.list = function(req, res, next) {
|
exports.list = function(req, res, next) {
|
||||||
var bId = req.query.block;
|
var bId = req.query.block;
|
||||||
var aId = req.query.address;
|
var addrStr = req.query.address;
|
||||||
var limit = req.query.limit || 1000;
|
var page = req.query.pageNum;
|
||||||
|
var pageLength = 20;
|
||||||
|
var pagesTotal = 1;
|
||||||
|
var txLength;
|
||||||
|
var txs;
|
||||||
|
|
||||||
if (bId) {
|
if (bId) {
|
||||||
Block.fromHashWithInfo(bId, function(err, block) {
|
Block.fromHashWithInfo(bId, function(err, block) {
|
||||||
|
@ -63,14 +67,28 @@ exports.list = function(req, res, next) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
async.mapSeries(block.info.tx, getTransaction,
|
txLength = block.info.tx.length;
|
||||||
|
|
||||||
|
if (page) {
|
||||||
|
var spliceInit = page * pageLength;
|
||||||
|
txs = block.info.tx.splice(spliceInit, pageLength);
|
||||||
|
pagesTotal = Math.ceil(txLength / pageLength);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
txs = block.info.tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
async.mapSeries(txs, getTransaction,
|
||||||
function(err, results) {
|
function(err, results) {
|
||||||
res.jsonp(results);
|
res.jsonp({
|
||||||
|
pagesTotal: pagesTotal,
|
||||||
|
txs: results
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (aId) {
|
else if (addrStr) {
|
||||||
var a = Address.new(aId);
|
var a = Address.new(addrStr);
|
||||||
|
|
||||||
a.update(function(err) {
|
a.update(function(err) {
|
||||||
if (err && !a.totalReceivedSat) {
|
if (err && !a.totalReceivedSat) {
|
||||||
|
@ -79,23 +97,25 @@ exports.list = function(req, res, next) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
async.mapSeries(a.transactions, getTransaction,
|
txLength = a.transactions.length;
|
||||||
function(err, results) {
|
|
||||||
res.jsonp(results);
|
if (page) {
|
||||||
});
|
var spliceInit = page * pageLength;
|
||||||
});
|
txs = a.transactions.splice(spliceInit, pageLength);
|
||||||
|
pagesTotal = Math.ceil(txLength / pageLength);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Transaction
|
txs = a.transactions;
|
||||||
.find()
|
|
||||||
.limit(limit)
|
|
||||||
.sort('-time')
|
|
||||||
.exec(function(err, txs) {
|
|
||||||
if (err) {
|
|
||||||
res.status(500).send(err);
|
|
||||||
} else {
|
|
||||||
res.jsonp(txs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async.mapSeries(txs, getTransaction,
|
||||||
|
function(err, results) {
|
||||||
|
res.jsonp({
|
||||||
|
pagesTotal: pagesTotal,
|
||||||
|
txs: results
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -60,7 +60,7 @@ function spec() {
|
||||||
// TODO TXout!
|
// TODO TXout!
|
||||||
//T
|
//T
|
||||||
function (cb) {
|
function (cb) {
|
||||||
TransactionItem.find({addr:that.addrStr}).sort({ts:1}).exec(function(err,txItems){
|
TransactionItem.find({addr:that.addrStr}).sort({ts:-1}).exec(function(err,txItems){
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
txItems.forEach(function(txItem){
|
txItems.forEach(function(txItem){
|
||||||
|
|
|
@ -72,6 +72,15 @@ BlockSchema.statics.load = function(id, cb) {
|
||||||
}).exec(cb);
|
}).exec(cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BlockSchema.statics.fromHeight = function(height, cb) {
|
||||||
|
var rpc = new RpcClient(config.bitcoind);
|
||||||
|
var hash = {};
|
||||||
|
rpc.getBlockHash(height, function(err, bh){
|
||||||
|
if (err) return cb(err);
|
||||||
|
hash.blockHash = bh.result;
|
||||||
|
cb(null, hash);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
BlockSchema.statics.fromHash = function(hash, cb) {
|
BlockSchema.statics.fromHash = function(hash, cb) {
|
||||||
this.findOne({
|
this.findOne({
|
||||||
|
|
|
@ -171,10 +171,13 @@ TransactionSchema.statics.explodeTransactionItems = function(txid, time, cb) {
|
||||||
TransactionItem.create({
|
TransactionItem.create({
|
||||||
txid : txid,
|
txid : txid,
|
||||||
value_sat : o.valueSat,
|
value_sat : o.valueSat,
|
||||||
addr : o.scriptPubKey.addresses[0],
|
addr : o.scriptPubKey.addresses[0], // TODO: only address 0?
|
||||||
index : o.n,
|
index : o.n,
|
||||||
ts : time,
|
ts : time,
|
||||||
}, next_out);
|
}, next_out);
|
||||||
|
if (addrs.indexOf(o.scriptPubKey.addresses[0]) === -1) {
|
||||||
|
addrs.push(o.scriptPubKey.addresses[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log ('WARN in TX: %s could not parse OUTPUT %d', txid, o.n);
|
console.log ('WARN in TX: %s could not parse OUTPUT %d', txid, o.n);
|
||||||
|
@ -279,7 +282,7 @@ TransactionSchema.statics.queryInfo = function(txid, cb) {
|
||||||
else {
|
else {
|
||||||
tx.ins.forEach(function(i) {
|
tx.ins.forEach(function(i) {
|
||||||
if (i.value) {
|
if (i.value) {
|
||||||
info.vin[c].value = util.formatValue(i.value);
|
info.vin[c].value = parseFloat(util.formatValue(i.value));
|
||||||
var n = util.valueToBigInt(i.value).toNumber();
|
var n = util.valueToBigInt(i.value).toNumber();
|
||||||
info.vin[c].valueSat = n;
|
info.vin[c].valueSat = n;
|
||||||
valueIn = valueIn.add( n );
|
valueIn = valueIn.add( n );
|
||||||
|
@ -319,7 +322,7 @@ TransactionSchema.statics.queryInfo = function(txid, cb) {
|
||||||
|
|
||||||
if ( !tx.isCoinBase() ) {
|
if ( !tx.isCoinBase() ) {
|
||||||
info.valueIn = valueIn / util.COIN;
|
info.valueIn = valueIn / util.COIN;
|
||||||
info.feeds = (valueIn - valueOut) / util.COIN;
|
info.fees = (valueIn - valueOut) / util.COIN;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var reward = BitcoreBlock.getBlockValue(info.height) / util.COIN;
|
var reward = BitcoreBlock.getBlockValue(info.height) / util.COIN;
|
||||||
|
@ -343,8 +346,13 @@ TransactionSchema.methods.fillInfo = function(next) {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
|
|
||||||
that.info = info;
|
that.info = info;
|
||||||
|
if (! that.info) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
that.info.time = that.time;
|
that.info.time = that.time;
|
||||||
return next();
|
return next();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ script(type='text/javascript', src='/js/services/socket.js')
|
||||||
//Application Controllers
|
//Application Controllers
|
||||||
script(type='text/javascript', src='/js/controllers/index.js')
|
script(type='text/javascript', src='/js/controllers/index.js')
|
||||||
script(type='text/javascript', src='/js/controllers/header.js')
|
script(type='text/javascript', src='/js/controllers/header.js')
|
||||||
script(type='text/javascript', src='/js/controllers/footer.js')
|
|
||||||
script(type='text/javascript', src='/js/controllers/blocks.js')
|
script(type='text/javascript', src='/js/controllers/blocks.js')
|
||||||
script(type='text/javascript', src='/js/controllers/transactions.js')
|
script(type='text/javascript', src='/js/controllers/transactions.js')
|
||||||
script(type='text/javascript', src='/js/controllers/address.js')
|
script(type='text/javascript', src='/js/controllers/address.js')
|
||||||
|
|
|
@ -31,7 +31,7 @@ module.exports = function(app, historicSync) {
|
||||||
|
|
||||||
//custom middleware
|
//custom middleware
|
||||||
function setHistoric(req, res, next) {
|
function setHistoric(req, res, next) {
|
||||||
req.syncInfo = historicSync.syncInfo;
|
req.historicSync = historicSync;
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
app.use('/api/sync', setHistoric);
|
app.use('/api/sync', setHistoric);
|
||||||
|
|
|
@ -14,6 +14,9 @@ module.exports = function(app, historicSync) {
|
||||||
app.get('/api/block/:blockHash', blocks.show);
|
app.get('/api/block/:blockHash', blocks.show);
|
||||||
app.param('blockHash', blocks.block);
|
app.param('blockHash', blocks.block);
|
||||||
|
|
||||||
|
app.get('/api/block-index/:height', blocks.blockindex);
|
||||||
|
app.param('height', blocks.blockindex);
|
||||||
|
|
||||||
// Transaction routes
|
// Transaction routes
|
||||||
var transactions = require('../app/controllers/transactions');
|
var transactions = require('../app/controllers/transactions');
|
||||||
app.get('/api/tx/:txid', transactions.show);
|
app.get('/api/tx/:txid', transactions.show);
|
||||||
|
|
26
insight.js
26
insight.js
|
@ -24,6 +24,16 @@ var express = require('express'),
|
||||||
var config = require('./config/config');
|
var config = require('./config/config');
|
||||||
|
|
||||||
//Bootstrap db connection
|
//Bootstrap db connection
|
||||||
|
// If mongod is running
|
||||||
|
mongoose.connection.on('open', function () {
|
||||||
|
console.log('Connected to mongo server.');
|
||||||
|
});
|
||||||
|
// If mongod is not running
|
||||||
|
mongoose.connection.on('error', function (err) {
|
||||||
|
console.log('Could not connect to mongo server!');
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
|
||||||
mongoose.connect(config.db);
|
mongoose.connect(config.db);
|
||||||
|
|
||||||
//Bootstrap models
|
//Bootstrap models
|
||||||
|
@ -45,19 +55,29 @@ walk(models_path);
|
||||||
|
|
||||||
// historic_sync process
|
// historic_sync process
|
||||||
var historicSync = {};
|
var historicSync = {};
|
||||||
|
|
||||||
|
|
||||||
if (!config.disableHistoricSync) {
|
if (!config.disableHistoricSync) {
|
||||||
historicSync = new HistoricSync();
|
historicSync = new HistoricSync();
|
||||||
|
|
||||||
historicSync.init({
|
historicSync.init({
|
||||||
skipDbConnection: true,
|
skipDbConnection: true,
|
||||||
shouldBroadcast: true,
|
shouldBroadcast: true,
|
||||||
|
progressStep: 2,
|
||||||
networkName: config.network
|
networkName: config.network
|
||||||
}, function() {
|
}, function(err) {
|
||||||
historicSync.smart_import(function(err){
|
if (err) {
|
||||||
|
var txt = 'ABORTED with error: ' + err.message;
|
||||||
|
console.log('[historic_sync] ' + txt);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
historicSync.smartImport(function(err){
|
||||||
var txt= 'ended.';
|
var txt= 'ended.';
|
||||||
if (err) txt = 'ABORTED with error: ' + err.message;
|
if (err) txt = 'ABORTED with error: ' + err.message;
|
||||||
|
|
||||||
console.log('[historic_sync] ' + txt, historicSync.syncInfo);
|
console.log('[historic_sync] ' + txt, historicSync.info());
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
require('classtool');
|
require('classtool');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function spec() {
|
function spec() {
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var RpcClient = require('bitcore/RpcClient').class();
|
var RpcClient = require('bitcore/RpcClient').class();
|
||||||
|
@ -13,6 +14,9 @@ function spec() {
|
||||||
var Sync = require('./Sync').class();
|
var Sync = require('./Sync').class();
|
||||||
var sockets = require('../app/controllers/socket.js');
|
var sockets = require('../app/controllers/socket.js');
|
||||||
|
|
||||||
|
|
||||||
|
var BAD_GEN_ERROR = 'Bad genesis block. Network mismatch between Insight and bitcoind? Insight is configured for:';
|
||||||
|
|
||||||
function HistoricSync(opts) {
|
function HistoricSync(opts) {
|
||||||
this.network = config.network === 'testnet' ? networks.testnet: networks.livenet;
|
this.network = config.network === 'testnet' ? networks.testnet: networks.livenet;
|
||||||
|
|
||||||
|
@ -21,27 +25,54 @@ function spec() {
|
||||||
this.genesis = genesisHashReversed.reverse().toString('hex');
|
this.genesis = genesisHashReversed.reverse().toString('hex');
|
||||||
this.sync = new Sync(opts);
|
this.sync = new Sync(opts);
|
||||||
|
|
||||||
|
|
||||||
//available status: new / syncing / finished / aborted
|
//available status: new / syncing / finished / aborted
|
||||||
this.status = 'new';
|
this.status = 'new';
|
||||||
this.syncInfo = {};
|
this.error = null;
|
||||||
|
|
||||||
|
this.syncPercentage = 0;
|
||||||
|
this.syncedBlocks = 0;
|
||||||
|
this.skippedBlocks = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function p() {
|
function p() {
|
||||||
var args = [];
|
var args = [];
|
||||||
Array.prototype.push.apply(args, arguments);
|
Array.prototype.push.apply(args, arguments);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
args.unshift('[historic_sync]');
|
args.unshift('[historic_sync]');
|
||||||
/*jshint validthis:true */
|
/*jshint validthis:true */
|
||||||
console.log.apply(this, args);
|
console.log.apply(this, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HistoricSync.prototype.setError = function(err) {
|
||||||
|
var self = this;
|
||||||
|
self.error = err.toString();
|
||||||
|
self.status='error';
|
||||||
|
self.showProgress();
|
||||||
|
};
|
||||||
|
|
||||||
HistoricSync.prototype.init = function(opts, cb) {
|
HistoricSync.prototype.init = function(opts, cb) {
|
||||||
this.rpc = new RpcClient(config.bitcoind);
|
|
||||||
this.opts = opts;
|
var self = this;
|
||||||
this.sync.init(opts, cb);
|
self.rpc = new RpcClient(config.bitcoind);
|
||||||
|
self.opts = opts;
|
||||||
|
self.sync.init(opts, function(err) {
|
||||||
|
if (err) {
|
||||||
|
self.setError(err);
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// check testnet?
|
||||||
|
self.rpc.getBlockHash(0, function(err, res){
|
||||||
|
if (!err && ( res && res.result !== self.genesis)) {
|
||||||
|
err = new Error(BAD_GEN_ERROR + config.network);
|
||||||
|
self.setError(err);
|
||||||
|
}
|
||||||
|
return cb(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
HistoricSync.prototype.close = function() {
|
HistoricSync.prototype.close = function() {
|
||||||
|
@ -49,35 +80,56 @@ function spec() {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
HistoricSync.prototype.info = function() {
|
||||||
|
return {
|
||||||
|
status: this.status,
|
||||||
|
blockChainHeight: this.blockChainHeight,
|
||||||
|
syncPercentage: this.syncPercentage,
|
||||||
|
skippedBlocks: this.skippedBlocks,
|
||||||
|
syncedBlocks: this.syncedBlocks,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
HistoricSync.prototype.showProgress = function() {
|
HistoricSync.prototype.showProgress = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var i = self.syncInfo;
|
if (self.error) {
|
||||||
var per = parseInt(100 * i.syncedBlocks / i.blocksToSync);
|
p('ERROR:' + self.error);
|
||||||
p(util.format('status: %d/%d [%d%%]', i.syncedBlocks, i.blocksToSync, per));
|
}
|
||||||
if (self.opts.broadcast) {
|
else {
|
||||||
sockets.broadcastSyncInfo(self.syncInfo);
|
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));
|
||||||
|
}
|
||||||
|
if (self.opts.shouldBroadcast) {
|
||||||
|
sockets.broadcastSyncInfo(self.info());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
HistoricSync.prototype.getPrevNextBlock = function(blockHash, blockEnd, opts, cb) {
|
HistoricSync.prototype.getPrevNextBlock = function(blockHash, blockEnd, opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// recursion end.
|
// recursion end.
|
||||||
if (!blockHash) return cb();
|
if (!blockHash) return cb();
|
||||||
|
|
||||||
var existed = 0;
|
var existed = false;
|
||||||
var blockInfo;
|
var blockInfo;
|
||||||
var blockObj;
|
var blockObj;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
// Already got it?
|
// Already got it?
|
||||||
function(c) {
|
function(c) {
|
||||||
Block.findOne({hash:blockHash}, function(err,block){
|
Block.findOne({
|
||||||
if (err) { p(err); return c(err); }
|
hash: blockHash
|
||||||
|
},
|
||||||
|
function(err, block) {
|
||||||
|
if (err) {
|
||||||
|
p(err);
|
||||||
|
return c(err);
|
||||||
|
}
|
||||||
if (block) {
|
if (block) {
|
||||||
existed =1;
|
existed = true;
|
||||||
blockObj = block;
|
blockObj = block;
|
||||||
}
|
}
|
||||||
return c();
|
return c();
|
||||||
|
@ -85,12 +137,10 @@ function spec() {
|
||||||
},
|
},
|
||||||
//show some (inacurate) status
|
//show some (inacurate) status
|
||||||
function(c) {
|
function(c) {
|
||||||
var step = parseInt(self.syncInfo.blocksToSync / 100);
|
if ( ( self.syncedBlocks + self.skippedBlocks) % self.step === 1) {
|
||||||
if (step < 10) step = 10;
|
|
||||||
|
|
||||||
if (self.syncInfo.syncedBlocks % step === 1) {
|
|
||||||
self.showProgress();
|
self.showProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
return c();
|
return c();
|
||||||
},
|
},
|
||||||
//get Info from RPC
|
//get Info from RPC
|
||||||
|
@ -98,7 +148,6 @@ function spec() {
|
||||||
|
|
||||||
// TODO: if we store prev/next, no need to go to RPC
|
// TODO: if we store prev/next, no need to go to RPC
|
||||||
// if (blockObj && blockObj.nextBlockHash) return c();
|
// if (blockObj && blockObj.nextBlockHash) return c();
|
||||||
|
|
||||||
self.rpc.getBlock(blockHash, function(err, ret) {
|
self.rpc.getBlock(blockHash, function(err, ret) {
|
||||||
if (err) return c(err);
|
if (err) return c(err);
|
||||||
|
|
||||||
|
@ -127,48 +176,38 @@ function spec() {
|
||||||
return c();
|
return c();
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
],
|
], function(err) {
|
||||||
function (err){
|
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
self.err = util.format('ERROR: @%s: %s [count: syncedBlocks: %d]', blockHash, err, self.syncInfo.syncedBlocks);
|
self.err = util.format('ERROR: @%s: %s [count: syncedBlocks: %d]', blockHash, err, self.syncedBlocks);
|
||||||
self.status = 'aborted';
|
self.status = 'aborted';
|
||||||
|
self.showProgress();
|
||||||
p(self.err);
|
p(self.err);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
self.err = null;
|
self.err = null;
|
||||||
self.status = 'syncing';
|
self.status = 'syncing';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.upToExisting && existed ) {
|
if ( (opts.upToExisting && existed && self.syncedBlocks >= self.blockChainHeight) ||
|
||||||
var diff = self.syncInfo.blocksToSync - self.syncInfo.syncedBlocks;
|
(blockEnd && blockEnd === blockHash)) {
|
||||||
if (diff <= 0) {
|
|
||||||
self.status = 'finished';
|
self.status = 'finished';
|
||||||
p('DONE. Found existing block: ', blockHash);
|
p('DONE. Found existing block: ', blockHash);
|
||||||
|
self.showProgress();
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
self.syncInfo.skipped_blocks = self.syncInfo.skipped_blocks || 1;
|
|
||||||
if ((self.syncInfo.skipped_blocks++ % 1000) === 1 ) {
|
|
||||||
p('WARN found target block\n\tbut blockChain Height is still higher that ours. Previous light sync must be interrupted.\n\tWill keep syncing.', self.syncInfo.syncedBlocks, self.syncInfo.blocksToSync, self.syncInfo.skipped_blocks);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blockEnd && blockEnd === blockHash) {
|
|
||||||
self.status = 'finished';
|
|
||||||
p('DONE. Found END block: ', blockHash);
|
|
||||||
return cb(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Continue
|
// Continue
|
||||||
if (blockInfo && blockInfo.result) {
|
if (blockInfo && blockInfo.result) {
|
||||||
if (! existed) self.syncInfo.syncedBlocks++;
|
|
||||||
if (opts.prev && blockInfo.result.previousblockhash) {
|
if (existed)
|
||||||
|
self.skippedBlocks++;
|
||||||
|
else
|
||||||
|
self.syncedBlocks++;
|
||||||
|
|
||||||
|
// recursion
|
||||||
|
if (opts.prev && blockInfo.result.previousblockhash)
|
||||||
return self.getPrevNextBlock(blockInfo.result.previousblockhash, blockEnd, opts, cb);
|
return self.getPrevNextBlock(blockInfo.result.previousblockhash, blockEnd, opts, cb);
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.next && blockInfo.result.nextblockhash)
|
if (opts.next && blockInfo.result.nextblockhash)
|
||||||
return self.getPrevNextBlock(blockInfo.result.nextblockhash, blockEnd, opts, cb);
|
return self.getPrevNextBlock(blockInfo.result.nextblockhash, blockEnd, opts, cb);
|
||||||
|
@ -177,13 +216,12 @@ function spec() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
HistoricSync.prototype.import_history = function(opts, next) {
|
HistoricSync.prototype.importHistory = function(opts, next) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var retry_secs = 2;
|
var retry_secs = 2;
|
||||||
|
|
||||||
var bestBlock;
|
var bestBlock;
|
||||||
var blockChainHeight;
|
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
function(cb) {
|
function(cb) {
|
||||||
|
@ -199,14 +237,14 @@ function spec() {
|
||||||
|
|
||||||
self.rpc.getBlockCount(function(err, res) {
|
self.rpc.getBlockCount(function(err, res) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
blockChainHeight = res.result;
|
self.blockChainHeight = res.result;
|
||||||
return cb();
|
return cb();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(cb) {
|
function(cb) {
|
||||||
if (!opts.reverse) return cb();
|
if (!opts.reverse) return cb();
|
||||||
|
|
||||||
self.rpc.getBlockHash(blockChainHeight, function(err, res) {
|
self.rpc.getBlockHash(self.blockChainHeight, function(err, res) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
bestBlock = res.result;
|
bestBlock = res.result;
|
||||||
|
@ -215,29 +253,21 @@ function spec() {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(cb) {
|
function(cb) {
|
||||||
// This is only to inform progress.
|
if (opts.upToExisting) {
|
||||||
if (!opts.upToExisting) {
|
|
||||||
self.rpc.getInfo(function(err, res) {
|
|
||||||
if (err) return cb(err);
|
|
||||||
self.syncInfo.blocksToSync = res.result.blocks;
|
|
||||||
return cb();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// should be isOrphan = true or null to be more accurate.
|
// should be isOrphan = true or null to be more accurate.
|
||||||
Block.count({ isOrphan: null}, function(err, count) {
|
Block.count({
|
||||||
|
isOrphan: null
|
||||||
|
},
|
||||||
|
function(err, count) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
self.syncInfo.blocksToSync = blockChainHeight - count;
|
self.syncedBlocks = count || 0;
|
||||||
if (self.syncInfo.blocksToSync < 1) self.syncInfo.blocksToSync = 1;
|
|
||||||
return cb();
|
return cb();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
],
|
], function(err) {
|
||||||
function(err) {
|
|
||||||
|
|
||||||
|
|
||||||
var start, end;
|
var start, end;
|
||||||
function sync() {
|
function sync() {
|
||||||
if (opts.reverse) {
|
if (opts.reverse) {
|
||||||
|
@ -250,18 +280,6 @@ function spec() {
|
||||||
end = null;
|
end = null;
|
||||||
opts.next = true;
|
opts.next = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.syncInfo = util._extend(self.syncInfo, {
|
|
||||||
start: start,
|
|
||||||
isStartGenesis: start === self.genesis,
|
|
||||||
end: end,
|
|
||||||
isEndGenesis: end === self.genesis,
|
|
||||||
scanningForward: opts.next,
|
|
||||||
scanningBackward: opts.prev,
|
|
||||||
upToExisting: opts.upToExisting,
|
|
||||||
syncedBlocks: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
p('Starting from: ', start);
|
p('Starting from: ', start);
|
||||||
p(' to : ', end);
|
p(' to : ', end);
|
||||||
p(' opts: ', JSON.stringify(opts));
|
p(' opts: ', JSON.stringify(opts));
|
||||||
|
@ -271,15 +289,27 @@ function spec() {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
p('Retrying in %d secs', retry_secs);
|
p('Retrying in %d secs', retry_secs);
|
||||||
sync();
|
sync();
|
||||||
}, retry_secs * 1000);
|
},
|
||||||
|
retry_secs * 1000);
|
||||||
}
|
}
|
||||||
else
|
else return next(err);
|
||||||
return next(err);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!self.step) {
|
||||||
|
var step = parseInt( (self.blockChainHeight - self.syncedBlocks) / 1000);
|
||||||
|
|
||||||
|
if (self.opts.progressStep) {
|
||||||
|
step = self.opts.progressStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step < 10) step = 10;
|
||||||
|
self.step = step;
|
||||||
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
self.syncInfo = util._extend(self.syncInfo, { error: err.message });
|
self.setError(err);
|
||||||
return next(err, 0);
|
return next(err, 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -289,14 +319,16 @@ function spec() {
|
||||||
};
|
};
|
||||||
|
|
||||||
// upto if we have genesis block?
|
// upto if we have genesis block?
|
||||||
HistoricSync.prototype.smart_import = function(next) {
|
HistoricSync.prototype.smartImport = function(next) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
Block.findOne({hash:self.genesis}, function(err, b){
|
Block.findOne({
|
||||||
|
hash: self.genesis
|
||||||
|
},
|
||||||
|
function(err, b) {
|
||||||
|
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
|
|
||||||
|
|
||||||
if (!b) {
|
if (!b) {
|
||||||
p('Could not find Genesis block. Running FULL SYNC');
|
p('Could not find Genesis block. Running FULL SYNC');
|
||||||
}
|
}
|
||||||
|
@ -305,15 +337,14 @@ function spec() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var opts = {
|
var opts = {
|
||||||
reverse: 1,
|
reverse: true,
|
||||||
upToExisting: b ? true: false,
|
upToExisting: b ? true: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
return self.import_history(opts, next);
|
return self.importHistory(opts, next);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return HistoricSync;
|
return HistoricSync;
|
||||||
}
|
}
|
||||||
module.defineClass(spec);
|
module.defineClass(spec);
|
||||||
|
|
|
@ -60,7 +60,6 @@
|
||||||
"mongoose": "~3.8.3",
|
"mongoose": "~3.8.3",
|
||||||
"lodash": "~2.4.1",
|
"lodash": "~2.4.1",
|
||||||
"bower": "~1.2.8",
|
"bower": "~1.2.8",
|
||||||
"bitcore": "*",
|
|
||||||
"buffertools": "*",
|
"buffertools": "*",
|
||||||
"grunt": "~0.4.2",
|
"grunt": "~0.4.2",
|
||||||
"grunt-cli": "~0.1.11",
|
"grunt-cli": "~0.1.11",
|
||||||
|
@ -75,7 +74,9 @@
|
||||||
"socket.io": "~0.9.16",
|
"socket.io": "~0.9.16",
|
||||||
"moment": "~2.5.0",
|
"moment": "~2.5.0",
|
||||||
"sinon": "~1.7.3",
|
"sinon": "~1.7.3",
|
||||||
"chai": "~1.8.1"
|
"chai": "~1.8.1",
|
||||||
|
"bitcore": "git://github.com/bitpay/bitcore.git",
|
||||||
|
"bufferput": "git://github.com/bitpay/node-bufferput.git"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"grunt-contrib-watch": "latest",
|
"grunt-contrib-watch": "latest",
|
||||||
|
|
|
@ -29,7 +29,7 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
/* Negative indent footer by its height */
|
/* Negative indent footer by its height */
|
||||||
margin: 0 auto -60px;
|
margin: 0 auto -51px;
|
||||||
/* Pad bottom by footer height */
|
/* Pad bottom by footer height */
|
||||||
padding: 0 0 60px;
|
padding: 0 0 60px;
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||||
.m20h {margin: 0 20px;}
|
.m20h {margin: 0 20px;}
|
||||||
.m5v {margin: 5px 0;}
|
.m5v {margin: 5px 0;}
|
||||||
.m20v {margin: 20px 0;}
|
.m20v {margin: 20px 0;}
|
||||||
|
.m10v {margin: 10px 0;}
|
||||||
.m50v {margin: 50px 0;}
|
.m50v {margin: 50px 0;}
|
||||||
.m10b {margin-bottom: 10px;}
|
.m10b {margin-bottom: 10px;}
|
||||||
|
|
||||||
|
@ -91,18 +92,18 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||||
font-family: Ubuntu, sans-serif;
|
font-family: Ubuntu, sans-serif;
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-size: 13px;
|
font-size: 15px;
|
||||||
color: #BCDF7E;
|
color: #BCDF7E;
|
||||||
line-height: 18px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#search::-moz-placeholder {
|
#search::-moz-placeholder {
|
||||||
font-family: Ubuntu, sans-serif;
|
font-family: Ubuntu, sans-serif;
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
font-size: 13px;
|
font-size: 15px;
|
||||||
color: #BCDF7E;
|
color: #BCDF7E;
|
||||||
line-height: 18px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status {
|
.status {
|
||||||
|
@ -119,11 +120,10 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.col-gray {
|
.col-gray {
|
||||||
|
width: 267px;
|
||||||
background-color: #F4F4F4;
|
background-color: #F4F4F4;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
margin-top: 21px;
|
margin-top: 21px;
|
||||||
width: 265px;
|
|
||||||
height: 87%;
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,9 +159,8 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||||
border-radius: :;px;
|
border-radius: :;px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.block-id h1 {
|
.block-id h3 {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 24px;
|
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -221,10 +220,29 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||||
border: 2px solid #6C0000;
|
border: 2px solid #6C0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#status .table {
|
||||||
|
margin-bottom: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar-info {
|
||||||
|
background-color: #8DC429;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the fixed height of the footer here */
|
/* Set the fixed height of the footer here */
|
||||||
#footer {
|
#footer {
|
||||||
height: 60px;
|
height: 51px;
|
||||||
background-color: #f5f5f5;
|
background-color: #373D42;
|
||||||
|
border-top: 4px solid #656E76;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer .insight {
|
||||||
|
font-size: 20px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-footer {
|
||||||
|
border-top: 2px dashed #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.line-bot {
|
.line-bot {
|
||||||
|
@ -246,9 +264,14 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||||
#wrap > .container {
|
#wrap > .container {
|
||||||
padding: 60px 15px 0;
|
padding: 60px 15px 0;
|
||||||
}
|
}
|
||||||
/*.container .text-muted {
|
|
||||||
margin: 20px 0;
|
.container .text-muted {
|
||||||
}*/
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container .text-muted a {
|
||||||
|
color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
#footer > .container {
|
#footer > .container {
|
||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
|
@ -265,7 +288,13 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||||
|
|
||||||
#search { width: 400px; }
|
#search { width: 400px; }
|
||||||
|
|
||||||
|
.no_matching {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
border: 2px solid #64920F;
|
||||||
|
padding: 10px 20px;
|
||||||
|
position: absolute;
|
||||||
|
top: 46px;
|
||||||
|
}
|
||||||
|
|
||||||
/*Animations*/
|
/*Animations*/
|
||||||
.fader.ng-enter {
|
.fader.ng-enter {
|
||||||
|
@ -334,4 +363,30 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||||
background-color: #1a1a1a;
|
background-color: #1a1a1a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.expanded-tx {
|
||||||
|
border-bottom: 1px dashed #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.expanded-tx small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status .t {
|
||||||
|
color: white;
|
||||||
|
display: inline-block;
|
||||||
|
padding:0px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status .text-danger {
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status .text-warning {
|
||||||
|
background: yellow;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status .text-default {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@ angular.module('insight').config(['$routeProvider',
|
||||||
when('/block/:blockHash', {
|
when('/block/:blockHash', {
|
||||||
templateUrl: 'views/block.html'
|
templateUrl: 'views/block.html'
|
||||||
}).
|
}).
|
||||||
|
when('/block-index/:blockHeight', {
|
||||||
|
controller: 'BlocksController',
|
||||||
|
template: 'Redirecting...'
|
||||||
|
}).
|
||||||
when('/tx/:txId', {
|
when('/tx/:txId', {
|
||||||
templateUrl: 'views/transaction.html'
|
templateUrl: 'views/transaction.html'
|
||||||
}).
|
}).
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('insight.address').controller('AddressController',
|
angular.module('insight.address').controller('AddressController',
|
||||||
['$scope',
|
|
||||||
'$rootScope',
|
|
||||||
'$routeParams',
|
|
||||||
'$location',
|
|
||||||
'Global',
|
|
||||||
'Address',
|
|
||||||
'get_socket',
|
|
||||||
function ($scope, $rootScope, $routeParams, $location, Global, Address, get_socket) {
|
function ($scope, $rootScope, $routeParams, $location, Global, Address, get_socket) {
|
||||||
$scope.global = Global;
|
$scope.global = Global;
|
||||||
|
|
||||||
|
@ -33,4 +26,4 @@ angular.module('insight.address').controller('AddressController',
|
||||||
socket.emit('subscribe', $routeParams.addrStr);
|
socket.emit('subscribe', $routeParams.addrStr);
|
||||||
|
|
||||||
$scope.params = $routeParams;
|
$scope.params = $routeParams;
|
||||||
}]);
|
});
|
||||||
|
|
|
@ -1,8 +1,20 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('insight.blocks').controller('BlocksController', ['$scope', '$rootScope', '$routeParams', '$location', 'Global', 'Block', 'Blocks', function ($scope, $rootScope, $routeParams, $location, Global, Block, Blocks) {
|
angular.module('insight.blocks').controller('BlocksController',
|
||||||
|
function ($scope, $rootScope, $routeParams, $location, Global, Block, Blocks, BlockByHeight) {
|
||||||
$scope.global = Global;
|
$scope.global = Global;
|
||||||
|
|
||||||
|
if ($routeParams.blockHeight) {
|
||||||
|
BlockByHeight.get({
|
||||||
|
blockHeight: $routeParams.blockHeight
|
||||||
|
}, function(hash) {
|
||||||
|
$location.path('/block/' + hash.blockHash);
|
||||||
|
}, function() {
|
||||||
|
$rootScope.flashMessage = 'Bad Request';
|
||||||
|
$location.path('/');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$scope.list = function() {
|
$scope.list = function() {
|
||||||
Blocks.get({
|
Blocks.get({
|
||||||
blockDate: $routeParams.blockDate
|
blockDate: $routeParams.blockDate
|
||||||
|
@ -32,4 +44,4 @@ angular.module('insight.blocks').controller('BlocksController', ['$scope', '$roo
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.params = $routeParams;
|
$scope.params = $routeParams;
|
||||||
}]);
|
});
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
angular.module('insight.system').controller('FooterController',
|
|
||||||
['$scope',
|
|
||||||
'Global',
|
|
||||||
'Status',
|
|
||||||
function ($scope, Global, Status) {
|
|
||||||
$scope.global = Global;
|
|
||||||
|
|
||||||
$scope.getFooter = function() {
|
|
||||||
Status.get({
|
|
||||||
q: 'getInfo'
|
|
||||||
}, function(d) {
|
|
||||||
$scope.info = d.info;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
}]);
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('insight.system').controller('HeaderController', ['$scope', 'Global', function ($scope, Global) {
|
angular.module('insight.system').controller('HeaderController',
|
||||||
|
function ($scope, Global) {
|
||||||
$scope.global = Global;
|
$scope.global = Global;
|
||||||
|
|
||||||
$scope.menu = [
|
$scope.menu = [
|
||||||
|
@ -15,4 +16,4 @@ angular.module('insight.system').controller('HeaderController', ['$scope', 'Glob
|
||||||
];
|
];
|
||||||
|
|
||||||
$scope.isCollapsed = false;
|
$scope.isCollapsed = false;
|
||||||
}]);
|
});
|
||||||
|
|
|
@ -3,12 +3,6 @@
|
||||||
var TRANSACTION_DISPLAYED = 5;
|
var TRANSACTION_DISPLAYED = 5;
|
||||||
var BLOCKS_DISPLAYED = 5;
|
var BLOCKS_DISPLAYED = 5;
|
||||||
angular.module('insight.system').controller('IndexController',
|
angular.module('insight.system').controller('IndexController',
|
||||||
['$scope',
|
|
||||||
'$rootScope',
|
|
||||||
'Global',
|
|
||||||
'get_socket',
|
|
||||||
'Blocks',
|
|
||||||
'Transactions',
|
|
||||||
function($scope, $rootScope, Global, get_socket, Blocks, Transactions) {
|
function($scope, $rootScope, Global, get_socket, Blocks, Transactions) {
|
||||||
$scope.global = Global;
|
$scope.global = Global;
|
||||||
|
|
||||||
|
@ -55,4 +49,4 @@ angular.module('insight.system').controller('IndexController',
|
||||||
|
|
||||||
$scope.txs = [];
|
$scope.txs = [];
|
||||||
$scope.blocks = [];
|
$scope.blocks = [];
|
||||||
}]);
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('insight.search').controller('SearchController', ['$scope', '$routeParams', '$location', 'Global', 'Block', 'Transaction', 'Address', function ($scope, $routeParams, $location, Global, Block, Transaction, Address) {
|
angular.module('insight.search').controller('SearchController',
|
||||||
|
function ($scope, $routeParams, $location, $timeout, Global, Block, Transaction, Address, BlockByHeight) {
|
||||||
$scope.global = Global;
|
$scope.global = Global;
|
||||||
|
|
||||||
$scope.search = function() {
|
$scope.search = function() {
|
||||||
|
@ -9,6 +10,11 @@ angular.module('insight.search').controller('SearchController', ['$scope', '$rou
|
||||||
$scope.badQuery = false;
|
$scope.badQuery = false;
|
||||||
$scope.q = '';
|
$scope.q = '';
|
||||||
|
|
||||||
|
BlockByHeight.get({
|
||||||
|
blockHeight: q
|
||||||
|
}, function(hash) {
|
||||||
|
$location.path('/block/' + hash.blockHash);
|
||||||
|
}, function() { // block by height not found
|
||||||
Block.get({
|
Block.get({
|
||||||
blockHash: q
|
blockHash: q
|
||||||
}, function() {
|
}, function() {
|
||||||
|
@ -25,10 +31,14 @@ angular.module('insight.search').controller('SearchController', ['$scope', '$rou
|
||||||
$location.path('address/' + q);
|
$location.path('address/' + q);
|
||||||
}, function () { //address not found, fail :(
|
}, function () { //address not found, fail :(
|
||||||
$scope.badQuery = true;
|
$scope.badQuery = true;
|
||||||
|
$timeout(function() {
|
||||||
|
$scope.badQuery = false;
|
||||||
|
}, 2000);
|
||||||
$scope.q = q;
|
$scope.q = q;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
}]);
|
});
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('insight.status').controller('StatusController', ['$scope', '$routeParams', '$location', '$rootScope', 'Global', 'Status', 'Sync', function ($scope, $routeParams, $location, $rootScope, Global, Status, Sync) {
|
angular.module('insight.status').controller('StatusController',
|
||||||
|
function($scope, $routeParams, $location, $rootScope, Global, Status, Sync, get_socket) {
|
||||||
$scope.global = Global;
|
$scope.global = Global;
|
||||||
|
|
||||||
$scope.getStatus = function(q) {
|
$scope.getStatus = function(q) {
|
||||||
Status.get({
|
Status.get({
|
||||||
q: 'get' + q
|
q: 'get' + q
|
||||||
}, function(d) {
|
},
|
||||||
|
function(d) {
|
||||||
$rootScope.infoError = null;
|
$rootScope.infoError = null;
|
||||||
angular.extend($scope, d);
|
angular.extend($scope, d);
|
||||||
}, function(e) {
|
},
|
||||||
|
function(e) {
|
||||||
if (e.status === 503) {
|
if (e.status === 503) {
|
||||||
$rootScope.infoError = 'Backend Error. ' + e.data;
|
$rootScope.infoError = 'Backend Error. ' + e.data;
|
||||||
}
|
}
|
||||||
|
@ -19,13 +22,26 @@ angular.module('insight.status').controller('StatusController', ['$scope', '$rou
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.getSync = function() {
|
var on_sync_update = function(sync) {
|
||||||
Sync.get({}, function(sync) {
|
|
||||||
$rootScope.syncError = null;
|
|
||||||
$scope.sync = sync;
|
$scope.sync = sync;
|
||||||
}, function(e) {
|
};
|
||||||
$rootScope.syncError = 'Could not get sync information' + e;
|
|
||||||
|
$scope.getSync = function() {
|
||||||
|
Sync.get({},
|
||||||
|
function(sync) {
|
||||||
|
on_sync_update(sync);
|
||||||
|
},
|
||||||
|
function(e) {
|
||||||
|
$scope.sync = { error: 'Could not get sync information' + e };
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}]);
|
|
||||||
|
var socket = get_socket($scope);
|
||||||
|
socket.emit('subscribe', 'sync');
|
||||||
|
socket.on('status', function(sync) {
|
||||||
|
console.log('[status.js.55::] sync status update received!');
|
||||||
|
on_sync_update(sync);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,87 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('insight.transactions').controller('transactionsController',
|
angular.module('insight.transactions').controller('transactionsController',
|
||||||
['$scope',
|
|
||||||
'$rootScope',
|
|
||||||
'$routeParams',
|
|
||||||
'$location',
|
|
||||||
'Global',
|
|
||||||
'Transaction',
|
|
||||||
'TransactionsByBlock',
|
|
||||||
'TransactionsByAddress',
|
|
||||||
'get_socket',
|
|
||||||
function ($scope, $rootScope, $routeParams, $location, Global, Transaction, TransactionsByBlock, TransactionsByAddress, get_socket) {
|
function ($scope, $rootScope, $routeParams, $location, Global, Transaction, TransactionsByBlock, TransactionsByAddress, get_socket) {
|
||||||
$scope.global = Global;
|
$scope.global = Global;
|
||||||
|
$scope.loading = false;
|
||||||
|
$scope.loadedBy = null;
|
||||||
|
|
||||||
|
var pageNum = 0;
|
||||||
|
var pagesTotal = 1;
|
||||||
|
|
||||||
$scope.findThis = function() {
|
$scope.findThis = function() {
|
||||||
$scope.findTx($routeParams.txId);
|
$scope.findTx($routeParams.txId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.aggregateItems = function(items) {
|
||||||
|
if (!items) return [];
|
||||||
|
|
||||||
|
var l = items.length;
|
||||||
|
|
||||||
|
var ret = [];
|
||||||
|
var tmp = {};
|
||||||
|
var u=0;
|
||||||
|
// TODO multiple output address
|
||||||
|
//
|
||||||
|
for(var i=0; i < l; i++) {
|
||||||
|
|
||||||
|
var notAddr = false;
|
||||||
|
|
||||||
|
// non standard input
|
||||||
|
if (items[i].scriptSig && !items[i].addr) {
|
||||||
|
items[i].addr = 'Unparsed address [' + u++ + ']';
|
||||||
|
items[i].notAddr = true;
|
||||||
|
notAddr = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// non standard output
|
||||||
|
if (items[i].scriptPubKey && !items[i].scriptPubKey.addresses) {
|
||||||
|
items[i].scriptPubKey.addresses = ['Unparsed address [' + u++ + ']'];
|
||||||
|
items[i].notAddr = true;
|
||||||
|
notAddr = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiple addr at output
|
||||||
|
if (items[i].scriptPubKey && items[i].scriptPubKey.addresses.length > 1) {
|
||||||
|
items[i].addr = items[i].scriptPubKey.addresses.join(',');
|
||||||
|
ret.push(items[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var addr = items[i].addr || (items[i].scriptPubKey && items[i].scriptPubKey.addresses[0] );
|
||||||
|
|
||||||
|
if (!tmp[addr]) {
|
||||||
|
tmp[addr] = {};
|
||||||
|
tmp[addr].valueSat = 0;
|
||||||
|
tmp[addr].count = 0;
|
||||||
|
tmp[addr].addr = addr;
|
||||||
|
tmp[addr].items = [];
|
||||||
|
}
|
||||||
|
tmp[addr].valueSat += items[i].valueSat;
|
||||||
|
tmp[addr].value = tmp[addr].valueSat / 100000000;
|
||||||
|
tmp[addr].items.push(items[i]);
|
||||||
|
tmp[addr].notAddr = notAddr;
|
||||||
|
tmp[addr].count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
angular.forEach(tmp, function(v) {
|
||||||
|
ret.push(v);
|
||||||
|
});
|
||||||
|
return (ret);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.processTX = function(tx) {
|
||||||
|
tx.vinSimple = $scope.aggregateItems(tx.vin);
|
||||||
|
tx.voutSimple = $scope.aggregateItems(tx.vout);
|
||||||
|
};
|
||||||
|
|
||||||
$scope.findTx = function(txid) {
|
$scope.findTx = function(txid) {
|
||||||
Transaction.get({
|
Transaction.get({
|
||||||
txId: txid
|
txId: txid
|
||||||
}, function(tx) {
|
}, function(tx) {
|
||||||
$scope.tx = tx;
|
$scope.tx = tx;
|
||||||
$scope.txs.push(tx);
|
$scope.processTX(tx);
|
||||||
|
$scope.txs.unshift(tx);
|
||||||
}, function(e) {
|
}, function(e) {
|
||||||
if (e.status === 400) {
|
if (e.status === 400) {
|
||||||
$rootScope.flashMessage = 'Invalid Transaction ID: ' + $routeParams.txId;
|
$rootScope.flashMessage = 'Invalid Transaction ID: ' + $routeParams.txId;
|
||||||
|
@ -37,27 +96,62 @@ angular.module('insight.transactions').controller('transactionsController',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.byBlock = function(bId) {
|
$scope.byBlock = function() {
|
||||||
TransactionsByBlock.query({
|
TransactionsByBlock.get({
|
||||||
block: bId
|
block: $routeParams.blockHash,
|
||||||
}, function(txs) {
|
pageNum: pageNum
|
||||||
$scope.txs = txs;
|
}, function(data) {
|
||||||
|
$scope.paginate(data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.byAddress = function(aId) {
|
$scope.byAddress = function () {
|
||||||
TransactionsByAddress.query({
|
TransactionsByAddress.get({
|
||||||
address: aId
|
address: $routeParams.addrStr,
|
||||||
}, function(txs) {
|
pageNum: pageNum
|
||||||
$scope.txs = txs;
|
}, function(data) {
|
||||||
|
$scope.paginate(data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.paginate = function (data) {
|
||||||
|
$scope.loading = false;
|
||||||
|
|
||||||
|
pagesTotal = data.pagesTotal;
|
||||||
|
pageNum += 1;
|
||||||
|
|
||||||
|
data.txs.forEach(function(tx) {
|
||||||
|
$scope.processTX(tx);
|
||||||
|
$scope.txs.push(tx);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.load = function(from) {
|
||||||
|
$scope.loadedBy = from;
|
||||||
|
$scope.loadMore();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.loadMore = function() {
|
||||||
|
if (pageNum < pagesTotal && !$scope.loading) {
|
||||||
|
$scope.loading = true;
|
||||||
|
|
||||||
|
if ($scope.loadedBy === 'address') {
|
||||||
|
$scope.byAddress();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$scope.byBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var socket = get_socket($scope);
|
var socket = get_socket($scope);
|
||||||
socket.on('atx', function(tx) {
|
socket.on('atx', function(tx) {
|
||||||
console.log('Incoming transaction for address!', tx);
|
console.log('atx '+tx.txid);
|
||||||
|
var beep = new Audio('/sound/transaction.mp3');
|
||||||
|
beep.play();
|
||||||
$scope.findTx(tx.txid);
|
$scope.findTx(tx.txid);
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.txs = [];
|
$scope.txs = [];
|
||||||
|
|
||||||
}]);
|
});
|
||||||
|
|
|
@ -1 +1,25 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('insight.address').directive('whenScrolled', ['$window', function($window) {
|
||||||
|
return {
|
||||||
|
link: function(scope, elm, attr) {
|
||||||
|
var pageHeight, clientHeight, scrollPos;
|
||||||
|
$window = angular.element($window);
|
||||||
|
|
||||||
|
var handler = function() {
|
||||||
|
pageHeight = window.document.documentElement.scrollHeight;
|
||||||
|
clientHeight = window.document.documentElement.clientHeight;
|
||||||
|
scrollPos = window.pageYOffset;
|
||||||
|
|
||||||
|
if (pageHeight - (scrollPos + clientHeight) === 0) {
|
||||||
|
scope.$apply(attr.whenScrolled);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$window.on('scroll', handler);
|
||||||
|
scope.$on('$destroy', function() {
|
||||||
|
return $window.off('scroll', handler);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('insight.address').factory('Address', ['$resource', function($resource) {
|
angular.module('insight.address').factory('Address',
|
||||||
|
function($resource) {
|
||||||
return $resource('/api/addr/:addrStr', {
|
return $resource('/api/addr/:addrStr', {
|
||||||
addrStr: '@addStr'
|
addrStr: '@addStr'
|
||||||
}, {
|
}, {
|
||||||
|
@ -18,5 +19,5 @@ angular.module('insight.address').factory('Address', ['$resource', function($res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}]);
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('insight.blocks').factory('Block', ['$resource', function($resource) {
|
angular.module('insight.blocks').factory('Block',
|
||||||
|
function($resource) {
|
||||||
return $resource('/api/block/:blockHash', {
|
return $resource('/api/block/:blockHash', {
|
||||||
blockHash: '@blockHash'
|
blockHash: '@blockHash'
|
||||||
}, {
|
}, {
|
||||||
|
@ -18,8 +19,15 @@ angular.module('insight.blocks').factory('Block', ['$resource', function($resour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}]);
|
});
|
||||||
|
|
||||||
angular.module('insight.blocks').factory('Blocks', ['$resource', function($resource) {
|
angular.module('insight.blocks').factory('Blocks',
|
||||||
|
function($resource) {
|
||||||
return $resource('/api/blocks');
|
return $resource('/api/blocks');
|
||||||
}]);
|
});
|
||||||
|
|
||||||
|
angular.module('insight.blocks').factory('BlockByHeight',
|
||||||
|
function($resource) {
|
||||||
|
return $resource('/api/block-index/:blockHeight');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
//Global service for global variables
|
//Global service for global variables
|
||||||
angular.module('insight.system').factory('Global', [function() {}]);
|
angular.module('insight.system').factory('Global',
|
||||||
|
function() {
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,8 @@ ScopedSocket.prototype.emit = function(event, data, callback) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
angular.module('insight.socket').factory('get_socket', ['$rootScope', function($rootScope) {
|
angular.module('insight.socket').factory('get_socket',
|
||||||
|
function($rootScope) {
|
||||||
var socket = io.connect();
|
var socket = io.connect();
|
||||||
return function(scope) {
|
return function(scope) {
|
||||||
var scopedSocket = new ScopedSocket(socket, $rootScope);
|
var scopedSocket = new ScopedSocket(socket, $rootScope);
|
||||||
|
@ -55,5 +56,5 @@ angular.module('insight.socket').factory('get_socket', ['$rootScope', function($
|
||||||
});
|
});
|
||||||
return scopedSocket;
|
return scopedSocket;
|
||||||
};
|
};
|
||||||
}]);
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('insight.status').factory('Status', ['$resource', function($resource) {
|
angular.module('insight.status').factory('Status',
|
||||||
|
function($resource) {
|
||||||
return $resource('/api/status', {
|
return $resource('/api/status', {
|
||||||
q: '@q'
|
q: '@q'
|
||||||
});
|
});
|
||||||
}]);
|
});
|
||||||
|
|
||||||
angular.module('insight.status').factory('Sync', ['$resource', function($resource) {
|
angular.module('insight.status').factory('Sync',
|
||||||
|
function($resource) {
|
||||||
return $resource('/api/sync');
|
return $resource('/api/sync');
|
||||||
}]);
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('insight.transactions').factory('Transaction', ['$resource', function($resource) {
|
angular.module('insight.transactions').factory('Transaction',
|
||||||
|
function($resource) {
|
||||||
return $resource('/api/tx/:txId', {
|
return $resource('/api/tx/:txId', {
|
||||||
txId: '@txId'
|
txId: '@txId'
|
||||||
}, {
|
}, {
|
||||||
|
@ -18,20 +19,23 @@ angular.module('insight.transactions').factory('Transaction', ['$resource', func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}]);
|
});
|
||||||
|
|
||||||
angular.module('insight.transactions').factory('TransactionsByBlock', ['$resource', function($resource) {
|
angular.module('insight.transactions').factory('TransactionsByBlock',
|
||||||
|
function($resource) {
|
||||||
return $resource('/api/txs', {
|
return $resource('/api/txs', {
|
||||||
block: '@block'
|
block: '@block'
|
||||||
});
|
});
|
||||||
}]);
|
});
|
||||||
|
|
||||||
angular.module('insight.transactions').factory('TransactionsByAddress', ['$resource', function($resource) {
|
angular.module('insight.transactions').factory('TransactionsByAddress',
|
||||||
|
function($resource) {
|
||||||
return $resource('/api/txs', {
|
return $resource('/api/txs', {
|
||||||
address: '@address'
|
address: '@address'
|
||||||
});
|
});
|
||||||
}]);
|
});
|
||||||
|
|
||||||
angular.module('insight.transactions').factory('Transactions', ['$resource', function($resource) {
|
angular.module('insight.transactions').factory('Transactions',
|
||||||
|
function($resource) {
|
||||||
return $resource('/api/txs');
|
return $resource('/api/txs');
|
||||||
}]);
|
});
|
||||||
|
|
Binary file not shown.
|
@ -1,45 +1,44 @@
|
||||||
<section data-ng-controller="AddressController" data-ng-init="findOne()">
|
<section data-ng-controller="AddressController" data-ng-init="findOne()">
|
||||||
<div class="page-header">
|
|
||||||
<h1>
|
|
||||||
Address
|
|
||||||
<small>Addresses are identifiers which you use to send bitcoins to another person.</small>
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-9">
|
<div class="col-md-3">
|
||||||
<table class="table table-striped">
|
<div class="bs-sidebar hidden-print affix col-gray">
|
||||||
|
<div class="text-center m10v">
|
||||||
|
<qrcode size="200" data="{{address.addrStr}}"></qrcode>
|
||||||
|
<h4><span class="glyphicon glyphicon-qrcode"></span> Address</h4>
|
||||||
|
<a class="ellipsis" href="/#!/address/{{address.addrStr}}">{{address.addrStr}}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="m50v">
|
||||||
|
<h4>Summary</h4>
|
||||||
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Address</td>
|
<td class="small">Total Received</td>
|
||||||
<td><a href="/#!/address/{{address.addrStr}}">{{address.addrStr}}</a></td>
|
<td class="address ellipsis text-right">{{address.totalReceived}} BTC</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Total Received</td>
|
<td class="small">Total Sent</td>
|
||||||
<td>{{address.totalReceived}} BTC</td>
|
<td class="address ellipsis text-right">{{address.totalSent}} BTC</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Total Sent</td>
|
<td class="small">Final Balance</td>
|
||||||
<td>{{address.totalSent}} BTC</td>
|
<td class="address ellipsis text-right">{{address.balance}} BTC</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Final Balance</td>
|
<td class="small">No. Transactions</td>
|
||||||
<td>{{address.balance}} BTC</td>
|
<td class="address ellipsis text-right">{{address.txApperances}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td>No. Transactions</td>
|
|
||||||
<td>{{address.txApperances}}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div> <!-- END OF TRANSACTIONS TABLE -->
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3">
|
</div> <!-- END OF COL-MD-3 -->
|
||||||
<qrcode size="200" data="{{address.addrStr}}"></qrcode>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-ng-controller="transactionsController" data-ng-init="byAddress(params.addrStr)">
|
<div class="col-md-9">
|
||||||
<h2>Transactions <small>Transactions contained within this block</small></h2>
|
<div data-ng-controller="transactionsController" data-ng-init="load('address')">
|
||||||
<div data-ng-include src="'/views/transaction/list.html'"></div>
|
<h2>Transactions <small>Transactions for this address</small></h2>
|
||||||
|
<div data-ng-include src="'/views/transaction/list.html'" when-scrolled="loadMore()"></div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> <!-- END OF ROW -->
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -1,37 +1,36 @@
|
||||||
<section data-ng-controller="BlocksController" data-ng-init="findOne()">
|
<section data-ng-controller="BlocksController" data-ng-init="findOne()">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<div class="bs-sidebar hidden-print affix col-gray">
|
<div class="bs-sidebar affix col-gray">
|
||||||
<div class="block-id">
|
<div class="block-id">
|
||||||
<div class="icon-block text-center">
|
<div class="icon-block text-center">
|
||||||
<span class="glyphicon glyphicon-list-alt"></span>
|
<span class="glyphicon glyphicon-list-alt"></span>
|
||||||
</div>
|
</div>
|
||||||
<h1 data-ng-if="block">Block #{{ block.height }}</h1>
|
<h3 data-ng-if="block">Block #{{ block.height }}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="m50v" data-ng-show="!tx.isCoinBase">
|
<div class="m50v" data-ng-show="!tx.isCoinBase">
|
||||||
<h4>Hashes</h4>
|
<h4>Hashes</h4>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td> <small>Hash </small></td>
|
<td class="small"> Hash </td>
|
||||||
<td><a class="address ellipsis" href="/#!/block/{{block.hash}}">{{block.hash}}</a></td>
|
<td><a class="address ellipsis" href="/#!/block/{{block.hash}}">{{block.hash}}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><small> Previous Block</small></td>
|
<td class="small"> Previous Block</td>
|
||||||
<td><a class="address ellipsis" href="/#!/block/{{block.previousblockhash}}">{{block.previousblockhash}}</a></td>
|
<td><a class="address ellipsis" href="/#!/block/{{block.previousblockhash}}">{{block.previousblockhash}}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><small> Next Block</small></td>
|
<td class="small"> Next Block</td>
|
||||||
<td><a class="address ellipsis" href="/#!/block/{{block.nextblockhash}}">{{block.nextblockhash}}</a></td>
|
<td><a class="address ellipsis" href="/#!/block/{{block.nextblockhash}}">{{block.nextblockhash}}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><small> Merkle Root</small></td>
|
<td class="small">Merkle Root</td>
|
||||||
<td> <p class="address ellipsis"> {{block.merkleroot}} </p> </td>
|
<td> <p class="address ellipsis"> {{block.merkleroot}} </p> </td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div> <!-- END OF TRANSACTIONS TABLE -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div> <!-- END OF COL-GRAY -->
|
</div> <!-- END OF COL-GRAY -->
|
||||||
|
@ -69,7 +68,7 @@
|
||||||
<td class="text-right text-muted">{{block.bits}}</td>
|
<td class="text-right text-muted">{{block.bits}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td> <strong> Size </strong></td>
|
<td> <strong> Size (bytes) </strong></td>
|
||||||
<td class="text-right text-muted">{{block.size}}</td>
|
<td class="text-right text-muted">{{block.size}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -85,9 +84,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div><!-- END OF ROW -->
|
</div><!-- END OF ROW -->
|
||||||
|
|
||||||
<div data-ng-controller="transactionsController" data-ng-init="byBlock(params.blockHash)">
|
<div data-ng-controller="transactionsController" data-ng-init="load('block')">
|
||||||
<h2>Transactions <small >Transactions contained within this block</small></h2>
|
<h2>Transactions <small >Transactions contained within this block</small></h2>
|
||||||
<div data-ng-include src="'/views/transaction/list.html'"></div>
|
<div data-ng-include src="'/views/transaction/list.html'" when-scrolled="loadMore()"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,20 +1,35 @@
|
||||||
<section data-ng-controller="BlocksController" data-ng-init="list()">
|
<section data-ng-controller="BlocksController" data-ng-init="list()">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="bs-sidebar affix col-gray">
|
||||||
|
<div class="block-id">
|
||||||
|
<div class="icon-block text-center">
|
||||||
|
<span class="glyphicon glyphicon-list"></span>
|
||||||
|
<h3>Blocks <br> mined on:</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="lead text-center m20v">{{pagination.current}}</p>
|
||||||
|
|
||||||
|
<div class="m50v">
|
||||||
|
<a class="btn btn-default" href="#!/blocks-date/{{pagination.prev}}"><small>← {{pagination.prev}}</small></a>
|
||||||
|
<a class="btn btn-primary" href="#!/blocks-date/{{pagination.next}}"><small>{{pagination.next}} →</small></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-8">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>
|
<h1>
|
||||||
<span class="glyphicon glyphicon-calendar"></span>
|
|
||||||
Blocks
|
Blocks
|
||||||
<small>by date</small>
|
<small>by date</small>
|
||||||
</h1>
|
</h1>
|
||||||
<ul class="pagination">
|
|
||||||
<li><a href="#!/blocks-date/{{pagination.prev}}">« {{pagination.prev}}</a></li>
|
|
||||||
<li class="disabled"><a href="#">{{pagination.current}}</a></li>
|
|
||||||
<li><a href="#!/blocks-date/{{pagination.next}}">{{pagination.next}} »</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-striped" ng-show="blocks || blocks.length">
|
<table class="table" data-ng-show="blocks || blocks.length">
|
||||||
<thead>
|
<thead>
|
||||||
|
<tr>
|
||||||
<th>Hash</th>
|
<th>Hash</th>
|
||||||
<th>Solved at</th>
|
<th>Solved at</th>
|
||||||
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr data-ng-repeat="block in blocks">
|
<tr data-ng-repeat="block in blocks">
|
||||||
|
@ -23,5 +38,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<h1 class="text-center text-muted" ng-hide="!blocks || blocks.length">No blocks yet.</h1>
|
</div>
|
||||||
|
</div>
|
||||||
|
<h2 class="text-center text-muted" data-ng-hide="!blocks || blocks.length">No blocks yet.</h2>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -1,10 +1,3 @@
|
||||||
<div data-ng-controller="FooterController" data-ng-init="getFooter()">
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p class="text-muted text-right" data-ng-show="info.blocks">
|
<a class="insight m10v pull-right" href="/"><small>Insight</small></a>
|
||||||
Blocks: {{info.blocks}} |
|
|
||||||
Connections: {{info.connections}} |
|
|
||||||
Difficulty: {{info.difficulty}}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
|
@ -11,28 +11,33 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse navbar-collapse">
|
<div class="collapse navbar-collapse">
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li data-ng-repeat="item in menu" ui-route="/{{item.link}}" ng-class="{active: $uiRoute}">
|
<li data-ng-repeat="item in menu" ui-route="/{{item.link}}" data-ng-class="{active: $uiRoute}">
|
||||||
<a href="#!/{{item.link}}">{{item.title}}</a>
|
<a href="#!/{{item.link}}">{{item.title}}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div ng-controller="SearchController">
|
<div data-ng-controller="SearchController">
|
||||||
<form class="navbar-form navbar-left" role="search" ng-submit="search()">
|
<form class="navbar-form navbar-left" role="search" data-ng-submit="search()">
|
||||||
<div class="form-group" ng-class="{'has-error': badQuery}">
|
<div class="form-group" data-ng-class="{'has-error': badQuery}">
|
||||||
<input id="search" type="text" class="form-control" ng-model="q" placeholder="Search for block, transaction or address">
|
<input id="search" type="text" class="form-control" data-ng-model="q" placeholder="Search for block, transaction or address">
|
||||||
</div>
|
</div>
|
||||||
<span class="text-danger" ng-show="badQuery">No matching records found!</span>
|
<div class="no_matching text-danger" data-ng-show="badQuery">No matching records found!</div>
|
||||||
</form>
|
</form>
|
||||||
<div class="status" data-ng-controller="FooterController" data-ng-init="getFooter()">
|
</div>
|
||||||
<i class="small" data-ng-show="info.blocks">
|
<div class="status" data-ng-controller="StatusController">
|
||||||
<strong>Status:</strong> On Sync
|
<span data-ng-init="getSync()">
|
||||||
</i>
|
<div class="t text-danger" data-ng-show="sync.error" tooltip="{{sync.error}}" tooltip-placement="bottom"> ERROR </div>
|
||||||
|
<div class="t text-warning " tooltip="{{sync.syncedBlocks}} / {{sync.blockChainHeight}} synced. {{sync.skippedBlocks}} skipped" tooltip-placement="bottom" data-ng-show="sync.status==='syncing'"> {{sync.status}} {{sync.syncPercentage}}%</div>
|
||||||
|
<div class="t text-default" tooltip="Historic sync finished" tooltip-placement="bottom" data-ng-show="sync.status==='finished'"> On sync</div>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span data-ng-init="getStatus('Info')">
|
||||||
<i class="small">
|
<i class="small">
|
||||||
<strong> Connections: </strong> {{info.connections}}
|
<strong> Conn: </strong> {{info.connections}}
|
||||||
</i>
|
</i>
|
||||||
<i class="small">
|
<i class="small">
|
||||||
<strong>Height:</strong> {{info.blocks}}
|
<strong>Height:</strong> {{info.blocks}}
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,130 +1,42 @@
|
||||||
<section data-ng-controller="StatusController">
|
<section data-ng-controller="StatusController">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>
|
<h1>
|
||||||
Status
|
Application Status
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div id="status" class="row">
|
||||||
<div class="col-lg-6">
|
<div class="col-md-9">
|
||||||
<h3>getInfo</h3>
|
|
||||||
<table class="table table-striped" data-ng-init="getStatus('Info')">
|
<h4>Sync Status</h4>
|
||||||
|
<table class="table" data-ng-init="getSync()">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr data-ng-show="!info && !infoError">
|
|
||||||
<td colspan="2" class="text-center">Loading...
|
|
||||||
<tr data-ng-show="infoError">
|
|
||||||
<td colspan="2" class="text-danger">{{infoError}}
|
|
||||||
<tr>
|
|
||||||
<td>Version</td>
|
|
||||||
<td>{{info.version}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>protocolversion</td>
|
|
||||||
<td>{{info.protocolversion}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>walletversion</td>
|
|
||||||
<td>{{info.walletversion}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>balance</td>
|
|
||||||
<td>{{info.balance}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>blocks</td>
|
|
||||||
<td>{{info.blocks}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>timeoffset</td>
|
|
||||||
<td>{{info.timeoffset}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>connections</td>
|
|
||||||
<td>{{info.connections}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>proxy</td>
|
|
||||||
<td>{{info.proxy}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>difficulty</td>
|
|
||||||
<td>{{info.difficulty}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>testnet</td>
|
|
||||||
<td>{{info.testnet}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>keypoololdest</td>
|
|
||||||
<td>{{info.keypoololdest}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>keypoolsize</td>
|
|
||||||
<td>{{info.keypoolsize}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>paytxfee</td>
|
|
||||||
<td>{{info.paytxfee}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>infoErrors</td>
|
|
||||||
<td>{{info.infoErrors}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<h3>sync status</h3>
|
|
||||||
<table class="table table-striped" data-ng-init="getSync()">
|
|
||||||
<tbody>
|
|
||||||
<tr data-ng-show="syncError">
|
|
||||||
<td colspan="2"> <span class="text-danger"> {{ syncError }} </span>
|
|
||||||
<tr data-ng-show="sync.error">
|
<tr data-ng-show="sync.error">
|
||||||
<td colspan="2"> <span class="text-danger"> {{ sync.err }} </span>
|
<td colspan="2"> <span class="text-danger"> {{sync.error}} </span>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Sync Progress</td>
|
<td>Sync Progress</td>
|
||||||
<td> {{(100 * sync.syncedBlocks/sync.blocksToSync)| number:2}}%
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>blocksToSync</td>
|
|
||||||
<td>{{sync.blocksToSync}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>syncedBlocks</td>
|
|
||||||
<td>{{sync.syncedBlocks}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>start</td>
|
|
||||||
<td>{{sync.start}}
|
|
||||||
<span data-ng-show="sync.isStartGenesis"> (genesisBlock) </span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>end</td>
|
|
||||||
<td>{{sync.end}}
|
|
||||||
<span data-ng-show="sync.isEndGenesis"> (genesisBlock) </span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Sync Type</td>
|
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<div class="progress">
|
||||||
<li data-ng-show="sync.upToExisting"> <span> Stops at existing block </span>
|
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: {{ sync.syncPercentage}}%">
|
||||||
<li>
|
<span>{{sync.syncPercentage}}% Complete</span>
|
||||||
<span data-ng-show="sync.scanningBackward"> scanningBackward </span>
|
</div>
|
||||||
<span data-ng-hide="sync.scanningBackward"> scanningForward </span>
|
</div>
|
||||||
</ul>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Initial Block Chain Height</td>
|
||||||
|
<td class="text-right">{{sync.blockChainHeight}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Synced Blocks</td>
|
||||||
|
<td class="text-right">{{sync.syncedBlocks}}</td>
|
||||||
|
<tr>
|
||||||
|
<td>Skipped Blocks (previously synced)</td>
|
||||||
|
<td class="text-right">{{sync.skippedBlocks}}</td>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h3>getTxOutSetInfo</h3>
|
<h4>Transaction Output Set Information</h4>
|
||||||
<table class="table table-striped" data-ng-init="getStatus('TxOutSetInfo')">
|
<table class="table" data-ng-init="getStatus('TxOutSetInfo')">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr data-ng-show="!txoutsetinfo && !infoError">
|
<tr data-ng-show="!txoutsetinfo && !infoError">
|
||||||
<td colspan="2" class="text-center">Loading...</td>
|
<td colspan="2" class="text-center">Loading...</td>
|
||||||
|
@ -134,59 +46,37 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Height</td>
|
<td>Height</td>
|
||||||
<td>{{txoutsetinfo.height}}</td>
|
<td class="text-right"><a href="/#!/block-index/{{txoutsetinfo.height}}">{{txoutsetinfo.height}}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>bestblock</td>
|
<td>Best Block</td>
|
||||||
<td>{{txoutsetinfo.bestblock}}</td>
|
<td class="text-right"><a href="/#!/block/{{txoutsetinfo.bestblock}}">{{txoutsetinfo.bestblock}}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>transactions</td>
|
<td>Transactions</td>
|
||||||
<td>{{txoutsetinfo.transactions}}</td>
|
<td class="text-right"> {{txoutsetinfo.transactions}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>txouts</td>
|
<td>Transaction Outputs</td>
|
||||||
<td>{{txoutsetinfo.txouts}}</td>
|
<td class="text-right">{{txoutsetinfo.txouts}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>bytes_serialized</td>
|
<td>Bytes Serialized</td>
|
||||||
<td>{{txoutsetinfo.bytes_serialized}}</td>
|
<td class="text-right">{{txoutsetinfo.bytes_serialized}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>hash_serialized</td>
|
<td>Hash Serialized</td>
|
||||||
<td>{{txoutsetinfo.hash_serialized}}</td>
|
<td class="text-right">{{txoutsetinfo.hash_serialized}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>total_amount</td>
|
<td>Total Amount</td>
|
||||||
<td>{{txoutsetinfo.total_amount}}</td>
|
<td class="text-right">{{txoutsetinfo.total_amount}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
<h4>Last Block</h4>
|
||||||
<div class="col-lg-6">
|
<table class="table" data-ng-init="getStatus('LastBlockHash')">
|
||||||
<h3>getDifficulty</h3>
|
|
||||||
<table class="table table-striped" data-ng-init="getStatus('Difficulty')">
|
|
||||||
<tbody>
|
|
||||||
<tr data-ng-show="!difficulty && !infoError">
|
|
||||||
<td colspan="2" class="text-center">Loading...</td>
|
|
||||||
</tr>
|
|
||||||
<tr data-ng-show="infoError">
|
|
||||||
<td colspan="2" class="text-danger">{{infoError}}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>Difficulty</td>
|
|
||||||
<td>{{difficulty}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<h3>getLastBlockHash</h3>
|
|
||||||
<table class="table table-striped" data-ng-init="getStatus('LastBlockHash')">
|
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr data-ng-show="!lastblockhash && !infoError">
|
<tr data-ng-show="!lastblockhash && !infoError">
|
||||||
<td colspan="2" class="text-center">Loading...</td>
|
<td colspan="2" class="text-center">Loading...</td>
|
||||||
|
@ -196,11 +86,98 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Last block hash</td>
|
<td>Last block hash</td>
|
||||||
<td>{{lastblockhash}}</td>
|
<td class="text-right"><a href="/#!/block/{{lastblockhash}}">{{lastblockhash}}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div> <!-- END OF COL-8 -->
|
||||||
|
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="col-gray">
|
||||||
|
<h4>Bitcoin node information</h4>
|
||||||
|
<table class="table" data-ng-init="getStatus('Info')">
|
||||||
|
<tbody>
|
||||||
|
<tr data-ng-show="!info && !infoError">
|
||||||
|
<td colspan="2" class="text-center">Loading...
|
||||||
|
<tr data-ng-show="infoError">
|
||||||
|
<td colspan="2" class="text-danger">{{infoError}}
|
||||||
|
<tr>
|
||||||
|
<td>Version</td>
|
||||||
|
<td class="text-right">{{info.version}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Protocol version</td>
|
||||||
|
<td class="text-right">{{info.protocolversion}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Wallet version</td>
|
||||||
|
<td class="text-right">{{info.walletversion}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Balance (BTC)</td>
|
||||||
|
<td class="text-right">{{info.balance}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Blocks</td>
|
||||||
|
<td class="text-right"><a href="/#!/block-index/{{info.blocks}}">{{info.blocks}}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Time Offset</td>
|
||||||
|
<td class="text-right">{{info.timeoffset}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Connections to other nodes</td>
|
||||||
|
<td class="text-right">{{info.connections}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Proxy setting</td>
|
||||||
|
<td class="text-right">{{info.proxy}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Mining Difficulty</td>
|
||||||
|
<td class="text-right">{{info.difficulty}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Testnet</td>
|
||||||
|
<td class="text-right">{{info.testnet}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Keypool Oldest Date</td>
|
||||||
|
<td class="text-right">{{info.keypoololdest*1000 | date:'medium' }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Keypool Size</td>
|
||||||
|
<td class="text-right">{{info.keypoolsize}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Default Transaction Fee (BTC)</td>
|
||||||
|
<td class="text-right">{{info.paytxfee}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Info Errors</td>
|
||||||
|
<td class="text-right">{{info.infoErrors}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h4>Difficulty</h4>
|
||||||
|
<table class="table" data-ng-init="getStatus('Difficulty')">
|
||||||
|
<tbody>
|
||||||
|
<tr data-ng-show="!difficulty && !infoError">
|
||||||
|
<td colspan="2" class="text-center">Loading...</td>
|
||||||
|
</tr>
|
||||||
|
<tr data-ng-show="infoError">
|
||||||
|
<td colspan="2" class="text-danger">{{infoError}}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Mining Difficulty</td>
|
||||||
|
<td>{{difficulty}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div> <!-- END OF COL-GRAY -->
|
||||||
|
</div> <!-- END OF COL-3 -->
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
@ -5,72 +5,13 @@
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="block-tx">
|
<div class="block-tx">
|
||||||
<div class="line-bot">
|
<div data-ng-include src="'/views/transaction/tx.html'"></div>
|
||||||
<a href="/#!/tx/{{tx.txid}}">{{tx.txid}}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row m10b">
|
|
||||||
|
|
||||||
<div class="col-md-5">
|
|
||||||
<ul class="list-unstyled" data-ng-repeat="vin in tx.vin" data-ng-show="!tx.isCoinBase">
|
|
||||||
<li>
|
|
||||||
<a class="m10h vm lead glyphicon glyphicon-circle-arrow-left" href="/#!/tx/{{vin.txid}}" alt="Outpoint: {{vin.txid}},{{vin.vout}}" data-toggle="tooltip" title="Outpoint: {{vin.txid}},{{vin.vout}}">
|
|
||||||
</a>
|
|
||||||
<span data-ng-show="!vin.addr">Address could not be parsed</span>
|
|
||||||
<a data-ng-show="vin.addr" href="/#!/address/{{vin.addr}}">{{vin.addr}}</a>
|
|
||||||
<span class="pull-right badge">{{vin.value}} BTC</span>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
<div data-ng-show="tx.isCoinBase">
|
|
||||||
<ul class="list-unstyled" data-ng-repeat="vinn in tx.vin">
|
|
||||||
<li>
|
|
||||||
No Inputs (Newly Generated isCoinBasens)
|
|
||||||
<span class="pull-right badge">{{vinn.reward}} BTC</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-2 text-center">
|
|
||||||
<span class="glyphicon glyphicon-chevron-right lead"></span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-5" data-ng-repeat="vout in tx.vout">
|
|
||||||
<div class="row m10b">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<b>{{vout.scriptPubKey.type}}</b>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-9">
|
|
||||||
<ul class="list-unstyled" data-ng-repeat="addr in vout.scriptPubKey.addresses">
|
|
||||||
<li>
|
|
||||||
<a class="ellipsis pull-left" style="width:200px;" href="/#!/address/{{addr}}">{{addr}}</a>
|
|
||||||
<span class="pull-right badge">{{vout.value}} BTC</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="line-top">
|
|
||||||
<small class="text-muted">Feeds: {{tx.feeds}}</small>
|
|
||||||
<div class="pull-right">
|
|
||||||
<button data-ng-show="tx.confirmations" type="button" class="btn btn-success">
|
|
||||||
{{tx.confirmations}} Confirmations
|
|
||||||
</button>
|
|
||||||
<button data-ng-show="!tx.confirmations" type="button" class="btn btn-danger">
|
|
||||||
Unconfirmed Transaction!
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-primary">{{tx.valueOut}} BTC</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div><!-- END OF BLOCK-TX -->
|
</div><!-- END OF BLOCK-TX -->
|
||||||
|
|
||||||
<div class="row m50v">
|
<div class="row m50v">
|
||||||
<div data-ng-class="{'col-md-6':!tx.isCoinBase}">
|
<div data-ng-class="{'col-md-6':!tx.isCoinBase}">
|
||||||
<h3>Summary</h3>
|
<h3>Summary</h3>
|
||||||
<table class="table">
|
<table class="table" style="table-layout: fixed">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong> Size </strong></td>
|
<td><strong> Size </strong></td>
|
||||||
|
@ -81,9 +22,10 @@
|
||||||
<td class="text-muted text-right">{{tx.time * 1000|date:'medium'}}</td>
|
<td class="text-muted text-right">{{tx.time * 1000|date:'medium'}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>Block </strong></td>
|
<td><strong>Block </strong>
|
||||||
<td class="text-muted text-right"><a href="/#!/block/{{tx.blockhash}}">Block</a></td>
|
<td class="text-right">
|
||||||
</tr>
|
|
||||||
|
<a href="/#!/block/{{tx.blockhash}}" class=" ellipsis">{{tx.blockhash}}</a>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -101,11 +43,12 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>Fees</strong></td>
|
<td><strong>Fees</strong></td>
|
||||||
<td class="text-muted text-right">{{tx.feeds}} BTC</td>
|
<td class="text-muted text-right">{{tx.fees}} BTC</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
@ -1,71 +1,9 @@
|
||||||
<div data-ng-show="!txs || txs.lenght">Loading...</div>
|
<div class="alert alert-warning" data-ng-show="txs.length && !txs[0].txid">There are not transactions</div>
|
||||||
<div class="alert alert-warning" data-ng-show="txs && !txs[0].txid">There are not transactions</div>
|
<div class="block-tx fader" data-ng-show="txs && txs[0].txid" data-ng-repeat="tx in txs">
|
||||||
<div class="block-tx" data-ng-show="txs && txs[0].txid" data-ng-repeat="tx in txs">
|
<div data-ng-include src="'/views/transaction/tx.html'"></div>
|
||||||
<div class="line-bot">
|
|
||||||
<a href="/#!/tx/{{tx.txid}}">{{tx.txid}}</a>
|
|
||||||
<span class="pull-right">{{tx.time * 1000 | date:'medium'}}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-5">
|
|
||||||
<div class="ellipsis row" data-ng-show="tx.isCoinBase" data-ng-repeat="vin in tx.vin">
|
|
||||||
<div class="col-md-10">
|
|
||||||
<p class="ellipsis">No Inputs (Newly Generated isCoinBasens)</p>
|
|
||||||
</div>
|
|
||||||
<p class="text-muted pull-right"> <small>{{vin.reward}} BTC</small></p>
|
|
||||||
</div>
|
|
||||||
<ul class="list-unstyled" data-ng-repeat="vin in tx.vin" data-ng-show="!tx.isCoinBase">
|
|
||||||
<li class="row">
|
|
||||||
<a class="col-md-1 glyphicon glyphicon-circle-arrow-left" href="/#!/tx/{{vin.txid}}" alt="Outpoint: {{vin.txid}},{{vin.vout}}" data-toggle="tooltip" title="Outpoint: {{vin.txid}},{{vin.vout}}">
|
|
||||||
</a>
|
|
||||||
<div class="col-md-8">
|
|
||||||
<div class="ellipsis">
|
|
||||||
<span data-ng-show="!vin.addr">Address could not be parsed</span>
|
|
||||||
<a data-ng-show="vin.addr" href="/#!/address/{{vin.addr}}">{{vin.addr}}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="text-right text-muted"><small>{{vin.value}} BTC</small></p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-1 text-center">
|
|
||||||
<span class="glyphicon glyphicon-arrow-right lead"> </span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div data-ng-repeat="vout in tx.vout">
|
|
||||||
<small data-ng-repeat="address in vout.scriptPubKey.addresses">{{vout.scriptPubKey.type}}</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div data-ng-repeat="vout in tx.vout">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="ellipsis">
|
|
||||||
<a href="/#!/address/{{address}}" data-ng-repeat="address in vout.scriptPubKey.addresses" class="ellipsis">{{address}}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<p class="text-right text-muted"> <small>{{vout.value}} BTC</small></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="line-top">
|
|
||||||
<div class="m5v">
|
|
||||||
<div class="pull-right">
|
|
||||||
<button data-ng-show="tx.confirmations" type="button" class="btn btn-success">
|
|
||||||
{{tx.confirmations}} Confirmations
|
|
||||||
</button>
|
|
||||||
<button data-ng-show="!tx.confirmations" type="button" class="btn btn-danger">
|
|
||||||
Unconfirmed Transaction!
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-primary">{{tx.valueOut}} BTC</button>
|
|
||||||
</div>
|
|
||||||
<small data-ng-show="!tx.isCoinBase" class="text-muted">Feeds: {{tx.feeds}}</small>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="progress progress-striped active" data-ng-show="!txs.length || loading">
|
||||||
|
<div class="progress-bar" style="width: 100%">
|
||||||
|
<span>Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
<div class="line-bot">
|
||||||
|
<a href="/#!/tx/{{tx.txid}}">{{tx.txid}}</a>
|
||||||
|
<a class="pull-right" style="margin-left:10px" data-ng-click="itemsExpanded = !itemsExpanded">
|
||||||
|
<span class="glyphicon" data-ng-class="{'glyphicon-minus-sign': itemsExpanded, 'glyphicon-plus-sign': !itemsExpanded}" tooltip="Show/Hide items details" tooltip-placement="down"></span>
|
||||||
|
</a>
|
||||||
|
<span class="pull-right">{{tx.time * 1000 | date:'medium'}}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-5">
|
||||||
|
<div class="ellipsis row" data-ng-show="tx.isCoinBase" data-ng-repeat="vin in tx.vin">
|
||||||
|
<div class="col-md-10">
|
||||||
|
<p class="ellipsis">No Inputs (Newly Generated Coins)</p>
|
||||||
|
</div>
|
||||||
|
<p class="text-muted pull-right"> <small>{{vin.reward}} BTC</small></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-ng-show="!tx.isCoinBase">
|
||||||
|
<ul class="list-unstyled" data-ng-repeat="vin in tx.vinSimple" data-ng-show="!itemsExpanded">
|
||||||
|
<li class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="ellipsis">
|
||||||
|
<span data-ng-show="vin.notAddr">{{vin.addr}}</span>
|
||||||
|
<a data-ng-show="!vin.notAddr" href="/#!/address/{{vin.addr}}">{{vin.addr}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-right text-muted"><small>{{vin.value}} BTC</small></p>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="list-unstyled" data-ng-repeat="vin in tx.vin" data-ng-show="itemsExpanded">
|
||||||
|
<li class="row expanded-tx">
|
||||||
|
<a class="col-md-1 glyphicon glyphicon-arrow-right" href="/#!/tx/{{vin.txid}}" alt="Outpoint: {{vin.txid}},{{vin.vout}}" tooltip="Outpoint: {{vin.txid}},{{vin.vout}}" tooltip-placement="right" >
|
||||||
|
</a>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="ellipsis">
|
||||||
|
<span data-ng-show="vin.notAddr">{{vin.addr}}</span>
|
||||||
|
<a data-ng-show="!vin.notAddr" href="/#!/address/{{vin.addr}}">{{vin.addr}}</a>
|
||||||
|
</div>
|
||||||
|
<div style="word-wrap:break-word">
|
||||||
|
<small><strong>scriptSig</strong> {{vin.scriptSig.asm}}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-right text-muted"><small>{{vin.value}} BTC</small></p>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-1 text-center">
|
||||||
|
<span class="glyphicon glyphicon-arrow-right lead"> </span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="row">
|
||||||
|
<div data-ng-repeat="vout in tx.voutSimple" data-ng-show="!itemsExpanded">
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="ellipsis">
|
||||||
|
<span data-ng-show="vout.notAddr">{{vout.addr}}</span>
|
||||||
|
<a href="/#!/address/{{address}}" data-ng-show="!vout.notAddr" data-ng-repeat="address in vout.addr.split(',')">{{address}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<p class="text-right text-muted"> <small>{{vout.value}} BTC</small></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div data-ng-repeat="vout in tx.vout" data-ng-show="itemsExpanded">
|
||||||
|
<div class="col-md-9 expanded-tx">
|
||||||
|
<div class="ellipsis">
|
||||||
|
<a href="/#!/address/{{address}}" data-ng-repeat="address in vout.scriptPubKey.addresses">{{address}}</a>
|
||||||
|
</div>
|
||||||
|
<small><strong>type</strong> {{vout.scriptPubKey.type}}</small>
|
||||||
|
<div>
|
||||||
|
<small><strong>scriptPubKey</strong> {{vout.scriptPubKey.asm}}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<p class="text-right text-muted"> <small>{{vout.value}} BTC</small></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="line-top">
|
||||||
|
<div class="m5v">
|
||||||
|
<div class="pull-right">
|
||||||
|
<button data-ng-show="tx.confirmations" type="button" class="btn btn-success">
|
||||||
|
{{tx.confirmations}} Confirmations
|
||||||
|
</button>
|
||||||
|
<button data-ng-show="!tx.confirmations" type="button" class="btn btn-danger">
|
||||||
|
Unconfirmed Transaction!
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-primary">{{tx.valueOut}} BTC</button>
|
||||||
|
</div>
|
||||||
|
<small data-ng-show="!tx.isCoinBase" class="text-muted">Fees: {{tx.fees}}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -33,10 +33,10 @@ async.series([
|
||||||
},
|
},
|
||||||
function(cb) {
|
function(cb) {
|
||||||
if (program.smart) {
|
if (program.smart) {
|
||||||
historicSync.smart_import(cb);
|
historicSync.smartImport(cb);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
historicSync.import_history({
|
historicSync.importHistory({
|
||||||
destroy: program.destroy,
|
destroy: program.destroy,
|
||||||
reverse: program.reverse,
|
reverse: program.reverse,
|
||||||
upToExisting: program.uptoexisting,
|
upToExisting: program.uptoexisting,
|
||||||
|
@ -50,7 +50,7 @@ async.series([
|
||||||
console.log('CRITICAL ERROR: ', err);
|
console.log('CRITICAL ERROR: ', err);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log('Finished.\n Status:\n', historicSync.syncInfo);
|
console.log('Finished.\n Status:\n', historicSync.info());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue