From b1ae73848c0c1ce32ccd4d1846401139419e6547 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Tue, 16 Dec 2014 14:41:00 -0800 Subject: [PATCH] add naive getFromTx for insight. --- lib/bitcoind.js | 10 ++++ src/bitcoindjs.cc | 137 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) diff --git a/lib/bitcoind.js b/lib/bitcoind.js index dfcd1c22..8d01478d 100644 --- a/lib/bitcoind.js +++ b/lib/bitcoind.js @@ -600,6 +600,16 @@ Bitcoin.prototype.getBlocksByTime = function(options, callback) { }); }; +Bitcoin.prototype.getFromTx = function(txid, callback) { + if (bitcoin.stopping) return []; + return bitcoindjs.getFromTx(txid, function(err, txs) { + if (err) return callback(err); + return callback(null, txs.map(function(tx) { + return bitcoin.tx(tx) + })); + }); +}; + Bitcoin.prototype.getLastFileIndex = function() { if (bitcoin.stopping) return []; return bitcoindjs.getLastFileIndex(); diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index 4c425750..abd1d09c 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -224,6 +224,7 @@ NAN_METHOD(GetBestBlock); NAN_METHOD(GetChainHeight); NAN_METHOD(GetBlockByTx); NAN_METHOD(GetBlocksByTime); +NAN_METHOD(GetFromTx); NAN_METHOD(GetLastFileIndex); NAN_METHOD(GetBlockHex); @@ -605,6 +606,17 @@ struct async_rescan_data { Persistent callback; }; +/** + * async_from_tx_data + */ + +struct async_from_tx_data { + std::string err_msg; + std::string txid; + ctx_list *ctxs; + Persistent callback; +}; + /** * Read Raw DB */ @@ -2495,6 +2507,130 @@ async_block_time_after(uv_work_t *req) { delete req; } +/** + * GetFromTx() + * bitcoindjs.getFromTx() + * Get all TXes beyond a txid + */ + +NAN_METHOD(GetFromTx) { + NanScope(); + + // if (SHUTTING_DOWN()) NanReturnValue(Undefined()); + + if (args.Length() < 2 + || !args[0]->IsString() + || !args[1]->IsFunction()) { + return NanThrowError( + "Usage: bitcoindjs.getFromTx(txid, callback)"); + } + + async_from_tx_data *data = new async_from_tx_data(); + + uv_work_t *req = new uv_work_t(); + req->data = data; + + String::Utf8Value txid_(args[0]->ToString()); + std::string txid = std::string(*txid_); + + data->txid = txid; + data->ctxs = NULL; + data->err_msg = std::string(""); + + Local callback = Local::Cast(args[1]); + data->callback = Persistent::New(callback); + + int status = uv_queue_work(uv_default_loop(), + req, async_from_tx, + (uv_after_work_cb)async_from_tx_after); + + assert(status == 0); + + NanReturnValue(Undefined()); +} + +static void +async_from_tx(uv_work_t *req) { + async_from_tx_data* data = static_cast(req->data); + + // if (SHUTTING_DOWN()) return; + + uint256 txid(data->txid); + bool found = false; + 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) { + if (found || ctx.GetHash() == txid) { + if (!found) found = true; + ctx_list *item = new ctx_list(); + item->ctx = ctx; + item->blockhash = cblock.GetHash(); + if (data->ctxs == NULL) { + data->ctxs = item; + } else { + data->ctxs->next = item; + data->ctxs = item; + } + } + } + } else { + data->err_msg = std::string("TX not found."); + break; + } + } +} + +static void +async_from_tx_after(uv_work_t *req) { + NanScope(); + async_from_tx_data* data = static_cast(req->data); + + // if (SHUTTING_DOWN()) return; + + if (data->err_msg != "") { + Local err = Exception::Error(NanNew(data->err_msg)); + const unsigned argc = 1; + Local 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 tx = NanNew(); + int i = 0; + ctx_list *next; + for (ctx_list *item = data->ctxs; item; item = next) { + Local jstx = NanNew(); + ctx_to_jstx(item->ctx, item->blockhash, jstx); + tx->Set(i, jstx); + i++; + next = item->next; + delete item; + } + Local argv[argc] = { + Local::New(Null()), + Local::New(tx) + }; + 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; +} + #if 0 // ~/work/node_modules/bitcore/lib/Bloom.js // ~/bitcoin/src/bloom.cpp @@ -7121,6 +7257,7 @@ init(Handle target) { NODE_SET_METHOD(target, "getChainHeight", GetChainHeight); NODE_SET_METHOD(target, "getBlockByTx", GetBlockByTx); NODE_SET_METHOD(target, "getBlocksByTime", GetBlocksByTime); + NODE_SET_METHOD(target, "getFromTx", GetFromTx); NODE_SET_METHOD(target, "getLastFileIndex", GetLastFileIndex); NODE_SET_METHOD(target, "getBlockHex", GetBlockHex); NODE_SET_METHOD(target, "getTxHex", GetTxHex);