Merge branch 'master' of github.com:bitpay/mystery into feature/p2p-import
Conflicts: app/controllers/transactions.js app/models/Transaction.js config/env/development.js lib/Sync.js test/model/block.js
This commit is contained in:
commit
ead58e1e52
29
Gruntfile.js
29
Gruntfile.js
|
@ -1,6 +1,16 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = function(grunt) {
|
module.exports = function(grunt) {
|
||||||
|
|
||||||
|
|
||||||
|
//Load NPM tasks
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||||
|
grunt.loadNpmTasks('grunt-mocha-test');
|
||||||
|
grunt.loadNpmTasks('grunt-nodemon');
|
||||||
|
grunt.loadNpmTasks('grunt-concurrent');
|
||||||
|
grunt.loadNpmTasks('grunt-env');
|
||||||
|
|
||||||
// Project Configuration
|
// Project Configuration
|
||||||
grunt.initConfig({
|
grunt.initConfig({
|
||||||
pkg: grunt.file.readJSON('package.json'),
|
pkg: grunt.file.readJSON('package.json'),
|
||||||
|
@ -29,6 +39,11 @@ module.exports = function(grunt) {
|
||||||
options: {
|
options: {
|
||||||
livereload: true
|
livereload: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
// we monitor only app/models/* because we have test for models only now
|
||||||
|
files: ['test/**/*.js', 'test/*.js','app/models/*.js'],
|
||||||
|
tasks: ['test'],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
jshint: {
|
jshint: {
|
||||||
|
@ -43,7 +58,7 @@ module.exports = function(grunt) {
|
||||||
options: {
|
options: {
|
||||||
reporter: 'spec',
|
reporter: 'spec',
|
||||||
},
|
},
|
||||||
src: ['test/*.js']
|
src: ['test/**/*.js'],
|
||||||
},
|
},
|
||||||
|
|
||||||
nodemon: {
|
nodemon: {
|
||||||
|
@ -51,9 +66,9 @@ module.exports = function(grunt) {
|
||||||
options: {
|
options: {
|
||||||
file: 'server.js',
|
file: 'server.js',
|
||||||
args: [],
|
args: [],
|
||||||
ignoredFiles: ['public/**'],
|
ignoredFiles: ['public/**', 'test/**'],
|
||||||
watchedExtensions: ['js'],
|
watchedExtensions: ['js'],
|
||||||
nodeArgs: ['--debug'],
|
// nodeArgs: ['--debug'],
|
||||||
delayTime: 1,
|
delayTime: 1,
|
||||||
env: {
|
env: {
|
||||||
PORT: 3000
|
PORT: 3000
|
||||||
|
@ -75,14 +90,6 @@ module.exports = function(grunt) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//Load NPM tasks
|
|
||||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
|
||||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
|
||||||
grunt.loadNpmTasks('grunt-mocha-test');
|
|
||||||
grunt.loadNpmTasks('grunt-nodemon');
|
|
||||||
grunt.loadNpmTasks('grunt-concurrent');
|
|
||||||
grunt.loadNpmTasks('grunt-env');
|
|
||||||
|
|
||||||
//Making grunt default to force in order not to break the project.
|
//Making grunt default to force in order not to break the project.
|
||||||
grunt.option('force', true);
|
grunt.option('force', true);
|
||||||
|
|
||||||
|
|
40
README.md
40
README.md
|
@ -45,26 +45,34 @@ $ npm install -g bower
|
||||||
|
|
||||||
http://localhost:3000
|
http://localhost:3000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
Get bitcore from github repository:
|
|
||||||
$ git clone https://github.com/bitpay/bitcore.git
|
|
||||||
$ cd bitcore
|
|
||||||
$ npm install
|
|
||||||
|
|
||||||
Run sync from mystery repository:
|
|
||||||
$ utils/sync.js
|
|
||||||
|
|
||||||
check utils/sync.js --help for options.
|
|
||||||
|
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
A REST API is provided at /api. The entry points are:
|
A REST API is provided at /api. The entry points are:
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
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 mystery repository. We need to
|
||||||
|
use bitcore from github, not with npm for now:
|
||||||
|
|
||||||
|
$ cd mystery/node_modules
|
||||||
|
|
||||||
|
$ rm -R bitcore
|
||||||
|
|
||||||
|
$ ln -s <path-to-your-clone-repositoy>/bitcore
|
||||||
|
|
||||||
|
Run sync from mystery repository (to save blocks in MongoDB):
|
||||||
|
|
||||||
|
$ utils/sync.js
|
||||||
|
|
||||||
|
Check utils/sync.js --help for options.
|
||||||
|
|
||||||
### Blocks
|
### Blocks
|
||||||
```
|
```
|
||||||
/api/block/[:hash]
|
/api/block/[:hash]
|
||||||
|
|
|
@ -29,41 +29,56 @@ exports.show = function(req, res) {
|
||||||
res.jsonp(req.block);
|
res.jsonp(req.block);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* List of blocks at HomePage
|
|
||||||
*/
|
|
||||||
exports.last_blocks = function(req, res) {
|
|
||||||
Block.find().sort({time:-1}).limit(7).exec(function(err, blocks) {
|
|
||||||
if (err) {
|
|
||||||
res.render('error', {
|
|
||||||
status: 500
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
res.jsonp(blocks);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of blocks by date
|
* List of blocks by date
|
||||||
*/
|
*/
|
||||||
exports.list = function(req, res) {
|
exports.list = function(req, res) {
|
||||||
var findParam = {};
|
//helper to convert timestamps to yyyy-mm-dd format
|
||||||
|
var formatTimestamp = function (date) {
|
||||||
|
var yyyy = date.getUTCFullYear().toString();
|
||||||
|
var mm = (date.getUTCMonth() + 1).toString(); // getMonth() is zero-based
|
||||||
|
var dd = date.getUTCDate().toString();
|
||||||
|
|
||||||
|
return yyyy + '-' + (mm[1] ? mm : '0' + mm[0]) + '-' + (dd[1] ? dd : '0' + dd[0]); //padding
|
||||||
|
};
|
||||||
|
|
||||||
|
var dateStr;
|
||||||
if (req.query.blockDate) {
|
if (req.query.blockDate) {
|
||||||
findParam = {};
|
dateStr = req.query.blockDate;
|
||||||
|
} else {
|
||||||
|
dateStr = formatTimestamp(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var gte = Math.round((new Date(dateStr)).getTime() / 1000);
|
||||||
|
|
||||||
|
//pagination
|
||||||
|
var lte = gte + 86400;
|
||||||
|
var prev = formatTimestamp(new Date((gte - 86400) * 1000));
|
||||||
|
var next = formatTimestamp(new Date(lte * 1000));
|
||||||
|
|
||||||
Block
|
Block
|
||||||
.find(findParam)
|
.find({
|
||||||
.limit(5)
|
time: {
|
||||||
|
'$gte': gte,
|
||||||
|
'$lte': lte
|
||||||
|
}
|
||||||
|
})
|
||||||
.exec(function(err, blocks) {
|
.exec(function(err, blocks) {
|
||||||
if (err) {
|
if (err) {
|
||||||
res.render('error', {
|
res.render('error', {
|
||||||
status: 500
|
status: 500
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.jsonp(blocks);
|
res.jsonp({
|
||||||
|
blocks: blocks,
|
||||||
|
pagination: {
|
||||||
|
next: next,
|
||||||
|
prev: prev,
|
||||||
|
current: dateStr
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,12 @@ var Transaction = require('../models/Transaction');
|
||||||
*/
|
*/
|
||||||
exports.transaction = function(req, res, next, txid) {
|
exports.transaction = function(req, res, next, txid) {
|
||||||
Transaction.fromIdWithInfo(txid, function(err, tx) {
|
Transaction.fromIdWithInfo(txid, function(err, tx) {
|
||||||
if (err) return next(err);
|
if (err) {
|
||||||
|
console.log(err);
|
||||||
|
res.status(404).send('Not found');
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
if (!tx) return next(new Error('Failed to load TX ' + txid));
|
if (!tx) return next(new Error('Failed to load TX ' + txid));
|
||||||
req.transaction = tx.info;
|
req.transaction = tx.info;
|
||||||
next();
|
next();
|
||||||
|
@ -25,9 +30,11 @@ exports.transaction = function(req, res, next, txid) {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show block
|
|
||||||
*/
|
*/
|
||||||
exports.show = function(req, res) {
|
exports.show = function(req, res) {
|
||||||
res.jsonp(req.transaction);
|
|
||||||
|
if (req.transaction) {
|
||||||
|
res.jsonp(req.transaction);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ BlockSchema.statics.fromHash = function(hash, cb) {
|
||||||
BlockSchema.statics.fromHashWithInfo = function(hash, cb) {
|
BlockSchema.statics.fromHashWithInfo = function(hash, cb) {
|
||||||
this.fromHash(hash, function(err, block) {
|
this.fromHash(hash, function(err, block) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
if (!block) { return cb(new Error('Block not found')); }
|
||||||
|
|
||||||
block.getInfo(function(err) { return cb(err,block); } );
|
block.getInfo(function(err) { return cb(err,block); } );
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,10 +3,16 @@
|
||||||
/**
|
/**
|
||||||
* Module dependencies.
|
* Module dependencies.
|
||||||
*/
|
*/
|
||||||
var mongoose = require('mongoose'),
|
|
||||||
Schema = mongoose.Schema,
|
var mongoose = require('mongoose'),
|
||||||
async = require('async'),
|
Schema = mongoose.Schema,
|
||||||
|
async = require('async'),
|
||||||
RpcClient = require('bitcore/RpcClient').class(),
|
RpcClient = require('bitcore/RpcClient').class(),
|
||||||
|
Transaction = require('bitcore/Transaction').class(),
|
||||||
|
Address = require('bitcore/Address').class(),
|
||||||
|
networks = require('bitcore/networks'),
|
||||||
|
util = require('bitcore/util/util'),
|
||||||
|
bignum = require('bignum'),
|
||||||
config = require('../../config/config');
|
config = require('../../config/config');
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,10 +47,15 @@ TransactionSchema.statics.fromId = function(txid, cb) {
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionSchema.statics.fromIdWithInfo = function(txid, cb) {
|
TransactionSchema.statics.fromIdWithInfo = function(txid, cb) {
|
||||||
|
|
||||||
|
// TODO Should we go to mongoDB first? Now, no extra information is stored at mongo.
|
||||||
|
|
||||||
this.fromId(txid, function(err, tx) {
|
this.fromId(txid, function(err, tx) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
tx.getInfo(function(err) { return cb(err,tx); } );
|
if (!tx) { return cb(new Error('TX not found')); }
|
||||||
|
|
||||||
|
tx.queryInfo(function(err) { return cb(err,tx); } );
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -68,18 +79,114 @@ TransactionSchema.statics.createFromArray = function(txs, next) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TransactionSchema.methods.fillInputValues = function (tx, next) {
|
||||||
|
|
||||||
TransactionSchema.methods.getInfo = function (next) {
|
if (tx.isCoinBase()) return next();
|
||||||
|
|
||||||
|
if (! this.rpc) this.rpc = new RpcClient(config.bitcoind);
|
||||||
|
|
||||||
var that = this;
|
var that = this;
|
||||||
var rpc = new RpcClient(config.bitcoind);
|
async.each(tx.ins, function(i, cb) {
|
||||||
|
|
||||||
rpc.getRawTransaction(this.txid, 1, function(err, txInfo) {
|
var outHash = i.getOutpointHash();
|
||||||
|
var outIndex = i.getOutpointIndex();
|
||||||
|
var outHashBase64 = outHash.reverse().toString('hex');
|
||||||
|
|
||||||
|
var c=0;
|
||||||
|
that.rpc.getRawTransaction(outHashBase64, function(err, txdata) {
|
||||||
|
var txin = new Transaction();
|
||||||
|
|
||||||
|
if (err || ! txdata.result) return cb( new Error('Input TX '+outHashBase64+' not found'));
|
||||||
|
|
||||||
|
var b = new Buffer(txdata.result,'hex');
|
||||||
|
txin.parse(b);
|
||||||
|
|
||||||
|
|
||||||
|
if ( txin.isCoinBase() ) {
|
||||||
|
return cb();
|
||||||
|
}
|
||||||
|
|
||||||
|
txin.outs.forEach( function(j) {
|
||||||
|
// console.log( c + ': ' + util.formatValue(j.v) );
|
||||||
|
if (c === outIndex) {
|
||||||
|
i.value = j.v;
|
||||||
|
}
|
||||||
|
c++;
|
||||||
|
});
|
||||||
|
return cb();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function(err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
TransactionSchema.methods.queryInfo = function (next) {
|
||||||
|
|
||||||
|
var that = this;
|
||||||
|
var network = ( config.network === 'testnet') ? networks.testnet : networks.livenet ;
|
||||||
|
this.rpc = new RpcClient(config.bitcoind);
|
||||||
|
|
||||||
|
|
||||||
|
this.rpc.getRawTransaction(this.txid, 1, function(err, txInfo) {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
|
|
||||||
that.info = txInfo.result;
|
that.info = txInfo.result;
|
||||||
|
|
||||||
//console.log("THAT", that);
|
// Transaction parsing
|
||||||
return next(null, that.info);
|
var b = new Buffer(txInfo.result.hex,'hex');
|
||||||
|
var tx = new Transaction();
|
||||||
|
tx.parse(b);
|
||||||
|
|
||||||
|
that.fillInputValues(tx, function(err) {
|
||||||
|
|
||||||
|
// Copy TX relevant values to .info
|
||||||
|
|
||||||
|
var c = 0;
|
||||||
|
|
||||||
|
|
||||||
|
var valueIn = bignum(0);
|
||||||
|
var valueOut = bignum(0);
|
||||||
|
|
||||||
|
if ( tx.isCoinBase() ) {
|
||||||
|
that.info.isCoinBase = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tx.ins.forEach(function(i) {
|
||||||
|
|
||||||
|
that.info.vin[c].value = util.formatValue(i.value);
|
||||||
|
var n = util.valueToBigInt(i.value).toNumber();
|
||||||
|
valueIn = valueIn.add( n );
|
||||||
|
|
||||||
|
var scriptSig = i.getScript();
|
||||||
|
var pubKey = scriptSig.simpleInPubKey();
|
||||||
|
var pubKeyHash = util.sha256ripe160(pubKey);
|
||||||
|
var addr = new Address(network.addressPubkey, pubKeyHash);
|
||||||
|
var addrStr = addr.toString();
|
||||||
|
|
||||||
|
that.info.vin[c].addr = addrStr;
|
||||||
|
|
||||||
|
c++;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.outs.forEach( function(i) {
|
||||||
|
var n = util.valueToBigInt(i.v).toNumber();
|
||||||
|
valueOut = valueOut.add(n);
|
||||||
|
});
|
||||||
|
|
||||||
|
that.info.valueOut = valueOut / util.COIN;
|
||||||
|
|
||||||
|
if ( !tx.isCoinBase() ) {
|
||||||
|
that.info.valueIn = valueIn / util.COIN;
|
||||||
|
that.info.feeds = (valueIn - valueOut) / util.COIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
that.info.size = b.length;
|
||||||
|
|
||||||
|
return next(err, that.info);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ script(type='text/javascript', src='/lib/angular/angular.js')
|
||||||
script(type='text/javascript', src='/lib/angular-cookies/angular-cookies.js')
|
script(type='text/javascript', src='/lib/angular-cookies/angular-cookies.js')
|
||||||
script(type='text/javascript', src='/lib/angular-resource/angular-resource.js')
|
script(type='text/javascript', src='/lib/angular-resource/angular-resource.js')
|
||||||
script(type='text/javascript', src='/lib/angular-route/angular-route.js')
|
script(type='text/javascript', src='/lib/angular-route/angular-route.js')
|
||||||
|
script(type='text/javascript', src='/lib/qrcode-generator/js/qrcode.js')
|
||||||
|
script(type='text/javascript', src='/lib/angular-qrcode/qrcode.js')
|
||||||
|
|
||||||
//Angular UI
|
//Angular UI
|
||||||
script(type='text/javascript', src='/lib/angular-bootstrap/ui-bootstrap.js')
|
script(type='text/javascript', src='/lib/angular-bootstrap/ui-bootstrap.js')
|
||||||
|
@ -23,6 +25,7 @@ script(type='text/javascript', src='/js/directives.js')
|
||||||
script(type='text/javascript', src='/js/filters.js')
|
script(type='text/javascript', src='/js/filters.js')
|
||||||
|
|
||||||
//Application Services
|
//Application Services
|
||||||
|
script(type='text/javascript', src='/js/services/transactions.js')
|
||||||
script(type='text/javascript', src='/js/services/blocks.js')
|
script(type='text/javascript', src='/js/services/blocks.js')
|
||||||
script(type='text/javascript', src='/js/services/global.js')
|
script(type='text/javascript', src='/js/services/global.js')
|
||||||
script(type='text/javascript', src='/js/services/index.js')
|
script(type='text/javascript', src='/js/services/index.js')
|
||||||
|
@ -31,4 +34,6 @@ script(type='text/javascript', src='/js/services/index.js')
|
||||||
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/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/address.js')
|
||||||
script(type='text/javascript', src='/js/init.js')
|
script(type='text/javascript', src='/js/init.js')
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"angular-route": "latest",
|
"angular-route": "latest",
|
||||||
"bootstrap": "3.0.3",
|
"bootstrap": "3.0.3",
|
||||||
"angular-bootstrap": "0.9.0",
|
"angular-bootstrap": "0.9.0",
|
||||||
"angular-ui-utils": "0.1.0"
|
"angular-ui-utils": "0.1.0",
|
||||||
|
"angular-qrcode": "latest"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,5 +11,6 @@ module.exports = {
|
||||||
protocol: 'http',
|
protocol: 'http',
|
||||||
host: process.env.BITCOIND_HOST || '127.0.0.1',
|
host: process.env.BITCOIND_HOST || '127.0.0.1',
|
||||||
port: process.env.BITCOIND_PORT || '18332',
|
port: process.env.BITCOIND_PORT || '18332',
|
||||||
}
|
},
|
||||||
|
network: 'testnet',
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
db: "mongodb://localhost/mystery-test",
|
db: "mongodb://localhost/mystery-dev",
|
||||||
port: 3001,
|
|
||||||
app: {
|
app: {
|
||||||
name: "Mystery - Test"
|
name: "Mystery - Test"
|
||||||
}
|
},
|
||||||
|
bitcoind: {
|
||||||
|
user: 'mystery',
|
||||||
|
pass: 'real_mystery',
|
||||||
|
protocol: 'http',
|
||||||
|
host: process.env.BITCOIND_HOST || '127.0.0.1',
|
||||||
|
port: process.env.BITCOIND_PORT || '8332',
|
||||||
|
},
|
||||||
|
network: 'testnet',
|
||||||
}
|
}
|
|
@ -9,12 +9,13 @@ module.exports = function(app) {
|
||||||
//Block routes
|
//Block routes
|
||||||
var blocks = require('../app/controllers/blocks');
|
var blocks = require('../app/controllers/blocks');
|
||||||
app.get('/api/blocks', blocks.list);
|
app.get('/api/blocks', blocks.list);
|
||||||
|
|
||||||
|
|
||||||
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('/last_blocks', blocks.last_blocks);
|
|
||||||
|
|
||||||
var transactions = require('../app/controllers/transactions');
|
var transactions = require('../app/controllers/transactions');
|
||||||
app.get('/tx/:txid', transactions.show);
|
app.get('/api/tx/:txid', transactions.show);
|
||||||
|
|
||||||
app.param('txid', transactions.transaction);
|
app.param('txid', transactions.transaction);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@ server=1
|
||||||
txindex=1
|
txindex=1
|
||||||
|
|
||||||
# Allow connections outsite localhost?
|
# Allow connections outsite localhost?
|
||||||
# rpcallowip=192.168.0.*
|
rpcallowip=192.168.1.*
|
||||||
|
rpcallowip='192.168.1.*'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
"async": "*",
|
"async": "*",
|
||||||
"classtool": "*",
|
"classtool": "*",
|
||||||
"commander": "*",
|
"commander": "*",
|
||||||
|
"bignum": "*",
|
||||||
"express": "~3.4.7",
|
"express": "~3.4.7",
|
||||||
"jade": "~1.0.2",
|
"jade": "~1.0.2",
|
||||||
"mongoose": "~3.8.3",
|
"mongoose": "~3.8.3",
|
||||||
|
|
|
@ -40,6 +40,11 @@ body {
|
||||||
padding-right: 15px;
|
padding-right: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
.code {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.address {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('mystery', ['ngCookies', 'ngResource', 'ngRoute', 'ui.bootstrap', 'ui.route', 'mystery.system', 'mystery.index', 'mystery.blocks']);
|
angular.module('mystery', ['ngCookies', 'ngResource', 'ngRoute', 'ui.bootstrap', 'ui.route', 'mystery.system', 'mystery.index', 'mystery.blocks', 'mystery.transactions', 'monospaced.qrcode', 'mystery.address']);
|
||||||
|
|
||||||
angular.module('mystery.system', []);
|
angular.module('mystery.system', []);
|
||||||
angular.module('mystery.index', []);
|
angular.module('mystery.index', []);
|
||||||
angular.module('mystery.blocks', []);
|
angular.module('mystery.blocks', []);
|
||||||
|
angular.module('mystery.transactions', []);
|
||||||
|
angular.module('mystery.address', []);
|
||||||
|
|
|
@ -7,6 +7,9 @@ angular.module('mystery').config(['$routeProvider',
|
||||||
when('/block/:blockHash', {
|
when('/block/:blockHash', {
|
||||||
templateUrl: 'views/block.html'
|
templateUrl: 'views/block.html'
|
||||||
}).
|
}).
|
||||||
|
when('/tx/:txId', {
|
||||||
|
templateUrl: 'views/transaction.html'
|
||||||
|
}).
|
||||||
when('/', {
|
when('/', {
|
||||||
templateUrl: 'views/index.html'
|
templateUrl: 'views/index.html'
|
||||||
}).
|
}).
|
||||||
|
@ -14,7 +17,10 @@ angular.module('mystery').config(['$routeProvider',
|
||||||
templateUrl: 'views/blocks/list.html'
|
templateUrl: 'views/blocks/list.html'
|
||||||
}).
|
}).
|
||||||
when('/blocks-date/:blockDate', {
|
when('/blocks-date/:blockDate', {
|
||||||
templateUrl: 'views/blocks/list_date.html'
|
templateUrl: 'views/blocks/list.html'
|
||||||
|
}).
|
||||||
|
when('/address/:address', {
|
||||||
|
templateUrl: 'views/address.html'
|
||||||
}).
|
}).
|
||||||
otherwise({
|
otherwise({
|
||||||
redirectTo: '/'
|
redirectTo: '/'
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('mystery.address').controller('AddressController', ['$scope', function ($scope) {
|
||||||
|
|
||||||
|
//example data
|
||||||
|
$scope.address = '1JmTTDcksW7A6GN7JnxuXkMAXsVN9zmgm1';
|
||||||
|
$scope.hash160 = '77ad7d08aaa9cf489ea4e468eaeb892b85f71e27';
|
||||||
|
$scope.transactions = [
|
||||||
|
{
|
||||||
|
hash: '49a1d01759690476dbeec4a8efd969c09c6d4269ea2d88f4d9d4f098f021413c',
|
||||||
|
time: 1234123445,
|
||||||
|
amount: 0.3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
hash: 'cce948b422a4d485900fb82e64458720eb89f545af3f07ddf7d18660f9f881e9',
|
||||||
|
time: 1234123445,
|
||||||
|
amount: 0.1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}]);
|
|
@ -3,17 +3,12 @@
|
||||||
angular.module('mystery.blocks').controller('BlocksController', ['$scope', '$routeParams', '$location', 'Global', 'Block', 'Blocks', function ($scope, $routeParams, $location, Global, Block, Blocks) {
|
angular.module('mystery.blocks').controller('BlocksController', ['$scope', '$routeParams', '$location', 'Global', 'Block', 'Blocks', function ($scope, $routeParams, $location, Global, Block, Blocks) {
|
||||||
$scope.global = Global;
|
$scope.global = Global;
|
||||||
|
|
||||||
$scope.list_blocks = function() {
|
$scope.list = function() {
|
||||||
Blocks.query(function(blocks) {
|
Blocks.get({
|
||||||
$scope.blocks = blocks;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.list_blocks_date = function() {
|
|
||||||
Blocks.query({
|
|
||||||
blockDate: $routeParams.blockDate
|
blockDate: $routeParams.blockDate
|
||||||
}, function(blocks) {
|
}, function(res) {
|
||||||
$scope.blocks = blocks;
|
$scope.blocks = res.blocks;
|
||||||
|
$scope.pagination = res.pagination;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,5 @@
|
||||||
|
|
||||||
angular.module('mystery.system').controller('IndexController', ['$scope', 'Global', 'Index', function ($scope, Global, Index) {
|
angular.module('mystery.system').controller('IndexController', ['$scope', 'Global', 'Index', function ($scope, Global, Index) {
|
||||||
$scope.global = Global;
|
$scope.global = Global;
|
||||||
$scope.last_blocks = function() {
|
$scope.index = Index;
|
||||||
Index.query(function(blocks) {
|
|
||||||
$scope.blocks = blocks;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('mystery.transactions').controller('transactionsController', ['$scope', '$routeParams', '$location', 'Global', 'Transaction', function ($scope, $routeParams, $location, Global, Transaction) {
|
||||||
|
$scope.global = Global;
|
||||||
|
|
||||||
|
$scope.findOne = function() {
|
||||||
|
Transaction.get({
|
||||||
|
txId: $routeParams.txId
|
||||||
|
}, function(tx) {
|
||||||
|
$scope.tx = tx;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}]);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('mystery.index').factory('Index', ['$resource', function($resource) {
|
angular.module('mystery.index').factory('Index', ['$resource', function($resource) {
|
||||||
return $resource('/last_blocks');
|
return $resource;
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('mystery.transactions').factory('Transaction', ['$resource', function($resource) {
|
||||||
|
return $resource('/api/tx/:txId', {
|
||||||
|
txId: '@txId'
|
||||||
|
});
|
||||||
|
}]);
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
<section data-ng-controller="AddressController">
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>
|
||||||
|
Address
|
||||||
|
<small>{{address}}</small>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-9">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Address</td>
|
||||||
|
<td><a href="#!/address/{{address}}">{{address}}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Hash160</td>
|
||||||
|
<td><a href="#!/address/{{hash160}}">{{hash160}}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Total Output</td>
|
||||||
|
<td>1 BTC</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Total Input</td>
|
||||||
|
<td>0.2 BTC</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Current balance</td>
|
||||||
|
<td>10.2 BTC</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-3">
|
||||||
|
<qrcode size="200" data="{{address}}"></qrcode>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<h3>
|
||||||
|
Transactions
|
||||||
|
<small>transactions this address relates to</small>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Transaction Hash</th>
|
||||||
|
<th>Datetime</th>
|
||||||
|
<th>Transacted amount</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr data-ng-repeat="transaction in transactions">
|
||||||
|
<td><a href="#!/tx/{{transaction.hash}}">{{transaction.hash}}</a></td>
|
||||||
|
<td>{{transaction.time | date:'medium'}}</td>
|
||||||
|
<td>{{transaction.amount}} BTC</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
|
@ -1,23 +1,114 @@
|
||||||
<section data-ng-controller="BlocksController" data-ng-init="findOne()">
|
<section data-ng-controller="BlocksController" data-ng-init="findOne()">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>Block Page</h1>
|
<h1 data-ng-if="block">Block #{{ block.height }}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">Summary</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Number Of Transactions</td>
|
||||||
|
<td>--</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Output Total</td>
|
||||||
|
<td>--</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Estimated Transaction Volume</td>
|
||||||
|
<td>--</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Transaction Fees</td>
|
||||||
|
<td>--</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Height</td>
|
||||||
|
<td>{{block.height}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Timestamp</td>
|
||||||
|
<td>{{block.time * 1000 | date:'medium'}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Received Time</td>
|
||||||
|
<td>--<td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Relayed By</td>
|
||||||
|
<td>--</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Difficulty</td>
|
||||||
|
<td>{{block.difficulty}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Bits</td>
|
||||||
|
<td>{{block.bits}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Size</td>
|
||||||
|
<td>{{block.size}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Version</td>
|
||||||
|
<td>{{block.version}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Nonce</td>
|
||||||
|
<td>{{block.nonce}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="panel panel-default" data-ng-show="!tx.isCoinBase">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">Hashes</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Hash</td>
|
||||||
|
<td><a class="address" href="/#!/block/{{block.hash}}">{{block.hash}}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Previous Block</td>
|
||||||
|
<td><a class="address" href="/#!/block/{{block.previousblockhash}}">{{block.previousblockhash}}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Next Block</td>
|
||||||
|
<td><a class="address" href="/#!/block/{{block.nextblockhash}}">{{block.nextblockhash}}</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Merkle Root</td>
|
||||||
|
<td class="address">{{block.merkleroot}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Transactions <small>Transactions contained within this block</small></h2>
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<th>Height</th>
|
<th>Hash</th>
|
||||||
<th>Age</th>
|
|
||||||
<th>Transactions</th>
|
|
||||||
<th>Confirmations</th>
|
|
||||||
<th>Size (kB)</th>
|
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr data-ng-repeat="tx in block.tx">
|
||||||
<td>{{block.height}}</td>
|
<td><a href="/#!/tx/{{tx}}">{{tx}}</a></td>
|
||||||
<td>{{block.time | date:'short'}}</td>
|
</tr>
|
||||||
<td>{{block.tx.length }}</td>
|
|
||||||
<td>{{block.confirmations}}</td>
|
|
||||||
<td>{{block.size / 1024}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
|
@ -1,10 +1,26 @@
|
||||||
<section data-ng-controller="BlocksController" data-ng-init="list_blocks()">
|
<section data-ng-controller="BlocksController" data-ng-init="list()">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>Blocks by Date</h1>
|
<h1>
|
||||||
|
<span class="glyphicon glyphicon-calendar"></span>
|
||||||
|
Blocks
|
||||||
|
<small>by date</small>
|
||||||
|
</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>
|
||||||
<ul>
|
<table class="table table-striped">
|
||||||
<li data-ng-repeat="block in blocks">
|
<thead>
|
||||||
<span>{{block.hash}}</span> {{block.time}}
|
<th>Hash</th>
|
||||||
</li>
|
<th>Solved at</th>
|
||||||
</ul>
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr data-ng-repeat="block in blocks">
|
||||||
|
<td><a href="#!/block/{{block.hash}}">{{block.hash}}</a></td>
|
||||||
|
<td>{{block.time * 1000 | date:'medium'}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</section>
|
</section>
|
|
@ -1,10 +0,0 @@
|
||||||
<section data-ng-controller="BlocksController" data-ng-init="list_blocks_date()">
|
|
||||||
<div class="page-header">
|
|
||||||
<h1>Blocks by defined date</h1>
|
|
||||||
</div>
|
|
||||||
<ul>
|
|
||||||
<li data-ng-repeat="block in blocks">
|
|
||||||
<span>{{block.hash}}</span> {{block.time}}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
|
@ -1,23 +1,8 @@
|
||||||
<section data-ng-controller="IndexController" data-ng-init="last_blocks()">
|
<section data-ng-controller="IndexController" data-ng-init="last_blocks()">
|
||||||
<div class="page-header">
|
<div class="jumbotron">
|
||||||
<h1>Hello BitPay!</h1>
|
<h1>Hello, BitPay!</h1>
|
||||||
|
<p>Start here for blocks information</p>
|
||||||
|
<p><a href="/#!/blocks" class="btn btn-primary btn-lg">List all blocks</a></p>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-striped">
|
|
||||||
<thead>
|
|
||||||
<th>Height</th>
|
|
||||||
<th>Age</th>
|
|
||||||
<th>Transactions</th>
|
|
||||||
<th>Confirmations</th>
|
|
||||||
<th>Size (kB)</th>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr data-ng-repeat="block in blocks">
|
|
||||||
<td><a href="#!/block/{{block.hash}}">{{block.height}}</a></td>
|
|
||||||
<td>{{block.time | date:'short'}}</td>
|
|
||||||
<td>{{block.tx.length }}</td>
|
|
||||||
<td>{{block.confirmations}}</td>
|
|
||||||
<td>{{block.size / 1024}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
<section data-ng-controller="transactionsController" data-ng-init="findOne()">
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>
|
||||||
|
Transaction
|
||||||
|
<small>View information about a bitcoin transaction</small>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="well well-sm">
|
||||||
|
{{tx.txid}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Input</th>
|
||||||
|
<th> </th>
|
||||||
|
<th>Output</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td width="45%">
|
||||||
|
<ul class="list-unstyled" data-ng-repeat="vin in tx.vin" data-ng-show="!tx.isCoinBase">
|
||||||
|
<li><a href="/#!/address/{{vin.addr}}">{{vin.addr}}</a> <span class="pull-right badge">{{vin.value}} BTC</span></li>
|
||||||
|
</ul>
|
||||||
|
<div data-ng-show="tx.isCoinBase">
|
||||||
|
No Inputs (Newly Generated isCoinBasens)
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td width="10%" style="text-align: center;"><span class="glyphicon glyphicon-chevron-right"> </span></td>
|
||||||
|
<td width="45%">
|
||||||
|
<div data-ng-repeat="vout in tx.vout">
|
||||||
|
<ul class="list-unstyled" data-ng-repeat="addr in vout.scriptPubKey.addresses">
|
||||||
|
<li><a href="/#!/address/{{addr}}">{{addr}}</a> <span class="pull-right badge">{{vout.value}} BTC</span></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3" style="text-align: right;">
|
||||||
|
<button type="button" class="btn btn-primary">{{tx.confirmations}} Confirmations</button>
|
||||||
|
<button type="button" class="btn btn-success">{{tx.valueOut}} BTC</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">Summary</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Size</td>
|
||||||
|
<td>{{tx.size}} (bytes)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Received Time</td>
|
||||||
|
<td>{{tx.time * 1000|date:'medium'}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Reward From Block</td>
|
||||||
|
<td><a href="/#!/block/{{tx.blockhash}}">Need height to show (it links to block page)</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="panel panel-default" data-ng-show="!tx.isCoinBase">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">Inputs and Outputs</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Total Input</td>
|
||||||
|
<td>{{tx.valueIn}} BTC</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Total Output</td>
|
||||||
|
<td>{{tx.valueOut}} BTC</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Fees</td>
|
||||||
|
<td>{{tx.feeds}} BTC</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||||
|
|
||||||
|
|
||||||
var TESTING_BLOCK = '0000000000b6288775bbd326bedf324ca8717a15191da58391535408205aada4';
|
var TESTING_BLOCK = '000000000185678d3d7ecc9962c96418174431f93fe20bf216d5565272423f74';
|
||||||
|
|
||||||
var
|
var
|
||||||
mongoose= require('mongoose'),
|
mongoose= require('mongoose'),
|
||||||
|
@ -14,12 +14,17 @@ var
|
||||||
|
|
||||||
mongoose.connection.on('error', function(err) { console.log(err); });
|
mongoose.connection.on('error', function(err) { console.log(err); });
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
describe('Block getInfo', function(){
|
describe('Block getInfo', function(){
|
||||||
|
=======
|
||||||
|
describe('Block fromHashWithInfo', function(){
|
||||||
|
>>>>>>> fd86e6d074c5aa4642172b221b9e6f69f3fd8634
|
||||||
|
|
||||||
before(function(done) {
|
before(function(done) {
|
||||||
mongoose.connect(config.db);
|
mongoose.connect(config.db);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
after(function(done) {
|
after(function(done) {
|
||||||
mongoose.connection.close();
|
mongoose.connection.close();
|
||||||
|
@ -34,12 +39,34 @@ describe('Block getInfo', function(){
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
=======
|
||||||
|
|
||||||
|
after(function(done) {
|
||||||
|
mongoose.connection.close();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should poll block\'s info from mongoose', function(done) {
|
||||||
|
var block2 = Block.fromHashWithInfo(TESTING_BLOCK, function(err, b2) {
|
||||||
|
if (err) done(err);
|
||||||
|
|
||||||
|
assert.equal(b2.hash, TESTING_BLOCK);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
>>>>>>> fd86e6d074c5aa4642172b221b9e6f69f3fd8634
|
||||||
|
|
||||||
it('should poll block\'s info from bitcoind', function(done) {
|
it('should poll block\'s info from bitcoind', function(done) {
|
||||||
var block2 = Block.fromHashWithInfo(TESTING_BLOCK, function(err, b2) {
|
var block2 = Block.fromHashWithInfo(TESTING_BLOCK, function(err, b2) {
|
||||||
if (err) done(err);
|
if (err) done(err);
|
||||||
assert.equal(b2.info.hash, TESTING_BLOCK);
|
assert.equal(b2.info.hash, TESTING_BLOCK);
|
||||||
|
<<<<<<< HEAD
|
||||||
assert.equal(b2.info.chainwork, '00000000000000000000000000000000000000000000000000446af21d50acd3');
|
assert.equal(b2.info.chainwork, '00000000000000000000000000000000000000000000000000446af21d50acd3');
|
||||||
|
=======
|
||||||
|
assert.equal(b2.info.chainwork, '000000000000000000000000000000000000000000000000001b6dc969ffe847');
|
||||||
|
>>>>>>> fd86e6d074c5aa4642172b221b9e6f69f3fd8634
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var
|
||||||
|
mongoose= require('mongoose'),
|
||||||
|
assert = require('assert'),
|
||||||
|
config = require('../../config/config'),
|
||||||
|
Transaction = require('../../app/models/Transaction');
|
||||||
|
|
||||||
|
|
||||||
|
mongoose.connection.on('error', function(err) { console.log(err); });
|
||||||
|
|
||||||
|
describe('Transaction fromIdWithInfo', function(){
|
||||||
|
|
||||||
|
before(function(done) {
|
||||||
|
mongoose.connect(config.db);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function(done) {
|
||||||
|
mongoose.connection.close();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pool tx\'s object from mongoose', function(done) {
|
||||||
|
var test_txid = '21798ddc9664ac0ef618f52b151dda82dafaf2e26d2bbef6cdaf55a6957ca237';
|
||||||
|
Transaction.fromIdWithInfo(test_txid, function(err, tx) {
|
||||||
|
if (err) done(err);
|
||||||
|
assert.equal(tx.txid, test_txid);
|
||||||
|
assert(!tx.info.isCoinBase);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pool tx\'s info from bitcoind', function(done) {
|
||||||
|
var test_txid = '21798ddc9664ac0ef618f52b151dda82dafaf2e26d2bbef6cdaf55a6957ca237';
|
||||||
|
Transaction.fromIdWithInfo(test_txid, function(err, tx) {
|
||||||
|
if (err) done(err);
|
||||||
|
assert.equal(tx.info.txid, test_txid);
|
||||||
|
assert.equal(tx.info.blockhash, '000000000185678d3d7ecc9962c96418174431f93fe20bf216d5565272423f74');
|
||||||
|
assert.equal(tx.info.valueOut, 1.66174);
|
||||||
|
assert.equal(tx.info.feeds, 0.0005 );
|
||||||
|
assert.equal(tx.info.size, 226 );
|
||||||
|
assert(!tx.info.isCoinBase);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('test a coinbase TX', function(done) {
|
||||||
|
var test_txid2 = '2a104bab1782e9b6445583296d4a0ecc8af304e4769ceb64b890e8219c562399';
|
||||||
|
Transaction.fromIdWithInfo(test_txid2, function(err, tx) {
|
||||||
|
if (err) done(err);
|
||||||
|
assert(tx.info.isCoinBase);
|
||||||
|
assert.equal(tx.info.txid, test_txid2);
|
||||||
|
assert(!tx.info.feeds);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue