Browse Source

Merge pull request #3839

fd704c7 move pow constants to chainparams (jtimon)
df852d2 Refactor proof of work related functions out of main (jtimon)
try
Wladimir J. van der Laan 10 years ago
parent
commit
208bf5b9e0
No known key found for this signature in database GPG Key ID: 74810B012346C9A6
  1. 2
      src/Makefile.am
  2. 7
      src/chainparams.cpp
  3. 5
      src/chainparams.h
  4. 113
      src/main.cpp
  5. 10
      src/main.h
  6. 1
      src/miner.cpp
  7. 119
      src/pow.cpp
  8. 23
      src/pow.h
  9. 1
      src/rpcmining.cpp
  10. 1
      src/test/DoS_tests.cpp
  11. 5
      src/txdb.cpp

2
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 \

7
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;

5
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;

113
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);

10
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

1
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

119
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();
}

23
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

1
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"

1
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"

5
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 {

Loading…
Cancel
Save