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