From 1ca032e9c756d7605db51cd6cfce418ab5113e81 Mon Sep 17 00:00:00 2001 From: CryptoManiac Date: Fri, 11 Jul 2014 01:22:02 +0400 Subject: [PATCH] Make sure that new stake modifier meets fixed generation interval. Mandatory protocol update, becomes active since 20 Oct 2014. --- src/kernel.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++-- src/kernel.h | 8 +++++++- src/main.cpp | 36 ++++++++++++++++++++++++++++++++++-- src/txdb-leveldb.cpp | 10 ++++++++++ src/txdb-leveldb.h | 2 ++ 5 files changed, 97 insertions(+), 5 deletions(-) diff --git a/src/kernel.cpp b/src/kernel.cpp index bd1cdf3..2484c3c 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -12,6 +12,15 @@ using namespace std; extern int nStakeMaxAge; extern int nStakeTargetSpacing; +// Protocol switch time for fixed kernel modifier interval +unsigned int nModifierSwitchTime = 1413763200; // Mon, 20 Oct 2014 00:00:00 GMT +unsigned int nModifierTestSwitchTime = 1397520000; // Tue, 15 Apr 2014 00:00:00 GMT + +// Note: user must upgrade before the protocol switch deadline, otherwise it's required to +// re-download the blockchain. The timestamp of upgrade is recorded in the blockchain +// database. +unsigned int nModifierUpgradeTime = 0; + typedef std::map MapModifierCheckpoints; // Hard checkpoints of stake modifiers to ensure they are deterministic @@ -34,6 +43,12 @@ static std::map mapStakeModifierCheckpointsTestNet = ( 0, 0x0e00670bu ) ; +// Whether the given block is subject to new modifier protocol +bool IsFixedModifierInterval(unsigned int nTimeBlock) +{ + return (nTimeBlock >= (fTestNet? nModifierTestSwitchTime : nModifierSwitchTime)); +} + // Get time weight int64 GetWeight(int64 nIntervalBeginning, int64 nIntervalEnd) { @@ -135,15 +150,17 @@ static bool SelectBlockFromCandidates(vector >& vSortedByTi // block. This is to make it difficult for an attacker to gain control of // additional bits in the stake modifier, even after generating a chain of // blocks. -bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64& nStakeModifier, bool& fGeneratedStakeModifier) +bool ComputeNextStakeModifier(const CBlockIndex* pindexCurrent, uint64& nStakeModifier, bool& fGeneratedStakeModifier) { nStakeModifier = 0; fGeneratedStakeModifier = false; + const CBlockIndex* pindexPrev = pindexCurrent->pprev; if (!pindexPrev) { fGeneratedStakeModifier = true; return true; // genesis block's modifier is 0 } + // First find current stake modifier and its generation block time // if it's not old enough, return the same stake modifier int64 nModifierTime = 0; @@ -151,10 +168,35 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64& nStakeModif return error("ComputeNextStakeModifier: unable to get last modifier"); if (fDebug) { - printf("ComputeNextStakeModifier: prev modifier=0x%016"PRI64x" time=%s\n", nStakeModifier, DateTimeStrFormat(nModifierTime).c_str()); + printf("ComputeNextStakeModifier: prev modifier=0x%016"PRI64x" time=%s epoch=%u\n", nStakeModifier, DateTimeStrFormat(nModifierTime).c_str(), (unsigned int)nModifierTime); } if (nModifierTime / nModifierInterval >= pindexPrev->GetBlockTime() / nModifierInterval) + { + if (fDebug) + { + printf("ComputeNextStakeModifier: no new interval keep current modifier: pindexPrev nHeight=%d nTime=%u\n", pindexPrev->nHeight, (unsigned int)pindexPrev->GetBlockTime()); + } return true; + } + if (nModifierTime / nModifierInterval >= pindexCurrent->GetBlockTime() / nModifierInterval) + { + // fixed interval protocol requires current block timestamp also be in a different modifier interval + if (IsFixedModifierInterval(pindexCurrent->nTime)) + { + if (fDebug) + { + printf("ComputeNextStakeModifier: no new interval keep current modifier: pindexCurrent nHeight=%d nTime=%u\n", pindexCurrent->nHeight, (unsigned int)pindexCurrent->GetBlockTime()); + } + return true; + } + else + { + if (fDebug) + { + printf("ComputeNextStakeModifier: old modifier at block %s not meeting fixed modifier interval: pindexCurrent nHeight=%d nTime=%u\n", pindexCurrent->GetBlockHash().ToString().c_str(), pindexCurrent->nHeight, (unsigned int)pindexCurrent->GetBlockTime()); + } + } + } // Sort candidate blocks by timestamp vector > vSortedByTimestamp; diff --git a/src/kernel.h b/src/kernel.h index 00c7163..a9c8a23 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -6,6 +6,9 @@ #include "main.h" +// ChainDB upgrade time +extern unsigned int nModifierUpgradeTime; + // MODIFIER_INTERVAL: time to elapse before new modifier is computed extern unsigned int nModifierInterval; @@ -13,8 +16,11 @@ extern unsigned int nModifierInterval; // ratio of group interval length between the last group and the first group static const int MODIFIER_INTERVAL_RATIO = 3; +// Whether the given block is subject to new modifier protocol +bool IsFixedModifierInterval(unsigned int nTimeBlock); + // Compute the hash modifier for proof-of-stake -bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64& nStakeModifier, bool& fGeneratedStakeModifier); +bool ComputeNextStakeModifier(const CBlockIndex* pindexCurrent, uint64& nStakeModifier, bool& fGeneratedStakeModifier); // Check whether stake kernel meets hash target // Sets hashProofOfStake on success return diff --git a/src/main.cpp b/src/main.cpp index d8fedf4..cdc33c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2132,7 +2132,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) // ppcoin: compute stake modifier uint64 nStakeModifier = 0; bool fGeneratedStakeModifier = false; - if (!ComputeNextStakeModifier(pindexNew->pprev, nStakeModifier, fGeneratedStakeModifier)) + if (!ComputeNextStakeModifier(pindexNew, nStakeModifier, fGeneratedStakeModifier)) return error("AddToBlockIndex() : ComputeNextStakeModifier() failed"); pindexNew->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier); pindexNew->nStakeModifierChecksum = GetStakeModifierChecksum(pindexNew); @@ -2844,9 +2844,16 @@ bool LoadBlockIndex(bool fAllowNew) if (!block.AddToBlockIndex(nFile, nBlockPos)) return error("LoadBlockIndex() : genesis block not accepted"); - // ppcoin: initialize synchronized checkpoint + // initialize synchronized checkpoint if (!Checkpoints::WriteSyncCheckpoint((!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))) return error("LoadBlockIndex() : failed to init sync checkpoint"); + + // upgrade time set to zero if txdb initialized + { + if (!txdb.WriteModifierUpgradeTime(0)) + return error("LoadBlockIndex() : failed to init upgrade info"); + printf(" Upgrade Info: ModifierUpgradeTime txdb initialization\n"); + } } string strPubKey = ""; @@ -2864,6 +2871,23 @@ bool LoadBlockIndex(bool fAllowNew) return error("LoadBlockIndex() : failed to reset sync-checkpoint"); } + // upgrade time set to zero if blocktreedb initialized + if (txdb.ReadModifierUpgradeTime(nModifierUpgradeTime)) + { + if (nModifierUpgradeTime) + printf(" Upgrade Info: blocktreedb upgrade detected at timestamp %d\n", nModifierUpgradeTime); + else + printf(" Upgrade Info: no blocktreedb upgrade detected.\n"); + } + else + { + nModifierUpgradeTime = GetTime(); + printf(" Upgrade Info: upgrading blocktreedb at timestamp %u\n", nModifierUpgradeTime); + if (!txdb.WriteModifierUpgradeTime(nModifierUpgradeTime)) + return error("LoadBlockIndex() : failed to write upgrade info"); + } + + return true; } @@ -3027,6 +3051,14 @@ string GetWarnings(string strFor) strStatusBar = strMiscWarning; } + // if detected unmet upgrade requirement enter safe mode + // Note: Modifier upgrade requires blockchain redownload if past protocol switch + if (IsFixedModifierInterval(nModifierUpgradeTime + 60*60*24)) // 1 day margin + { + nPriority = 5000; + strStatusBar = strRPC = "WARNING: Blockchain redownload required approaching or past v.0.4.4.6u4 upgrade deadline."; + } + // if detected invalid checkpoint enter safe mode if (Checkpoints::hashInvalidCheckpoint != 0) { diff --git a/src/txdb-leveldb.cpp b/src/txdb-leveldb.cpp index 8367665..f21ae68 100644 --- a/src/txdb-leveldb.cpp +++ b/src/txdb-leveldb.cpp @@ -304,6 +304,16 @@ bool CTxDB::WriteCheckpointPubKey(const string& strPubKey) return Write(string("strCheckpointPubKey"), strPubKey); } +bool CTxDB::ReadModifierUpgradeTime(unsigned int& nUpgradeTime) +{ + return Read(string("nUpgradeTime"), nUpgradeTime); +} + +bool CTxDB::WriteModifierUpgradeTime(const unsigned int& nUpgradeTime) +{ + return Write(string("nUpgradeTime"), nUpgradeTime); +} + static CBlockIndex *InsertBlockIndex(uint256 hash) { if (hash == 0) diff --git a/src/txdb-leveldb.h b/src/txdb-leveldb.h index 67b4036..ceee914 100644 --- a/src/txdb-leveldb.h +++ b/src/txdb-leveldb.h @@ -201,6 +201,8 @@ public: bool WriteSyncCheckpoint(uint256 hashCheckpoint); bool ReadCheckpointPubKey(std::string& strPubKey); bool WriteCheckpointPubKey(const std::string& strPubKey); + bool ReadModifierUpgradeTime(unsigned int& nUpgradeTime); + bool WriteModifierUpgradeTime(const unsigned int& nUpgradeTime); bool LoadBlockIndex(); private: bool LoadBlockIndexGuts(); -- 1.7.1