1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
11 void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
13 batch.Erase(make_pair('c', hash));
15 batch.Write(make_pair('c', hash), coins);
18 void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
19 batch.Write('B', hash);
22 CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
25 bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) {
26 return db.Read(make_pair('c', txid), coins);
29 bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) {
31 BatchWriteCoins(batch, txid, coins);
32 return db.WriteBatch(batch);
35 bool CCoinsViewDB::HaveCoins(const uint256 &txid) {
36 return db.Exists(make_pair('c', txid));
39 CBlockIndex *CCoinsViewDB::GetBestBlock() {
40 uint256 hashBestChain;
41 if (!db.Read('B', hashBestChain))
43 std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hashBestChain);
44 if (it == mapBlockIndex.end())
49 bool CCoinsViewDB::SetBestBlock(CBlockIndex *pindex) {
51 BatchWriteHashBestChain(batch, pindex->GetBlockHash());
52 return db.WriteBatch(batch);
55 bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
56 printf("Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
59 for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
60 BatchWriteCoins(batch, it->first, it->second);
62 BatchWriteHashBestChain(batch, pindex->GetBlockHash());
64 return db.WriteBatch(batch);
67 CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDB(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
70 bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
72 return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
75 bool CBlockTreeDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
77 return Read('I', bnBestInvalidWork);
80 bool CBlockTreeDB::WriteBestInvalidWork(const CBigNum& bnBestInvalidWork)
82 return Write('I', bnBestInvalidWork);
85 bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
86 return Write(make_pair('f', nFile), info);
89 bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
90 return Read(make_pair('f', nFile), info);
93 bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
94 return Write('l', nFile);
97 bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
99 return Write('R', '1');
104 bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
105 fReindexing = Exists('R');
109 bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
110 return Read('l', nFile);
113 bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
114 leveldb::Iterator *pcursor = db.NewIterator();
115 pcursor->SeekToFirst();
117 while (pcursor->Valid()) {
119 leveldb::Slice slKey = pcursor->key();
120 CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
123 if (chType == 'c' && !fRequestShutdown) {
124 leveldb::Slice slValue = pcursor->value();
125 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
131 stats.nTransactions++;
132 BOOST_FOREACH(const CTxOut &out, coins.vout) {
134 stats.nTransactionOutputs++;
136 stats.nSerializedSize += 32 + slValue.size();
139 } catch (std::exception &e) {
140 return error("%s() : deserialize error", __PRETTY_FUNCTION__);
144 stats.nHeight = GetBestBlock()->nHeight;
148 bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
149 return Read(make_pair('t', txid), pos);
152 bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
154 for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
155 batch.Write(make_pair('t', it->first), it->second);
156 return WriteBatch(batch);
159 bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
160 return Write(std::make_pair('F', name), fValue ? '1' : '0');
163 bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
165 if (!Read(std::make_pair('F', name), ch))
171 bool CBlockTreeDB::LoadBlockIndexGuts()
173 leveldb::Iterator *pcursor = NewIterator();
175 CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
176 ssKeySet << make_pair('b', uint256(0));
177 pcursor->Seek(ssKeySet.str());
179 // Load mapBlockIndex
180 while (pcursor->Valid()) {
182 leveldb::Slice slKey = pcursor->key();
183 CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
186 if (chType == 'b' && !fRequestShutdown) {
187 leveldb::Slice slValue = pcursor->value();
188 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
189 CDiskBlockIndex diskindex;
190 ssValue >> diskindex;
192 // Construct block index object
193 CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
194 pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
195 pindexNew->nHeight = diskindex.nHeight;
196 pindexNew->nFile = diskindex.nFile;
197 pindexNew->nDataPos = diskindex.nDataPos;
198 pindexNew->nUndoPos = diskindex.nUndoPos;
199 pindexNew->nVersion = diskindex.nVersion;
200 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
201 pindexNew->nTime = diskindex.nTime;
202 pindexNew->nBits = diskindex.nBits;
203 pindexNew->nNonce = diskindex.nNonce;
204 pindexNew->nStatus = diskindex.nStatus;
205 pindexNew->nTx = diskindex.nTx;
207 // Watch for genesis block
208 if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
209 pindexGenesisBlock = pindexNew;
211 if (!pindexNew->CheckIndex())
212 return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
216 break; // if shutdown requested or finished loading block index
218 } catch (std::exception &e) {
219 return error("%s() : deserialize error", __PRETTY_FUNCTION__);