misc fixes.
This commit is contained in:
parent
56f68983d3
commit
a9ec49f954
@ -187,11 +187,14 @@ Chain.prototype.__defineGetter__('height', function() {
|
|||||||
|
|
||||||
Chain.prototype._lock = function _lock(func, args, force) {
|
Chain.prototype._lock = function _lock(func, args, force) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var block;
|
var block, called;
|
||||||
|
|
||||||
if (force) {
|
if (force) {
|
||||||
assert(this.busy);
|
assert(this.busy);
|
||||||
return function() {};
|
return function unlock() {
|
||||||
|
assert(!called);
|
||||||
|
called = true;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.busy) {
|
if (this.busy) {
|
||||||
@ -214,6 +217,9 @@ Chain.prototype._lock = function _lock(func, args, force) {
|
|||||||
return function unlock() {
|
return function unlock() {
|
||||||
var item, block;
|
var item, block;
|
||||||
|
|
||||||
|
assert(!called);
|
||||||
|
called = true;
|
||||||
|
|
||||||
self.busy = false;
|
self.busy = false;
|
||||||
|
|
||||||
if (func === Chain.prototype.add) {
|
if (func === Chain.prototype.add) {
|
||||||
@ -584,9 +590,6 @@ Chain.prototype._checkDuplicates = function _checkDuplicates(block, prev, callba
|
|||||||
|
|
||||||
// BIP30 - Ensure there are no duplicate txids
|
// BIP30 - Ensure there are no duplicate txids
|
||||||
self.blockdb.hasTX(hash, function(err, result) {
|
self.blockdb.hasTX(hash, function(err, result) {
|
||||||
if (called)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return done(err);
|
return done(err);
|
||||||
|
|
||||||
@ -759,8 +762,6 @@ Chain.prototype.resetHeight = function resetHeight(height, force) {
|
|||||||
// no longer need.
|
// no longer need.
|
||||||
this.purgeOrphans();
|
this.purgeOrphans();
|
||||||
this.purgePending();
|
this.purgePending();
|
||||||
|
|
||||||
unlock();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.resetHeightAsync = function resetHeightAsync(height, callback, force) {
|
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)
|
if (self.orphan.size > self.orphanLimit)
|
||||||
self.pruneOrphans();
|
self.pruneOrphans();
|
||||||
|
|
||||||
|
// Keep track of total blocks handled.
|
||||||
|
self.total += total;
|
||||||
|
|
||||||
// We intentionally did not asyncify the
|
// We intentionally did not asyncify the
|
||||||
// callback so if it calls chain.add, it
|
// callback so if it calls chain.add, it
|
||||||
// still gets added to the queue. The
|
// 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
|
// so we don't cause a stack overflow if
|
||||||
// these end up being all sync chain.adds.
|
// these end up being all sync chain.adds.
|
||||||
utils.nextTick(function() {
|
utils.nextTick(function() {
|
||||||
// XXX Possibly put `unlock()` above callback!
|
unlock();
|
||||||
if (err)
|
if (err)
|
||||||
callback(err);
|
callback(err);
|
||||||
else
|
else
|
||||||
callback(null, total);
|
callback(null, total);
|
||||||
|
|
||||||
self.total += total;
|
|
||||||
|
|
||||||
unlock();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -123,8 +123,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.resetHeightAsync(height, callback);
|
return self.resetHeightAsync(height, callback);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
utils.debug('Chain successfully loaded.');
|
utils.debug('Chain successfully loaded.');
|
||||||
callback();
|
callback();
|
||||||
@ -157,6 +156,7 @@ ChainDB.prototype.closeSync = function closeSync() {
|
|||||||
this.ramdisk = null;
|
this.ramdisk = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.close(this.fd);
|
fs.close(this.fd);
|
||||||
this.fd = null;
|
this.fd = null;
|
||||||
};
|
};
|
||||||
@ -174,6 +174,7 @@ ChainDB.prototype.closeAsync = function closeAsync(callback) {
|
|||||||
fs.close(this.fd, function(err) {
|
fs.close(this.fd, function(err) {
|
||||||
if (err)
|
if (err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
self.fd = null;
|
self.fd = null;
|
||||||
return callback();
|
return callback();
|
||||||
});
|
});
|
||||||
@ -349,7 +350,7 @@ ChainDB.prototype.saveSync = function saveSync(entry) {
|
|||||||
|
|
||||||
if (entry.height * BLOCK_SIZE !== this.size) {
|
if (entry.height * BLOCK_SIZE !== this.size) {
|
||||||
utils.debug('Warning attempt to write to height: %d/%d', this.height);
|
utils.debug('Warning attempt to write to height: %d/%d', this.height);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache the past 1001 blocks in memory
|
// Cache the past 1001 blocks in memory
|
||||||
@ -402,8 +403,10 @@ ChainDB.prototype.saveAsync = function saveAsync(entry, callback) {
|
|||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
assert(self.queue[entry.height]);
|
assert(self.queue[entry.height]);
|
||||||
|
|
||||||
delete self.queue[entry.height];
|
delete self.queue[entry.height];
|
||||||
self.queueSize--;
|
self.queueSize--;
|
||||||
|
|
||||||
if (self.queueSize === 0)
|
if (self.queueSize === 0)
|
||||||
self.emit('flush');
|
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) {
|
ChainDB.prototype.resetHeightSync = function resetHeightSync(height) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var size, count, existing;
|
|
||||||
var osize = this.size;
|
var osize = this.size;
|
||||||
var ohighest = this.highest;
|
var ohighest = this.highest;
|
||||||
var otip = this.tip;
|
var otip = this.tip;
|
||||||
|
var size, count, existing;
|
||||||
|
|
||||||
if (typeof height === 'string')
|
if (typeof height === 'string')
|
||||||
height = this.heightLookup[height];
|
height = this.heightLookup[height];
|
||||||
|
|
||||||
assert(height >= 0);
|
assert(height >= 0);
|
||||||
|
assert(this.tip);
|
||||||
|
|
||||||
size = (height + 1) * BLOCK_SIZE;
|
size = (height + 1) * BLOCK_SIZE;
|
||||||
count = this.getSize();
|
count = this.getSize();
|
||||||
|
|
||||||
|
if (height > count - 1)
|
||||||
|
throw new Error('Height too high.');
|
||||||
|
|
||||||
if (height === count - 1)
|
if (height === count - 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert(height <= count - 1);
|
|
||||||
assert(this.tip);
|
|
||||||
|
|
||||||
for (i = height + 1; i < count; i++) {
|
for (i = height + 1; i < count; i++) {
|
||||||
existing = this.getSync(i);
|
existing = this.getSync(i);
|
||||||
|
|
||||||
assert(existing);
|
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];
|
delete this.heightLookup[existing.hash];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,28 +479,29 @@ ChainDB.prototype.resetHeightSync = function resetHeightSync(height) {
|
|||||||
|
|
||||||
ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback) {
|
ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var size, count, pending, called;
|
|
||||||
var osize = this.size;
|
var osize = this.size;
|
||||||
var ohighest = this.highest;
|
var ohighest = this.highest;
|
||||||
var otip = this.tip;
|
var otip = this.tip;
|
||||||
|
var size, count, pending, called;
|
||||||
|
|
||||||
|
callback = utils.asyncify(callback);
|
||||||
|
|
||||||
if (typeof height === 'string')
|
if (typeof height === 'string')
|
||||||
height = this.heightLookup[height];
|
height = this.heightLookup[height];
|
||||||
|
|
||||||
assert(height >= 0);
|
assert(height >= 0);
|
||||||
|
assert(this.tip);
|
||||||
callback = utils.asyncify(callback);
|
|
||||||
|
|
||||||
size = (height + 1) * BLOCK_SIZE;
|
size = (height + 1) * BLOCK_SIZE;
|
||||||
count = this.getSize();
|
count = this.getSize();
|
||||||
pending = count - (height + 1);
|
pending = count - (height + 1);
|
||||||
|
|
||||||
|
if (height > count - 1)
|
||||||
|
return callback(new Error('Height too high'));
|
||||||
|
|
||||||
if (height === count - 1)
|
if (height === count - 1)
|
||||||
return callback();
|
return callback();
|
||||||
|
|
||||||
assert(height <= count - 1);
|
|
||||||
assert(this.tip);
|
|
||||||
|
|
||||||
// Prevent any more writes
|
// Prevent any more writes
|
||||||
// by setting this early.
|
// by setting this early.
|
||||||
this.size = size;
|
this.size = size;
|
||||||
@ -527,8 +526,14 @@ ChainDB.prototype.resetHeightAsync = function resetHeightAsync(height, callback)
|
|||||||
|
|
||||||
assert(existing);
|
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];
|
delete self.heightLookup[existing.hash];
|
||||||
|
|
||||||
if (!--pending)
|
if (!--pending)
|
||||||
done();
|
done();
|
||||||
}, true);
|
}, true);
|
||||||
|
|||||||
@ -19,7 +19,7 @@ var fs = bcoin.fs;
|
|||||||
* Mempool
|
* Mempool
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Mempool(pool, options) {
|
function Mempool(node, options) {
|
||||||
if (!(this instanceof Mempool))
|
if (!(this instanceof Mempool))
|
||||||
return new Mempool(pool, options);
|
return new Mempool(pool, options);
|
||||||
|
|
||||||
@ -27,8 +27,8 @@ function Mempool(pool, options) {
|
|||||||
options = {};
|
options = {};
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.pool = pool;
|
this.node = node;
|
||||||
this.blockdb = pool.blockdb;
|
this.blockdb = node.blockdb;
|
||||||
|
|
||||||
this.txs = {};
|
this.txs = {};
|
||||||
this.spent = {};
|
this.spent = {};
|
||||||
@ -235,7 +235,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
|||||||
data: tx.hash(),
|
data: tx.hash(),
|
||||||
reason: 'non-standard'
|
reason: 'non-standard'
|
||||||
});
|
});
|
||||||
pool.setMisbehavior(peer, 100);
|
self.node.pool.setMisbehavior(peer, 100);
|
||||||
return callback(new Error('TX is not standard.'));
|
return callback(new Error('TX is not standard.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,7 +245,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
|||||||
data: tx.hash(),
|
data: tx.hash(),
|
||||||
reason: 'non-standard-inputs'
|
reason: 'non-standard-inputs'
|
||||||
});
|
});
|
||||||
pool.setMisbehavior(peer, 100);
|
self.node.pool.setMisbehavior(peer, 100);
|
||||||
return callback(new Error('TX inputs are not standard.'));
|
return callback(new Error('TX inputs are not standard.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,11 +255,11 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
|||||||
data: tx.hash(),
|
data: tx.hash(),
|
||||||
reason: 'nonexistent-coins'
|
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.'));
|
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();
|
ts = utils.now();
|
||||||
if (!tx.isFinal(height, ts)) {
|
if (!tx.isFinal(height, ts)) {
|
||||||
return callback(new Error('TX is not final.'));
|
return callback(new Error('TX is not final.'));
|
||||||
@ -267,7 +267,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
|||||||
data: tx.hash(),
|
data: tx.hash(),
|
||||||
reason: 'not-final'
|
reason: 'not-final'
|
||||||
});
|
});
|
||||||
pool.setMisbehavior(peer, 100);
|
self.node.pool.setMisbehavior(peer, 100);
|
||||||
return callback(new Error('TX is not final.'));
|
return callback(new Error('TX is not final.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
|||||||
data: tx.hash(),
|
data: tx.hash(),
|
||||||
reason: 'negative-value'
|
reason: 'negative-value'
|
||||||
});
|
});
|
||||||
pool.setMisbehavior(peer, 100);
|
self.node.pool.setMisbehavior(peer, 100);
|
||||||
return callback(new Error('TX is spending negative coins.'));
|
return callback(new Error('TX is spending negative coins.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,7 +310,7 @@ Mempool.prototype.addTX = function addTX(tx, peer, callback) {
|
|||||||
data: tx.hash(),
|
data: tx.hash(),
|
||||||
reason: 'script-failed'
|
reason: 'script-failed'
|
||||||
});
|
});
|
||||||
pool.setMisbehavior(peer, 100);
|
self.node.pool.setMisbehavior(peer, 100);
|
||||||
return callback(new Error('TX did not verify.'));
|
return callback(new Error('TX did not verify.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ var EventEmitter = require('events').EventEmitter;
|
|||||||
* Miner
|
* Miner
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function Miner(options) {
|
function Miner(pool, options) {
|
||||||
if (!(this instanceof Miner))
|
if (!(this instanceof Miner))
|
||||||
return new Miner(options);
|
return new Miner(options);
|
||||||
|
|
||||||
@ -30,15 +30,17 @@ function Miner(options) {
|
|||||||
this.address = this.options.address;
|
this.address = this.options.address;
|
||||||
this.msg = this.options.msg || 'mined by bcoin';
|
this.msg = this.options.msg || 'mined by bcoin';
|
||||||
|
|
||||||
this.pool = options.pool || bcoin.pool.global;
|
this.pool = pool || bcoin.pool.global;
|
||||||
this.chain = options.chain || this.pool.chain || bcoin.chain.global;
|
this.chain = this.pool.chain;
|
||||||
|
this.mempool = this.pool.mempool;
|
||||||
|
this.blockdb = this.pool.blockdb;
|
||||||
|
|
||||||
this.running = false;
|
this.running = false;
|
||||||
this.timeout = null;
|
this.timeout = null;
|
||||||
this.interval = null;
|
this.interval = null;
|
||||||
|
|
||||||
this.fee = new bn(0);
|
this.fee = new bn(0);
|
||||||
this.last = this.chain.getTip();
|
this.last = this.chain.tip;
|
||||||
this.block = null;
|
this.block = null;
|
||||||
this.iterations = 0;
|
this.iterations = 0;
|
||||||
this._begin = utils.now();
|
this._begin = utils.now();
|
||||||
@ -51,18 +53,26 @@ inherits(Miner, EventEmitter);
|
|||||||
Miner.prototype._init = function _init() {
|
Miner.prototype._init = function _init() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.pool.on('tx', function(tx) {
|
if (this.mempool) {
|
||||||
self.addTX(tx);
|
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);
|
self.addBlock(block);
|
||||||
});
|
});
|
||||||
|
|
||||||
// this.chain.on('tip', function(entry) {
|
|
||||||
// self.addBlock(entry);
|
|
||||||
// });
|
|
||||||
|
|
||||||
this.on('block', function(block) {
|
this.on('block', function(block) {
|
||||||
utils.debug(
|
utils.debug(
|
||||||
'Found block: %d (%s)',
|
'Found block: %d (%s)',
|
||||||
@ -123,7 +133,10 @@ Miner.prototype.add = function add(msg) {
|
|||||||
|
|
||||||
Miner.prototype.addBlock = function addBlock(block) {
|
Miner.prototype.addBlock = function addBlock(block) {
|
||||||
if (!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
|
// Somebody found the next block before
|
||||||
// us, start over with the new target.
|
// us, start over with the new target.
|
||||||
@ -222,7 +235,7 @@ Miner.prototype.createBlock = function createBlock(tx) {
|
|||||||
seq: 0xffffffff
|
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');
|
throw new Error('Coinbase script is too large');
|
||||||
|
|
||||||
coinbase.addOutput({
|
coinbase.addOutput({
|
||||||
|
|||||||
@ -39,6 +39,7 @@ function Node(options) {
|
|||||||
this.mempool = null;
|
this.mempool = null;
|
||||||
this.pool = null;
|
this.pool = null;
|
||||||
this.chain = null;
|
this.chain = null;
|
||||||
|
this.miner = null;
|
||||||
|
|
||||||
Node.global = this;
|
Node.global = this;
|
||||||
|
|
||||||
@ -50,18 +51,19 @@ inherits(Node, EventEmitter);
|
|||||||
Node.prototype._init = function _init() {
|
Node.prototype._init = function _init() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.blockdb = new bcoin.blockdb(this.options.blockdb);
|
|
||||||
this.mempool = new bcoin.mempool(this, this.options.mempool);
|
|
||||||
|
|
||||||
if (!this.options.pool)
|
if (!this.options.pool)
|
||||||
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.spv = false;
|
||||||
this.options.pool.blockdb = this.blockdb;
|
this.options.pool.blockdb = this.blockdb;
|
||||||
this.options.pool.mempool = this.mempool;
|
this.options.pool.mempool = this.mempool;
|
||||||
|
|
||||||
this.pool = new bcoin.pool(this.options.pool);
|
this.pool = new bcoin.pool(this.options.pool);
|
||||||
this.chain = this.pool.chain;
|
this.chain = this.pool.chain;
|
||||||
|
this.miner = new bcoin.miner(this.pool, this.options.miner);
|
||||||
|
|
||||||
this.mempool.on('error', function(err) {
|
this.mempool.on('error', function(err) {
|
||||||
self.emit('error', err);
|
self.emit('error', err);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user