PPCoin: Immediate sync-checkpoint to defend against 51% mining attack
authorSunny King <sunnyking9999@gmail.com>
Wed, 25 Jul 2012 16:29:17 +0000 (17:29 +0100)
committerSunny King <sunnyking9999@gmail.com>
Wed, 25 Jul 2012 16:30:48 +0000 (17:30 +0100)
src/bitcoinrpc.cpp
src/checkpoints.cpp
src/checkpoints.h
src/main.cpp

index 6c7f425..c0c9d2d 100644 (file)
@@ -2211,59 +2211,30 @@ Value sendalert(const Array& params, bool fHelp)
     return result;
 }
 
-// ppcoin: send checkpoint
-Value sendcheckpoint(const Array& params, bool fHelp)
+// ppcoin: set checkpoint key
+Value setcheckpointkey(const Array& params, bool fHelp)
 {
-    if (fHelp || params.size() > 2 || params.size() < 1 )
+    if (fHelp || params.size() != 1)
         throw runtime_error(
-            "sendcheckpoint <privatekey> [checkpointhash]\n"
-            "<privatekey> is hex string of checkpoint master private key\n"
-            "<checkpointhash> is the hash of checkpoint block\n");
+            "setcheckpointkey <privatekey>\n"
+            "<privatekey> is hex string of checkpoint master private key\n");
 
     CSyncCheckpoint checkpoint;
-    CKey key;
-
-    // TODO: omit checkpointhash parameter
-    if (params.size() > 1)
-    {
-        checkpoint.hashCheckpoint = uint256(params[1].get_str());
-        if (!mapBlockIndex.count(checkpoint.hashCheckpoint))
-            throw runtime_error(
-                "Provided checkpoint block is not on main chain\n");
-    }
-    else
-    {
-        checkpoint.hashCheckpoint = Checkpoints::AutoSelectSyncCheckpoint();
-        if (checkpoint.hashCheckpoint == Checkpoints::hashSyncCheckpoint)
-            throw runtime_error(
-                "Unable to select a more recent sync-checkpoint");
-    }
-
+    checkpoint.hashCheckpoint = hashGenesisBlock;
     CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
     sMsg << (CUnsignedSyncCheckpoint)checkpoint;
     checkpoint.vchMsg = vector<unsigned char>(sMsg.begin(), sMsg.end());
 
     vector<unsigned char> vchPrivKey = ParseHex(params[0].get_str());
+    CKey key;
     key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
     if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
         throw runtime_error(
             "Unable to sign checkpoint, check private key?\n");
 
-    if(!checkpoint.ProcessSyncCheckpoint(NULL))
-        throw runtime_error(
-            "Failed to process checkpoint.\n");
-    // Relay checkpoint
-    {
-        LOCK(cs_vNodes);
-        BOOST_FOREACH(CNode* pnode, vNodes)
-            checkpoint.RelayTo(pnode);
-    }
+    CSyncCheckpoint::strMasterPrivKey = params[0].get_str();
 
-    Object result;
-    result.push_back(Pair("checkpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
-    result.push_back(Pair("height", mapBlockIndex[Checkpoints::hashSyncCheckpoint]->nHeight));
-    result.push_back(Pair("timestamp", DateTimeStrFormat("%x %H:%M:%S", mapBlockIndex[Checkpoints::hashSyncCheckpoint]->GetBlockTime()).c_str()));
-    return result;
+    return "checkpoint master key has been set.";
 }
 
 
@@ -2327,7 +2298,7 @@ static const CRPCCommand vRPCCommands[] =
     { "repairwallet",           &repairwallet,           false},
     { "makekeypair",            &makekeypair,            false},
     { "sendalert",              &sendalert,              false},
-    { "sendcheckpoint",         &sendcheckpoint,         false},
+    { "setcheckpointkey",       &setcheckpointkey,       false},
 };
 
 CRPCTable::CRPCTable()
index abd72d4..bd4eba7 100644 (file)
@@ -185,16 +185,6 @@ namespace Checkpoints
         return false;
     }
 
