aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGavin Andresen <gavinandresen@gmail.com>2013-01-25 12:55:52 -0800
committerGavin Andresen <gavinandresen@gmail.com>2013-01-25 12:55:52 -0800
commit63cc7661a5dc40479a4492a678c38b1021b9ce92 (patch)
tree8b8bfc427581dc17774a9f30c379dc4c687ae063
parentd3ab598fd5261a89002c0b12913c4f3e22e82f33 (diff)
parent2d1fa42e85c9164688aa69b3f54f015fbefc06aa (diff)
Merge pull request #2168 from sipa/txindex
Add optional transaction index to databases
-rw-r--r--src/init.cpp6
-rw-r--r--src/main.cpp44
-rw-r--r--src/main.h24
-rw-r--r--src/txdb.cpp23
-rw-r--r--src/txdb.h4
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();
};