diff --git a/src/main.cpp b/src/main.cpp index c7ba15ef1..ddc37ea53 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1420,25 +1420,6 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state } } -void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev) -{ - block.nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - - // Updating time can change work required on testnet: - if (Params().AllowMinDifficultyBlocks()) - block.nBits = GetNextWorkRequired(pindexPrev, &block); -} - - - - - - - - - - - void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight) { bool ret; @@ -2435,12 +2416,7 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex return state.DoS(100, error("CheckBlockHeader() : block with timestamp before last checkpoint"), REJECT_CHECKPOINT, "time-too-old"); } - bool fOverflow = false; - uint256 bnNewBlock; - bnNewBlock.SetCompact(block.nBits, NULL, &fOverflow); - uint256 bnRequired; - bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); - if (fOverflow || bnNewBlock > bnRequired) + if (!CheckMinWork(block.nBits, pcheckpoint->nBits, deltaTime)) { return state.DoS(100, error("CheckBlockHeader() : block with too little proof-of-work"), REJECT_INVALID, "bad-diffbits"); @@ -3297,15 +3273,6 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) return nLoaded > 0; } - - - - - - - - - ////////////////////////////////////////////////////////////////////////////// // // CAlert diff --git a/src/main.h b/src/main.h index 142c41444..0a1ff4546 100644 --- a/src/main.h +++ b/src/main.h @@ -14,6 +14,7 @@ #include "coins.h" #include "core.h" #include "net.h" +#include "pow.h" #include "script.h" #include "sync.h" #include "txmempool.h" @@ -163,8 +164,6 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, b bool ActivateBestChain(CValidationState &state, CBlock *pblock = NULL); int64_t GetBlockValue(int nHeight, int64_t nFees); -void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev); - /** Create a new block index entry for a given block hash */ CBlockIndex * InsertBlockIndex(uint256 hash); /** Verify a signature */ @@ -736,17 +735,7 @@ public: uint256 GetBlockWork() const { - uint256 bnTarget; - bool fNegative; - bool fOverflow; - bnTarget.SetCompact(nBits, &fNegative, &fOverflow); - if (fNegative || fOverflow || bnTarget == 0) - return 0; - // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 - // as it's too large for a uint256. However, as 2**256 is at least as large - // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, - // or ~bnTarget / (nTarget+1) + 1. - return (~bnTarget / (bnTarget + 1)) + 1; + return GetProofIncrement(nBits); } enum { nMedianTimeSpan=11 }; diff --git a/src/miner.cpp b/src/miner.cpp index 8696edcf6..96dc80a26 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -307,7 +307,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - UpdateTime(*pblock, pindexPrev); + UpdateTime(pblock, pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); @@ -540,7 +540,7 @@ void static BitcoinMiner(CWallet *pwallet) break; // Update nTime every few seconds - UpdateTime(*pblock, pindexPrev); + UpdateTime(pblock, pindexPrev); if (Params().AllowMinDifficultyBlocks()) { // Changing pblock->nTime can change work required on testnet: diff --git a/src/pow.cpp b/src/pow.cpp index b091cbec3..893f6c18b 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -8,6 +8,7 @@ #include "chainparams.h" #include "core.h" #include "main.h" +#include "timedata.h" #include "uint256.h" #include "util.h" @@ -94,27 +95,58 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits) } // -// minimum amount of work that could possibly be required nTime after -// minimum work required was nBase +// true if nBits is greater than the minimum amount of work that could +// possibly be required deltaTime after minimum work required was nBase // -unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime) +bool CheckMinWork(unsigned int nBits, unsigned int nBase, int64_t deltaTime) { + bool fOverflow = false; + uint256 bnNewBlock; + bnNewBlock.SetCompact(nBits, NULL, &fOverflow); + if (fOverflow) + return false; + const uint256 &bnLimit = Params().ProofOfWorkLimit(); // Testnet has min-difficulty blocks // after Params().TargetSpacing()*2 time between blocks: - if (Params().AllowMinDifficultyBlocks() && nTime > Params().TargetSpacing()*2) - return bnLimit.GetCompact(); + if (Params().AllowMinDifficultyBlocks() && deltaTime > Params().TargetSpacing()*2) + return bnNewBlock <= bnLimit; uint256 bnResult; bnResult.SetCompact(nBase); - while (nTime > 0 && bnResult < bnLimit) + while (deltaTime > 0 && bnResult < bnLimit) { // Maximum 400% adjustment... bnResult *= 4; // ... in best-case exactly 4-times-normal target time - nTime -= Params().TargetTimespan()*4; + deltaTime -= Params().TargetTimespan()*4; } if (bnResult > bnLimit) bnResult = bnLimit; - return bnResult.GetCompact(); + + return bnNewBlock <= bnResult; +} + +void UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev) +{ + pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + + // Updating time can change work required on testnet: + if (Params().AllowMinDifficultyBlocks()) + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); +} + +uint256 GetProofIncrement(unsigned int nBits) +{ + uint256 bnTarget; + bool fNegative; + bool fOverflow; + bnTarget.SetCompact(nBits, &fNegative, &fOverflow); + if (fNegative || fOverflow || bnTarget == 0) + return 0; + // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 + // as it's too large for a uint256. However, as 2**256 is at least as large + // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, + // or ~bnTarget / (nTarget+1) + 1. + return (~bnTarget / (bnTarget + 1)) + 1; } diff --git a/src/pow.h b/src/pow.h index 0ce5b4876..f350d763f 100644 --- a/src/pow.h +++ b/src/pow.h @@ -17,7 +17,11 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ bool CheckProofOfWork(uint256 hash, unsigned int nBits); -/** Calculate the minimum amount of work a received block needs, without knowing its direct parent */ -unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime); +/** Check the work is more than the minimum a received block needs, without knowing its direct parent */ +bool CheckMinWork(unsigned int nBits, unsigned int nBase, int64_t deltaTime); + +void UpdateTime(CBlockHeader* block, const CBlockIndex* pindexPrev); + +uint256 GetProofIncrement(unsigned int nBits); #endif diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 6e508abcd..e4a5bc416 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -458,7 +458,7 @@ Value getblocktemplate(const Array& params, bool fHelp) CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Update nTime - UpdateTime(*pblock, pindexPrev); + UpdateTime(pblock, pindexPrev); pblock->nNonce = 0; Array transactions; diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 4ecf6e253..8fa38c360 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -107,11 +107,7 @@ static bool CheckNBits(unsigned int nbits1, int64_t time1, unsigned int nbits2, return CheckNBits(nbits2, time2, nbits1, time1); int64_t deltaTime = time2-time1; - uint256 required; - required.SetCompact(ComputeMinWork(nbits1, deltaTime)); - uint256 have; - have.SetCompact(nbits2); - return (have <= required); + return CheckMinWork(nbits2, nbits1, deltaTime); } BOOST_AUTO_TEST_CASE(DoS_checknbits)