Prepare database format for multi-stage block processing
authoralex <alex@alex-VirtualBox.(none)>
Wed, 22 Jan 2014 20:00:57 +0000 (00:00 +0400)
committeralex <alex@alex-VirtualBox.(none)>
Wed, 22 Jan 2014 20:00:57 +0000 (00:00 +0400)
This commit adds a status field and a transaction counter to the block
indexes.

src/checkpoints.cpp
src/db.cpp
src/init.cpp
src/main.cpp
src/main.h

index f8c00c6..e9567a2 100644 (file)
@@ -168,7 +168,7 @@ namespace Checkpoints
                 CBlock block;
                 if (!block.ReadFromDisk(pindexCheckpoint))
                     return error("AcceptPendingSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
-                if (!block.SetBestChain(pindexCheckpoint))
+                if (!SetBestChain(pindexCheckpoint))
                 {
                     hashInvalidCheckpoint = hashPendingCheckpoint;
                     return error("AcceptPendingSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
@@ -256,7 +256,7 @@ namespace Checkpoints
             CBlock block;
             if (!block.ReadFromDisk(mapBlockIndex[hash]))
                 return error("ResetSyncCheckpoint: ReadFromDisk failed for hardened checkpoint %s", hash.ToString().c_str());
-            if (!block.SetBestChain(mapBlockIndex[hash]))
+            if (!SetBestChain(mapBlockIndex[hash]))
             {
                 return error("ResetSyncCheckpoint: SetBestChain failed for hardened checkpoint %s", hash.ToString().c_str());
             }
@@ -419,7 +419,7 @@ bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom)
         CBlock block;
         if (!block.ReadFromDisk(pindexCheckpoint))
             return error("ProcessSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashCheckpoint.ToString().c_str());
-        if (!block.SetBestChain(pindexCheckpoint))
+        if (!SetBestChain(pindexCheckpoint))
         {
             Checkpoints::hashInvalidCheckpoint = hashCheckpoint;
             return error("ProcessSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashCheckpoint.ToString().c_str());
index 9fbcc8a..0f01dd6 100644 (file)
@@ -649,6 +649,9 @@ bool LoadBlockIndex(CChainDB &chaindb)
     {
         CBlockIndex* pindex = item.second;
         pindex->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + pindex->GetBlockTrust();
+        pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
+        if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS && !(pindex->nStatus & BLOCK_FAILED_MASK))
+            setBlockIndexValid.insert(pindex);
 
         // Calculate stake modifier checksum
         pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex);
@@ -769,7 +772,8 @@ bool CChainDB::LoadBlockIndexGuts()
             CBlockIndex* pindexNew = InsertBlockIndex(blockHash);
             pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
             pindexNew->nHeight        = diskindex.nHeight;
-            pindexNew->pos            = diskindex.pos;
+            pindexNew->nFile          = diskindex.nFile;
+            pindexNew->nDataPos       = diskindex.nDataPos;
             pindexNew->nUndoPos       = diskindex.nUndoPos;
             pindexNew->nMint          = diskindex.nMint;
             pindexNew->nMoneySupply   = diskindex.nMoneySupply;
@@ -783,13 +787,15 @@ bool CChainDB::LoadBlockIndexGuts()
             pindexNew->nTime          = diskindex.nTime;
             pindexNew->nBits          = diskindex.nBits;
             pindexNew->nNonce         = diskindex.nNonce;
+            pindexNew->nStatus        = diskindex.nStatus;
+            pindexNew->nTx            = diskindex.nTx;
 
             // Watch for genesis block
             if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
                 pindexGenesisBlock = pindexNew;
 
             if (!pindexNew->CheckIndex())
-                return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
+                return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
 
             // Build setStakeSeen
             if (pindexNew->IsProofOfStake())
index 565eec7..7281e01 100644 (file)
@@ -847,38 +847,9 @@ bool AppInit2()
     // ********************************************************* Step 9: import blocks
 
     // scan for better chains in the block chain database, that are not yet connected in the active best chain
-    CBlockIndex *pindexFoundBest = pindexBest;
-    for (std::map<uint256,CBlockIndex*>::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) {
-        CBlockIndex *pindex = it->second;
-        if (pindexFoundBest==NULL || pindex->nChainTrust > pindexFoundBest->nChainTrust)
-            pindexFoundBest = pindex;
-    }
-    if (pindexFoundBest != pindexBest) {
-        uiInterface.InitMessage(_("Importing blocks from block database..."));
-        uint64 nTxs = 0;
-        uint64 nBlocks = 0;
-        std::vector<CBlockIndex*> vAttach;
-        vAttach.reserve(pindexFoundBest->nHeight - (pindexBest==NULL ? 0 : pindexBest->nHeight));
-        while (pindexFoundBest && pindexFoundBest->nChainTrust > (pindexBest==NULL ? 0 : pindexBest->nChainTrust)) {
-            vAttach.push_back(pindexFoundBest);
-            pindexFoundBest = pindexFoundBest->pprev;
-        }
-        for (std::vector<CBlockIndex*>::reverse_iterator it = vAttach.rbegin(); it != vAttach.rend(); it++) {
-            CBlockIndex *pindex = *it;
-            CBlock block;
-            if (!block.ReadFromDisk(pindex))
-                break;
-            nTxs += block.vtx.size();
-            nBlocks++;
-            if (pindex->nHeight == 0 || nTxs + nBlocks*3 > 500) {
-                nTxs=0;
-                nBlocks=0;
-                block.SetBestChain(pindex);
-            }
-            if (fRequestShutdown)
-                break;
-        }
-    }
+    uiInterface.InitMessage(_("Importing blocks from block database..."));
+    if (!ConnectBestBlock())
+        strErrors << "Failed to connect best block";
 
     if (mapArgs.count("-loadblock"))
     {
index ab7a7ba..c4fead8 100644 (file)
@@ -58,6 +58,7 @@ uint256 nBestInvalidTrust = 0;
 uint256 hashBestChain = 0;
 CBlockIndex* pindexBest = NULL;
 int64 nTimeBestReceived = 0;
+set<CBlockIndex*, CBlockIndexTrustComparator> setBlockIndexValid; // may contain all CBlockIndex*'s that have validness >=BLOCK_VALID_TRANSACTIONS, and must contain those who aren't failed
 
 CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have
 
@@ -1320,6 +1321,61 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
       DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
 }
 
+void static InvalidBlockFound(CBlockIndex *pindex) {
+    pindex->nStatus |= BLOCK_FAILED_VALID;
+    CChainDB().WriteBlockIndex(CDiskBlockIndex(pindex));
+    setBlockIndexValid.erase(pindex);
+    InvalidChainFound(pindex);
+    if (pindex->pnext)
+        ConnectBestBlock(); // reorganise away from the failed block
+}
+
+bool ConnectBestBlock() {
+    do {
+        CBlockIndex *pindexNewBest;
+
+        {
+            std::set<CBlockIndex*,CBlockIndexTrustComparator>::reverse_iterator it = setBlockIndexValid.rbegin();
+            if (it == setBlockIndexValid.rend())
+                return true;
+            pindexNewBest = *it;
+        }
+
+        if (pindexNewBest == pindexBest)
+            return true; // nothing to do
+
+        // check ancestry
+        CBlockIndex *pindexTest = pindexNewBest;
+        std::vector<CBlockIndex*> vAttach;
+        do {
+            if (pindexTest->nStatus & BLOCK_FAILED_MASK) {
+                // mark descendants failed
+                CChainDB chaindb;
+                CBlockIndex *pindexFailed = pindexNewBest;
+                while (pindexTest != pindexFailed) {
+                    pindexFailed->nStatus |= BLOCK_FAILED_CHILD;
+                    setBlockIndexValid.erase(pindexFailed);
+                    chaindb.WriteBlockIndex(CDiskBlockIndex(pindexFailed));
+                    pindexFailed = pindexFailed->pprev;
+                }
+                InvalidChainFound(pindexNewBest);
+                break;
+            }
+
+            if (pindexBest == NULL || pindexTest->nChainTrust > pindexBest->nChainTrust)
+                vAttach.push_back(pindexTest);
+
+            if (pindexTest->pprev == NULL || pindexTest->pnext != NULL) {
+                reverse(vAttach.begin(), vAttach.end());
+                BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach)
+                    if (!SetBestChain(pindexSwitch))
+                        return false;
+                return true;
+            }
+            pindexTest = pindexTest->pprev;
+        } while(true);
+    } while(true);
+}
 
 void CBlock::UpdateTime(const CBlockIndex* pindexPrev)
 {
@@ -1720,24 +1776,29 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
     if (fJustCheck)
         return true;
 
-    CChainDB chaindb;
-    CDiskBlockPos pos;
-
     // Write undo information to disk
-    if (pindex->GetUndoPos().IsNull())
+    if (pindex->GetUndoPos().IsNull() || (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS)
     {
-        if (!FindUndoPos(chaindb, pindex->pos.nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 8))
-            return error("ConnectBlock() : FindUndoPos failed");
-        if (!blockundo.WriteToDisk(pos))
-            return error("ConnectBlock() : CBlockUndo::WriteToDisk failed");
+        CChainDB chaindb;
 
-        // update nUndoPos in block index
-        pindex->nUndoPos = pos.nPos + 1;
-    }
+        if (pindex->GetUndoPos().IsNull()) {
+            CDiskBlockPos pos;
+            if (!FindUndoPos(chaindb, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 8))
+                return error("ConnectBlock() : FindUndoPos failed");
+            if (!blockundo.WriteToDisk(pos))
+                return error("ConnectBlock() : CBlockUndo::WriteToDisk failed");
+
+            // update nUndoPos in block index
+            pindex->nUndoPos = pos.nPos;
+            pindex->nStatus |= BLOCK_HAVE_UNDO;
+        }
+
+        pindex->nStatus = (pindex->nStatus & ~BLOCK_VALID_MASK) | BLOCK_VALID_SCRIPTS;
 
-    CDiskBlockIndex blockindex(pindex);
-    if (!chaindb.WriteBlockIndex(blockindex))
-        return error("ConnectBlock() : WriteBlockIndex failed");
+        CDiskBlockIndex blockindex(pindex);
+        if (!chaindb.WriteBlockIndex(blockindex))
+            return error("ConnectBlock() : WriteBlockIndex failed");
+    }
 
     // add this block to the view's blockchain
     if (!view.SetBestBlock(pindex))
@@ -1754,13 +1815,13 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust
     return true;
 }
 
-bool CBlock::SetBestChain(CBlockIndex* pindexNew)
+bool SetBestChain(CBlockIndex* pindexNew)
 {
     CCoinsViewCache &view = *pcoinsTip;
 
     // special case for attaching the genesis block
     // note that no ConnectBlock is called, so its coinbase output is non-spendable
-    if (pindexGenesisBlock == NULL && pindexNew->GetBlockHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
+    if (pindexGenesisBlock == NULL && pindexNew->GetBlockHash() == hashGenesisBlock)
     {
         view.SetBestBlock(pindexNew);
         if (!view.Flush())
@@ -1825,24 +1886,19 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
     vector<CTransaction> vDelete;
     BOOST_FOREACH(CBlockIndex *pindex, vConnect) {
         CBlock block;
-        CBlock *pblock;
-        if (pindex == pindexNew) // connecting *this block
-            pblock = this;
-        else { // other block; read it from disk
-            if (!block.ReadFromDisk(pindex))
-                return error("SetBestBlock() : ReadFromDisk for connect failed");
-            pblock = &block;
-        }
+        if (!block.ReadFromDisk(pindex))
+            return error("SetBestBlock() : ReadFromDisk for connect failed");
         CCoinsViewCache viewTemp(view, true);
-        if (!pblock->ConnectBlock(pindex, viewTemp)) {
+        if (!block.ConnectBlock(pindex, viewTemp)) {
             InvalidChainFound(pindexNew);
+            InvalidBlockFound(pindex);
             return error("SetBestBlock() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
         }
         if (!viewTemp.Flush())
             return error("SetBestBlock() : Cache flush failed after connect");
 
         // Queue memory transactions to delete
-        BOOST_FOREACH(const CTransaction& tx, pblock->vtx)
+        BOOST_FOREACH(const CTransaction& tx, block.vtx)
             vDelete.push_back(tx);
     }
 
@@ -1891,10 +1947,8 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
 
     uint256 nBestBlockTrust = pindexBest->nHeight != 0 ? (pindexBest->nChainTrust - pindexBest->pprev->nChainTrust) : pindexBest->nChainTrust;
 
-    printf("SetBestChain: new best=%s  height=%d  trust=%s  blocktrust=%"PRI64d"  date=%s\n",
-      hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
-      CBigNum(nBestChainTrust).ToString().c_str(),
-      nBestBlockTrust.Get64(),
+    printf("SetBestChain: new best=%s  height=%d  trust=%s blocktrust=%s  tx=%lu  date=%s\n",
+      hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str(), CBigNum(nBestBlockTrust).ToString().c_str(), (unsigned long)pindexNew->nChainTx,
       DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
 
     // Check the version of the last 100 blocks to see if we need to upgrade:
@@ -2008,9 +2062,13 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
         pindexNew->pprev = (*miPrev).second;
         pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
     }
+    pindexNew->nTx = vtx.size();
     pindexNew->nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + pindexNew->GetBlockTrust();
-    pindexNew->pos = pos;
+    pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx;
+    pindexNew->nFile = pos.nFile;
+    pindexNew->nDataPos = pos.nPos;
     pindexNew->nUndoPos = 0;
+    pindexNew->nStatus = BLOCK_VALID_TRANSACTIONS | BLOCK_HAVE_DATA;
 
     // Compute stake entropy bit for stake modifier
     if (!pindexNew->SetStakeEntropyBit(GetStakeEntropyBit(pindexNew->nTime)))
@@ -2034,6 +2092,8 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
     if (!CheckStakeModifierCheckpoints(pindexNew->nHeight, pindexNew->nStakeModifierChecksum))
         return error("AddToBlockIndex() : Rejected by stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindexNew->nHeight, nStakeModifier);
 
+    setBlockIndexValid.insert(pindexNew);
+
     CChainDB chaindb;
     if (!chaindb.TxnBegin())
         return false;
@@ -2041,8 +2101,8 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
     if (!chaindb.TxnCommit())
         return false;
 
-    // New best
-    if (!SetBestChain(pindexNew))
+    // New best?
+    if (!ConnectBestBlock())
         return false;
 
     if (pindexNew == pindexBest)
index 038eb36..195d62e 100644 (file)
@@ -25,6 +25,7 @@ class CAddress;
 class CInv;
 class CRequestTracker;
 class CNode;
+class CBlockIndexTrustComparator;
 
 static const unsigned int MAX_BLOCK_SIZE = 1000000;
 static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
@@ -72,6 +73,7 @@ extern libzerocoin::Params* ZCParams;
 extern CScript COINBASE_FLAGS;
 extern CCriticalSection cs_main;
 extern std::map<uint256, CBlockIndex*> mapBlockIndex;
+extern std::set<CBlockIndex*, CBlockIndexTrustComparator> setBlockIndexValid;
 extern std::set<std::pair<COutPoint, unsigned int> > setStakeSeen;
 extern CBlockIndex* pindexGenesisBlock;
 extern unsigned int nStakeMinAge;
@@ -135,6 +137,8 @@ int GetNumBlocksOfPeers();
 bool IsInitialBlockDownload();
 std::string GetWarnings(std::string strFor);
 bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow);
+bool SetBestChain(CBlockIndex* pindexNew);
+bool ConnectBestBlock();
 uint256 WantedByOrphan(const CBlock* pblockOrphan);
 const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake);
 void StakeMiner(CWallet *pwallet);
@@ -1385,9 +1389,6 @@ public:
     // Read a block from disk
     bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
 
-    // Make this block (with given index) the new tip of the active block chain
-    bool SetBestChain(CBlockIndex* pindexNew);
-
     // Add this block to the block index, and if necessary, switch the active block chain to this
     bool AddToBlockIndex(const CDiskBlockPos &pos);
 
@@ -1472,6 +1473,24 @@ extern CCriticalSection cs_LastBlockFile;
 extern CBlockFileInfo infoLastBlockFile;
 extern int nLastBlockFile;
 
+enum BlockStatus {
+    BLOCK_VALID_UNKNOWN      =    0,
+    BLOCK_VALID_HEADER       =    1, // parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future
+    BLOCK_VALID_TREE         =    2, // parent found, difficulty matches, timestamp >= median previous, checkpoint
+    BLOCK_VALID_TRANSACTIONS =    3, // only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids, sigops, size, merkle root
+    BLOCK_VALID_CHAIN        =    4, // outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30
+    BLOCK_VALID_SCRIPTS      =    5, // scripts/signatures ok
+    BLOCK_VALID_MASK         =    7,
+
+    BLOCK_HAVE_DATA          =    8, // full block available in blk*.dat
+    BLOCK_HAVE_UNDO          =   16, // undo data available in rev*.dat
+    BLOCK_HAVE_MASK          =   24,
+
+    BLOCK_FAILED_VALID       =   32, // stage after last reached validness failed
+    BLOCK_FAILED_CHILD       =   64, // descends from failed block
+    BLOCK_FAILED_MASK        =   96
+};
+
 /** The block chain is a tree shaped structure starting with the
  * genesis block at the root, with each block potentially having multiple
  * candidates to be the next block.  pprev and pnext link a path through the
@@ -1482,50 +1501,92 @@ extern int nLastBlockFile;
 class CBlockIndex
 {
 public:
+    // pointer to the hash of the block, if any. memory is owned by this CBlockIndex
     const uint256* phashBlock;
+
+    // pointer to the index of the predecessor of this block
     CBlockIndex* pprev;
+
+    // (memory only) pointer to the index of the *active* successor of this block
     CBlockIndex* pnext;
+
+    // height of the entry in the chain. The genesis block has height 0
     int nHeight;
-    CDiskBlockPos pos;
+
+    // Which # file this block is stored in (blk?????.dat)
+    int nFile;
+
+    // Byte offset within blk?????.dat where this block's data is stored
+    unsigned int nDataPos;
+
+    // Byte offset within rev?????.dat where this block's undo data is stored
     unsigned int nUndoPos;
-    uint256 nChainTrust; // trust score of block chain
 
+    // (memory only) Trust score of block chain up to and including this block
+    uint256 nChainTrust;
+
+    // Number of transactions in this block.
+    unsigned int nTx;
+
+    // (memory only) Number of transactions in the chain up to and including this block
+    unsigned int nChainTx;
+
+    // Verification status of this block. See enum BlockStatus for detailed info
+    unsigned int nStatus;
+
+    // Coins amount created by this block
     int64 nMint;
+
+    // Total coins created in this block chain up to and including this block
     int64 nMoneySupply;
 
+    // Block flags
     unsigned int nFlags;
     enum
     {
-        BLOCK_PROOF_OF_STAKE = (1 << 0), // is proof-of-stake block
-        BLOCK_STAKE_ENTROPY  = (1 << 1), // entropy bit for stake modifier
-        BLOCK_STAKE_MODIFIER = (1 << 2), // regenerated stake modifier
+        // is proof-of-stake block
+        BLOCK_PROOF_OF_STAKE = (1 << 0),
+        // entropy bit for stake modifier
+        BLOCK_STAKE_ENTROPY  = (1 << 1),
+        // regenerated stake modifier
+        BLOCK_STAKE_MODIFIER = (1 << 2),
     };
 
-    uint64 nStakeModifier; // hash modifier for proof-of-stake
-    unsigned int nStakeModifierChecksum; // checksum of index; in-memeory only
+    // Hash modifier for proof-of-stake kernel
+    uint64 nStakeModifier;
 
-    // proof-of-stake specific fields
+    // Checksum of index in-memory only
+    unsigned int nStakeModifierChecksum;
+
+    // Predecessor of coinstake transaction
     COutPoint prevoutStake;
+
+    // Timestamp of coinstake transaction
     unsigned int nStakeTime;
+
+    // Kernel hash
     uint256 hashProofOfStake;
 
-    // block header
+    // Block header
     int nVersion;
     uint256 hashMerkleRoot;
     unsigned int nTime;
     unsigned int nBits;
     unsigned int nNonce;
 
-
     CBlockIndex()
     {
         phashBlock = NULL;
         pprev = NULL;
         pnext = NULL;
         nHeight = 0;
-        pos.SetNull();
+        nFile = 0;
+        nDataPos = 0;
         nUndoPos = 0;
         nChainTrust = 0;
+        nTx = 0;
+        nChainTx = 0;
+        nStatus = 0;
         nMint = 0;
         nMoneySupply = 0;
         nFlags = 0;
@@ -1548,9 +1609,13 @@ public:
         pprev = NULL;
         pnext = NULL;
         nHeight = 0;
-        pos.SetNull();
+        nFile = 0;
+        nDataPos = 0;
         nUndoPos = 0;
         nChainTrust = 0;
+        nTx = 0;
+        nChainTx = 0;
+        nStatus = 0;
         nMint = 0;
         nMoneySupply = 0;
         nFlags = 0;
@@ -1577,15 +1642,22 @@ public:
     }
 
     CDiskBlockPos GetBlockPos() const {
-        return pos;
+        CDiskBlockPos ret;
+        if (nStatus & BLOCK_HAVE_DATA) {
+            ret.nFile = nFile;
+            ret.nPos  = nDataPos;
+        } else
+            ret.SetNull();
+        return ret;
     }
 
     CDiskBlockPos GetUndoPos() const {
-        CDiskBlockPos ret = pos;
-        if (nUndoPos == 0)
+        CDiskBlockPos ret;
+        if (nStatus & BLOCK_HAVE_UNDO) {
+            ret.nFile = nFile;
+            ret.nPos  = nUndoPos;
+        } else
             ret.SetNull();
-        else
-            ret.nPos = nUndoPos - 1;
         return ret;
     }
 
@@ -1719,6 +1791,16 @@ public:
     }
 };
 
+struct CBlockIndexTrustComparator
+{
+    bool operator()(CBlockIndex *pa, CBlockIndex *pb) {
+        if (pa->nChainTrust > pb->nChainTrust) return false;
+        if (pa->nChainTrust < pb->nChainTrust) return true;
+
+        return false; // identical blocks
+    }
+};
+
 /** Used to marshal pointers into hashes for db storage. */
 class CDiskBlockIndex : public CBlockIndex
 {
@@ -1739,11 +1821,17 @@ public:
     IMPLEMENT_SERIALIZE
     (
         if (!(nType & SER_GETHASH))
-            READWRITE(nVersion);
-
-        READWRITE(nHeight);
-        READWRITE(pos);
-        READWRITE(nUndoPos);
+            READWRITE(VARINT(nVersion));
+
+        READWRITE(VARINT(nHeight));
+        READWRITE(VARINT(nStatus));
+        READWRITE(VARINT(nTx));
+        if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO))
+            READWRITE(VARINT(nFile));
+        if (nStatus & BLOCK_HAVE_DATA)
+            READWRITE(VARINT(nDataPos));
+        if (nStatus & BLOCK_HAVE_UNDO)
+            READWRITE(VARINT(nUndoPos));
         READWRITE(nMint);
         READWRITE(nMoneySupply);
         READWRITE(nFlags);