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