@@ -244,7 +244,7 @@ CDB::CDB(const char *pszFile, const char* pszMode) :
244244
245245 ret = pdb->open (NULL , // Txn pointer
246246 fMockDb ? NULL : pszFile, // Filename
247- " main" , // Logical db name
247+ fMockDb ? pszFile : " main" , // Logical db name
248248 DB_BTREE, // Database type
249249 nFlags, // Flags
250250 0 );
@@ -273,7 +273,7 @@ CDB::CDB(const char *pszFile, const char* pszMode) :
273273
274274static bool IsChainFile (std::string strFile)
275275{
276- if (strFile == " blkindex .dat" )
276+ if (strFile == " coins.dat " || strFile == " chain .dat" )
277277 return true ;
278278
279279 return false ;
@@ -475,111 +475,66 @@ void CDBEnv::Flush(bool fShutdown)
475475
476476
477477//
478- // CTxDB
478+ // CChainDB and CCoinsDB
479479//
480480
481- bool CTxDB::ReadTxIndex (uint256 hash, CTxIndex& txindex)
482- {
481+ bool CCoinsDB::HaveCoins (uint256 hash) {
483482 assert (!fClient );
484- txindex.SetNull ();
485- return Read (make_pair (string (" tx" ), hash), txindex);
483+ return Exists (make_pair (' c' , hash));
486484}
487485
488- bool CTxDB::UpdateTxIndex (uint256 hash, const CTxIndex& txindex)
489- {
486+ bool CCoinsDB::ReadCoins (uint256 hash, CCoins &coins) {
490487 assert (!fClient );
491- return Write (make_pair (string (" tx" ), hash), txindex);
492- }
493-
494- bool CTxDB::AddTxIndex (const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
495- {
496- assert (!fClient );
497-
498- // Add to tx index
499- uint256 hash = tx.GetHash ();
500- CTxIndex txindex (pos, tx.vout .size ());
501- return Write (make_pair (string (" tx" ), hash), txindex);
488+ return Read (make_pair (' c' , hash), coins);
502489}
503490
504- bool CTxDB::EraseTxIndex (const CTransaction& tx)
505- {
506- assert (!fClient );
507- uint256 hash = tx.GetHash ();
508-
509- return Erase (make_pair (string (" tx" ), hash));
510- }
511-
512- bool CTxDB::ContainsTx (uint256 hash)
513- {
491+ bool CCoinsDB::WriteCoins (uint256 hash, const CCoins &coins) {
514492 assert (!fClient );
515- return Exists (make_pair (string (" tx" ), hash));
493+ if (coins.IsPruned ())
494+ return Erase (make_pair (' c' , hash));
495+ else
496+ return Write (make_pair (' c' , hash), coins);
516497}
517498
518- bool CTxDB::ReadDiskTx (uint256 hash, CTransaction& tx, CTxIndex& txindex )
499+ bool CChainDB::WriteBlockIndex ( const CDiskBlockIndex& blockindex )
519500{
520- assert (!fClient );
521- tx.SetNull ();
522- if (!ReadTxIndex (hash, txindex))
523- return false ;
524- return (tx.ReadFromDisk (txindex.pos ));
501+ return Write (make_pair (' b' , blockindex.GetBlockHash ()), blockindex);
525502}
526503
527- bool CTxDB::ReadDiskTx (uint256 hash, CTransaction& tx )
504+ bool CCoinsDB::ReadHashBestChain (uint256& hashBestChain )
528505{
529- CTxIndex txindex;
530- return ReadDiskTx (hash, tx, txindex);
506+ return Read (' B' , hashBestChain);
531507}
532508
533- bool CTxDB::ReadDiskTx (COutPoint outpoint, CTransaction& tx, CTxIndex& txindex )
509+ bool CCoinsDB::WriteHashBestChain (uint256 hashBestChain )
534510{
535- return ReadDiskTx (outpoint. hash , tx, txindex );
511+ return Write ( ' B ' , hashBestChain );
536512}
537513
538- bool CTxDB::ReadDiskTx (COutPoint outpoint, CTransaction& tx )
514+ bool CChainDB::ReadBestInvalidWork (CBigNum& bnBestInvalidWork )
539515{
540- CTxIndex txindex;
541- return ReadDiskTx (outpoint.hash , tx, txindex);
516+ return Read (' I' , bnBestInvalidWork);
542517}
543518
544- bool CTxDB::WriteBlockIndex ( const CDiskBlockIndex& blockindex )
519+ bool CChainDB::WriteBestInvalidWork (CBigNum bnBestInvalidWork )
545520{
546- return Write (make_pair ( string ( " blockindex " ), blockindex. GetBlockHash ()), blockindex );
521+ return Write (' I ' , bnBestInvalidWork );
547522}
548523
549- bool CTxDB ::WriteBlockFileInfo (int nFile, const CBlockFileInfo &info) {
550- return Write (make_pair (string ( " blockfile " ) , nFile), info);
524+ bool CChainDB ::WriteBlockFileInfo (int nFile, const CBlockFileInfo &info) {
525+ return Write (make_pair (' f ' , nFile), info);
551526}
552527
553- bool CTxDB ::ReadBlockFileInfo (int nFile, CBlockFileInfo &info) {
554- return Read (make_pair (string ( " blockfile " ) , nFile), info);
528+ bool CChainDB ::ReadBlockFileInfo (int nFile, CBlockFileInfo &info) {
529+ return Read (make_pair (' f ' , nFile), info);
555530}
556531
557- bool CTxDB ::WriteLastBlockFile (int nFile) {
558- return Write (string ( " lastblockfile " ) , nFile);
532+ bool CChainDB ::WriteLastBlockFile (int nFile) {
533+ return Write (' l ' , nFile);
559534}
560535
561- bool CTxDB::ReadLastBlockFile (int &nFile) {
562- return Read (string (" lastblockfile" ), nFile);
563- }
564-
565- bool CTxDB::ReadHashBestChain (uint256& hashBestChain)
566- {
567- return Read (string (" hashBestChain" ), hashBestChain);
568- }
569-
570- bool CTxDB::WriteHashBestChain (uint256 hashBestChain)
571- {
572- return Write (string (" hashBestChain" ), hashBestChain);
573- }
574-
575- bool CTxDB::ReadBestInvalidWork (CBigNum& bnBestInvalidWork)
576- {
577- return Read (string (" bnBestInvalidWork" ), bnBestInvalidWork);
578- }
579-
580- bool CTxDB::WriteBestInvalidWork (CBigNum bnBestInvalidWork)
581- {
582- return Write (string (" bnBestInvalidWork" ), bnBestInvalidWork);
536+ bool CChainDB::ReadLastBlockFile (int &nFile) {
537+ return Read (' l' , nFile);
583538}
584539
585540CBlockIndex static * InsertBlockIndex (uint256 hash)
@@ -602,9 +557,9 @@ CBlockIndex static * InsertBlockIndex(uint256 hash)
602557 return pindexNew;
603558}
604559
605- bool CTxDB:: LoadBlockIndex ()
560+ bool LoadBlockIndex (CCoinsDB &coindb, CChainDB &chaindb )
606561{
607- if (!LoadBlockIndexGuts ())
562+ if (!chaindb. LoadBlockIndexGuts ())
608563 return false ;
609564
610565 if (fRequestShutdown )
@@ -626,29 +581,39 @@ bool CTxDB::LoadBlockIndex()
626581 }
627582
628583 // Load block file info
629- ReadLastBlockFile (nLastBlockFile);
584+ chaindb. ReadLastBlockFile (nLastBlockFile);
630585 printf (" LoadBlockIndex(): last block file = %i\n " , nLastBlockFile);
631- if (ReadBlockFileInfo (nLastBlockFile, infoLastBlockFile))
586+ if (chaindb. ReadBlockFileInfo (nLastBlockFile, infoLastBlockFile))
632587 printf (" LoadBlockIndex(): last block file: %s\n " , infoLastBlockFile.ToString ().c_str ());
633588
634589 // Load hashBestChain pointer to end of best chain
635- if (!ReadHashBestChain (hashBestChain))
590+ if (!coindb. ReadHashBestChain (hashBestChain))
636591 {
637592 if (pindexGenesisBlock == NULL )
638593 return true ;
639594 return error (" CTxDB::LoadBlockIndex() : hashBestChain not loaded" );
640595 }
641- if (!mapBlockIndex.count (hashBestChain))
596+ std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find (hashBestChain);
597+ if (it == mapBlockIndex.end ()) {
642598 return error (" CTxDB::LoadBlockIndex() : hashBestChain not found in the block index" );
643- pindexBest = mapBlockIndex[hashBestChain];
644- nBestHeight = pindexBest->nHeight ;
645- bnBestChainWork = pindexBest->bnChainWork ;
646- printf (" LoadBlockIndex(): hashBestChain=%s height=%d date=%s\n " ,
647- hashBestChain.ToString ().substr (0 ,20 ).c_str (), nBestHeight,
648- DateTimeStrFormat (" %x %H:%M:%S" , pindexBest->GetBlockTime ()).c_str ());
599+ } else {
600+ // set 'next' pointers in best chain
601+ CBlockIndex *pindex = it->second ;
602+ while (pindex != NULL && pindex->pprev != NULL ) {
603+ CBlockIndex *pindexPrev = pindex->pprev ;
604+ pindexPrev->pnext = pindex;
605+ pindex = pindexPrev;
606+ }
607+ pindexBest = it->second ;
608+ nBestHeight = pindexBest->nHeight ;
609+ bnBestChainWork = pindexBest->bnChainWork ;
610+ }
611+ printf (" LoadBlockIndex(): hashBestChain=%s height=%d date=%s\n " ,
612+ hashBestChain.ToString ().substr (0 ,20 ).c_str (), nBestHeight,
613+ DateTimeStrFormat (" %x %H:%M:%S" , pindexBest->GetBlockTime ()).c_str ());
649614
650615 // Load bnBestInvalidWork, OK if it doesn't exist
651- ReadBestInvalidWork (bnBestInvalidWork);
616+ chaindb. ReadBestInvalidWork (bnBestInvalidWork);
652617
653618 // Verify blocks in the best chain
654619 int nCheckLevel = GetArg (" -checklevel" , 1 );
@@ -664,7 +629,6 @@ bool CTxDB::LoadBlockIndex()
664629 if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
665630 break ;
666631 CBlock block;
667- CDiskBlockPos blockPos = pindex->GetBlockPos ();
668632 if (!block.ReadFromDisk (pindex))
669633 return error (" LoadBlockIndex() : block.ReadFromDisk failed" );
670634 // check level 1: verify block validity
@@ -673,106 +637,20 @@ bool CTxDB::LoadBlockIndex()
673637 printf (" LoadBlockIndex() : *** found bad block at %d, hash=%s\n " , pindex->nHeight , pindex->GetBlockHash ().ToString ().c_str ());
674638 pindexFork = pindex->pprev ;
675639 }
676- // check level 2: verify transaction index validity
677- if (nCheckLevel>1 )
678- {
679- BOOST_FOREACH (const CTransaction &tx, block.vtx )
680- {
681- uint256 hashTx = tx.GetHash ();
682- CTxIndex txindex;
683- if (ReadTxIndex (hashTx, txindex))
684- {
685- // check level 3: checker transaction hashes
686- if (nCheckLevel>2 || blockPos != txindex.pos .blockPos )
687- {
688- // either an error or a duplicate transaction
689- CTransaction txFound;
690- if (!txFound.ReadFromDisk (txindex.pos ))
691- {
692- printf (" LoadBlockIndex() : *** cannot read mislocated transaction %s\n " , hashTx.ToString ().c_str ());
693- pindexFork = pindex->pprev ;
694- }
695- else
696- if (txFound.GetHash () != hashTx) // not a duplicate tx
697- {
698- printf (" LoadBlockIndex(): *** invalid tx position for %s\n " , hashTx.ToString ().c_str ());
699- pindexFork = pindex->pprev ;
700- }
701- }
702- // check level 4: check whether spent txouts were spent within the main chain
703- unsigned int nOutput = 0 ;
704- if (nCheckLevel>3 )
705- {
706- BOOST_FOREACH (const CDiskTxPos &txpos, txindex.vSpent )
707- {
708- if (!txpos.IsNull ())
709- {
710- // check level 6: check whether spent txouts were spent by a valid transaction that consume them
711- if (nCheckLevel>5 )
712- {
713- CTransaction txSpend;
714- if (!txSpend.ReadFromDisk (txpos))
715- {
716- printf (" LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n " , hashTx.ToString ().c_str (), nOutput);
717- pindexFork = pindex->pprev ;
718- }
719- else if (!txSpend.CheckTransaction ())
720- {
721- printf (" LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n " , hashTx.ToString ().c_str (), nOutput);
722- pindexFork = pindex->pprev ;
723- }
724- else
725- {
726- bool fFound = false ;
727- BOOST_FOREACH (const CTxIn &txin, txSpend.vin )
728- if (txin.prevout .hash == hashTx && txin.prevout .n == nOutput)
729- fFound = true ;
730- if (!fFound )
731- {
732- printf (" LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n " , hashTx.ToString ().c_str (), nOutput);
733- pindexFork = pindex->pprev ;
734- }
735- }
736- }
737- }
738- nOutput++;
739- }
740- }
741- }
742- // check level 5: check whether all prevouts are marked spent
743- if (nCheckLevel>4 )
744- {
745- BOOST_FOREACH (const CTxIn &txin, tx.vin )
746- {
747- CTxIndex txindex;
748- if (ReadTxIndex (txin.prevout .hash , txindex))
749- if (txindex.vSpent .size ()-1 < txin.prevout .n || txindex.vSpent [txin.prevout .n ].IsNull ())
750- {
751- printf (" LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n " , txin.prevout .hash .ToString ().c_str (), txin.prevout .n , hashTx.ToString ().c_str ());
752- pindexFork = pindex->pprev ;
753- }
754- }
755- }
756- }
757- }
640+ // TODO: stronger verifications
758641 }
759642 if (pindexFork && !fRequestShutdown )
760643 {
761- // Reorg back to the fork
762- printf (" LoadBlockIndex() : *** moving best chain pointer back to block %d\n " , pindexFork->nHeight );
763- CBlock block;
764- if (!block.ReadFromDisk (pindexFork))
765- return error (" LoadBlockIndex() : block.ReadFromDisk failed" );
766- CTxDB txdb;
767- block.SetBestChain (txdb, pindexFork);
644+ // TODO: reorg back
645+ return error (" LoadBlockIndex(): chain database corrupted" );
768646 }
769647
770648 return true ;
771649}
772650
773651
774652
775- bool CTxDB ::LoadBlockIndexGuts ()
653+ bool CChainDB ::LoadBlockIndexGuts ()
776654{
777655 // Get database cursor
778656 Dbc* pcursor = GetCursor ();
@@ -786,7 +664,7 @@ bool CTxDB::LoadBlockIndexGuts()
786664 // Read next record
787665 CDataStream ssKey (SER_DISK, CLIENT_VERSION);
788666 if (fFlags == DB_SET_RANGE)
789- ssKey << make_pair (string ( " blockindex " ) , uint256 (0 ));
667+ ssKey << make_pair (' b ' , uint256 (0 ));
790668 CDataStream ssValue (SER_DISK, CLIENT_VERSION);
791669 int ret = ReadAtCursor (pcursor, ssKey, ssValue, fFlags );
792670 fFlags = DB_NEXT;
@@ -798,17 +676,16 @@ bool CTxDB::LoadBlockIndexGuts()
798676 // Unserialize
799677
800678 try {
801- string strType ;
802- ssKey >> strType ;
803- if (strType == " blockindex " && !fRequestShutdown )
679+ char chType ;
680+ ssKey >> chType ;
681+ if (chType == ' b ' && !fRequestShutdown )
804682 {
805683 CDiskBlockIndex diskindex;
806684 ssValue >> diskindex;
807685
808686 // Construct block index object
809687 CBlockIndex* pindexNew = InsertBlockIndex (diskindex.GetBlockHash ());
810688 pindexNew->pprev = InsertBlockIndex (diskindex.hashPrev );
811- pindexNew->pnext = InsertBlockIndex (diskindex.hashNext );
812689 pindexNew->nHeight = diskindex.nHeight ;
813690 pindexNew->pos = diskindex.pos ;
814691 pindexNew->nUndoPos = diskindex.nUndoPos ;
0 commit comments