use tiny to cache addresses and start where we left off.
This commit is contained in:
parent
144cb40195
commit
774f08c91f
@ -417,36 +417,78 @@ Bitcoin.prototype.getMiningInfo = function() {
|
|||||||
return bitcoindjs.getMiningInfo();
|
return bitcoindjs.getMiningInfo();
|
||||||
};
|
};
|
||||||
|
|
||||||
Bitcoin._addrCache = {};
|
|
||||||
Bitcoin._collectAddrGarbage = null;
|
|
||||||
Bitcoin.prototype.getAddrTransactions = function(addr, callback) {
|
Bitcoin.prototype.getAddrTransactions = function(addr, callback) {
|
||||||
if (!Bitcoin._collectAddrGarbage) {
|
if (!bitcoin.db) {
|
||||||
Bitcoin._collectAddrGarbage = setInterval(function() {
|
var tiny = require('tiny').json;
|
||||||
Bitcoin._addrCache = {};
|
bitcoin.db = tiny({
|
||||||
}, 20 * 60 * 1000);
|
file: process.env.HOME + '/.bitcoindjs.addr.db',
|
||||||
Bitcoin._collectAddrGarbage.unref();
|
saveIndex: false,
|
||||||
}
|
initialCache: false
|
||||||
var cached = Bitcoin._addrCache[addr];
|
|
||||||
if (cached && Date.now() <= (cached.time + 10 * 60 * 1000)) {
|
|
||||||
setImmediate(function() {
|
|
||||||
return callback(null, cached.addr);
|
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
return bitcoindjs.getAddrTransactions(addr, function(err, addr) {
|
return bitcoin.db.get(addr, function(err, records) {
|
||||||
if (err) return callback(err);
|
var found = !err && records && records.length;
|
||||||
addr = bitcoin.addr(addr);
|
var last = found && records[records.length - 1];
|
||||||
if (addr.tx[0] && !addr.tx[0].vout[0]) {
|
var limit = 15 * 60 * 1000;
|
||||||
return callback(null, bitcoin.addr({
|
if (!found || last.timestamp + limit < Date.now()) {
|
||||||
address: addr.address,
|
var options = {
|
||||||
tx: []
|
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] = {
|
var txs = [];
|
||||||
addr: addr,
|
return utils.forEach(records, function(record, next) {
|
||||||
time: Date.now()
|
var block = record.block;
|
||||||
};
|
var txid = record.txid;
|
||||||
return callback(null, addr);
|
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);
|
return bitcoindjs.getBlock(hash, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Bitcoin.prototype.getChainHeight = function() {
|
||||||
|
return bitcoindjs.getChainHeight();
|
||||||
|
};
|
||||||
|
|
||||||
Bitcoin.prototype.log =
|
Bitcoin.prototype.log =
|
||||||
Bitcoin.prototype.info = function() {
|
Bitcoin.prototype.info = function() {
|
||||||
if (this.options.silent) return;
|
if (this.options.silent) return;
|
||||||
|
|||||||
@ -18,7 +18,8 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nan": "1.3.0",
|
"nan": "1.3.0",
|
||||||
"mkdirp": "0.5.0"
|
"mkdirp": "0.5.0",
|
||||||
|
"tiny": "0.0.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"mocha": "~1.16.2",
|
"mocha": "~1.16.2",
|
||||||
|
|||||||
@ -212,6 +212,7 @@ NAN_METHOD(GetGenerate);
|
|||||||
NAN_METHOD(GetMiningInfo);
|
NAN_METHOD(GetMiningInfo);
|
||||||
NAN_METHOD(GetAddrTransactions);
|
NAN_METHOD(GetAddrTransactions);
|
||||||
NAN_METHOD(GetBestBlock);
|
NAN_METHOD(GetBestBlock);
|
||||||
|
NAN_METHOD(GetChainHeight);
|
||||||
|
|
||||||
NAN_METHOD(GetBlockHex);
|
NAN_METHOD(GetBlockHex);
|
||||||
NAN_METHOD(GetTxHex);
|
NAN_METHOD(GetTxHex);
|
||||||
@ -473,6 +474,7 @@ struct async_addrtx_data {
|
|||||||
std::string err_msg;
|
std::string err_msg;
|
||||||
std::string addr;
|
std::string addr;
|
||||||
ctx_list *ctxs;
|
ctx_list *ctxs;
|
||||||
|
int64_t blockindex;
|
||||||
Persistent<Function> callback;
|
Persistent<Function> callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1966,24 +1968,46 @@ NAN_METHOD(GetAddrTransactions) {
|
|||||||
NanScope();
|
NanScope();
|
||||||
|
|
||||||
if (args.Length() < 2
|
if (args.Length() < 2
|
||||||
|| !args[0]->IsString()
|
|| (!args[0]->IsString() && !args[0]->IsObject())
|
||||||
|| !args[1]->IsFunction()) {
|
|| !args[1]->IsFunction()) {
|
||||||
return NanThrowError(
|
return NanThrowError(
|
||||||
"Usage: bitcoindjs.getAddrTransactions(addr, callback)");
|
"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]);
|
Local<Function> callback = Local<Function>::Cast(args[1]);
|
||||||
|
|
||||||
Persistent<Function> cb;
|
Persistent<Function> cb;
|
||||||
cb = Persistent<Function>::New(callback);
|
cb = Persistent<Function>::New(callback);
|
||||||
|
|
||||||
std::string addr = std::string(*addr_);
|
|
||||||
|
|
||||||
async_addrtx_data *data = new async_addrtx_data();
|
async_addrtx_data *data = new async_addrtx_data();
|
||||||
data->err_msg = std::string("");
|
data->err_msg = std::string("");
|
||||||
data->addr = addr;
|
data->addr = addr;
|
||||||
data->ctxs = NULL;
|
data->ctxs = NULL;
|
||||||
|
data->blockindex = blockindex;
|
||||||
data->callback = Persistent<Function>::New(callback);
|
data->callback = Persistent<Function>::New(callback);
|
||||||
|
|
||||||
uv_work_t *req = new uv_work_t();
|
uv_work_t *req = new uv_work_t();
|
||||||
@ -2002,6 +2026,11 @@ static void
|
|||||||
async_get_addrtx(uv_work_t *req) {
|
async_get_addrtx(uv_work_t *req) {
|
||||||
async_addrtx_data* data = static_cast<async_addrtx_data*>(req->data);
|
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);
|
CBitcoinAddress address = CBitcoinAddress(data->addr);
|
||||||
if (!address.IsValid()) {
|
if (!address.IsValid()) {
|
||||||
data->err_msg = std::string("Invalid address.");
|
data->err_msg = std::string("Invalid address.");
|
||||||
@ -2011,10 +2040,16 @@ async_get_addrtx(uv_work_t *req) {
|
|||||||
#if !USE_LDB_ADDR
|
#if !USE_LDB_ADDR
|
||||||
CScript expected = GetScriptForDestination(address.Get());
|
CScript expected = GetScriptForDestination(address.Get());
|
||||||
|
|
||||||
// int64_t i = 0;
|
int64_t i = 0;
|
||||||
|
|
||||||
// Check the last 20,000 blocks
|
// Check the last 20,000 blocks
|
||||||
int64_t i = chainActive.Height() - 20000;
|
// int64_t i = chainActive.Height() - 20000;
|
||||||
if (i < 0) i = 0;
|
// if (i < 0) i = 0;
|
||||||
|
|
||||||
|
if (data->blockindex != -1) {
|
||||||
|
i = data->blockindex;
|
||||||
|
}
|
||||||
|
|
||||||
int64_t height = chainActive.Height();
|
int64_t height = chainActive.Height();
|
||||||
|
|
||||||
for (; i <= height; i++) {
|
for (; i <= height; i++) {
|
||||||
@ -2152,6 +2187,23 @@ NAN_METHOD(GetBestBlock) {
|
|||||||
NanReturnValue(NanNew<String>(hash.GetHex()));
|
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()
|
* GetBlockHex()
|
||||||
* bitcoindjs.getBlockHex(callback)
|
* bitcoindjs.getBlockHex(callback)
|
||||||
@ -6179,6 +6231,7 @@ init(Handle<Object> target) {
|
|||||||
NODE_SET_METHOD(target, "getMiningInfo", GetMiningInfo);
|
NODE_SET_METHOD(target, "getMiningInfo", GetMiningInfo);
|
||||||
NODE_SET_METHOD(target, "getAddrTransactions", GetAddrTransactions);
|
NODE_SET_METHOD(target, "getAddrTransactions", GetAddrTransactions);
|
||||||
NODE_SET_METHOD(target, "getBestBlock", GetBestBlock);
|
NODE_SET_METHOD(target, "getBestBlock", GetBestBlock);
|
||||||
|
NODE_SET_METHOD(target, "getChainHeight", GetChainHeight);
|
||||||
NODE_SET_METHOD(target, "getBlockHex", GetBlockHex);
|
NODE_SET_METHOD(target, "getBlockHex", GetBlockHex);
|
||||||
NODE_SET_METHOD(target, "getTxHex", GetTxHex);
|
NODE_SET_METHOD(target, "getTxHex", GetTxHex);
|
||||||
NODE_SET_METHOD(target, "blockFromHex", BlockFromHex);
|
NODE_SET_METHOD(target, "blockFromHex", BlockFromHex);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user