-    uint256 AutoSelectSyncCheckpoint()
-    {
-        // select a block some time ago
-        CBlockIndex *pindex = mapBlockIndex[hashSyncCheckpoint];
-        while (pindex->pnext && pindex->pnext->GetBlockTime() + CHECKPOINT_MIN_SPAN <= GetAdjustedTime())
-            pindex = pindex->pnext;
-        return pindex->GetBlockHash();
-    }
-
-    // Check against synchronized checkpoint
     bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev)
     {
         if (fTestNet) return true; // Testnet has no checkpoints
@@ -282,11 +272,40 @@ namespace Checkpoints
         if (pfrom && hashPendingCheckpoint != 0 && (!mapBlockIndex.count(hashPendingCheckpoint)) && (!mapOrphanBlocks.count(hashPendingCheckpoint)))
             pfrom->AskFor(CInv(MSG_BLOCK, hashPendingCheckpoint));
     }
+
+    bool SendSyncCheckpoint(uint256 hashCheckpoint)
+    {
+        CSyncCheckpoint checkpoint;
+        checkpoint.hashCheckpoint = hashCheckpoint;
+        CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
+        sMsg << (CUnsignedSyncCheckpoint)checkpoint;
+        checkpoint.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());
+
+        if (CSyncCheckpoint::strMasterPrivKey.empty())
+            return error("SendSyncCheckpoint: Checkpoint master key unavailable.");
+        std::vector<unsigned char> vchPrivKey = ParseHex(CSyncCheckpoint::strMasterPrivKey);
+        CKey key;
+        key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
+        if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
+            return error("SendSyncCheckpoint: Unable to sign checkpoint, check private key?");
+
+        if(!checkpoint.ProcessSyncCheckpoint(NULL))
+            return error("SendSyncCheckpoint: Failed to process checkpoint.");
+        // Relay checkpoint
+        {
+            LOCK(cs_vNodes);
+            BOOST_FOREACH(CNode* pnode, vNodes)
+                checkpoint.RelayTo(pnode);
+        }
+        return true;
+    }
 }
 
 // ppcoin: sync-checkpoint master key
 const std::string CSyncCheckpoint::strMasterPubKey = "0424f20205e5da98ba632bbd278a11a6499585f62bfb2c782377ef59f0251daab8085fc31471bcb8180bc75ed0fa41bb50c7c084511d54015a3a5241d645c7268a";
 
+std::string CSyncCheckpoint::strMasterPrivKey = "";
+
 // ppcoin: verify signature of sync-checkpoint message
 bool CSyncCheckpoint::CheckSignature()
 {
index ff815c8..cc4bebd 100644 (file)
@@ -10,7 +10,6 @@
 #include "util.h"
 
 #define STAKE_MIN_AGE (60 * 60 * 24)      // minimum age for coin age
-#define CHECKPOINT_MIN_SPAN (60 * 60 * 4) // 4 hours checkpoint
 
 class uint256;
 class CBlockIndex;
@@ -38,11 +37,11 @@ namespace Checkpoints
     CBlockIndex* GetLastSyncCheckpoint();
     bool WriteSyncCheckpoint(const uint256& hashCheckpoint);
     bool AcceptPendingSyncCheckpoint();
-    uint256 AutoSelectSyncCheckpoint();
     bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev);
     bool WantedByPendingSyncCheckpoint(uint256 hashBlock);
     bool ResetSyncCheckpoint();
     void AskForPendingSyncCheckpoint(CNode* pfrom);
+    bool SendSyncCheckpoint(uint256 hashCheckpoint);
 }
 
 // ppcoin: synchronized checkpoint
@@ -86,6 +85,7 @@ class CSyncCheckpoint : public CUnsignedSyncCheckpoint
 {
 public:
     static const std::string strMasterPubKey;
+    static std::string strMasterPrivKey;
 
     std::vector<unsigned char> vchMsg;
     std::vector<unsigned char> vchSig;
index 429caae..334125f 100644 (file)
@@ -2091,6 +2091,11 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
     }
 
     printf("ProcessBlock: ACCEPTED\n");
+
+    // ppcoin: if responsible for sync-checkpoint send it
+    if (pfrom && !CSyncCheckpoint::strMasterPrivKey.empty())
+        Checkpoints::SendSyncCheckpoint(hashBestChain);
+
     return true;
 }