txdb: add coin locking system.

This commit is contained in:
Christopher Jeffrey 2016-08-16 23:23:40 -07:00
parent 77502ca496
commit e235f3bee6
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
2 changed files with 94 additions and 4 deletions

View File

@ -255,6 +255,7 @@ function TXDB(wallet) {
this.logger = wallet.db.logger;
this.network = wallet.db.network;
this.options = wallet.db.options;
this.locked = {};
this.locker = new bcoin.locker(this);
this.coinCache = new bcoin.lru(10000, 1);
@ -808,6 +809,9 @@ TXDB.prototype.add = function add(tx, info, callback) {
if (err)
return callback(err);
// Clear any locked coins to free up memory.
self.unlockTX(tx);
self.emit('tx', tx, info);
if (tx.ts !== 0)
@ -1000,6 +1004,9 @@ TXDB.prototype._confirm = function _confirm(tx, info, callback) {
// and remove pending flag to mark as confirmed.
assert(tx.height >= 0);
// Clear any locked coins to free up memory.
self.unlockTX(tx);
// Save the original received time.
tx.ps = existing.ps;
@ -1308,6 +1315,90 @@ TXDB.prototype._unconfirm = function unconfirm(tx, info, callback, force) {
});
};
/**
* Lock all coins in a transaction.
* @param {TX} tx
*/
TXDB.prototype.lockTX = function lockTX(tx) {
var i, input;
if (tx.isCoinbase())
return;
for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i];
this.lockCoin(input.prevout);
}
};
/**
* Unlock all coins in a transaction.
* @param {TX} tx
*/
TXDB.prototype.unlockTX = function unlockTX(tx) {
var i, input;
if (tx.isCoinbase())
return;
for (i = 0; i < tx.inputs.length; i++) {
input = tx.inputs[i];
this.unlockCoin(input.prevout);
}
};
/**
* Lock a single coin.
* @param {Coin|Outpoint} coin
*/
TXDB.prototype.lockCoin = function lockCoin(coin) {
var key = coin.hash + coin.index;
this.locked[key] = true;
};
/**
* Unlock a single coin.
* @param {Coin|Outpoint} coin
*/
TXDB.prototype.unlockCoin = function unlockCoin(coin) {
var key = coin.hash + coin.index;
delete this.locked[key];
};
/**
* Test locked status of a single coin.
* @param {Coin|Outpoint} coin
*/
TXDB.prototype.isLocked = function isLocked(coin) {
var key = coin.hash + coin.index;
return this.locked[key] === true;
};
/**
* Filter array of coins or outpoints
* for only unlocked ones.
* @param {Coin[]|Outpoint[]}
* @returns {Array}
*/
TXDB.prototype.filterLocked = function filterLocked(coins) {
var out = [];
var i, coin;
for (i = 0; i < coins.length; i++) {
coin = coins[i];
if (!this.isLocked(coin))
out.push(coins);
}
return coins;
};
/**
* Get hashes of all transactions in the database.
* @param {Number?} account

View File

@ -815,6 +815,9 @@ Wallet.prototype.fund = function fund(tx, options, callback, force) {
rate = self.network.getRate();
}
// Don't use any locked coins.
coins = self.tx.filterLocked(coins);
try {
tx.fund(coins, {
selection: options.selection || 'age',
@ -2053,8 +2056,6 @@ function Account(db, options) {
if (!(this instanceof Account))
return new Account(db, options);
EventEmitter.call(this);
assert(db, 'Database is required.');
this.db = db;
@ -2082,8 +2083,6 @@ function Account(db, options) {
this.fromOptions(options);
}
utils.inherits(Account, EventEmitter);
/**
* Inject properties from options object.
* @private