Inspired by former implementations by Eric Lombrozo and Rusty Russell, and based on code by Jorge Timon.tags/v0.15.1
@@ -152,6 +152,7 @@ BITCOIN_CORE_H = \ | |||
utilmoneystr.h \ | |||
utiltime.h \ | |||
validationinterface.h \ | |||
versionbits.h \ | |||
wallet/crypter.h \ | |||
wallet/db.h \ | |||
wallet/rpcwallet.h \ | |||
@@ -204,6 +205,7 @@ libbitcoin_server_a_SOURCES = \ | |||
txdb.cpp \ | |||
txmempool.cpp \ | |||
validationinterface.cpp \ | |||
versionbits.cpp \ | |||
$(BITCOIN_CORE_H) | |||
if ENABLE_ZMQ |
@@ -14,8 +14,6 @@ | |||
#include <vector> | |||
#include <boost/foreach.hpp> | |||
struct CDiskBlockPos | |||
{ | |||
int nFile; |
@@ -81,6 +81,8 @@ public: | |||
consensus.nPowTargetSpacing = 10 * 60; | |||
consensus.fPowAllowMinDifficultyBlocks = false; | |||
consensus.fPowNoRetargeting = false; | |||
consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 | |||
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing | |||
/** | |||
* 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 | |||
@@ -162,6 +164,8 @@ public: | |||
consensus.nPowTargetSpacing = 10 * 60; | |||
consensus.fPowAllowMinDifficultyBlocks = true; | |||
consensus.fPowNoRetargeting = false; | |||
consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains | |||
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing | |||
pchMessageStart[0] = 0x0b; | |||
pchMessageStart[1] = 0x11; | |||
pchMessageStart[2] = 0x09; | |||
@@ -225,6 +229,8 @@ public: | |||
consensus.nPowTargetSpacing = 10 * 60; | |||
consensus.fPowAllowMinDifficultyBlocks = true; | |||
consensus.fPowNoRetargeting = true; | |||
consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains | |||
consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016) | |||
pchMessageStart[0] = 0xfa; | |||
pchMessageStart[1] = 0xbf; |
@@ -7,8 +7,28 @@ | |||
#define BITCOIN_CONSENSUS_PARAMS_H | |||
#include "uint256.h" | |||
#include <map> | |||
#include <string> | |||
namespace Consensus { | |||
enum DeploymentPos | |||
{ | |||
MAX_VERSION_BITS_DEPLOYMENTS = 0, | |||
}; | |||
/** | |||
* Struct for each individual consensus rule change using BIP9. | |||
*/ | |||
struct BIP9Deployment { | |||
/** Bit position to select the particular bit in nVersion. */ | |||
int bit; | |||
/** Start MedianTime for version bits miner confirmation. Can be a date in the past */ | |||
int64_t nStartTime; | |||
/** Timeout/expiry MedianTime for the deployment attempt. */ | |||
int64_t nTimeout; | |||
}; | |||
/** | |||
* Parameters that influence chain consensus. | |||
*/ | |||
@@ -22,6 +42,14 @@ struct Params { | |||
/** Block height and hash at which BIP34 becomes active */ | |||
int BIP34Height; | |||
uint256 BIP34Hash; | |||
/** | |||
* Minimum blocks including miner confirmation of the total of 2016 blocks in a retargetting period, | |||
* (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments. | |||
* Examples: 1916 for 95%, 1512 for testchains. | |||
*/ | |||
uint32_t nRuleChangeActivationThreshold; | |||
uint32_t nMinerConfirmationWindow; | |||
BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS]; | |||
/** Proof of work parameters */ | |||
uint256 powLimit; | |||
bool fPowAllowMinDifficultyBlocks; |
@@ -466,7 +466,7 @@ std::string HelpMessage(HelpMessageMode mode) | |||
strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE)); | |||
strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE)); | |||
if (showDebug) | |||
strUsage += HelpMessageOpt("-blockversion=<n>", strprintf("Override block version to test forking scenarios (default: %d)", (int)CBlock::CURRENT_VERSION)); | |||
strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios"); | |||
strUsage += HelpMessageGroup(_("RPC server options:")); | |||
strUsage += HelpMessageOpt("-server", _("Accept command line and JSON-RPC commands")); |
@@ -34,6 +34,7 @@ | |||
#include "utilmoneystr.h" | |||
#include "utilstrencodings.h" | |||
#include "validationinterface.h" | |||
#include "versionbits.h" | |||
#include <sstream> | |||
@@ -2083,6 +2084,51 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const | |||
} | |||
} | |||
// Protected by cs_main | |||
static VersionBitsCache versionbitscache; | |||
int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) | |||
{ | |||
LOCK(cs_main); | |||
int32_t nVersion = VERSIONBITS_TOP_BITS; | |||
for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { | |||
ThresholdState state = VersionBitsState(pindexPrev, params, (Consensus::DeploymentPos)i, versionbitscache); | |||
if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) { | |||
nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i); | |||
} | |||
} | |||
return nVersion; | |||
} | |||
/** | |||
* Threshold condition checker that triggers when unknown versionbits are seen on the network. | |||
*/ | |||
class WarningBitsConditionChecker : public AbstractThresholdConditionChecker | |||
{ | |||
private: | |||
int bit; | |||
public: | |||
WarningBitsConditionChecker(int bitIn) : bit(bitIn) {} | |||
int64_t BeginTime(const Consensus::Params& params) const { return 0; } | |||
int64_t EndTime(const Consensus::Params& params) const { return std::numeric_limits<int64_t>::max(); } | |||
int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; } | |||
int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; } | |||
bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const | |||
{ | |||
return ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && | |||
((pindex->nVersion >> bit) & 1) != 0 && | |||
((ComputeBlockVersion(pindex->pprev, params) >> bit) & 1) == 0; | |||
} | |||
}; | |||
// Protected by cs_main | |||
static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS]; | |||
static int64_t nTimeCheck = 0; | |||
static int64_t nTimeForks = 0; | |||
static int64_t nTimeVerify = 0; | |||
@@ -2452,24 +2498,42 @@ void static UpdateTip(CBlockIndex *pindexNew) { | |||
// Check the version of the last 100 blocks to see if we need to upgrade: | |||
static bool fWarned = false; | |||
if (!IsInitialBlockDownload() && !fWarned) | |||
if (!IsInitialBlockDownload()) | |||
{ | |||
int nUpgraded = 0; | |||
const CBlockIndex* pindex = chainActive.Tip(); | |||
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) { | |||
WarningBitsConditionChecker checker(bit); | |||
ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]); | |||
if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) { | |||
if (state == THRESHOLD_ACTIVE) { | |||
strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit); | |||
if (!fWarned) { | |||
CAlert::Notify(strMiscWarning, true); | |||
fWarned = true; | |||
} | |||
} else { | |||
LogPrintf("%s: unknown new rules are about to activate (versionbit %i)\n", __func__, bit); | |||
} | |||
} | |||
} | |||
for (int i = 0; i < 100 && pindex != NULL; i++) | |||
{ | |||
if (pindex->nVersion > CBlock::CURRENT_VERSION) | |||
int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus()); | |||
if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0) | |||
++nUpgraded; | |||
pindex = pindex->pprev; | |||
} | |||
if (nUpgraded > 0) | |||
LogPrintf("%s: %d of last 100 blocks above version %d\n", __func__, nUpgraded, (int)CBlock::CURRENT_VERSION); | |||
LogPrintf("%s: %d of last 100 blocks have unexpected version\n", __func__, nUpgraded); | |||
if (nUpgraded > 100/2) | |||
{ | |||
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: | |||
strMiscWarning = _("Warning: This version is obsolete; upgrade required!"); | |||
CAlert::Notify(strMiscWarning, true); | |||
fWarned = true; | |||
strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect"); | |||
if (!fWarned) { | |||
CAlert::Notify(strMiscWarning, true); | |||
fWarned = true; | |||
} | |||
} | |||
} | |||
} | |||
@@ -3763,6 +3827,10 @@ void UnloadBlockIndex() | |||
setDirtyFileInfo.clear(); | |||
mapNodeState.clear(); | |||
recentRejects.reset(NULL); | |||
versionbitscache.Clear(); | |||
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) { | |||
warningcache[b].clear(); | |||
} | |||
BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) { | |||
delete entry.second; |
@@ -537,6 +537,11 @@ extern CBlockTreeDB *pblocktree; | |||
*/ | |||
int GetSpendHeight(const CCoinsViewCache& inputs); | |||
/** | |||
* Determine what nVersion a new block should use. | |||
*/ | |||
int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params); | |||
/** Reject codes greater or equal to this can be returned by AcceptToMemPool | |||
* for transactions, to signal internal conditions. They cannot and should not | |||
* be sent over the P2P network. |
@@ -79,11 +79,6 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s | |||
return NULL; | |||
CBlock *pblock = &pblocktemplate->block; // pointer for convenience | |||
// -regtest only: allow overriding block.nVersion with | |||
// -blockversion=N to test forking scenarios | |||
if (chainparams.MineBlocksOnDemand()) | |||
pblock->nVersion = GetArg("-blockversion", pblock->nVersion); | |||
// Create coinbase tx | |||
CMutableTransaction txNew; | |||
txNew.vin.resize(1); | |||
@@ -137,6 +132,12 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s | |||
pblock->nTime = GetAdjustedTime(); | |||
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); | |||
pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); | |||
// -regtest only: allow overriding block.nVersion with | |||
// -blockversion=N to test forking scenarios | |||
if (chainparams.MineBlocksOnDemand()) | |||
pblock->nVersion = GetArg("-blockversion", pblock->nVersion); | |||
int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) | |||
? nMedianTimePast | |||
: pblock->GetBlockTime(); |
@@ -21,7 +21,6 @@ class CBlockHeader | |||
{ | |||
public: | |||
// header | |||
static const int32_t CURRENT_VERSION=4; | |||
int32_t nVersion; | |||
uint256 hashPrevBlock; | |||
uint256 hashMerkleRoot; | |||
@@ -49,7 +48,7 @@ public: | |||
void SetNull() | |||
{ | |||
nVersion = CBlockHeader::CURRENT_VERSION; | |||
nVersion = 0; | |||
hashPrevBlock.SetNull(); | |||
hashMerkleRoot.SetNull(); | |||
nTime = 0; |
@@ -247,13 +247,40 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) | |||
// subsidy changing | |||
int nHeight = chainActive.Height(); | |||
chainActive.Tip()->nHeight = 209999; | |||
// Create an actual 209999-long block chain (without valid blocks). | |||
while (chainActive.Tip()->nHeight < 209999) { | |||
CBlockIndex* prev = chainActive.Tip(); | |||
CBlockIndex* next = new CBlockIndex(); | |||
next->phashBlock = new uint256(GetRandHash()); | |||
pcoinsTip->SetBestBlock(next->GetBlockHash()); | |||
next->pprev = prev; | |||
next->nHeight = prev->nHeight + 1; | |||
next->BuildSkip(); | |||
chainActive.SetTip(next); | |||
} | |||
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); | |||
delete pblocktemplate; | |||
chainActive.Tip()->nHeight = 210000; | |||
// Extend to a 210000-long block chain. | |||
while (chainActive.Tip()->nHeight < 210000) { | |||
CBlockIndex* prev = chainActive.Tip(); | |||
CBlockIndex* next = new CBlockIndex(); | |||
next->phashBlock = new uint256(GetRandHash()); | |||
pcoinsTip->SetBestBlock(next->GetBlockHash()); | |||
next->pprev = prev; | |||
next->nHeight = prev->nHeight + 1; | |||
next->BuildSkip(); | |||
chainActive.SetTip(next); | |||
} | |||
BOOST_CHECK(pblocktemplate = CreateNewBlock(chainparams, scriptPubKey)); | |||
delete pblocktemplate; | |||
chainActive.Tip()->nHeight = nHeight; | |||
// Delete the dummy blocks again. | |||
while (chainActive.Tip()->nHeight > nHeight) { | |||
CBlockIndex* del = chainActive.Tip(); | |||
chainActive.SetTip(del->pprev); | |||
pcoinsTip->SetBestBlock(del->pprev->GetBlockHash()); | |||
delete del->phashBlock; | |||
delete del; | |||
} | |||
// non-final txs in mempool | |||
SetMockTime(chainActive.Tip()->GetMedianTimePast()+1); |
@@ -0,0 +1,133 @@ | |||
// Copyright (c) 2016 The Bitcoin Core developers | |||
// Distributed under the MIT software license, see the accompanying | |||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | |||
#include "versionbits.h" | |||
ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const | |||
{ | |||
int nPeriod = Period(params); | |||
int nThreshold = Threshold(params); | |||
int64_t nTimeStart = BeginTime(params); | |||
int64_t nTimeTimeout = EndTime(params); | |||
// A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1. | |||
if (pindexPrev != NULL) { | |||
pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod)); | |||
} | |||
// Walk backwards in steps of nPeriod to find a pindexPrev whose information is known | |||
std::vector<const CBlockIndex*> vToCompute; | |||
while (cache.count(pindexPrev) == 0) { | |||
if (pindexPrev == NULL) { | |||
// The genesis block is by definition defined. | |||
cache[pindexPrev] = THRESHOLD_DEFINED; | |||
break; | |||
} | |||
if (pindexPrev->GetMedianTimePast() < nTimeStart) { | |||
// Optimizaton: don't recompute down further, as we know every earlier block will be before the start time | |||
cache[pindexPrev] = THRESHOLD_DEFINED; | |||
break; | |||
} | |||
vToCompute.push_back(pindexPrev); | |||
pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod); | |||
} | |||
// At this point, cache[pindexPrev] is known | |||
assert(cache.count(pindexPrev)); | |||
ThresholdState state = cache[pindexPrev]; | |||
// Now walk forward and compute the state of descendants of pindexPrev | |||
while (!vToCompute.empty()) { | |||
ThresholdState stateNext = state; | |||
pindexPrev = vToCompute.back(); | |||
vToCompute.pop_back(); | |||
switch (state) { | |||
case THRESHOLD_DEFINED: { | |||
if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { | |||
stateNext = THRESHOLD_FAILED; | |||
} else if (pindexPrev->GetMedianTimePast() >= nTimeStart) { | |||
stateNext = THRESHOLD_STARTED; | |||
} | |||
break; | |||
} | |||
case THRESHOLD_STARTED: { | |||
if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) { | |||
stateNext = THRESHOLD_FAILED; | |||
break; | |||
} | |||
// We need to count | |||
const CBlockIndex* pindexCount = pindexPrev; | |||
int count = 0; | |||
for (int i = 0; i < nPeriod; i++) { | |||
if (Condition(pindexCount, params)) { | |||
count++; | |||
} | |||
pindexCount = pindexCount->pprev; | |||
} | |||
if (count >= nThreshold) { | |||
stateNext = THRESHOLD_LOCKED_IN; | |||
} | |||
break; | |||
} | |||
case THRESHOLD_LOCKED_IN: { | |||
// Always progresses into ACTIVE. | |||
stateNext = THRESHOLD_ACTIVE; | |||
break; | |||
} | |||
case THRESHOLD_FAILED: | |||
case THRESHOLD_ACTIVE: { | |||
// Nothing happens, these are terminal states. | |||
break; | |||
} | |||
} | |||
cache[pindexPrev] = state = stateNext; | |||
} | |||
return state; | |||
} | |||
namespace | |||
{ | |||
/** | |||
* Class to implement versionbits logic. | |||
*/ | |||
class VersionBitsConditionChecker : public AbstractThresholdConditionChecker { | |||
private: | |||
const Consensus::DeploymentPos id; | |||
protected: | |||
int64_t BeginTime(const Consensus::Params& params) const { return params.vDeployments[id].nStartTime; } | |||
int64_t EndTime(const Consensus::Params& params) const { return params.vDeployments[id].nTimeout; } | |||
int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; } | |||
int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; } | |||
bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const | |||
{ | |||
return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0); | |||
} | |||
public: | |||
VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {} | |||
uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; } | |||
}; | |||
} | |||
ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache) | |||
{ | |||
return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, cache.caches[pos]); | |||
} | |||
uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos) | |||
{ | |||
return VersionBitsConditionChecker(pos).Mask(params); | |||
} | |||
void VersionBitsCache::Clear() | |||
{ | |||
for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) { | |||
caches[d].clear(); | |||
} | |||
} |
@@ -0,0 +1,59 @@ | |||
// Copyright (c) 2016 The Bitcoin Core developers | |||
// Distributed under the MIT software license, see the accompanying | |||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | |||
#ifndef BITCOIN_CONSENSUS_VERSIONBITS | |||
#define BITCOIN_CONSENSUS_VERSIONBITS | |||
#include "chain.h" | |||
#include <map> | |||
/** What block version to use for new blocks (pre versionbits) */ | |||
static const int32_t VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4; | |||
/** What bits to set in version for versionbits blocks */ | |||
static const int32_t VERSIONBITS_TOP_BITS = 0x20000000UL; | |||
/** What bitmask determines whether versionbits is in use */ | |||
static const int32_t VERSIONBITS_TOP_MASK = 0xE0000000UL; | |||
/** Total bits available for versionbits */ | |||
static const int32_t VERSIONBITS_NUM_BITS = 29; | |||
enum ThresholdState { | |||
THRESHOLD_DEFINED, | |||
THRESHOLD_STARTED, | |||
THRESHOLD_LOCKED_IN, | |||
THRESHOLD_ACTIVE, | |||
THRESHOLD_FAILED, | |||
}; | |||
// A map that gives the state for blocks whose height is a multiple of Period(). | |||
// The map is indexed by the block's parent, however, so all keys in the map | |||
// will either be NULL or a block with (height + 1) % Period() == 0. | |||
typedef std::map<const CBlockIndex*, ThresholdState> ThresholdConditionCache; | |||
/** | |||
* Abstract class that implements BIP9-style threshold logic, and caches results. | |||
*/ | |||
class AbstractThresholdConditionChecker { | |||
protected: | |||
virtual bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const =0; | |||
virtual int64_t BeginTime(const Consensus::Params& params) const =0; | |||
virtual int64_t EndTime(const Consensus::Params& params) const =0; | |||
virtual int Period(const Consensus::Params& params) const =0; | |||
virtual int Threshold(const Consensus::Params& params) const =0; | |||
public: | |||
// Note that the function below takes a pindexPrev as input: they compute information for block B based on its parent. | |||
ThresholdState GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const; | |||
}; | |||
struct VersionBitsCache | |||
{ | |||
ThresholdConditionCache caches[Consensus::MAX_VERSION_BITS_DEPLOYMENTS]; | |||
void Clear(); | |||
}; | |||
ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache); | |||
uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos); | |||
#endif |