diff options
author | Gavin Andresen <gavinandresen@gmail.com> | 2013-01-25 12:55:52 -0800 |
---|---|---|
committer | Gavin Andresen <gavinandresen@gmail.com> | 2013-01-25 12:55:52 -0800 |
commit | 63cc7661a5dc40479a4492a678c38b1021b9ce92 (patch) | |
tree | 8b8bfc427581dc17774a9f30c379dc4c687ae063 | |
parent | d3ab598fd5261a89002c0b12913c4f3e22e82f33 (diff) | |
parent | 2d1fa42e85c9164688aa69b3f54f015fbefc06aa (diff) |
Merge pull request #2168 from sipa/txindex
Add optional transaction index to databases
-rw-r--r-- | src/init.cpp | 6 | ||||
-rw-r--r-- | src/main.cpp | 44 | ||||
-rw-r--r-- | src/main.h | 24 | ||||
-rw-r--r-- | src/txdb.cpp | 23 | ||||
-rw-r--r-- | src/txdb.h | 4 |
5 files changed, 94 insertions, 7 deletions
diff --git a/src/init.cpp b/src/init.cpp index 1d49a7bedb..7285e7c0d5 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -305,6 +305,7 @@ std::string HelpMessage() " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n" + " -checkblocks=<n> " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" + " -checklevel=<n> " + _("How thorough the block verification is (0-4, default: 3)") + "\n" + + " -txindex " + _("Maintain a full transaction index (default: 0)") + "\n" + " -loadblock=<file> " + _("Imports blocks from external blk000??.dat file") + "\n" + " -reindex " + _("Rebuild blockchain index from current blk000??.dat files") + "\n" + " -par=N " + _("Set the number of script verification threads (1-16, 0=auto, default: 0)") + "\n" + @@ -781,7 +782,7 @@ bool AppInit2() if (nTotalCache < (1 << 22)) nTotalCache = (1 << 22); // total cache cannot be less than 4 MiB size_t nBlockTreeDBCache = nTotalCache / 8; - if (nBlockTreeDBCache > (1 << 21)) + if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", false)) nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB nTotalCache -= nBlockTreeDBCache; size_t nCoinDBCache = nTotalCache / 2; // use half of the remaining cache for coindb cache @@ -806,6 +807,9 @@ bool AppInit2() if (!VerifyDB()) return InitError(_("Corrupted block database detected. Please restart the client with -reindex.")); + if (mapArgs.count("-txindex") && fTxIndex != GetBoolArg("-txindex", false)) + return InitError(_("You need to rebuild the databases using -reindex to change -txindex")); + // as LoadBlockIndex can take several minutes, it's possible the user // requested to kill bitcoin-qt during the last operation. If so, exit. // As the program has not fully started yet, Shutdown() is possibly overkill. diff --git a/src/main.cpp b/src/main.cpp index f6fce00e6e..84a5cdc17b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,6 +45,7 @@ int nScriptCheckThreads = 0; bool fImporting = false; bool fReindex = false; bool fBenchmark = false; +bool fTxIndex = false; unsigned int nCoinCacheSize = 5000; CMedianFilter<int> cPeerBlockCounts(8, 0); // Amount of blocks that other nodes claim to have @@ -950,6 +951,25 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock } } + if (fTxIndex) { + CDiskTxPos postx; + if (pblocktree->ReadTxIndex(hash, postx)) { + CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); + CBlockHeader header; + try { + file >> header; + fseek(file, postx.nTxOffset, SEEK_CUR); + file >> txOut; + } catch (std::exception &e) { + return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); + } + hashBlock = header.GetHash(); + if (txOut.GetHash() != hash) + return error("%s() : txid mismatch", __PRETTY_FUNCTION__); + return true; + } + } + if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it int nHeight = -1; { @@ -1641,6 +1661,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust int64 nFees = 0; int nInputs = 0; unsigned int nSigOps = 0; + CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(vtx.size())); + std::vector<std::pair<uint256, CDiskTxPos> > vPos; + vPos.reserve(vtx.size()); for (unsigned int i=0; i<vtx.size(); i++) { @@ -1680,6 +1703,8 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust if (!tx.IsCoinBase()) blockundo.vtxundo.push_back(txundo); + vPos.push_back(std::make_pair(GetTxHash(i), pos)); + pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); } int64 nTime = GetTimeMicros() - nStart; if (fBenchmark) @@ -1719,6 +1744,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust return error("ConnectBlock() : WriteBlockIndex failed"); } + if (fTxIndex) + pblocktree->WriteTxIndex(vPos); + // add this block to the view's block chain if (!view.SetBestBlock(pindex)) return false; @@ -2548,6 +2576,10 @@ bool static LoadBlockIndexDB() pblocktree->ReadReindexing(fReindexing); fReindex |= fReindexing; + // Check whether we have a transaction index + pblocktree->ReadFlag("txindex", fTxIndex); + printf("LoadBlockIndex(): transaction index %s\n", fTxIndex ? "enabled" : "disabled"); + // Load hashBestChain pointer to end of best chain pindexBest = pcoinsTip->GetBestBlock(); if (pindexBest == NULL) @@ -2652,13 +2684,10 @@ bool LoadBlockIndex() hashGenesisBlock = uint256("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"); } - if (fReindex) - return true; - // // Load block index from databases // - if (!LoadBlockIndexDB()) + if (!fReindex && !LoadBlockIndexDB()) return false; // @@ -2666,6 +2695,13 @@ bool LoadBlockIndex() // if (mapBlockIndex.empty()) { + fTxIndex = GetBoolArg("-txindex", false); + pblocktree->WriteFlag("txindex", fTxIndex); + printf("Initializing databases...\n"); + + if (fReindex) + return true; + // Genesis Block: // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1) // CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0) diff --git a/src/main.h b/src/main.h index 2d3a9f5bd0..edfea7b510 100644 --- a/src/main.h +++ b/src/main.h @@ -93,6 +93,7 @@ extern bool fImporting; extern bool fReindex; extern bool fBenchmark; extern int nScriptCheckThreads; +extern bool fTxIndex; extern unsigned int nCoinCacheSize; // Settings @@ -196,9 +197,8 @@ static inline std::string BlockHashStr(const uint256& hash) bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); -class CDiskBlockPos +struct CDiskBlockPos { -public: int nFile; unsigned int nPos; @@ -228,7 +228,27 @@ public: bool IsNull() const { return (nFile == -1); } }; +struct CDiskTxPos : public CDiskBlockPos +{ + unsigned int nTxOffset; // after header + + IMPLEMENT_SERIALIZE( + READWRITE(*(CDiskBlockPos*)this); + READWRITE(VARINT(nTxOffset)); + ) + + CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) { + } + + CDiskTxPos() { + SetNull(); + } + void SetNull() { + CDiskBlockPos::SetNull(); + nTxOffset = 0; + } +}; /** An inpoint - a combination of a transaction and an index n into its vin */ diff --git a/src/txdb.cpp b/src/txdb.cpp index 93c5f23d8b..78fa0279ba 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -145,6 +145,29 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) { return true; } +bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) { + return Read(make_pair('t', txid), pos); +} + +bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) { + CLevelDBBatch batch; + for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++) + batch.Write(make_pair('t', it->first), it->second); + return WriteBatch(batch); +} + +bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) { + return Write(std::make_pair('F', name), fValue ? '1' : '0'); +} + +bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) { + char ch; + if (!Read(std::make_pair('F', name), ch)) + return false; + fValue = ch == '1'; + return true; +} + bool CBlockTreeDB::LoadBlockIndexGuts() { leveldb::Iterator *pcursor = NewIterator(); diff --git a/src/txdb.h b/src/txdb.h index d7d327069f..ebac81b301 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -43,6 +43,10 @@ public: bool WriteLastBlockFile(int nFile); bool WriteReindexing(bool fReindex); bool ReadReindexing(bool &fReindex); + bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos); + bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list); + bool WriteFlag(const std::string &name, bool fValue); + bool ReadFlag(const std::string &name, bool &fValue); bool LoadBlockIndexGuts(); }; |