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) {
12 batch.Write(make_pair('c', hash), coins);
15 void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
16 batch.Write('B', hash);
19 CCoinsViewDB::CCoinsViewDB(bool fMemory) : db(GetDataDir() / "coins", fMemory) {
22 bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) {
23 return db.Read(make_pair('c', txid), coins);
26 bool CCoinsViewDB::SetCoins(uint256 txid, const CCoins &coins) {
28 BatchWriteCoins(batch, txid, coins);
29 return db.WriteBatch(batch);
32 bool CCoinsViewDB::HaveCoins(uint256 txid) {
33 return db.Exists(make_pair('c', txid));
36 CBlockIndex *CCoinsViewDB::GetBestBlock() {
37 uint256 hashBestChain;
38 if (!db.Read('B', hashBestChain))
40 std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hashBestChain);
41 if (it == mapBlockIndex.end())
46 bool CCoinsViewDB::SetBestBlock(CBlockIndex *pindex) {
48 BatchWriteHashBestChain(batch, pindex->GetBlockHash());
49 return db.WriteBatch(batch);
52 bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
53 printf("Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
56 for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
57 BatchWriteCoins(batch, it->first, it->second);
58 BatchWriteHashBestChain(batch, pindex->GetBlockHash());
60 return db.WriteBatch(batch);
63 CBlockTreeDB::CBlockTreeDB(bool fMemory) : CLevelDB(GetDataDir() / "blktree", fMemory) {
66 bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
68 return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
71 bool CBlockTreeDB::ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust)
73 return Read('I', bnBestInvalidTrust);
76 bool CBlockTreeDB::WriteBestInvalidTrust(CBigNum bnBestInvalidTrust)
78 return Write('I', bnBestInvalidTrust);
81 bool CBlockTreeDB::ReadSyncCheckpoint(uint256& hashCheckpoint)
83 return Read('H', hashCheckpoint);
86 bool CBlockTreeDB::WriteSyncCheckpoint(uint256 hashCheckpoint)
88 return Write('H', hashCheckpoint);
91 bool CBlockTreeDB::ReadCheckpointPubKey(string& strPubKey)
93 return Read('K', strPubKey);
96 bool CBlockTreeDB::WriteCheckpointPubKey(const string& strPubKey)
98 return Write('K', strPubKey);
101 bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
102 return Write(make_pair('f', nFile), info);
105 bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
106 return Read(make_pair('f', nFile), info);
109 bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
110 return Write('l', nFile);
113 bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
114 return Read('l', nFile);
117 bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
118 leveldb::Iterator *pcursor = db.NewIterator();
119 pcursor->SeekToFirst();
121 while (pcursor->Valid()) {
123 leveldb::Slice slKey = pcursor->key();
124 CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
127 if (chType == 'c' && !fRequestShutdown) {
128 leveldb::Slice slValue = pcursor->value();
129 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
134 if (!coins.IsPruned()) {
135 stats.nTransactions++;
136 BOOST_FOREACH(const CTxOut &out, coins.vout) {
138 stats.nTransactionOutputs++;
142 stats.nPrunedTransactions++;
144 stats.nSerializedSize += 32 + slValue.size();
147 } catch (std::exception &e) {
148 return error("%s() : deserialize error", __PRETTY_FUNCTION__);
152 stats.nHeight = GetBestBlock()->nHeight;
156 bool CBlockTreeDB::LoadBlockIndexGuts()
158 leveldb::Iterator *pcursor = NewIterator();
160 CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
161 ssKeySet << make_pair('b', uint256(0));
162 pcursor->Seek(ssKeySet.str());
164 // Load mapBlockIndex
165 while (pcursor->Valid()) {
167 leveldb::Slice slKey = pcursor->key();
168 CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
171 if (chType == 'b' && !fRequestShutdown) {
172 leveldb::Slice slValue = pcursor->value();
173 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
174 CDiskBlockIndex diskindex;
175 ssValue >> diskindex;
177 uint256 blockHash = diskindex.GetBlockHash();
179 // Construct block index object
180 CBlockIndex* pindexNew = InsertBlockIndex(blockHash);
181 pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
182 pindexNew->nHeight = diskindex.nHeight;
183 pindexNew->nFile = diskindex.nFile;
184 pindexNew->nDataPos = diskindex.nDataPos;
185 pindexNew->nUndoPos = diskindex.nUndoPos;
186 pindexNew->nMint = diskindex.nMint;
187 pindexNew->nMoneySupply = diskindex.nMoneySupply;
188 pindexNew->nFlags = diskindex.nFlags;
189 pindexNew->nStakeModifier = diskindex.nStakeModifier;
190 pindexNew->prevoutStake = diskindex.prevoutStake;
191 pindexNew->nStakeTime = diskindex.nStakeTime;
192 pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
193 pindexNew->nVersion = diskindex.nVersion;
194 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
195 pindexNew->nTime = diskindex.nTime;
196 pindexNew->nBits = diskindex.nBits;
197 pindexNew->nNonce = diskindex.nNonce;
198 pindexNew->nStatus = diskindex.nStatus;
199 pindexNew->nTx = diskindex.nTx;
201 // Watch for genesis block
202 if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
203 pindexGenesisBlock = pindexNew;
205 if (!pindexNew->CheckIndex())
206 return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
208 // Build setStakeSeen
209 if (pindexNew->IsProofOfStake())
210 setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
214 break; // if shutdown requested or finished loading block index
216 } catch (std::exception &e) {
217 return error("%s() : deserialize error", __PRETTY_FUNCTION__);