5ccf07d20c1a8fcb2d52407fdb0fba66412ecfca
[novacoin.git] / src / txdb-leveldb.cpp
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 license.txt or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "txdb-leveldb.h"
7 #include "kernel.h"
8 #include "checkpoints.h"
9
10 #include <boost/version.hpp>
11 #include <boost/filesystem.hpp>
12 #include <boost/filesystem/fstream.hpp>
13
14 #include <leveldb/env.h>
15 #include <leveldb/cache.h>
16 #include <leveldb/filter_policy.h>
17 #include <memenv/memenv.h>
18
19 using namespace std;
20
21 leveldb::DB *txdb; // global pointer for LevelDB object instance
22
23 static leveldb::Options GetOptions() {
24     leveldb::Options options;
25     int nCacheSizeMB = GetArgInt("-dbcache", 25);
26     options.block_cache = leveldb::NewLRUCache(nCacheSizeMB * 1048576);
27     options.filter_policy = leveldb::NewBloomFilterPolicy(10);
28     return options;
29 }
30
31 void init_blockindex(leveldb::Options& options, bool fRemoveOld = false) {
32     // First time init.
33     boost::filesystem::path directory = GetDataDir() / "txleveldb";
34
35     if (fRemoveOld) {
36         boost::filesystem::remove_all(directory); // remove directory
37         unsigned int nFile = 1;
38
39         for ( ; ; )
40         {
41             boost::filesystem::path strBlockFile = GetDataDir() / strprintf("blk%04u.dat", nFile);
42
43             // Break if no such file
44             if( !boost::filesystem::exists( strBlockFile ) )
45                 break;
46
47             boost::filesystem::remove(strBlockFile);
48
49             nFile++;
50         }
51     }
52
53     boost::filesystem::create_directory(directory);
54     printf("Opening LevelDB in %s\n", directory.string().c_str());
55     leveldb::Status status = leveldb::DB::Open(options, directory.string(), &txdb);
56     if (!status.ok()) {
57         throw runtime_error(strprintf("init_blockindex(): error opening database environment %s", status.ToString().c_str()));
58     }
59 }
60
61 // CDB subclasses are created and destroyed VERY OFTEN. That's why
62 // we shouldn't treat this as free operations.
63 CTxDB::CTxDB(const char* pszMode)
64 {
65     assert(pszMode);
66     activeBatch = NULL;
67     fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
68
69     if (txdb) {
70         pdb = txdb;
71         return;
72     }
73
74     bool fCreate = strchr(pszMode, 'c');
75
76     options = GetOptions();
77     options.create_if_missing = fCreate;
78     options.filter_policy = leveldb::NewBloomFilterPolicy(10);
79
80     init_blockindex(options); // Init directory
81     pdb = txdb;
82
83     if (Exists(string("version")))
84     {
85         ReadVersion(nVersion);
86         printf("Transaction index version is %d\n", nVersion);
87
88         if (nVersion < DATABASE_VERSION)
89         {
90             printf("Required index version is %d, removing old database\n", DATABASE_VERSION);
91
92             // Leveldb instance destruction
93             delete activeBatch;
94             activeBatch = NULL;
95             delete txdb;
96             txdb = pdb = NULL;
97
98             init_blockindex(options, true); // Remove directory and create new database
99             pdb = txdb;
100
101             bool fTmp = fReadOnly;
102             fReadOnly = false;
103             WriteVersion(DATABASE_VERSION); // Save transaction index version
104             fReadOnly = fTmp;
105         }
106     }
107     else if (fCreate)
108     {
109         bool fTmp = fReadOnly;
110         fReadOnly = false;
111         WriteVersion(DATABASE_VERSION);
112         fReadOnly = fTmp;
113     }
114
115     printf("Opened LevelDB successfully\n");
116 }
117
118 void CTxDB::Close()
119 {
120     delete txdb;
121     txdb = pdb = NULL;
122     delete options.filter_policy;
123     options.filter_policy = NULL;
124     delete options.block_cache;
125     options.block_cache = NULL;
126     delete activeBatch;
127     activeBatch = NULL;
128 }
129
130 bool CTxDB::TxnBegin()
131 {
132     assert(!activeBatch);
133     activeBatch = new leveldb::WriteBatch();
134     return true;
135 }
136
137 bool CTxDB::TxnCommit()
138 {
139     assert(activeBatch);
140     leveldb::Status status = pdb->Write(leveldb::WriteOptions(), activeBatch);
141     delete activeBatch;
142     activeBatch = NULL;
143     if (!status.ok()) {
144         printf("LevelDB batch commit failure: %s\n", status.ToString().c_str());
145         return false;
146     }
147     return true;
148 }
149
150 class CBatchScanner : public leveldb::WriteBatch::Handler {
151 public:
152     std::string needle;
153     bool *deleted;
154     std::string *foundValue;
155     bool foundEntry;
156
157     CBatchScanner() : foundEntry(false) {}
158
159     virtual void Put(const leveldb::Slice& key, const leveldb::Slice& value) {
160         if (key.ToString() == needle) {
161             foundEntry = true;
162             *deleted = false;
163             *foundValue = value.ToString();
164         }
165     }
166
167     virtual void Delete(const leveldb::Slice& key) {
168         if (key.ToString() == needle) {
169             foundEntry = true;
170             *deleted = true;
171         }
172     }
173 };
174
175 // When performing a read, if we have an active batch we need to check it first
176 // before reading from the database, as the rest of the code assumes that once
177 // a database transaction begins reads are consistent with it. It would be good
178 // to change that assumption in future and avoid the performance hit, though in
179 // practice it does not appear to be large.
180 bool CTxDB::ScanBatch(const CDataStream &key, string *value, bool *deleted) const {
181     assert(activeBatch);
182     *deleted = false;
183     CBatchScanner scanner;
184     scanner.needle = key.str();
185     scanner.deleted = deleted;
186     scanner.foundValue = value;
187     leveldb::Status status = activeBatch->Iterate(&scanner);
188     if (!status.ok()) {
189         throw runtime_error(status.ToString());
190     }
191     return scanner.foundEntry;
192 }
193
194 bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex)
195 {
196     assert(!fClient);
197     txindex.SetNull();
198     return Read(make_pair(string("tx"), hash), txindex);
199 }
200
201 bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
202 {
203     assert(!fClient);
204     return Write(make_pair(string("tx"), hash), txindex);
205 }
206
207 bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
208 {
209     assert(!fClient);
210
211     // Add to tx index
212     uint256 hash = tx.GetHash();
213     CTxIndex txindex(pos, tx.vout.size());
214     return Write(make_pair(string("tx"), hash), txindex);
215 }
216
217 bool CTxDB::EraseTxIndex(const CTransaction& tx)
218 {
219     assert(!fClient);
220     uint256 hash = tx.GetHash();
221
222     return Erase(make_pair(string("tx"), hash));
223 }
224
225 bool CTxDB::ContainsTx(uint256 hash)
226 {
227     assert(!fClient);
228     return Exists(make_pair(string("tx"), hash));
229 }
230
231 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
232 {
233     assert(!fClient);
234     tx.SetNull();
235     if (!ReadTxIndex(hash, txindex))
236         return false;
237     return (tx.ReadFromDisk(txindex.pos));
238 }
239
240 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx)
241 {
242     CTxIndex txindex;
243     return ReadDiskTx(hash, tx, txindex);
244 }
245
246 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex)
247 {
248     return ReadDiskTx(outpoint.hash, tx, txindex);
249 }
250
251 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx)
252 {
253     CTxIndex txindex;
254     return ReadDiskTx(outpoint.hash, tx, txindex);
255 }
256
257 bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
258 {
259     return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex);
260 }
261
262 bool CTxDB::ReadHashBestChain(uint256& hashBestChain)
263 {
264     return Read(string("hashBestChain"), hashBestChain);
265 }
266
267 bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
268 {
269     return Write(string("hashBestChain"), hashBestChain);
270 }
271
272 bool CTxDB::ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust)
273 {
274     return Read(string("bnBestInvalidTrust"), bnBestInvalidTrust);
275 }
276
277 bool CTxDB::WriteBestInvalidTrust(CBigNum bnBestInvalidTrust)
278 {
279     return Write(string("bnBestInvalidTrust"), bnBestInvalidTrust);
280 }
281
282 bool CTxDB::ReadSyncCheckpoint(uint256& hashCheckpoint)
283 {
284     return Read(string("hashSyncCheckpoint"), hashCheckpoint);
285 }
286
287 bool CTxDB::WriteSyncCheckpoint(uint256 hashCheckpoint)
288 {
289     return Write(string("hashSyncCheckpoint"), hashCheckpoint);
290 }
291
292 bool CTxDB::ReadCheckpointPubKey(string& strPubKey)
293 {
294     return Read(string("strCheckpointPubKey"), strPubKey);
295 }
296
297 bool CTxDB::WriteCheckpointPubKey(const string& strPubKey)
298 {
299     return Write(string("strCheckpointPubKey"), strPubKey);
300 }
301
302 bool CTxDB::ReadModifierUpgradeTime(unsigned int& nUpgradeTime)
303 {
304     return Read(string("nUpgradeTime"), nUpgradeTime);
305 }
306
307 bool CTxDB::WriteModifierUpgradeTime(const unsigned int& nUpgradeTime)
308 {
309     return Write(string("nUpgradeTime"), nUpgradeTime);
310 }
311
312 static CBlockIndex *InsertBlockIndex(uint256 hash)
313 {
314     if (hash == 0)
315         return NULL;
316
317     // Return existing
318     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
319     if (mi != mapBlockIndex.end())
320         return (*mi).second;
321
322     // Create new
323     CBlockIndex* pindexNew = new(nothrow) CBlockIndex();
324     if (!pindexNew)
325         throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
326     mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
327     pindexNew->phashBlock = &((*mi).first);
328
329     return pindexNew;
330 }
331
332 bool CTxDB::LoadBlockIndex()
333 {
334     if (mapBlockIndex.size() > 0) {
335         // Already loaded once in this session. It can happen during migration
336         // from BDB.
337         return true;
338     }
339     // The block index is an in-memory structure that maps hashes to on-disk
340     // locations where the contents of the block can be found. Here, we scan it
341     // out of the DB and into mapBlockIndex.
342     leveldb::Iterator *iterator = pdb->NewIterator(leveldb::ReadOptions());
343     // Seek to start key.
344     CDataStream ssStartKey(SER_DISK, CLIENT_VERSION);
345     ssStartKey << make_pair(string("blockindex"), uint256(0));
346     iterator->Seek(ssStartKey.str());
347     // Now read each entry.
348     while (iterator->Valid())
349     {
350         // Unpack keys and values.
351         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
352         ssKey.write(iterator->key().data(), iterator->key().size());
353         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
354         ssValue.write(iterator->value().data(), iterator->value().size());
355         string strType;
356         ssKey >> strType;
357         // Did we reach the end of the data to read?
358         if (fRequestShutdown || strType != "blockindex")
359             break;
360         CDiskBlockIndex diskindex;
361         ssValue >> diskindex;
362
363         uint256 blockHash = diskindex.GetBlockHash();
364
365         // Construct block index object
366         CBlockIndex* pindexNew    = InsertBlockIndex(blockHash);
367         pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
368         pindexNew->pnext          = InsertBlockIndex(diskindex.hashNext);
369         pindexNew->nFile          = diskindex.nFile;
370         pindexNew->nBlockPos      = diskindex.nBlockPos;
371         pindexNew->nHeight        = diskindex.nHeight;
372         pindexNew->nMint          = diskindex.nMint;
373         pindexNew->nMoneySupply   = diskindex.nMoneySupply;
374         pindexNew->nFlags         = diskindex.nFlags;
375         pindexNew->nStakeModifier = diskindex.nStakeModifier;
376         pindexNew->prevoutStake   = diskindex.prevoutStake;
377         pindexNew->nStakeTime     = diskindex.nStakeTime;
378         pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
379         pindexNew->nVersion       = diskindex.nVersion;
380         pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
381         pindexNew->nTime          = diskindex.nTime;
382         pindexNew->nBits          = diskindex.nBits;
383         pindexNew->nNonce         = diskindex.nNonce;
384
385         // Watch for genesis block
386         if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
387             pindexGenesisBlock = pindexNew;
388
389         if (!pindexNew->CheckIndex()) {
390             delete iterator;
391             return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
392         }
393
394         // NovaCoin: build setStakeSeen
395         if (pindexNew->IsProofOfStake())
396             setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
397
398         iterator->Next();
399     }
400     delete iterator;
401
402     if (fRequestShutdown)
403         return true;
404
405     // Calculate nChainTrust
406     vector<pair<int, CBlockIndex*> > vSortedByHeight;
407     vSortedByHeight.reserve(mapBlockIndex.size());
408     for (const auto& item : mapBlockIndex)
409     {
410         CBlockIndex* pindex = item.second;
411         vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
412     }
413     sort(vSortedByHeight.begin(), vSortedByHeight.end());
414     for (const auto& item : vSortedByHeight)
415     {
416         CBlockIndex* pindex = item.second;
417         pindex->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + pindex->GetBlockTrust();
418         // NovaCoin: calculate stake modifier checksum
419         pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex);
420         if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum))
421             return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016" PRIx64, pindex->nHeight, pindex->nStakeModifier);
422     }
423
424     // Load hashBestChain pointer to end of best chain
425     if (!ReadHashBestChain(hashBestChain))
426     {
427         if (pindexGenesisBlock == NULL)
428             return true;
429         return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
430     }
431     if (!mapBlockIndex.count(hashBestChain))
432         return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
433     pindexBest = mapBlockIndex[hashBestChain];
434     nBestHeight = pindexBest->nHeight;
435     nBestChainTrust = pindexBest->nChainTrust;
436
437     printf("LoadBlockIndex(): hashBestChain=%s  height=%d  trust=%s  date=%s\n",
438       hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str(),
439       DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
440
441     // NovaCoin: load hashSyncCheckpoint
442     if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint))
443         return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded");
444     printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str());
445
446     // Load bnBestInvalidTrust, OK if it doesn't exist
447     CBigNum bnBestInvalidTrust;
448     ReadBestInvalidTrust(bnBestInvalidTrust);
449     nBestInvalidTrust = bnBestInvalidTrust.getuint256();
450
451     // Verify blocks in the best chain
452     int nCheckLevel = GetArgInt("-checklevel", 1);
453     int nCheckDepth = GetArgInt( "-checkblocks", 2500);
454     if (nCheckDepth == 0)
455         nCheckDepth = 1000000000; // suffices until the year 19000
456     if (nCheckDepth > nBestHeight)
457         nCheckDepth = nBestHeight;
458     printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
459     CBlockIndex* pindexFork = NULL;
460     map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos;
461     for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
462     {
463         if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
464             break;
465         CBlock block;
466         if (!block.ReadFromDisk(pindex))
467             return error("LoadBlockIndex() : block.ReadFromDisk failed");
468         // check level 1: verify block validity
469         // check level 7: verify block signature too
470         if (nCheckLevel>0 && !block.CheckBlock(true, true, (nCheckLevel>6)))
471         {
472             printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
473             pindexFork = pindex->pprev;
474         }
475         // check level 2: verify transaction index validity
476         if (nCheckLevel>1)
477         {
478             pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos);
479             mapBlockPos[pos] = pindex;
480             for (const CTransaction &tx : block.vtx)
481             {
482                 uint256 hashTx = tx.GetHash();
483                 CTxIndex txindex;
484                 if (ReadTxIndex(hashTx, txindex))
485                 {
486                     // check level 3: checker transaction hashes
487                     if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos)
488                     {
489                         // either an error or a duplicate transaction
490                         CTransaction txFound;
491                         if (!txFound.ReadFromDisk(txindex.pos))
492                         {
493                             printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str());
494                             pindexFork = pindex->pprev;
495                         }
496                         else
497                             if (txFound.GetHash() != hashTx) // not a duplicate tx
498                             {
499                                 printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str());
500                                 pindexFork = pindex->pprev;
501                             }
502                     }
503                     // check level 4: check whether spent txouts were spent within the main chain
504                     unsigned int nOutput = 0;
505                     if (nCheckLevel>3)
506                     {
507                         for (const CDiskTxPos &txpos : txindex.vSpent)
508                         {
509                             if (!txpos.IsNull())
510                             {
511                                 pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos);
512                                 if (!mapBlockPos.count(posFind))
513                                 {
514                                     printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str());
515                                     pindexFork = pindex->pprev;
516                                 }
517                                 // check level 6: check whether spent txouts were spent by a valid transaction that consume them
518                                 if (nCheckLevel>5)
519                                 {
520                                     CTransaction txSpend;
521                                     if (!txSpend.ReadFromDisk(txpos))
522                                     {
523                                         printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput);
524                                         pindexFork = pindex->pprev;
525                                     }
526                                     else if (!txSpend.CheckTransaction())
527                                     {
528                                         printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput);
529                                         pindexFork = pindex->pprev;
530                                     }
531                                     else
532                                     {
533                                         bool fFound = false;
534                                         for (const CTxIn &txin : txSpend.vin)
535                                             if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput)
536                                                 fFound = true;
537                                         if (!fFound)
538                                         {
539                                             printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput);
540                                             pindexFork = pindex->pprev;
541                                         }
542                                     }
543                                 }
544                             }
545                             nOutput++;
546                         }
547                     }
548                 }
549                 // check level 5: check whether all prevouts are marked spent
550                 if (nCheckLevel>4)
551                 {
552                      for (const CTxIn &txin : tx.vin)
553                      {
554                           CTxIndex txindex;
555                           if (ReadTxIndex(txin.prevout.hash, txindex))
556                               if (txindex.vSpent.size()-1 < txin.prevout.n || txindex.vSpent[txin.prevout.n].IsNull())
557                               {
558                                   printf("LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n", txin.prevout.hash.ToString().c_str(), txin.prevout.n, hashTx.ToString().c_str());
559                                   pindexFork = pindex->pprev;
560                               }
561                      }
562                 }
563             }
564         }
565     }
566     if (pindexFork && !fRequestShutdown)
567     {
568         // Reorg back to the fork
569         printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
570         CBlock block;
571         if (!block.ReadFromDisk(pindexFork))
572             return error("LoadBlockIndex() : block.ReadFromDisk failed");
573         CTxDB txdb;
574         block.SetBestChain(txdb, pindexFork);
575     }
576
577     return true;
578 }