diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2014-06-25 09:14:14 +0200 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2014-06-25 09:14:36 +0200 |
commit | 208bf5b9e0a86900bddf5722dc192c3262480e36 (patch) | |
tree | b70a86a5daf38ff1846a58340aefb27779d693e0 | |
parent | 27383b9015e204ac834d5df00737fe23bb042bc4 (diff) | |
parent | fd704c7b2c5ab8b24b1829f000b829d7156b8b3c (diff) |
Merge pull request #3839
fd704c7 move pow constants to chainparams (jtimon)
df852d2 Refactor proof of work related functions out of main (jtimon)
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/chainparams.cpp | 7 | ||||
-rw-r--r-- | src/chainparams.h | 5 | ||||
-rw-r--r-- | src/main.cpp | 113 | ||||
-rw-r--r-- | src/main.h | 10 | ||||
-rw-r--r-- | src/miner.cpp | 1 | ||||
-rw-r--r-- | src/pow.cpp | 119 | ||||
-rw-r--r-- | src/pow.h | 23 | ||||
-rw-r--r-- | src/rpcmining.cpp | 1 | ||||
-rw-r--r-- | src/test/DoS_tests.cpp | 1 | ||||
-rw-r--r-- | src/txdb.cpp | 5 |
11 files changed, 163 insertions, 124 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 5ecded442c..7e7fa0c3ca 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -71,6 +71,7 @@ BITCOIN_CORE_H = \ netbase.h \ net.h \ noui.h \ + pow.h \ protocol.h \ rpcclient.h \ rpcprotocol.h \ @@ -121,6 +122,7 @@ libbitcoin_server_a_SOURCES = \ miner.cpp \ net.cpp \ noui.cpp \ + pow.cpp \ rpcblockchain.cpp \ rpcmining.cpp \ rpcmisc.cpp \ diff --git a/src/chainparams.cpp b/src/chainparams.cpp index afbae6fc57..eb56af750e 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -117,6 +117,8 @@ public: nRejectBlockOutdatedMajority = 950; nToCheckBlockUpgradeMajority = 1000; nMinerThreads = 0; + nTargetTimespan = 14 * 24 * 60 * 60; // two weeks + nTargetSpacing = 10 * 60; // Build the genesis block. Note that the output of the genesis coinbase cannot // be spent as it did not originally exist in the database. @@ -204,6 +206,9 @@ public: nEnforceBlockUpgradeMajority = 51; nRejectBlockOutdatedMajority = 75; nToCheckBlockUpgradeMajority = 100; + nMinerThreads = 0; + nTargetTimespan = 14 * 24 * 60 * 60; // two weeks + nTargetSpacing = 10 * 60; strDataDir = "testnet3"; // Modify the testnet genesis block so the timestamp is valid for a later start. @@ -251,6 +256,8 @@ public: nRejectBlockOutdatedMajority = 950; nToCheckBlockUpgradeMajority = 1000; nMinerThreads = 1; + nTargetTimespan = 14 * 24 * 60 * 60; // two weeks + nTargetSpacing = 10 * 60; bnProofOfWorkLimit = ~uint256(0) >> 1; genesis.nTime = 1296688602; genesis.nBits = 0x207fffff; diff --git a/src/chainparams.h b/src/chainparams.h index c0a6ebda6b..e9774bbfa2 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -70,6 +70,9 @@ public: bool AllowMinDifficultyBlocks() const { return fAllowMinDifficultyBlocks; } /* Make standard checks */ bool RequireStandard() const { return fRequireStandard; } + int64_t TargetTimespan() const { return nTargetTimespan; } + int64_t TargetSpacing() const { return nTargetSpacing; } + int64_t Interval() const { return nTargetTimespan / nTargetSpacing; } const std::string& DataDir() const { return strDataDir; } /* Make miner stop after a block is found. In RPC, don't return * until nGenProcLimit blocks are generated */ @@ -95,6 +98,8 @@ protected: int nEnforceBlockUpgradeMajority; int nRejectBlockOutdatedMajority; int nToCheckBlockUpgradeMajority; + int64_t nTargetTimespan; + int64_t nTargetSpacing; std::string strDataDir; int nMinerThreads; std::vector<CDNSSeedData> vSeeds; diff --git a/src/main.cpp b/src/main.cpp index d3f04b95fa..ea47601081 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,7 @@ #include "checkqueue.h" #include "init.h" #include "net.h" +#include "pow.h" #include "txdb.h" #include "txmempool.h" #include "ui_interface.h" @@ -1194,118 +1195,6 @@ int64_t GetBlockValue(int nHeight, int64_t nFees) return nSubsidy + nFees; } -static const int64_t nTargetTimespan = 14 * 24 * 60 * 60; // two weeks -static const int64_t nTargetSpacing = 10 * 60; -static const int64_t nInterval = nTargetTimespan / nTargetSpacing; - -// -// minimum amount of work that could possibly be required nTime after -// minimum work required was nBase -// -unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime) -{ - const uint256 &bnLimit = Params().ProofOfWorkLimit(); - // Testnet has min-difficulty blocks - // after nTargetSpacing*2 time between blocks: - if (Params().AllowMinDifficultyBlocks() && nTime > nTargetSpacing*2) - return bnLimit.GetCompact(); - - uint256 bnResult; - bnResult.SetCompact(nBase); - while (nTime > 0 && bnResult < bnLimit) - { - // Maximum 400% adjustment... - bnResult *= 4; - // ... in best-case exactly 4-times-normal target time - nTime -= nTargetTimespan*4; - } - if (bnResult > bnLimit) - bnResult = bnLimit; - return bnResult.GetCompact(); -} - -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock) -{ - unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact(); - - // Genesis block - if (pindexLast == NULL) - return nProofOfWorkLimit; - - // Only change once per interval - if ((pindexLast->nHeight+1) % nInterval != 0) - { - if (Params().AllowMinDifficultyBlocks()) - { - // Special difficulty rule for testnet: - // If the new block's timestamp is more than 2* 10 minutes - // then allow mining of a min-difficulty block. - if (pblock->nTime > pindexLast->nTime + nTargetSpacing*2) - return nProofOfWorkLimit; - else - { - // Return the last non-special-min-difficulty-rules-block - const CBlockIndex* pindex = pindexLast; - while (pindex->pprev && pindex->nHeight % nInterval != 0 && pindex->nBits == nProofOfWorkLimit) - pindex = pindex->pprev; - return pindex->nBits; - } - } - return pindexLast->nBits; - } - - // Go back by what we want to be 14 days worth of blocks - const CBlockIndex* pindexFirst = pindexLast; - for (int i = 0; pindexFirst && i < nInterval-1; i++) - pindexFirst = pindexFirst->pprev; - assert(pindexFirst); - - // Limit adjustment step - int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime(); - LogPrintf(" nActualTimespan = %d before bounds\n", nActualTimespan); - if (nActualTimespan < nTargetTimespan/4) - nActualTimespan = nTargetTimespan/4; - if (nActualTimespan > nTargetTimespan*4) - nActualTimespan = nTargetTimespan*4; - - // Retarget - uint256 bnNew; - uint256 bnOld; - bnNew.SetCompact(pindexLast->nBits); - bnOld = bnNew; - bnNew *= nActualTimespan; - bnNew /= nTargetTimespan; - - if (bnNew > Params().ProofOfWorkLimit()) - bnNew = Params().ProofOfWorkLimit(); - - /// debug print - LogPrintf("GetNextWorkRequired RETARGET\n"); - LogPrintf("nTargetTimespan = %d nActualTimespan = %d\n", nTargetTimespan, nActualTimespan); - LogPrintf("Before: %08x %s\n", pindexLast->nBits, bnOld.ToString()); - LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); - - return bnNew.GetCompact(); -} - -bool CheckProofOfWork(uint256 hash, unsigned int nBits) -{ - bool fNegative; - bool fOverflow; - uint256 bnTarget; - bnTarget.SetCompact(nBits, &fNegative, &fOverflow); - - // Check range - if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit()) - return error("CheckProofOfWork() : nBits below minimum work"); - - // Check proof of work matches claimed amount - if (hash > bnTarget) - return error("CheckProofOfWork() : hash doesn't match nBits"); - - return true; -} - bool IsInitialBlockDownload() { LOCK(cs_main); diff --git a/src/main.h b/src/main.h index 27041a0026..9858bcfd69 100644 --- a/src/main.h +++ b/src/main.h @@ -146,10 +146,6 @@ bool ProcessMessages(CNode* pfrom); bool SendMessages(CNode* pto, bool fSendTrickle); /** Run an instance of the script checking thread */ void ThreadScriptCheck(); -/** 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 whether we are doing an initial block download (synchronizing from disk or network) */ bool IsInitialBlockDownload(); /** Format a string that describes several potential problems detected by the core */ @@ -159,7 +155,6 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, b /** Find the best known block, and make it the tip of the block chain */ bool ActivateBestChain(CValidationState &state); int64_t GetBlockValue(int nHeight, int64_t nFees); -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock); void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev); @@ -812,11 +807,6 @@ public: return (~bnTarget / (bnTarget + 1)) + 1; } - bool CheckIndex() const - { - return CheckProofOfWork(GetBlockHash(), nBits); - } - enum { nMedianTimeSpan=11 }; int64_t GetMedianTimePast() const diff --git a/src/miner.cpp b/src/miner.cpp index 6b1f58b229..19b4694357 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -9,6 +9,7 @@ #include "hash.h" #include "main.h" #include "net.h" +#include "pow.h" #ifdef ENABLE_WALLET #include "wallet.h" #endif diff --git a/src/pow.cpp b/src/pow.cpp new file mode 100644 index 0000000000..952250decd --- /dev/null +++ b/src/pow.cpp @@ -0,0 +1,119 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "pow.h" + +#include "chainparams.h" +#include "core.h" +#include "main.h" +#include "uint256.h" + +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock) +{ + unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact(); + + // Genesis block + if (pindexLast == NULL) + return nProofOfWorkLimit; + + // Only change once per interval + if ((pindexLast->nHeight+1) % Params().Interval() != 0) + { + if (Params().AllowMinDifficultyBlocks()) + { + // Special difficulty rule for testnet: + // If the new block's timestamp is more than 2* 10 minutes + // then allow mining of a min-difficulty block. + if (pblock->nTime > pindexLast->nTime + Params().TargetSpacing()*2) + return nProofOfWorkLimit; + else + { + // Return the last non-special-min-difficulty-rules-block + const CBlockIndex* pindex = pindexLast; + while (pindex->pprev && pindex->nHeight % Params().Interval() != 0 && pindex->nBits == nProofOfWorkLimit) + pindex = pindex->pprev; + return pindex->nBits; + } + } + return pindexLast->nBits; + } + + // Go back by what we want to be 14 days worth of blocks + const CBlockIndex* pindexFirst = pindexLast; + for (int i = 0; pindexFirst && i < Params().Interval()-1; i++) + pindexFirst = pindexFirst->pprev; + assert(pindexFirst); + + // Limit adjustment step + int64_t nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime(); + LogPrintf(" nActualTimespan = %d before bounds\n", nActualTimespan); + if (nActualTimespan < Params().TargetTimespan()/4) + nActualTimespan = Params().TargetTimespan()/4; + if (nActualTimespan > Params().TargetTimespan()*4) + nActualTimespan = Params().TargetTimespan()*4; + + // Retarget + uint256 bnNew; + uint256 bnOld; + bnNew.SetCompact(pindexLast->nBits); + bnOld = bnNew; + bnNew *= nActualTimespan; + bnNew /= Params().TargetTimespan(); + + if (bnNew > Params().ProofOfWorkLimit()) + bnNew = Params().ProofOfWorkLimit(); + + /// debug print + LogPrintf("GetNextWorkRequired RETARGET\n"); + LogPrintf("Params().TargetTimespan() = %d nActualTimespan = %d\n", Params().TargetTimespan(), nActualTimespan); + LogPrintf("Before: %08x %s\n", pindexLast->nBits, bnOld.ToString()); + LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); + + return bnNew.GetCompact(); +} + +bool CheckProofOfWork(uint256 hash, unsigned int nBits) +{ + bool fNegative; + bool fOverflow; + uint256 bnTarget; + bnTarget.SetCompact(nBits, &fNegative, &fOverflow); + + // Check range + if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit()) + return error("CheckProofOfWork() : nBits below minimum work"); + + // Check proof of work matches claimed amount + if (hash > bnTarget) + return error("CheckProofOfWork() : hash doesn't match nBits"); + + return true; +} + +// +// minimum amount of work that could possibly be required nTime after +// minimum work required was nBase +// +unsigned int ComputeMinWork(unsigned int nBase, int64_t nTime) +{ + 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(); + + uint256 bnResult; + bnResult.SetCompact(nBase); + while (nTime > 0 && bnResult < bnLimit) + { + // Maximum 400% adjustment... + bnResult *= 4; + // ... in best-case exactly 4-times-normal target time + nTime -= Params().TargetTimespan()*4; + } + if (bnResult > bnLimit) + bnResult = bnLimit; + return bnResult.GetCompact(); +} diff --git a/src/pow.h b/src/pow.h new file mode 100644 index 0000000000..0ce5b48766 --- /dev/null +++ b/src/pow.h @@ -0,0 +1,23 @@ + +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_POW_H +#define BITCOIN_POW_H + +#include <stdint.h> + +class CBlockIndex; +class CBlockHeader; +class uint256; + +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock); + +/** 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); + +#endif diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index a1410f0e41..f60070eb5b 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -9,6 +9,7 @@ #include "net.h" #include "main.h" #include "miner.h" +#include "pow.h" #ifdef ENABLE_WALLET #include "db.h" #include "wallet.h" diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 3a45844411..d512053051 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -11,6 +11,7 @@ #include "keystore.h" #include "main.h" #include "net.h" +#include "pow.h" #include "script.h" #include "serialize.h" diff --git a/src/txdb.cpp b/src/txdb.cpp index 4eab8525a5..92137f71ff 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -6,6 +6,7 @@ #include "txdb.h" #include "core.h" +#include "pow.h" #include "uint256.h" #include <stdint.h> @@ -212,8 +213,8 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->nStatus = diskindex.nStatus; pindexNew->nTx = diskindex.nTx; - if (!pindexNew->CheckIndex()) - return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString()); + if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits)) + return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString()); pcursor->Next(); } else { |