add testing for key cache
This commit is contained in:
parent
13fd2592fc
commit
865a69f6f2
5
index.js
5
index.js
|
@ -18,11 +18,13 @@ bitcore.encoding.BufferReader = require('./lib/encoding/bufferreader');
|
||||||
bitcore.encoding.BufferWriter = require('./lib/encoding/bufferwriter');
|
bitcore.encoding.BufferWriter = require('./lib/encoding/bufferwriter');
|
||||||
bitcore.encoding.Varint = require('./lib/encoding/varint');
|
bitcore.encoding.Varint = require('./lib/encoding/varint');
|
||||||
|
|
||||||
|
// utilities
|
||||||
bitcore.util = {};
|
bitcore.util = {};
|
||||||
bitcore.util.bitcoin = require('./lib/util/bitcoin');
|
bitcore.util.bitcoin = require('./lib/util/bitcoin');
|
||||||
bitcore.util.buffer = require('./lib/util/buffer');
|
bitcore.util.buffer = require('./lib/util/buffer');
|
||||||
bitcore.util.js = require('./lib/util/js');
|
bitcore.util.js = require('./lib/util/js');
|
||||||
|
|
||||||
|
// errors thrown by the library
|
||||||
bitcore.errors = require('./lib/errors');
|
bitcore.errors = require('./lib/errors');
|
||||||
|
|
||||||
// main bitcoin library
|
// main bitcoin library
|
||||||
|
@ -53,3 +55,6 @@ bitcore.deps.elliptic = require('elliptic');
|
||||||
//bitcore.txpartial = require('lib/txpartial');
|
//bitcore.txpartial = require('lib/txpartial');
|
||||||
|
|
||||||
//bitcore.bip70 = require('lib/bip70');
|
//bitcore.bip70 = require('lib/bip70');
|
||||||
|
|
||||||
|
// Internal usage, exposed for testing/advanced tweaking
|
||||||
|
bitcore._HDKeyCache = require('./lib/hdkeycache');
|
||||||
|
|
|
@ -1,16 +1,45 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var cache = {};
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
_cache: {},
|
||||||
|
_count: 0,
|
||||||
|
_eraseIndex: 0,
|
||||||
|
_usedList: {},
|
||||||
|
_usedIndex: {},
|
||||||
|
_CACHE_SIZE: 5000,
|
||||||
|
|
||||||
get: function(xkey, number, hardened) {
|
get: function(xkey, number, hardened) {
|
||||||
|
hardened = !!hardened;
|
||||||
var key = xkey + '/' + number + '/' + hardened;
|
var key = xkey + '/' + number + '/' + hardened;
|
||||||
if (cache[key]) {
|
if (this._cache[key]) {
|
||||||
return cache[key];
|
this._cacheHit(key);
|
||||||
|
return this._cache[key];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
set: function(xkey, number, hardened, derived) {
|
set: function(xkey, number, hardened, derived) {
|
||||||
|
hardened = !!hardened;
|
||||||
var key = xkey + '/' + number + '/' + hardened;
|
var key = xkey + '/' + number + '/' + hardened;
|
||||||
cache[key] = derived;
|
this._cache[key] = derived;
|
||||||
|
this._cacheHit(key);
|
||||||
|
},
|
||||||
|
_cacheHit: function(key) {
|
||||||
|
if (this._usedIndex[key]) {
|
||||||
|
delete this._usedList[this._usedIndex[key]];
|
||||||
|
}
|
||||||
|
this._usedList[this._count] = key;
|
||||||
|
this._usedIndex[key] = this._count;
|
||||||
|
this._count++;
|
||||||
|
this._cacheRemove();
|
||||||
|
},
|
||||||
|
_cacheRemove: function() {
|
||||||
|
while (this._eraseIndex < this._count - this._CACHE_SIZE) {
|
||||||
|
if (this._usedList[this._eraseIndex]) {
|
||||||
|
var removeKey = this._usedList[this._eraseIndex];
|
||||||
|
delete this._usedIndex[removeKey];
|
||||||
|
delete this._cache[removeKey];
|
||||||
|
}
|
||||||
|
delete this._usedList[this._eraseIndex];
|
||||||
|
this._eraseIndex++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('lodash');
|
||||||
|
var expect = require('chai').expect;
|
||||||
|
var bitcore = require('..');
|
||||||
|
var HDPrivateKey = bitcore.HDPrivateKey;
|
||||||
|
|
||||||
|
var xprivkey = 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi';
|
||||||
|
|
||||||
|
describe('HDKey cache', function() {
|
||||||
|
/* jshint unused: false */
|
||||||
|
var cache = bitcore._HDKeyCache;
|
||||||
|
var master = new HDPrivateKey(xprivkey);
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
cache._cache = {};
|
||||||
|
cache._count = 0;
|
||||||
|
cache._eraseIndex = 0;
|
||||||
|
cache._usedIndex = {};
|
||||||
|
cache._usedList = {};
|
||||||
|
cache._CACHE_SIZE = 3; // Reduce for quick testing
|
||||||
|
});
|
||||||
|
|
||||||
|
it('saves a derived key', function() {
|
||||||
|
var child = master.derive(0);
|
||||||
|
expect(cache._cache[master.xprivkey + '/0/false'].xprivkey).to.equal(child.xprivkey);
|
||||||
|
});
|
||||||
|
it('starts erasing unused keys', function() {
|
||||||
|
var child1 = master.derive(0);
|
||||||
|
var child2 = child1.derive(0);
|
||||||
|
var child3 = child2.derive(0);
|
||||||
|
expect(cache._cache[master.xprivkey + '/0/false'].xprivkey).to.equal(child1.xprivkey);
|
||||||
|
var child4 = child3.derive(0);
|
||||||
|
expect(cache._cache[master.xprivkey + '/0/false']).to.equal(undefined);
|
||||||
|
});
|
||||||
|
it('avoids erasing keys that get cache hits ("hot keys")', function() {
|
||||||
|
var child1 = master.derive(0);
|
||||||
|
var child2 = master.derive(0).derive(0);
|
||||||
|
expect(cache._cache[master.xprivkey + '/0/false'].xprivkey).to.equal(child1.xprivkey);
|
||||||
|
var child1_copy = master.derive(0);
|
||||||
|
expect(cache._cache[master.xprivkey + '/0/false'].xprivkey).to.equal(child1.xprivkey);
|
||||||
|
});
|
||||||
|
it('keeps the size of the cache small', function() {
|
||||||
|
var child1 = master.derive(0);
|
||||||
|
var child2 = child1.derive(0);
|
||||||
|
var child3 = child2.derive(0);
|
||||||
|
var child4 = child3.derive(0);
|
||||||
|
expect(_.size(cache._cache)).to.equal(3);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue