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.logger = wallet.db.logger;
this.network = wallet.db.network; this.network = wallet.db.network;
this.options = wallet.db.options; this.options = wallet.db.options;
this.locked = {};
this.locker = new bcoin.locker(this); this.locker = new bcoin.locker(this);
this.coinCache = new bcoin.lru(10000, 1); this.coinCache = new bcoin.lru(10000, 1);
@ -808,6 +809,9 @@ TXDB.prototype.add = function add(tx, info, callback) {
if (err) if (err)
return callback(err); return callback(err);
// Clear any locked coins to free up memory.
self.unlockTX(tx);
self.emit('tx', tx, info); self.emit('tx', tx, info);
if (tx.ts !== 0) if (tx.ts !== 0)
@ -1000,6 +1004,9 @@ TXDB.prototype._confirm = function _confirm(tx, info, callback) {
// and remove pending flag to mark as confirmed. // and remove pending flag to mark as confirmed.
assert(tx.height >= 0); assert(tx.height >= 0);
// Clear any locked coins to free up memory.
self.unlockTX(tx);
// Save the original received time. // Save the original received time.
tx.ps = existing.ps; 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. * Get hashes of all transactions in the database.
* @param {Number?} account * @param {Number?} account

View File

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