optimize fields in mongo for better storage

This commit is contained in:
Matias Alejo Garcia 2014-01-27 17:10:03 -03:00
parent 243f22381d
commit 7607651fd7
6 changed files with 112 additions and 47 deletions

View File

@ -37,13 +37,13 @@ exports.show = function(req, res) {
* Show block by Height * Show block by Height
*/ */
exports.blockindex = function(req, res, next, height) { exports.blockindex = function(req, res, next, height) {
Block.fromHeight(height, function(err, hash) { Block.blockIndex(height, function(err, hashStr) {
if (err) { if (err) {
console.log(err); console.log(err);
res.status(400).send('Bad Request'); // TODO res.status(400).send('Bad Request'); // TODO
} }
else { else {
res.jsonp(hash); res.jsonp(hashStr);
} }
}); });
}; };

View File

@ -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}).exec(function(err,txItems){
if (err) return cb(err); if (err) return cb(err);
txItems.forEach(function(txItem){ txItems.forEach(function(txItem){

View File

@ -8,7 +8,6 @@ var mongoose = require('mongoose'),
RpcClient = require('bitcore/RpcClient').class(), RpcClient = require('bitcore/RpcClient').class(),
util = require('bitcore/util/util'), util = require('bitcore/util/util'),
BitcoreBlock= require('bitcore/Block').class(), BitcoreBlock= require('bitcore/Block').class(),
Transaction = require('./Transaction').class(),
TransactionItem = require('./TransactionItem'), TransactionItem = require('./TransactionItem'),
config = require('../../config/config') config = require('../../config/config')
; ;
@ -21,19 +20,53 @@ var BlockSchema = new Schema({
// For now we keep this as short as possible // For now we keep this as short as possible
// More fields will be propably added as we move // More fields will be propably added as we move
// forward with the UX // forward with the UX
hash: { _id: {
type: String, type: Buffer,
index: true, index: true,
unique: true, unique: true,
required: true,
}, },
time: Number, time: Number,
nextBlockHash: String, nextBlockHash: Buffer,
isOrphan: Boolean, isOrphan: Boolean,
}); });
/** BlockSchema.virtual('hash').get(function () {
* Validations return this._id;
*/ });
BlockSchema.virtual('hash').set(function (hash) {
this._id = hash;
});
BlockSchema.virtual('hashStr').get(function () {
return this._id.toString('hex');
});
BlockSchema.virtual('hashStr').set(function (hashStr) {
if (hashStr)
this._id = new Buffer(hashStr,'hex');
else
this._id = null;
});
BlockSchema.virtual('nextBlockHashStr').get(function () {
return this.nextBlockHash.toString('hex');
});
BlockSchema.virtual('nextBlockHashStr').set(function (hashStr) {
if (hashStr)
this.nextBlockHash = new Buffer(hashStr,'hex');
else
this.nextBlockHash = null;
});
/* /*
BlockSchema.path('title').validate(function(title) { BlockSchema.path('title').validate(function(title) {
@ -54,9 +87,8 @@ BlockSchema.statics.customCreate = function(block, cb) {
var newBlock = new That(); var newBlock = new That();
newBlock.time = block.time ? block.time : Math.round(new Date().getTime() / 1000); newBlock.time = block.time ? block.time : Math.round(new Date().getTime() / 1000);
newBlock.hash = block.hash; newBlock.hashStr = block.hash;
newBlock.nextBlockHash = block.nextBlockHash; newBlock.nextBlockHashStr = block.nextBlockHash;
TransactionItem.createFromArray(block.tx, function(err, inserted_txs) { TransactionItem.createFromArray(block.tx, function(err, inserted_txs) {
if (err) return cb(err); if (err) return cb(err);
@ -67,40 +99,38 @@ BlockSchema.statics.customCreate = function(block, cb) {
}); });
}; };
BlockSchema.statics.load = function(id, cb) {
this.findOne({
_id: id
}).exec(cb);
};
BlockSchema.statics.fromHeight = function(height, cb) { BlockSchema.statics.blockIndex = function(height, cb) {
var rpc = new RpcClient(config.bitcoind); var rpc = new RpcClient(config.bitcoind);
var hash = {}; var hashStr = {};
rpc.getBlockHash(height, function(err, bh){ rpc.getBlockHash(height, function(err, bh){
if (err) return cb(err); if (err) return cb(err);
hash.blockHash = bh.result; hashStr.blockHash = bh.result;
cb(null, hash); cb(null, hashStr);
}); });
}; };
BlockSchema.statics.fromHash = function(hash, cb) { BlockSchema.statics.fromHash = function(hashStr, cb) {
var hash = new Buffer(hashStr, 'hex');
this.findOne({ this.findOne({
hash: hash, hash: hash,
}).exec(cb); }).exec(cb);
}; };
BlockSchema.statics.fromHashWithInfo = function(hash, cb) { BlockSchema.statics.fromHashWithInfo = function(hashStr, cb) {
var That = this; var That = this;
this.fromHash(hash, function(err, block) { That.fromHash(hashStr, function(err, block) {
if (err) return cb(err); if (err) return cb(err);
if (!block) { if (!block) {
// No in mongo...but maybe in bitcoind... lets query it // No in mongo...but maybe in bitcoind... lets query it
block = new That(); block = new That();
block.hash = hash; block.hashStr = hashStr;
block.getInfo(function(err, blockInfo) { block.getInfo(function(err, blockInfo) {
if (err) return cb(err); if (err) return cb(err);
if (!blockInfo) return cb(); if (!blockInfo) return cb();
@ -121,10 +151,10 @@ BlockSchema.statics.fromHashWithInfo = function(hash, cb) {
// TODO: Can we store the rpc instance in the Block object? // TODO: Can we store the rpc instance in the Block object?
BlockSchema.methods.getInfo = function (next) { BlockSchema.methods.getInfo = function (next) {
var that = this; var self = this;
var rpc = new RpcClient(config.bitcoind); var rpc = new RpcClient(config.bitcoind);
rpc.getBlock(this.hash, function(err, blockInfo) { rpc.getBlock(self.hashStr, function(err, blockInfo) {
// Not found? // Not found?
if (err && err.code === -5) return next(); if (err && err.code === -5) return next();
@ -135,12 +165,10 @@ BlockSchema.methods.getInfo = function (next) {
* Any other way to lazy load a property in a mongoose object? * Any other way to lazy load a property in a mongoose object?
*/ */
that.info = blockInfo.result; self.info = blockInfo.result;
self.info.reward = BitcoreBlock.getBlockValue(self.info.height) / util.COIN ;
that.info.reward = BitcoreBlock.getBlockValue(that.info.height) / util.COIN ; return next(null, self.info);
//console.log("THAT", that);
return next(null, that.info);
}); });
}; };

