extern int nStakeMaxAge;
extern int nStakeTargetSpacing;
+// Protocol switch time for fixed kernel modifier interval
+unsigned int nModifierSwitchTime = 1402531200; // Thu, 12 Jun 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
return min(nIntervalEnd - nIntervalBeginning - nStakeMinAge, (int64)nStakeMaxAge);
}
+// Whether the given block is subject to new modifier protocol
+bool IsFixedModifierInterval(unsigned int nTimeBlock)
+{
+ return (nTimeBlock >= (fTestNet? nModifierTestSwitchTime : nModifierSwitchTime));
+}
+
// Get the last stake modifier and its generation time from a given block
static bool GetLastStakeModifier(const CBlockIndex* pindex, uint64& nStakeModifier, int64& nModifierTime)
{
// 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;
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;
#include "main.h"
+// ChainDB upgrade time
+extern unsigned int nModifierUpgradeTime;
+
+// Whether a given block is subject to new modifier protocol
+bool IsFixedModifierInterval(unsigned int nTimeBlock);
+
// MODIFIER_INTERVAL: time to elapse before new modifier is computed
extern unsigned int nModifierInterval;
static const int MODIFIER_INTERVAL_RATIO = 3;
// 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 and targetProofOfStake on success return
// 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);
// 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 (!pblocktree->WriteModifierUpgradeTime(0))
+ return error("LoadBlockIndex() : failed to init upgrade info");
+ printf(" Upgrade Info: blocktreedb initialization\n");
}
string strPubKey = "";
return error("LoadBlockIndex() : failed to reset sync-checkpoint");
}
+ // upgrade time set to zero if blocktreedb initialized
+ if (pblocktree->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 (!pblocktree->WriteModifierUpgradeTime(nModifierUpgradeTime))
+ return error("LoadBlockIndex() : failed to write upgrade info");
+ }
+
return true;
}
strStatusBar = _("WARNING: Checkpoint is too old. Wait for block chain to download, or notify developers.");
}
+ // 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.7b6 upgrade deadline.";
+ }
+
// ppcoin: if detected invalid checkpoint enter safe mode
if (Checkpoints::hashInvalidCheckpoint != 0)
{
return Write('K', strPubKey);
}
+bool CBlockTreeDB::ReadModifierUpgradeTime(unsigned int& nUpgradeTime)
+{
+ return Read('M', nUpgradeTime);
+}
+
+bool CBlockTreeDB::WriteModifierUpgradeTime(const unsigned int& nUpgradeTime)
+{
+ return Write('M', nUpgradeTime);
+}
+
bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
return Write(make_pair('f', nFile), info);
}
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 LoadBlockIndexGuts();
};