misc method improvements.

This commit is contained in:
Christopher Jeffrey 2016-02-19 02:53:33 -08:00
parent 71557ba95c
commit 9bc3e44a7f
7 changed files with 121 additions and 172 deletions

View File

@ -347,20 +347,6 @@ Block.prototype.getCoinbaseHeight = function getCoinbaseHeight() {
return height; return height;
}; };
Block.prototype.getNextBlock = function getNextBlock() {
var next;
if (!this.chain)
return utils.toHex(constants.zeroHash);
next = this.chain.getNextBlock(this.hash('hex'));
if (!next)
return utils.toHex(constants.zeroHash);
return next;
};
Block.reward = function reward(height) { Block.reward = function reward(height) {
var halvings = height / network.halvingInterval | 0; var halvings = height / network.halvingInterval | 0;
var reward; var reward;
@ -432,7 +418,7 @@ Block.prototype.getFee = function getFee() {
Block.prototype.getEntry = function getEntry() { Block.prototype.getEntry = function getEntry() {
if (!this.chain) if (!this.chain)
return; return;
return this.chain.getBlock(this); return this.chain.getEntry(this);
}; };
Block.prototype.isOrphan = function isOrphan() { Block.prototype.isOrphan = function isOrphan() {
@ -462,10 +448,6 @@ Block.prototype.__defineGetter__('rhash', function() {
return utils.revHex(this.hash('hex')); return utils.revHex(this.hash('hex'));
}); });
Block.prototype.__defineGetter__('nextBlock', function() {
return this.getNextBlock();
});
Block.prototype.__defineGetter__('reward', function() { Block.prototype.__defineGetter__('reward', function() {
return this.getReward(); return this.getReward();
}); });
@ -493,7 +475,6 @@ Block.prototype.inspect = function inspect() {
delete copy._chain; delete copy._chain;
copy.hash = this.hash('hex'); copy.hash = this.hash('hex');
copy.rhash = this.rhash; copy.rhash = this.rhash;
copy.nextBlock = this.getNextBlock();
copy.reward = utils.btc(this.getReward()); copy.reward = utils.btc(this.getReward());
copy.fee = utils.btc(this.getFee()); copy.fee = utils.btc(this.getFee());
copy.date = new Date((copy.ts || 0) * 1000).toISOString(); copy.date = new Date((copy.ts || 0) * 1000).toISOString();

View File

@ -737,7 +737,7 @@ BlockDB.prototype._getTXByAddress = function _getTXByAddress(address, callback)
if (data) { if (data) {
try { try {
tx = bcoin.tx.fromRaw(data); tx = bcoin.tx.fromRaw(data);
entry = bcoin.chain.global.db.get(record.height); entry = bcoin.chain.global.db.getSync(record.height);
assert(entry); assert(entry);
} catch (e) { } catch (e) {
return callback(e); return callback(e);
@ -797,7 +797,7 @@ BlockDB.prototype.getTX = function getTX(hash, callback) {
if (data) { if (data) {
try { try {
tx = bcoin.tx.fromRaw(data); tx = bcoin.tx.fromRaw(data);
entry = bcoin.chain.global.db.get(record.height); entry = bcoin.chain.global.db.getSync(record.height);
assert(entry); assert(entry);
} catch (e) { } catch (e) {
return callback(e); return callback(e);
@ -847,7 +847,7 @@ BlockDB.prototype.getBlock = function getBlock(hash, callback) {
block.height = record.height; block.height = record.height;
if (self.options.paranoid) { if (self.options.paranoid) {
if (typeof hash === 'number') { if (typeof hash === 'number') {
hash = bcoin.chain.global.get(hash); hash = bcoin.chain.global.db.getSync(hash);
if (!hash) if (!hash)
return callback(null, block); return callback(null, block);
hash = hash.hash; hash = hash.hash;
@ -1051,7 +1051,7 @@ function BlockData(options) {
if (!this.file) if (!this.file)
this.file = process.env.HOME + '/bcoin-block-' + network.type + '.db'; this.file = process.env.HOME + '/bcoin-block-' + network.type + '.db';
this._bufferPool = { used: {} }; this.bufferPool = { used: {} };
this.size = 0; this.size = 0;
this.fd = null; this.fd = null;
@ -1076,7 +1076,7 @@ BlockData.prototype._init = function _init() {
if (!this.exists()) if (!this.exists())
fs.writeFileSync(this.file, new Buffer([])); fs.writeFileSync(this.file, new Buffer([]));
this.size = this.getSize(); this.size = this.getFileSize();
this.fd = fs.openSync(this.file, 'r+'); this.fd = fs.openSync(this.file, 'r+');
}; };
@ -1115,24 +1115,24 @@ BlockData.prototype._malloc = function _malloc(size) {
if (size > 500) if (size > 500)
return new Buffer(size); return new Buffer(size);
if (!this._bufferPool[size]) if (!this.bufferPool[size])
this._bufferPool[size] = new Buffer(size); this.bufferPool[size] = new Buffer(size);
if (this._bufferPool.used[size] === this._bufferPool[size]) if (this.bufferPool.used[size] === this.bufferPool[size])
return new Buffer(size); return new Buffer(size);
this._bufferPool.used[size] = this._bufferPool[size]; this.bufferPool.used[size] = this.bufferPool[size];
return this._bufferPool[size]; return this.bufferPool[size];
}; };
BlockData.prototype._free = function _free(buf) { BlockData.prototype._free = function _free(buf) {
if (!this.options.usePool) if (!this.options.usePool)
return; return;
if (this._bufferPool.used[buf.length] === buf) { if (this.bufferPool.used[buf.length] === buf) {
assert(this._bufferPool[buf.length] === buf); assert(this.bufferPool[buf.length] === buf);
delete this._bufferPool.used[buf.length]; delete this.bufferPool.used[buf.length];
} }
}; };
@ -1148,7 +1148,7 @@ BlockData.prototype.exists = function exists() {
} }
}; };
BlockData.prototype.getSize = function getSize() { BlockData.prototype.getFileSize = function getFileSize() {
if (!bcoin.fs) if (!bcoin.fs)
return this.ramdisk.size; return this.ramdisk.size;
@ -1277,6 +1277,9 @@ BlockData.prototype._readAsync = function _readAsync(size, offset, callback) {
return callback(err); return callback(err);
} }
if (!bytes)
return callback(new Error('_readAsync() failed.'));
index += bytes; index += bytes;
size -= bytes; size -= bytes;
offset += bytes; offset += bytes;
@ -1349,6 +1352,9 @@ BlockData.prototype._writeAsync = function _writeAsync(data, offset, callback) {
return callback(err); return callback(err);
} }
if (!bytes)
return callback(new Error('_writeAsync() failed.'));
index += bytes; index += bytes;
size -= bytes; size -= bytes;
offset += bytes; offset += bytes;

View File

@ -233,7 +233,7 @@ Chain.prototype._preload = function _preload(callback) {
utils.debug('Loading %s', url); utils.debug('Loading %s', url);
stream = request.get(url); stream = request.get(url);
chainHeight = this.db.count() - 1; chainHeight = this.db.getSize() - 1;
height = 0; height = 0;
buf = { buf = {
data: [], data: [],
@ -249,7 +249,7 @@ Chain.prototype._preload = function _preload(callback) {
stream.on('error', function(err) { stream.on('error', function(err) {
var start = Math.max(0, height - 2); var start = Math.max(0, height - 2);
self.resetHeight(start); self.resetHeightSync(start);
return callback(err, start + 1); return callback(err, start + 1);
}); });
@ -285,7 +285,7 @@ Chain.prototype._preload = function _preload(callback) {
if (lastEntry && entry.prevBlock !== lastEntry.hash) { if (lastEntry && entry.prevBlock !== lastEntry.hash) {
start = Math.max(0, height - 2); start = Math.max(0, height - 2);
stream.destroy(); stream.destroy();
self.resetHeight(start); self.resetHeightSync(start);
return callback(new Error('Corrupt headers.'), start + 1); return callback(new Error('Corrupt headers.'), start + 1);
} }
@ -294,7 +294,7 @@ Chain.prototype._preload = function _preload(callback) {
if (!block.verify()) { if (!block.verify()) {
start = Math.max(0, height - 2); start = Math.max(0, height - 2);
stream.destroy(); stream.destroy();
self.resetHeight(start); self.resetHeightSync(start);
return callback(new Error('Bad headers.'), start + 1); return callback(new Error('Bad headers.'), start + 1);
} }
@ -311,10 +311,12 @@ Chain.prototype._preload = function _preload(callback) {
// Filthy hack to avoid writing // Filthy hack to avoid writing
// redundant blocks to disk! // redundant blocks to disk!
if (height < chainHeight) if (height <= chainHeight) {
self.db._cache(entry);
self.db._populate(entry); self.db._populate(entry);
else } else {
self.db.save(entry); self.db.saveAsync(entry);
}
height++; height++;
@ -666,7 +668,7 @@ Chain.prototype._addEntry = function _addEntry(entry, block, callback) {
} }
// Duplicate height (do a sync call here since this is cached) // Duplicate height (do a sync call here since this is cached)
existing = this.db.get(entry.height); existing = this.db.getSync(entry.height);
if (existing && existing.hash === entry.hash) if (existing && existing.hash === entry.hash)
return callback(null, false); return callback(null, false);
@ -674,7 +676,7 @@ Chain.prototype._addEntry = function _addEntry(entry, block, callback) {
if (err) if (err)
return callback(err); return callback(err);
self.db.save(entry, function(err) { self.db.saveAsync(entry, function(err) {
if (err) if (err)
return callback(err); return callback(err);
@ -694,7 +696,7 @@ Chain.prototype.resetHeight = function resetHeight(height) {
if (height === count - 1) if (height === count - 1)
return; return;
this.db.resetHeight(height); this.db.resetHeightSync(height);
// Reset the orphan map completely. There may // Reset the orphan map completely. There may
// have been some orphans on a forked chain we // have been some orphans on a forked chain we
@ -753,7 +755,7 @@ Chain.prototype.revertHeight = function revertHeight(height, callback) {
callback(err, result); callback(err, result);
} }
chainHeight = this.db.count() - 1; chainHeight = this.db.getSize() - 1;
if (chainHeight < 0) if (chainHeight < 0)
return done(new Error('Bad chain height.')); return done(new Error('Bad chain height.'));
@ -824,7 +826,7 @@ Chain.prototype.syncHeight = function syncHeight(callback) {
callback(err, result); callback(err, result);
} }
chainHeight = this.db.count() - 1; chainHeight = this.db.getSize() - 1;
if (chainHeight < 0) if (chainHeight < 0)
return done(new Error('Bad chain height.')); return done(new Error('Bad chain height.'));
@ -867,7 +869,7 @@ Chain.prototype.resetTime = function resetTime(ts) {
var entry = this.byTime(ts); var entry = this.byTime(ts);
if (!entry) if (!entry)
return; return;
return this.resetHeight(entry.height); return this.resetHeightSync(entry.height);
}; };
Chain.prototype.resetTimeAsync = function resetTimeAsync(ts, callback) { Chain.prototype.resetTimeAsync = function resetTimeAsync(ts, callback) {
@ -1114,7 +1116,7 @@ Chain.prototype.add = function add(initial, peer, callback) {
// Lookup previous entry. // Lookup previous entry.
// We can do this synchronously: // We can do this synchronously:
// it is already cached. // it is already cached.
prev = self.db.get(prevHeight); prev = self.db.getSync(prevHeight);
assert(prev); assert(prev);
// Do "contextual" verification on our block // Do "contextual" verification on our block
@ -1258,7 +1260,7 @@ Chain.prototype.byTime = function byTime(ts) {
// timestamp. // timestamp.
while (start < end) { while (start < end) {
pos = (start + end) >> 1; pos = (start + end) >> 1;
entry = this.db.get(pos); entry = this.db.getSync(pos);
delta = Math.abs(ts - entry.ts); delta = Math.abs(ts - entry.ts);
if (delta <= 60 * 60) if (delta <= 60 * 60)
@ -1271,7 +1273,7 @@ Chain.prototype.byTime = function byTime(ts) {
} }
} }
return this.db.get(start); return this.db.getSync(start);
}; };
Chain.prototype.byTimeAsync = function byTimeAsync(ts, callback) { Chain.prototype.byTimeAsync = function byTimeAsync(ts, callback) {
@ -1349,19 +1351,19 @@ Chain.prototype.hasPending = function hasPending(hash) {
return !!this.pendingBlocks[hash]; return !!this.pendingBlocks[hash];
}; };
Chain.prototype.getBlock = function getBlock(hash) { Chain.prototype.getEntry = function getEntry(hash) {
if (typeof hash === 'number') if (typeof hash === 'number')
return this.db.get(hash); return this.db.getSync(hash);
if (utils.isBuffer(hash)) if (utils.isBuffer(hash))
hash = utils.toHex(hash); hash = utils.toHex(hash);
else if (hash.hash) else if (hash.hash)
hash = hash.hash('hex'); hash = hash.hash('hex');
return this.db.get(hash); return this.db.getSync(hash);
}; };
Chain.prototype.getBlockAsync = function getBlockAsync(hash, callback) { Chain.prototype.getEntryAsync = function getEntryAsync(hash, callback) {
if (typeof hash === 'number') if (typeof hash === 'number')
return this.db.getAsync(hash, callback); return this.db.getAsync(hash, callback);
@ -1399,26 +1401,23 @@ Chain.prototype.getProgress = function getProgress() {
return Math.min(1, this.tip.ts / (utils.now() - 40 * 60)); return Math.min(1, this.tip.ts / (utils.now() - 40 * 60));
}; };
Chain.prototype.hashRange = function hashRange(start, end) { Chain.prototype.getHashRange = function getHashRange(start, end) {
var hashes = []; var hashes = [];
var i; var i;
start = this.byTime(start); start = this.byTime(start);
end = this.byTime(end); end = this.byTime(end);
if (!end)
end = this.tip;
if (!start || !end) if (!start || !end)
return hashes; return hashes;
for (i = start.height; i < end.height + 1; i++) for (i = start.height; i < end.height + 1; i++)
hashes.push(this.db.get(i).hash); hashes.push(this.db.getSync(i).hash);
return hashes; return hashes;
}; };
Chain.prototype.hashRangeAsync = function hashRangeAsync(start, end, callback) { Chain.prototype.getHashRangeAsync = function getHashRangeAsync(start, end, callback) {
var self = this; var self = this;
var called; var called;
@ -1441,9 +1440,6 @@ Chain.prototype.hashRangeAsync = function hashRangeAsync(start, end, callback) {
hashes = []; hashes = [];
if (!end)
end = self.tip;
if (!start || !end) if (!start || !end)
return done(null, hashes); return done(null, hashes);
@ -1460,7 +1456,7 @@ Chain.prototype.hashRangeAsync = function hashRangeAsync(start, end, callback) {
if (!entry) if (!entry)
return done(new Error('No entry for hash range.')); return done(new Error('No entry for hash range.'));
hashes.push(entry.hash); hashes[i - start.height] = entry.hash;
if (!--pending) if (!--pending)
return done(null, hashes); return done(null, hashes);
@ -1503,7 +1499,7 @@ Chain.prototype.getLocator = function getLocator(start) {
i = top; i = top;
for (;;) { for (;;) {
existing = this.db.get(i); existing = this.db.getSync(i);
assert(existing); assert(existing);
hashes.push(existing.hash); hashes.push(existing.hash);
i = i - step; i = i - step;
@ -1624,41 +1620,8 @@ Chain.prototype.getHeight = function getHeight(hash) {
return this.db.getHeight(hash); return this.db.getHeight(hash);
}; };
Chain.prototype.getNextBlock = function getNextBlock(hash) {
var height = this.db.getHeight(hash);
var entry;
if (height === -1)
return;
entry = this.db.get(height + 1);
if (!entry)
return;
return entry.hash;
};
Chain.prototype.getNextBlockAsync = function getNextBlockAsync(hash, callback) {
var height = this.db.getHeight(hash);
if (height === -1)
return callback();
return this.db.getAsync(height + 1, function(err, entry) {
if (err)
return callback(err);
if (!entry)
return callback();
return callback(null, entry.hash);
});
};
Chain.prototype.getSize = function getSize() { Chain.prototype.getSize = function getSize() {
return this.db.count(); return this.db.getSize();
}; };
// Legacy // Legacy
@ -1702,7 +1665,7 @@ Chain.prototype.getTarget = function getTarget(last, block) {
// Back 2 weeks // Back 2 weeks
// NOTE: This is cached. // NOTE: This is cached.
first = this.db.get(last.height - (network.powDiffInterval - 1)); first = this.db.getSync(last.height - (network.powDiffInterval - 1));
assert(first); assert(first);

View File

@ -38,11 +38,11 @@ function ChainBlock(chain, data) {
ChainBlock.BLOCK_SIZE = 112; ChainBlock.BLOCK_SIZE = 112;
ChainBlock.prototype.__defineGetter__('prev', function() { ChainBlock.prototype.__defineGetter__('prev', function() {
return this.chain.db.get(this.height - 1); return this.chain.db.getSync(this.height - 1);
}); });
ChainBlock.prototype.__defineGetter__('next', function() { ChainBlock.prototype.__defineGetter__('next', function() {
return this.chain.db.get(this.height + 1); return this.chain.db.getSync(this.height + 1);
}); });
ChainBlock.prototype.getProof = function getProof() { ChainBlock.prototype.getProof = function getProof() {
@ -53,13 +53,19 @@ ChainBlock.prototype.getProof = function getProof() {
}; };
ChainBlock.prototype.getChainwork = function getChainwork() { ChainBlock.prototype.getChainwork = function getChainwork() {
var prev;
// Workaround for genesis block
// being added _in_ chaindb.
if (!this.chain.db) if (!this.chain.db)
return; return;
var prev = this.prev;
prev = this.prev;
return (prev ? prev.chainwork : new bn(0)).add(this.getProof()); return (prev ? prev.chainwork : new bn(0)).add(this.getProof());
}; };
ChainBlock.prototype.isGenesis = function isGenesis(version) { ChainBlock.prototype.isGenesis = function isGenesis() {
return this.hash === network.genesis.hash; return this.hash === network.genesis.hash;
}; };

View File

@ -38,9 +38,9 @@ function ChainDB(chain, options) {
this.file = process.env.HOME + '/bcoin-chain-' + network.type + '.db'; this.file = process.env.HOME + '/bcoin-chain-' + network.type + '.db';
this.heightLookup = {}; this.heightLookup = {};
this._queue = {}; this.queue = {};
this._cache = {}; this.cache = {};
this._bufferPool = { used: {} }; this.bufferPool = { used: {} };
this.highest = -1; this.highest = -1;
this.tip = null; this.tip = null;
this.height = -1; this.height = -1;
@ -90,12 +90,12 @@ ChainDB.prototype._init = function _init() {
if (!this.exists()) if (!this.exists())
fs.writeFileSync(this.file, new Buffer([])); fs.writeFileSync(this.file, new Buffer([]));
this.size = this.getSize(); this.size = this.getFileSize();
if (this.size % BLOCK_SIZE !== 0) { if (this.size % BLOCK_SIZE !== 0) {
utils.debug('Blockchain is at an odd length. Truncating.'); utils.debug('Blockchain is at an odd length. Truncating.');
fs.truncateSync(this.file, this.size - (this.size % BLOCK_SIZE)); fs.truncateSync(this.file, this.size - (this.size % BLOCK_SIZE));
this.size = this.getSize(); this.size = this.getFileSize();
assert(this.size % BLOCK_SIZE === 0); assert(this.size % BLOCK_SIZE === 0);
} }
@ -111,7 +111,7 @@ ChainDB.prototype._init = function _init() {
ChainDB.prototype.load = function load(start, callback) { ChainDB.prototype.load = function load(start, callback) {
var self = this; var self = this;
var count = this.count(); var count = this.getSize();
var i = start || 0; var i = start || 0;
var lastEntry; var lastEntry;
@ -122,7 +122,7 @@ ChainDB.prototype.load = function load(start, callback) {
utils.debug( utils.debug(
'Blockchain is corrupt after height %d. Resetting.', 'Blockchain is corrupt after height %d. Resetting.',
height); height);
self.resetHeight(height); self.resetHeightSync(height);
} else { } else {
utils.debug('Chain successfully loaded.'); utils.debug('Chain successfully loaded.');
} }
@ -156,7 +156,7 @@ ChainDB.prototype.closeSync = function closeSync() {
this.ramdisk = null; this.ramdisk = null;
return; return;
} }
fs.closeSync(this.fd); fs.close(this.fd);
this.fd = null; this.fd = null;
}; };
@ -182,24 +182,24 @@ ChainDB.prototype._malloc = function _malloc(size) {
if (!this.options.usePool) if (!this.options.usePool)
return new Buffer(size); return new Buffer(size);
if (!this._bufferPool[size]) if (!this.bufferPool[size])
this._bufferPool[size] = new Buffer(size); this.bufferPool[size] = new Buffer(size);
if (this._bufferPool.used[size] === this._bufferPool[size]) if (this.bufferPool.used[size] === this.bufferPool[size])
return new Buffer(size); return new Buffer(size);
this._bufferPool.used[size] = this._bufferPool[size]; this.bufferPool.used[size] = this.bufferPool[size];
return this._bufferPool[size]; return this.bufferPool[size];
}; };
ChainDB.prototype._free = function _free(buf) { ChainDB.prototype._free = function _free(buf) {
if (!this.options.usePool) if (!this.options.usePool)
return; return;
if (this._bufferPool.used[buf.length] === buf) { if (this.bufferPool.used[buf.length] === buf) {
assert(this._bufferPool[buf.length] === buf); assert(this.bufferPool[buf.length] === buf);
delete this._bufferPool.used[buf.length]; delete this.bufferPool.used[buf.length];
} }
}; };
@ -215,7 +215,7 @@ ChainDB.prototype.exists = function exists() {
} }
}; };
ChainDB.prototype.getSize = function getSize() { ChainDB.prototype.getFileSize = function getFileSize() {
if (!bcoin.fs) if (!bcoin.fs)
return this.ramdisk.size; return this.ramdisk.size;
@ -226,18 +226,18 @@ ChainDB.prototype.getSize = function getSize() {
} }
}; };
ChainDB.prototype.count = function count() { ChainDB.prototype.getSize = function getSize() {
var len = this.size / BLOCK_SIZE; var len = this.size / BLOCK_SIZE;
assert(len % 1 === 0); assert(len % 1 === 0);
return len; return len;
}; };
ChainDB.prototype.cache = function cache(entry) { ChainDB.prototype._cache = function _cache(entry) {
if (entry.height > this.highest) { if (entry.height > this.highest) {
this.highest = entry.height; this.highest = entry.height;
delete this._cache[entry.height - this._cacheWindow]; delete this.cache[entry.height - this._cacheWindow];
this._cache[entry.height] = entry; this.cache[entry.height] = entry;
assert(Object.keys(this._cache).length <= this._cacheWindow); assert(Object.keys(this.cache).length <= this._cacheWindow);
} }
}; };
@ -260,21 +260,17 @@ ChainDB.prototype._populate = function _populate(entry) {
} }
}; };
ChainDB.prototype.get = function get(height) {
return this.getSync(height);
};
ChainDB.prototype.getSync = function getSync(height) { ChainDB.prototype.getSync = function getSync(height) {
var data, entry; var data, entry;
if (typeof height === 'string') if (typeof height === 'string')
height = this.heightLookup[height]; height = this.heightLookup[height];
if (this._cache[height]) if (this.cache[height])
return this._cache[height]; return this.cache[height];
if (this._queue[height]) if (this.queue[height])
return this._queue[height]; return this.queue[height];
if (height < 0 || height == null) if (height < 0 || height == null)
return; return;
@ -289,11 +285,12 @@ ChainDB.prototype.getSync = function getSync(height) {
entry = bcoin.chainblock.fromRaw(this.chain, height, data); entry = bcoin.chainblock.fromRaw(this.chain, height, data);
// Populate the entry.
this._populate(entry); this._populate(entry);
// Cache the past 1001 blocks in memory // Cache the past 1001 blocks in memory
// (necessary for isSuperMajority) // (necessary for isSuperMajority)
this.cache(entry); this._cache(entry);
return entry; return entry;
}; };
@ -306,11 +303,11 @@ ChainDB.prototype.getAsync = function getAsync(height, callback) {
if (typeof height === 'string') if (typeof height === 'string')
height = this.heightLookup[height]; height = this.heightLookup[height];
if (this._cache[height]) if (this.cache[height])
return callback(null, this._cache[height]); return callback(null, this.cache[height]);
if (this._queue[height]) if (this.queue[height])
return callback(null, this._queue[height]); return callback(null, this.queue[height]);
if (height < 0 || height == null) if (height < 0 || height == null)
return callback(); return callback();
@ -321,31 +318,25 @@ ChainDB.prototype.getAsync = function getAsync(height, callback) {
return this._readAsync(BLOCK_SIZE, height * BLOCK_SIZE, function(err, data) { return this._readAsync(BLOCK_SIZE, height * BLOCK_SIZE, function(err, data) {
var entry; var entry;
// We can't ensure the integrity of
// the chain if we get an error.
// Just throw.
if (err) if (err)
throw err; return callback(err);
if (!data) if (!data)
return callback(); return callback();
entry = bcoin.chainblock.fromRaw(self.chain, height, data); entry = bcoin.chainblock.fromRaw(self.chain, height, data);
// Populate the entry.
self._populate(entry); self._populate(entry);
// Cache the past 1001 blocks in memory // Cache the past 1001 blocks in memory
// (necessary for isSuperMajority) // (necessary for isSuperMajority)
self.cache(entry); self._cache(entry);
return callback(null, entry); return callback(null, entry);
}); });
}; };
ChainDB.prototype.save = function save(entry, callback) {
return this.saveAsync(entry, callback);
};
ChainDB.prototype.saveSync = function saveSync(entry) { ChainDB.prototype.saveSync = function saveSync(entry) {
var raw, offset; var raw, offset;
@ -354,8 +345,9 @@ ChainDB.prototype.saveSync = function saveSync(entry) {
// Cache the past 1001 blocks in memory // Cache the past 1001 blocks in memory
// (necessary for isSuperMajority) // (necessary for isSuperMajority)
this.cache(entry); this._cache(entry);
// Populate the entry.
this._populate(entry); this._populate(entry);
raw = entry.toRaw(); raw = entry.toRaw();
@ -375,34 +367,32 @@ ChainDB.prototype.saveAsync = function saveAsync(entry, callback) {
// Cache the past 1001 blocks in memory // Cache the past 1001 blocks in memory
// (necessary for isSuperMajority) // (necessary for isSuperMajority)
this.cache(entry); this._cache(entry);
// Populate the entry.
this._populate(entry); this._populate(entry);
// Something is already writing. Cancel it // Something is already writing. Cancel it
// and synchronously write the data after // and synchronously write the data after
// it cancels. // it cancels.
if (this._queue[entry.height]) { if (this.queue[entry.height]) {
this._queue[entry.height] = entry; this.queue[entry.height] = entry;
return callback(); return callback();
} }
// Speed up writes by doing them asynchronously // Speed up writes by doing them asynchronously
// and keeping the data to be written in memory. // and keeping the data to be written in memory.
this._queue[entry.height] = entry; this.queue[entry.height] = entry;
// Write asynchronously to the db. // Write asynchronously to the db.
raw = entry.toRaw(); raw = entry.toRaw();
offset = entry.height * BLOCK_SIZE; offset = entry.height * BLOCK_SIZE;
return this._writeAsync(raw, offset, function(err, success) { return this._writeAsync(raw, offset, function(err, success) {
// We can't ensure the integrity of
// the chain if we get an error.
// Just throw.
if (err) if (err)
throw err; return callback(err);
var item = self._queue[entry.height]; var item = self.queue[entry.height];
// Something tried to write here but couldn't. // Something tried to write here but couldn't.
// Synchronously write it and get it over with. // Synchronously write it and get it over with.
@ -413,26 +403,26 @@ ChainDB.prototype.saveAsync = function saveAsync(entry, callback) {
err = e; err = e;
} }
delete self._queue[entry.height]; delete self.queue[entry.height];
return callback(null, success); return callback(null, success);
}); });
}; };
ChainDB.prototype.drop = function drop(height) { ChainDB.prototype._drop = function _drop(height) {
assert(height >= 0); assert(height >= 0);
// Potential race condition here. Not sure how // Potential race condition here. Not sure how
// to handle this. // to handle this.
if (this._queue[height]) { if (this.queue[height]) {
utils.debug('Warning: write job in progress.'); utils.debug('Warning: write job in progress.');
delete this._queue[height]; delete this.queue[height];
} }
delete this._cache[height]; delete this.cache[height];
}; };
ChainDB.prototype.resetHeight = function resetHeight(height) { ChainDB.prototype.resetHeightSync = function resetHeightSync(height) {
var size, count, existing; var size, count, existing;
if (typeof height === 'string') if (typeof height === 'string')
@ -441,7 +431,7 @@ ChainDB.prototype.resetHeight = function resetHeight(height) {
assert(height >= 0); assert(height >= 0);
size = (height + 1) * BLOCK_SIZE; size = (height + 1) * BLOCK_SIZE;
count = this.count(); count = this.getSize();
if (height === count - 1) if (height === count - 1)
return; return;
@ -452,7 +442,7 @@ ChainDB.prototype.resetHeight = function resetHeight(height) {
for (i = height + 1; i < count; i++) { for (i = height + 1; i < count; i++) {
existing = this.get(i); existing = this.get(i);
assert(existing); assert(existing);
this.drop(i); this._drop(i);
delete this.heightLookup[existing.hash]; delete this.heightLookup[existing.hash];
} }
@ -481,7 +471,7 @@ ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback)
callback = utils.asyncify(callback); callback = utils.asyncify(callback);
size = (height + 1) * BLOCK_SIZE; size = (height + 1) * BLOCK_SIZE;
count = this.count() - 1; count = this.getSize();
pending = count - (height + 1); pending = count - (height + 1);
if (height === count - 1) if (height === count - 1)
@ -499,7 +489,7 @@ ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback)
return done(err); return done(err);
assert(existing); assert(existing);
self.drop(i); self._drop(i);
delete self.heightLookup[existing.hash]; delete self.heightLookup[existing.hash];
if (!--pending) if (!--pending)
done(); done();
@ -604,7 +594,7 @@ ChainDB.prototype._readAsync = function _readAsync(size, offset, callback) {
} }
if (!bytes) if (!bytes)
throw new Error('_readAsync() failed.'); return callback(new Error('_readAsync() failed.'));
index += bytes; index += bytes;
size -= bytes; size -= bytes;
@ -679,7 +669,7 @@ ChainDB.prototype._writeAsync = function _writeAsync(data, offset, callback) {
} }
if (!bytes) if (!bytes)
throw new Error('_writeAsync() failed.'); return callback(new Error('_writeAsync() failed.'));
index += bytes; index += bytes;
size -= bytes; size -= bytes;

View File

@ -129,7 +129,7 @@ Miner.prototype.addBlock = function addBlock(block) {
// us, start over with the new target. // us, start over with the new target.
if (block.height > this.last.height) { if (block.height > this.last.height) {
this.last = block.type === 'block' this.last = block.type === 'block'
? this.chain.getBlock(block) ? this.chain.getEntry(block)
: block; : block;
assert(this.last); assert(this.last);
this.start(); this.start();
@ -304,7 +304,7 @@ Miner.prototype.iterate = function iterate() {
self.emit('block', self.block); self.emit('block', self.block);
// Try to find a new block // Try to find a new block
self.last = self.chain.getBlock(self.block); self.last = self.chain.getEntry(self.block);
assert(self.last); assert(self.last);
self.block = self.createBlock(); self.block = self.createBlock();

View File

@ -1465,6 +1465,9 @@ Pool.prototype._request = function _request(peer, type, hash, options, cb) {
item = new LoadRequest(this, peer, type, hash, cb); item = new LoadRequest(this, peer, type, hash, cb);
if (options.noQueue)
return;
if (item.type === 'tx') { if (item.type === 'tx') {
if (peer._txQueue.length === 0) { if (peer._txQueue.length === 0) {
utils.nextTick(function() { utils.nextTick(function() {