From 83048eef3340f1af87aa7df793d4427a2134160c Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Mon, 8 Dec 2014 13:05:22 -0800 Subject: [PATCH] add get_tx_ldb. --- lib/bitcoind.js | 8 +-- src/bitcoindjs.cc | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 3 deletions(-) diff --git a/lib/bitcoind.js b/lib/bitcoind.js index cc9efed6..5e0d6bf9 100644 --- a/lib/bitcoind.js +++ b/lib/bitcoind.js @@ -405,8 +405,10 @@ Bitcoin.prototype.getTx = function(txid, blockhash, callback) { if (blockhash && typeof blockhash === 'string') { return bitcoindjs.getTransaction(txid, blockhash, traverse, function(err, tx) { if (err) return callback(err); - bitcoin.db.set('tx-block/' + txid, - { hash: blockhash }, utils.NOOP); + if (tx.blockhash) { + bitcoin.db.set('tx-block/' + txid, + { hash: tx.blockhash }, utils.NOOP); + } return callback(null, bitcoin.tx(tx)); }); } @@ -414,7 +416,7 @@ Bitcoin.prototype.getTx = function(txid, blockhash, callback) { // Will traverse blockchain if no block - slow: return bitcoinjs.getTransaction(txid, block ? block.hash : '', traverse, function(err, tx) { if (err) return callback(err); - if (!block) { + if (!block && tx.blockhash) { bitcoin.db.set('tx-block/' + txid, { hash: tx.blockhash }, utils.NOOP); } diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index 5e2d2237..6e71d9b4 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -189,6 +189,8 @@ using namespace v8; // LevelDB options #define USE_LDB_ADDR 0 #define USE_LDB_TX 0 +#define USE_LDB_GETTX 1 +#define USE_LDB_GETTX_MAIN 0 /** * Node.js Exposed Function Templates @@ -606,6 +608,11 @@ static ctx_list * read_addr(const std::string addr, const int64_t blockheight, const int64_t blocktime); #endif +#if defined(USE_LDB_GETTX) || defined(USE_LDB_GETTX_MAIN) +static bool +get_tx_ldb(const uint256 itxid, CTransaction& rctx, uint256& rblockhash); +#endif + #if USE_LDB_TX static bool get_block_by_tx(const std::string itxid, CBlock& rcblock, CBlockIndex **rcblock_index); @@ -1169,12 +1176,21 @@ async_get_tx(uv_work_t *req) { uint256 blockhash(data->blockhash); CTransaction ctx; +#if USE_LDB_GETTX_MAIN + if (get_tx_ldb(hash, ctx, blockhash)) { + data->ctx = ctx; + data->blockhash = blockhash.GetHex(); + } else { + data->err_msg = std::string("get_tx(): failed."); + } +#else if (get_tx(hash, blockhash, data->traverse, ctx)) { data->ctx = ctx; data->blockhash = blockhash.GetHex(); } else { data->err_msg = std::string("get_tx(): failed."); } +#endif } static void @@ -5849,6 +5865,9 @@ get_tx(uint256 txid, uint256& blockhash, const bool traverse, CTransaction& ctx) if (GetTransaction(txid, ctx, blockhash, true)) { return 1; } else if (traverse && blockhash != 0) { +#if USE_LDB_GETTX + get_tx_ldb(txid, ctx, blockhash); +#else CBlock block; CBlockIndex* pblockindex = mapBlockIndex[blockhash]; if (ReadBlockFromDisk(block, pblockindex)) { @@ -5860,6 +5879,7 @@ get_tx(uint256 txid, uint256& blockhash, const bool traverse, CTransaction& ctx) } } } +#endif } return 0; } @@ -6508,6 +6528,107 @@ error: } #endif +#if defined(USE_LDB_GETTX) || defined(USE_LDB_GETTX_MAIN) +/** + LevelDB Parser + DB: blocks/blk/revXXXXX.dat + */ + +static bool +get_tx_ldb(const uint256 itxid, CTransaction& rctx, uint256& rblockhash) { + leveldb::Iterator* pcursor = pblocktree->pdb->NewIterator(pblocktree->iteroptions); + + pcursor->SeekToFirst(); + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + try { + leveldb::Slice slKey = pcursor->key(); + + CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION); + + char type; + ssKey >> type; + + // Blockchain Index Structure: + // http://bitcoin.stackexchange.com/questions/28168 + + // Transaction Structure: + // 't' + 32-byte tx hash + // Which block file the tx is stored in + // Which offset in the block file the tx resides + // The offset from the top of the block containing the tx + if (type == 't') { + uint256 txid; + ssKey >> txid; + if (txid == itxid) { + leveldb::Slice slValue = pcursor->value(); + + CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION); + + // struct CDiskBlockPos { + // int nFile; + // unsigned int nPos; + // }; + // struct CDiskTxPos : public CDiskBlockPos { + // unsigned int nTxOffset; + // }; + + CDiskTxPos txPos; + ssValue >> txPos; + + CTransaction ctx; + uint256 blockhash; + + if (!pblocktree->ReadTxIndex(txid, txPos)) { + goto error; + } + + CAutoFile file(OpenBlockFile(txPos, true), SER_DISK, CLIENT_VERSION); + CBlockHeader header; + try { + file >> header; + fseek(file.Get(), txPos.nTxOffset, SEEK_CUR); + file >> ctx; + } catch (std::exception &e) { + goto error; + } + if (ctx.GetHash() != txid) { + goto error; + } + blockhash = header.GetHash(); + + CBlock cblock; + CBlockIndex* pblockindex = mapBlockIndex[blockhash]; + if (ReadBlockFromDisk(cblock, pblockindex)) { + BOOST_FOREACH(const CTransaction& ctx, cblock.vtx) { + if (ctx.GetHash() == itxid) { + rblockhash = blockhash; + rctx = ctx; + delete pcursor; + return true; + } + } + goto error; + } + + goto error; + } + } + + pcursor->Next(); + } catch (std::exception &e) { + delete pcursor; + return false; + } + } + +error: + delete pcursor; + return false; +} +#endif + /** LevelDB Parser DB: blocks/blk/revXXXXX.dat