[tests] reorganize utils.py module (code move only)
[bitcoinplatinum.git] / src / txdb.cpp
blobd24162ba2dc6d5c49f8dacf131af12127d22cd7c
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2016 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 #include "txdb.h"
8 #include "chainparams.h"
9 #include "hash.h"
10 #include "random.h"
11 #include "pow.h"
12 #include "uint256.h"
13 #include "util.h"
15 #include <stdint.h>
17 #include <boost/thread.hpp>
19 static const char DB_COIN = 'C';
20 static const char DB_COINS = 'c';
21 static const char DB_BLOCK_FILES = 'f';
22 static const char DB_TXINDEX = 't';
23 static const char DB_BLOCK_INDEX = 'b';
25 static const char DB_BEST_BLOCK = 'B';
26 static const char DB_HEAD_BLOCKS = 'H';
27 static const char DB_FLAG = 'F';
28 static const char DB_REINDEX_FLAG = 'R';
29 static const char DB_LAST_BLOCK = 'l';
31 namespace {
33 struct CoinEntry {
34 COutPoint* outpoint;
35 char key;
36 CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
38 template<typename Stream>
39 void Serialize(Stream &s) const {
40 s << key;
41 s << outpoint->hash;
42 s << VARINT(outpoint->n);
45 template<typename Stream>
46 void Unserialize(Stream& s) {
47 s >> key;
48 s >> outpoint->hash;
49 s >> VARINT(outpoint->n);
55 CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe, true)
59 bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const {
60 return db.Read(CoinEntry(&outpoint), coin);
63 bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
64 return db.Exists(CoinEntry(&outpoint));
67 uint256 CCoinsViewDB::GetBestBlock() const {
68 uint256 hashBestChain;
69 if (!db.Read(DB_BEST_BLOCK, hashBestChain))
70 return uint256();
71 return hashBestChain;
74 std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
75 std::vector<uint256> vhashHeadBlocks;
76 if (!db.Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
77 return std::vector<uint256>();
79 return vhashHeadBlocks;
82 bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
83 CDBBatch batch(db);
84 size_t count = 0;
85 size_t changed = 0;
86 size_t batch_size = (size_t)GetArg("-dbbatchsize", nDefaultDbBatchSize);
87 int crash_simulate = GetArg("-dbcrashratio", 0);
88 assert(!hashBlock.IsNull());
90 uint256 old_tip = GetBestBlock();
91 if (old_tip.IsNull()) {
92 // We may be in the middle of replaying.
93 std::vector<uint256> old_heads = GetHeadBlocks();
94 if (old_heads.size() == 2) {
95 assert(old_heads[0] == hashBlock);
96 old_tip = old_heads[1];
100 // In the first batch, mark the database as being in the middle of a
101 // transition from old_tip to hashBlock.
102 // A vector is used for future extensibility, as we may want to support
103 // interrupting after partial writes from multiple independent reorgs.
104 batch.Erase(DB_BEST_BLOCK);
105 batch.Write(DB_HEAD_BLOCKS, std::vector<uint256>{hashBlock, old_tip});
107 for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
108 if (it->second.flags & CCoinsCacheEntry::DIRTY) {
109 CoinEntry entry(&it->first);
110 if (it->second.coin.IsSpent())
111 batch.Erase(entry);
112 else
113 batch.Write(entry, it->second.coin);
114 changed++;
116 count++;
117 CCoinsMap::iterator itOld = it++;
118 mapCoins.erase(itOld);
119 if (batch.SizeEstimate() > batch_size) {
120 LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
121 db.WriteBatch(batch);
122 batch.Clear();
123 if (crash_simulate) {
124 static FastRandomContext rng;
125 if (rng.randrange(crash_simulate) == 0) {
126 LogPrintf("Simulating a crash. Goodbye.\n");
127 _Exit(0);
133 // In the last batch, mark the database as consistent with hashBlock again.
134 batch.Erase(DB_HEAD_BLOCKS);
135 batch.Write(DB_BEST_BLOCK, hashBlock);
137 LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
138 bool ret = db.WriteBatch(batch);
139 LogPrint(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
140 return ret;
143 size_t CCoinsViewDB::EstimateSize() const
145 return db.EstimateSize(DB_COIN, (char)(DB_COIN+1));
148 CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
151 bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
152 return Read(std::make_pair(DB_BLOCK_FILES, nFile), info);
155 bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
156 if (fReindexing)
157 return Write(DB_REINDEX_FLAG, '1');
158 else
159 return Erase(DB_REINDEX_FLAG);
162 bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
163 fReindexing = Exists(DB_REINDEX_FLAG);
164 return true;
167 bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
168 return Read(DB_LAST_BLOCK, nFile);
171 CCoinsViewCursor *CCoinsViewDB::Cursor() const
173 CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper*>(&db)->NewIterator(), GetBestBlock());
174 /* It seems that there are no "const iterators" for LevelDB. Since we
175 only need read operations on it, use a const-cast to get around
176 that restriction. */
177 i->pcursor->Seek(DB_COIN);
178 // Cache key of first record
179 if (i->pcursor->Valid()) {
180 CoinEntry entry(&i->keyTmp.second);
181 i->pcursor->GetKey(entry);
182 i->keyTmp.first = entry.key;
183 } else {
184 i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false
186 return i;
189 bool CCoinsViewDBCursor::GetKey(COutPoint &key) const
191 // Return cached key
192 if (keyTmp.first == DB_COIN) {
193 key = keyTmp.second;
194 return true;
196 return false;
199 bool CCoinsViewDBCursor::GetValue(Coin &coin) const
201 return pcursor->GetValue(coin);
204 unsigned int CCoinsViewDBCursor::GetValueSize() const
206 return pcursor->GetValueSize();
209 bool CCoinsViewDBCursor::Valid() const
211 return keyTmp.first == DB_COIN;
214 void CCoinsViewDBCursor::Next()
216 pcursor->Next();
217 CoinEntry entry(&keyTmp.second);
218 if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
219 keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
220 } else {
221 keyTmp.first = entry.key;
225 bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
226 CDBBatch batch(*this);
227 for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) {
228 batch.Write(std::make_pair(DB_BLOCK_FILES, it->first), *it->second);
230 batch.Write(DB_LAST_BLOCK, nLastFile);
231 for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) {
232 batch.Write(std::make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it));
234 return WriteBatch(batch, true);
237 bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
238 return Read(std::make_pair(DB_TXINDEX, txid), pos);
241 bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
242 CDBBatch batch(*this);
243 for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
244 batch.Write(std::make_pair(DB_TXINDEX, it->first), it->second);
245 return WriteBatch(batch);
248 bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
249 return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
252 bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
253 char ch;
254 if (!Read(std::make_pair(DB_FLAG, name), ch))
255 return false;
256 fValue = ch == '1';
257 return true;
260 bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex)
262 std::unique_ptr<CDBIterator> pcursor(NewIterator());
264 pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));
266 // Load mapBlockIndex
267 while (pcursor->Valid()) {
268 boost::this_thread::interruption_point();
269 std::pair<char, uint256> key;
270 if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {
271 CDiskBlockIndex diskindex;
272 if (pcursor->GetValue(diskindex)) {
273 // Construct block index object
274 CBlockIndex* pindexNew = insertBlockIndex(diskindex.GetBlockHash());
275 pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
276 pindexNew->nHeight = diskindex.nHeight;
277 pindexNew->nFile = diskindex.nFile;
278 pindexNew->nDataPos = diskindex.nDataPos;
279 pindexNew->nUndoPos = diskindex.nUndoPos;
280 pindexNew->nVersion = diskindex.nVersion;
281 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
282 pindexNew->nTime = diskindex.nTime;
283 pindexNew->nBits = diskindex.nBits;
284 pindexNew->nNonce = diskindex.nNonce;
285 pindexNew->nStatus = diskindex.nStatus;
286 pindexNew->nTx = diskindex.nTx;
288 if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams))
289 return error("%s: CheckProofOfWork failed: %s", __func__, pindexNew->ToString());
291 pcursor->Next();
292 } else {
293 return error("%s: failed to read value", __func__);
295 } else {
296 break;
300 return true;
303 namespace {
305 //! Legacy class to deserialize pre-pertxout database entries without reindex.
306 class CCoins
308 public:
309 //! whether transaction is a coinbase
310 bool fCoinBase;
312 //! unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped
313 std::vector<CTxOut> vout;
315 //! at which height this transaction was included in the active block chain
316 int nHeight;
318 //! empty constructor
319 CCoins() : fCoinBase(false), vout(0), nHeight(0) { }
321 template<typename Stream>
322 void Unserialize(Stream &s) {
323 unsigned int nCode = 0;
324 // version
325 int nVersionDummy;
326 ::Unserialize(s, VARINT(nVersionDummy));
327 // header code
328 ::Unserialize(s, VARINT(nCode));
329 fCoinBase = nCode & 1;
330 std::vector<bool> vAvail(2, false);
331 vAvail[0] = (nCode & 2) != 0;
332 vAvail[1] = (nCode & 4) != 0;
333 unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
334 // spentness bitmask
335 while (nMaskCode > 0) {
336 unsigned char chAvail = 0;
337 ::Unserialize(s, chAvail);
338 for (unsigned int p = 0; p < 8; p++) {
339 bool f = (chAvail & (1 << p)) != 0;
340 vAvail.push_back(f);
342 if (chAvail != 0)
343 nMaskCode--;
345 // txouts themself
346 vout.assign(vAvail.size(), CTxOut());
347 for (unsigned int i = 0; i < vAvail.size(); i++) {
348 if (vAvail[i])
349 ::Unserialize(s, REF(CTxOutCompressor(vout[i])));
351 // coinbase height
352 ::Unserialize(s, VARINT(nHeight));
358 /** Upgrade the database from older formats.
360 * Currently implemented: from the per-tx utxo model (0.8..0.14.x) to per-txout.
362 bool CCoinsViewDB::Upgrade() {
363 std::unique_ptr<CDBIterator> pcursor(db.NewIterator());
364 pcursor->Seek(std::make_pair(DB_COINS, uint256()));
365 if (!pcursor->Valid()) {
366 return true;
369 LogPrintf("Upgrading database...\n");
370 size_t batch_size = 1 << 24;
371 CDBBatch batch(db);
372 while (pcursor->Valid()) {
373 boost::this_thread::interruption_point();
374 std::pair<unsigned char, uint256> key;
375 if (pcursor->GetKey(key) && key.first == DB_COINS) {
376 CCoins old_coins;
377 if (!pcursor->GetValue(old_coins)) {
378 return error("%s: cannot parse CCoins record", __func__);
380 COutPoint outpoint(key.second, 0);
381 for (size_t i = 0; i < old_coins.vout.size(); ++i) {
382 if (!old_coins.vout[i].IsNull() && !old_coins.vout[i].scriptPubKey.IsUnspendable()) {
383 Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase);
384 outpoint.n = i;
385 CoinEntry entry(&outpoint);
386 batch.Write(entry, newcoin);
389 batch.Erase(key);
390 if (batch.SizeEstimate() > batch_size) {
391 db.WriteBatch(batch);
392 batch.Clear();
394 pcursor->Next();
395 } else {
396 break;
399 db.WriteBatch(batch);
400 return true;