View File

@ -10,9 +10,11 @@ var mongoose = require('mongoose'),
Schema = mongoose.Schema; Schema = mongoose.Schema;
var CONCURRENCY = 15; var CONCURRENCY = 15;
// TODO: use bitcore networks module
var genesisTXID = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b';
var TransactionItemSchema = new Schema({ var TransactionItemSchema = new Schema({
txid: String, txidBuf: Buffer,
index: Number, index: Number,
addr: { addr: {
type: String, type: String,
@ -25,12 +27,24 @@ var TransactionItemSchema = new Schema({
}); });
// TODO: use bitcore networks module
var genesisTXID = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b';
// Compound index // Compound index
TransactionItemSchema.index({txid: 1, index: 1, value_sat: 1}, {unique: true, dropDups: true}); TransactionItemSchema.index({txidBuf: 1, index: 1, value_sat: 1}, {unique: true, dropDups: true});
TransactionItemSchema.virtual('txid').get(function () {
return this.txidBuf.toString('hex');
});
TransactionItemSchema.virtual('txid').set(function (txidStr) {
if (txidStr)
this.txidBuf = new Buffer(txidStr,'hex');
else
this.txidBuf = null;
});
TransactionItemSchema.statics.load = function(id, cb) { TransactionItemSchema.statics.load = function(id, cb) {
@ -87,7 +101,6 @@ TransactionItemSchema.statics.explodeTransactionItems = function(txid, cb) {
value_sat : -1 * i.valueSat, value_sat : -1 * i.valueSat,
addr : i.addr, addr : i.addr,
index : i.n, index : i.n,
ts : info.time,
}, next_in); }, next_in);
if (addrs.indexOf(i.addr) === -1) { if (addrs.indexOf(i.addr) === -1) {
addrs.push(i.addr); addrs.push(i.addr);
@ -124,7 +137,6 @@ TransactionItemSchema.statics.explodeTransactionItems = function(txid, cb) {
value_sat : o.valueSat, value_sat : o.valueSat,
addr : o.scriptPubKey.addresses[0], // TODO: only address 0? addr : o.scriptPubKey.addresses[0], // TODO: only address 0?
index : o.n, index : o.n,
ts : info.time,
}, next_out); }, next_out);
if (addrs.indexOf(o.scriptPubKey.addresses[0]) === -1) { if (addrs.indexOf(o.scriptPubKey.addresses[0]) === -1) {
addrs.push(o.scriptPubKey.addresses[0]); addrs.push(o.scriptPubKey.addresses[0]);
@ -139,7 +151,7 @@ TransactionItemSchema.statics.explodeTransactionItems = function(txid, cb) {
if (err) { if (err) {
if (err.message.match(/E11000/)) { if (err.message.match(/E11000/)) {
is_new = false; is_new = false;
} }
else { else {
console.log('ERR at TX %s: %s', txid, err); console.log('ERR at TX %s: %s', txid, err);
return cb(err); return cb(err);

View File

@ -62,7 +62,6 @@ function spec() {
var self = this; var self = this;
async.series([ async.series([
function(b) { return self.db.collections.blocks.drop(b);}, function(b) { return self.db.collections.blocks.drop(b);},
function(b) { return self.db.collections.transactions.drop(b);},
function(b) { return self.db.collections.transactionitems.drop(b);}, function(b) { return self.db.collections.transactionitems.drop(b);},
], next); ], next);
}; };

View File

@ -1,11 +1,12 @@
#!/usr/bin/env node #!/usr/bin/env node
'use strict';
process.env.NODE_ENV = process.env.NODE_ENV || 'development'; process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var TESTING_BLOCK = '000000000185678d3d7ecc9962c96418174431f93fe20bf216d5565272423f74'; var TESTING_BLOCK = '000000000185678d3d7ecc9962c96418174431f93fe20bf216d5565272423f74';
var var
mongoose= require('mongoose'), mongoose= require('mongoose'),
assert = require('assert'), assert = require('assert'),
config = require('../../config/config'), config = require('../../config/config'),
@ -28,21 +29,46 @@ describe('Block fromHashWithInfo', function(){
it('should poll block\'s info from mongoose', function(done) { it('should poll block\'s info from mongoose', function(done) {
var block2 = Block.fromHashWithInfo(TESTING_BLOCK, function(err, b2) { Block.fromHashWithInfo(TESTING_BLOCK, function(err, b2) {
if (err) done(err); if (err) done(err);
assert.equal(b2.hash, TESTING_BLOCK);
var h = new Buffer(TESTING_BLOCK,'hex');
assert(b2.hashStr === TESTING_BLOCK);
assert.equal(b2.hashStr, TESTING_BLOCK);
done(); done();
}); });
}); });
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) { 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);
assert.equal(b2.info.chainwork, '000000000000000000000000000000000000000000000000001b6dc969ffe847'); assert.equal(b2.info.chainwork, '000000000000000000000000000000000000000000000000001b6dc969ffe847');
done(); done();
}); });
}); });
it('hash Virtuals SET', function(done) {
var b = new Block();
b.hashStr = 'a1a2';
assert.equal(b.hash.toString('hex'),'a1a2');
b.nextBlockHashStr = 'a1a3';
assert.equal(b.nextBlockHash.toString('hex'),'a1a3');
done();
});
it('hash Virtuals GET', function(done) {
var b = new Block();
b.hash = new Buffer('a1a2','hex');
assert.equal(b.hashStr,'a1a2');
b.nextBlockHash = new Buffer('b2b1','hex');
assert.equal(b.nextBlockHashStr,'b2b1');
done();
});
}); });