Esteban Ordano
10 years ago
3 changed files with 90 additions and 6 deletions
@ -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