diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 4c031c0b5..46ddc27cd 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -82,6 +82,7 @@ class CMainParams : public CChainParams { consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 2.5 * 60; + consensus.nPosTargetSpacing = consensus.nPowTargetSpacing * 9 + 60; consensus.nBtcPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; @@ -204,6 +205,7 @@ class CTestNetParams : public CChainParams { consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 2.5 * 60; + consensus.nPosTargetSpacing = consensus.nPowTargetSpacing * 9 + 60; consensus.nBtcPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = false; @@ -315,6 +317,7 @@ class CRegTestParams : public CChainParams { consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetSpacing = 2.5 * 60; + consensus.nPosTargetSpacing = consensus.nPowTargetSpacing * 9 + 60; consensus.nBtcPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = true; diff --git a/src/consensus/params.h b/src/consensus/params.h index dfc9accf2..6badfd522 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -62,6 +62,7 @@ struct Params { bool fPowAllowMinDifficultyBlocks; bool fPowNoRetargeting; int64_t nPowTargetSpacing; + int64_t nPosTargetSpacing; int64_t nBtcPowTargetSpacing; int64_t nPowTargetTimespan; int64_t DifficultyAdjustmentInterval() const { return 1; } diff --git a/src/miner.cpp b/src/miner.cpp index 0ac174eb9..475cf5b94 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -187,15 +187,15 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc pblock->nNonce = 0; pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]); - CValidationState state; - if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { - throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); - } - int64_t nTime2 = GetTimeMicros(); - if (nHeight > chainparams.GetConsensus().posHeight && !(nHeight % 10)) pblock->nVersion |= VERSIONBITS_POS; - + else { + CValidationState state; + if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { + throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); + } + } + int64_t nTime2 = GetTimeMicros(); LogPrint(BCLog::BENCH, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n", 0.001 * (nTime1 - nTimeStart), nPackagesSelected, nDescendantsUpdated, 0.001 * (nTime2 - nTime1), 0.001 * (nTime2 - nTimeStart)); diff --git a/src/pow.cpp b/src/pow.cpp index 3468e8cd6..742801750 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -12,10 +12,18 @@ static const int64_t DGWPastBlocksMax = 24; +const CBlockIndex* GetPrevPoS(const CBlockIndex* pindexLast, const Consensus::Params& params) { + auto cur = pindexLast; + while (cur != nullptr && cur->nHeight % 10) { + cur = cur->pprev; + } + return cur->nHeight > params.posHeight ? cur : nullptr; +} + static unsigned int DarkGravityWave(const CBlockIndex* pindexLast, const Consensus::Params& params, bool isHardfork) { /* current difficulty formula, dash - DarkGravity v3, written by Evan Duffield - evan@dash.org */ + if (pindexLast == nullptr) return UintToArith256(params.powLimit).GetCompact(); const CBlockIndex *BlockLastSolved = pindexLast; - const CBlockIndex *BlockReading = pindexLast; int64_t nActualTimespan = 0; int64_t LastBlockTime = 0; int64_t PastBlocksMin = 24; @@ -24,10 +32,19 @@ static unsigned int DarkGravityWave(const CBlockIndex* pindexLast, const Consens arith_uint256 PastDifficultyAverage; arith_uint256 PastDifficultyAveragePrev; - if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin) { + bool isNextPoS = !((pindexLast->nHeight + 1) % 10); + bool isPoSPeriod = (pindexLast->nHeight) > params.posHeight; + + if (BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin || + (isPoSPeriod && isNextPoS && (BlockLastSolved->nHeight - params.posHeight) / 10 < PastBlocksMin)) { return UintToArith256(params.powLimit).GetCompact(); } + + if (isPoSPeriod && isNextPoS) {BlockLastSolved = GetPrevPoS(pindexLast, params); } + const CBlockIndex *BlockReading = BlockLastSolved; + + for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) { if (PastBlocksMax > 0 && i > PastBlocksMax) { break; } CountBlocks++; @@ -45,13 +62,16 @@ static unsigned int DarkGravityWave(const CBlockIndex* pindexLast, const Consens LastBlockTime = BlockReading->GetBlockTime(); if (BlockReading->pprev == NULL) { assert(BlockReading); break; } - BlockReading = BlockReading->pprev; + BlockReading = isPoSPeriod ? + isNextPoS ? GetPrevPoS(BlockReading, params) : + BlockReading->pprev->IsProofOfStake() ? BlockReading->pprev->pprev : BlockReading->pprev + : BlockReading->pprev; } arith_uint256 bnNew(PastDifficultyAverage); - const auto powTargetSpacing = isHardfork ? params.nPowTargetSpacing : params.nBtcPowTargetSpacing; - int64_t _nTargetTimespan = CountBlocks * powTargetSpacing; + const auto targetSpacing = isHardfork ? isNextPoS && isPoSPeriod ? params.nPosTargetSpacing : params.nPowTargetSpacing : params.nBtcPowTargetSpacing; + int64_t _nTargetTimespan = (CountBlocks ? CountBlocks : 1) * targetSpacing; if (nActualTimespan < _nTargetTimespan/3) nActualTimespan = _nTargetTimespan/3; diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 0126f152e..ccdd8d980 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -134,8 +134,9 @@ UniValue generateBlocks(std::shared_ptr coinbaseScript, int nGen if (pwallet == nullptr) throw JSONRPCError(RPC_INTERNAL_ERROR, "No wallet for staking"); --nMaxTries; - if (!CreatePoSBlock(pblock, *pwallet)) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed to create PoS block"); + if (!CreatePoSBlock(pblock, *pwallet)) { + continue; + } } else { while (nMaxTries > 0 && pblock->nNonce < nInnerLoopCount && !CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { ++pblock->nNonce; diff --git a/src/validation.cpp b/src/validation.cpp index 7022eac1f..0b91f3fad 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1841,6 +1841,11 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd REJECT_INVALID, "bad-expected-pos"); } + if (pindex->nHeight % 10 && block.IsProofOfStake()) { + return state.DoS(1, error("ConnectBlock(): expected PoW block on height %d", pindex->nHeight), + REJECT_INVALID, "bad-expected-pos"); + } + // verify that the view's current state corresponds to the previous block uint256 hashPrevBlock = pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash(); assert(hashPrevBlock == view.GetBestBlock());