PPCoin: Orphan blocks target requirement against DOS
authorSunny King <sunnyking9999@gmail.com>
Mon, 25 Jun 2012 20:44:01 +0000 (21:44 +0100)
committerSunny King <sunnyking9999@gmail.com>
Mon, 25 Jun 2012 20:44:01 +0000 (21:44 +0100)
        Also fixes an issue in 4bb99fbc where prev block should be asked for

src/checkpoints.cpp
src/checkpoints.h
src/main.cpp
src/main.h

index c8ffdf7..d84c29d 100644 (file)
@@ -63,6 +63,19 @@ namespace Checkpoints
     uint256 hashInvalidCheckpoint = 0;
     CCriticalSection cs_hashSyncCheckpoint;
 
+    // ppcoin: get last synchronized checkpoint
+    CBlockIndex* GetLastSyncCheckpoint()
+    {
+        CRITICAL_BLOCK(cs_hashSyncCheckpoint)
+        {
+            if (!mapBlockIndex.count(hashSyncCheckpoint))
+                error("GetSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str());
+            else
+                return mapBlockIndex[hashSyncCheckpoint];
+        }
+        return NULL;
+    }
+
     // ppcoin: only descendant of current sync-checkpoint is allowed
     bool ValidateSyncCheckpoint(uint256 hashCheckpoint)
     {
@@ -195,10 +208,19 @@ namespace Checkpoints
         return true;
     }
 
-    bool IsPendingSyncCheckpoint(uint256 hashBlock)
+    bool WantedByPendingSyncCheckpoint(uint256 hashBlock)
     {
         CRITICAL_BLOCK(cs_hashSyncCheckpoint)
-            return ((!checkpointMessagePending.IsNull()) && hashBlock == checkpointMessagePending.hashCheckpoint);
+        {
+            if (checkpointMessagePending.IsNull())
+                return false;
+            if (hashBlock == checkpointMessagePending.hashCheckpoint)
+                return true;
+            if (mapOrphanBlocks.count(checkpointMessagePending.hashCheckpoint) 
+                && hashBlock == WantedByOrphan(mapOrphanBlocks[checkpointMessagePending.hashCheckpoint]))
+                return true;
+        }
+        return false;
     }
 
     // ppcoin: automatic checkpoint (represented by height of checkpoint)
@@ -356,7 +378,7 @@ bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom)
                 pfrom->PushGetBlocks(pindexBest, hashCheckpoint);
                 // ask directly as well in case rejected earlier by duplicate
                 // proof-of-stake because getblocks may not get it this time
-                pfrom->AskFor(CInv(MSG_BLOCK, mapOrphanBlocks.count(hashCheckpoint)? GetOrphanRoot(mapOrphanBlocks[hashCheckpoint]) : hashCheckpoint));
+                pfrom->AskFor(CInv(MSG_BLOCK, mapOrphanBlocks.count(hashCheckpoint)? WantedByOrphan(mapOrphanBlocks[hashCheckpoint]) : hashCheckpoint));
             }
             return false;
         }
index 3fc62c7..a52f720 100644 (file)
@@ -125,10 +125,11 @@ namespace Checkpoints
     extern uint256 hashInvalidCheckpoint;
     extern CCriticalSection cs_hashSyncCheckpoint;
 
+    CBlockIndex* GetLastSyncCheckpoint();
     bool AcceptPendingSyncCheckpoint();
     uint256 AutoSelectSyncCheckpoint();
     bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev);
-    bool IsPendingSyncCheckpoint(uint256 hashBlock);
+    bool WantedByPendingSyncCheckpoint(uint256 hashBlock);
 
     // ppcoin: automatic checkpoint
     extern int nAutoCheckpoint;
index c66b74c..fc591be 100644 (file)
@@ -660,7 +660,7 @@ bool CBlock::ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions)
     return true;
 }
 
-uint256 GetOrphanRoot(const CBlock* pblock)
+uint256 static GetOrphanRoot(const CBlock* pblock)
 {
     // Work back to the first block in the orphan chain
     while (mapOrphanBlocks.count(pblock->hashPrevBlock))
@@ -668,6 +668,15 @@ uint256 GetOrphanRoot(const CBlock* pblock)
     return pblock->GetHash();
 }
 
