From 780f526bc9466c4dc51dd290f9fa5f87c5321387 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 17 Jan 2018 11:25:28 +0000 Subject: [PATCH] Network upgrade activation mechanism --- src/Makefile.am | 2 + src/chainparams.cpp | 8 ++++ src/consensus/params.h | 42 +++++++++++++++++ src/consensus/upgrades.cpp | 94 ++++++++++++++++++++++++++++++++++++++ src/consensus/upgrades.h | 77 +++++++++++++++++++++++++++++++ 5 files changed, 223 insertions(+) create mode 100644 src/consensus/upgrades.cpp create mode 100644 src/consensus/upgrades.h diff --git a/src/Makefile.am b/src/Makefile.am index 44b4d8281..d8ab34ea0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -138,6 +138,7 @@ BITCOIN_CORE_H = \ compressor.h \ consensus/consensus.h \ consensus/params.h \ + consensus/upgrades.h \ consensus/validation.h \ core_io.h \ core_memusage.h \ @@ -354,6 +355,7 @@ libbitcoin_common_a_SOURCES = \ chainparams.cpp \ coins.cpp \ compressor.cpp \ + consensus/upgrades.cpp \ core_read.cpp \ core_write.cpp \ hash.cpp \ diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 36b71b5c7..fd928318d 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -90,6 +90,9 @@ public: consensus.nPowMaxAdjustDown = 32; // 32% adjustment down consensus.nPowMaxAdjustUp = 16; // 16% adjustment up consensus.nPowTargetSpacing = 2.5 * 60; + consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight = + Consensus::NetworkUpgrade::ALWAYS_ACTIVE; + /** * The message start string should be awesome! ⓩ❤ */ @@ -241,6 +244,9 @@ public: consensus.nPowMaxAdjustDown = 32; // 32% adjustment down consensus.nPowMaxAdjustUp = 16; // 16% adjustment up consensus.nPowTargetSpacing = 2.5 * 60; + consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight = + Consensus::NetworkUpgrade::ALWAYS_ACTIVE; + pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0x1a; pchMessageStart[2] = 0xf9; @@ -341,6 +347,8 @@ public: consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up consensus.nPowTargetSpacing = 2.5 * 60; + consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight = + Consensus::NetworkUpgrade::ALWAYS_ACTIVE; pchMessageStart[0] = 0xaa; pchMessageStart[1] = 0xe8; diff --git a/src/consensus/params.h b/src/consensus/params.h index c74e66d5f..59d725cba 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -9,6 +9,47 @@ #include "uint256.h" namespace Consensus { + +/** + * Index into Params.vUpgrades and NetworkUpgradeInfo + * + * Being array indices, these MUST be numbered consecutively. + * + * The order of these indices MUST match the order of the upgrades on-chain, as + * several functions depends on the enum being sorted. + */ +enum UpgradeIndex { + // Sprout must be first + BASE_SPROUT, + // NOTE: Also add new upgrades to NetworkUpgradeInfo in upgrades.cpp + MAX_NETWORK_UPGRADES +}; + +struct NetworkUpgrade { + /** + * Height of the first block for which the new consensus rules will be active + */ + int nActivationHeight; + + /** + * Special value for nActivationHeight indicating that the upgrade is always active. + * This is useful for testing, as it means tests don't need to deal with the activation + * process (namely, faking a chain of somewhat-arbitrary length). + * + * New blockchains that want to enable upgrade rules from the beginning can also use + * this value. However, additional care must be taken to ensure the genesis block + * satisfies the enabled rules. + */ + static constexpr int ALWAYS_ACTIVE = 0; + + /** + * Special value for nActivationHeight indicating that the upgrade will never activate. + * This is useful when adding upgrade code that has a testnet activation height, but + * should remain disabled on mainnet. + */ + static constexpr int NO_ACTIVATION_HEIGHT = -1; +}; + /** * Parameters that influence chain consensus. */ @@ -39,6 +80,7 @@ struct Params { int nMajorityEnforceBlockUpgrade; int nMajorityRejectBlockOutdated; int nMajorityWindow; + NetworkUpgrade vUpgrades[MAX_NETWORK_UPGRADES]; /** Proof of work parameters */ uint256 powLimit; int64_t nPowAveragingWindow; diff --git a/src/consensus/upgrades.cpp b/src/consensus/upgrades.cpp new file mode 100644 index 000000000..1191e02ff --- /dev/null +++ b/src/consensus/upgrades.cpp @@ -0,0 +1,94 @@ +// 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", + } +}; + +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 ???: + // + // ACTIVATION_HEIGHT + // The block height at which the network upgrade rules will come into effect. + // + // For removal of ambiguity, the block at height ACTIVATION_HEIGHT - 1 is + // subject to the pre-upgrade consensus rules. + 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; +} diff --git a/src/consensus/upgrades.h b/src/consensus/upgrades.h new file mode 100644 index 000000000..c62655530 --- /dev/null +++ b/src/consensus/upgrades.h @@ -0,0 +1,77 @@ +// 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" + +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); + +#endif // ZCASH_CONSENSUS_UPGRADES_H