forked from hush/hush3
Browse Source
Network upgrade activation mechanism Implements ZIP 200. Integration with `CChainParams` inspired by https://github.com/bitcoin/bitcoin/pull/7575. Includes block index rewinding logic cherry-picked from https://github.com/bitcoin/bitcoin/pull/8149. Closes #2286. Part of #2905.metaverse
![sysadmin@z.cash](/assets/img/avatar_default.png)
15 changed files with 709 additions and 16 deletions
@ -0,0 +1,124 @@ |
|||
// Copyright (c) 2018 The Zcash developers
|
|||
// Distributed under the MIT software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#include "consensus/upgrades.h" |
|||
|
|||
/**
|
|||
* General information about each network upgrade. |
|||
* Ordered by Consensus::UpgradeIndex. |
|||
*/ |
|||
const struct NUInfo NetworkUpgradeInfo[Consensus::MAX_NETWORK_UPGRADES] = { |
|||
{ |
|||
/*.nBranchId =*/ 0, |
|||
/*.strName =*/ "Sprout", |
|||
/*.strInfo =*/ "The Zcash network at launch", |
|||
}, |
|||
{ |
|||
/*.nBranchId =*/ 0x74736554, |
|||
/*.strName =*/ "Test dummy", |
|||
/*.strInfo =*/ "Test dummy info", |
|||
}, |
|||
{ |
|||
/*.nBranchId =*/ 0x5ba81b19, |
|||
/*.strName =*/ "Overwinter", |
|||
/*.strInfo =*/ "TBD", |
|||
} |
|||
}; |
|||
|
|||
UpgradeState NetworkUpgradeState( |
|||
int nHeight, |
|||
const Consensus::Params& params, |
|||
Consensus::UpgradeIndex idx) |
|||
{ |
|||
assert(nHeight >= 0); |
|||
assert(idx >= Consensus::BASE_SPROUT && idx < Consensus::MAX_NETWORK_UPGRADES); |
|||
auto nActivationHeight = params.vUpgrades[idx].nActivationHeight; |
|||
|
|||
if (nActivationHeight == Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) { |
|||
return UPGRADE_DISABLED; |
|||
} else if (nHeight >= nActivationHeight) { |
|||
// From ZIP 200:
|
|||
//
|
|||
// ACTIVATION_HEIGHT
|
|||
// The non-zero block height at which the network upgrade rules will come
|
|||
// into effect, and be enforced as part of the blockchain consensus.
|
|||
//
|
|||
// For removal of ambiguity, the block at height ACTIVATION_HEIGHT - 1 is
|
|||
// subject to the pre-upgrade consensus rules, and would be the last common
|
|||
// block in the event of a persistent pre-upgrade branch.
|
|||
return UPGRADE_ACTIVE; |
|||
} else { |
|||
return UPGRADE_PENDING; |
|||
} |
|||
} |
|||
|
|||
bool NetworkUpgradeActive( |
|||
int nHeight, |
|||
const Consensus::Params& params, |
|||
Consensus::UpgradeIndex idx) |
|||
{ |
|||
return NetworkUpgradeState(nHeight, params, idx) == UPGRADE_ACTIVE; |
|||
} |
|||
|
|||
int CurrentEpoch(int nHeight, const Consensus::Params& params) { |
|||
for (auto idxInt = Consensus::MAX_NETWORK_UPGRADES - 1; idxInt >= Consensus::BASE_SPROUT; idxInt--) { |
|||
if (NetworkUpgradeActive(nHeight, params, Consensus::UpgradeIndex(idxInt))) { |
|||
return idxInt; |
|||
} |
|||
} |
|||
} |
|||
|
|||
uint32_t CurrentEpochBranchId(int nHeight, const Consensus::Params& params) { |
|||
return NetworkUpgradeInfo[CurrentEpoch(nHeight, params)].nBranchId; |
|||
} |
|||
|
|||
bool IsActivationHeight( |
|||
int nHeight, |
|||
const Consensus::Params& params, |
|||
Consensus::UpgradeIndex idx) |
|||
{ |
|||
assert(idx >= Consensus::BASE_SPROUT && idx < Consensus::MAX_NETWORK_UPGRADES); |
|||
|
|||
// Don't count Sprout as an activation height
|
|||
if (idx == Consensus::BASE_SPROUT) { |
|||
return false; |
|||
} |
|||
|
|||
return nHeight >= 0 && nHeight == params.vUpgrades[idx].nActivationHeight; |
|||
} |
|||
|
|||
bool IsActivationHeightForAnyUpgrade( |
|||
int nHeight, |
|||
const Consensus::Params& params) |
|||
{ |
|||
if (nHeight < 0) { |
|||
return false; |
|||
} |
|||
|
|||
// Don't count Sprout as an activation height
|
|||
for (int idx = Consensus::BASE_SPROUT + 1; idx < Consensus::MAX_NETWORK_UPGRADES; idx++) { |
|||
if (nHeight == params.vUpgrades[idx].nActivationHeight) |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
boost::optional<int> NextActivationHeight( |
|||
int nHeight, |
|||
const Consensus::Params& params) |
|||
{ |
|||
if (nHeight < 0) { |
|||
return boost::none; |
|||
} |
|||
|
|||
// Don't count Sprout as an activation height
|
|||
for (auto idx = Consensus::BASE_SPROUT + 1; idx < Consensus::MAX_NETWORK_UPGRADES; idx++) { |
|||
if (NetworkUpgradeState(nHeight, params, Consensus::UpgradeIndex(idx)) == UPGRADE_PENDING) { |
|||
return params.vUpgrades[idx].nActivationHeight; |
|||
} |
|||
} |
|||
|
|||
return boost::none; |
|||
} |
@ -0,0 +1,87 @@ |
|||
// Copyright (c) 2018 The Zcash developers
|
|||
// Distributed under the MIT software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#ifndef ZCASH_CONSENSUS_UPGRADES_H |
|||
#define ZCASH_CONSENSUS_UPGRADES_H |
|||
|
|||
#include "consensus/params.h" |
|||
|
|||
#include <boost/optional.hpp> |
|||
|
|||
enum UpgradeState { |
|||
UPGRADE_DISABLED, |
|||
UPGRADE_PENDING, |
|||
UPGRADE_ACTIVE |
|||
}; |
|||
|
|||
struct NUInfo { |
|||
/** Branch ID (a random non-zero 32-bit value) */ |
|||
uint32_t nBranchId; |
|||
/** User-facing name for the upgrade */ |
|||
std::string strName; |
|||
/** User-facing information string about the upgrade */ |
|||
std::string strInfo; |
|||
}; |
|||
|
|||
extern const struct NUInfo NetworkUpgradeInfo[]; |
|||
|
|||
/**
|
|||
* Checks the state of a given network upgrade based on block height. |
|||
* Caller must check that the height is >= 0 (and handle unknown heights). |
|||
*/ |
|||
UpgradeState NetworkUpgradeState( |
|||
int nHeight, |
|||
const Consensus::Params& params, |
|||
Consensus::UpgradeIndex idx); |
|||
|
|||
/**
|
|||
* Returns true if the given network upgrade is active as of the given block |
|||
* height. Caller must check that the height is >= 0 (and handle unknown |
|||
* heights). |
|||
*/ |
|||
bool NetworkUpgradeActive( |
|||
int nHeight, |
|||
const Consensus::Params& params, |
|||
Consensus::UpgradeIndex idx); |
|||
|
|||
/**
|
|||
* Returns the index of the most recent upgrade as of the given block height |
|||
* (corresponding to the current "epoch"). Consensus::BASE_SPROUT is the |
|||
* default value if no upgrades are active. Caller must check that the height |
|||
* is >= 0 (and handle unknown heights). |
|||
*/ |
|||
int CurrentEpoch(int nHeight, const Consensus::Params& params); |
|||
|
|||
/**
|
|||
* Returns the branch ID of the most recent upgrade as of the given block height |
|||
* (corresponding to the current "epoch"), or 0 if no upgrades are active. |
|||
* Caller must check that the height is >= 0 (and handle unknown heights). |
|||
*/ |
|||
uint32_t CurrentEpochBranchId(int nHeight, const Consensus::Params& params); |
|||
|
|||
/**
|
|||
* Returns true if the given block height is the activation height for the given |
|||
* upgrade. |
|||
*/ |
|||
bool IsActivationHeight( |
|||
int nHeight, |
|||
const Consensus::Params& params, |
|||
Consensus::UpgradeIndex upgrade); |
|||
|
|||
/**
|
|||
* Returns true if the given block height is the activation height for any upgrade. |
|||
*/ |
|||
bool IsActivationHeightForAnyUpgrade( |
|||
int nHeight, |
|||
const Consensus::Params& params); |
|||
|
|||
/**
|
|||
* Returns the activation height for the next upgrade after the given block height, |
|||
* or boost::none if there are no more known upgrades. |
|||
*/ |
|||
boost::optional<int> NextActivationHeight( |
|||
int nHeight, |
|||
const Consensus::Params& params); |
|||
|
|||
#endif // ZCASH_CONSENSUS_UPGRADES_H
|
@ -0,0 +1,173 @@ |
|||
#include <gtest/gtest.h> |
|||
|
|||
#include "chainparams.h" |
|||
#include "consensus/upgrades.h" |
|||
|
|||
#include <boost/optional.hpp> |
|||
|
|||
class UpgradesTest : public ::testing::Test { |
|||
protected: |
|||
virtual void SetUp() { |
|||
} |
|||
|
|||
virtual void TearDown() { |
|||
// Revert to default
|
|||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); |
|||
} |
|||
}; |
|||
|
|||
TEST_F(UpgradesTest, NetworkUpgradeState) { |
|||
SelectParams(CBaseChainParams::REGTEST); |
|||
const Consensus::Params& params = Params().GetConsensus(); |
|||
|
|||
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
|
|||
EXPECT_EQ( |
|||
NetworkUpgradeState(0, params, Consensus::UPGRADE_TESTDUMMY), |
|||
UPGRADE_DISABLED); |
|||
EXPECT_EQ( |
|||
NetworkUpgradeState(1000000, params, Consensus::UPGRADE_TESTDUMMY), |
|||
UPGRADE_DISABLED); |
|||
|
|||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); |
|||
|
|||
EXPECT_EQ( |
|||
NetworkUpgradeState(0, params, Consensus::UPGRADE_TESTDUMMY), |
|||
UPGRADE_ACTIVE); |
|||
EXPECT_EQ( |
|||
NetworkUpgradeState(1000000, params, Consensus::UPGRADE_TESTDUMMY), |
|||
UPGRADE_ACTIVE); |
|||
|
|||
int nActivationHeight = 100; |
|||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight); |
|||
|
|||
EXPECT_EQ( |
|||
NetworkUpgradeState(0, params, Consensus::UPGRADE_TESTDUMMY), |
|||
UPGRADE_PENDING); |
|||
EXPECT_EQ( |
|||
NetworkUpgradeState(nActivationHeight - 1, params, Consensus::UPGRADE_TESTDUMMY), |
|||
UPGRADE_PENDING); |
|||
EXPECT_EQ( |
|||
NetworkUpgradeState(nActivationHeight, params, Consensus::UPGRADE_TESTDUMMY), |
|||
UPGRADE_ACTIVE); |
|||
EXPECT_EQ( |
|||
NetworkUpgradeState(1000000, params, Consensus::UPGRADE_TESTDUMMY), |
|||
UPGRADE_ACTIVE); |
|||
} |
|||
|
|||
TEST_F(UpgradesTest, CurrentEpoch) { |
|||
SelectParams(CBaseChainParams::REGTEST); |
|||
const Consensus::Params& params = Params().GetConsensus(); |
|||
auto nBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_TESTDUMMY].nBranchId; |
|||
|
|||
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
|
|||
EXPECT_EQ(CurrentEpoch(0, params), Consensus::BASE_SPROUT); |
|||
EXPECT_EQ(CurrentEpochBranchId(0, params), 0); |
|||
EXPECT_EQ(CurrentEpoch(1000000, params), Consensus::BASE_SPROUT); |
|||
EXPECT_EQ(CurrentEpochBranchId(1000000, params), 0); |
|||
|
|||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); |
|||
|
|||
EXPECT_EQ(CurrentEpoch(0, params), Consensus::UPGRADE_TESTDUMMY); |
|||
EXPECT_EQ(CurrentEpochBranchId(0, params), nBranchId); |
|||
EXPECT_EQ(CurrentEpoch(1000000, params), Consensus::UPGRADE_TESTDUMMY); |
|||
EXPECT_EQ(CurrentEpochBranchId(1000000, params), nBranchId); |
|||
|
|||
int nActivationHeight = 100; |
|||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight); |
|||
|
|||
EXPECT_EQ(CurrentEpoch(0, params), Consensus::BASE_SPROUT); |
|||
EXPECT_EQ(CurrentEpochBranchId(0, params), 0); |
|||
EXPECT_EQ(CurrentEpoch(nActivationHeight - 1, params), Consensus::BASE_SPROUT); |
|||
EXPECT_EQ(CurrentEpochBranchId(nActivationHeight - 1, params), 0); |
|||
EXPECT_EQ(CurrentEpoch(nActivationHeight, params), Consensus::UPGRADE_TESTDUMMY); |
|||
EXPECT_EQ(CurrentEpochBranchId(nActivationHeight, params), nBranchId); |
|||
EXPECT_EQ(CurrentEpoch(1000000, params), Consensus::UPGRADE_TESTDUMMY); |
|||
EXPECT_EQ(CurrentEpochBranchId(1000000, params), nBranchId); |
|||
} |
|||
|
|||
TEST_F(UpgradesTest, IsActivationHeight) { |
|||
SelectParams(CBaseChainParams::REGTEST); |
|||
const Consensus::Params& params = Params().GetConsensus(); |
|||
|
|||
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
|
|||
EXPECT_FALSE(IsActivationHeight(-1, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
EXPECT_FALSE(IsActivationHeight(0, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
EXPECT_FALSE(IsActivationHeight(1, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
EXPECT_FALSE(IsActivationHeight(1000000, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
|
|||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); |
|||
|
|||
EXPECT_FALSE(IsActivationHeight(-1, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
EXPECT_TRUE(IsActivationHeight(0, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
EXPECT_FALSE(IsActivationHeight(1, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
EXPECT_FALSE(IsActivationHeight(1000000, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
|
|||
int nActivationHeight = 100; |
|||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight); |
|||
|
|||
EXPECT_FALSE(IsActivationHeight(-1, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
EXPECT_FALSE(IsActivationHeight(0, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
EXPECT_FALSE(IsActivationHeight(1, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
EXPECT_FALSE(IsActivationHeight(nActivationHeight - 1, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
EXPECT_TRUE(IsActivationHeight(nActivationHeight, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
EXPECT_FALSE(IsActivationHeight(nActivationHeight + 1, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
EXPECT_FALSE(IsActivationHeight(1000000, params, Consensus::UPGRADE_TESTDUMMY)); |
|||
} |
|||
|
|||
TEST_F(UpgradesTest, IsActivationHeightForAnyUpgrade) { |
|||
SelectParams(CBaseChainParams::REGTEST); |
|||
const Consensus::Params& params = Params().GetConsensus(); |
|||
|
|||
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
|
|||
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(-1, params)); |
|||
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(0, params)); |
|||
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1, params)); |
|||
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params)); |
|||
|
|||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); |
|||
|
|||
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(-1, params)); |
|||
EXPECT_TRUE(IsActivationHeightForAnyUpgrade(0, params)); |
|||
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1, params)); |
|||
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params)); |
|||
|
|||
int nActivationHeight = 100; |
|||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight); |
|||
|
|||
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(-1, params)); |
|||
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(0, params)); |
|||
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1, params)); |
|||
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(nActivationHeight - 1, params)); |
|||
EXPECT_TRUE(IsActivationHeightForAnyUpgrade(nActivationHeight, params)); |
|||
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(nActivationHeight + 1, params)); |
|||
EXPECT_FALSE(IsActivationHeightForAnyUpgrade(1000000, params)); |
|||
} |
|||
|
|||
TEST_F(UpgradesTest, NextActivationHeight) { |
|||
SelectParams(CBaseChainParams::REGTEST); |
|||
const Consensus::Params& params = Params().GetConsensus(); |
|||
|
|||
// Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT
|
|||
EXPECT_EQ(NextActivationHeight(-1, params), boost::none); |
|||
EXPECT_EQ(NextActivationHeight(0, params), boost::none); |
|||
EXPECT_EQ(NextActivationHeight(1, params), boost::none); |
|||
EXPECT_EQ(NextActivationHeight(1000000, params), boost::none); |
|||
|
|||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); |
|||
|
|||
EXPECT_EQ(NextActivationHeight(-1, params), boost::none); |
|||
EXPECT_EQ(NextActivationHeight(0, params), boost::none); |
|||
EXPECT_EQ(NextActivationHeight(1, params), boost::none); |
|||
EXPECT_EQ(NextActivationHeight(1000000, params), boost::none); |
|||
|
|||
int nActivationHeight = 100; |
|||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_TESTDUMMY, nActivationHeight); |
|||
|
|||
EXPECT_EQ(NextActivationHeight(-1, params), boost::none); |
|||
EXPECT_EQ(NextActivationHeight(0, params), nActivationHeight); |
|||
EXPECT_EQ(NextActivationHeight(1, params), nActivationHeight); |
|||
EXPECT_EQ(NextActivationHeight(nActivationHeight - 1, params), nActivationHeight); |
|||
EXPECT_EQ(NextActivationHeight(nActivationHeight, params), boost::none); |
|||
EXPECT_EQ(NextActivationHeight(nActivationHeight + 1, params), boost::none); |
|||
EXPECT_EQ(NextActivationHeight(1000000, params), boost::none); |
|||
} |
Loading…
Reference in new issue