use tiny to cache addresses and start where we left off.

This commit is contained in:
Christopher Jeffrey 2014-12-01 22:05:26 -08:00
parent 144cb40195
commit 774f08c91f
3 changed files with 134 additions and 34 deletions

View File

@ -417,36 +417,78 @@ Bitcoin.prototype.getMiningInfo = function() {
return bitcoindjs.getMiningInfo();
};
Bitcoin._addrCache = {};
Bitcoin._collectAddrGarbage = null;
Bitcoin.prototype.getAddrTransactions = function(addr, callback) {
if (!Bitcoin._collectAddrGarbage) {
Bitcoin._collectAddrGarbage = setInterval(function() {
Bitcoin._addrCache = {};
}, 20 * 60 * 1000);
Bitcoin._collectAddrGarbage.unref();
}
var cached = Bitcoin._addrCache[addr];
if (cached && Date.now() <= (cached.time + 10 * 60 * 1000)) {
setImmediate(function() {
return callback(null, cached.addr);
if (!bitcoin.db) {
var tiny = require('tiny').json;
bitcoin.db = tiny({
file: process.env.HOME + '/.bitcoindjs.addr.db',
saveIndex: false,
initialCache: false
});
return;
}
return bitcoindjs.getAddrTransactions(addr, function(err, addr) {
if (err) return callback(err);
addr = bitcoin.addr(addr);
if (addr.tx[0] && !addr.tx[0].vout[0]) {
return callback(null, bitcoin.addr({
address: addr.address,
tx: []
}));
return bitcoin.db.get(addr, function(err, records) {
var found = !err && records && records.length;
var last = found && records[records.length - 1];
var limit = 15 * 60 * 1000;
if (!found || last.timestamp + limit < Date.now()) {
var options = {
address: addr,
blockindex: (records || []).reduce(function(out, record) {
return record.blockindex > out
? record.blockindex
: out;
}, -1)
};
return bitcoindjs.getAddrTransactions(options, function(err, addr) {
if (err) return callback(err);
addr = bitcoin.addr(addr);
if (addr.tx[0] && !addr.tx[0].vout[0]) {
return bitcoin.db.set(addr, [{
txid: null,
blockhash: null,
blockindex: null,
timestamp: Date.now()
}], function() {
return callback(null, bitcoin.addr({
address: addr.address,
tx: []
}));
});
}
var set = [];
if (records && records.length) {
set = records;
}
addr.tx.forEach(function(tx) {
set.push({
txid: tx.txid,
blockhash: tx.blockhash,
blockindex: tx.blockindex,
timestamp: Date.now()
});
});
return bitcoin.db.set(addr, set, function() {
return callback(null, addr);
});
});
}
Bitcoin._addrCache[addr.address] = {
addr: addr,
time: Date.now()
};
return callback(null, addr);
var txs = [];
return utils.forEach(records, function(record, next) {
var block = record.block;
var txid = record.txid;
var index = record.blockindex;
if (txid == null) return next();
return bitcoin.getTransaction(txid, block, function(err, tx) {
if (err) return next();
txs.push(tx);
return next();
});
}, function() {
return callback(null, bitcoin.addr({
address: addr,
tx: txs
}));
});
});
};
@ -455,6 +497,10 @@ Bitcoin.prototype.getBestBlock = function(callback) {
return bitcoindjs.getBlock(hash, callback);
};
Bitcoin.prototype.getChainHeight = function() {
return bitcoindjs.getChainHeight();
};
Bitcoin.prototype.log =
Bitcoin.prototype.info = function() {
if (this.options.silent) return;

View File

@ -18,7 +18,8 @@
],
"dependencies": {
"nan": "1.3.0",
"mkdirp": "0.5.0"
"mkdirp": "0.5.0",
"tiny": "0.0.10"
},
"devDependencies": {
"mocha": "~1.16.2",

View File

@ -212,6 +212,7 @@ NAN_METHOD(GetGenerate);
NAN_METHOD(GetMiningInfo);
NAN_METHOD(GetAddrTransactions);
NAN_METHOD(GetBestBlock);
NAN_METHOD(GetChainHeight);
NAN_METHOD(GetBlockHex);
NAN_METHOD(GetTxHex);
@ -473,6 +474,7 @@ struct async_addrtx_data {
std::string err_msg;
std::string addr;
ctx_list *ctxs;
int64_t blockindex;
Persistent<Function> callback;
};
@ -1966,24 +1968,46 @@ NAN_METHOD(GetAddrTransactions) {
NanScope();
if (args.Length() < 2
|| !args[0]->IsString()
|| (!args[0]->IsString() && !args[0]->IsObject())
|| !args[1]->IsFunction()) {
return NanThrowError(
"Usage: bitcoindjs.getAddrTransactions(addr, callback)");
}
String::Utf8Value addr_(args[0]->ToString());
std::string addr = "";
int64_t blockindex = -1;
if (args[0]->IsString()) {
String::Utf8Value addr_(args[0]->ToString());
addr = std::string(*addr_);
} else if (args[0]->IsObject()) {
Local<Object> options = Local<Object>::Cast(args[0]);
if (options->Get(NanNew<String>("address"))->IsString()) {
String::Utf8Value s_(options->Get(NanNew<String>("address"))->ToString());
addr = std::string(*s_);
}
if (options->Get(NanNew<String>("addr"))->IsString()) {
String::Utf8Value s_(options->Get(NanNew<String>("addr"))->ToString());
addr = std::string(*s_);
}
if (options->Get(NanNew<String>("index"))->IsString()) {
blockindex = options->Get(NanNew<String>("index"))->IntegerValue();
}
if (options->Get(NanNew<String>("blockindex"))->IsString()) {
blockindex = options->Get(NanNew<String>("blockindex"))->IntegerValue();
}
}
Local<Function> callback = Local<Function>::Cast(args[1]);
Persistent<Function> cb;
cb = Persistent<Function>::New(callback);
std::string addr = std::string(*addr_);
async_addrtx_data *data = new async_addrtx_data();
data->err_msg = std::string("");
data->addr = addr;
data->ctxs = NULL;
data->blockindex = blockindex;
data->callback = Persistent<Function>::New(callback);
uv_work_t *req = new uv_work_t();
@ -2002,6 +2026,11 @@ static void
async_get_addrtx(uv_work_t *req) {
async_addrtx_data* data = static_cast<async_addrtx_data*>(req->data);
if (data->addr.empty()) {
data->err_msg = std::string("Invalid address.");
return;
}
CBitcoinAddress address = CBitcoinAddress(data->addr);
if (!address.IsValid()) {
data->err_msg = std::string("Invalid address.");
@ -2011,10 +2040,16 @@ async_get_addrtx(uv_work_t *req) {
#if !USE_LDB_ADDR
CScript expected = GetScriptForDestination(address.Get());
// int64_t i = 0;
int64_t i = 0;
// Check the last 20,000 blocks
int64_t i = chainActive.Height() - 20000;
if (i < 0) i = 0;
// int64_t i = chainActive.Height() - 20000;
// if (i < 0) i = 0;
if (data->blockindex != -1) {
i = data->blockindex;
}
int64_t height = chainActive.Height();
for (; i <= height; i++) {
@ -2152,6 +2187,23 @@ NAN_METHOD(GetBestBlock) {
NanReturnValue(NanNew<String>(hash.GetHex()));
}
/**
* GetChainHeight()
* bitcoindjs.getChainHeight()
* Get miscellaneous information
*/
NAN_METHOD(GetChainHeight) {
NanScope();
if (args.Length() > 0) {
return NanThrowError(
"Usage: bitcoindjs.getChainHeight()");
}
NanReturnValue(NanNew<Number>((int)chainActive.Height())->ToInt32());
}
/**
* GetBlockHex()
* bitcoindjs.getBlockHex(callback)
@ -6179,6 +6231,7 @@ init(Handle<Object> target) {
NODE_SET_METHOD(target, "getMiningInfo", GetMiningInfo);
NODE_SET_METHOD(target, "getAddrTransactions", GetAddrTransactions);
NODE_SET_METHOD(target, "getBestBlock", GetBestBlock);
NODE_SET_METHOD(target, "getChainHeight", GetChainHeight);
NODE_SET_METHOD(target, "getBlockHex", GetBlockHex);
NODE_SET_METHOD(target, "getTxHex", GetTxHex);
NODE_SET_METHOD(target, "blockFromHex", BlockFromHex);