Add BIP9 Softfork Capability for OP_CHECKBLOCKATHEIGHT

This commit is contained in:
joshuayabut 2017-05-07 12:50:09 -04:00
parent 48c79776d3
commit 5a8b402c59
17 changed files with 509 additions and 24 deletions

View File

@ -176,6 +176,7 @@ BITCOIN_CORE_H = \
utilstrencodings.h \
utiltime.h \
validationinterface.h \
versionbits.h \
version.h \
wallet/asyncrpcoperation_sendmany.h \
wallet/crypter.h \
@ -232,6 +233,7 @@ libbitcoin_server_a_SOURCES = \
txdb.cpp \
txmempool.cpp \
validationinterface.cpp \
versionbits.cpp \
$(BITCOIN_CORE_H) \
$(LIBZCASH_H)

View File

@ -14,8 +14,6 @@
#include <vector>
#include <boost/foreach.hpp>
struct CDiskBlockPos
{
int nFile;

View File

@ -50,6 +50,14 @@ public:
consensus.nPowMaxAdjustUp = 16; // 16% adjustment up
consensus.nPowTargetSpacing = 2.5 * 60;
consensus.fPowAllowMinDifficultyBlocks = false;
consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
// Deployment of OP_CHECKBLOCKATHEIGHT softfork
consensus.vDeployments[Consensus::DEPLOYMENT_CBAH].bit = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CBAH].nStartTime = 1493596800; // May 1, 2017
consensus.vDeployments[Consensus::DEPLOYMENT_CBAH].nTimeout = 1525132800; // May 1, 2018
/**
* The message start string should be awesome!
*/
@ -212,6 +220,14 @@ public:
consensus.powLimit = uint256S("07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
consensus.fPowAllowMinDifficultyBlocks = true;
consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
// Deployment of OP_CHECKBLOCKATHEIGHT softfork
consensus.vDeployments[Consensus::DEPLOYMENT_CBAH].bit = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CBAH].nStartTime = 1493596800; // May 1, 2017
consensus.vDeployments[Consensus::DEPLOYMENT_CBAH].nTimeout = 1525132800; // May 1, 2018
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0x1a;
pchMessageStart[2] = 0xf9;
@ -303,6 +319,13 @@ public:
assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow);
consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down
consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up
consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
// Deployment of OP_CHECKBLOCKATHEIGHT softfork
consensus.vDeployments[Consensus::DEPLOYMENT_CBAH].bit = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CBAH].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CBAH].nTimeout = 999999999999ULL;
pchMessageStart[0] = 0xaa;
pchMessageStart[1] = 0xe8;
pchMessageStart[2] = 0x3f;

View File

@ -7,8 +7,31 @@
#define BITCOIN_CONSENSUS_PARAMS_H
#include "uint256.h"
#include <map>
#include <string>
namespace Consensus {
enum DeploymentPos
{
//DEPLOYMENT_SEGWIT, // Deployment of BIP141, BIP143, and BIP147.
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
DEPLOYMENT_CBAH,
MAX_VERSION_BITS_DEPLOYMENTS
};
/**
* 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.
*/
@ -40,6 +63,14 @@ struct Params {
int nMajorityEnforceBlockUpgrade;
int nMajorityRejectBlockOutdated;
int nMajorityWindow;
/**
* Minimum blocks including miner confirmation of the total of 2016 blocks in a retargeting 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;

View File

@ -461,7 +461,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 (GetBoolArg("-help-debug", false))
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");
#ifdef ENABLE_MINING
strUsage += HelpMessageGroup(_("Mining options:"));

View File

@ -26,6 +26,7 @@
#include "util.h"
#include "utilmoneystr.h"
#include "validationinterface.h"
#include "versionbits.h"
#include "wallet/asyncrpcoperation_sendmany.h"
#include <sstream>
@ -2022,6 +2023,51 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const
}
}
// Protected by cs_main
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 nTimeVerify = 0;
static int64_t nTimeConnect = 0;
static int64_t nTimeIndex = 0;
@ -2090,6 +2136,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
}
// Start enforcing OP_CHECKBLOCKATHEIGHT rules using versionbits logic.
if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CBAH, versionbitscache) == THRESHOLD_ACTIVE) {
flags |= SCRIPT_VERIFY_CHECKBLOCKATHEIGHT;
}
CBlockUndo blockundo;
CCheckQueueControl<CScriptCheck> control(fExpensiveChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
@ -2378,24 +2429,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 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;
}
}
}
}
@ -3707,6 +3776,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;
@ -4057,6 +4130,18 @@ void static CheckBlockIndex()
assert(nNodes == forward.size());
}
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos)
{
LOCK(cs_main);
return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache);
}
int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos)
{
LOCK(cs_main);
return VersionBitsStateSinceHeight(chainActive.Tip(), params, pos, versionbitscache);
}
//////////////////////////////////////////////////////////////////////////////
//
// CAlert

View File

@ -25,6 +25,7 @@
#include "tinyformat.h"
#include "txmempool.h"
#include "uint256.h"
#include "versionbits.h"
#include <algorithm>
#include <exception>
@ -251,6 +252,11 @@ void PruneAndFlush();
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
bool* pfMissingInputs, bool fRejectAbsurdFee=false);
/** Get the BIP9 state for a given deployment at the current tip. */
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos);
/** Get the block height at which the BIP9 deployment switched into the state for the block building on the current tip. */
int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos);
struct CNodeStateStats {
int nMisbehavior;
@ -523,6 +529,13 @@ extern CBlockTreeDB *pblocktree;
*/
int GetSpendHeight(const CCoinsViewCache& inputs);
extern VersionBitsCache versionbitscache;
/**
* Determine what nVersion a new block should use.
*/
int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params);
namespace Consensus {
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams);
}

