From f71bd2c2d800ca1cee9aa8d95dd89216e6e3fbb4 Mon Sep 17 00:00:00 2001 From: Ross Nicoll Date: Wed, 27 Dec 2017 21:11:14 +0000 Subject: [PATCH] Change BIP65/66 enforcement to match Dogecoin (#1403) * Introduce first estimates at BIP lock-in blocks * Introduce Dogecoin BIP parameters * Re-introduce supermajority rules for BIP65 * Add BIP65 supermajority rules * Tighten v3 block constraints * Don't enforce coinbase in v2 blocks * Correct testnet majority params * Change to using base version when checking supermajority --- src/chainparams.cpp | 31 ++++++++++++++++++++----------- src/consensus/params.h | 7 ++++++- src/rpc/blockchain.cpp | 15 ++++++++++++++- src/validation.cpp | 30 ++++++++++++++++++++++++++---- 4 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 0ab4d8b4f..5e0e51f27 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -71,11 +71,14 @@ public: CMainParams() { strNetworkID = "main"; consensus.nSubsidyHalvingInterval = 100000; - // XXX: BIP heights and hashes all need to be updated to Dogecoin values - consensus.BIP34Height = 227931; - consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8"); - consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0 - consensus.BIP66Height = 363725; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931 + consensus.nMajorityEnforceBlockUpgrade = 1500; + consensus.nMajorityRejectBlockOutdated = 1900; + consensus.nMajorityWindow = 2000; + // BIP34 is never enforced in Dogecoin v2 blocks, so we enforce from v3 + consensus.BIP34Height = 1034383; + consensus.BIP34Hash = uint256S("0x80d1364201e5df97e696c03bdd24dc885e8617b9de51e453c10a4f629b1e797a"); + // consensus.BIP65Height = 1032483; // Not enabled in Doge yet + consensus.BIP66Height = 1034383; // 80d1364201e5df97e696c03bdd24dc885e8617b9de51e453c10a4f629b1e797a - this is the last block that could be v2, 1900 blocks past the last v2 block consensus.powLimit = uint256S("0x00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 20; consensus.nPowTargetTimespan = 4 * 60 * 60; // pre-digishield: 4 hours consensus.nPowTargetSpacing = 60; // 1 minute @@ -182,11 +185,14 @@ public: CTestNetParams() { strNetworkID = "test"; consensus.nSubsidyHalvingInterval = 100000; - // XXX: BIP heights and hashes all need to be updated to Dogecoin values - consensus.BIP34Height = 21111; - consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8"); - consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6 - consensus.BIP66Height = 330776; // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182 + consensus.nMajorityEnforceBlockUpgrade = 501; + consensus.nMajorityRejectBlockOutdated = 750; + consensus.nMajorityWindow = 1000; + // BIP34 is never enforced in Dogecoin v2 blocks, so we enforce from v3 + consensus.BIP34Height = 708658; + consensus.BIP34Hash = uint256S("0x21b8b97dcdb94caa67c7f8f6dbf22e61e0cfe0e46e1fff3528b22864659e9b38"); + // consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6 + consensus.BIP66Height = 708658; // 21b8b97dcdb94caa67c7f8f6dbf22e61e0cfe0e46e1fff3528b22864659e9b38 - this is the last block that could be v2, 1900 blocks past the last v2 block consensus.powLimit = uint256S("0x00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 20; consensus.nPowTargetTimespan = 4 * 60 * 60; // pre-digishield: 4 hours consensus.nPowTargetSpacing = 60; // 1 minute @@ -280,9 +286,12 @@ public: CRegTestParams() { strNetworkID = "regtest"; consensus.nSubsidyHalvingInterval = 150; + consensus.nMajorityEnforceBlockUpgrade = 750; + consensus.nMajorityRejectBlockOutdated = 950; + consensus.nMajorityWindow = 1000; consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests) consensus.BIP34Hash = uint256(); - consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests) + // consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests) consensus.BIP66Height = 1251; // BIP66 activated on regtest (Used in rpc activation tests) consensus.powLimit = uint256S("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1; consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks diff --git a/src/consensus/params.h b/src/consensus/params.h index 55a7b27b6..7d8d53c44 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -39,11 +39,16 @@ struct BIP9Deployment { struct Params { uint256 hashGenesisBlock; int nSubsidyHalvingInterval; + /** Used to check majorities for block version upgrade */ + int nMajorityEnforceBlockUpgrade; + int nMajorityRejectBlockOutdated; + int nMajorityWindow; + int nCoinbaseMaturity; /** Block height and hash at which BIP34 becomes active */ int BIP34Height; uint256 BIP34Hash; /** Block height at which BIP65 becomes active */ - int BIP65Height; + // int BIP65Height; /** Block height at which BIP66 becomes active */ int BIP66Height; /** diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index a5eeeeb11..8f0e88924 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1065,7 +1065,20 @@ static UniValue SoftForkMajorityDesc(int version, CBlockIndex* pindex, const Con activated = pindex->nHeight >= consensusParams.BIP66Height; break; case 4: - activated = pindex->nHeight >= consensusParams.BIP65Height; + int nFound = 0; + int nRequired = consensusParams.nMajorityRejectBlockOutdated; + CBlockIndex* pstart = pindex; + for (int i = 0; i < consensusParams.nMajorityWindow && pstart != NULL; i++) + { + if (pstart->nVersion >= version) + ++nFound; + pstart = pstart->pprev; + } + + activated = nFound >= nRequired; + rv.push_back(Pair("found", nFound)); + rv.push_back(Pair("required", nRequired)); + rv.push_back(Pair("window", consensusParams.nMajorityWindow)); break; } rv.push_back(Pair("status", activated)); diff --git a/src/validation.cpp b/src/validation.cpp index 2cb9e8c33..6431d5b26 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -84,6 +84,11 @@ CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; CTxMemPool mempool(::minRelayTxFee); +/** + * Returns true if there are nRequired or more blocks of minVersion or above + * in the last Consensus::Params::nMajorityWindow blocks, starting at pstart and going backwards. + */ +static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams); static void CheckBlockIndex(const Consensus::Params& consensusParams); /** Constant stuff for coinbase transactions we create: */ @@ -1858,8 +1863,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin flags |= SCRIPT_VERIFY_DERSIG; } - // Start enforcing CHECKLOCKTIMEVERIFY (BIP65) rule - if (pindex->nHeight >= chainparams.GetConsensus().BIP65Height) { + // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4 + // blocks, when 75% of the network has upgraded: + if (block.GetBaseVersion() >= 4 && IsSuperMajority(4, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; } @@ -3022,11 +3028,15 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta // Reject outdated version blocks when 95% (75% on testnet) of the network has upgraded: // check for version 2, 3 and 4 upgrades // Dogecoin: Version 2 enforcement was never used - if((block.GetBaseVersion() < 3 && nHeight >= consensusParams.BIP66Height) || - (block.GetBaseVersion() < 4 && nHeight >= consensusParams.BIP65Height)) + if((block.GetBaseVersion() < 3 && nHeight >= consensusParams.BIP66Height)) return state.Invalid(false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", block.GetBaseVersion()), strprintf("rejected nVersion=0x%08x block", block.GetBaseVersion())); + // Dogecoin: Introduce supermajority rules for v4 blocks + if (block.GetBaseVersion() < 4 && IsSuperMajority(4, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams)) + return state.Invalid(error("%s : rejected nVersion=3 block", __func__), + REJECT_OBSOLETE, "bad-version"); + return true; } @@ -3259,6 +3269,18 @@ static bool AcceptBlock(const std::shared_ptr& pblock, CValidation return true; } +static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams) +{ + unsigned int nFound = 0; + for (int i = 0; i < consensusParams.nMajorityWindow && nFound < nRequired && pstart != NULL; i++) + { + if (pstart->nVersion >= minVersion) + ++nFound; + pstart = pstart->pprev; + } + return (nFound >= nRequired); +} + bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr pblock, bool fForceProcessing, bool *fNewBlock) { {