diff --git a/src/consensus/upgrades.cpp b/src/consensus/upgrades.cpp index f06e7063c..42089bbb1 100644 --- a/src/consensus/upgrades.cpp +++ b/src/consensus/upgrades.cpp @@ -102,3 +102,21 @@ bool IsActivationHeightForAnyUpgrade( return false; } + +boost::optional 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; +} diff --git a/src/consensus/upgrades.h b/src/consensus/upgrades.h index c62655530..0c5462c2e 100644 --- a/src/consensus/upgrades.h +++ b/src/consensus/upgrades.h @@ -7,6 +7,8 @@ #include "consensus/params.h" +#include + enum UpgradeState { UPGRADE_DISABLED, UPGRADE_PENDING, @@ -74,4 +76,12 @@ 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 NextActivationHeight( + int nHeight, + const Consensus::Params& params); + #endif // ZCASH_CONSENSUS_UPGRADES_H diff --git a/src/gtest/test_upgrades.cpp b/src/gtest/test_upgrades.cpp index 3312e0569..1066a28d0 100644 --- a/src/gtest/test_upgrades.cpp +++ b/src/gtest/test_upgrades.cpp @@ -3,6 +3,8 @@ #include "chainparams.h" #include "consensus/upgrades.h" +#include + class UpgradesTest : public ::testing::Test { protected: virtual void SetUp() { @@ -140,3 +142,32 @@ TEST_F(UpgradesTest, IsActivationHeightForAnyUpgrade) { 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); +}