View File

@ -149,6 +149,13 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
const int nHeight = pindexPrev->nHeight + 1;
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);
CCoinsViewCache view(pcoinsTip);
// Priority order to process transactions

View File

@ -22,7 +22,6 @@ class CBlockHeader
public:
// header
static const size_t HEADER_SIZE=4+32+32+32+4+4+32; // excluding Equihash solution
static const int32_t CURRENT_VERSION=4;
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
@ -54,7 +53,7 @@ public:
void SetNull()
{
nVersion = CBlockHeader::CURRENT_VERSION;
nVersion = 0;
hashPrevBlock.SetNull();
hashMerkleRoot.SetNull();
hashReserved.SetNull();

View File

@ -634,6 +634,26 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex*
return rv;
}
static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
{
UniValue rv(UniValue::VOBJ);
const ThresholdState thresholdState = VersionBitsTipState(consensusParams, id);
switch (thresholdState) {
case THRESHOLD_DEFINED: rv.push_back(Pair("status", "defined")); break;
case THRESHOLD_STARTED: rv.push_back(Pair("status", "started")); break;
case THRESHOLD_LOCKED_IN: rv.push_back(Pair("status", "locked_in")); break;
case THRESHOLD_ACTIVE: rv.push_back(Pair("status", "active")); break;
case THRESHOLD_FAILED: rv.push_back(Pair("status", "failed")); break;
}
if (THRESHOLD_STARTED == thresholdState)
{
rv.push_back(Pair("bit", consensusParams.vDeployments[id].bit));
}
rv.push_back(Pair("startTime", consensusParams.vDeployments[id].nStartTime));
rv.push_back(Pair("timeout", consensusParams.vDeployments[id].nTimeout));
return rv;
}
UniValue getblockchaininfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@ -662,8 +682,15 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
" },\n"
" \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
" }, ...\n"
" ]\n"
" \n"
"}\n"
" \"bip9_softforks\": { (object) status of BIP9 softforks in progress\n"
" \"xxxx\" : { (string) name of the softfork\n"
" \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"lockedin\", \"active\", \"failed\"\n"
" \"bit\": xx, (numeric) the bit, 0-28, in the block version field used to signal this soft fork\n"
" \"startTime\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n"
" \"timeout\": xx (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
" }\n"
"\nExamples:\n"
+ HelpExampleCli("getblockchaininfo", "")
+ HelpExampleRpc("getblockchaininfo", "")
@ -688,10 +715,14 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
const Consensus::Params& consensusParams = Params().GetConsensus();
CBlockIndex* tip = chainActive.Tip();
UniValue softforks(UniValue::VARR);
UniValue bip9_softforks(UniValue::VOBJ);
softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
bip9_softforks.push_back(Pair("cbah", BIP9SoftForkDesc(consensusParams, Consensus::DEPLOYMENT_CBAH)));
obj.push_back(Pair("softforks", softforks));
obj.push_back(Pair("bip9_softforks", bip9_softforks));
if (fPruneMode)
{

View File

@ -443,6 +443,14 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Implemented by: @movrcx; See: https://github.com/zencashio/zen/issues/12
case OP_CHECKBLOCKATHEIGHT:
{
if (!(flags & SCRIPT_VERIFY_CHECKBLOCKATHEIGHT)) {
// not enabled; treat as a NOP5
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
}
break;
}
// we need two objects on the stack
if (stack.size() < 2)
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);

