txdb: add coin locking system.
This commit is contained in:
parent
77502ca496
commit
e235f3bee6
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user