Added a utxo cache.
This commit is contained in:
parent
95d5441031
commit
bdea9e8517
154
lib/addresses.js
154
lib/addresses.js
@ -6,6 +6,7 @@ var async = require('async');
|
|||||||
var TxController = require('./transactions');
|
var TxController = require('./transactions');
|
||||||
var Common = require('./common');
|
var Common = require('./common');
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
|
var LRU = require('lru-cache');
|
||||||
|
|
||||||
function AddressController(node) {
|
function AddressController(node) {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
@ -14,6 +15,14 @@ function AddressController(node) {
|
|||||||
this.txController = new TxController(node);
|
this.txController = new TxController(node);
|
||||||
this.common = new Common({log: this.node.log});
|
this.common = new Common({log: this.node.log});
|
||||||
this._block = this.node.services.block;
|
this._block = this.node.services.block;
|
||||||
|
this._utxoCache = new LRU({
|
||||||
|
max: 250,
|
||||||
|
maxAge: 1000 * 10
|
||||||
|
});
|
||||||
|
// limit the size of the request to about 100,000 bytes
|
||||||
|
// we'll use 34 bytes as the size of each address.
|
||||||
|
this._maxAddresses = Math.floor(100000/34);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AddressController.prototype.show = function(req, res) {
|
AddressController.prototype.show = function(req, res) {
|
||||||
@ -142,73 +151,25 @@ AddressController.prototype.check = function(addresses) {
|
|||||||
AddressController.prototype.utxo = function(req, res) {
|
AddressController.prototype.utxo = function(req, res) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
var cachedUtxos = this._utxoCache.get(req.addr);
|
||||||
|
|
||||||
|
if (cachedUtxos) {
|
||||||
|
return res.jsonp(cachedUtxos);
|
||||||
|
}
|
||||||
|
|
||||||
this._address.getAddressUnspentOutputs(req.addr, {}, function(err, utxos) {
|
this._address.getAddressUnspentOutputs(req.addr, {}, function(err, utxos) {
|
||||||
|
var results;
|
||||||
if(err) {
|
if(err) {
|
||||||
return self.common.handleErrors(err, res);
|
return self.common.handleErrors(err, res);
|
||||||
} else if (!utxos.length) {
|
} else if (!utxos.length) {
|
||||||
return res.jsonp([]);
|
results = [];
|
||||||
}
|
}
|
||||||
res.jsonp(utxos.map(self.transformUtxo.bind(self)));
|
results = utxos.map(self.transformUtxo.bind(self));
|
||||||
|
self._utxoCache.set(req.addr, results);
|
||||||
|
res.jsonp(results);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// this call could take a while to run depending on what addresses are used
|
|
||||||
// considering memory constraints, we will streaming out the results for addresses
|
|
||||||
// not necessarily in the order we received them
|
|
||||||
AddressController.prototype.multiutxo = function(req, res) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
var addresses;
|
|
||||||
|
|
||||||
if (_.isArray(req.addrs)) {
|
|
||||||
addresses = _.uniq(req.addrs);
|
|
||||||
} else {
|
|
||||||
addresses = req.addrs.split(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
var addressesLeft = addresses.length;
|
|
||||||
var startedWriting = false;
|
|
||||||
res.write('[');
|
|
||||||
|
|
||||||
var sep = ',';
|
|
||||||
|
|
||||||
async.eachLimit(addresses, 4, function(addr, next) {
|
|
||||||
|
|
||||||
self._address.getAddressUnspentOutputs(addr, {}, function(err, utxos) {
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addressesLeft-- > 0 && utxos.length > 0 && startedWriting) {
|
|
||||||
res.write(sep);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(var i = 0; i < utxos.length; i++) {
|
|
||||||
startedWriting = true;
|
|
||||||
if (utxos.length - 1 === i) {
|
|
||||||
sep = '';
|
|
||||||
}
|
|
||||||
res.write(JSON.stringify(self.transformUtxo(utxos[i])) + sep);
|
|
||||||
}
|
|
||||||
|
|
||||||
sep = ',';
|
|
||||||
next();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}, function(err) {
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
return self.common.handleErrors(err, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.write(']');
|
|
||||||
res.end();
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
AddressController.prototype.transformUtxo = function(utxoArg) {
|
AddressController.prototype.transformUtxo = function(utxoArg) {
|
||||||
var utxo = {
|
var utxo = {
|
||||||
address: utxoArg.address,
|
address: utxoArg.address,
|
||||||
@ -238,6 +199,81 @@ AddressController.prototype._getTransformOptions = function(req) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// this call could take a while to run depending on what addresses are used
|
||||||
|
// considering memory constraints, we will streaming out the results for addresses
|
||||||
|
// not necessarily in the order we received them
|
||||||
|
AddressController.prototype.multiutxo = function(req, res) {
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var addresses;
|
||||||
|
|
||||||
|
if (_.isArray(req.addrs)) {
|
||||||
|
addresses = _.uniq(req.addrs);
|
||||||
|
} else {
|
||||||
|
addresses = _.compact(req.addrs.split(','));
|
||||||
|
}
|
||||||
|
|
||||||
|
var cacheKey = addresses.join('');
|
||||||
|
|
||||||
|
if (addresses.length > this._maxAddresses) {
|
||||||
|
return self.common.handleErrors(new Error('Too many addresses.'), res);
|
||||||
|
}
|
||||||
|
|
||||||
|
var cachedUtxos = this._utxoCache.get(cacheKey);
|
||||||
|
|
||||||
|
if (cachedUtxos) {
|
||||||
|
return res.jsonp(cachedUtxos);
|
||||||
|
}
|
||||||
|
|
||||||
|
var addressesLeft = addresses.length;
|
||||||
|
var startedWriting = false;
|
||||||
|
var cache = [];
|
||||||
|
|
||||||
|
res.write('[');
|
||||||
|
|
||||||
|
var sep = ',';
|
||||||
|
|
||||||
|
async.eachLimit(addresses, 4, function(addr, next) {
|
||||||
|
|
||||||
|
self._address.getAddressUnspentOutputs(addr, {}, function(err, utxos) {
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addressesLeft-- > 0 && utxos.length > 0 && startedWriting) {
|
||||||
|
res.write(sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var i = 0; i < utxos.length; i++) {
|
||||||
|
startedWriting = true;
|
||||||
|
if (utxos.length - 1 === i) {
|
||||||
|
sep = '';
|
||||||
|
}
|
||||||
|
cache.push(utxos[i]);
|
||||||
|
res.write(JSON.stringify(self.transformUtxo(utxos[i])) + sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
sep = ',';
|
||||||
|
next();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}, function(err) {
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
return self.common.handleErrors(err, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
self._utxoCache.set(cacheKey, cache);
|
||||||
|
|
||||||
|
res.write(']');
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
AddressController.prototype.multitxs = function(req, res) {
|
AddressController.prototype.multitxs = function(req, res) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
|||||||
30
package-lock.json
generated
30
package-lock.json
generated
@ -1063,24 +1063,12 @@
|
|||||||
"integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4="
|
"integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4="
|
||||||
},
|
},
|
||||||
"lru-cache": {
|
"lru-cache": {
|
||||||
"version": "4.0.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
|
||||||
"integrity": "sha1-E0OVXtry432bnn7nJB4nxLn7cr4=",
|
"integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"pseudomap": "1.0.2",
|
"pseudomap": "1.0.2",
|
||||||
"yallist": "2.0.0"
|
"yallist": "2.1.2"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"pseudomap": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
|
||||||
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
|
|
||||||
},
|
|
||||||
"yallist": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.0.0.tgz",
|
|
||||||
"integrity": "sha1-MGxUODXwnuGkyyO3vOmrNByRzdQ="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mime-db": {
|
"mime-db": {
|
||||||
@ -1542,6 +1530,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"pseudomap": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
|
||||||
|
},
|
||||||
"pump": {
|
"pump": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/pump/-/pump-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/pump/-/pump-1.0.2.tgz",
|
||||||
@ -2417,6 +2410,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
|
||||||
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
|
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
|
||||||
},
|
},
|
||||||
|
"yallist": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||||
|
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
|
||||||
|
},
|
||||||
"yeast": {
|
"yeast": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
"body-parser": "^1.13.3",
|
"body-parser": "^1.13.3",
|
||||||
"compression": "^1.6.1",
|
"compression": "^1.6.1",
|
||||||
"lodash": "^2.4.1",
|
"lodash": "^2.4.1",
|
||||||
"lru-cache": "^4.0.1",
|
"lru-cache": "^4.1.1",
|
||||||
"morgan": "^1.7.0",
|
"morgan": "^1.7.0",
|
||||||
"request": "^2.64.0"
|
"request": "^2.64.0"
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user