Add Google's LevelDB support
[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;
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 void MakeMockTXDB() {
37     leveldb::Options options = GetOptions();
38     options.create_if_missing = true;
39     // This will leak but don't care here.
40     options.env = leveldb::NewMemEnv(leveldb::Env::Default());
41     leveldb::Status status = leveldb::DB::Open(options, "txdb", &txdb);
42     if (!status.ok()) 
43         throw runtime_error(strprintf("Could not create mock LevelDB: %s", status.ToString().c_str()));
44     CTxDB txdb("w");
45     txdb.WriteVersion(CLIENT_VERSION);
46 }
47
48 // NOTE: CDB subclasses are created and destroyed VERY OFTEN. Therefore we have
49 // to keep databases in global variables to avoid constantly creating and
50 // destroying them, which sucks. In future the code should be changed to not
51 // treat the instantiation of a database as a free operation.
52 CTxDB::CTxDB(const char* pszMode)
53 {
54     assert(pszMode);
55     pdb = txdb;
56     activeBatch = NULL;
57     fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
58
59     if (txdb)
60         return;
61
62     // First time init.
63     filesystem::path directory = GetDataDir() / "txleveldb";
64     bool fCreate = strchr(pszMode, 'c');
65
66     options = GetOptions();
67     options.create_if_missing = fCreate;
68     options.filter_policy = leveldb::NewBloomFilterPolicy(10);
69     filesystem::create_directory(directory);
70     printf("Opening LevelDB in %s\n", directory.string().c_str());
71     leveldb::Status status = leveldb::DB::Open(options, directory.string(), &txdb);
72     if (!status.ok()) {
73         throw runtime_error(strprintf("CDB(): error opening database environment %s", status.ToString().c_str()));
74     }
75     pdb = txdb;
76
77     if (fCreate && !Exists(string("version")))
78     {
79         bool fTmp = fReadOnly;
80         fReadOnly = false;
81         WriteVersion(CLIENT_VERSION);
82         fReadOnly = fTmp;
83     }
84     printf("Opened LevelDB sucessfully\n");
85 }
86
87 void CTxDB::Close()
88 {
89     delete txdb;
90     txdb = pdb = NULL;
91     delete options.filter_policy;
92     options.filter_policy = NULL;
93     delete options.block_cache;
94     options.block_cache = NULL;
95     delete activeBatch;
96     activeBatch = NULL;
97 }
98
99 bool CTxDB::TxnBegin()
100 {
101     assert(!activeBatch);
102     activeBatch = new leveldb::WriteBatch();
103     return true;
104 }
105
106 bool CTxDB::TxnCommit()
107 {
108     assert(activeBatch);
109     leveldb::Status status = pdb->Write(leveldb::WriteOptions(), activeBatch);
110     delete activeBatch;
111     activeBatch = NULL;
112     if (!status.ok()) {
113         printf("LevelDB batch commit failure: %s\n", status.ToString().c_str());
114         return false;
115     }
116     return true;
117 }
118
119 class CBatchScanner : public leveldb::WriteBatch::Handler {
120 public:
121     std::string needle;
122     bool *deleted;
123     std::string *foundValue;
124     bool foundEntry;
125
126     CBatchScanner() : foundEntry(false) {}
127
128     virtual void Put(const leveldb::Slice& key, const leveldb::Slice& value) {
129         if (key.ToString() == needle) {
130             foundEntry = true;
131             *deleted = false;
132             *foundValue = value.ToString();
133         }
134     }
135
136     virtual void Delete(const leveldb::Slice& key) {
137         if (key.ToString() == needle) {
138             foundEntry = true;
139             *deleted = true;
140         }
141     }
142 };
143
144 // When performing a read, if we have an active batch we need to check it first
145 // before reading from the database, as the rest of the code assumes that once
146 // a database transaction begins reads are consistent with it. It would be good
147 // to change that assumption in future and avoid the performance hit, though in
148 // practice it does not appear to be large.
149 bool CTxDB::ScanBatch(const CDataStream &key, string *value, bool *deleted) const {
150     assert(activeBatch);
151     *deleted = false;
152     CBatchScanner scanner;
153     scanner.needle = key.str();
154     scanner.deleted = deleted;
155     scanner.foundValue = value;
156     leveldb::Status status = activeBatch->Iterate(&scanner);
157     if (!status.ok()) {
158         throw runtime_error(status.ToString());
159     }
160     return scanner.foundEntry;
161 }
162
163 bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex)
164 {
165     assert(!fClient);
166     txindex.SetNull();
167     return Read(make_pair(string("tx"), hash), txindex);
168 }
169
170 bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
171 {
172     assert(!fClient);
173     return Write(make_pair(string("tx"), hash), txindex);
174 }
175
176 bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
177 {
178     assert(!fClient);
179
180     // Add to tx index
181     uint256 hash = tx.GetHash();
182     CTxIndex txindex(pos, tx.vout.size());
183     return Write(make_pair(string("tx"), hash), txindex);
184 }
185
186 bool CTxDB::EraseTxIndex(const CTransaction& tx)
187 {
188     assert(!fClient);
189     uint256 hash = tx.GetHash();
190
191     return Erase(make_pair(string("tx"), hash));
192 }
193
194 bool CTxDB::ContainsTx(uint256 hash)
195 {
196     assert(!fClient);
197     return Exists(make_pair(string("tx"), hash));
198 }
199
200 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
201 {
202     assert(!fClient);
203     tx.SetNull();
204     if (!ReadTxIndex(hash, txindex))
205         return false;
206     return (tx.ReadFromDisk(txindex.pos));
207 }
208
209 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx)
210 {
211     CTxIndex txindex;
212     return ReadDiskTx(hash, tx, txindex);
213 }
214
215 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex)
216 {
217     return ReadDiskTx(outpoint.hash, tx, txindex);
218 }
219
220 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx)
221 {
222     CTxIndex txindex;
223     return ReadDiskTx(outpoint.hash, tx, txindex);
224 }
225
226 bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
227 {
228     return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex);
229 }
230
231 bool CTxDB::ReadHashBestChain(uint256& hashBestChain)
232 {
233     return Read(string("hashBestChain"), hashBestChain);
234 }
235
236 bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
237 {
238     return Write(string("hashBestChain"), hashBestChain);
239 }
240
241 bool CTxDB::ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust)
242 {
243     return Read(string("bnBestInvalidTrust"), bnBestInvalidTrust);
244 }
245
246 bool CTxDB::WriteBestInvalidTrust(CBigNum bnBestInvalidTrust)
247 {
248     return Write(string("bnBestInvalidTrust"), bnBestInvalidTrust);
249 }
250
251 bool CTxDB::ReadSyncCheckpoint(uint256& hashCheckpoint)
252 {
253     return Read(string("hashSyncCheckpoint"), hashCheckpoint);
254 }
255
256 bool CTxDB::WriteSyncCheckpoint(uint256 hashCheckpoint)
257 {
258     return Write(string("hashSyncCheckpoint"), hashCheckpoint);
259 }
260
261 bool CTxDB::ReadCheckpointPubKey(string& strPubKey)
262 {
263     return Read(string("strCheckpointPubKey"), strPubKey);
264 }
265
266 bool CTxDB::WriteCheckpointPubKey(const string& strPubKey)
267 {
268     return Write(string("strCheckpointPubKey"), strPubKey);
269 }
270
271 static CBlockIndex *InsertBlockIndex(uint256 hash)
272 {
273     if (hash == 0)
274         return NULL;
275
276     // Return existing
277     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
278     if (mi != mapBlockIndex.end())
279         return (*mi).second;
280
281     // Create new
282     CBlockIndex* pindexNew = new CBlockIndex();
283     if (!pindexNew)
284         throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
285     mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
286     pindexNew->phashBlock = &((*mi).first);
287
288     return pindexNew;
289 }
290
291 bool CTxDB::LoadBlockIndex()
292 {
293     if (mapBlockIndex.size() > 0) {
294         // Already loaded once in this session. It can happen during migration
295         // from BDB.
296         return true;
297     }
298     // The block index is an in-memory structure that maps hashes to on-disk
299     // locations where the contents of the block can be found. Here, we scan it
300     // out of the DB and into mapBlockIndex.
301     leveldb::Iterator *iterator = pdb->NewIterator(leveldb::ReadOptions());
302     // Seek to start key.
303     CDataStream ssStartKey(SER_DISK, CLIENT_VERSION);
304     ssStartKey << make_pair(string("blockindex"), uint256(0));
305     iterator->Seek(ssStartKey.str());
306     // Now read each entry.
307     while (iterator->Valid())
308     {
309         // Unpack keys and values.
310         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
311         ssKey.write(iterator->key().data(), iterator->key().size());
312         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
313         ssValue.write(iterator->value().data(), iterator->value().size());
314         string strType;
315         ssKey >> strType;
316         // Did we reach the end of the data to read?
317         if (fRequestShutdown || strType != "blockindex")
318             break;
319         CDiskBlockIndex diskindex;
320         ssValue >> diskindex;
321
322         // Construct block index object
323         CBlockIndex* pindexNew    = InsertBlockIndex(diskindex.GetBlockHash());
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 && diskindex.GetBlockHash() == hashGenesisBlock)
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     BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& 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     BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& 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"PRI64x, 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 = GetArg("-checklevel", 1);
410     int nCheckDepth = GetArg( "-checkblocks", 2500);
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             pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos);
436             mapBlockPos[pos] = pindex;
437             BOOST_FOREACH(const CTransaction &tx, block.vtx)
438             {
439                 uint256 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                         BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent)
465                         {
466                             if (!txpos.IsNull())
467                             {
468                                 pair<unsigned int, unsigned int> 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                                         BOOST_FOREACH(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                      BOOST_FOREACH(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 }
536
537 extern bool fDisableSignatureChecking;
538
539 static uint64 nTotalBytes;
540 static uint64 nTotalBytesCompleted;
541 static double nProgressPercent;
542 static LevelDBMigrationProgress *callbackTotalOperationProgress;
543
544 void MigrationProgress(unsigned int bytesRead) {
545     // Called from inside LoadExternalBlockFile with how many bytes were
546     // processed so far.
547     nTotalBytesCompleted += bytesRead;
548     double newProgressPercent = 100.0 * ((double)nTotalBytesCompleted / (double)nTotalBytes);
549     // Throttle UI notifications.
550     if (newProgressPercent - nProgressPercent < 0.01)
551         return;
552     nProgressPercent = newProgressPercent;
553     printf("LevelDB migration %0.2f%% complete.\n", nProgressPercent);
554     (*callbackTotalOperationProgress)(nProgressPercent);
555 }
556
557 LevelDBMigrationResult MaybeMigrateToLevelDB(LevelDBMigrationProgress &progress) {
558     // Check if we have a blkindex.dat: if so, delete it. Because leveldb is
559     // more efficient (space-wise) than bdb, this should ensure we have enough
560     // disk space to perform the migration. We delete before migrate because if
561     // we got here, the code to handle the BDB based block index is not compiled
562     // in anymore, so there's no point in keeping the old file around - it's
563     // onwards and upwards.
564     //
565     // The act of replaying would normally append data to the blk data files,
566     // but we're reading from them so we don't want that. We disable it here,
567     // along with the signature checking as it doesn't help us right now. Note
568     // that replaying the chain could b0rk the wallet, but this process takes
569     // place before any wallets are registered.
570     //
571     // TODO(hearn): Assert on lack of a wallet here.
572
573     int64 nStart = GetTimeMillis();
574
575     boost::filesystem::path oldIndex = GetDataDir() / "blkindex.dat";
576     if (!boost::filesystem::exists(oldIndex)) {
577         return NONE_NEEDED;
578     }
579
580     // Check we have enough disk space for migration. We need at least 2GB free
581     // to hold the blk file we are migrating, and leveldb may have transient
582     // storage spikes, so we ask for at least 3GB.
583     uint64 nFreeBytesAvailable = filesystem::space(GetDataDir()).available;
584     if (nFreeBytesAvailable < 3UL * 1024UL * 1024UL * 1024UL) {
585         return INSUFFICIENT_DISK_SPACE;
586     }
587
588     printf("Deleting old blkindex.dat to make space for leveldb import.\n");
589     boost::filesystem::remove(oldIndex);
590     FILE *file;
591     int nFile = 1;
592     // Firstly, figure out the total number of bytes we need to migrate, for
593     // the progress indicator.
594     nTotalBytes = 0;
595     while (true)
596     {
597         std::string filename = strprintf("blk%04d.dat", nFile);
598         boost::filesystem::path blkpath = GetDataDir() / filename;
599         if (!boost::filesystem::exists(blkpath))
600             break;
601         uintmax_t nFileSize = boost::filesystem::file_size(blkpath);
602         if (nFileSize == static_cast<uintmax_t>(-1))   // Some other error.
603             break;
604         nTotalBytes += nFileSize;
605         nFile++;
606     }
607     nFile = 1;
608
609     // Set up progress calculations and callbacks.
610     callbackTotalOperationProgress = &progress;
611     ExternalBlockFileProgress callbackProgress;
612     callbackProgress.connect(MigrationProgress);
613     (*callbackTotalOperationProgress)(0.0);
614
615     // We don't need to re-run scripts during migration as they were run already
616     // and this saves a lot of time.
617     fDisableSignatureChecking = true;
618     // There may be multiple blk0000?.dat files, iterate over each one, rename
619     // it and then reimport it. For the first one, we need to initialize the
620     // fresh file with the genesis block.
621     while (true)
622     {
623         std::string filename = strprintf("blk%04d.dat", nFile);
624         std::string tmpname = strprintf("tmp-blk%04d.dat", nFile);
625         boost::filesystem::path blkpath = GetDataDir() / filename;
626         if (!boost::filesystem::exists(blkpath)) {
627             // No more work to do.
628             break;
629         }
630         boost::filesystem::path tmppath = GetDataDir() / tmpname;
631         boost::filesystem::rename(blkpath, tmppath);
632         printf("Migrating blk%04d.dat to leveldb\n", nFile);
633         file = fopen(tmppath.string().c_str(), "rb");
634         if (nFile == 1) {
635             // This will create a fresh blk0001.dat ready for usage.
636             LoadBlockIndex();
637         }
638         // LoadExternalBlockFile will close the given input file itself.
639         // It reads each block from the storage files and calls ProcessBlock
640         // on each one, which will go back and add to the database.
641         if (!LoadExternalBlockFile(file, &callbackProgress)) {
642             // We can't really clean up elegantly here.
643             fDisableSignatureChecking = false;
644             return OTHER_ERROR;
645         }
646         boost::filesystem::remove(tmppath);
647         nFile++;
648     }
649     fDisableSignatureChecking = false;
650     printf("LevelDB migration took %fs\n", (GetTimeMillis() - nStart) / 1000.0);
651     return COMPLETED;
652 }