2014-01-30 14:51:18 -08:00
|
|
|
'use strict';
|
2014-05-07 05:45:44 -07:00
|
|
|
var bitcore = require('bitcore'),
|
|
|
|
Block = bitcore.Block,
|
|
|
|
networks = bitcore.networks,
|
2014-05-07 06:42:45 -07:00
|
|
|
Parser = bitcore.BinaryParser,
|
2014-05-07 05:45:44 -07:00
|
|
|
fs = require('fs'),
|
|
|
|
Buffer = bitcore.Buffer,
|
|
|
|
glob = require('glob'),
|
|
|
|
async = require('async');
|
2014-03-05 18:03:56 -08:00
|
|
|
|
|
|
|
function BlockExtractor(dataDir, network) {
|
|
|
|
|
|
|
|
var self = this;
|
|
|
|
var path = dataDir + '/blocks/blk*.dat';
|
|
|
|
|
|
|
|
self.dataDir = dataDir;
|
|
|
|
self.files = glob.sync(path);
|
|
|
|
self.nfiles = self.files.length;
|
|
|
|
|
|
|
|
if (self.nfiles === 0)
|
|
|
|
throw new Error('Could not find block files at: ' + path);
|
|
|
|
|
|
|
|
self.currentFileIndex = 0;
|
|
|
|
self.isCurrentRead = false;
|
|
|
|
self.currentBuffer = null;
|
|
|
|
self.currentParser = null;
|
|
|
|
self.network = network === 'testnet' ? networks.testnet: networks.livenet;
|
|
|
|
self.magic = self.network.magic.toString('hex');
|
|
|
|
}
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
BlockExtractor.prototype.currentFile = function() {
|
|
|
|
var self = this;
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
return self.files[self.currentFileIndex];
|
|
|
|
};
|
2014-02-01 17:57:31 -08:00
|
|
|
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
BlockExtractor.prototype.nextFile = function() {
|
|
|
|
var self = this;
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
if (self.currentFileIndex < 0) return false;
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
var ret = true;
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
self.isCurrentRead = false;
|
|
|
|
self.currentBuffer = null;
|
|
|
|
self.currentParser = null;
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
if (self.currentFileIndex < self.nfiles - 1) {
|
|
|
|
self.currentFileIndex++;
|
2014-01-30 14:51:18 -08:00
|
|
|
}
|
2014-03-05 18:03:56 -08:00
|
|
|
else {
|
|
|
|
self.currentFileIndex=-1;
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
};
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
BlockExtractor.prototype.readCurrentFileSync = function() {
|
|
|
|
var self = this;
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
if (self.currentFileIndex < 0 || self.isCurrentRead) return;
|
2014-01-30 14:51:18 -08:00
|
|
|
|
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
self.isCurrentRead = true;
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
var fname = self.currentFile();
|
|
|
|
if (!fname) return;
|
2014-01-30 14:51:18 -08:00
|
|
|
|
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
var stats = fs.statSync(fname);
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
var size = stats.size;
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
console.log('Reading Blockfile %s [%d MB]',
|
|
|
|
fname, parseInt(size/1024/1024));
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
var fd = fs.openSync(fname, 'r');
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
var buffer = new Buffer(size);
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
fs.readSync(fd, buffer, 0, size, 0);
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
self.currentBuffer = buffer;
|
|
|
|
self.currentParser = new Parser(buffer);
|
|
|
|
};
|
2014-01-30 14:51:18 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
BlockExtractor.prototype.getNextBlock = function(cb) {
|
|
|
|
var self = this;
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
var b;
|
|
|
|
var magic;
|
|
|
|
async.series([
|
|
|
|
function (a_cb) {
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
async.whilst(
|
|
|
|
function() {
|
2014-05-27 06:59:34 -07:00
|
|
|
return (!magic || magic === '00000000');
|
2014-03-05 18:03:56 -08:00
|
|
|
},
|
|
|
|
function(w_cb) {
|
2014-05-27 06:59:34 -07:00
|
|
|
magic = null;
|
2014-01-30 14:51:18 -08:00
|
|
|
|
2014-03-05 18:03:56 -08:00
|
|
|
self.readCurrentFileSync();
|
2014-05-26 12:58:44 -07:00
|
|
|
if (self.currentFileIndex < 0) return cb();
|
2014-05-26 10:09:25 -07:00
|
|
|
|
2014-05-27 06:59:34 -07:00
|
|
|
var byte0 = self.currentParser ? self.currentParser.buffer(1).toString('hex') : null;
|
2014-05-26 10:09:25 -07:00
|
|
|
|
2014-05-27 06:59:34 -07:00
|
|
|
if (byte0) {
|
|
|
|
// Grab 3 bytes from block without removing them
|
|
|
|
var p = self.currentParser.pos;
|
|
|
|
var bytes123 = self.currentParser.subject.toString('hex',p,p+3);
|
|
|
|
magic = byte0 + bytes123;
|
2014-05-26 10:09:25 -07:00
|
|
|
|
2014-05-27 06:59:34 -07:00
|
|
|
if (magic !=='00000000' && magic !== self.magic) {
|
|
|
|
|
|
|
|
if (self.errorCount++ > 4)
|
|
|
|
return cb(new Error('CRITICAL ERROR: Magic number mismatch: ' +
|
|
|
|
magic + '!=' + self.magic));
|
|
|
|
|
|
|
|
magic=null;
|
2014-05-26 12:58:44 -07:00
|
|
|
}
|
2014-05-27 06:59:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!self.currentParser || self.currentParser.eof() ) {
|
|
|
|
if (self.nextFile())
|
|
|
|
console.log('Moving forward to file:' + self.currentFile() );
|
|
|
|
else
|
2014-03-05 18:03:56 -08:00
|
|
|
console.log('Finished all files');
|
2014-05-27 06:59:34 -07:00
|
|
|
|
|
|
|
magic = null;
|
|
|
|
return w_cb();
|
2014-03-05 18:03:56 -08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return w_cb();
|
|
|
|
}
|
|
|
|
}, a_cb);
|
|
|
|
},
|
|
|
|
function (a_cb) {
|
|
|
|
if (!magic) return a_cb();
|
2014-05-27 06:59:34 -07:00
|
|
|
// Remove 3 bytes from magic and spacer
|
|
|
|
self.currentParser.buffer(3+4);
|
2014-03-05 18:03:56 -08:00
|
|
|
return a_cb();
|
|
|
|
},
|
|
|
|
function (a_cb) {
|
|
|
|
if (!magic) return a_cb();
|
|
|
|
|
|
|
|
b = new Block();
|
|
|
|
b.parse(self.currentParser);
|
|
|
|
b.getHash();
|
2014-05-27 06:59:34 -07:00
|
|
|
self.errorCount=0;
|
2014-03-05 18:03:56 -08:00
|
|
|
return a_cb();
|
|
|
|
},
|
|
|
|
], function(err) {
|
|
|
|
return cb(err,b);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = require('soop')(BlockExtractor);
|
2014-01-30 14:51:18 -08:00
|
|
|
|