373 lines
13 KiB
C++
373 lines
13 KiB
C++
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
|
// Copyright (c) 2016-2023 The Zcash developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
|
|
|
#ifndef BITCOIN_CONSENSUS_PARAMS_H
|
|
#define BITCOIN_CONSENSUS_PARAMS_H
|
|
|
|
#include <script/script.h>
|
|
#include "uint256.h"
|
|
#include "key_constants.h"
|
|
#include <zcash/address/sapling.hpp>
|
|
|
|
#include <optional>
|
|
#include <variant>
|
|
|
|
namespace Consensus {
|
|
|
|
// Early declaration to ensure it is accessible.
|
|
struct Params;
|
|
|
|
/**
|
|
* 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 depend on the enum being sorted.
|
|
*/
|
|
enum UpgradeIndex : uint32_t {
|
|
// Sprout must be first
|
|
BASE_SPROUT,
|
|
UPGRADE_TESTDUMMY,
|
|
UPGRADE_OVERWINTER,
|
|
UPGRADE_SAPLING,
|
|
UPGRADE_BLOSSOM,
|
|
UPGRADE_HEARTWOOD,
|
|
UPGRADE_CANOPY,
|
|
UPGRADE_NU5,
|
|
// Add new network upgrades before this line.
|
|
// NOTE: Also add new upgrades to NetworkUpgradeInfo in upgrades.cpp
|
|
UPGRADE_ZFUTURE,
|
|
MAX_NETWORK_UPGRADES
|
|
};
|
|
|
|
struct NetworkUpgrade {
|
|
/**
|
|
* The first protocol version which will understand the new consensus rules
|
|
*/
|
|
int nProtocolVersion;
|
|
|
|
/**
|
|
* 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;
|
|
|
|
/**
|
|
* The hash of the block at height nActivationHeight, if known. This is set manually
|
|
* after a network upgrade activates.
|
|
*
|
|
* We use this in IsInitialBlockDownload to detect whether we are potentially being
|
|
* fed a fake alternate chain. We use NU activation blocks for this purpose instead of
|
|
* the checkpoint blocks, because network upgrades (should) have significantly more
|
|
* scrutiny than regular releases. nMinimumChainWork MUST be set to at least the chain
|
|
* work of this block, otherwise this detection will have false positives.
|
|
*/
|
|
std::optional<uint256> hashActivationBlock;
|
|
};
|
|
|
|
typedef std::variant<libzcash::SaplingPaymentAddress, CScript> FundingStreamAddress;
|
|
|
|
/**
|
|
* Index into Params.vFundingStreams.
|
|
*
|
|
* Being array indices, these MUST be numbered consecutively.
|
|
*/
|
|
enum FundingStreamIndex : uint32_t {
|
|
FS_ZIP214_BP,
|
|
FS_ZIP214_ZF,
|
|
FS_ZIP214_MG,
|
|
MAX_FUNDING_STREAMS,
|
|
};
|
|
const auto FIRST_FUNDING_STREAM = FS_ZIP214_BP;
|
|
|
|
enum FundingStreamError {
|
|
CANOPY_NOT_ACTIVE,
|
|
ILLEGAL_RANGE,
|
|
INSUFFICIENT_ADDRESSES,
|
|
};
|
|
|
|
class FundingStream
|
|
{
|
|
private:
|
|
int startHeight;
|
|
int endHeight;
|
|
std::vector<FundingStreamAddress> addresses;
|
|
|
|
FundingStream(int startHeight, int endHeight, const std::vector<FundingStreamAddress>& addresses):
|
|
startHeight(startHeight), endHeight(endHeight), addresses(addresses) { }
|
|
public:
|
|
FundingStream(const FundingStream& fs):
|
|
startHeight(fs.startHeight), endHeight(fs.endHeight), addresses(fs.addresses) { }
|
|
|
|
static std::variant<FundingStream, FundingStreamError> ValidateFundingStream(
|
|
const Consensus::Params& params,
|
|
const int startHeight,
|
|
const int endHeight,
|
|
const std::vector<FundingStreamAddress>& addresses
|
|
);
|
|
|
|
static FundingStream ParseFundingStream(
|
|
const Consensus::Params& params,
|
|
const KeyConstants& keyConstants,
|
|
const int startHeight,
|
|
const int endHeight,
|
|
const std::vector<std::string>& strAddresses);
|
|
|
|
int GetStartHeight() const { return startHeight; };
|
|
int GetEndHeight() const { return endHeight; };
|
|
const std::vector<FundingStreamAddress>& GetAddresses() const {
|
|
return addresses;
|
|
};
|
|
|
|
FundingStreamAddress RecipientAddress(const Params& params, int nHeight) const;
|
|
};
|
|
|
|
enum ConsensusFeature : uint32_t {
|
|
// Index value for the maximum consensus feature ID.
|
|
MAX_FEATURES
|
|
};
|
|
const auto FIRST_CONSENSUS_FEATURE = MAX_FEATURES;
|
|
|
|
template <class Feature>
|
|
struct FeatureInfo {
|
|
std::vector<Feature> dependsOn;
|
|
UpgradeIndex activation;
|
|
};
|
|
|
|
/**
|
|
* A FeatureSet encodes a directed acyclic graph of feature dependencies
|
|
* as an array indexed by feature ID. Values are FeatureInfo objects
|
|
* containing the list of feature IDs upon which the index's feature ID
|
|
* depends.
|
|
*
|
|
* The `Feature` and `Params` template parameters permit for the
|
|
* logic of `FeatureActive` to be tested against a mock set of
|
|
* features and activation heights.
|
|
*/
|
|
template <class Feature, class Params>
|
|
class FeatureSet {
|
|
private:
|
|
std::vector<FeatureInfo<Feature>> features;
|
|
public:
|
|
FeatureSet(std::vector<FeatureInfo<Feature>> features): features(features) {
|
|
}
|
|
|
|
bool FeatureActive(
|
|
const Params& params,
|
|
const int nHeight,
|
|
const Feature feature) const {
|
|
assert(feature < features.size());
|
|
|
|
// The feature must be explicitly required by a CLI argument or by
|
|
// the feature being universally available above a network upgrade
|
|
// activation height.
|
|
if (params.NetworkUpgradeActive(nHeight, features[feature].activation) ||
|
|
params.FeatureRequired(feature)) {
|
|
// Transitively check that if a feature is active, all of the other features
|
|
// that it depends on are also active.
|
|
auto requires = features[feature].dependsOn;
|
|
assert(std::all_of(
|
|
requires.begin(),
|
|
requires.end(),
|
|
[&](Feature feat) {
|
|
return FeatureActive(params, nHeight, feat);
|
|
}
|
|
));
|
|
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* The set of features supported by Zcashd.
|
|
*/
|
|
const FeatureSet<ConsensusFeature, Params> Features({});
|
|
|
|
/** ZIP208 block target interval in seconds. */
|
|
static const unsigned int PRE_BLOSSOM_POW_TARGET_SPACING = 150;
|
|
static const unsigned int POST_BLOSSOM_POW_TARGET_SPACING = 75;
|
|
static_assert(PRE_BLOSSOM_POW_TARGET_SPACING > POST_BLOSSOM_POW_TARGET_SPACING, "Blossom target spacing must be less than pre-Blossom target spacing.");
|
|
static_assert(PRE_BLOSSOM_POW_TARGET_SPACING % POST_BLOSSOM_POW_TARGET_SPACING == 0, "Blossom target spacing must exactly divide pre-Blossom target spacing.");
|
|
|
|
static const int BLOSSOM_POW_TARGET_SPACING_RATIO = PRE_BLOSSOM_POW_TARGET_SPACING / POST_BLOSSOM_POW_TARGET_SPACING;
|
|
static_assert(BLOSSOM_POW_TARGET_SPACING_RATIO * POST_BLOSSOM_POW_TARGET_SPACING == PRE_BLOSSOM_POW_TARGET_SPACING, "Invalid BLOSSOM_POW_TARGET_SPACING_RATIO");
|
|
|
|
static const unsigned int PRE_BLOSSOM_HALVING_INTERVAL = 840000;
|
|
static const unsigned int PRE_BLOSSOM_REGTEST_HALVING_INTERVAL = 144;
|
|
|
|
#define POST_BLOSSOM_HALVING_INTERVAL(preBlossomInterval) \
|
|
(preBlossomInterval * Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO)
|
|
|
|
/**
|
|
* Parameters that influence chain consensus.
|
|
*/
|
|
struct Params {
|
|
/**
|
|
* Returns the activation height for the specified network upgrade, if any.
|
|
*/
|
|
std::optional<int> GetActivationHeight(Consensus::UpgradeIndex idx) const;
|
|
|
|
/**
|
|
* 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, Consensus::UpgradeIndex idx) const;
|
|
|
|
/**
|
|
* Returns the activation height of the latest settled upgrade, as defined
|
|
* in <https://zips.z.cash/protocol/protocol.pdf#blockchain>.
|
|
*/
|
|
int HeightOfLatestSettledUpgrade() const;
|
|
|
|
bool FutureTimestampSoftForkActive(int nHeight) const;
|
|
|
|
bool FeatureActive(int nHeight, Consensus::ConsensusFeature feature) const;
|
|
|
|
bool FeatureRequired(Consensus::ConsensusFeature feature) const;
|
|
|
|
uint256 hashGenesisBlock;
|
|
|
|
bool fCoinbaseMustBeShielded = false;
|
|
|
|
/** Needs to evenly divide MAX_SUBSIDY to avoid rounding errors. */
|
|
int nSubsidySlowStartInterval;
|
|
/**
|
|
* Shift based on a linear ramp for slow start:
|
|
*
|
|
* MAX_SUBSIDY*(t_s/2 + t_r) = MAX_SUBSIDY*t_h Coin balance
|
|
* t_s + t_r = t_h + t_c Block balance
|
|
*
|
|
* t_s = nSubsidySlowStartInterval
|
|
* t_r = number of blocks between end of slow start and first halving
|
|
* t_h = nPreBlossomSubsidyHalvingInterval
|
|
* t_c = SubsidySlowStartShift()
|
|
*/
|
|
int SubsidySlowStartShift() const { return nSubsidySlowStartInterval / 2; }
|
|
int nPreBlossomSubsidyHalvingInterval;
|
|
int nPostBlossomSubsidyHalvingInterval;
|
|
|
|
/**
|
|
* Identify the halving index at the specified height. The result will be
|
|
* negative during the slow-start period.
|
|
*/
|
|
int Halving(int nHeight) const;
|
|
|
|
/**
|
|
* Get the block height of the specified halving.
|
|
*/
|
|
int HalvingHeight(int nHeight, int halvingIndex) const;
|
|
|
|
int GetLastFoundersRewardBlockHeight(int nHeight) const;
|
|
|
|
int FundingPeriodIndex(int fundingStreamStartHeight, int nHeight) const;
|
|
|
|
/** Used to check majorities for block version upgrade */
|
|
int nMajorityEnforceBlockUpgrade;
|
|
int nMajorityRejectBlockOutdated;
|
|
int nMajorityWindow;
|
|
NetworkUpgrade vUpgrades[MAX_NETWORK_UPGRADES];
|
|
|
|
int nFundingPeriodLength;
|
|
std::optional<FundingStream> vFundingStreams[MAX_FUNDING_STREAMS];
|
|
void AddZIP207FundingStream(
|
|
const KeyConstants& keyConstants,
|
|
FundingStreamIndex idx,
|
|
int startHeight,
|
|
int endHeight,
|
|
const std::vector<std::string>& addresses);
|
|
|
|
/**
|
|
* A set of features that have been explicitly force-enabled
|
|
* via the CLI, overriding block-height based decisions for
|
|
* this feature.
|
|
*/
|
|
std::set<ConsensusFeature> vRequiredFeatures;
|
|
|
|
/**
|
|
* Default block height at which the future timestamp soft fork rule activates.
|
|
*
|
|
* Genesis blocks are hard-coded into the binary for all networks
|
|
* (mainnet, testnet, regtest), and have now-ancient timestamps. So we need to
|
|
* handle the case where we might use the genesis block's timestamp as the
|
|
* median-time-past.
|
|
*
|
|
* GetMedianTimePast() is implemented such that the chosen block is the
|
|
* median of however many blocks we are able to select up to
|
|
* nMedianTimeSpan = 11. For example, if nHeight == 6:
|
|
*
|
|
* ,-<pmedian ,-<pbegin ,-<pend
|
|
* [-, -, -, -, 0, 1, 2, 3, 4, 5, 6] -
|
|
*
|
|
* and thus pbegin[(pend - pbegin)/2] will select block height 3, assuming
|
|
* that the block timestamps are all greater than the genesis block's
|
|
* timestamp. For regtest mode, this is a valid assumption; we generate blocks
|
|
* deterministically and in-order. For mainnet it was true in practice, and
|
|
* we aren't going to be starting a new chain linked directly from the mainnet
|
|
* genesis block.
|
|
*
|
|
* Therefore, for regtest and mainnet we only risk using the regtest genesis
|
|
* block's timestamp for nHeight < 2 (as GetMedianTimePast() uses floor division).
|
|
*
|
|
* Separately, for mainnet this is also necessary because there was a long time
|
|
* between starting to find the mainnet genesis block (which was mined with a
|
|
* single laptop) and mining the block at height 1. For any new mainnet chain
|
|
* using Zcash code, the soft fork rule would be enabled from the start so that
|
|
* miners would limit their timestamps accordingly.
|
|
*
|
|
* For testnet, the future timestamp soft fork rule was violated for many
|
|
* blocks prior to Blossom activation. At Blossom, the time threshold for the
|
|
* (testnet-specific) minimum difficulty rule was changed in such a way that
|
|
* starting from shortly after the Blossom activation, no further blocks
|
|
* violate the soft fork rule. So for testnet we override the soft fork
|
|
* activation height in chainparams.cpp.
|
|
*/
|
|
int nFutureTimestampSoftForkHeight = 2;
|
|
|
|
/** Proof of work parameters */
|
|
unsigned int nEquihashN = 0;
|
|
unsigned int nEquihashK = 0;
|
|
uint256 powLimit;
|
|
std::optional<uint32_t> nPowAllowMinDifficultyBlocksAfterHeight;
|
|
bool fPowNoRetargeting;
|
|
int64_t nPowAveragingWindow;
|
|
int64_t nPowMaxAdjustDown;
|
|
int64_t nPowMaxAdjustUp;
|
|
int64_t nPreBlossomPowTargetSpacing;
|
|
int64_t nPostBlossomPowTargetSpacing;
|
|
|
|
int64_t PoWTargetSpacing(int nHeight) const;
|
|
int64_t AveragingWindowTimespan(int nHeight) const;
|
|
int64_t MinActualTimespan(int nHeight) const;
|
|
int64_t MaxActualTimespan(int nHeight) const;
|
|
|
|
uint256 nMinimumChainWork;
|
|
};
|
|
} // namespace Consensus
|
|
|
|
#endif // BITCOIN_CONSENSUS_PARAMS_H
|