add locks to txdb.
This commit is contained in:
parent
2797cd2f44
commit
eb569ae12d
@ -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',
|
||||
|
||||
@ -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');
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user