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::ReadModifierUpgradeTime(unsigned int& nUpgradeTime)
103 return Read('M', nUpgradeTime);
106 bool CBlockTreeDB::WriteModifierUpgradeTime(const unsigned int& nUpgradeTime)
108 return Write('M', nUpgradeTime);
111 bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
112 return Write(make_pair('f', nFile), info);
115 bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
116 return Read(make_pair('f', nFile), info);
119 bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
120 return Write('l', nFile);
123 bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
124 return Read('l', nFile);
127 bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
128 leveldb::Iterator *pcursor = db.NewIterator();
129 pcursor->SeekToFirst();
131 while (pcursor->Valid()) {
133 leveldb::Slice slKey = pcursor->key();
134 CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
137 if (chType == 'c' && !fRequestShutdown) {
138 leveldb::Slice slValue = pcursor->value();
139 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
144 if (!coins.IsPruned()) {
145 stats.nTransactions++;
146 BOOST_FOREACH(const CTxOut &out, coins.vout) {
148 stats.nTransactionOutputs++;
152 stats.nPrunedTransactions++;
154 stats.nSerializedSize += 32 + slValue.size();
157 } catch (std::exception &e) {
158 return error("%s() : deserialize error", __PRETTY_FUNCTION__);
162 stats.nHeight = GetBestBlock()->nHeight;
166 bool CBlockTreeDB::LoadBlockIndexGuts()
168 leveldb::Iterator *pcursor = NewIterator();
170 CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
171 ssKeySet << make_pair('b', uint256(0));
172 pcursor->Seek(ssKeySet.str());
174 // Load mapBlockIndex
175 while (pcursor->Valid()) {
177 leveldb::Slice slKey = pcursor->key();
178 CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
181 if (chType == 'b' && !fRequestShutdown) {
182 leveldb::Slice slValue = pcursor->value();
183 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
184 CDiskBlockIndex diskindex;
185 ssValue >> diskindex;
187 uint256 blockHash = diskindex.GetBlockHash();
189 // Construct block index object
190 CBlockIndex* pindexNew = InsertBlockIndex(blockHash);
191 pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
192 pindexNew->nHeight = diskindex.nHeight;
193 pindexNew->nFile = diskindex.nFile;
194 pindexNew->nDataPos = diskindex.nDataPos;
195 pindexNew->nUndoPos = diskindex.nUndoPos;
196 pindexNew->nMint = diskindex.nMint;
197 pindexNew->nMoneySupply = diskindex.nMoneySupply;
198 pindexNew->nFlags = diskindex.nFlags;
199 pindexNew->nStakeModifier = diskindex.nStakeModifier;
200 pindexNew->prevoutStake = diskindex.prevoutStake;
201 pindexNew->nStakeTime = diskindex.nStakeTime;
202 pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
203 pindexNew->nVersion = diskindex.nVersion;
204 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
205 pindexNew->nTime = diskindex.nTime;
206 pindexNew->nBits = diskindex.nBits;
207 pindexNew->nNonce = diskindex.nNonce;
208 pindexNew->nStatus = diskindex.nStatus;
209 pindexNew->nTx = diskindex.nTx;
211 // Watch for genesis block
212 if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
213 pindexGenesisBlock = pindexNew;
215 if (!pindexNew->CheckIndex())
216 return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
218 // Build setStakeSeen
219 if (pindexNew->IsProofOfStake())
220 setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
224 break; // if shutdown requested or finished loading block index
226 } catch (std::exception &e) {
227 return error("%s() : deserialize error", __PRETTY_FUNCTION__);