misc fixes.

This commit is contained in:
Christopher Jeffrey 2016-02-19 19:48:24 -08:00
parent 56f68983d3
commit a9ec49f954
5 changed files with 87 additions and 67 deletions

View File

@ -187,11 +187,14 @@ Chain.prototype.__defineGetter__('height', function() {
Chain.prototype._lock = function _lock(func, args, force) {
var self = this;
var block;
var block, called;
if (force) {
assert(this.busy);
return function() {};
return function unlock() {
assert(!called);
called = true;
};
}
if (this.busy) {
@ -214,6 +217,9 @@ Chain.prototype._lock = function _lock(func, args, force) {
return function unlock() {
var item, block;
assert(!called);
called = true;
self.busy = false;
if (func === Chain.prototype.add) {
@ -584,9 +590,6 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
// BIP30 - Ensure there are no duplicate txids
self.blockdb.hasTX(hash, function(err, result) {
if (called)
return;
if (err)
return done(err);
@ -759,8 +762,6 @@ Chain.prototype.resetHeight = function resetHeight(height, force) {
// no longer need.
this.purgeOrphans();
this.purgePending();
unlock();
};
Chain.prototype.resetHeightAsync = function resetHeightAsync(height, callback, force) {
@ -1262,6 +1263,9 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
if (self.orphan.size > self.orphanLimit)
self.pruneOrphans();
// Keep track of total blocks handled.
self.total += total;
// We intentionally did not asyncify the
// callback so if it calls chain.add, it
// still gets added to the queue. The
@ -1269,15 +1273,11 @@ Chain.prototype.add = function add(initial, peer, callback, force) {
// so we don't cause a stack overflow if
// these end up being all sync chain.adds.
utils.nextTick(function() {
// XXX Possibly put `unlock()` above callback!
unlock();
if (err)
callback(err);
else
callback(null, total);
self.total += total;
unlock();
});
}
};

View File

@ -123,8 +123,7 @@ ChainDB.prototype.load = function load(start, callback) {
utils.debug(
'Blockchain is corrupt after height %d. Resetting.',
height);
self.resetHeightAsync(height, callback);
return;
return self.resetHeightAsync(height, callback);
}
utils.debug('Chain successfully loaded.');
callback();
@ -157,6 +156,7 @@ ChainDB.prototype.closeSync = function closeSync() {
this.ramdisk = null;
return;
}
fs.close(this.fd);
this.fd = null;
};
@ -174,6 +174,7 @@ ChainDB.prototype.closeAsync = function closeAsync(callback) {
fs.close(this.fd, function(err) {
if (err)
return callback(err);
self.fd = null;
return callback();
});
@ -349,7 +350,7 @@ ChainDB.prototype.saveSync = function saveSync(entry) {
if (entry.height * BLOCK_SIZE !== this.size) {
utils.debug('Warning attempt to write to height: %d/%d', this.height);
return;
return false;
}
// Cache the past 1001 blocks in memory
@ -402,8 +403,10 @@ ChainDB.prototype.saveAsync = function saveAsync(entry, callback) {
return callback(err);
assert(self.queue[entry.height]);
delete self.queue[entry.height];
self.queueSize--;
if (self.queueSize === 0)
self.emit('flush');
@ -411,44 +414,39 @@ ChainDB.prototype.saveAsync = function saveAsync(entry, callback) {
});
};
ChainDB.prototype._drop = function _drop(height) {
assert(height >= 0);
// Potential race condition here. Not sure how
// to handle this.
if (this.queue[height]) {
utils.debug('Warning: write job in progress.');
// delete this.queue[height];
}
delete this.cache[height];
};
ChainDB.prototype.resetHeightSync = function resetHeightSync(height) {
var self = this;
var size, count, existing;
var osize = this.size;
var ohighest = this.highest;
var otip = this.tip;
var size, count, existing;
if (typeof height === 'string')
height = this.heightLookup[height];
assert(height >= 0);
assert(this.tip);
size = (height + 1) * BLOCK_SIZE;
count = this.getSize();
if (height > count - 1)
throw new Error('Height too high.');
if (height === count - 1)
return;
assert(height <= count - 1);
assert(this.tip);
for (i = height + 1; i < count; i++) {
existing = this.getSync(i);
assert(existing);
this._drop(i);
// Warn of potential race condition
// (handled with _onFlush).
if (this.queue[i])
utils.debug('Warning: write job in progress.');
delete this.cache[i];
delete this.heightLookup[existing.hash];
}
@ -481,28 +479,29 @@ ChainDB.prototype.resetHeightSync = function resetHeightSync(height) {
ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback) {
var self = this;
var size, count, pending, called;
var osize = this.size;
var ohighest = this.highest;
var otip = this.tip;
var size, count, pending, called;
callback = utils.asyncify(callback);
if (typeof height === 'string')
height = this.heightLookup[height];
assert(height >= 0);
callback = utils.asyncify(callback);
assert(this.tip);
size = (height + 1) * BLOCK_SIZE;
count = this.getSize();
pending = count - (height + 1);
if (height > count - 1)
return callback(new Error('Height too high'));
if (height === count - 1)
return callback();
assert(height <= count - 1);
assert(this.tip);
// Prevent any more writes
// by setting this early.
this.size = size;
@ -527,8 +526,14 @@ ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback)
assert(existing);
self._drop(i);
// Warn of potential race condition
// (handled with _onFlush).
if (self.queue[i])
utils.debug('Warning: write job in progress.');
delete self.cache[i];
delete self.heightLookup[existing.hash];
if (!--pending)
done();
}, true);

View File

@ -19,7 +19,7 @@ var fs = bcoin.fs;
* Mempool
*/
function Mempool(pool, options) {
function Mempool(node, options) {
if (!(this instanceof Mempool))
return new Mempool(pool, options);
@ -27,8 +27,8 @@ function Mempool(pool, options) {
options = {};
this.options = options;
this.pool = pool;
this.blockdb = pool.blockdb;
this.node = node;
this.blockdb = node.blockdb;
this.txs = {};
this.spent = {};
@ -235,7 +235,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
data: tx.hash(),
reason: 'non-standard'
});
pool.setMisbehavior(peer, 100);
self.node.pool.setMisbehavior(peer, 100);
return callback(new Error('TX is not standard.'));
}
@ -245,7 +245,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
data: tx.hash(),
reason: 'non-standard-inputs'
});
pool.setMisbehavior(peer, 100);
self.node.pool.setMisbehavior(peer, 100);
return callback(new Error('TX inputs are not standard.'));
}
@ -255,11 +255,11 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
data: tx.hash(),
reason: 'nonexistent-coins'
});
pool.setMisbehavior(peer, 100);
self.node.pool.setMisbehavior(peer, 100);
return callback(new Error('TX is spending coins that it does not have.'));
}
height = self.pool.chain.height + 1;
height = self.node.pool.chain.height + 1;
ts = utils.now();
if (!tx.isFinal(height, ts)) {
return callback(new Error('TX is not final.'));
@ -267,7 +267,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
data: tx.hash(),
reason: 'not-final'
});
pool.setMisbehavior(peer, 100);
self.node.pool.setMisbehavior(peer, 100);
return callback(new Error('TX is not final.'));
}
@ -299,7 +299,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
data: tx.hash(),
reason: 'negative-value'
});
pool.setMisbehavior(peer, 100);
self.node.pool.setMisbehavior(peer, 100);
return callback(new Error('TX is spending negative coins.'));
}
}
@ -310,7 +310,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
data: tx.hash(),
reason: 'script-failed'
});
pool.setMisbehavior(peer, 100);
self.node.pool.setMisbehavior(peer, 100);
return callback(new Error('TX did not verify.'));
}

