http tests. caches.

This commit is contained in:
Christopher Jeffrey 2016-07-13 14:53:37 -07:00
parent a60a48da9a
commit 682596fb05
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
9 changed files with 167 additions and 59 deletions

View File

@ -209,7 +209,7 @@ function ChainDB(chain, options) {
// Key size: 66b (* 2) // Key size: 66b (* 2)
this.coinWindow = ((165 * 1024 + 2300 * 4) + (2300 * 66 * 2)) * 5; this.coinWindow = ((165 * 1024 + 2300 * 4) + (2300 * 66 * 2)) * 5;
this.coinCache = new NullCache(this.coinWindow); this.coinCache = new bcoin.lru.nil(this.coinWindow);
this.cacheHash = new bcoin.lru(this.cacheWindow, 1); this.cacheHash = new bcoin.lru(this.cacheWindow, 1);
this.cacheHeight = new bcoin.lru(this.cacheWindow, 1); this.cacheHeight = new bcoin.lru(this.cacheWindow, 1);
} }
@ -1482,20 +1482,6 @@ ChainDB.prototype._pruneBlock = function _pruneBlock(block, batch, callback) {
}); });
}; };
/**
* A null cache. Every method is a NOP.
* @constructor
* @param {Number} size
*/
function NullCache(size) {}
NullCache.prototype.set = function set(key, value) {};
NullCache.prototype.remove = function remove(key) {};
NullCache.prototype.get = function get(key) {};
NullCache.prototype.has = function has(key) {};
NullCache.prototype.reset = function reset() {};
/* /*
* Helpers * Helpers
*/ */

View File

