From 5043313a037be9aa7c15f873b40515b927c694af Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 17 Aug 2013 01:46:30 +0400 Subject: [PATCH] Minor optimization * Timestamp field added into checkpoints table * Skip header signature checking while connecting block (it's safe because ProcessBlock still performs signatures checking) * Skip PoW header ECDSA signatures validation since block #9689 until last checkpoint --- src/checkpoints.cpp | 50 ++++++++++++++++++++++++++++++++++---------------- src/checkpoints.h | 3 +++ src/kernel.cpp | 15 ++++++++++++--- src/main.cpp | 39 +++++++++++++++++++++++++++------------ src/main.h | 12 +++++++----- 5 files changed, 83 insertions(+), 36 deletions(-) diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index a1a1dc4..1fe5177 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -13,7 +13,18 @@ namespace Checkpoints { - typedef std::map MapCheckpoints; + struct Checkpoint + { + uint256 hashCheckPoint; + unsigned int nTime; + }; + + typedef std::map MapCheckpoints; + + Checkpoint initCheckpoint(uint256 hashCheckPoint, unsigned int nTime) + { + return {hashCheckPoint, nTime}; + } // // What makes a good checkpoint block? @@ -24,22 +35,22 @@ namespace Checkpoints // 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) @@ -48,7 +59,7 @@ namespace Checkpoints MapCheckpoints::const_iterator i = checkpoints.find(nHeight); if (i == checkpoints.end()) return true; - return hash == i->second; + return hash == i->second.hashCheckPoint; } int GetTotalBlocksEstimate() @@ -58,13 +69,20 @@ namespace Checkpoints return checkpoints.rbegin()->first; } + int GetLastCheckpointTime() + { + MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); + + return checkpoints.rbegin()->second.nTime; + } + CBlockIndex* GetLastCheckpoint(const std::map& 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::const_iterator t = mapBlockIndex.find(hash); if (t != mapBlockIndex.end()) return t->second; @@ -254,7 +272,7 @@ namespace Checkpoints 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 @@ -279,7 +297,7 @@ namespace Checkpoints 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)) diff --git a/src/checkpoints.h b/src/checkpoints.h index 4f5db11..1074cd2 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -28,6 +28,9 @@ namespace Checkpoints // Returns last CBlockIndex* in mapBlockIndex that is a checkpoint CBlockIndex* GetLastCheckpoint(const std::map& mapBlockIndex); + // Returns last checkpoint timestamp + int GetLastCheckpointTime(); + extern uint256 hashSyncCheckpoint; extern CSyncCheckpoint checkpointMessage; extern uint256 hashInvalidCheckpoint; diff --git a/src/kernel.cpp b/src/kernel.cpp index b98b7ba..0a0ef9d 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -12,6 +12,8 @@ using namespace std; extern int nStakeMaxAge; extern int nStakeTargetSpacing; +typedef std::map MapModifierCheckpoints; + // Hard checkpoints of stake modifiers to ensure they are deterministic static std::map mapStakeModifierCheckpoints = boost::assign::map_list_of @@ -24,6 +26,12 @@ static std::map mapStakeModifierCheckpoints = ( 26174, 0xaf9983dcu ) ; +// Hard checkpoints of stake modifiers to ensure they are deterministic (testNet) +static std::map 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) { @@ -394,8 +402,9 @@ unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex) // 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; } diff --git a/src/main.cpp b/src/main.cpp index 8a562dd..daa7f7d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1585,8 +1585,8 @@ bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex) 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, @@ -2042,7 +2042,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) 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 @@ -2099,7 +2099,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) -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. @@ -2161,6 +2161,10 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const // 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 { @@ -2172,6 +2176,23 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const 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 @@ -2207,12 +2228,6 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const 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; } @@ -2563,7 +2578,7 @@ bool CBlock::SignBlock(const CKeyStore& keystore) } // ppcoin: check block signature -bool CBlock::CheckBlockSignature() const +bool CBlock::CheckBlockSignature(bool fProofOfStake) const { if (GetHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)) return vchBlockSig.empty(); @@ -2571,7 +2586,7 @@ bool CBlock::CheckBlockSignature() const vector vSolutions; txnouttype whichType; - if(IsProofOfStake()) + if(fProofOfStake) { const CTxOut& txout = vtx[1].vout[1]; diff --git a/src/main.h b/src/main.h index 0e2af16..7a2b9dc 100644 --- a/src/main.h +++ b/src/main.h @@ -36,6 +36,8 @@ static const int64 MAX_MONEY = 2000000000 * COIN; 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 @@ -925,15 +927,15 @@ public: 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 @@ -1103,11 +1105,11 @@ public: 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); -- 1.7.1