diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 8a5e613c7..a26655585 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -28,9 +28,14 @@ using namespace std; */ class CMainParams : public CChainParams { +protected: + Consensus::Params digishieldConsensus; + Consensus::Params auxpowConsensus; public: CMainParams() { strNetworkID = "main"; + + // Blocks 0 - 144999 are conventional difficulty calculation consensus.nSubsidyHalvingInterval = 100000; consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; @@ -39,10 +44,29 @@ public: consensus.nPowTargetTimespan = 4 * 60 * 60; // pre-digishield: 4 hours consensus.nPowTargetSpacing = 60; // 1 minute consensus.fPowAllowMinDifficultyBlocks = false; + consensus.fPowAllowDigishieldMinDifficultyBlocks = false; consensus.nAuxpowChainId = 0x0062; // 98 - Josh Wise! - consensus.nAuxpowStartHeight = 371337; consensus.fStrictChainId = true; - consensus.nLegacyBlocksBefore = 371337; + consensus.fAllowLegacyBlocks = true; + consensus.nHeightEffective = 0; + consensus.fDigishieldDifficultyCalculation = false; + + // Blocks 145000 - 371336 are Digishield without AuxPoW + digishieldConsensus = consensus; + digishieldConsensus.nHeightEffective = 145000; + digishieldConsensus.fDigishieldDifficultyCalculation = true; + digishieldConsensus.nPowTargetTimespan = 60; // post-digishield: 1 minute + + // Blocks 371337+ are AuxPoW + auxpowConsensus = digishieldConsensus; + auxpowConsensus.nHeightEffective = 371337; + auxpowConsensus.fAllowLegacyBlocks = false; + + // Assemble the binary search tree of consensus parameters + pConsensusRoot = &digishieldConsensus; + digishieldConsensus.pLeft = &consensus; + digishieldConsensus.pRight = &auxpowConsensus; + /** * The message start string is designed to be unlikely to occur in normal data. * The characters are rarely used upper ASCII, not valid as UTF-8, and produce @@ -84,6 +108,8 @@ public: genesis.nNonce = 99943; consensus.hashGenesisBlock = genesis.GetHash(); + digishieldConsensus.hashGenesisBlock = consensus.hashGenesisBlock; + auxpowConsensus.hashGenesisBlock = consensus.hashGenesisBlock; assert(consensus.hashGenesisBlock == uint256S("0x1a91e3dace36e2be3bf030a65679fe821aa1d6ef92e7c9902eb318182c355691")); assert(genesis.hashMerkleRoot == uint256S("0x5b2a3f53f605d62c53e62932dac6925e3d74afa5a4b459745c36d42d0ed26a69")); @@ -145,16 +171,53 @@ static CMainParams mainParams; * Testnet (v3) */ class CTestNetParams : public CMainParams { +private: + Consensus::Params minDifficultyConsensus; public: CTestNetParams() { strNetworkID = "test"; + + // Blocks 0 - 144999 are pre-Digishield + consensus.nHeightEffective = 0; + consensus.nPowTargetTimespan = 4 * 60 * 60; // pre-digishield: 4 hours + consensus.fDigishieldDifficultyCalculation = false; + consensus.fPowAllowMinDifficultyBlocks = true; + consensus.fPowAllowDigishieldMinDifficultyBlocks = false; consensus.nMajorityEnforceBlockUpgrade = 51; consensus.nMajorityRejectBlockOutdated = 75; consensus.nMajorityWindow = 100; - consensus.fPowAllowMinDifficultyBlocks = true; - consensus.nAuxpowStartHeight = 158100; consensus.fStrictChainId = false; - consensus.nLegacyBlocksBefore = 158100; + consensus.nHeightEffective = 0; + consensus.fAllowLegacyBlocks = true; + + // Reset links before we copy parameters + consensus.pLeft = NULL; + consensus.pRight = NULL; + + // Blocks 145000 - 157499 are Digishield without minimum difficulty on all blocks + digishieldConsensus = consensus; + digishieldConsensus.nHeightEffective = 145000; + digishieldConsensus.nPowTargetTimespan = 60; // post-digishield: 1 minute + digishieldConsensus.fDigishieldDifficultyCalculation = true; + digishieldConsensus.fPowAllowMinDifficultyBlocks = false; + + // Blocks 157500 - 158099 are Digishield with minimum difficulty on all blocks + minDifficultyConsensus = digishieldConsensus; + minDifficultyConsensus.nHeightEffective = 157500; + minDifficultyConsensus.fPowAllowDigishieldMinDifficultyBlocks = true; + minDifficultyConsensus.fPowAllowMinDifficultyBlocks = true; + + // Enable AuxPoW at 158100 + auxpowConsensus = minDifficultyConsensus; + auxpowConsensus.nHeightEffective = 158100; + auxpowConsensus.fPowAllowDigishieldMinDifficultyBlocks = true; + auxpowConsensus.fAllowLegacyBlocks = false; + + // Assemble the binary search tree of parameters + pConsensusRoot = &digishieldConsensus; + digishieldConsensus.pLeft = &consensus; + digishieldConsensus.pRight = &minDifficultyConsensus; + minDifficultyConsensus.pRight = &auxpowConsensus; pchMessageStart[0] = 0xfc; pchMessageStart[1] = 0xc1; @@ -169,6 +232,9 @@ public: genesis.nTime = 1391503289; genesis.nNonce = 997879; consensus.hashGenesisBlock = genesis.GetHash(); + digishieldConsensus.hashGenesisBlock = consensus.hashGenesisBlock; + minDifficultyConsensus.hashGenesisBlock = consensus.hashGenesisBlock; + auxpowConsensus.hashGenesisBlock = consensus.hashGenesisBlock; assert(consensus.hashGenesisBlock == uint256S("0xbb0a78264637406b6360aad926284d544d7049f45189db5664f3c4d07350559e")); vFixedSeeds.clear(); @@ -215,9 +281,28 @@ public: consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; + consensus.nPowTargetTimespan = 4 * 60 * 60; // pre-digishield: 4 hours consensus.powLimit = uint256S("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1; consensus.fStrictChainId = true; - consensus.nLegacyBlocksBefore = 0; + consensus.fAllowLegacyBlocks = false; // Never allow legacy blocks on RegTest + + // Reset links before we copy parameters + consensus.pLeft = NULL; + consensus.pRight = NULL; + + digishieldConsensus = consensus; + digishieldConsensus.nHeightEffective = 10; + digishieldConsensus.nPowTargetTimespan = 60; // post-digishield: 1 minute + digishieldConsensus.fDigishieldDifficultyCalculation = true; + + auxpowConsensus = digishieldConsensus; + auxpowConsensus.nHeightEffective = 20; + + // Assemble the binary search tree of parameters + digishieldConsensus.pLeft = &consensus; + digishieldConsensus.pRight = &auxpowConsensus; + pConsensusRoot = &digishieldConsensus; + pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0xbf; pchMessageStart[2] = 0xb5; @@ -227,6 +312,8 @@ public: genesis.nBits = 0x207fffff; genesis.nNonce = 2; consensus.hashGenesisBlock = genesis.GetHash(); + digishieldConsensus.hashGenesisBlock = consensus.hashGenesisBlock; + auxpowConsensus.hashGenesisBlock = consensus.hashGenesisBlock; nDefaultPort = 18444; assert(consensus.hashGenesisBlock == uint256S("0x3d2160a3b5dc4a9d62e7e66a295f70313ac808440ef7400d6c0772171ce973a5")); nPruneAfterHeight = 1000; diff --git a/src/chainparams.h b/src/chainparams.h index b9d1c1758..6ddb6072b 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -45,7 +45,24 @@ public: MAX_BASE58_TYPES }; - const Consensus::Params& GetConsensus() const { return consensus; } + const Consensus::Params& GetConsensus(uint32_t nTargetHeight) const { + return *GetConsensus(nTargetHeight, pConsensusRoot); + } + + Consensus::Params *GetConsensus(uint32_t nTargetHeight, Consensus::Params *pRoot) const { + if (nTargetHeight < pRoot -> nHeightEffective && pRoot -> pLeft != NULL) { + return GetConsensus(nTargetHeight, pRoot -> pLeft); + } else if (nTargetHeight > pRoot -> nHeightEffective && pRoot -> pRight != NULL) { + Consensus::Params *pCandidate = GetConsensus(nTargetHeight, pRoot -> pRight); + if (pCandidate->nHeightEffective <= nTargetHeight) { + return pCandidate; + } + } + + // No better match below the target height + return pRoot; + } + const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } const std::vector& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } @@ -76,6 +93,7 @@ protected: CChainParams() {} Consensus::Params consensus; + Consensus::Params *pConsensusRoot; // Binary search tree root CMessageHeader::MessageStartChars pchMessageStart; //! Raw pub key bytes for the broadcast alert signing key. std::vector vAlertPubKey; diff --git a/src/consensus/params.h b/src/consensus/params.h index 873a93d78..f0fdae660 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -25,23 +25,20 @@ struct Params { int64_t nPowTargetSpacing; int64_t nPowTargetTimespan; int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; } - /** Auxpow parameters */ - int32_t nAuxpowChainId; - int nAuxpowStartHeight; - bool fStrictChainId; - int nLegacyBlocksBefore; // -1 for "always allow" - /** - * Check whether or not to allow legacy blocks at the given height. - * @param nHeight Height of the block to check. - * @return True if it is allowed to have a legacy version. - */ - bool AllowLegacyBlocks(unsigned nHeight) const - { - if (nLegacyBlocksBefore < 0) - return true; - return static_cast (nHeight) < nLegacyBlocksBefore; - } + /** Dogecoin-specific parameters */ + bool fDigishieldDifficultyCalculation; + bool fPowAllowDigishieldMinDifficultyBlocks; // Allow minimum difficulty blocks where a retarget would normally occur + + /** Auxpow parameters */ + int16_t nAuxpowChainId; + bool fStrictChainId; + bool fAllowLegacyBlocks; + + /** Height-aware consensus parameters */ + uint32_t nHeightEffective; // When these parameters come into use + struct Params *pLeft; // Left hand branch + struct Params *pRight; // Right hand branch }; } // namespace Consensus diff --git a/src/dogecoin.cpp b/src/dogecoin.cpp index dd394d5b4..6916982e0 100644 --- a/src/dogecoin.cpp +++ b/src/dogecoin.cpp @@ -16,21 +16,34 @@ int static generateMTRandom(unsigned int s, int range) return dist(gen); } +// Dogecoin: Normally minimum difficulty blocks can only occur in between +// retarget blocks. However, once we introduce Digishield every block is +// a retarget, so we need to handle minimum difficulty on all blocks. +bool AllowDigishieldMinDifficultyForBlock(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) +{ + // check if the chain allows minimum difficulty blocks + if (!params.fPowAllowMinDifficultyBlocks) + return false; + + // check if the chain allows minimum difficulty blocks on recalc blocks + if (pindexLast->nHeight < 157500) + // if (!params.fPowAllowDigishieldMinDifficultyBlocks) + return false; + + // Allow for a minimum block time if the elapsed time > 2*nTargetSpacing + return (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2); +} + unsigned int CalculateDogecoinNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params) { int nHeight = pindexLast->nHeight + 1; - bool fNewDifficultyProtocol = (nHeight >= 145000); - // bool fNewDifficultyProtocol = (nHeight >= params.GetDigiShieldForkBlock()); - const int64_t retargetTimespan = fNewDifficultyProtocol ? 60 // params.DigiShieldTargetTimespan() - : - params.nPowTargetTimespan; - + const int64_t retargetTimespan = params.nPowTargetTimespan; const int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime; int64_t nModulatedTimespan = nActualTimespan; int64_t nMaxTimespan; int64_t nMinTimespan; - if (fNewDifficultyProtocol) //DigiShield implementation - thanks to RealSolid & WDC for this code + if (params.fDigishieldDifficultyCalculation) //DigiShield implementation - thanks to RealSolid & WDC for this code { // amplitude filter - thanks to daft27 for this code nModulatedTimespan = retargetTimespan + (nModulatedTimespan - retargetTimespan) / 8; @@ -66,12 +79,6 @@ unsigned int CalculateDogecoinNextWorkRequired(const CBlockIndex* pindexLast, in if (bnNew > bnPowLimit) bnNew = bnPowLimit; - /// debug print - LogPrintf("GetNextWorkRequired RETARGET\n"); - LogPrintf("params.nPowTargetTimespan = %d nActualTimespan = %d\n", params.nPowTargetTimespan, nActualTimespan); - LogPrintf("Before: %08x %s\n", pindexLast->nBits, bnOld.ToString()); - LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); - return bnNew.GetCompact(); } diff --git a/src/dogecoin.h b/src/dogecoin.h index edc07b5f5..e466d1e98 100644 --- a/src/dogecoin.h +++ b/src/dogecoin.h @@ -6,6 +6,7 @@ #include "chain.h" #include "chainparams.h" +bool AllowDigishieldMinDifficultyForBlock(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params); CAmount GetDogecoinBlockSubsidy(int nHeight, const Consensus::Params& consensusParams, uint256 prevHash); unsigned int CalculateDogecoinNextWorkRequired(const CBlockIndex* pindexLast, int64_t nLastRetargetTime, const Consensus::Params& params); diff --git a/src/init.cpp b/src/init.cpp index 0923dcb3a..fa8e4317e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1150,7 +1150,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // If the loaded chain has a wrong genesis, bail out immediately // (we're likely using a testnet datadir, or the other way around). - if (!mapBlockIndex.empty() && mapBlockIndex.count(chainparams.GetConsensus().hashGenesisBlock) == 0) + if (!mapBlockIndex.empty() && mapBlockIndex.count(chainparams.GetConsensus(0).hashGenesisBlock) == 0) return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); // Initialize the block index (no-op if non-empty database was already loaded) diff --git a/src/main.cpp b/src/main.cpp index 39b97d1d6..a5a8db09e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1182,7 +1182,7 @@ static bool ReadBlockOrHeader(T& block, const CDiskBlockPos& pos) } // Check the header - if (!CheckAuxPowProofOfWork(block, Params().GetConsensus())) + if (!CheckAuxPowProofOfWork(block, Params().GetConsensus(0))) // FIXME: Can we get height at all? return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); return true; @@ -1800,6 +1800,7 @@ static int64_t nTimeTotal = 0; bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) { const CChainParams& chainparams = Params(); + const Consensus::Params consensus = chainparams.GetConsensus(pindex->nHeight); AssertLockHeld(cs_main); // Check it again in case a previous version let a bad block in if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) @@ -1811,7 +1812,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Special case for the genesis block, skipping connection of its transactions // (its coinbase is unspendable) - if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) { + if (block.GetHash() == consensus.hashGenesisBlock) { if (!fJustCheck) view.SetBestBlock(pindex->GetBlockHash()); return true; @@ -1850,7 +1851,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE; // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, when 75% of the network has upgraded: - if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { + if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, consensus.nMajorityEnforceBlockUpgrade, consensus)) { flags |= SCRIPT_VERIFY_DERSIG; } @@ -1913,7 +1914,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart; LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001); - CAmount blockReward = nFees + GetDogecoinBlockSubsidy(pindex->nHeight, chainparams.GetConsensus(), hashPrevBlock); + CAmount blockReward = nFees + GetDogecoinBlockSubsidy(pindex->nHeight, consensus, hashPrevBlock); if (block.vtx[0].GetValueOut() > blockReward) return state.DoS(100, error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", @@ -2667,7 +2668,7 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW) { // Check proof of work matches claimed amount - if (fCheckPOW && !CheckAuxPowProofOfWork(block, Params().GetConsensus())) + if (fCheckPOW && !CheckAuxPowProofOfWork(block, Params().GetConsensus(0))) // FIXME: Get actual height return state.DoS(50, error("CheckBlockHeader(): proof of work failed"), REJECT_INVALID, "high-hash"); @@ -2742,7 +2743,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev) { const CChainParams& chainParams = Params(); - const Consensus::Params& consensusParams = chainParams.GetConsensus(); + const Consensus::Params& consensusParams = chainParams.GetConsensus(pindexPrev->nHeight + 1); uint256 hash = block.GetHash(); if (hash == consensusParams.hashGenesisBlock) return true; @@ -2752,15 +2753,15 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta int nHeight = pindexPrev->nHeight+1; // Disallow legacy blocks after merge-mining start. - if (!Params().GetConsensus().AllowLegacyBlocks(nHeight) + if (!consensusParams.fAllowLegacyBlocks && block.nVersion.IsLegacy()) - return state.DoS(100, error("%s : legacy block after auxpow start", - __func__), + return state.DoS(100, error("%s : legacy block after auxpow start at height %d, parameters effective from %d", + __func__, pindexPrev->nHeight + 1, consensusParams.nHeightEffective), REJECT_INVALID, "late-legacy-block"); // Check proof of work if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) - return state.DoS(100, error("%s: incorrect proof of work", __func__), + return state.DoS(100, error("%s: incorrect proof of work at height %d", __func__, nHeight), REJECT_INVALID, "bad-diffbits"); // Check timestamp against prev @@ -2797,7 +2798,6 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex * const pindexPrev) { const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; - const Consensus::Params& consensusParams = Params().GetConsensus(); // Check that all transactions are finalized BOOST_FOREACH(const CTransaction& tx, block.vtx) @@ -2807,7 +2807,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): - if (block.nVersion >= 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams)) + // Dogecoin: Block v2 was never enforced + if (block.nVersion >= 3) { CScript expect = CScript() << nHeight; if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || @@ -2842,7 +2843,7 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc // Get prev block index CBlockIndex* pindexPrev = NULL; - if (hash != chainparams.GetConsensus().hashGenesisBlock) { + if (hash != chainparams.GetConsensus(0).hashGenesisBlock) { BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); if (mi == mapBlockIndex.end()) return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk"); @@ -3485,7 +3486,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) // detect out of order blocks, and store them for later uint256 hash = block.GetHash(); - if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { + if (hash != chainparams.GetConsensus(0).hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { LogPrint("reindex", "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(), block.hashPrevBlock.ToString()); if (dbp) @@ -3500,7 +3501,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) nLoaded++; if (state.IsError()) break; - } else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { + } else if (hash != chainparams.GetConsensus(0).hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); } @@ -3542,7 +3543,6 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) void static CheckBlockIndex() { - const Consensus::Params& consensusParams = Params().GetConsensus(); if (!fCheckBlockIndex) { return; } @@ -3557,6 +3557,7 @@ void static CheckBlockIndex() return; } + // Build forward-pointing map of the entire block tree. std::multimap forward; for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) { @@ -3583,6 +3584,7 @@ void static CheckBlockIndex() CBlockIndex* pindexFirstNotChainValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN (regardless of being valid or not). CBlockIndex* pindexFirstNotScriptsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS (regardless of being valid or not). while (pindex != NULL) { + const Consensus::Params& consensusParams = Params().GetConsensus(nHeight); nNodes++; if (pindexFirstInvalid == NULL && pindex->nStatus & BLOCK_FAILED_VALID) pindexFirstInvalid = pindex; if (pindexFirstMissing == NULL && !(pindex->nStatus & BLOCK_HAVE_DATA)) pindexFirstMissing = pindex; @@ -3816,8 +3818,8 @@ bool static AlreadyHave(const CInv& inv) void static ProcessGetData(CNode* pfrom) { std::deque::iterator it = pfrom->vRecvGetData.begin(); - vector vNotFound; + const Consensus::Params &consensus = Params().GetConsensus(chainActive.Height()); LOCK(cs_main); @@ -3846,7 +3848,7 @@ void static ProcessGetData(CNode* pfrom) // best equivalent proof of work) than the best header chain we know about. send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) && - (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, Params().GetConsensus()) < nOneMonth); + (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, consensus) < nOneMonth); if (!send) { LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId()); } @@ -4208,12 +4210,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // not a direct successor. pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexBestHeader), inv.hash); CNodeState *nodestate = State(pfrom->GetId()); - if (chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - chainparams.GetConsensus().nPowTargetSpacing * 20 && + if (chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - chainparams.GetConsensus(chainActive.Height()).nPowTargetSpacing * 20 && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { vToFetch.push_back(inv); // Mark block as in flight already, even though the actual "getdata" message only goes out // later (within the same cs_main lock, though). - MarkBlockAsInFlight(pfrom->GetId(), inv.hash, chainparams.GetConsensus()); + MarkBlockAsInFlight(pfrom->GetId(), inv.hash, chainparams.GetConsensus(chainActive.Height())); } LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); } @@ -4876,7 +4878,7 @@ bool ProcessMessages(CNode* pfrom) bool SendMessages(CNode* pto, bool fSendTrickle) { - const Consensus::Params& consensusParams = Params().GetConsensus(); + const Consensus::Params& consensusParams = Params().GetConsensus(chainActive.Height()); { // Don't send anything until we get its version message if (pto->nVersion == 0) diff --git a/src/miner.cpp b/src/miner.cpp index f83f43ceb..70968ee50 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -328,15 +328,16 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); // Compute final coinbase transaction. - txNew.vout[0].nValue = nFees + GetDogecoinBlockSubsidy(nHeight, chainparams.GetConsensus(), pindexPrev->GetBlockHash()); + const Consensus::Params &consensus = chainparams.GetConsensus(nHeight); + txNew.vout[0].nValue = nFees + GetDogecoinBlockSubsidy(nHeight, consensus, pindexPrev->GetBlockHash()); txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; pblock->vtx[0] = txNew; pblocktemplate->vTxFees[0] = -nFees; // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - UpdateTime(pblock, Params().GetConsensus(), pindexPrev); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); + UpdateTime(pblock, consensus, pindexPrev); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensus); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); @@ -482,6 +483,7 @@ void static BitcoinMiner(CWallet *pwallet) // unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrev = chainActive.Tip(); + const Consensus::Params &consensus = Params().GetConsensus(pindexPrev -> nHeight + 1); auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); if (!pblocktemplate.get()) @@ -540,8 +542,8 @@ void static BitcoinMiner(CWallet *pwallet) break; // Update nTime every few seconds - UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); - if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) + UpdateTime(pblock, consensus, pindexPrev); + if (consensus.fPowAllowMinDifficultyBlocks) { // Changing pblock->nTime can change work required on testnet: hashTarget.SetCompact(pblock->nBits); diff --git a/src/pow.cpp b/src/pow.cpp index 44eee9c35..772e11f2f 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -12,6 +12,22 @@ #include "uint256.h" #include "util.h" +// Determine if the for the given block, a min difficulty setting applies +bool AllowMinDifficultyForBlock(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) +{ + // check if the chain allows minimum difficulty blocks + if (!params.fPowAllowMinDifficultyBlocks) + return false; + + // Dogecoin: Magic number at which reset protocol switches + // check if we allow minimum difficulty at this block-height + if (pindexLast->nHeight < 157500) + return false; + + // Allow for a minimum block time if the elapsed time > 2*nTargetSpacing + return (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2); +} + unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact(); @@ -20,6 +36,15 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead if (pindexLast == NULL) return nProofOfWorkLimit; + // Dogecoin: Special rules for minimum difficulty blocks with Digishield + if (AllowDigishieldMinDifficultyForBlock(pindexLast, pblock, params)) + { + // Special difficulty rule for testnet: + // If the new block's timestamp is more than 2* nTargetSpacing minutes + // then allow mining of a min-difficulty block. + return nProofOfWorkLimit; + } + // Only change once per difficulty adjustment interval if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0) { @@ -55,7 +80,6 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF { // Limit adjustment step int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime; - LogPrintf(" nActualTimespan = %d before bounds\n", nActualTimespan); if (nActualTimespan < params.nPowTargetTimespan/4) nActualTimespan = params.nPowTargetTimespan/4; if (nActualTimespan > params.nPowTargetTimespan*4) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 7eee8bb05..e0ba823de 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -47,7 +47,7 @@ Value GetNetworkHashPS(int lookup, int height) { // If lookup is -1, then use blocks since last difficulty change. if (lookup <= 0) - lookup = pb->nHeight % Params().GetConsensus().DifficultyAdjustmentInterval() + 1; + lookup = pb->nHeight % Params().GetConsensus(pb->nHeight).DifficultyAdjustmentInterval() + 1; // If lookup is larger than chain, then set it to chain length. if (lookup > pb->nHeight) @@ -159,7 +159,7 @@ Value generate(const Array& params, bool fHelp) LOCK(cs_main); IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); } - while (!CheckProofOfWork(pblock->GetPoWHash(), pblock->nBits, Params().GetConsensus())) { + while (!CheckProofOfWork(pblock->GetPoWHash(), pblock->nBits, Params().GetConsensus(nHeight))) { // Yes, there is a chance every nonce could fail to satisfy the -regtest // target -- 1 in 2^(2^32). That ain't gonna happen. ++pblock->nNonce; @@ -518,7 +518,7 @@ Value getblocktemplate(const Array& params, bool fHelp) CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Update nTime - UpdateTime(pblock, Params().GetConsensus(), pindexPrev); + UpdateTime(pblock, Params().GetConsensus(pindexPrev->nHeight), pindexPrev); pblock->nNonce = 0; static const Array aCaps = boost::assign::list_of("proposal"); @@ -773,14 +773,6 @@ Value getauxblock(const Array& params, bool fHelp) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Namecoin is downloading blocks..."); - /* This should never fail, since the chain is already - past the point of merge-mining start. Check nevertheless. */ - { - LOCK(cs_main); - if (chainActive.Height() + 1 < Params().GetConsensus().nAuxpowStartHeight) - throw std::runtime_error("getauxblock method is not yet available"); - } - /* The variables below are used to keep track of created and not yet submitted auxpow blocks. Lock them, just in case. In principle there's only one RPC thread, so it should be fine without locking diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index 0eda2ca1a..915326d4c 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -203,7 +203,7 @@ BOOST_AUTO_TEST_CASE(PartitionAlert) CCriticalSection csDummy; CBlockIndex indexDummy[800]; CChainParams& params = Params(CBaseChainParams::MAIN); - int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing; + int64_t nPowTargetSpacing = params.GetConsensus(0).nPowTargetSpacing; // Generate fake blockchain timestamps relative to // an arbitrary time: diff --git a/src/test/auxpow_tests.cpp b/src/test/auxpow_tests.cpp index 566c88feb..24c0bf263 100644 --- a/src/test/auxpow_tests.cpp +++ b/src/test/auxpow_tests.cpp @@ -180,7 +180,7 @@ CAuxpowBuilder::buildCoinbaseData(bool header, const std::vector& BOOST_AUTO_TEST_CASE(check_auxpow) { - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = Params().GetConsensus(371337); CAuxpowBuilder builder(5, 42); CAuxPow auxpow; @@ -339,16 +339,16 @@ mineBlock(CBlockHeader& block, bool ok, int nBits = -1) } if (ok) - BOOST_CHECK(CheckProofOfWork(block.GetPoWHash(), nBits, Params().GetConsensus())); + BOOST_CHECK(CheckProofOfWork(block.GetPoWHash(), nBits, Params().GetConsensus(371337))); else - BOOST_CHECK(!CheckProofOfWork(block.GetPoWHash(), nBits, Params().GetConsensus())); + BOOST_CHECK(!CheckProofOfWork(block.GetPoWHash(), nBits, Params().GetConsensus(371337))); } BOOST_AUTO_TEST_CASE(auxpow_pow) { /* Use regtest parameters to allow mining with easy difficulty. */ SelectParams(CBaseChainParams::REGTEST); - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = Params().GetConsensus(371337); const arith_uint256 target = (~arith_uint256(0) >> 1); CBlockHeader block; diff --git a/src/test/dogecoin_tests.cpp b/src/test/dogecoin_tests.cpp index 4a8d08089..7185b377a 100644 --- a/src/test/dogecoin_tests.cpp +++ b/src/test/dogecoin_tests.cpp @@ -63,7 +63,7 @@ BOOST_AUTO_TEST_CASE(subsidy_limit_test) { int nHeight = 0; int nStepSize= 1; - const Consensus::Params& params = Params(CBaseChainParams::MAIN).GetConsensus(); + const Consensus::Params& params = Params(CBaseChainParams::MAIN).GetConsensus(0); CAmount nSum = 0; uint256 prevHash = uint256S("0"); @@ -105,7 +105,7 @@ BOOST_AUTO_TEST_CASE(subsidy_limit_test) BOOST_AUTO_TEST_CASE(get_next_work_difficulty_limit) { SelectParams(CBaseChainParams::MAIN); - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = Params().GetConsensus(0); CBlockIndex pindexLast; int64_t nLastRetargetTime = 1386474927; // Block # 1 @@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_difficulty_limit) BOOST_AUTO_TEST_CASE(get_next_work_pre_digishield) { SelectParams(CBaseChainParams::MAIN); - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = Params().GetConsensus(0); CBlockIndex pindexLast; int64_t nLastRetargetTime = 1386942008; // Block 9359 @@ -133,7 +133,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_pre_digishield) BOOST_AUTO_TEST_CASE(get_next_work_digishield) { SelectParams(CBaseChainParams::MAIN); - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = Params().GetConsensus(145000); CBlockIndex pindexLast; int64_t nLastRetargetTime = 1395094427; @@ -148,7 +148,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_digishield) BOOST_AUTO_TEST_CASE(get_next_work_digishield_modulated_upper) { SelectParams(CBaseChainParams::MAIN); - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = Params().GetConsensus(145000); CBlockIndex pindexLast; int64_t nLastRetargetTime = 1395100835; @@ -163,7 +163,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_digishield_modulated_upper) BOOST_AUTO_TEST_CASE(get_next_work_digishield_modulated_lower) { SelectParams(CBaseChainParams::MAIN); - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = Params().GetConsensus(145000); CBlockIndex pindexLast; int64_t nLastRetargetTime = 1395380517; @@ -178,7 +178,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_digishield_modulated_lower) BOOST_AUTO_TEST_CASE(get_next_work_digishield_rounding) { SelectParams(CBaseChainParams::MAIN); - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = Params().GetConsensus(145000); CBlockIndex pindexLast; int64_t nLastRetargetTime = 1395094679; @@ -191,4 +191,40 @@ BOOST_AUTO_TEST_CASE(get_next_work_digishield_rounding) BOOST_CHECK_EQUAL(CalculateDogecoinNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1b6558a4); } +BOOST_AUTO_TEST_CASE(hardfork_parameters) +{ + SelectParams(CBaseChainParams::MAIN); + const Consensus::Params& initialParams = Params().GetConsensus(0); + + BOOST_CHECK_EQUAL(initialParams.nPowTargetTimespan, 14400); + BOOST_CHECK_EQUAL(initialParams.fAllowLegacyBlocks, true); + BOOST_CHECK_EQUAL(initialParams.fDigishieldDifficultyCalculation, false); + + const Consensus::Params& initialParamsEnd = Params().GetConsensus(144999); + BOOST_CHECK_EQUAL(initialParamsEnd.nPowTargetTimespan, 14400); + BOOST_CHECK_EQUAL(initialParamsEnd.fAllowLegacyBlocks, true); + BOOST_CHECK_EQUAL(initialParamsEnd.fDigishieldDifficultyCalculation, false); + + const Consensus::Params& digishieldParams = Params().GetConsensus(145000); + BOOST_CHECK_EQUAL(digishieldParams.nPowTargetTimespan, 60); + BOOST_CHECK_EQUAL(digishieldParams.fAllowLegacyBlocks, true); + BOOST_CHECK_EQUAL(digishieldParams.fDigishieldDifficultyCalculation, true); + + const Consensus::Params& digishieldParamsEnd = Params().GetConsensus(371336); + BOOST_CHECK_EQUAL(digishieldParamsEnd.nPowTargetTimespan, 60); + BOOST_CHECK_EQUAL(digishieldParamsEnd.fAllowLegacyBlocks, true); + BOOST_CHECK_EQUAL(digishieldParamsEnd.fDigishieldDifficultyCalculation, true); + + const Consensus::Params& auxpowParams = Params().GetConsensus(371337); + BOOST_CHECK_EQUAL(auxpowParams.nHeightEffective, 371337); + BOOST_CHECK_EQUAL(auxpowParams.nPowTargetTimespan, 60); + BOOST_CHECK_EQUAL(auxpowParams.fAllowLegacyBlocks, false); + BOOST_CHECK_EQUAL(auxpowParams.fDigishieldDifficultyCalculation, true); + + const Consensus::Params& auxpowHighParams = Params().GetConsensus(700000); // Arbitrary point after last hard-fork + BOOST_CHECK_EQUAL(auxpowHighParams.nPowTargetTimespan, 60); + BOOST_CHECK_EQUAL(auxpowHighParams.fAllowLegacyBlocks, false); + BOOST_CHECK_EQUAL(auxpowHighParams.fDigishieldDifficultyCalculation, true); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index fad447362..fcd86c3d5 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -18,7 +18,7 @@ BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup) /* BOOST_AUTO_TEST_CASE(get_next_work) { SelectParams(CBaseChainParams::MAIN); - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = Params().GetConsensus(0); int64_t nLastRetargetTime = 1261130161; // Block #30240 CBlockIndex pindexLast; @@ -33,7 +33,7 @@ BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup) /* BOOST_AUTO_TEST_CASE(get_next_work_pow_limit) { SelectParams(CBaseChainParams::MAIN); - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = Params().GetConsensus(0); int64_t nLastRetargetTime = 1231006505; // Block #0 CBlockIndex pindexLast; @@ -48,7 +48,7 @@ BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup) /* BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual) { SelectParams(CBaseChainParams::MAIN); - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = Params().GetConsensus(0); int64_t nLastRetargetTime = 1279008237; // Block #66528 CBlockIndex pindexLast; @@ -63,7 +63,7 @@ BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup) /* BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual) { SelectParams(CBaseChainParams::MAIN); - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = Params().GetConsensus(0); int64_t nLastRetargetTime = 1263163443; // NOTE: Not an actual block time CBlockIndex pindexLast; @@ -76,7 +76,7 @@ BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) { SelectParams(CBaseChainParams::MAIN); - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = Params().GetConsensus(0); std::vector blocks(10000); for (int i = 0; i < 10000; i++) {