namespace Checkpoints
{
- typedef std::map<int, uint256> MapCheckpoints;
+ struct Checkpoint
+ {
+ uint256 hashCheckPoint;
+ unsigned int nTime;
+ };
+
+ typedef std::map<int, Checkpoint> MapCheckpoints;
+
+ Checkpoint initCheckpoint(uint256 hashCheckPoint, unsigned int nTime)
+ {
+ return {hashCheckPoint, nTime};
+ }
//
// What makes a good checkpoint block?
//
static MapCheckpoints mapCheckpoints =
boost::assign::map_list_of
- ( 0, hashGenesisBlock )
- ( 6000, uint256("0x000000000945e3c9d8e15df834e802521eb79f9ceb4191a27bdfadad4b777f4a"))
- ( 9690, uint256("0x00000000026561450859c46868099e0df6068a538f038cb18988fd8d47dcdaf5"))
- ( 13560, uint256("0xa1591a0fcbf11f282d671581edb9f0aadcd06fee69761081e0a3245914c13729"))
- ( 14189, uint256("0x00000000020f76474d2522b19c7bfafc43ba6ecbabae54293bcd9546159c8c1d"))
- ( 19600, uint256("0x252ae08d6df4bc7220c1dcdaed7b8a6e78bab05a60173511e8f565a3a38ce3c3"))
- ( 21800, uint256("0x64bdeb35023f240ed01beaa082f840f2d4cc6defccbbcda1260de87e58296b37"))
- ( 26174, uint256("0x00000000006cf1bfaa0d73caea92f6d2afa465651a76415b8d53b0bb0e01a8be"))
- ( 27451, uint256("0xd65424c24041b9f2e531f8f275f1a3c8bb105f0b29005b0bd577ae1a73341080"))
-
+ ( 0, initCheckpoint(hashGenesisBlock, 1360105017) )
+ ( 6000, initCheckpoint(uint256("0x000000000945e3c9d8e15df834e802521eb79f9ceb4191a27bdfadad4b777f4a"), 1360814368) )
+ ( 9690, initCheckpoint(uint256("0x00000000026561450859c46868099e0df6068a538f038cb18988fd8d47dcdaf5"), 1362791423) )
+ ( 13560, initCheckpoint(uint256("0xa1591a0fcbf11f282d671581edb9f0aadcd06fee69761081e0a3245914c13729"), 1364674052) )
+ ( 14189, initCheckpoint(uint256("0x00000000020f76474d2522b19c7bfafc43ba6ecbabae54293bcd9546159c8c1d"), 1365215020) )
+ ( 19600, initCheckpoint(uint256("0x252ae08d6df4bc7220c1dcdaed7b8a6e78bab05a60173511e8f565a3a38ce3c3"), 1367840555) )
+ ( 21800, initCheckpoint(uint256("0x64bdeb35023f240ed01beaa082f840f2d4cc6defccbbcda1260de87e58296b37"), 1368888542) )
+ ( 26174, initCheckpoint(uint256("0x00000000006cf1bfaa0d73caea92f6d2afa465651a76415b8d53b0bb0e01a8be"), 1371039324) )
+ ( 27451, initCheckpoint(uint256("0xd65424c24041b9f2e531f8f275f1a3c8bb105f0b29005b0bd577ae1a73341080"), 1371687462) )
+ ( 37092, initCheckpoint(uint256("0x0000000000a38c2f98556f46793b453e92d8fab2d31c0b93fd08bcf78e56099d"), 1376677203) )
;
// TestNet has no checkpoints
static MapCheckpoints mapCheckpointsTestnet =
boost::assign::map_list_of
- ( 0, hashGenesisBlockTestNet )
+ ( 0, initCheckpoint(hashGenesisBlock, 1360105017) )
;
bool CheckHardened(int nHeight, const uint256& hash)
MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
if (i == checkpoints.end()) return true;
- return hash == i->second;
+ return hash == i->second.hashCheckPoint;
}
int GetTotalBlocksEstimate()
return checkpoints.rbegin()->first;
}
+ int GetLastCheckpointTime()
+ {
+ MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
+
+ return checkpoints.rbegin()->second.nTime;
+ }
+
CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
{
MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
{
- const uint256& hash = i.second;
+ const uint256& hash = i.second.hashCheckPoint;
std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
if (t != mapBlockIndex.end())
return t->second;
bool ResetSyncCheckpoint()
{
LOCK(cs_hashSyncCheckpoint);
- const uint256& hash = mapCheckpoints.rbegin()->second;
+ const uint256& hash = mapCheckpoints.rbegin()->second.hashCheckPoint;
if (mapBlockIndex.count(hash) && !mapBlockIndex[hash]->IsInMainChain())
{
// checkpoint block accepted but not yet in main chain
BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
{
- const uint256& hash = i.second;
+ const uint256& hash = i.second.hashCheckPoint;
if (mapBlockIndex.count(hash) && mapBlockIndex[hash]->IsInMainChain())
{
if (!WriteSyncCheckpoint(hash))
// Returns last CBlockIndex* in mapBlockIndex that is a checkpoint
CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex);
+ // Returns last checkpoint timestamp
+ int GetLastCheckpointTime();
+
extern uint256 hashSyncCheckpoint;
extern CSyncCheckpoint checkpointMessage;
extern uint256 hashInvalidCheckpoint;
extern int nStakeMaxAge;
extern int nStakeTargetSpacing;
+typedef std::map<int, unsigned int> MapModifierCheckpoints;
+
// Hard checkpoints of stake modifiers to ensure they are deterministic
static std::map<int, unsigned int> mapStakeModifierCheckpoints =
boost::assign::map_list_of
( 26174, 0xaf9983dcu )
;
+// Hard checkpoints of stake modifiers to ensure they are deterministic (testNet)
+static std::map<int, unsigned int> mapStakeModifierCheckpointsTestNet =
+ boost::assign::map_list_of
+ ( 0, 0x0e00670bu )
+ ;
+
// Get the last stake modifier and its generation time from a given block
static bool GetLastStakeModifier(const CBlockIndex* pindex, uint64& nStakeModifier, int64& nModifierTime)
{
// Check stake modifier hard checkpoints
bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierChecksum)
{
- if (fTestNet) return true; // Testnet has no checkpoints
- if (mapStakeModifierCheckpoints.count(nHeight))
- return nStakeModifierChecksum == mapStakeModifierCheckpoints[nHeight];
+ MapModifierCheckpoints& checkpoints = (fTestNet ? mapStakeModifierCheckpointsTestNet : mapStakeModifierCheckpoints);
+
+ if (checkpoints.count(nHeight))
+ return nStakeModifierChecksum == checkpoints[nHeight];
return true;
}
bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
{
- // Check it again in case a previous version let a bad block in
- if (!CheckBlock(!fJustCheck, !fJustCheck))
+ // Check it again in case a previous version let a bad block in, but skip BlockSig checking
+ if (!CheckBlock(!fJustCheck, !fJustCheck, false))
return false;
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
pindexNew->nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + pindexNew->GetBlockTrust();
// ppcoin: compute stake entropy bit for stake modifier
- if (!pindexNew->SetStakeEntropyBit(GetStakeEntropyBit(pindexNew->nHeight)))
+ if (!pindexNew->SetStakeEntropyBit(GetStakeEntropyBit(pindexNew->nTime)))
return error("AddToBlockIndex() : SetStakeEntropyBit() failed");
// ppcoin: record proof-of-stake hash value
-bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
+bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) const
{
// These are checks that are independent of context
// that can be verified before saving an orphan block.
// Check coinstake timestamp
if (!CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].nTime))
return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%"PRI64d" nTimeTx=%u", GetBlockTime(), vtx[1].nTime));
+
+ // NovaCoin: check proof-of-stake block signature
+ if (fCheckSig && !CheckBlockSignature(true))
+ return DoS(100, error("CheckBlock() : bad proof-of-stake block signature"));
}
else
{
return DoS(50, error("CheckBlock() : coinbase reward exceeded (actual=%"PRI64d" vs calculated=%"PRI64d")",
vtx[0].GetValueOut(),
GetProofOfWorkReward(nBits) - nFee));
+
+ // Should we check proof-of-work block signature or not?
+ //
+ // * Always skip on TestNet
+ // * Perform checking for the first 9689 blocks
+ // * Perform checking since last checkpoint until 20 Sep 2013 (will be removed after)
+
+ if(!fTestNet && fCheckSig)
+ {
+ bool isAfterCheckpoint = (GetBlockTime() > Checkpoints::GetLastCheckpointTime());
+ bool checkEntropySig = (GetBlockTime() < ENTROPY_SWITCH_TIME);
+ bool checkPoWSig = (isAfterCheckpoint && GetBlockTime() < CHAINCHECKS_SWITCH_TIME);
+
+ // NovaCoin: check proof-of-work block signature
+ if ((checkEntropySig || checkPoWSig) && !CheckBlockSignature(false))
+ return DoS(100, error("CheckBlock() : bad proof-of-work block signature"));
+ }
}
// Check transactions
if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree())
return DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"));
- // NovaCoin: check proof-of-stake block signature
- if (IsProofOfStake() || (!fTestNet && GetBlockTime() < CHAINCHECKS_SWITCH_TIME))
- {
- if (!CheckBlockSignature())
- return DoS(100, error("CheckBlock() : bad block signature"));
- }
return true;
}
}
// ppcoin: check block signature
-bool CBlock::CheckBlockSignature() const
+bool CBlock::CheckBlockSignature(bool fProofOfStake) const
{
if (GetHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
return vchBlockSig.empty();
vector<valtype> vSolutions;
txnouttype whichType;
- if(IsProofOfStake())
+ if(fProofOfStake)
{
const CTxOut& txout = vtx[1].vout[1];
static const int64 MAX_MINT_PROOF_OF_WORK = 100 * COIN;
static const int64 MAX_MINT_PROOF_OF_STAKE = 1 * COIN;
static const int64 MIN_TXOUT_AMOUNT = MIN_TX_FEE;
+
+static const unsigned int ENTROPY_SWITCH_TIME = 1362791041; // Sat, 09 Mar 2013 01:04:01 GMT
static const unsigned int STAKE_SWITCH_TIME = 1371686400; // Thu, 20 Jun 2013 00:00:00 GMT
static const unsigned int TARGETS_SWITCH_TIME = 1374278400; // Sat, 20 Jul 2013 00:00:00 GMT
static const unsigned int LOCKS_SWITCH_TIME = 1376956800; // Tue, 20 Aug 2013 00:00:00 GMT
void UpdateTime(const CBlockIndex* pindexPrev);
// ppcoin: entropy bit for stake modifier if chosen by modifier
- unsigned int GetStakeEntropyBit(unsigned int nHeight) const
+ unsigned int GetStakeEntropyBit(unsigned int nTime) const
{
// Protocol switch to support p2pool at novacoin block #9689
- if (nHeight >= 9689 || fTestNet)
+ if (nTime >= ENTROPY_SWITCH_TIME || fTestNet)
{
// Take last bit of block hash as entropy bit
unsigned int nEntropyBit = ((GetHash().Get64()) & 1llu);
if (fDebug && GetBoolArg("-printstakemodifier"))
- printf("GetStakeEntropyBit: nHeight=%u hashBlock=%s nEntropyBit=%u\n", nHeight, GetHash().ToString().c_str(), nEntropyBit);
+ printf("GetStakeEntropyBit: nTime=%u hashBlock=%s nEntropyBit=%u\n", nTime, GetHash().ToString().c_str(), nEntropyBit);
return nEntropyBit;
}
// Before novacoin block #9689 - old protocol
bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew);
bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);
- bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true) const;
+ bool CheckBlock(bool fCheckPOW=true, bool fCheckMerkleRoot=true, bool fCheckSig=true) const;
bool AcceptBlock();
bool GetCoinAge(uint64& nCoinAge) const; // ppcoin: calculate total coin age spent in block
bool SignBlock(const CKeyStore& keystore);
- bool CheckBlockSignature() const;
+ bool CheckBlockSignature(bool fProofOfStake) const;
private:
bool SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew);