@@ -244,7 +244,7 @@ CDB::CDB(const char *pszFile, const char* pszMode) :
244
244
245
245
ret = pdb->open (NULL , // Txn pointer
246
246
fMockDb ? NULL : pszFile, // Filename
247
- " main" , // Logical db name
247
+ fMockDb ? pszFile : " main" , // Logical db name
248
248
DB_BTREE, // Database type
249
249
nFlags, // Flags
250
250
0 );
@@ -273,7 +273,7 @@ CDB::CDB(const char *pszFile, const char* pszMode) :
273
273
274
274
static bool IsChainFile (std::string strFile)
275
275
{
276
- if (strFile == " blkindex .dat" )
276
+ if (strFile == " coins.dat " || strFile == " chain .dat" )
277
277
return true ;
278
278
279
279
return false ;
@@ -475,111 +475,66 @@ void CDBEnv::Flush(bool fShutdown)
475
475
476
476
477
477
//
478
- // CTxDB
478
+ // CChainDB and CCoinsDB
479
479
//
480
480
481
- bool CTxDB::ReadTxIndex (uint256 hash, CTxIndex& txindex)
482
- {
481
+ bool CCoinsDB::HaveCoins (uint256 hash) {
483
482
assert (!fClient );
484
- txindex.SetNull ();
485
- return Read (make_pair (string (" tx" ), hash), txindex);
483
+ return Exists (make_pair (' c' , hash));
486
484
}
487
485
488
- bool CTxDB::UpdateTxIndex (uint256 hash, const CTxIndex& txindex)
489
- {
486
+ bool CCoinsDB::ReadCoins (uint256 hash, CCoins &coins) {
490
487
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);
502
489
}
503
490
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) {
514
492
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);
516
497
}
517
498
518
- bool CTxDB::ReadDiskTx (uint256 hash, CTransaction& tx, CTxIndex& txindex )
499
+ bool CChainDB::WriteBlockIndex ( const CDiskBlockIndex& blockindex )
519
500
{
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);
525
502
}
526
503
527
- bool CTxDB::ReadDiskTx (uint256 hash, CTransaction& tx )
504
+ bool CCoinsDB::ReadHashBestChain (uint256& hashBestChain )
528
505
{
529
- CTxIndex txindex;
530
- return ReadDiskTx (hash, tx, txindex);
506
+ return Read (' B' , hashBestChain);
531
507
}
532
508
533
- bool CTxDB::ReadDiskTx (COutPoint outpoint, CTransaction& tx, CTxIndex& txindex )
509
+ bool CCoinsDB::WriteHashBestChain (uint256 hashBestChain )
534
510
{
535
- return ReadDiskTx (outpoint. hash , tx, txindex );
511
+ return Write ( ' B ' , hashBestChain );
536
512
}
537
513
538
- bool CTxDB::ReadDiskTx (COutPoint outpoint, CTransaction& tx )
514
+ bool CChainDB::ReadBestInvalidWork (CBigNum& bnBestInvalidWork )
539
515
{
540
- CTxIndex txindex;
541
- return ReadDiskTx (outpoint.hash , tx, txindex);
516
+ return Read (' I' , bnBestInvalidWork);
542
517
}
543
518
544
- bool CTxDB::WriteBlockIndex ( const CDiskBlockIndex& blockindex )
519
+ bool CChainDB::WriteBestInvalidWork (CBigNum bnBestInvalidWork )
545
520
{
546
- return Write (make_pair ( string ( " blockindex " ), blockindex. GetBlockHash ()), blockindex );
521
+ return Write (' I ' , bnBestInvalidWork );
547
522
}
548
523
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);
551
526
}
552
527
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);
555
530
}
556
531
557
- bool CTxDB ::WriteLastBlockFile (int nFile) {
558
- return Write (string ( " lastblockfile " ) , nFile);
532
+ bool CChainDB ::WriteLastBlockFile (int nFile) {
533
+ return Write (' l ' , nFile);
559
534
}
560
535
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);
583
538
}
584
539
585
540
CBlockIndex static * InsertBlockIndex (uint256 hash)
@@ -602,9 +557,9 @@ CBlockIndex static * InsertBlockIndex(uint256 hash)
602
557
return pindexNew;
603
558
}
604
559
605
- bool CTxDB:: LoadBlockIndex ()
560
+ bool LoadBlockIndex (CCoinsDB &coindb, CChainDB &chaindb )
606
561
{
607
- if (!LoadBlockIndexGuts ())
562
+ if (!chaindb. LoadBlockIndexGuts ())
608
563
return false ;
609
564
610
565
if (fRequestShutdown )
@@ -626,29 +581,39 @@ bool CTxDB::LoadBlockIndex()
626
581
}
627
582
628
583
// Load block file info
629
- ReadLastBlockFile (nLastBlockFile);
584
+ chaindb. ReadLastBlockFile (nLastBlockFile);
630
585
printf (" LoadBlockIndex(): last block file = %i\n " , nLastBlockFile);
631
- if (ReadBlockFileInfo (nLastBlockFile, infoLastBlockFile))
586
+ if (chaindb. ReadBlockFileInfo (nLastBlockFile, infoLastBlockFile))
632
587
printf (" LoadBlockIndex(): last block file: %s\n " , infoLastBlockFile.ToString ().c_str ());
633
588
634
589
// Load hashBestChain pointer to end of best chain
635
- if (!ReadHashBestChain (hashBestChain))
590
+ if (!coindb. ReadHashBestChain (hashBestChain))
636
591
{
637
592
if (pindexGenesisBlock == NULL )
638
593
return true ;
639
594
return error (" CTxDB::LoadBlockIndex() : hashBestChain not loaded" );
640
595
}
641
- if (!mapBlockIndex.count (hashBestChain))
596
+ std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find (hashBestChain);
597
+ if (it == mapBlockIndex.end ()) {
642
598
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 ());
649
614
650
615
// Load bnBestInvalidWork, OK if it doesn't exist
651
- ReadBestInvalidWork (bnBestInvalidWork);
616
+ chaindb. ReadBestInvalidWork (bnBestInvalidWork);
652
617
653
618
// Verify blocks in the best chain
654
619
int nCheckLevel = GetArg (" -checklevel" , 1 );
@@ -664,7 +629,6 @@ bool CTxDB::LoadBlockIndex()
664
629
if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
665
630
break ;
666
631
CBlock block;
667
- CDiskBlockPos blockPos = pindex->GetBlockPos ();
668
632
if (!block.ReadFromDisk (pindex))
669
633
return error (" LoadBlockIndex() : block.ReadFromDisk failed" );
670
634
// check level 1: verify block validity
@@ -673,106 +637,20 @@ bool CTxDB::LoadBlockIndex()
673
637
printf (" LoadBlockIndex() : *** found bad block at %d, hash=%s\n " , pindex->nHeight , pindex->GetBlockHash ().ToString ().c_str ());
674
638
pindexFork = pindex->pprev ;
675
639
}
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
758
641
}
759
642
if (pindexFork && !fRequestShutdown )
760
643
{
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" );
768
646
}
769
647
770
648
return true ;
771
649
}
772
650
773
651
774
652
775
- bool CTxDB ::LoadBlockIndexGuts ()
653
+ bool CChainDB ::LoadBlockIndexGuts ()
776
654
{
777
655
// Get database cursor
778
656
Dbc* pcursor = GetCursor ();
@@ -786,7 +664,7 @@ bool CTxDB::LoadBlockIndexGuts()
786
664
// Read next record
787
665
CDataStream ssKey (SER_DISK, CLIENT_VERSION);
788
666
if (fFlags == DB_SET_RANGE)
789
- ssKey << make_pair (string ( " blockindex " ) , uint256 (0 ));
667
+ ssKey << make_pair (' b ' , uint256 (0 ));
790
668
CDataStream ssValue (SER_DISK, CLIENT_VERSION);
791
669
int ret = ReadAtCursor (pcursor, ssKey, ssValue, fFlags );
792
670
fFlags = DB_NEXT;
@@ -798,17 +676,16 @@ bool CTxDB::LoadBlockIndexGuts()
798
676
// Unserialize
799
677
800
678
try {
801
- string strType ;
802
- ssKey >> strType ;
803
- if (strType == " blockindex " && !fRequestShutdown )
679
+ char chType ;
680
+ ssKey >> chType ;
681
+ if (chType == ' b ' && !fRequestShutdown )
804
682
{
805
683
CDiskBlockIndex diskindex;
806
684
ssValue >> diskindex;
807
685
808
686
// Construct block index object
809
687
CBlockIndex* pindexNew = InsertBlockIndex (diskindex.GetBlockHash ());
810
688
pindexNew->pprev = InsertBlockIndex (diskindex.hashPrev );
811
- pindexNew->pnext = InsertBlockIndex (diskindex.hashNext );
812
689
pindexNew->nHeight = diskindex.nHeight ;
813
690
pindexNew->pos = diskindex.pos ;
814
691
pindexNew->nUndoPos = diskindex.nUndoPos ;
0 commit comments