View File

@ -17,7 +17,7 @@ var EventEmitter = require('events').EventEmitter;
* Miner
*/
function Miner(options) {
function Miner(pool, options) {
if (!(this instanceof Miner))
return new Miner(options);
@ -30,15 +30,17 @@ function Miner(options) {
this.address = this.options.address;
this.msg = this.options.msg || 'mined by bcoin';
this.pool = options.pool || bcoin.pool.global;
this.chain = options.chain || this.pool.chain || bcoin.chain.global;
this.pool = pool || bcoin.pool.global;
this.chain = this.pool.chain;
this.mempool = this.pool.mempool;
this.blockdb = this.pool.blockdb;
this.running = false;
this.timeout = null;
this.interval = null;
this.fee = new bn(0);
this.last = this.chain.getTip();
this.last = this.chain.tip;
this.block = null;
this.iterations = 0;
this._begin = utils.now();
@ -51,18 +53,26 @@ inherits(Miner, EventEmitter);
Miner.prototype._init = function _init() {
var self = this;
this.pool.on('tx', function(tx) {
self.addTX(tx);
});
if (this.mempool) {
this.mempool.on('tx', function(tx) {
if (!self.running)
return;
self.addTX(tx);
});
} else {
this.pool.on('tx', function(tx) {
if (!self.running)
return;
self.addTX(tx);
});
}
this.chain.on('block', function(block) {
this.chain.on('add block', function(block) {
if (!self.running)
return;
self.addBlock(block);
});
// this.chain.on('tip', function(entry) {
// self.addBlock(entry);
// });
this.on('block', function(block) {
utils.debug(
'Found block: %d (%s)',
@ -123,7 +133,10 @@ Miner.prototype.add = function add(msg) {
Miner.prototype.addBlock = function addBlock(block) {
if (!block)
block = this.chain.getTip();
block = this.chain.tip;
if (!this.last)
this.last = this.chain.tip;
// Somebody found the next block before
// us, start over with the new target.
@ -222,7 +235,7 @@ Miner.prototype.createBlock = function createBlock(tx) {
seq: 0xffffffff
});
if (script.getSize(coinbase.inputs[0].script) > 100)
if (bcoin.script.getSize(coinbase.inputs[0].script) > 100)
throw new Error('Coinbase script is too large');
coinbase.addOutput({

View File

@ -39,6 +39,7 @@ function Node(options) {
this.mempool = null;
this.pool = null;
this.chain = null;
this.miner = null;
Node.global = this;
@ -50,18 +51,19 @@ inherits(Node, EventEmitter);
Node.prototype._init = function _init() {
var self = this;
this.blockdb = new bcoin.blockdb(this.options.blockdb);
this.mempool = new bcoin.mempool(this, this.options.mempool);
if (!this.options.pool)
this.options.pool = {};
this.blockdb = new bcoin.blockdb(this.options.blockdb);
this.mempool = new bcoin.mempool(this, this.options.mempool);
this.options.pool.spv = false;
this.options.pool.blockdb = this.blockdb;
this.options.pool.mempool = this.mempool;
this.pool = new bcoin.pool(this.options.pool);
this.chain = this.pool.chain;
this.miner = new bcoin.miner(this.pool, this.options.miner);
this.mempool.on('error', function(err) {
self.emit('error', err);