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(bool fMemory) : db(GetDataDir() / "coins", fMemory) {
25 bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) {
26 return db.Read(make_pair('c', txid), coins);
29 bool CCoinsViewDB::SetCoins(uint256 txid, const CCoins &coins) {
31 BatchWriteCoins(batch, txid, coins);
32 return db.WriteBatch(batch);
35 bool CCoinsViewDB::HaveCoins(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);
61 BatchWriteHashBestChain(batch, pindex->GetBlockHash());
63 return db.WriteBatch(batch);
66 CBlockTreeDB::CBlockTreeDB(bool fMemory) : CLevelDB(GetDataDir() / "blktree", fMemory) {
69 bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
71 return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
74 bool CBlockTreeDB::ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust)
76 return Read('I', bnBestInvalidTrust);
79 bool CBlockTreeDB::WriteBestInvalidTrust(CBigNum bnBestInvalidTrust)
81 return Write('I', bnBestInvalidTrust);
84 bool CBlockTreeDB::ReadSyncCheckpoint(uint256& hashCheckpoint)
86 return Read('H', hashCheckpoint);
89 bool CBlockTreeDB::WriteSyncCheckpoint(uint256 hashCheckpoint)
91 return Write('H', hashCheckpoint);
94 bool CBlockTreeDB::ReadCheckpointPubKey(string& strPubKey)
96 return Read('K', strPubKey);
99 bool CBlockTreeDB::WriteCheckpointPubKey(const string& strPubKey)
101 return Write('K', strPubKey);
104 bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
105 return Write(make_pair('f', nFile), info);
108 bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
109 return Read(make_pair('f', nFile), info);
112 bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
113 return Write('l', nFile);
116 bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
117 return Read('l', nFile);
120 bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
121 leveldb::Iterator *pcursor = db.NewIterator();
122 pcursor->SeekToFirst();
124 while (pcursor->Valid()) {
126 leveldb::Slice slKey = pcursor->key();
127 CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
130 if (chType == 'c' && !fRequestShutdown) {
131 leveldb::Slice slValue = pcursor->value();
132 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
138 stats.nTransactions++;
139 BOOST_FOREACH(const CTxOut &out, coins.vout) {
141 stats.nTransactionOutputs++;
143 stats.nSerializedSize += 32 + slValue.size();
146 } catch (std::exception &e) {
147 return error("%s() : deserialize error", __PRETTY_FUNCTION__);
151 stats.nHeight = GetBestBlock()->nHeight;
155 bool CBlockTreeDB::LoadBlockIndexGuts()
157 leveldb::Iterator *pcursor = NewIterator();
159 CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
160 ssKeySet << make_pair('b', uint256(0));
161 pcursor->Seek(ssKeySet.str());
163 // Load mapBlockIndex
164 while (pcursor->Valid()) {
166 leveldb::Slice slKey = pcursor->key();
167 CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
170 if (chType == 'b' && !fRequestShutdown) {
171 leveldb::Slice slValue = pcursor->value();
172 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
173 CDiskBlockIndex diskindex;
174 ssValue >> diskindex;
176 uint256 blockHash = diskindex.GetBlockHash();
178 // Construct block index object
179 CBlockIndex* pindexNew = InsertBlockIndex(blockHash);
180 pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
181 pindexNew->nHeight = diskindex.nHeight;
182 pindexNew->nFile = diskindex.nFile;
183 pindexNew->nDataPos = diskindex.nDataPos;
184 pindexNew->nUndoPos = diskindex.nUndoPos;
185 pindexNew->nMint = diskindex.nMint;
186 pindexNew->nMoneySupply = diskindex.nMoneySupply;
187 pindexNew->nFlags = diskindex.nFlags;
188 pindexNew->nStakeModifier = diskindex.nStakeModifier;
189 pindexNew->prevoutStake = diskindex.prevoutStake;
190 pindexNew->nStakeTime = diskindex.nStakeTime;
191 pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
192 pindexNew->nVersion = diskindex.nVersion;
193 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
194 pindexNew->nTime = diskindex.nTime;
195 pindexNew->nBits = diskindex.nBits;
196 pindexNew->nNonce = diskindex.nNonce;
197 pindexNew->nStatus = diskindex.nStatus;
198 pindexNew->nTx = diskindex.nTx;
200 // Watch for genesis block
201 if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
202 pindexGenesisBlock = pindexNew;
204 if (!pindexNew->CheckIndex())
205 return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
207 // Build setStakeSeen
208 if (pindexNew->IsProofOfStake())
209 setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
213 break; // if shutdown requested or finished loading block index
215 } catch (std::exception &e) {
216 return error("%s() : deserialize error", __PRETTY_FUNCTION__);