From: Sunny King Date: Wed, 25 Jul 2012 16:29:17 +0000 (+0100) Subject: PPCoin: Immediate sync-checkpoint to defend against 51% mining attack X-Git-Tag: v0.4.0-unstable~124 X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=commitdiff_plain;h=44f601723c3a1c68de6e613a897e9f8418eb874a PPCoin: Immediate sync-checkpoint to defend against 51% mining attack --- diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 6c7f425..c0c9d2d 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -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 [checkpointhash]\n" - " is hex string of checkpoint master private key\n" - " is the hash of checkpoint block\n"); + "setcheckpointkey \n" + " 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(sMsg.begin(), sMsg.end()); vector 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() diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index abd72d4..bd4eba7 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -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(sMsg.begin(), sMsg.end()); + + if (CSyncCheckpoint::strMasterPrivKey.empty()) + return error("SendSyncCheckpoint: Checkpoint master key unavailable."); + std::vector 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() { diff --git a/src/checkpoints.h b/src/checkpoints.h index ff815c8..cc4bebd 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -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 vchMsg; std::vector vchSig; diff --git a/src/main.cpp b/src/main.cpp index 429caae..334125f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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; }