add locks to txdb.

This commit is contained in:
Christopher Jeffrey 2016-03-21 17:29:15 -07:00
parent 2797cd2f44
commit eb569ae12d
3 changed files with 77 additions and 46 deletions

View File

@ -12,12 +12,15 @@ var db = {};
module.exports = function ldb(name, options) {
var file = bcoin.prefix + '/' + name + '-' + network.type + '.db';
var backend = process.env.BCOIN_DB;
var backend = typeof options.db === 'string'
? options.db
: process.env.BCOIN_DB;
if (!db[file]) {
if (options.db) {
if (options.db && typeof options.db !== 'string') {
bcoin.ensurePrefix();
backend = options.db;
} else if (bcoin.isBrowser) {
} else if (bcoin.isBrowser && backend !== 'memdown') {
backend = require('level-js');
} else {
if (!backend || backend === 'leveldb')
@ -26,6 +29,11 @@ module.exports = function ldb(name, options) {
backend = 'rocksdown';
else if (backend === 'lmdb')
backend = 'lmdb';
else if (backend === 'memory')
backend = 'memdown';
if (backend !== 'memdown')
bcoin.ensurePrefix();
backend = require(backend);
}
@ -33,8 +41,6 @@ module.exports = function ldb(name, options) {
if (!options)
options = {};
bcoin.ensurePrefix();
db[file] = new LowlevelUp(file, {
keyEncoding: 'ascii',
valueEncoding: 'binary',

View File

@ -29,6 +29,13 @@ function Mempool(node, options) {
this.node = node;
this.chain = node.chain;
this.db = node.chain.db;
if (this.options.memory) {
this.db = bcoin.ldb('mempool', {
db: 'memdown'
});
}
this.tx = new bcoin.txdb('m', this.db, {
indexSpent: true,
indexExtra: false,
@ -100,7 +107,7 @@ Mempool.prototype._lock = function _lock(func, args, force) {
self.busy = false;
if (func === Chain.prototype.add) {
if (func === Mempool.prototype.add) {
if (self.pending.length === 0)
self.emit('flush');
}

View File

@ -182,7 +182,7 @@ TXPool.prototype.mapAddresses = function mapAddresses(address, callback) {
})();
};
TXPool.prototype._addOrphan = function add(key, hash, index, callback) {
TXPool.prototype._addOrphan = function _addOrphan(key, hash, index, callback) {
var prefix = this.prefix + '/';
var orphans;
@ -243,12 +243,12 @@ TXPool.prototype._getOrphans = function _getOrphans(key, callback) {
});
};
TXPool.prototype.add = function add(tx, callback) {
TXPool.prototype.add = function add(tx, callback, force) {
var self = this;
if (Array.isArray(tx)) {
return utils.forEachSerial(tx, function(tx, next) {
self.add(tx, next);
self.add(tx, next, force);
}, callback);
}
@ -261,7 +261,7 @@ TXPool.prototype.add = function add(tx, callback) {
return callback(null, false);
}
return self._add(tx, map, callback);
return self._add(tx, map, callback, force);
});
};
@ -281,20 +281,16 @@ TXPool.prototype._add = function add(tx, map, callback, force) {
if (!unlock)
return;
function done(err, result) {
unlock();
if (callback)
callback(err, result);
}
callback = utils.wrap(callback, unlock);
// Attempt to confirm tx before adding it.
this._confirm(tx, map, function(err, existing) {
if (err)
return done(err);
return callback(err);
// Ignore if we already have this tx.
if (existing)
return done(null, true);
return callback(null, true);
batch = self.db.batch();
@ -353,7 +349,7 @@ TXPool.prototype._add = function add(tx, map, callback, force) {
// Skip invalid transactions
if (!tx.verify(i))
return done(null, false);
return callback(null, false);
updated = true;
@ -390,16 +386,16 @@ TXPool.prototype._add = function add(tx, map, callback, force) {
self.isSpent(input.prevout.hash, input.prevout.index, function(err, result) {
if (err)
return done(err);
return callback(err);
// Are we double-spending?
if (result)
return done(new Error('Transaction is double-spending.'));
return callback(new Error('Transaction is double-spending.'));
// Add orphan, if no parent transaction is yet known
self._addOrphan(key, hash, i, function(err, orphans) {
if (err)
return done(err);
return callback(err);
batch.put(prefix + 'o/' + key, orphans);
@ -409,7 +405,7 @@ TXPool.prototype._add = function add(tx, map, callback, force) {
});
}, function(err) {
if (err)
return done(err);
return callback(err);
// Add unspent outputs or resolve orphans
utils.forEachSerial(tx.outputs, function(output, next, i) {
@ -429,7 +425,7 @@ TXPool.prototype._add = function add(tx, map, callback, force) {
var some = false;
if (err)
return done(err);
return callback(err);
if (!orphans)
return finish();
@ -459,7 +455,7 @@ TXPool.prototype._add = function add(tx, map, callback, force) {
if (err)
return next(err);
return next();
});
}, true);
}, function(err) {
if (err)
return next(err);
@ -493,11 +489,11 @@ TXPool.prototype._add = function add(tx, map, callback, force) {
});
}, function(err) {
if (err)
return done(err);
return callback(err);
batch.write(function(err) {
if (err)
return done(err);
return callback(err);
self.emit('tx', tx, map);
@ -508,11 +504,11 @@ TXPool.prototype._add = function add(tx, map, callback, force) {
self.emit('updated', tx, map);
}
return done(null, true);
return callback(null, true);
});
});
});
});
}, true);
};
TXPool.prototype.isSpent = function isSpent(hash, index, callback, checkCoin) {
@ -548,12 +544,18 @@ TXPool.prototype.isSpent = function isSpent(hash, index, callback, checkCoin) {
});
};
TXPool.prototype._confirm = function _confirm(tx, map, callback) {
TXPool.prototype._confirm = function _confirm(tx, map, callback, force) {
var self = this;
var prefix = this.prefix + '/';
var hash = tx.hash('hex');
var batch;
var unlock = this._lock(_confirm, [tx, map, callback], force);
if (!unlock)
return;
callback = utils.wrap(callback, unlock);
this.getTX(hash, function(err, existing) {
if (err)
return callback(err);
@ -634,16 +636,16 @@ TXPool.prototype._confirm = function _confirm(tx, map, callback) {
});
};
TXPool.prototype.remove = function remove(hash, callback) {
TXPool.prototype.remove = function remove(hash, callback, force) {
var self = this;
var first = Array.isArray(hash) ? hash[0] : hash;
if (!this.options.indexExtra && (first instanceof bcoin.tx))
return this.lazyRemove(hash, callback);
return this.lazyRemove(hash, callback, force);
if (Array.isArray(hash)) {
return utils.forEachSerial(hash, function(hash, next) {
self.remove(hash, next);
self.remove(hash, next, force);
}, callback);
}
@ -668,17 +670,17 @@ TXPool.prototype.remove = function remove(hash, callback) {
return callback(null, false);
}
return self._remove(tx, map, callback);
return self._remove(tx, map, callback, force);
});
});
};
TXPool.prototype.lazyRemove = function lazyRemove(tx, callback) {
TXPool.prototype.lazyRemove = function lazyRemove(tx, callback, force) {
var self = this;
if (Array.isArray(tx)) {
return utils.forEachSerial(tx, function(tx, next) {
self.lazyRemove(tx, next);
self.lazyRemove(tx, next, force);
}, callback);
}
@ -691,15 +693,23 @@ TXPool.prototype.lazyRemove = function lazyRemove(tx, callback) {
return callback(null, false);
}
return self._remove(tx, map, callback);
return self._remove(tx, map, callback, force);
});
};
TXPool.prototype._remove = function remove(tx, map, callback) {
TXPool.prototype._remove = function remove(tx, map, callback, force) {
var self = this;
var prefix = this.prefix + '/';
var hash = tx.hash('hex');
var batch = this.db.batch();
var batch;
var unlock = this._lock(remove, [tx, map, callback], force);
if (!unlock)
return;
callback = utils.wrap(callback, unlock);
batch = this.db.batch();
batch.del(prefix + 't/t/' + hash);
@ -795,12 +805,12 @@ TXPool.prototype._remove = function remove(tx, map, callback) {
});
};
TXPool.prototype.unconfirm = function unconfirm(hash, callback) {
TXPool.prototype.unconfirm = function unconfirm(hash, callback, force) {
var self = this;
if (Array.isArray(hash)) {
return utils.forEachSerial(hash, function(hash, next) {
self.unconfirm(hash, next);
self.unconfirm(hash, next, force);
}, callback);
}
@ -827,18 +837,26 @@ TXPool.prototype.unconfirm = function unconfirm(hash, callback) {
return callback(null, false);
}
return self._unconfirm(tx, map, callback);
return self._unconfirm(tx, map, callback, force);
});
});
};
TXPool.prototype._unconfirm = function unconfirm(tx, map, callback) {
TXPool.prototype._unconfirm = function unconfirm(tx, map, callback, force) {
var self = this;
var prefix = this.prefix + '/';
var hash = tx.hash('hex');
var batch = this.db.batch();
var height = tx.height;
var ts = tx.ts;
var hash, batch, height, ts;
var unlock = this._lock(unconfirm, [tx, map, callback], force);
if (!unlock)
return;
callback = utils.wrap(callback, unlock);
hash = tx.hash('hex');
batch = this.db.batch();
height = tx.height;
ts = tx.ts;
if (height !== -1)
return callback(null, false);