+// ppcoin: find block wanted by given orphan block
+uint256 WantedByOrphan(const CBlock* pblockOrphan)
+{
+    // Work back to the first block in the orphan chain
+    while (mapOrphanBlocks.count(pblockOrphan->hashPrevBlock))
+        pblockOrphan = mapOrphanBlocks[pblockOrphan->hashPrevBlock];
+    return pblockOrphan->hashPrevBlock;
+}
+
 int64 static GetProofOfWorkReward(unsigned int nBits)
 {
     CBigNum bnSubsidyLimit = 9999 * COIN; // subsidy amount for difficulty 1
@@ -723,12 +732,12 @@ unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
 {
     CBigNum bnResult;
     bnResult.SetCompact(nBase);
+    bnResult *= 2;
     while (nTime > 0 && bnResult < bnProofOfWorkLimit)
     {
-        // Maximum 400% adjustment...
-        bnResult *= 4;
-        // ... in best-case exactly 4-times-normal target time
-        nTime -= nTargetTimespan*4;
+        // Maximum 200% adjustment per day...
+        bnResult *= 2;
+        nTime -= 24 * 60 * 60;
     }
     if (bnResult > bnProofOfWorkLimit)
         bnResult = bnProofOfWorkLimit;
@@ -1617,7 +1626,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
     // ppcoin: check proof-of-stake
     // Limited duplicity on stake: prevents block flood attack
     // Duplicate stake allowed only when there is orphan child block
-    if (pblock->IsProofOfStake() && setStakeSeen.count(pblock->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::IsPendingSyncCheckpoint(hash))
+    if (pblock->IsProofOfStake() && setStakeSeen.count(pblock->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::WantedByPendingSyncCheckpoint(hash))
         return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for block %s", pblock->GetProofOfStake().first.ToString().c_str(), pblock->GetProofOfStake().second, hash.ToString().c_str());
 
     // Preliminary checks
@@ -1628,23 +1637,15 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
     if (pblock->IsProofOfStake() && !pblock->vtx[1].CheckProofOfStake(pblock->nBits))
         return error("ProcessBlock() : check proof-of-stake failed for block %s", hash.ToString().c_str());
 
-    CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
-    if (pcheckpoint && pblock->hashPrevBlock != hashBestChain)
+    CBlockIndex* pcheckpoint = Checkpoints::GetLastSyncCheckpoint();
+    if (pcheckpoint && pblock->hashPrevBlock != hashBestChain && !Checkpoints::WantedByPendingSyncCheckpoint(hash))
     {
         // Extra checks to prevent "fill up memory by spamming with bogus blocks"
         int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
-        if (deltaTime < 0)
-        {
-            pfrom->Misbehaving(100);
-            return error("ProcessBlock() : block with timestamp before last checkpoint");
-        }
         CBigNum bnNewBlock;
         bnNewBlock.SetCompact(pblock->nBits);
         CBigNum bnRequired;
-        if (pblock->IsProofOfWork())
-            bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
-        else
-            bnRequired = bnNewBlock; // TODO: Computer Min Stake Target Allowed
+        bnRequired.SetCompact(ComputeMinWork(GetLastBlockIndex(pcheckpoint, pblock->IsProofOfStake())->nBits, deltaTime));
 
         if (bnNewBlock > bnRequired)
         {
@@ -1664,7 +1665,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
         {
             // Limited duplicity on stake: prevents block flood attack
             // Duplicate stake allowed only when there is orphan child block
-            if (setStakeSeenOrphan.count(pblock2->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::IsPendingSyncCheckpoint(hash))
+            if (setStakeSeenOrphan.count(pblock2->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::WantedByPendingSyncCheckpoint(hash))
                 return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for orphan block %s", pblock2->GetProofOfStake().first.ToString().c_str(), pblock2->GetProofOfStake().second, hash.ToString().c_str());
             else
                 setStakeSeenOrphan.insert(pblock2->GetProofOfStake());
@@ -1678,7 +1679,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
             pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2));
             // ppcoin: getblocks may not obtain the ancestor block rejected
             // earlier by duplicate-stake check so we ask for it again directly
-            pfrom->AskFor(CInv(MSG_BLOCK, GetOrphanRoot(pblock2)));
+            pfrom->AskFor(CInv(MSG_BLOCK, WantedByOrphan(pblock2)));
         }
         return true;
     }
index 9e4a1a8..77d9199 100644 (file)
@@ -109,7 +109,7 @@ int GetNumBlocksOfPeers();
 bool IsInitialBlockDownload();
 std::string GetWarnings(std::string strFor);
 bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew);
-uint256 GetOrphanRoot(const CBlock* pblock);
+uint256 WantedByOrphan(const CBlock* pblockOrphan);