Enable future timestamp soft fork at varying heights according to network.

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira Hopwood 2020-02-04 19:56:53 +00:00
parent 5199ecdf41
commit 4ab896c69d
5 changed files with 71 additions and 23 deletions

View File

@ -323,6 +323,22 @@ public:
consensus.vUpgrades[Consensus::UPGRADE_HEARTWOOD].nActivationHeight =
Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
// On testnet we activate this rule 6 blocks after Blossom activation. From block 299188 and
// prior to Blossom activation, the testnet minimum-difficulty threshold was 15 minutes (i.e.
// a minimum difficulty block can be mined if no block is mined normally within 15 minutes):
// <https://zips.z.cash/zip-0205#change-to-difficulty-adjustment-on-testnet>
// However the median-time-past is 6 blocks behind, and the worst-case time for 7 blocks at a
// 15-minute spacing is ~105 minutes, which is exceeds the limit imposed by the soft fork of
// 90 minutes.
//
// After Blossom, the minimum difficulty threshold time is changed to 6 times the block target
// spacing, which is 7.5 minutes:
// <https://zips.z.cash/zip-0208#minimum-difficulty-blocks-on-the-test-network>
// 7 times that is 52.5 minutes which is well within the limit imposed by the soft fork.
static_assert(6 * Consensus::POST_BLOSSOM_POW_TARGET_SPACING * 7 < MAX_FUTURE_BLOCK_TIME_MTP - 60);
consensus.nFutureTimestampSoftForkHeight = consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight + 6;
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000000000000001dbb4c4224");

View File

@ -11,6 +11,10 @@ namespace Consensus {
return NetworkUpgradeState(nHeight, *this, idx) == UPGRADE_ACTIVE;
}
bool Params::FutureTimestampSoftForkActive(int nHeight) const {
return nHeight >= nFutureTimestampSoftForkHeight;
}
int Params::Halving(int nHeight) const {
// zip208
// Halving(height) :=

View File

@ -96,6 +96,8 @@ struct Params {
*/
bool NetworkUpgradeActive(int nHeight, Consensus::UpgradeIndex idx) const;
bool FutureTimestampSoftForkActive(int nHeight) const;
uint256 hashGenesisBlock;
bool fCoinbaseMustBeShielded;
@ -126,6 +128,47 @@ struct Params {
int nMajorityRejectBlockOutdated;
int nMajorityWindow;
NetworkUpgrade vUpgrades[MAX_NETWORK_UPGRADES];
/**
* 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;

View File

@ -3784,29 +3784,14 @@ bool ContextualCheckBlockHeader(
REJECT_INVALID, "time-too-old");
}
// Genesis blocks are hard-coded into the binary, and both testnet and
// regtest 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.
// Check future timestamp soft fork rule introduced in v2.1.1-1.
// This retrospectively activates at block height 2 for mainnet and regtest,
// and 6 blocks after Blossom activation for testnet.
// Explanations of these activation heights are in src/consensus/params.h
// and chainparams.cpp.
//
// 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.
//
// Therefore, we only risk using the regtest genesis block's timestamp for
// nHeight < 2 (as GetMedianTimePast() uses floor division).
//
// Separately, 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.
//
if (nHeight >= 2 && block.GetBlockTime() > medianTimePast + MAX_FUTURE_BLOCK_TIME_MTP) {
if (consensusParams.FutureTimestampSoftForkActive(nHeight) &&
block.GetBlockTime() > medianTimePast + MAX_FUTURE_BLOCK_TIME_MTP) {
return state.Invalid(error("%s: block at height %d, timestamp %d is too far ahead of median-time-past, limit is %d",
__func__, nHeight, block.GetBlockTime(), medianTimePast + MAX_FUTURE_BLOCK_TIME_MTP),
REJECT_INVALID, "time-too-far-ahead-of-mtp");

View File

@ -102,7 +102,7 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams,
auto medianTimePast = pindexPrev->GetMedianTimePast();
auto nTime = std::max(medianTimePast + 1, GetAdjustedTime());
// See the comment in ContextualCheckBlockHeader() for background.
if (pindexPrev->nHeight >= 1) {
if (consensusParams.FutureTimestampSoftForkActive(pindexPrev->nHeight + 1)) {
nTime = std::min(nTime, medianTimePast + MAX_FUTURE_BLOCK_TIME_MTP);
}
pblock->nTime = nTime;