From 90f586177cfe64fcfaee902b72fd21ef06d5143f Mon Sep 17 00:00:00 2001 From: Scott Nadal Date: Tue, 3 Jul 2012 16:19:26 +0100 Subject: [PATCH] PPCoin: Reset sync-checkpoint when checkpoint master key changes --- src/checkpoints.cpp | 119 +++++++++++++++++++++++++++++++++++++-------------- src/checkpoints.h | 2 + src/db.cpp | 23 ++++++++++ src/db.h | 2 + src/main.cpp | 5 +-- 5 files changed, 115 insertions(+), 36 deletions(-) diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 204741c..14141b3 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -43,7 +43,12 @@ namespace Checkpoints CBlockIndex* GetLastCheckpoint(const std::map& mapBlockIndex) { - if (fTestNet) return NULL; + if (fTestNet) { + std::map::const_iterator t = mapBlockIndex.find(hashGenesisBlock); + if (t != mapBlockIndex.end()) + return t->second; + return NULL; + } int64 nResult; BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints) @@ -57,7 +62,8 @@ namespace Checkpoints } // ppcoin: synchronized checkpoint (centrally broadcasted) - uint256 hashSyncCheckpoint; + uint256 hashSyncCheckpoint = 0; + uint256 hashPendingCheckpoint = 0; CSyncCheckpoint checkpointMessage; CSyncCheckpoint checkpointMessagePending; uint256 hashInvalidCheckpoint = 0; @@ -119,47 +125,58 @@ namespace Checkpoints return true; } + bool WriteSyncCheckpoint(const uint256& hashCheckpoint) + { + CTxDB txdb; + txdb.TxnBegin(); + if (!txdb.WriteSyncCheckpoint(hashCheckpoint)) + { + txdb.TxnAbort(); + return error("WriteSyncCheckpoint(): failed to write to db sync checkpoint %s", hashCheckpoint.ToString().c_str()); + } + if (!txdb.TxnCommit()) + return error("WriteSyncCheckpoint(): failed to commit to db sync checkpoint %s", hashCheckpoint.ToString().c_str()); + txdb.Close(); + + Checkpoints::hashSyncCheckpoint = hashCheckpoint; + return true; + } + bool AcceptPendingSyncCheckpoint() { CRITICAL_BLOCK(cs_hashSyncCheckpoint) { - if ((!checkpointMessagePending.IsNull()) && mapBlockIndex.count(checkpointMessagePending.hashCheckpoint)) + if (hashPendingCheckpoint != 0 && mapBlockIndex.count(hashPendingCheckpoint)) { - if (!ValidateSyncCheckpoint(checkpointMessagePending.hashCheckpoint)) + if (!ValidateSyncCheckpoint(hashPendingCheckpoint)) { + hashPendingCheckpoint = 0; checkpointMessagePending.SetNull(); return false; } CTxDB txdb; - CBlockIndex* pindexCheckpoint = mapBlockIndex[checkpointMessagePending.hashCheckpoint]; + CBlockIndex* pindexCheckpoint = mapBlockIndex[hashPendingCheckpoint]; if (!pindexCheckpoint->IsInMainChain()) { txdb.TxnBegin(); if (!Reorganize(txdb, pindexCheckpoint)) { txdb.TxnAbort(); - hashInvalidCheckpoint = checkpointMessagePending.hashCheckpoint; - return error("ProcessSyncCheckpoint: Reorganize failed for sync checkpoint %s", checkpointMessagePending.hashCheckpoint.ToString().c_str()); + hashInvalidCheckpoint = hashPendingCheckpoint; + return error("ProcessSyncCheckpoint: Reorganize failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str()); } } - - txdb.TxnBegin(); - if (!txdb.WriteSyncCheckpoint(checkpointMessagePending.hashCheckpoint)) - { - txdb.TxnAbort(); - return error("AcceptPendingSyncCheckpoint() : failed to write to db sync checkpoint %s\n", checkpointMessagePending.hashCheckpoint.ToString().c_str()); - } - if (!txdb.TxnCommit()) - return error("AcceptPendingSyncCheckpoint() : failed to commit to db sync checkpoint %s\n", checkpointMessagePending.hashCheckpoint.ToString().c_str()); txdb.Close(); - hashSyncCheckpoint = checkpointMessagePending.hashCheckpoint; + if (!WriteSyncCheckpoint(hashPendingCheckpoint)) + return error("AcceptPendingSyncCheckpoint(): failed to write sync checkpoint %s", hashPendingCheckpoint.ToString().c_str()); + hashPendingCheckpoint = 0; checkpointMessage = checkpointMessagePending; checkpointMessagePending.SetNull(); printf("AcceptPendingSyncCheckpoint : sync-checkpoint at %s\n", hashSyncCheckpoint.ToString().c_str()); // relay the checkpoint - CRITICAL_BLOCK(cs_hashSyncCheckpoint) + if (!checkpointMessage.IsNull()) BOOST_FOREACH(CNode* pnode, vNodes) checkpointMessage.RelayTo(pnode); return true; @@ -212,16 +229,60 @@ namespace Checkpoints { CRITICAL_BLOCK(cs_hashSyncCheckpoint) { - if (checkpointMessagePending.IsNull()) + if (hashPendingCheckpoint == 0) return false; - if (hashBlock == checkpointMessagePending.hashCheckpoint) + if (hashBlock == hashPendingCheckpoint) return true; - if (mapOrphanBlocks.count(checkpointMessagePending.hashCheckpoint) - && hashBlock == WantedByOrphan(mapOrphanBlocks[checkpointMessagePending.hashCheckpoint])) + if (mapOrphanBlocks.count(hashPendingCheckpoint) + && hashBlock == WantedByOrphan(mapOrphanBlocks[hashPendingCheckpoint])) return true; } return false; } + + // ppcoin: reset synchronized checkpoint to last hardened checkpoint + bool ResetSyncCheckpoint() + { + CRITICAL_BLOCK(cs_hashSyncCheckpoint) + { + const uint256& hash = mapCheckpoints.rbegin()->second; + if (mapBlockIndex.count(hash) && !mapBlockIndex[hash]->IsInMainChain()) + { + // checkpoint block accepted but not yet in main chain + printf("ResetSyncCheckpoint: Reorganize to hardened checkpoint %s\n", hash.ToString().c_str()); + CTxDB txdb; + txdb.TxnBegin(); + if (!Reorganize(txdb, mapBlockIndex[hash])) + { + txdb.TxnAbort(); + return error("ResetSyncCheckpoint: Reorganize failed for hardened checkpoint %s", hash.ToString().c_str()); + } + txdb.Close(); + } + else if(!mapBlockIndex.count(hash)) + { + // checkpoint block not yet accepted + hashPendingCheckpoint = hash; + checkpointMessagePending.SetNull(); + printf("ResetSyncCheckpoint: pending for sync-checkpoint %s\n", hashPendingCheckpoint.ToString().c_str()); + // TODO: when to ask for the checkpoint chain? + } + + BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints) + { + const uint256& hash = i.second; + if (mapBlockIndex.count(hash) && mapBlockIndex[hash]->IsInMainChain()) + { + if (!WriteSyncCheckpoint(hash)) + return error("ResetSyncCheckpoint: failed to write sync checkpoint %s", hash.ToString().c_str()); + printf("ResetSyncCheckpoint: sync-checkpoint reset to %s\n", hashSyncCheckpoint.ToString().c_str()); + return true; + } + } + + return false; + } + } } // ppcoin: sync-checkpoint master key @@ -253,6 +314,7 @@ bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom) if (!mapBlockIndex.count(hashCheckpoint)) { // We haven't received the checkpoint chain, keep the checkpoint as pending + Checkpoints::hashPendingCheckpoint = hashCheckpoint; Checkpoints::checkpointMessagePending = *this; printf("ProcessSyncCheckpoint: pending for sync-checkpoint %s\n", hashCheckpoint.ToString().c_str()); // Ask this guy to fill in what we're missing @@ -282,19 +344,12 @@ bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom) return error("ProcessSyncCheckpoint: Reorganize failed for sync checkpoint %s", hashCheckpoint.ToString().c_str()); } } - - txdb.TxnBegin(); - if (!txdb.WriteSyncCheckpoint(hashCheckpoint)) - { - txdb.TxnAbort(); - return error("ProcessSyncCheckpoint(): failed to write to db sync checkpoint %s", hashCheckpoint.ToString().c_str()); - } - if (!txdb.TxnCommit()) - return error("ProcessSyncCheckpoint(): failed to commit to db sync checkpoint %s", hashCheckpoint.ToString().c_str()); txdb.Close(); - Checkpoints::hashSyncCheckpoint = hashCheckpoint; + if (!Checkpoints::WriteSyncCheckpoint(hashCheckpoint)) + return error("ProcessSyncCheckpoint(): failed to write sync checkpoint %s", hashCheckpoint.ToString().c_str()); Checkpoints::checkpointMessage = *this; + Checkpoints::hashPendingCheckpoint = 0; Checkpoints::checkpointMessagePending.SetNull(); printf("ProcessSyncCheckpoint: sync-checkpoint at %s\n", hashCheckpoint.ToString().c_str()); } diff --git a/src/checkpoints.h b/src/checkpoints.h index 9d5a166..fd7d432 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -38,10 +38,12 @@ namespace Checkpoints extern CCriticalSection cs_hashSyncCheckpoint; 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(); } // ppcoin: synchronized checkpoint diff --git a/src/db.cpp b/src/db.cpp index e52e6cf..2d6293d 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -480,6 +480,16 @@ bool CTxDB::WriteSyncCheckpoint(uint256 hashCheckpoint) return Write(string("hashSyncCheckpoint"), hashCheckpoint); } +bool CTxDB::ReadCheckpointPubKey(string& strPubKey) +{ + return Read(string("strCheckpointPubKey"), strPubKey); +} + +bool CTxDB::WriteCheckpointPubKey(const string& strPubKey) +{ + return Write(string("strCheckpointPubKey"), strPubKey); +} + CBlockIndex static * InsertBlockIndex(uint256 hash) { if (hash == 0) @@ -584,6 +594,19 @@ bool CTxDB::LoadBlockIndex() return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded"); printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str()); + // ppcoin: if checkpoint master key changed must reset sync-checkpoint + string strPubKey = ""; + if (!ReadCheckpointPubKey(strPubKey) || strPubKey != CSyncCheckpoint::strMasterPubKey) + { + // write checkpoint master key to db + TxnBegin(); + WriteCheckpointPubKey(CSyncCheckpoint::strMasterPubKey); + if (!TxnCommit()) + return error("CTxDB::LoadBlockIndex() : failed to write new checkpoint master key"); + if (!Checkpoints::ResetSyncCheckpoint()) + return error("CTxDB::LoadBlockIndex() : failed to reset sync-checkpoint"); + } + // Load nBestInvalidTrust, OK if it doesn't exist ReadBestInvalidTrust(nBestInvalidTrust); diff --git a/src/db.h b/src/db.h index a899e51..038c6c4 100644 --- a/src/db.h +++ b/src/db.h @@ -293,6 +293,8 @@ public: bool WriteBestInvalidTrust(uint64 nBestInvalidTrust); bool ReadSyncCheckpoint(uint256& hashCheckpoint); bool WriteSyncCheckpoint(uint256 hashCheckpoint); + bool ReadCheckpointPubKey(std::string& strPubKey); + bool WriteCheckpointPubKey(const std::string& strPubKey); bool LoadBlockIndex(); }; diff --git a/src/main.cpp b/src/main.cpp index 3598c4a..4409dd2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1843,11 +1843,8 @@ bool LoadBlockIndex(bool fAllowNew) return error("LoadBlockIndex() : genesis block not accepted"); // ppcoin: initialize synchronized checkpoint - CTxDB txdbc; - if (!txdbc.WriteSyncCheckpoint(hashGenesisBlock)) + if (!Checkpoints::WriteSyncCheckpoint(hashGenesisBlock)) return error("LoadBlockIndex() : failed to init sync checkpoint"); - txdbc.Close(); - Checkpoints::hashSyncCheckpoint = hashGenesisBlock; } return true; -- 1.7.1