blockdb reset height.
This commit is contained in:
parent
997f0acbb0
commit
0191acd530
@ -24,6 +24,7 @@ if (!bcoin.isBrowser) {
|
||||
bcoin.fs = require('f' + 's');
|
||||
bcoin.crypto = require('cry' + 'pto');
|
||||
bcoin.net = require('n' + 'et');
|
||||
bcoin.cp = require('child_' + 'process');
|
||||
}
|
||||
|
||||
bcoin.elliptic = elliptic;
|
||||
|
||||
@ -63,6 +63,21 @@ function BlockDB(options) {
|
||||
|
||||
inherits(BlockDB, EventEmitter);
|
||||
|
||||
BlockDB.prototype.close = function close(callback) {
|
||||
var self = this;
|
||||
this.index.close(function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
self.data.closeAsync(function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
return callback();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
BlockDB.prototype.migrate = function migrate(blockSize, compression, callback) {
|
||||
var options, db, pending, stream, total, done;
|
||||
|
||||
@ -251,14 +266,23 @@ BlockDB.prototype.removeBlock = function removeBlock(hash, callback) {
|
||||
|
||||
batch = self.index.batch();
|
||||
|
||||
batch.del('b/b/' + hash);
|
||||
if (typeof hash === 'string')
|
||||
assert(block.hash('hex') === hash);
|
||||
|
||||
batch.del('b/b/' + block.hash('hex'));
|
||||
batch.del('b/h/' + block.height);
|
||||
|
||||
function done() {
|
||||
batch.write(function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
return callback(null, block);
|
||||
// TODO: Add check to make sure we
|
||||
// can ONLY remove the last block.
|
||||
self.data.truncateAsync(block._fileOffset, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
return callback(null, block);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -810,6 +834,29 @@ BlockDB.prototype.getBlock = function getBlock(hash, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
BlockDB.prototype.hasBlock = function hasBlock(hash, callback) {
|
||||
var self = this;
|
||||
var id = 'b/b/' + value;
|
||||
|
||||
if (typeof hash === 'number')
|
||||
id = 'b/h/' + value;
|
||||
|
||||
this.index.get(id, function(err, record) {
|
||||
if (err && err.type !== 'NotFoundError')
|
||||
return callback(err);
|
||||
|
||||
if (!record)
|
||||
return callback(null, false);
|
||||
|
||||
record = self.parseOffset(record);
|
||||
|
||||
if (self.data.size < record.offset + record.size)
|
||||
return callback(null, false);
|
||||
|
||||
return callback(null, true);
|
||||
});
|
||||
};
|
||||
|
||||
BlockDB.prototype.hasCoin = function hasCoin(hash, index, callback) {
|
||||
var id = 'u/t/' + hash + '/' + index;
|
||||
|
||||
@ -817,7 +864,15 @@ BlockDB.prototype.hasCoin = function hasCoin(hash, index, callback) {
|
||||
if (err && err.type !== 'NotFoundError')
|
||||
return callback(err);
|
||||
|
||||
return callback(null, record ? true : false);
|
||||
if (!record)
|
||||
return callback(null, false);
|
||||
|
||||
record = self.parseOffset(record);
|
||||
|
||||
if (self.data.size < record.offset + record.size)
|
||||
return callback(null, false);
|
||||
|
||||
return callback(null, true);
|
||||
});
|
||||
};
|
||||
|
||||
@ -828,7 +883,15 @@ BlockDB.prototype.hasTX = function hasTX(hash, callback) {
|
||||
if (err && err.type !== 'NotFoundError')
|
||||
return callback(err);
|
||||
|
||||
return callback(null, record ? true : false);
|
||||
if (!record)
|
||||
return callback(null, false);
|
||||
|
||||
record = self.parseOffset(record);
|
||||
|
||||
if (self.data.size < record.offset + record.size)
|
||||
return callback(null, false);
|
||||
|
||||
return callback(null, true);
|
||||
});
|
||||
};
|
||||
|
||||
@ -841,6 +904,57 @@ BlockDB.prototype.isSpent = function isSpent(hash, index, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
BlockDB.prototype.getHeight = function getHeight(callback) {
|
||||
var self = this;
|
||||
var maxHeight = -1;
|
||||
var stream;
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
stream = this.index.createKeyStream({
|
||||
start: 'b/h',
|
||||
end: 'b/h~'
|
||||
});
|
||||
|
||||
stream.on('data', function(data) {
|
||||
var parts = data.key.split('/').slice(2);
|
||||
var height = +parts[0];
|
||||
if (height > maxHeight)
|
||||
maxHeight = height;
|
||||
});
|
||||
|
||||
stream.on('error', function(err) {
|
||||
return callback(err);
|
||||
});
|
||||
|
||||
stream.on('end', function() {
|
||||
return callback(null, maxHeight);
|
||||
});
|
||||
};
|
||||
|
||||
BlockDB.prototype.resetHeight = function resetHeight(height, callback) {
|
||||
var self = this;
|
||||
this.getHeight(function(err, currentHeight) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
if (currentHeight < height)
|
||||
return callback(new Error('Cannot reset to height ' + height));
|
||||
|
||||
(function next() {
|
||||
if (height === currentHeight)
|
||||
return callback();
|
||||
|
||||
self.removeBlock(height, function(err, block) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
height--;
|
||||
next();
|
||||
});
|
||||
})();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* BlockData
|
||||
*/
|
||||
@ -888,7 +1002,34 @@ BlockData.prototype._init = function _init() {
|
||||
this.fd = fs.openSync(this.file, 'r+');
|
||||
};
|
||||
|
||||
BlockData.prototype._malloc = function(size) {
|
||||
BlockData.prototype.closeSync = function closeSync() {
|
||||
if (!bcoin.fs) {
|
||||
this.ramdisk = null;
|
||||
return;
|
||||
}
|
||||
fs.closeSync(this.fd);
|
||||
this.fd = null;
|
||||
};
|
||||
|
||||
BlockData.prototype.closeAsync = function closeAsync(callback) {
|
||||
var self = this;
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (!bcoin.fs) {
|
||||
this.ramdisk = null;
|
||||
return callback();
|
||||
}
|
||||
|
||||
fs.close(this.fd, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
self.fd = null;
|
||||
return callback();
|
||||
});
|
||||
};
|
||||
|
||||
BlockData.prototype._malloc = function _malloc(size) {
|
||||
if (size > 500)
|
||||
return new Buffer(size);
|
||||
|
||||
@ -903,7 +1044,7 @@ BlockData.prototype._malloc = function(size) {
|
||||
return this._bufferPool[size];
|
||||
};
|
||||
|
||||
BlockData.prototype._free = function(buf) {
|
||||
BlockData.prototype._free = function _free(buf) {
|
||||
if (this._bufferPool.used[buf.length] === buf) {
|
||||
assert(this._bufferPool[buf.length] === buf);
|
||||
delete this._bufferPool.used[buf.length];
|
||||
@ -967,15 +1108,34 @@ BlockData.prototype.saveAsync = function saveAsync(data, callback) {
|
||||
});
|
||||
};
|
||||
|
||||
BlockData.prototype.truncate = function truncate(size) {
|
||||
this.size = size;
|
||||
|
||||
BlockData.prototype.truncateSync = function truncateSync(size) {
|
||||
if (!bcoin.fs) {
|
||||
this.ramdisk.truncate(this.size);
|
||||
this.ramdisk.truncate(size);
|
||||
this.size = size;
|
||||
return;
|
||||
}
|
||||
|
||||
fs.ftruncateSync(this.fd, this.size);
|
||||
fs.ftruncateSync(this.fd, size);
|
||||
this.size = size;
|
||||
};
|
||||
|
||||
BlockData.prototype.truncateAsync = function truncateAsync(size, callback) {
|
||||
var self = this;
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (!bcoin.fs) {
|
||||
this.ramdisk.truncate(size);
|
||||
this.size = size;
|
||||
return callback();
|
||||
}
|
||||
|
||||
fs.ftruncate(this.fd, size, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
self.size = size;
|
||||
return callback();
|
||||
});
|
||||
};
|
||||
|
||||
BlockData.prototype._readSync = function _readSync(size, offset) {
|
||||
|
||||
@ -110,6 +110,11 @@ Chain.prototype._init = function _init() {
|
||||
|
||||
utils.debug('Starting chain load at height: %s', i);
|
||||
|
||||
function doneForReal() {
|
||||
self.loading = false;
|
||||
self.emit('load');
|
||||
}
|
||||
|
||||
function done(height) {
|
||||
if (height != null) {
|
||||
utils.debug(
|
||||
@ -119,8 +124,33 @@ Chain.prototype._init = function _init() {
|
||||
} else {
|
||||
utils.debug('Chain successfully loaded.');
|
||||
}
|
||||
self.loading = false;
|
||||
self.emit('load');
|
||||
|
||||
if (!self.blockdb)
|
||||
return doneForReal();
|
||||
|
||||
return doneForReal();
|
||||
|
||||
self.blockdb.getHeight(function(err, height) {
|
||||
if (err)
|
||||
throw err;
|
||||
|
||||
if (height === self.tip.height)
|
||||
return doneForReal();
|
||||
|
||||
utils.debug('ChainDB and BlockDB are out of sync. Syncing...');
|
||||
|
||||
if (height < self.tip.height)
|
||||
return self.resetHeight(height);
|
||||
|
||||
if (height > self.tip.height) {
|
||||
return self.blockdb.resetHeight(self.tip.height, function(err) {
|
||||
if (err)
|
||||
throw err;
|
||||
|
||||
return doneForReal();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
(function next() {
|
||||
@ -267,7 +297,7 @@ Chain.prototype._saveBlock = function _saveBlock(block, callback) {
|
||||
if (!this.blockdb)
|
||||
return callback();
|
||||
|
||||
this.blockdb.block.saveBlock(block, function(err) {
|
||||
this.blockdb.saveBlock(block, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
@ -474,6 +504,7 @@ Chain.prototype._verify = function _verify(block, prev) {
|
||||
};
|
||||
|
||||
Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callback) {
|
||||
var self = this;
|
||||
var height = prev.height + 1;
|
||||
var pending = block.txs.length;
|
||||
var called;
|
||||
@ -521,6 +552,7 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
|
||||
};
|
||||
|
||||
Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callback) {
|
||||
var self = this;
|
||||
var height = prev.height + 1;
|
||||
|
||||
if (!this.blockdb || block.subtype !== 'block')
|
||||
@ -542,7 +574,7 @@ Chain.prototype._checkInputs = function _checkInputs(block, prev, flags, callbac
|
||||
|
||||
// Check all transactions
|
||||
for (i = 0; i < block.txs.length; i++) {
|
||||
tx = blocks.txs[i];
|
||||
tx = block.txs[i];
|
||||
hash = tx.hash('hex');
|
||||
|
||||
for (j = 0; j < tx.inputs.length; j++) {
|
||||
|
||||
@ -85,7 +85,34 @@ ChainDB.prototype._init = function _init() {
|
||||
this.fd = fs.openSync(this.file, 'r+');
|
||||
};
|
||||
|
||||
ChainDB.prototype._malloc = function(size) {
|
||||
ChainDB.prototype.closeSync = function closeSync() {
|
||||
if (!bcoin.fs) {
|
||||
this.ramdisk = null;
|
||||
return;
|
||||
}
|
||||
fs.closeSync(this.fd);
|
||||
this.fd = null;
|
||||
};
|
||||
|
||||
ChainDB.prototype.closeAsync = function closeAsync(callback) {
|
||||
var self = this;
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (!bcoin.fs) {
|
||||
this.ramdisk = null;
|
||||
return callback();
|
||||
}
|
||||
|
||||
fs.close(this.fd, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
self.fd = null;
|
||||
return callback();
|
||||
});
|
||||
};
|
||||
|
||||
ChainDB.prototype._malloc = function _malloc(size) {
|
||||
if (!this._bufferPool[size])
|
||||
this._bufferPool[size] = new Buffer(size);
|
||||
|
||||
@ -97,7 +124,7 @@ ChainDB.prototype._malloc = function(size) {
|
||||
return this._bufferPool[size];
|
||||
};
|
||||
|
||||
ChainDB.prototype._free = function(buf) {
|
||||
ChainDB.prototype._free = function _free(buf) {
|
||||
if (this._bufferPool.used[buf.length] === buf) {
|
||||
assert(this._bufferPool[buf.length] === buf);
|
||||
delete this._bufferPool.used[buf.length];
|
||||
@ -312,22 +339,49 @@ ChainDB.prototype.remove = function remove(height) {
|
||||
|
||||
assert(height >= 0);
|
||||
|
||||
this.truncate(height);
|
||||
this.truncateSync(height);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
ChainDB.prototype.truncate = function truncate(height) {
|
||||
this.size = (height + 1) * BLOCK_SIZE;
|
||||
this.tip = height;
|
||||
ChainDB.prototype.truncateSync = function truncateSync(height) {
|
||||
var size = (height + 1) * BLOCK_SIZE;
|
||||
|
||||
if (!bcoin.fs) {
|
||||
this.ramdisk.truncate(this.size);
|
||||
this.ramdisk.truncate(size);
|
||||
this.size = size;
|
||||
this.tip = height;
|
||||
return;
|
||||
}
|
||||
|
||||
fs.ftruncateSync(this.fd, this.size);
|
||||
fs.ftruncateSync(this.fd, size);
|
||||
this.size = size;
|
||||
this.tip = height;
|
||||
};
|
||||
|
||||
ChainDB.prototype.truncateAsync = function truncateAsync(height) {
|
||||
var self = this;
|
||||
var size = (height + 1) * BLOCK_SIZE;
|
||||
|
||||
callback = utils.asyncify(callback);
|
||||
|
||||
if (!bcoin.fs) {
|
||||
this.ramdisk.truncate(size);
|
||||
this.size = size;
|
||||
this.tip = height;
|
||||
return callback();
|
||||
}
|
||||
|
||||
fs.ftruncate(this.fd, size, function(err) {
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
self.size = size;
|
||||
self.tip = height;
|
||||
|
||||
return callback();
|
||||
});
|
||||
};
|
||||
|
||||
ChainDB.prototype.isNull = function isNull(height) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user