1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2013 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.
15 void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
17 batch.Erase(make_pair('c', hash));
19 batch.Write(make_pair('c', hash), coins);
22 void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
23 batch.Write('B', hash);
26 CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
29 bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) {
30 return db.Read(make_pair('c', txid), coins);
33 bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) {
35 BatchWriteCoins(batch, txid, coins);
36 return db.WriteBatch(batch);
39 bool CCoinsViewDB::HaveCoins(const uint256 &txid) {
40 return db.Exists(make_pair('c', txid));
43 CBlockIndex *CCoinsViewDB::GetBestBlock() {
44 uint256 hashBestChain;
45 if (!db.Read('B', hashBestChain))
47 std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hashBestChain);
48 if (it == mapBlockIndex.end())
53 bool CCoinsViewDB::SetBestBlock(CBlockIndex *pindex) {
55 BatchWriteHashBestChain(batch, pindex->GetBlockHash());
56 return db.WriteBatch(batch);
59 bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
60 LogPrint("coindb", "Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
63 for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
64 BatchWriteCoins(batch, it->first, it->second);
66 BatchWriteHashBestChain(batch, pindex->GetBlockHash());
68 return db.WriteBatch(batch);
71 CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
74 bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
76 return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
79 bool CBlockTreeDB::WriteBestInvalidWork(const CBigNum& bnBestInvalidWork)
81 // Obsolete; only written for backward compatibility.
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 CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
118 stats.hashBlock = GetBestBlock()->GetBlockHash();
119 ss << stats.hashBlock;
120 int64_t nTotalAmount = 0;
121 while (pcursor->Valid()) {
122 boost::this_thread::interruption_point();
124 leveldb::Slice slKey = pcursor->key();
125 CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
129 leveldb::Slice slValue = pcursor->value();
130 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
136 ss << VARINT(coins.nVersion);
137 ss << (coins.fCoinBase ? 'c' : 'n');
138 ss << VARINT(coins.nHeight);
139 stats.nTransactions++;
140 for (unsigned int i=0; i<coins.vout.size(); i++) {
141 const CTxOut &out = coins.vout[i];
143 stats.nTransactionOutputs++;
146 nTotalAmount += out.nValue;
149 stats.nSerializedSize += 32 + slValue.size();
153 } catch (std::exception &e) {
154 return error("%s() : deserialize error", __PRETTY_FUNCTION__);
158 stats.nHeight = GetBestBlock()->nHeight;
159 stats.hashSerialized = ss.GetHash();
160 stats.nTotalAmount = nTotalAmount;
164 bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
165 return Read(make_pair('t', txid), pos);
168 bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
170 for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
171 batch.Write(make_pair('t', it->first), it->second);
172 return WriteBatch(batch);
175 bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
176 return Write(std::make_pair('F', name), fValue ? '1' : '0');
179 bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
181 if (!Read(std::make_pair('F', name), ch))
187 bool CBlockTreeDB::LoadBlockIndexGuts()
189 leveldb::Iterator *pcursor = NewIterator();
191 CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
192 ssKeySet << make_pair('b', uint256(0));
193 pcursor->Seek(ssKeySet.str());
195 // Load mapBlockIndex
196 while (pcursor->Valid()) {
197 boost::this_thread::interruption_point();
199 leveldb::Slice slKey = pcursor->key();
200 CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
204 leveldb::Slice slValue = pcursor->value();
205 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
206 CDiskBlockIndex diskindex;
207 ssValue >> diskindex;
209 // Construct block index object
210 CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
211 pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
212 pindexNew->nHeight = diskindex.nHeight;
213 pindexNew->nFile = diskindex.nFile;
214 pindexNew->nDataPos = diskindex.nDataPos;
215 pindexNew->nUndoPos = diskindex.nUndoPos;
216 pindexNew->nVersion = diskindex.nVersion;
217 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
218 pindexNew->nTime = diskindex.nTime;
219 pindexNew->nBits = diskindex.nBits;
220 pindexNew->nNonce = diskindex.nNonce;
221 pindexNew->nStatus = diskindex.nStatus;
222 pindexNew->nTx = diskindex.nTx;
224 if (!pindexNew->CheckIndex())
225 return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
229 break; // if shutdown requested or finished loading block index
231 } catch (std::exception &e) {
232 return error("%s() : deserialize error", __PRETTY_FUNCTION__);