View File

@ -86,6 +86,9 @@ enum
// See BIP65 for details.
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
// Verify OP_CHECKBLOCKATHEIGHT
SCRIPT_VERIFY_CHECKBLOCKATHEIGHT = (1U << 10),
};
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);

View File

@ -13,6 +13,7 @@
#include <boost/foreach.hpp>
#include "main.h"
#include "versionbits.h"
using namespace std;
@ -322,20 +323,29 @@ public:
bool operator()(const CKeyID &keyID) const {
script->clear();
CBlockIndex *currentBlock = chainActive.Tip();
int blockIndex = currentBlock->nHeight - 300;
if (blockIndex < 0)
blockIndex = 0;
*script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG << ToByteVector(chainActive[blockIndex]->GetBlockHash()) << chainActive[blockIndex]->nHeight << OP_CHECKBLOCKATHEIGHT;
if (THRESHOLD_ACTIVE == VersionBitsState(chainActive[(currentBlock->nHeight - 1) < 0 ? 0 : (currentBlock->nHeight - 1)], Params().GetConsensus(), Consensus::DEPLOYMENT_CBAH, versionbitscache)) {
CBlockIndex *currentBlock = chainActive.Tip();
int blockIndex = currentBlock->nHeight - 300;
if (blockIndex < 0)
blockIndex = 0;
*script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG << ToByteVector(chainActive[blockIndex]->GetBlockHash()) << chainActive[blockIndex]->nHeight << OP_CHECKBLOCKATHEIGHT;
}
else
*script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
return true;
}
bool operator()(const CScriptID &scriptID) const {
script->clear();
CBlockIndex *currentBlock = chainActive.Tip();
int blockIndex = currentBlock->nHeight - 300;
if (blockIndex < 0)
blockIndex = 0;
*script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL << ToByteVector(chainActive[blockIndex]->GetBlockHash()) << chainActive[blockIndex]->nHeight << OP_CHECKBLOCKATHEIGHT;
if (THRESHOLD_ACTIVE == VersionBitsState(chainActive[(currentBlock->nHeight - 1) < 0 ? 0 : (currentBlock->nHeight - 1)], Params().GetConsensus(), Consensus::DEPLOYMENT_CBAH, versionbitscache)) {
int blockIndex = currentBlock->nHeight - 300;
if (blockIndex < 0)
blockIndex = 0;
*script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL << ToByteVector(chainActive[blockIndex]->GetBlockHash()) << chainActive[blockIndex]->nHeight << OP_CHECKBLOCKATHEIGHT;
}
else
*script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
return true;
}
#endif

View File

@ -52,7 +52,8 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
SCRIPT_VERIFY_CLEANSTACK |
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
SCRIPT_VERIFY_LOW_S;
SCRIPT_VERIFY_LOW_S |
SCRIPT_VERIFY_CHECKBLOCKATHEIGHT;
/** For convenience, standard but not mandatory verify flags. */
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;

View File

@ -378,13 +378,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(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(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);

177
src/versionbits.cpp Normal file
View File

@ -0,0 +1,177 @@
// 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"
#include "consensus/params.h"
const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] = {
{
/*.name =*/ "cbah",
/*.gbt_force =*/ true,
}
};
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) {
// Optimization: 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;
}
int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
{
const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);
// BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment."
if (initialState == THRESHOLD_DEFINED) {
return 0;
}
const int nPeriod = Period(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.
// To ease understanding of the following height calculation, it helps to remember that
// right now pindexPrev points to the block prior to the block that we are computing for, thus:
// if we are computing for the last block of a period, then pindexPrev points to the second to last block of the period, and
// if we are computing for the first block of a period, then pindexPrev points to the last block of the previous period.
// The parent of the genesis block is represented by NULL.
pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
const CBlockIndex* previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
while (previousPeriodParent != NULL && GetStateFor(previousPeriodParent, params, cache) == initialState) {
pindexPrev = previousPeriodParent;
previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
}
// Adjust the result because right now we point to the parent block.
return pindexPrev->nHeight + 1;
}
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]);
}
int VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache)
{
return VersionBitsConditionChecker(pos).GetStateSinceHeightFor(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();
}
}

70
src/versionbits.h Normal file
View File

@ -0,0 +1,70 @@
// 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;
struct BIP9DeploymentInfo {
/** Deployment name */
const char *name;
/** Whether GBT clients can safely ignore this rule in simplified usage */
bool gbt_force;
};
extern const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[];
/**
* 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 functions below take 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;
int GetStateSinceHeightFor(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);
int VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache);
uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos);
#endif