Make sure that new stake modifier meets fixed generation interval.
authorCryptoManiac <balthazar@yandex.ru>
Thu, 10 Jul 2014 21:22:02 +0000 (01:22 +0400)
committerCryptoManiac <balthazar@yandex.ru>
Thu, 10 Jul 2014 21:22:02 +0000 (01:22 +0400)
Mandatory protocol update, becomes active since 20 Oct 2014.

src/kernel.cpp
src/kernel.h
src/main.cpp
src/txdb-leveldb.cpp
src/txdb-leveldb.h

index bd1cdf3..2484c3c 100644 (file)
@@ -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<int, unsigned int> MapModifierCheckpoints;
 
 // Hard checkpoints of stake modifiers to ensure they are deterministic
@@ -34,6 +43,12 @@ static std::map<int, unsigned int> 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<pair<int64, uint256> >& 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<pair<int64, uint256> > vSortedByTimestamp;
index 00c7163..a9c8a23 100644 (file)
@@ -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
index d8fedf4..cdc33c1 100644 (file)
@@ -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)
     {
index 8367665..f21ae68 100644 (file)
@@ -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)
index 67b4036..ceee914 100644 (file)
@@ -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();