getBlockHeight. getAddrTransactions.

This commit is contained in:
Christopher Jeffrey 2014-11-04 16:08:31 -08:00
parent a02a672a22
commit da496dcbc7
2 changed files with 250 additions and 29 deletions

View File

@ -330,6 +330,13 @@ Bitcoin.prototype.getBlock = function(blockHash, callback) {
});
};
Bitcoin.prototype.getBlockHeight = function(height, callback) {
return bitcoindjs.getBlock(+height, function(err, block) {
if (err) return callback(err);
return callback(null, bitcoin.block(block));
});
};
Bitcoin.prototype.getTx = function(txHash, blockHash, callback) {
if (!callback) {
callback = blockHash;
@ -369,6 +376,10 @@ Bitcoin.prototype.getMiningInfo = function() {
return bitcoindjs.getMiningInfo();
};
Bitcoin.prototype.getAddrTransactions = function(addr, callback) {
return bitcoindjs.getAddrTransactions(addr, callback);
};
Bitcoin.prototype.log =
Bitcoin.prototype.info = function() {
if (this.options.silent) return;

View File

@ -238,6 +238,7 @@ NAN_METHOD(GetProgress);
NAN_METHOD(SetGenerate);
NAN_METHOD(GetGenerate);
NAN_METHOD(GetMiningInfo);
NAN_METHOD(GetAddrTransactions);
NAN_METHOD(GetBlockHex);
NAN_METHOD(GetTxHex);
@ -319,6 +320,12 @@ async_get_tx(uv_work_t *req);
static void
async_get_tx_after(uv_work_t *req);
static void
async_get_addrtx(uv_work_t *req);
static void
async_get_addrtx_after(uv_work_t *req);
static void
async_broadcast_tx(uv_work_t *req);
@ -426,18 +433,6 @@ struct async_node_data {
Persistent<Function> callback;
};
/**
* async_hook_data
* Hook into bitcoind packet reception.
*/
struct async_hook_data {
std::string err_msg;
std::string result;
CNode result_pfrom;
Persistent<Function> callback;
};
/**
* async_block_data
*/
@ -445,8 +440,9 @@ struct async_hook_data {
struct async_block_data {
std::string err_msg;
std::string hash;
CBlock result_block;
CBlockIndex* result_blockindex;
int64_t height;
CBlock cblock;
CBlockIndex* cblock_index;
Persistent<Function> callback;
};
@ -462,6 +458,22 @@ struct async_tx_data {
Persistent<Function> callback;
};
/**
* async_addrtx_data
*/
typedef struct _ctx_list {
CTransaction ctx;
struct _ctx_list *next;
} ctx_list;
struct async_addrtx_data {
std::string err_msg;
std::string addr;
ctx_list *ctxs;
Persistent<Function> callback;
};
/**
* async_broadcast_tx_data
*/
@ -901,7 +913,7 @@ NAN_METHOD(IsStopped) {
/**
* GetBlock()
* bitcoind.getBlock(blockHash, callback)
* bitcoind.getBlock([blockHash,blockHeight], callback)
* Read any block from disk asynchronously.
*/
@ -909,20 +921,29 @@ NAN_METHOD(GetBlock) {
NanScope();
if (args.Length() < 2
|| !args[0]->IsString()
|| (!args[0]->IsString() || !args[0]->IsNumber())
|| !args[1]->IsFunction()) {
return NanThrowError(
"Usage: bitcoindjs.getBlock(blockHash, callback)");
"Usage: bitcoindjs.getBlock([blockHash,blockHeight], callback)");
}
async_block_data *data = new async_block_data();
if (args[0]->IsNumber()) {
int64_t height = args[0]->IntegerValue();
data->err_msg = std::string("");
data->hash = std::string("");
data->height = height;
} else {
String::Utf8Value hash_(args[0]->ToString());
std::string hash = std::string(*hash_);
data->err_msg = std::string("");
data->hash = hash;
data->height = -1;
}
String::Utf8Value hash(args[0]->ToString());
Local<Function> callback = Local<Function>::Cast(args[1]);
std::string hashp = std::string(*hash);
async_block_data *data = new async_block_data();
data->err_msg = std::string("");
data->hash = hashp;
data->callback = Persistent<Function>::New(callback);
uv_work_t *req = new uv_work_t();
@ -940,13 +961,27 @@ NAN_METHOD(GetBlock) {
static void
async_get_block(uv_work_t *req) {
async_block_data* data = static_cast<async_block_data*>(req->data);
if (data->height != -1) {
CBlockIndex* pblockindex = chainActive[data->height];
CBlock cblock;
if (ReadBlockFromDisk(cblock, pblockindex)) {
data->cblock = cblock;
data->cblock_index = pblockindex;
} else {
data->err_msg = std::string("get_block(): failed.");
}
return;
}
std::string strHash = data->hash;
uint256 hash(strHash);
CBlock cblock;
CBlockIndex* pblockindex = mapBlockIndex[hash];
if (ReadBlockFromDisk(cblock, pblockindex)) {
data->result_block = cblock;
data->result_blockindex = pblockindex;
data->cblock = cblock;
data->cblock_index = pblockindex;
} else {
data->err_msg = std::string("get_block(): failed.");
}
@ -967,8 +1002,8 @@ async_get_block_after(uv_work_t *req) {
node::FatalException(try_catch);
}
} else {
const CBlock& cblock = data->result_block;
CBlockIndex* cblock_index = data->result_blockindex;
const CBlock& cblock = data->cblock;
CBlockIndex* cblock_index = data->cblock_index;
Local<Object> jsblock = NanNew<Object>();
cblock_to_jsblock(cblock, cblock_index, jsblock, false);
@ -1613,8 +1648,8 @@ async_get_progress_after(uv_work_t *req) {
node::FatalException(try_catch);
}
} else {
const CBlock& cblock = data->result_block;
CBlockIndex* cblock_index = data->result_blockindex;
const CBlock& cblock = data->cblock;
CBlockIndex* cblock_index = data->cblock_index;
Local<Object> jsblock = NanNew<Object>();
cblock_to_jsblock(cblock, cblock_index, jsblock, false);
@ -1800,6 +1835,180 @@ NAN_METHOD(GetMiningInfo) {
NanReturnValue(obj);
}
/**
* GetAddrTransactions()
* bitcoind.getAddrTransactions(addr, callback)
* Read any transaction from disk asynchronously.
*/
NAN_METHOD(GetAddrTransactions) {
NanScope();
if (args.Length() < 2
|| !args[0]->IsString()
|| !args[1]->IsFunction()) {
return NanThrowError(
"Usage: bitcoindjs.getAddrTransactions(addr, callback)");
}
String::Utf8Value addr_(args[0]->ToString());
Local<Function> callback = Local<Function>::Cast(args[2]);
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->callback = Persistent<Function>::New(callback);
uv_work_t *req = new uv_work_t();
req->data = data;
int status = uv_queue_work(uv_default_loop(),
req, async_get_addrtx,
(uv_after_work_cb)async_get_addrtx_after);
assert(status == 0);
NanReturnValue(Undefined());
}
static void
async_get_addrtx(uv_work_t *req) {
async_addrtx_data* data = static_cast<async_addrtx_data*>(req->data);
CBitcoinAddress address = CBitcoinAddress(data->addr);
if (!address.IsValid()) {
data->err_msg = std::string("bad addr");
return;
}
CScript expected = GetScriptForDestination(address.Get());
int64_t i = 0;
int64_t height = chainActive.Height();
for (; i <= height; i++) {
CBlockIndex* pblockindex = chainActive[i];
CBlock cblock;
if (ReadBlockFromDisk(cblock, pblockindex)) {
BOOST_FOREACH(const CTransaction& ctx, cblock.vtx) {
// vin
BOOST_FOREACH(const CTxIn& txin, ctx.vin) {
// prev_txid
// std::string prev_txid = txin.prevout.hash.GetHex();
// asm
// std::string input_asm = txin.scriptSig.ToString();
// hex
// std::string input_hex = HexStr(txin.scriptSig.begin(), txin.scriptSig.end());
// format:
// { sig, pubkey }
// pseudocode:
// pubkey = input_asm.split().get(1);
// addr = base58(dsha(pubkey));
if (txin.scriptSig == expected) {
ctx_list *item = new ctx_list();
item->ctx = ctx;
if (data->ctxs == NULL) {
data->ctxs = item;
} else {
data->ctxs->next = item;
data->ctxs = item;
}
goto done;
}
}
// vout
for (unsigned int vo = 0; vo < ctx.vout.size(); vo++) {
const CTxOut& txout = ctx.vout[vo];
const CScript& scriptPubKey = txout.scriptPubKey;
txnouttype type;
vector<CTxDestination> addresses;
int nRequired;
if (ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
BOOST_FOREACH(const CTxDestination& addr, addresses) {
std::string str_addr = CBitcoinAddress(addr).ToString();
if (data->addr == str_addr) {
ctx_list *item = new ctx_list();
item->ctx = ctx;
if (data->ctxs == NULL) {
data->ctxs = item;
} else {
data->ctxs->next = item;
data->ctxs = item;
}
goto done;
}
}
}
}
}
done:
continue;
} else {
data->err_msg = std::string("get_addrtx(): failed.");
break;
}
}
return;
}
static void
async_get_addrtx_after(uv_work_t *req) {
NanScope();
async_addrtx_data* data = static_cast<async_addrtx_data*>(req->data);
if (!data->err_msg.empty()) {
Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
const unsigned argc = 1;
Local<Value> argv[argc] = { err };
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
} else {
const unsigned argc = 2;
Local<Object> result = NanNew<Object>();
Local<Array> tx = NanNew<Array>();
int i = 0;
ctx_list *next;
for (ctx_list *item = data->ctxs; item; item = next) {
Local<Object> jstx = NanNew<Object>();
ctx_to_jstx(item->ctx, 0, jstx);
tx->Set(i, jstx);
i++;
next = item->next;
delete item;
}
result->Set(NanNew<String>("address"), NanNew<String>(data->addr));
result->Set(NanNew<String>("tx"), tx);
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
Local<Value>::New(result)
};
TryCatch try_catch;
data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
data->callback.Dispose();
delete data;
delete req;
}
/**
* GetBlockHex()
* bitcoindjs.getBlockHex(callback)
@ -5234,6 +5443,7 @@ init(Handle<Object> target) {
NODE_SET_METHOD(target, "setGenerate", SetGenerate);
NODE_SET_METHOD(target, "getGenerate", GetGenerate);
NODE_SET_METHOD(target, "getMiningInfo", GetMiningInfo);
NODE_SET_METHOD(target, "getAddrTransactions", GetAddrTransactions);
NODE_SET_METHOD(target, "getBlockHex", GetBlockHex);
NODE_SET_METHOD(target, "getTxHex", GetTxHex);
NODE_SET_METHOD(target, "blockFromHex", BlockFromHex);