PPCoin: Synchronized checkpoint accepting descendant blocks only
authorScott Nadal <scott.nadal@gmail.com>
Mon, 18 Jun 2012 15:20:10 +0000 (16:20 +0100)
committerScott Nadal <scott.nadal@gmail.com>
Mon, 18 Jun 2012 15:20:10 +0000 (16:20 +0100)
src/checkpoints.cpp
src/checkpoints.h
src/main.cpp

index d986b07..888d106 100644 (file)
@@ -77,7 +77,8 @@ namespace Checkpoints
 
         CBlockIndex* pindex = pindexCheckpointRecv;
         while (pindex->nHeight > pindexSyncCheckpoint->nHeight)
-            pindex = pindex->pprev;
+            if (!(pindex = pindex->pprev))
+                return error("ValidateSyncCheckpoint: pprev null - block index structure failure");
         if (pindex->GetBlockHash() != hashSyncCheckpoint)
             return error("ValidateSyncCheckpoint: new sync-checkpoint %s is not a descendant of current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str());
         return true;
@@ -122,13 +123,27 @@ namespace Checkpoints
     }
 
     // Check against synchronized checkpoint
-    bool CheckSync(int nHeight, const uint256& hashBlock)
+    bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev)
     {
         if (fTestNet) return true; // Testnet has no checkpoints
+        int nHeight = pindexPrev->nHeight + 1;
 
         CRITICAL_BLOCK(cs_hashSyncCheckpoint)
         {
-            CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
+            // sync-checkpoint should always be accepted block
+            assert(mapBlockIndex.count(hashSyncCheckpoint));
+            const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
+
+            if (nHeight > pindexSync->nHeight)
+            {
+                // trace back to same height as sync-checkpoint
+                const CBlockIndex* pindex = pindexPrev;
+                while (pindex->nHeight > pindexSync->nHeight)
+                    if (!(pindex = pindex->pprev))
+                        return error("CheckSync: pprev null - block index structure failure");
+                if (pindex->nHeight < pindexSync->nHeight || pindex->GetBlockHash() != hashSyncCheckpoint)
+                    return false; // only descendant of sync-checkpoint can pass check
+            }
             if (nHeight == pindexSync->nHeight && hashBlock != hashSyncCheckpoint)
                 return false; // same height with sync-checkpoint
             if (nHeight < pindexSync->nHeight && !mapBlockIndex.count(hashBlock))
index db3fe19..e90458e 100644 (file)
@@ -137,7 +137,7 @@ namespace Checkpoints
 
     bool AcceptPendingSyncCheckpoint();
     uint256 AutoSelectSyncCheckpoint();
-    bool CheckSync(int nHeight, const uint256& hashBlock);
+    bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev);
 
     // ppcoin: automatic checkpoint
     extern int nAutoCheckpoint;
index 4de69bf..b8d83b2 100644 (file)
@@ -1579,8 +1579,8 @@ bool CBlock::AcceptBlock()
         return DoS(100, error("AcceptBlock() : rejected by automatic checkpoint at %d", Checkpoints::nAutoCheckpoint));
 
     // ppcoin: check that the block satisfies synchronized checkpoint
-    if (!Checkpoints::CheckSync(nHeight, hash))
-        return DoS(100, error("AcceptBlock() : rejected by synchronized checkpoint"));
+    if (!Checkpoints::CheckSync(hash, pindexPrev))
+        return error("AcceptBlock() : rejected by synchronized checkpoint");
 
     // Write block to history file
     if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))