walletdb: remove global methods. in-memory balance.

This commit is contained in:
Christopher Jeffrey 2016-08-14 16:31:12 -07:00
parent 9a1ba962fd
commit 1e98ce25d9
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
4 changed files with 161 additions and 392 deletions

View File

@ -298,7 +298,7 @@ Fullnode.prototype._open = function open(callback) {
}, },
function(next) { function(next) {
if (self.options.noScan) { if (self.options.noScan) {
self.walletdb.writeTip(self.chain.tip.hash, next); self.walletdb.setTip(self.chain.tip.hash, 0, next);
return next(); return next();
} }
// Always rescan to make sure we didn't miss anything: // Always rescan to make sure we didn't miss anything:

View File

@ -48,12 +48,39 @@ 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.locker = new bcoin.locker(this); this.locker = new bcoin.locker(this);
this.current = null;
this.coinCache = new bcoin.lru(10000, 1); this.coinCache = new bcoin.lru(10000, 1);
this.balance = new Balance();
this.current = null;
this.balance = null;
} }
/**
* Open TXDB.
* @param {Function} callback
*/
TXDB.prototype.open = function open(callback) {
var self = this;
this.getBalance(function(err, balance) {
if (err)
return callback(err);
self.logger.info('TXDB loaded for %s.', self.wallet.id);
self.logger.info(
'Balance: unconfirmed=%s confirmed=%s total=%s.',
utils.btc(balance.unconfirmed),
utils.btc(balance.confirmed),
utils.btc(balance.total));
self.balance = balance;
return callback();
});
};
/** /**
* Compile wallet prefix. * Compile wallet prefix.
* @param {String} key * @param {String} key
@ -1086,11 +1113,11 @@ TXDB.prototype.getHistoryHashes = function getHistoryHashes(account, callback) {
} }
this.iterate({ this.iterate({
gte: account ? 'T/' + account + '/' : 't', gte: account != null ? 'T/' + account + '/' : 't',
lte: account ? 'T/' + account + '/~' : 't~', lte: account != null ? 'T/' + account + '/~' : 't~',
transform: function(key) { transform: function(key) {
key = key.split('/'); key = key.split('/');
if (account) if (account != null)
return key[4]; return key[4];
return key[3]; return key[3];
} }
@ -1110,11 +1137,11 @@ TXDB.prototype.getUnconfirmedHashes = function getUnconfirmedHashes(account, cal
} }
this.iterate({ this.iterate({
gte: account ? 'P/' + account + '/' : 'p', gte: account != null ? 'P/' + account + '/' : 'p',
lte: account ? 'P/' + account + '/~' : 'p~', lte: account != null ? 'P/' + account + '/~' : 'p~',
transform: function(key) { transform: function(key) {
key = key.split('/'); key = key.split('/');
if (account) if (account != null)
return key[4]; return key[4];
return key[3]; return key[3];
} }
@ -1134,11 +1161,11 @@ TXDB.prototype.getCoinHashes = function getCoinHashes(account, callback) {
} }
this.iterate({ this.iterate({
gte: account ? 'C/' + account + '/' : 'c', gte: account != null ? 'C/' + account + '/' : 'c',
lte: account ? 'C/' + account + '/~' : 'c~', lte: account != null ? 'C/' + account + '/~' : 'c~',
transform: function(key) { transform: function(key) {
key = key.split('/'); key = key.split('/');
if (account) if (account != null)
return [key[4], +key[5]]; return [key[4], +key[5]];
return [key[3], +key[4]]; return [key[3], +key[4]];
} }
@ -1157,24 +1184,24 @@ TXDB.prototype.getCoinHashes = function getCoinHashes(account, callback) {
*/ */
TXDB.prototype.getHeightRangeHashes = function getHeightRangeHashes(account, options, callback) { TXDB.prototype.getHeightRangeHashes = function getHeightRangeHashes(account, options, callback) {
if (typeof account !== 'string') { if (typeof account !== 'number') {
callback = options; callback = options;
options = account; options = account;
account = null; account = null;
} }
this.iterate({ this.iterate({
gte: account gte: account != null
? 'H/' + account + '/' + pad32(options.start) + '/' ? 'H/' + account + '/' + pad32(options.start) + '/'
: 'h/' + pad32(options.start) + '/', : 'h/' + pad32(options.start) + '/',
lte: account lte: account != null
? 'H/' + account + '/' + pad32(options.end) + '/~' ? 'H/' + account + '/' + pad32(options.end) + '/~'
: 'h/' + pad32(options.end) + '/~', : 'h/' + pad32(options.end) + '/~',
limit: options.limit, limit: options.limit,
reverse: options.reverse, reverse: options.reverse,
transform: function(key) { transform: function(key) {
key = key.split('/'); key = key.split('/');
if (account) if (account != null)
return key[4]; return key[4];
return key[3]; return key[3];
} }
@ -1209,17 +1236,17 @@ TXDB.prototype.getRangeHashes = function getRangeHashes(account, options, callba
} }
this.iterate({ this.iterate({
gte: account gte: account != null
? 'M/' + account + '/' + pad32(options.start) + '/' ? 'M/' + account + '/' + pad32(options.start) + '/'
: 'm/' + pad32(options.start) + '/', : 'm/' + pad32(options.start) + '/',
lte: account lte: account != null
? 'M/' + account + '/' + pad32(options.end) + '/~' ? 'M/' + account + '/' + pad32(options.end) + '/~'
: 'm/' + pad32(options.end) + '/~', : 'm/' + pad32(options.end) + '/~',
limit: options.limit, limit: options.limit,
reverse: options.reverse, reverse: options.reverse,
transform: function(key) { transform: function(key) {
key = key.split('/'); key = key.split('/');
if (account) if (account != null)
return key[4]; return key[4];
return key[3]; return key[3];
} }
@ -1237,7 +1264,7 @@ TXDB.prototype.getRangeHashes = function getRangeHashes(account, options, callba
* @param {Function} callback - Returns [Error, {@link TX}[]]. * @param {Function} callback - Returns [Error, {@link TX}[]].
*/ */
TXDB.prototype.getRange = function getLast(account, options, callback) { TXDB.prototype.getRange = function getRange(account, options, callback) {
var self = this; var self = this;
var txs = []; var txs = [];
@ -1308,6 +1335,36 @@ TXDB.prototype.getHistory = function getHistory(account, callback) {
account = null; account = null;
} }
// Slow case
if (account != null)
return this.getAccountHistory(account, callback);
// Fast case
this.iterate({
gte: 't',
lte: 't~',
values: true,
parse: function(data) {
return bcoin.tx.fromExtended(data);
}
}, callback);
};
/**
* Get all account transactions.
* @param {Number?} account
* @param {Function} callback - Returns [Error, {@link TX}[]].
*/
TXDB.prototype.getAccountHistory = function getAccountHistory(account, callback) {
var self = this;
var txs = [];
if (typeof account === 'function') {
callback = account;
account = null;
}
this.getHistoryHashes(account, function(err, hashes) { this.getHistoryHashes(account, function(err, hashes) {
if (err) if (err)
return callback(err); return callback(err);
@ -1423,7 +1480,7 @@ TXDB.prototype.getCoins = function getCoins(account, callback) {
} }
// Slow case // Slow case
if (account) if (account != null)
return this.getAccountCoins(account, callback); return this.getAccountCoins(account, callback);
// Fast case // Fast case
@ -1623,7 +1680,7 @@ TXDB.prototype.toDetails = function toDetails(tx, callback) {
return callback(err); return callback(err);
if (!info) if (!info)
return callback(); return callback(new Error('Info not found.'));
return callback(null, info.toDetails()); return callback(null, info.toDetails());
}); });
@ -1695,7 +1752,7 @@ TXDB.prototype.hasCoin = function hasCoin(hash, index, callback) {
TXDB.prototype.getBalance = function getBalance(account, callback) { TXDB.prototype.getBalance = function getBalance(account, callback) {
var self = this; var self = this;
var balance = new Balance(this.wallet.id); var balance;
if (typeof account === 'function') { if (typeof account === 'function') {
callback = account; callback = account;
@ -1703,10 +1760,16 @@ TXDB.prototype.getBalance = function getBalance(account, callback) {
} }
// Slow case // Slow case
if (account) if (account != null)
return this.getAccountBalance(account, callback); return this.getAccountBalance(account, callback);
// Really fast case
if (this.balance)
return callback(null, this.balance);
// Fast case // Fast case
balance = new Balance(this.wallet.id);
this.iterate({ this.iterate({
gte: 'c', gte: 'c',
lte: 'c~', lte: 'c~',
@ -1832,7 +1895,7 @@ TXDB.prototype.zap = function zap(account, age, callback, force) {
callback = utils.wrap(callback, unlock); callback = utils.wrap(callback, unlock);
if (!utils.isNumber(age)) if (!utils.isUInt32(age))
return callback(new Error('Age must be a number.')); return callback(new Error('Age must be a number.'));
this.getRange(account, { this.getRange(account, {
@ -1863,7 +1926,7 @@ TXDB.prototype.abandon = function abandon(hash, callback, force) {
return callback(err); return callback(err);
if (!result) if (!result)
return callback(new Error('TX not found.')); return callback(new Error('TX not eligible.'));
self.remove(hash, callback, force); self.remove(hash, callback, force);
}); });
@ -2016,6 +2079,14 @@ Balance.prototype.toJSON = function toJSON() {
}; };
}; };
Balance.prototype.toString = function toString() {
return '<Balance'
+ ' unconfirmed=' + utils.btc(this.unconfirmed)
+ ' confirmed=' + utils.btc(this.confirmed)
+ ' total=' + utils.btc(this.total)
+ '>';
};
/* /*
* Helpers * Helpers
*/ */

View File

@ -170,7 +170,7 @@ Wallet.prototype.init = function init(options, callback) {
self.account = account; self.account = account;
return callback(); self.tx.open(callback);
}); });
}); });
}; };
@ -194,7 +194,7 @@ Wallet.prototype.open = function open(callback) {
self.account = account; self.account = account;
return callback(); self.tx.open(callback);
}); });
}; };
@ -207,8 +207,8 @@ Wallet.prototype.destroy = function destroy(callback) {
callback = utils.ensure(callback); callback = utils.ensure(callback);
try { try {
if (this.db.unregister(this)) this.db.unregister(this);
this.master.destroy(); this.master.destroy();
} catch (e) { } catch (e) {
this.emit('error', e); this.emit('error', e);
return callback(e); return callback(e);
@ -792,7 +792,7 @@ Wallet.prototype.fund = function fund(tx, options, callback, force) {
fee: options.fee, fee: options.fee,
subtractFee: options.subtractFee, subtractFee: options.subtractFee,
changeAddress: account.changeAddress.getAddress(), changeAddress: account.changeAddress.getAddress(),
height: self.network.height, height: self.db.height,
rate: rate, rate: rate,
wallet: self, wallet: self,
m: self.m, m: self.m,
@ -850,12 +850,12 @@ Wallet.prototype.createTX = function createTX(options, callback, force) {
// if (options.locktime != null) // if (options.locktime != null)
// tx.setLocktime(options.locktime); // tx.setLocktime(options.locktime);
// else // else
// tx.avoidFeeSniping(options.height); // tx.avoidFeeSniping(self.db.height);
if (!tx.isSane()) if (!tx.isSane())
return callback(new Error('CheckTransaction failed.')); return callback(new Error('CheckTransaction failed.'));
if (!tx.checkInputs(options.height)) if (!tx.checkInputs(self.db.height))
return callback(new Error('CheckInputs failed.')); return callback(new Error('CheckInputs failed.'));
self.scriptInputs(tx, function(err, total) { self.scriptInputs(tx, function(err, total) {

View File

@ -52,9 +52,12 @@ function WalletDB(options) {
this.fees = options.fees; this.fees = options.fees;
this.logger = options.logger || bcoin.defaultLogger; this.logger = options.logger || bcoin.defaultLogger;
this.batches = {}; this.batches = {};
this.watchers = {}; this.wallets = {};
this.workerPool = null; this.workerPool = null;
this.tip = this.network.genesis.hash;
this.height = 0;
// We need one read lock for `get` and `create`. // We need one read lock for `get` and `create`.
// It will hold locks specific to wallet ids. // It will hold locks specific to wallet ids.
this.readLock = new ReadLock(this); this.readLock = new ReadLock(this);
@ -140,13 +143,12 @@ WalletDB.prototype._open = function open(callback) {
WalletDB.prototype._close = function close(callback) { WalletDB.prototype._close = function close(callback) {
var self = this; var self = this;
var keys = Object.keys(this.watchers); var keys = Object.keys(this.wallets);
var watcher; var wallet;
utils.forEachSerial(keys, function(key, next) { utils.forEachSerial(keys, function(key, next) {
watcher = self.watchers[key]; wallet = self.wallets[key];
watcher.refs = 1; wallet.destroy(next);
watcher.object.destroy(next);
}, function(err) { }, function(err) {
if (err) if (err)
return callback(err); return callback(err);
@ -286,19 +288,9 @@ WalletDB.prototype.dump = function dump(callback) {
* @param {Object} object * @param {Object} object
*/ */
WalletDB.prototype.register = function register(object) { WalletDB.prototype.register = function register(wallet) {
var id = object.id; assert(!this.wallets[wallet.id]);
this.wallets[wallet.id] = wallet;
if (!this.watchers[id])
this.watchers[id] = { object: object, refs: 0 };
// Should never happen, and if it does, I will cry.
assert(this.watchers[id].object === object, 'I\'m crying.');
// We do some reference counting here
// because we're thug like that (police
// have a fit when your papers legit).
this.watchers[id].refs++;
}; };
/** /**
@ -307,25 +299,9 @@ WalletDB.prototype.register = function register(object) {
* @returns {Boolean} * @returns {Boolean}
*/ */
WalletDB.prototype.unregister = function unregister(object) { WalletDB.prototype.unregister = function unregister(wallet) {
var id = object.id; assert(this.wallets[wallet.id]);
var watcher = this.watchers[id]; delete this.wallets[wallet.id];
// NOP for now!
return false;
if (!watcher)
return false;
assert(watcher.object === object);
assert(watcher.refs !== 0, '`destroy()` called twice!');
if (--watcher.refs === 0) {
delete this.watchers[id];
return true;
}
return false;
}; };
/** /**
@ -336,7 +312,7 @@ WalletDB.prototype.unregister = function unregister(object) {
WalletDB.prototype.get = function get(id, callback) { WalletDB.prototype.get = function get(id, callback) {
var self = this; var self = this;
var unlock, watcher; var unlock, wallet;
unlock = this._lock(id, get, [id, callback]); unlock = this._lock(id, get, [id, callback]);
@ -348,12 +324,10 @@ WalletDB.prototype.get = function get(id, callback) {
if (!id) if (!id)
return callback(); return callback();
watcher = this.watchers[id]; wallet = this.wallets[id];
if (watcher) { if (wallet)
watcher.refs++; return callback(null, wallet);
return callback(null, watcher.object);
}
this._get(id, function(err, wallet) { this._get(id, function(err, wallet) {
if (err) if (err)
@ -521,7 +495,7 @@ WalletDB.prototype.has = function has(id, callback) {
if (!id) if (!id)
return callback(null, false); return callback(null, false);
if (this.watchers[id]) if (this.wallets[id])
return callback(null, true); return callback(null, true);
if (this.walletCache.has(id)) if (this.walletCache.has(id))
@ -948,7 +922,7 @@ WalletDB.prototype.getWallets = function getWallets(callback) {
WalletDB.prototype.rescan = function rescan(chaindb, callback) { WalletDB.prototype.rescan = function rescan(chaindb, callback) {
var self = this; var self = this;
this.getTip(function(err, hash) { this.getTip(function(err, hash, height) {
if (err) if (err)
return callback(err); return callback(err);
@ -965,7 +939,7 @@ WalletDB.prototype.rescan = function rescan(chaindb, callback) {
self.addTX(tx, function(err) { self.addTX(tx, function(err) {
if (err) if (err)
return next(err); return next(err);
self.writeTip(block.hash, next); self.setTip(block.hash, block.height, next);
}); });
}, callback); }, callback);
}); });
@ -989,9 +963,6 @@ WalletDB.prototype.fetchWallet = function fetchWallet(id, callback, handler) {
return callback(new Error('No wallet.')); return callback(new Error('No wallet.'));
handler(wallet, function(err, res1, res2) { handler(wallet, function(err, res1, res2) {
// Kill the reference.
// wallet.destroy();
if (err) if (err)
return callback(err); return callback(err);
@ -1102,18 +1073,18 @@ WalletDB.prototype.getTable = function getTable(address, callback) {
WalletDB.prototype.writeGenesis = function writeGenesis(callback) { WalletDB.prototype.writeGenesis = function writeGenesis(callback) {
var self = this; var self = this;
var hash;
this.db.has('R', function(err, result) { this.getTip(function(err, hash, height) {
if (err) if (err)
return callback(err); return callback(err);
if (result) if (hash) {
self.tip = hash;
self.height = height;
return callback(); return callback();
}
hash = new Buffer(self.network.genesis.hash, 'hex'); self.setTip(self.tip, self.height, callback);
self.db.put('R', hash, callback);
}); });
}; };
@ -1124,8 +1095,17 @@ WalletDB.prototype.writeGenesis = function writeGenesis(callback) {
WalletDB.prototype.getTip = function getTip(callback) { WalletDB.prototype.getTip = function getTip(callback) {
this.db.fetch('R', function(data) { this.db.fetch('R', function(data) {
return data.toString('hex'); var p = new BufferReader(data);
}, callback); return [p.readHash('hex'), p.readU32()];
}, function(err, items) {
if (err)
return callback(err);
if (!items)
return callback(null, null, -1);
return callback(null, items[0], items[1]);
});
}; };
/** /**
@ -1134,10 +1114,22 @@ WalletDB.prototype.getTip = function getTip(callback) {
* @param {Function} callback * @param {Function} callback
*/ */
WalletDB.prototype.writeTip = function writeTip(hash, callback) { WalletDB.prototype.setTip = function setTip(hash, height, callback) {
if (typeof hash === 'string') var self = this;
hash = new Buffer(hash, 'hex'); var p = new BufferWriter();
this.db.put('R', hash, callback);
p.writeHash(hash);
p.writeU32(height);
this.db.put('R', p.render(), function(err) {
if (err)
return callback(err);
self.tip = hash;
self.height = height;
return callback();
});
}; };
/** /**
@ -1159,7 +1151,7 @@ WalletDB.prototype.addBlock = function addBlock(block, txs, callback, force) {
if (this.options.useCheckpoints) { if (this.options.useCheckpoints) {
if (block.height < this.network.checkpoints.lastHeight) if (block.height < this.network.checkpoints.lastHeight)
return this.writeTip(block.hash, callback); return this.setTip(block.hash, block.height, callback);
} }
if (!Array.isArray(txs)) if (!Array.isArray(txs))
@ -1171,7 +1163,7 @@ WalletDB.prototype.addBlock = function addBlock(block, txs, callback, force) {
if (err) if (err)
return callback(err); return callback(err);
self.writeTip(block.hash, callback); self.setTip(block.hash, block.height, callback);
}); });
}; };
@ -1217,7 +1209,7 @@ WalletDB.prototype.removeBlock = function removeBlock(block, callback, force) {
}, function(err) { }, function(err) {
if (err) if (err)
return callback(err); return callback(err);
self.writeTip(block.prevBlock, callback); self.setTip(block.prevBlock, block.height - 1, callback);
}); });
}); });
}; };
@ -1283,300 +1275,6 @@ WalletDB.prototype.getPath = function getPath(id, address, callback) {
}); });
}; };
/**
* @see {@link TXDB#toDetails}.
*/
WalletDB.prototype.toDetails = function toDetails(id, tx, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.toDetails(tx, callback);
});
};
/**
* @see {@link TXDB#getTX}.
*/
WalletDB.prototype.getTX = function getTX(id, hash, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.getTX(hash, callback);
});
};
/**
* @see {@link TXDB#getCoin}.
*/
WalletDB.prototype.getCoin = function getCoin(id, hash, index, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.getCoin(hash, index, callback);
});
};
/**
* @see {@link TXDB#getHistory}.
*/
WalletDB.prototype.getHistory = function getHistory(id, account, callback) {
if (typeof account === 'function') {
callback = account;
account = null;
}
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.getHistory(account, callback);
});
};
/**
* @see {@link TXDB#getCoins}.
*/
WalletDB.prototype.getCoins = function getCoins(id, account, callback) {
if (typeof account === 'function') {
callback = account;
account = null;
}
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.getCoins(account, callback);
});
};
/**
* @see {@link TXDB#getUnconfirmed}.
*/
WalletDB.prototype.getUnconfirmed = function getUnconfirmed(id, account, callback) {
if (typeof account === 'function') {
callback = account;
account = null;
}
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.getUnconfirmed(account, callback);
});
};
/**
* @see {@link TXDB#getBalance}.
*/
WalletDB.prototype.getBalance = function getBalance(id, account, callback) {
if (typeof account === 'function') {
callback = account;
account = null;
}
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.getBalance(account, callback);
});
};
/**
* @see {@link TXDB#getLastTime}.
*/
WalletDB.prototype.getLastTime = function getLastTime(id, account, callback) {
if (typeof account === 'function') {
callback = account;
account = null;
}
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.getLastTime(account, callback);
});
};
/**
* @see {@link TXDB#getLast}.
*/
WalletDB.prototype.getLast = function getLast(id, account, limit, callback) {
if (typeof limit === 'function') {
callback = limit;
limit = account;
account = null;
}
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.getLast(account, limit, callback);
});
};
WalletDB.prototype.getTimeRange = function getTimeRange(id, account, options, callback) {
if (typeof options === 'function') {
callback = options;
options = account;
account = null;
}
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.getTimeRange(account, options, callback);
});
};
/**
* @see {@link TXDB#getRange}.
*/
WalletDB.prototype.getRange = function getRange(id, account, options, callback) {
if (typeof options === 'function') {
callback = options;
options = account;
account = null;
}
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.getRange(account, options, callback);
});
};
/**
* @see {@link TXDB#fillHistory}.
*/
WalletDB.prototype.fillHistory = function fillHistory(id, tx, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.fillHistory(tx, callback);
});
};
/**
* @see {@link TXDB#fillCoins}.
*/
WalletDB.prototype.fillCoins = function fillCoins(id, tx, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.fillCoins(tx, callback);
});
};
/**
* Zap all walletdb transactions.
* @see {@link TXDB#zap}.
*/
WalletDB.prototype.zap = function zap(id, account, age, callback) {
if (typeof age === 'function') {
callback = age;
age = account;
account = null;
}
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.tx.zap(account, age, callback);
});
};
WalletDB.prototype.createAddress = function createAddress(id, name, change, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.createAddress(name, change, callback);
});
};
WalletDB.prototype.fund = function fund(id, tx, options, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.fund(tx, options, callback);
});
};
WalletDB.prototype.scriptInputs = function scriptInputs(id, tx, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.scriptInputs(tx, callback);
});
};
WalletDB.prototype.sign = function sign(id, tx, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.sign(tx, options, callback);
});
};
WalletDB.prototype.createTX = function createTX(id, options, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.createTX(options, callback);
});
};
WalletDB.prototype.send = function send(id, options, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.send(options, callback);
});
};
WalletDB.prototype.addKey = function addKey(id, name, key, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.addKey(name, key, callback);
});
};
WalletDB.prototype.removeKey = function removeKey(id, name, key, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.removeKey(name, key, callback);
});
};
WalletDB.prototype.setPassphrase = function setPassphrase(id, old, new_, callback) {
if (typeof new_ === 'function') {
callback = new_;
new_ = old;
old = null;
}
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.setPassphrase(old, new_, callback);
});
};
WalletDB.prototype.retoken = function retoken(id, passphrase, callback) {
if (typeof passphrase === 'function') {
callback = passphrase;
passphrase = null;
}
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.retoken(passphrase, callback);
});
};
WalletDB.prototype.getInfo = function getInfo(id, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
callback(null, wallet);
});
};
WalletDB.prototype.ensureAccount = function ensureAccount(id, options, callback) {
var self = this;
var account = options.account;
if (typeof options.name === 'string')
account = options.name;
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.hasAccount(account, function(err, exists) {
if (err)
return callback(err);
if (exists)
return wallet.getAccount(account, callback);
wallet.createAccount(options, callback);
});
});
};
WalletDB.prototype.getRedeem = function getRedeem(id, hash, callback) {
this.fetchWallet(id, callback, function(wallet, callback) {
wallet.getRedeem(hash, callback);
});
};
/** /**
* Path * Path
* @constructor * @constructor