diff --git a/benchmarks/index.js b/benchmarks/index.js index a6b7ecf4..be32186b 100644 --- a/benchmarks/index.js +++ b/benchmarks/index.js @@ -90,7 +90,7 @@ bitcoind.on('ready', function() { c = 0; } var hash = fixtureData.txHashes[c]; - bitcoind.getTransaction(hash, function(err, tx) { + bitcoind.getTransaction(hash, true, function(err, tx) { if (err) { throw err; } diff --git a/integration/index.js b/integration/index.js index b018f3c1..bd2c2f22 100644 --- a/integration/index.js +++ b/integration/index.js @@ -54,7 +54,7 @@ describe('Basic Functionality', function() { var tx = bitcore.Transaction(); tx.fromString(data); it('for tx ' + tx.hash, function(done) { - bitcoind.getTransaction(tx.hash, function(err, response) { + bitcoind.getTransaction(tx.hash, true, function(err, response) { if (err) { throw err; } diff --git a/integration/livenet-spents.json b/integration/livenet-spents.json index 8c1eed28..35e57234 100644 --- a/integration/livenet-spents.json +++ b/integration/livenet-spents.json @@ -5,8 +5,8 @@ "outputIndex": 0 }, { - "txid": "64b2da257d93ab44d19ef9b374788d82b6885bc3fb3c17704f42f09b1096e982", - "outputIndex": 0 + "txid": "8131ffb0a2c945ecaf9b9063e59558784f9c3a74741ce6ae2a18d0571dac15bb", + "outputIndex": 1 }, { "txid": "226bbc4b1f851857f37aa96e9eb702946fc128b055e4decc684740005f5044cf", diff --git a/lib/bitcoind.js b/lib/bitcoind.js index bb022a84..9d1c0b5f 100644 --- a/lib/bitcoind.js +++ b/lib/bitcoind.js @@ -327,36 +327,8 @@ Bitcoin.prototype.isSpent = function(txid, outputIndex) { return bitcoindjs.isSpent(txid, outputIndex); }; -Bitcoin.prototype.getTransaction = -Bitcoin.prototype.getTx = function(txid, blockhash, callback) { - if (bitcoin.stopping) return []; - if (typeof txid === 'object' && txid) { - var options = txid; - callback = blockhash; - txid = options.txid || options.tx || options.txhash || options.id || options.hash; - blockhash = options.blockhash || options.block; - } - - if (typeof blockhash === 'function') { - callback = blockhash; - blockhash = ''; - } - - if (typeof blockhash !== 'string') { - if (blockhash) { - blockhash = blockhash.hash - || blockhash.blockhash - || (blockhash.getHash && blockhash.getHash()) - || ''; - } else { - blockhash = ''; - } - } - - return bitcoindjs.getTransaction(txid, blockhash, function(err, tx) { - if (err) return callback(err); - return callback(null, tx); - }); +Bitcoin.prototype.getTransaction = function(txid, queryMempool, callback) { + return bitcoindjs.getTransaction(txid, queryMempool, callback); }; Bitcoin.prototype.getTransactionWithBlock = function(txid, blockhash, callback) { diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index b4fb8467..fcf700a9 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -132,6 +132,7 @@ struct async_tx_data { std::string err_msg; std::string txid; std::string blockhash; + bool queryMempool; CTransaction ctx; Eternal callback; }; @@ -425,10 +426,8 @@ start_node_thread(void) { argc++; } - if (g_txindex) { - argv[argc] = (char *)"-txindex"; - argc++; - } + argv[argc] = (char *)"-txindex"; + argc++; argv[argc] = NULL; @@ -754,7 +753,7 @@ async_get_block_after(uv_work_t *req) { /** * GetTransaction() - * bitcoind.getTransaction(txid, [blockhash], callback) + * bitcoind.getTransaction(txid, callback) * Read any transaction from disk asynchronously. */ @@ -763,14 +762,14 @@ NAN_METHOD(GetTransaction) { HandleScope scope(isolate); if (args.Length() < 3 || !args[0]->IsString() - || !args[1]->IsString() + || !args[1]->IsBoolean() || !args[2]->IsFunction()) { return NanThrowError( - "Usage: bitcoindjs.getTransaction(txid, [blockhash], callback)"); + "Usage: bitcoindjs.getTransaction(txid, callback)"); } String::Utf8Value txid_(args[0]->ToString()); - String::Utf8Value blockhash_(args[1]->ToString()); + bool queryMempool = args[1]->BooleanValue(); Local callback = Local::Cast(args[2]); async_tx_data *data = new async_tx_data(); @@ -779,16 +778,12 @@ NAN_METHOD(GetTransaction) { data->txid = std::string(""); std::string txid = std::string(*txid_); - std::string blockhash = std::string(*blockhash_); data->txid = txid; + data->queryMempool = queryMempool; Eternal eternal(isolate, callback); data->callback = eternal; - if (blockhash == "") { - data->blockhash = uint256().GetHex(); - } - uv_work_t *req = new uv_work_t(); req->data = data; @@ -808,12 +803,38 @@ async_get_tx(uv_work_t *req) { uint256 hash = uint256S(data->txid); uint256 blockhash; CTransaction ctx; - - if (!GetTransaction(hash, ctx, blockhash, true)) { - data->err_msg = std::string("Transaction not found."); - } else { - data->ctx = ctx; - data->blockhash = blockhash.GetHex(); + + if (data->queryMempool) { + LOCK(cs_main); + { + if (mempool.lookup(hash, ctx)) + { + return; + } + } + } + + CDiskTxPos postx; + if (pblocktree->ReadTxIndex(hash, postx)) { + + CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); + + if (file.IsNull()) { + data->err_msg = std::string("%s: OpenBlockFile failed", __func__); + return; + } + + const int HEADER_SIZE = sizeof(int32_t) + sizeof(uint32_t) * 3 + sizeof(char) * 64; + + try { + fseek(file.Get(), postx.nTxOffset + HEADER_SIZE, SEEK_CUR); + file >> ctx; + data->ctx = ctx; + } catch (const std::exception& e) { + data->err_msg = std::string("Deserialize or I/O error - %s", __func__); + return; + } + } } @@ -842,7 +863,7 @@ async_get_tx_after(uv_work_t *req) { ssTx << ctx; std::string stx = ssTx.str(); Local rawNodeBuffer = node::Buffer::New(isolate, stx.c_str(), stx.size()); - + const unsigned argc = 2; Local argv[argc] = { Local::New(isolate, NanNull()),