@ -194,7 +194,9 @@ HTTPBase.prototype._initIO = function _initIO() {
if (!IOServer) if (!IOServer)
return; return;
this.io = new IOServer(); this.io = new IOServer({
transports: ['websocket']
});
this.io.attach(this.server); this.io.attach(this.server);

View File

@ -75,7 +75,10 @@ HTTPClient.prototype._open = function _open(callback) {
if (!IOClient) if (!IOClient)
return callback(); return callback();
this.socket = new IOClient(this.uri); this.socket = new IOClient(this.uri, {
transports: ['websocket'],
forceNew: true
});
this.socket.on('error', function(err) { this.socket.on('error', function(err) {
self.emit('error', err); self.emit('error', err);

View File

@ -353,8 +353,23 @@ function LRUItem(key, value) {
this.prev = null; this.prev = null;
} }
/**
* A null cache. Every method is a NOP.
* @constructor
* @param {Number} size
*/
function NullCache(size) {}
NullCache.prototype.set = function set(key, value) {};
NullCache.prototype.remove = function remove(key) {};
NullCache.prototype.get = function get(key) {};
NullCache.prototype.has = function has(key) {};
NullCache.prototype.reset = function reset() {};
/* /*
* Expose * Expose
*/ */
LRU.nil = NullCache;
module.exports = LRU; module.exports = LRU;

View File

@ -1868,7 +1868,7 @@ TX.prototype.inspect = function inspect() {
value: utils.btc(this.getOutputValue()), value: utils.btc(this.getOutputValue()),
fee: utils.btc(this.getFee()), fee: utils.btc(this.getFee()),
minFee: utils.btc(this.getMinFee()), minFee: utils.btc(this.getMinFee()),
rate: utils.btc(this.getRate()), rate: this.getRate(), // Rate can sometimes exceed 53 bits in testing
confirmations: this.getConfirmations(), confirmations: this.getConfirmations(),
priority: this.getPriority(), priority: this.getPriority(),
date: utils.date(this.ts || this.ps), date: utils.date(this.ts || this.ps),

View File

@ -1720,12 +1720,15 @@ Account.prototype.fromOptions = function fromOptions(options) {
assert(options, 'Options are required.'); assert(options, 'Options are required.');
assert(utils.isAlpha(options.id), 'Wallet ID must be alphanumeric.'); assert(utils.isAlpha(options.id), 'Wallet ID must be alphanumeric.');
assert(utils.isAlpha(options.name), 'Account name must be alphanumeric.');
assert(bcoin.hd.isHD(options.accountKey), 'Account key is required.'); assert(bcoin.hd.isHD(options.accountKey), 'Account key is required.');
assert(utils.isNumber(options.accountIndex), 'Account index is required.'); assert(utils.isNumber(options.accountIndex), 'Account index is required.');
this.id = options.id; this.id = options.id;
this.name = options.name;
if (options.name != null) {
assert(utils.isAlpha(options.name), 'Account name must be alphanumeric.');
this.name = options.name;
}
if (options.witness != null) { if (options.witness != null) {
assert(typeof options.witness === 'boolean'); assert(typeof options.witness === 'boolean');

View File

@ -54,6 +54,9 @@ function WalletDB(options) {
// 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);
this.accountCache = new bcoin.lru(100000, 1);
this.walletCache = new bcoin.lru(100000, 1);
this.pathCache = new bcoin.lru(100000, 1);
this.db = bcoin.ldb({ this.db = bcoin.ldb({
location: this.options.location, location: this.options.location,
@ -425,19 +428,13 @@ WalletDB.prototype.get = function get(id, callback) {
return callback(null, watcher.object); return callback(null, watcher.object);
} }
this.db.get('w/' + id, function(err, data) { this._get(id, function(err, wallet) {
if (err) if (err)
return callback(err); return callback(err);
if (!data) if (!wallet)
return callback(); return callback();
try {
wallet = bcoin.wallet.fromRaw(self, data);
} catch (e) {
return callback(e);
}
try { try {
self.register(wallet); self.register(wallet);
} catch (e) { } catch (e) {
@ -453,6 +450,37 @@ WalletDB.prototype.get = function get(id, callback) {
}); });
}; };
WalletDB.prototype._get = function get(id, callback) {
var self = this;
var wallet;
if (!id)
return callback();
wallet = this.walletCache.get(id);
if (wallet)
return callback(null, wallet);
this.db.get('w/' + id, function(err, data) {
if (err)
return callback(err);
if (!data)
return callback();
try {
wallet = bcoin.wallet.fromRaw(self, data);
} catch (e) {
return callback(e);
}
self.walletCache.set(id, wallet);
return callback(null, wallet);
});
};
/** /**
* Save a wallet to the database. * Save a wallet to the database.
* @param {Wallet} wallet * @param {Wallet} wallet
@ -463,6 +491,8 @@ WalletDB.prototype.save = function save(wallet, callback) {
if (!utils.isAlpha(wallet.id)) if (!utils.isAlpha(wallet.id))
return callback(new Error('Wallet IDs must be alphanumeric.')); return callback(new Error('Wallet IDs must be alphanumeric.'));
this.walletCache.set(wallet.id, wallet);
this.db.put('w/' + wallet.id, wallet.toRaw(), callback); this.db.put('w/' + wallet.id, wallet.toRaw(), callback);
}; };
@ -480,19 +510,13 @@ WalletDB.prototype.auth = function auth(id, token, callback) {
if (!id) if (!id)
return callback(new Error('Wallet not found.')); return callback(new Error('Wallet not found.'));
this.db.get('w/' + id, function(err, data) { this._get(id, function(err, wallet) {
if (err) if (err)
return callback(err); return callback(err);
if (!data) if (!wallet)
return callback(new Error('Wallet not found.')); return callback(new Error('Wallet not found.'));
try {
wallet = bcoin.wallet.fromRaw(self, data);
} catch (e) {
return callback(e);
}
if (typeof token === 'string') { if (typeof token === 'string') {
if (!utils.isHex(token)) if (!utils.isHex(token))
return callback(new Error('Authentication error.')); return callback(new Error('Authentication error.'));
@ -614,19 +638,13 @@ WalletDB.prototype.getAccount = function getAccount(id, name, callback) {
if (index === -1) if (index === -1)
return callback(); return callback();
self.db.get('a/' + id + '/' + index, function(err, data) { self._getAccount(id, index, function(err, account) {
if (err) if (err)
return callback(err); return callback(err);
if (!data) if (!account)
return callback(); return callback();
try {
account = bcoin.account.fromRaw(self, data);
} catch (e) {
return callback(e);
}
account.open(function(err) { account.open(function(err) {
if (err) if (err)
return callback(err); return callback(err);
@ -637,6 +655,33 @@ WalletDB.prototype.getAccount = function getAccount(id, name, callback) {
}); });
}; };
WalletDB.prototype._getAccount = function getAccount(id, index, callback) {
var self = this;
var key = id + '/' + index;
var account = this.accountCache.get(key);
if (account)
return callback(null, account);
this.db.get('a/' + key, function(err, data) {
if (err)
return callback(err);
if (!data)
return callback();
try {
account = bcoin.account.fromRaw(self, data);
} catch (e) {
return callback(e);
}
self.accountCache.set(key, account);
return callback(null, account);
});
};
/** /**
* List account names and indexes from the db. * List account names and indexes from the db.
* @param {WalletID} id * @param {WalletID} id
@ -675,6 +720,9 @@ WalletDB.prototype.getAccounts = function getAccounts(id, callback) {
*/ */
WalletDB.prototype.getAccountIndex = function getAccountIndex(id, name, callback) { WalletDB.prototype.getAccountIndex = function getAccountIndex(id, name, callback) {
if (!id)
return callback(null, -1);
if (name == null) if (name == null)
return callback(null, -1); return callback(null, -1);
@ -699,7 +747,7 @@ WalletDB.prototype.getAccountIndex = function getAccountIndex(id, name, callback
*/ */
WalletDB.prototype.saveAccount = function saveAccount(account, callback) { WalletDB.prototype.saveAccount = function saveAccount(account, callback) {
var index, batch; var index, key, batch;
if (!utils.isAlpha(account.name)) if (!utils.isAlpha(account.name))
return callback(new Error('Account names must be alphanumeric.')); return callback(new Error('Account names must be alphanumeric.'));
@ -709,9 +757,13 @@ WalletDB.prototype.saveAccount = function saveAccount(account, callback) {
index = new Buffer(4); index = new Buffer(4);
index.writeUInt32LE(account.accountIndex, 0, true); index.writeUInt32LE(account.accountIndex, 0, true);
batch.put('a/' + account.id + '/' + account.accountIndex, account.toRaw()); key = account.id + '/' + account.accountIndex;
batch.put('a/' + key, account.toRaw());
batch.put('i/' + account.id + '/' + account.name, index); batch.put('i/' + account.id + '/' + account.name, index);
this.accountCache.set(key, account);
batch.write(callback); batch.write(callback);
}; };
@ -816,7 +868,7 @@ WalletDB.prototype.saveAddress = function saveAddress(id, addresses, callback) {
self.emit('save address', address, path); self.emit('save address', address, path);
self.db.fetch('W/' + hash, parsePaths, function(err, paths) { self._getPaths(hash, function(err, paths) {
if (err) if (err)
return next(err); return next(err);
@ -828,6 +880,8 @@ WalletDB.prototype.saveAddress = function saveAddress(id, addresses, callback) {
paths[id] = path; paths[id] = path;
self.pathCache.set(hash, paths);
batch.put('W/' + hash, serializePaths(paths)); batch.put('W/' + hash, serializePaths(paths));
next(); next();
@ -840,6 +894,31 @@ WalletDB.prototype.saveAddress = function saveAddress(id, addresses, callback) {
}); });
}; };
WalletDB.prototype._getPaths = function _getPaths(hash, callback) {
var self = this;
var paths;
if (!hash)
return callback();
paths = this.pathCache.get(hash);
if (paths)
return callback(null, paths);
this.db.fetch('W/' + hash, parsePaths, function(err, paths) {
if (err)
return callback(err);
if (!paths)
return callback();
self.pathCache.set(hash, paths);
return callback(null, paths);
});
};
/** /**
* Test whether an address hash exists in the * Test whether an address hash exists in the
* path map and is relevant to the wallet id. * path map and is relevant to the wallet id.
@ -867,10 +946,7 @@ WalletDB.prototype.hasAddress = function hasAddress(id, address, callback) {
*/ */
WalletDB.prototype.getAddress = function getAddress(address, callback) { WalletDB.prototype.getAddress = function getAddress(address, callback) {
if (!address) this._getPaths(address, callback);
return callback();
this.db.fetch('W/' + address, parsePaths, callback);
}; };
/** /**

View File

@ -93,7 +93,7 @@ describe('HTTP', function() {
*/ */
it('should fill with funds', function(cb) { it('should fill with funds', function(cb) {
var balance, receive; var balance, receive, tx;
// Coinbase // Coinbase
var t1 = bcoin.mtx() var t1 = bcoin.mtx()
@ -112,10 +112,13 @@ describe('HTTP', function() {
receive = r[0]; receive = r[0];
}); });
wallet.once('tx', function(t, map) {
tx = t;
});
node.walletdb.addTX(t1, function(err) { node.walletdb.addTX(t1, function(err) {
assert.ifError(err); assert.ifError(err);
setTimeout(function() { setTimeout(function() {
return cb();
assert(receive); assert(receive);
assert.equal(receive.id, 'test'); assert.equal(receive.id, 'test');
assert.equal(receive.type, 'pubkeyhash'); assert.equal(receive.type, 'pubkeyhash');
@ -124,8 +127,10 @@ describe('HTTP', function() {
assert.equal(balance.confirmed, 0); assert.equal(balance.confirmed, 0);
assert.equal(balance.unconfirmed, 201840); assert.equal(balance.unconfirmed, 201840);
assert.equal(balance.total, 201840); assert.equal(balance.total, 201840);
assert(tx);
assert.equal(tx.hash('hex'), t1.hash('hex'));
cb(); cb();
}, 2000); }, 300);
}); });
}); });
@ -171,6 +176,24 @@ describe('HTTP', function() {
}); });
}); });
it('should generate new api key', function(cb) {
var t = wallet.token.toString('hex');
wallet.retoken(null, function(err, token) {
assert.ifError(err);
assert(token.length === 64);
assert.notEqual(token, t);
cb();
});
});
it('should get balance', function(cb) {
wallet.getBalance(function(err, balance) {
assert.ifError(err);
assert.equal(balance.total, 199570);
cb();
});
});
it('should cleanup', function(cb) { it('should cleanup', function(cb) {
constants.tx.COINBASE_MATURITY = 100; constants.tx.COINBASE_MATURITY = 100;
node.close(cb); node.close(cb);

View File

@ -86,10 +86,10 @@ describe('Wallet', function() {
w1.destroy(); w1.destroy();
walletdb.get(w1.id, function(err, w1_) { walletdb.get(w1.id, function(err, w1_) {
assert.ifError(err); assert.ifError(err);
assert(w1 !== w1_); // assert(w1 !== w1_);
assert(w1.master !== w1_.master); // assert(w1.master !== w1_.master);
assert.equal(w1.master.key.xprivkey, w1.master.key.xprivkey); assert.equal(w1.master.key.xprivkey, w1.master.key.xprivkey);
assert(w1.account !== w1_.account); // assert(w1.account !== w1_.account);
assert.equal(w1.account.accountKey.xpubkey, w1.account.accountKey.xpubkey); assert.equal(w1.account.accountKey.xpubkey, w1.account.accountKey.xpubkey);
cb(); cb();
}); });
@ -819,8 +819,8 @@ describe('Wallet', function() {
assert.ifError(err); assert.ifError(err);
assert.equal(account.name, 'foo'); assert.equal(account.name, 'foo');
assert.equal(account.accountIndex, 1); assert.equal(account.accountIndex, 1);
assert(account !== w1.account); // assert(account !== w1.account);
assert(account !== acc); // assert(account !== acc);
assert(account.accountKey.xpubkey === acc.accountKey.xpubkey); assert(account.accountKey.xpubkey === acc.accountKey.xpubkey);
assert(w1.account.accountIndex === 0); assert(w1.account.accountIndex === 0);
assert(account.receiveAddress.getAddress('base58') !== w1.account.receiveAddress.getAddress('base58')); assert(account.receiveAddress.getAddress('base58') !== w1.account.receiveAddress.getAddress('base58'));