From 8863d77d658ed6d8b7be09528a0ae4afd0070088 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 19 May 2019 13:30:24 -0700 Subject: [PATCH 01/50] Redefine PoW functions to accept height parameter. Introduce target spacing constants and redefine struct member variable nPoWTargetSpacing as a member function. The height parameter is used to determine if Blossom has activated yet. --- src/consensus/params.h | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/consensus/params.h b/src/consensus/params.h index 9cd3a84617d..ad0b44e4c34 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -10,6 +10,14 @@ #include +// Forward declaration. Enum requires storage type. +namespace Consensus { + struct Params; + enum UpgradeIndex : uint32_t; +} +bool NetworkUpgradeActive(int nHeight, const Consensus::Params& params, Consensus::UpgradeIndex idx); + + namespace Consensus { /** @@ -20,7 +28,7 @@ namespace Consensus { * 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 { +enum UpgradeIndex : uint32_t { // Sprout must be first BASE_SPROUT, UPGRADE_TESTDUMMY, @@ -61,6 +69,11 @@ struct NetworkUpgrade { static constexpr int NO_ACTIVATION_HEIGHT = -1; }; +/** 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; +BOOST_STATIC_ASSERT(POST_BLOSSOM_POW_TARGET_SPACING < PRE_BLOSSOM_POW_TARGET_SPACING); + /** * Parameters that influence chain consensus. */ @@ -100,10 +113,26 @@ struct Params { int64_t nPowAveragingWindow; int64_t nPowMaxAdjustDown; int64_t nPowMaxAdjustUp; - int64_t nPowTargetSpacing; - int64_t AveragingWindowTimespan() const { return nPowAveragingWindow * nPowTargetSpacing; } - int64_t MinActualTimespan() const { return (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp )) / 100; } - int64_t MaxActualTimespan() const { return (AveragingWindowTimespan() * (100 + nPowMaxAdjustDown)) / 100; } + int64_t nPreBlossomPowTargetSpacing; + int64_t nPostBlossomPowTargetSpacing; + + int64_t PoWTargetSpacing(int nHeight) const { + bool blossomActive = NetworkUpgradeActive(nHeight, *this, Consensus::UPGRADE_BLOSSOM); + return blossomActive ? nPostBlossomPowTargetSpacing : nPreBlossomPowTargetSpacing; + } + + int64_t AveragingWindowTimespan(int nHeight) const { + return nPowAveragingWindow * PoWTargetSpacing(nHeight); + } + + int64_t MinActualTimespan(int nHeight) const { + return (AveragingWindowTimespan(nHeight) * (100 - nPowMaxAdjustUp )) / 100; + } + + int64_t MaxActualTimespan(int nHeight) const { + return (AveragingWindowTimespan(nHeight) * (100 + nPowMaxAdjustDown)) / 100; + } + uint256 nMinimumChainWork; }; } // namespace Consensus From ac4a606d4a74161155f0f38028bd338ff3787a74 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 19 May 2019 13:36:17 -0700 Subject: [PATCH 02/50] Remove use of redundant member nPowTargetSpacing. --- src/chainparams.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 0980d78121e..1f5760f2993 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -98,7 +98,8 @@ class CMainParams : public CChainParams { assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); consensus.nPowMaxAdjustDown = 32; // 32% adjustment down consensus.nPowMaxAdjustUp = 16; // 16% adjustment up - consensus.nPowTargetSpacing = 2.5 * 60; + consensus.nPreBlossomPowTargetSpacing = Consensus::PRE_BLOSSOM_POW_TARGET_SPACING; + consensus.nPostBlossomPowTargetSpacing = Consensus::POST_BLOSSOM_POW_TARGET_SPACING; consensus.nPowAllowMinDifficultyBlocksAfterHeight = boost::none; consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002; consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight = @@ -289,7 +290,8 @@ class CTestNetParams : public CChainParams { assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); consensus.nPowMaxAdjustDown = 32; // 32% adjustment down consensus.nPowMaxAdjustUp = 16; // 16% adjustment up - consensus.nPowTargetSpacing = 2.5 * 60; + consensus.nPreBlossomPowTargetSpacing = Consensus::PRE_BLOSSOM_POW_TARGET_SPACING; + consensus.nPostBlossomPowTargetSpacing = Consensus::POST_BLOSSOM_POW_TARGET_SPACING; consensus.nPowAllowMinDifficultyBlocksAfterHeight = 299187; consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002; consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight = @@ -421,7 +423,8 @@ class CRegTestParams : public CChainParams { assert(maxUint/UintToArith256(consensus.powLimit) >= consensus.nPowAveragingWindow); consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up - consensus.nPowTargetSpacing = 2.5 * 60; + consensus.nPreBlossomPowTargetSpacing = Consensus::PRE_BLOSSOM_POW_TARGET_SPACING; + consensus.nPostBlossomPowTargetSpacing = Consensus::POST_BLOSSOM_POW_TARGET_SPACING; consensus.nPowAllowMinDifficultyBlocksAfterHeight = 0; consensus.vUpgrades[Consensus::BASE_SPROUT].nProtocolVersion = 170002; consensus.vUpgrades[Consensus::BASE_SPROUT].nActivationHeight = From 35d1fdeba6311027c3e8767f427b07fd6aafdb9b Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 19 May 2019 13:39:42 -0700 Subject: [PATCH 03/50] Replace nPoWTargetSpacing -> PoWTargetSpacing() --- src/metrics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index 9eecc22e5d0..a47f4538c80 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -135,7 +135,7 @@ int EstimateNetHeight(int height, int64_t tipmediantime, CChainParams chainParam Checkpoints::GetTotalBlocksEstimate(checkpointData), checkpointData.nTimeLastCheckpoint, chainParams.GenesisBlock().nTime, - chainParams.GetConsensus().nPowTargetSpacing); + chainParams.GetConsensus().PoWTargetSpacing(height)); } void TriggerRefresh() From b30ff0d36744777b1dd1440798306147bde869df Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 19 May 2019 13:54:43 -0700 Subject: [PATCH 04/50] Update PoW function calls to pass in height. --- src/pow.cpp | 28 ++++++++++++++++------------ src/pow.h | 3 ++- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/pow.cpp b/src/pow.cpp index ec0410acca2..3f0116d63dc 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -31,9 +31,9 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead pindexLast->nHeight >= params.nPowAllowMinDifficultyBlocksAfterHeight.get()) { // Special difficulty rule for testnet: - // If the new block's timestamp is more than 6 * 2.5 minutes + // If the new block's timestamp is more than 6 * block interval minutes // then allow mining of a min-difficulty block. - if (pblock && pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing * 6) + if (pblock && pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.PoWTargetSpacing(pindexLast->nHeight + 1) * 6) return nProofOfWorkLimit; } } @@ -54,29 +54,33 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead arith_uint256 bnAvg {bnTot / params.nPowAveragingWindow}; - return CalculateNextWorkRequired(bnAvg, pindexLast->GetMedianTimePast(), pindexFirst->GetMedianTimePast(), params); + return CalculateNextWorkRequired(bnAvg, + pindexLast->GetMedianTimePast(), pindexFirst->GetMedianTimePast(), + params, + pindexLast->nHeight + 1 ); } unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, int64_t nLastBlockTime, int64_t nFirstBlockTime, - const Consensus::Params& params) + const Consensus::Params& params, + int nextHeight) { // Limit adjustment step // Use medians to prevent time-warp attacks int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime; LogPrint("pow", " nActualTimespan = %d before dampening\n", nActualTimespan); - nActualTimespan = params.AveragingWindowTimespan() + (nActualTimespan - params.AveragingWindowTimespan())/4; + nActualTimespan = params.AveragingWindowTimespan(nextHeight) + (nActualTimespan - params.AveragingWindowTimespan(nextHeight))/4; LogPrint("pow", " nActualTimespan = %d before bounds\n", nActualTimespan); - if (nActualTimespan < params.MinActualTimespan()) - nActualTimespan = params.MinActualTimespan(); - if (nActualTimespan > params.MaxActualTimespan()) - nActualTimespan = params.MaxActualTimespan(); + if (nActualTimespan < params.MinActualTimespan(nextHeight)) + nActualTimespan = params.MinActualTimespan(nextHeight); + if (nActualTimespan > params.MaxActualTimespan(nextHeight)) + nActualTimespan = params.MaxActualTimespan(nextHeight); // Retarget const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); arith_uint256 bnNew {bnAvg}; - bnNew /= params.AveragingWindowTimespan(); + bnNew /= params.AveragingWindowTimespan(nextHeight); bnNew *= nActualTimespan; if (bnNew > bnPowLimit) @@ -84,7 +88,7 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, /// debug print LogPrint("pow", "GetNextWorkRequired RETARGET\n"); - LogPrint("pow", "params.AveragingWindowTimespan() = %d nActualTimespan = %d\n", params.AveragingWindowTimespan(), nActualTimespan); + LogPrint("pow", "params.AveragingWindowTimespan() = %d nActualTimespan = %d\n", params.AveragingWindowTimespan(nextHeight), nActualTimespan); LogPrint("pow", "Current average: %08x %s\n", bnAvg.GetCompact(), bnAvg.ToString()); LogPrint("pow", "After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); @@ -162,7 +166,7 @@ int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& fr r = from.nChainWork - to.nChainWork; sign = -1; } - r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip); + r = r * arith_uint256(params.PoWTargetSpacing(tip.nHeight)) / GetBlockProof(tip); if (r.bits() > 63) { return sign * std::numeric_limits::max(); } diff --git a/src/pow.h b/src/pow.h index e3cf822d8dd..67c41bc7f39 100644 --- a/src/pow.h +++ b/src/pow.h @@ -19,7 +19,8 @@ class arith_uint256; unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&); unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, int64_t nLastBlockTime, int64_t nFirstBlockTime, - const Consensus::Params&); + const Consensus::Params&, + int nextHeight = 0); /** Check whether the Equihash solution in a block header is valid */ bool CheckEquihashSolution(const CBlockHeader *pblock, const Consensus::Params&); From 4b985ce99901b2c0808cc2d76f9b51fa750c8f78 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 19 May 2019 14:30:56 -0700 Subject: [PATCH 05/50] Update GetBlockTimeout() to take height parameter. --- src/main.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 9549610d919..12aae555695 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -311,9 +311,9 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state) } // Returns time at which to timeout block request (nTime in microseconds) -int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consensus::Params &consensusParams) +int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consensus::Params &consensusParams, int nHeight) { - return nTime + 500000 * consensusParams.nPowTargetSpacing * (4 + nValidatedQueuedBefore); + return nTime + 500000 * consensusParams.PoWTargetSpacing(nHeight) * (4 + nValidatedQueuedBefore); } void InitializeNode(NodeId nodeid, const CNode *pnode) { @@ -368,7 +368,8 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Pa MarkBlockAsReceived(hash); int64_t nNow = GetTimeMicros(); - QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL, GetBlockTimeout(nNow, nQueuedValidatedHeaders, consensusParams)}; + int nHeight = pindex != NULL ? pindex->nHeight : chainActive.Height(); // Help block timeout computation + QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL, GetBlockTimeout(nNow, nQueuedValidatedHeaders, consensusParams, nHeight)}; nQueuedValidatedHeaders += newentry.fValidatedHeaders; list::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry); state->nBlocksInFlight++; @@ -6526,7 +6527,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // more quickly than once every 5 minutes, then we'll shorten the download window for this block). if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) { QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); - int64_t nTimeoutIfRequestedNow = GetBlockTimeout(nNow, nQueuedValidatedHeaders - state.nBlocksInFlightValidHeaders, consensusParams); + int64_t nTimeoutIfRequestedNow = GetBlockTimeout(nNow, nQueuedValidatedHeaders - state.nBlocksInFlightValidHeaders, consensusParams, pindexBestHeader->nHeight); if (queuedBlock.nTimeDisconnect > nTimeoutIfRequestedNow) { LogPrint("net", "Reducing block download timeout for peer=%d block=%s, orig=%d new=%d\n", pto->id, queuedBlock.hash.ToString(), queuedBlock.nTimeDisconnect, nTimeoutIfRequestedNow); queuedBlock.nTimeDisconnect = nTimeoutIfRequestedNow; From 22e8dc26797004bc13a7132776ac2fa392a75f0e Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 19 May 2019 14:33:03 -0700 Subject: [PATCH 06/50] Replace nPoWTargetSpacing -> PoWTargetSpacing() in ProcessMessage() --- src/main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 12aae555695..f2d65c30fe6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5590,7 +5590,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // not a direct successor. pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexBestHeader), inv.hash); CNodeState *nodestate = State(pfrom->GetId()); - if (chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - chainparams.GetConsensus().nPowTargetSpacing * 20 && + + if (chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - chainparams.GetConsensus().PoWTargetSpacing(pindexBestHeader->nHeight) * 20 && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { vToFetch.push_back(inv); // Mark block as in flight already, even though the actual "getdata" message only goes out @@ -5661,7 +5662,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } // If pruning, don't inv blocks unless we have on disk and are likely to still have // for some reasonable time window (1 hour) that block relay might require. - const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / chainparams.GetConsensus().nPowTargetSpacing; + const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / chainparams.GetConsensus().PoWTargetSpacing(pindex->nHeight); if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= chainActive.Tip()->nHeight - nPrunedBlocksLikelyToHave)) { LogPrint("net", " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); From 3a8fd5ea33823f4af12e02d9ecd5a079769a9359 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 19 May 2019 14:38:13 -0700 Subject: [PATCH 07/50] Replace nPoWTargetSpacing -> PoWTargetSpacing() in tests --- src/gtest/test_pow.cpp | 18 +++++++++--------- src/test/alert_tests.cpp | 2 +- src/test/miner_tests.cpp | 2 +- src/test/pow_tests.cpp | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/gtest/test_pow.cpp b/src/gtest/test_pow.cpp index 4557f6db11d..b0dd5fa41e7 100644 --- a/src/gtest/test_pow.cpp +++ b/src/gtest/test_pow.cpp @@ -16,7 +16,7 @@ TEST(PoW, DifficultyAveraging) { for (int i = 0; i <= lastBlk; i++) { blocks[i].pprev = i ? &blocks[i - 1] : nullptr; blocks[i].nHeight = i; - blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing; + blocks[i].nTime = 1269211443 + i * params.PoWTargetSpacing(blocks[i].nHeight); blocks[i].nBits = 0x1e7fffff; /* target 0x007fffff000... */ blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0); } @@ -32,12 +32,12 @@ TEST(PoW, DifficultyAveraging) { // Result should be unchanged, modulo integer division precision loss arith_uint256 bnRes; bnRes.SetCompact(0x1e7fffff); - bnRes /= params.AveragingWindowTimespan(); - bnRes *= params.AveragingWindowTimespan(); + bnRes /= params.AveragingWindowTimespan(blocks[lastBlk].nHeight); + bnRes *= params.AveragingWindowTimespan(blocks[lastBlk].nHeight); EXPECT_EQ(bnRes.GetCompact(), GetNextWorkRequired(&blocks[lastBlk], nullptr, params)); // Randomise the final block time (plus 1 to ensure it is always different) - blocks[lastBlk].nTime += GetRand(params.nPowTargetSpacing/2) + 1; + blocks[lastBlk].nTime += GetRand(params.PoWTargetSpacing(blocks[lastBlk].nHeight)/2) + 1; // Result should be the same as if last difficulty was used bnAvg.SetCompact(blocks[lastBlk].nBits); @@ -80,24 +80,24 @@ TEST(PoW, MinDifficultyRules) { for (int i = 0; i <= lastBlk; i++) { blocks[i].pprev = i ? &blocks[i - 1] : nullptr; blocks[i].nHeight = params.nPowAllowMinDifficultyBlocksAfterHeight.get() + i; - blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing; + blocks[i].nTime = 1269211443 + i * params.PoWTargetSpacing(blocks[i].nHeight); blocks[i].nBits = 0x1e7fffff; /* target 0x007fffff000... */ blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0); } // Create a new block at the target spacing CBlockHeader next; - next.nTime = blocks[lastBlk].nTime + params.nPowTargetSpacing; + next.nTime = blocks[lastBlk].nTime + params.PoWTargetSpacing(blocks[lastBlk].nHeight + 1); // Result should be unchanged, modulo integer division precision loss arith_uint256 bnRes; bnRes.SetCompact(0x1e7fffff); - bnRes /= params.AveragingWindowTimespan(); - bnRes *= params.AveragingWindowTimespan(); + bnRes /= params.AveragingWindowTimespan(blocks[lastBlk].nHeight); + bnRes *= params.AveragingWindowTimespan(blocks[lastBlk].nHeight); EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params), bnRes.GetCompact()); // Delay last block up to the edge of the min-difficulty limit - next.nTime += params.nPowTargetSpacing * 5; + next.nTime += params.PoWTargetSpacing(blocks[lastBlk].nHeight + 1) * 5; // Result should be unchanged, modulo integer division precision loss EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params), bnRes.GetCompact()); diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index 18acf1f67c5..f50f7c49725 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -391,7 +391,7 @@ BOOST_AUTO_TEST_CASE(PartitionAlert) CCriticalSection csDummy; CBlockIndex indexDummy[400]; CChainParams& params = Params(CBaseChainParams::MAIN); - int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing; + int64_t nPowTargetSpacing = params.GetConsensus().PoWTargetSpacing(0); // First 400 blocks are pre-Blossom // Generate fake blockchain timestamps relative to // an arbitrary time: diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 23e7634abbd..11bcaa0603e 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -168,7 +168,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // of the next block must be six spacings ahead of that to be at least // one spacing ahead of the tip. Within 11 blocks of genesis, the median // will be closer to the tip, and blocks will appear slower. - pblock->nTime = chainActive.Tip()->GetMedianTimePast()+6*Params().GetConsensus().nPowTargetSpacing; + pblock->nTime = chainActive.Tip()->GetMedianTimePast()+6*Params().GetConsensus().PoWTargetSpacing(i); CMutableTransaction txCoinbase(pblock->vtx[0]); txCoinbase.nVersion = 1; txCoinbase.vin[0].scriptSig = CScript() << (chainActive.Height()+1) << OP_0; diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index 5a11483f274..a83f5914b70 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) for (int i = 0; i < 10000; i++) { blocks[i].pprev = i ? &blocks[i - 1] : NULL; blocks[i].nHeight = i; - blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing; + blocks[i].nTime = 1269211443 + i * params.PoWTargetSpacing(blocks[i].nHeight); blocks[i].nBits = 0x207fffff; /* target 0x7fffff000... */ blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0); } From d7ebbeb2aa0ff79e57d86dfe5dbf709f62d2bd0b Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 19 May 2019 15:58:11 -0700 Subject: [PATCH 08/50] Modify PartitionCheck to be aware of pre & post Blossom target spacing. --- src/init.cpp | 7 +++---- src/main.cpp | 27 ++++++++++++++++++++++++++- src/main.h | 2 +- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 2743f473104..6d6fd1f4a5d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1861,11 +1861,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) StartNode(threadGroup, scheduler); - // Monitor the chain, and alert if we get blocks much quicker or slower than expected - int64_t nPowTargetSpacing = Params().GetConsensus().nPowTargetSpacing; + // Monitor the chain every minute, and alert if we get blocks much quicker or slower than expected. CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload, - boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing); - scheduler.scheduleEvery(f, nPowTargetSpacing); + boost::ref(cs_main), boost::cref(pindexBestHeader), 0); + scheduler.scheduleEvery(f, 60); #ifdef ENABLE_MINING // Generate coins in the background diff --git a/src/main.cpp b/src/main.cpp index f2d65c30fe6..fa28964e300 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2436,6 +2436,9 @@ void ThreadScriptCheck() { // we're being fed a bad chain (blocks being generated much // too slowly or too quickly). // +// When parameter nPowTargetSpacing is not set, the default value of 0 +// means use the block height of the best header to determine target spacing. +// Setting the parameter value is useful for testing. void PartitionCheck(bool (*initialDownloadCheck)(const CChainParams&), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing) @@ -2448,14 +2451,36 @@ void PartitionCheck(bool (*initialDownloadCheck)(const CChainParams&), const int SPAN_HOURS=4; const int SPAN_SECONDS=SPAN_HOURS*60*60; + + LOCK(cs); + + int bestHeaderHeight = bestHeader->nHeight; + int blossomHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + if (nPowTargetSpacing == 0) { + nPowTargetSpacing = Params().GetConsensus().PoWTargetSpacing(bestHeaderHeight); + blossomHeight = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; + } + int BLOCKS_EXPECTED = SPAN_SECONDS / nPowTargetSpacing; + // If the span period includes Blossom activation, adjust the number of expected blocks. + if (blossomHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT && + bestHeaderHeight > blossomHeight) + { + int t = SPAN_SECONDS; + int nBlossomBlocks = bestHeaderHeight - blossomHeight; + t -= nBlossomBlocks * Consensus::POST_BLOSSOM_POW_TARGET_SPACING; + if (t > 0) { + int nPreBlossomBlocks = t / Consensus::PRE_BLOSSOM_POW_TARGET_SPACING; + BLOCKS_EXPECTED = nPreBlossomBlocks + nBlossomBlocks; + } + } + boost::math::poisson_distribution poisson(BLOCKS_EXPECTED); std::string strWarning; int64_t startTime = GetAdjustedTime()-SPAN_SECONDS; - LOCK(cs); const CBlockIndex* i = bestHeader; int nBlocks = 0; while (i->GetBlockTime() >= startTime) { diff --git a/src/main.h b/src/main.h index cd2e39a0957..deda1276c7b 100644 --- a/src/main.h +++ b/src/main.h @@ -234,7 +234,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle); /** Run an instance of the script checking thread */ void ThreadScriptCheck(); /** Try to detect Partition (network isolation) attacks against us */ -void PartitionCheck(bool (*initialDownloadCheck)(const CChainParams&), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing); +void PartitionCheck(bool (*initialDownloadCheck)(const CChainParams&), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing = 0); /** Check whether we are doing an initial block download (synchronizing from disk or network) */ bool IsInitialBlockDownload(const CChainParams& chainParams); /** Format a string that describes several potential problems detected by the core */ From 742127271268d666c58e7d1b2abc557494d3996d Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Thu, 18 Jul 2019 14:57:13 -0600 Subject: [PATCH 09/50] Make nextHeight required in CalculateNextWorkRequired --- src/gtest/test_pow.cpp | 12 ++++++++---- src/pow.cpp | 2 +- src/pow.h | 2 +- src/test/pow_tests.cpp | 8 ++++---- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/gtest/test_pow.cpp b/src/gtest/test_pow.cpp index b0dd5fa41e7..b79d91b898f 100644 --- a/src/gtest/test_pow.cpp +++ b/src/gtest/test_pow.cpp @@ -27,7 +27,8 @@ TEST(PoW, DifficultyAveraging) { EXPECT_EQ(CalculateNextWorkRequired(bnAvg, blocks[lastBlk].GetMedianTimePast(), blocks[firstBlk].GetMedianTimePast(), - params), + params, + blocks[lastBlk].nHeight + 1), GetNextWorkRequired(&blocks[lastBlk], nullptr, params)); // Result should be unchanged, modulo integer division precision loss arith_uint256 bnRes; @@ -44,7 +45,8 @@ TEST(PoW, DifficultyAveraging) { EXPECT_EQ(CalculateNextWorkRequired(bnAvg, blocks[lastBlk].GetMedianTimePast(), blocks[firstBlk].GetMedianTimePast(), - params), + params, + blocks[lastBlk].nHeight + 1), GetNextWorkRequired(&blocks[lastBlk], nullptr, params)); // Result should not be unchanged EXPECT_NE(0x1e7fffff, GetNextWorkRequired(&blocks[lastBlk], nullptr, params)); @@ -57,7 +59,8 @@ TEST(PoW, DifficultyAveraging) { EXPECT_NE(CalculateNextWorkRequired(bnAvg, blocks[lastBlk].GetMedianTimePast(), blocks[firstBlk].GetMedianTimePast(), - params), + params, + blocks[lastBlk].nHeight + 1), GetNextWorkRequired(&blocks[lastBlk], nullptr, params)); // Result should be the same as if the average difficulty was used @@ -65,7 +68,8 @@ TEST(PoW, DifficultyAveraging) { EXPECT_EQ(CalculateNextWorkRequired(average, blocks[lastBlk].GetMedianTimePast(), blocks[firstBlk].GetMedianTimePast(), - params), + params, + blocks[lastBlk].nHeight + 1), GetNextWorkRequired(&blocks[lastBlk], nullptr, params)); } diff --git a/src/pow.cpp b/src/pow.cpp index 3f0116d63dc..d4139c48393 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -57,7 +57,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead return CalculateNextWorkRequired(bnAvg, pindexLast->GetMedianTimePast(), pindexFirst->GetMedianTimePast(), params, - pindexLast->nHeight + 1 ); + pindexLast->nHeight + 1); } unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, diff --git a/src/pow.h b/src/pow.h index 67c41bc7f39..26cde2e022c 100644 --- a/src/pow.h +++ b/src/pow.h @@ -20,7 +20,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, int64_t nLastBlockTime, int64_t nFirstBlockTime, const Consensus::Params&, - int nextHeight = 0); + int nextHeight); /** Check whether the Equihash solution in a block header is valid */ bool CheckEquihashSolution(const CBlockHeader *pblock, const Consensus::Params&); diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index a83f5914b70..21c043c9a26 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -24,7 +24,7 @@ BOOST_AUTO_TEST_CASE(get_next_work) arith_uint256 bnAvg; bnAvg.SetCompact(0x1d00ffff); BOOST_CHECK_EQUAL(0x1d011998, - CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params)); + CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); } /* Test the constraint on the upper bound for next work */ @@ -38,7 +38,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_pow_limit) arith_uint256 bnAvg; bnAvg.SetCompact(0x1f07ffff); BOOST_CHECK_EQUAL(0x1f07ffff, - CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params)); + CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); } /* Test the constraint on the lower bound for actual time taken */ @@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual) arith_uint256 bnAvg; bnAvg.SetCompact(0x1c05a3f4); BOOST_CHECK_EQUAL(0x1c04bceb, - CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params)); + CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); } /* Test the constraint on the upper bound for actual time taken */ @@ -66,7 +66,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual) arith_uint256 bnAvg; bnAvg.SetCompact(0x1c387f6f); BOOST_CHECK_EQUAL(0x1c4a93bb, - CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params)); + CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); } BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) From a63ec6e71736cb30cec4433e22a167dba0653f43 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Wed, 24 Jul 2019 15:37:33 -0600 Subject: [PATCH 10/50] Shorter block times rpc test --- qa/pull-tester/rpc-tests.sh | 1 + qa/rpc-tests/shorter_block_times.py | 50 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100755 qa/rpc-tests/shorter_block_times.py diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index aeda0da2cbf..3b6d411aead 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -73,6 +73,7 @@ testScripts=( 'p2p_node_bloom.py' 'regtest_signrawtransaction.py' 'finalsaplingroot.py' + 'shorter_block_times.py' 'sprout_sapling_migration.py' 'turnstile.py' ); diff --git a/qa/rpc-tests/shorter_block_times.py b/qa/rpc-tests/shorter_block_times.py new file mode 100755 index 00000000000..26599d30c1a --- /dev/null +++ b/qa/rpc-tests/shorter_block_times.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# Copyright (c) 2019 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import sys; assert sys.version_info < (3,), ur"This script does not run under Python 3. Please use Python 2.7.x." + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, + initialize_chain_clean, + start_nodes, +) + + +class ShorterBlockTimes(BitcoinTestFramework): + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir, [[ + '-nuparams=5ba81b19:0', # Overwinter + '-nuparams=76b809bb:0', # Sapling + '-nuparams=2bb40e60:101', # Blossom + ]] * 4) + + def setup_chain(self): + print("Initializing test directory " + self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + def run_test(self): + print "Mining blocks..." + self.nodes[0].generate(100) + self.sync_all() + + # Sanity-check the block height + assert_equal(self.nodes[0].getblockcount(), 100) + + print "Mining last pre-Blossom block" + # Activate blossom + self.nodes[1].generate(1) + self.sync_all() + assert_equal(10, self.nodes[1].getwalletinfo()['immature_balance']) + + # After blossom activation the block reward will be halved + print "Mining first Blossom block" + self.nodes[1].generate(1) + self.sync_all() + assert_equal(15, self.nodes[1].getwalletinfo()['immature_balance']) + + +if __name__ == '__main__': + ShorterBlockTimes().main() From c192e3a75d1db33b2664cdaded85d4a14f4ce177 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 26 Jul 2019 10:34:23 -0600 Subject: [PATCH 11/50] Update pow_tests for shorter block times --- src/chainparams.cpp | 12 +++++ src/chainparams.h | 2 + src/consensus/params.h | 2 +- src/pow.cpp | 22 ++++++--- src/test/pow_tests.cpp | 109 ++++++++++++++++++++++++++++++++++++----- 5 files changed, 127 insertions(+), 20 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 1f5760f2993..476385539e7 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -504,6 +504,14 @@ class CRegTestParams : public CChainParams { consensus.vUpgrades[idx].nActivationHeight = nActivationHeight; } + void UpdateRegtestPow(int64_t nPowMaxAdjustDown, int64_t nPowMaxAdjustUp, uint256 powLimit) + { + assert(strNetworkID == "regtest"); + consensus.nPowMaxAdjustDown = nPowMaxAdjustDown; + consensus.nPowMaxAdjustUp = nPowMaxAdjustUp; + consensus.powLimit = powLimit; + } + void SetRegTestZIP209Enabled() { fZIP209Enabled = true; } @@ -590,3 +598,7 @@ void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivation { regTestParams.UpdateNetworkUpgradeParameters(idx, nActivationHeight); } + +void UpdateRegtestPow(int64_t nPowMaxAdjustDown, int64_t nPowMaxAdjustUp, uint256 powLimit) { + regTestParams.UpdateRegtestPow(nPowMaxAdjustDown, nPowMaxAdjustUp, powLimit); +} diff --git a/src/chainparams.h b/src/chainparams.h index 17ebe9d31a6..34396b6d9d6 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -156,4 +156,6 @@ bool SelectParamsFromCommandLine(); */ void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivationHeight); +void UpdateRegtestPow(int64_t nPowMaxAdjustDown, int64_t nPowMaxAdjustUp, uint256 powLimit); + #endif // BITCOIN_CHAINPARAMS_H diff --git a/src/consensus/params.h b/src/consensus/params.h index ad0b44e4c34..ea517536fe8 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -126,7 +126,7 @@ struct Params { } int64_t MinActualTimespan(int nHeight) const { - return (AveragingWindowTimespan(nHeight) * (100 - nPowMaxAdjustUp )) / 100; + return (AveragingWindowTimespan(nHeight) * (100 - nPowMaxAdjustUp)) / 100; } int64_t MaxActualTimespan(int nHeight) const { diff --git a/src/pow.cpp b/src/pow.cpp index d4139c48393..899b4620818 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -65,30 +65,36 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, const Consensus::Params& params, int nextHeight) { + int64_t averagingWindowTimespan = params.AveragingWindowTimespan(nextHeight); + int64_t minActualTimespan = params.MinActualTimespan(nextHeight); + int64_t maxActualTimespan = params.MaxActualTimespan(nextHeight); // Limit adjustment step // Use medians to prevent time-warp attacks int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime; LogPrint("pow", " nActualTimespan = %d before dampening\n", nActualTimespan); - nActualTimespan = params.AveragingWindowTimespan(nextHeight) + (nActualTimespan - params.AveragingWindowTimespan(nextHeight))/4; + nActualTimespan = averagingWindowTimespan + (nActualTimespan - averagingWindowTimespan)/4; LogPrint("pow", " nActualTimespan = %d before bounds\n", nActualTimespan); - if (nActualTimespan < params.MinActualTimespan(nextHeight)) - nActualTimespan = params.MinActualTimespan(nextHeight); - if (nActualTimespan > params.MaxActualTimespan(nextHeight)) - nActualTimespan = params.MaxActualTimespan(nextHeight); + if (nActualTimespan < minActualTimespan) { + nActualTimespan = minActualTimespan; + } + if (nActualTimespan > maxActualTimespan) { + nActualTimespan = maxActualTimespan; + } // Retarget const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); arith_uint256 bnNew {bnAvg}; - bnNew /= params.AveragingWindowTimespan(nextHeight); + bnNew /= averagingWindowTimespan; bnNew *= nActualTimespan; - if (bnNew > bnPowLimit) + if (bnNew > bnPowLimit) { bnNew = bnPowLimit; + } /// debug print LogPrint("pow", "GetNextWorkRequired RETARGET\n"); - LogPrint("pow", "params.AveragingWindowTimespan() = %d nActualTimespan = %d\n", params.AveragingWindowTimespan(nextHeight), nActualTimespan); + LogPrint("pow", "params.AveragingWindowTimespan(%d) = %d nActualTimespan = %d\n", nextHeight, averagingWindowTimespan, nActualTimespan); LogPrint("pow", "Current average: %08x %s\n", bnAvg.GetCompact(), bnAvg.ToString()); LogPrint("pow", "After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index 21c043c9a26..1534cf8e8a8 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -11,6 +11,23 @@ using namespace std; +const Consensus::Params& ActivateBlossom() { + SelectParams(CBaseChainParams::REGTEST); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_BLOSSOM, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + UpdateRegtestPow(32, 16, uint256S("0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); + return Params().GetConsensus(); +} + +void DeactivateBlossom() { + UpdateRegtestPow(0, 0, uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f")); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_BLOSSOM, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + SelectParams(CBaseChainParams::MAIN); +} + BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup) /* Test calculation of next difficulty target with no constraints applying */ @@ -18,62 +35,120 @@ BOOST_AUTO_TEST_CASE(get_next_work) { SelectParams(CBaseChainParams::MAIN); const Consensus::Params& params = Params().GetConsensus(); + BOOST_CHECK_EQUAL(150, params.PoWTargetSpacing(0)); - int64_t nLastRetargetTime = 1262149169; // NOTE: Not an actual block time - int64_t nThisTime = 1262152739; // Block #32255 of Bitcoin + int64_t nLastRetargetTime = 1000000000; // NOTE: Not an actual block time + int64_t nThisTime = 1000003570; arith_uint256 bnAvg; bnAvg.SetCompact(0x1d00ffff); BOOST_CHECK_EQUAL(0x1d011998, CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); } + +BOOST_AUTO_TEST_CASE(get_next_work_blossom) +{ + const Consensus::Params& params = ActivateBlossom(); + BOOST_CHECK_EQUAL(75, params.PoWTargetSpacing(0)); + + int64_t nLastRetargetTime = 1000000000; // NOTE: Not an actual block time + int64_t nThisTime = 1000001445; + arith_uint256 bnAvg; + bnAvg.SetCompact(0x1d00ffff); + BOOST_CHECK_GT(0x1d011998, + CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); + + DeactivateBlossom(); +} + /* Test the constraint on the upper bound for next work */ BOOST_AUTO_TEST_CASE(get_next_work_pow_limit) { SelectParams(CBaseChainParams::MAIN); const Consensus::Params& params = Params().GetConsensus(); - int64_t nLastRetargetTime = 1231006505; // Block #0 of Bitcoin - int64_t nThisTime = 1233061996; // Block #2015 of Bitcoin + int64_t nLastRetargetTime = 1231006505; + int64_t nThisTime = 1233061996; arith_uint256 bnAvg; bnAvg.SetCompact(0x1f07ffff); BOOST_CHECK_EQUAL(0x1f07ffff, CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); } +BOOST_AUTO_TEST_CASE(get_next_work_pow_limit_blossom) +{ + const Consensus::Params& params = ActivateBlossom(); + + int64_t nLastRetargetTime = 1231006505; + int64_t nThisTime = 1233061996; + arith_uint256 bnAvg; + bnAvg.SetCompact(0x1f07ffff); + BOOST_CHECK_EQUAL(0x1f07ffff, + CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); + + DeactivateBlossom(); +} + /* Test the constraint on the lower bound for actual time taken */ BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual) { SelectParams(CBaseChainParams::MAIN); const Consensus::Params& params = Params().GetConsensus(); - int64_t nLastRetargetTime = 1279296753; // NOTE: Not an actual block time - int64_t nThisTime = 1279297671; // Block #68543 of Bitcoin + int64_t nLastRetargetTime = 1000000000; // NOTE: Not an actual block time + // 17*150*(1 - PoWMaxAdjustUp*PoWDampingFactor) = 918 + // so we pick 917 to be outside of this window + int64_t nThisTime = 100000917; arith_uint256 bnAvg; bnAvg.SetCompact(0x1c05a3f4); BOOST_CHECK_EQUAL(0x1c04bceb, CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); } +BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual_blossom) +{ + const Consensus::Params& params = ActivateBlossom(); + + int64_t nLastRetargetTime = 1000000000; // NOTE: Not an actual block time + int64_t nThisTime = 1000000458; + arith_uint256 bnAvg; + bnAvg.SetCompact(0x1c05a3f4); + BOOST_CHECK_EQUAL(0x1c04bceb, + CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); + + DeactivateBlossom(); +} + /* Test the constraint on the upper bound for actual time taken */ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual) { SelectParams(CBaseChainParams::MAIN); const Consensus::Params& params = Params().GetConsensus(); - int64_t nLastRetargetTime = 1269205629; // NOTE: Not an actual block time - int64_t nThisTime = 1269211443; // Block #46367 of Bitcoin + int64_t nLastRetargetTime = 1000000000; // NOTE: Not an actual block time + // 17*150*(1 + maxAdjustDown*PoWDampingFactor) = 5814 + int64_t nThisTime = 1000005815; arith_uint256 bnAvg; bnAvg.SetCompact(0x1c387f6f); BOOST_CHECK_EQUAL(0x1c4a93bb, CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); } -BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) +BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual_blossom) { - SelectParams(CBaseChainParams::MAIN); - const Consensus::Params& params = Params().GetConsensus(); + const Consensus::Params& params = ActivateBlossom(); + + int64_t nLastRetargetTime = 1000000000; // NOTE: Not an actual block time + int64_t nThisTime = 1000002908; + arith_uint256 bnAvg; + bnAvg.SetCompact(0x1c387f6f); + BOOST_CHECK_EQUAL(0x1c4a93bb, + CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); + + DeactivateBlossom(); +} +void GetBlockProofEquivalentTimeImpl(const Consensus::Params& params) { std::vector blocks(10000); for (int i = 0; i < 10000; i++) { blocks[i].pprev = i ? &blocks[i - 1] : NULL; @@ -93,4 +168,16 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) } } +BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) +{ + SelectParams(CBaseChainParams::MAIN); + GetBlockProofEquivalentTimeImpl(Params().GetConsensus()); +} + +BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test_blossom) +{ + GetBlockProofEquivalentTimeImpl(ActivateBlossom()); + DeactivateBlossom(); +} + BOOST_AUTO_TEST_SUITE_END() From ff0820df5ee8dc80016fa56c6574c646a0b9c037 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 26 Jul 2019 10:48:16 -0600 Subject: [PATCH 12/50] Update test_pow for shorter block times --- src/gtest/test_pow.cpp | 16 +++++++++++++--- src/test/pow_tests.cpp | 28 ++++++---------------------- src/utiltest.cpp | 20 ++++++++++++++++++++ src/utiltest.h | 4 ++++ 4 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/gtest/test_pow.cpp b/src/gtest/test_pow.cpp index b79d91b898f..4a09ac69dd9 100644 --- a/src/gtest/test_pow.cpp +++ b/src/gtest/test_pow.cpp @@ -4,10 +4,10 @@ #include "chainparams.h" #include "pow.h" #include "random.h" +#include "utiltest.h" -TEST(PoW, DifficultyAveraging) { - SelectParams(CBaseChainParams::MAIN); - const Consensus::Params& params = Params().GetConsensus(); +void TestDifficultyAveragigingImpl(const Consensus::Params& params) +{ size_t lastBlk = 2*params.nPowAveragingWindow; size_t firstBlk = lastBlk - params.nPowAveragingWindow; @@ -73,6 +73,16 @@ TEST(PoW, DifficultyAveraging) { GetNextWorkRequired(&blocks[lastBlk], nullptr, params)); } +TEST(PoW, DifficultyAveraging) { + SelectParams(CBaseChainParams::MAIN); + TestDifficultyAveragigingImpl(Params().GetConsensus()); +} + +TEST(PoW, DifficultyAveragingBlossom) { + TestDifficultyAveragigingImpl(ActivateBlossom(true)); + DeactivateBlossom(); +} + TEST(PoW, MinDifficultyRules) { SelectParams(CBaseChainParams::TESTNET); const Consensus::Params& params = Params().GetConsensus(); diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index 1534cf8e8a8..626aaf5955f 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -5,29 +5,13 @@ #include "main.h" #include "pow.h" #include "util.h" +#include "utiltest.h" #include "test/test_bitcoin.h" #include using namespace std; -const Consensus::Params& ActivateBlossom() { - SelectParams(CBaseChainParams::REGTEST); - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_BLOSSOM, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); - UpdateRegtestPow(32, 16, uint256S("0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); - return Params().GetConsensus(); -} - -void DeactivateBlossom() { - UpdateRegtestPow(0, 0, uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f")); - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_BLOSSOM, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); - SelectParams(CBaseChainParams::MAIN); -} - BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup) /* Test calculation of next difficulty target with no constraints applying */ @@ -48,7 +32,7 @@ BOOST_AUTO_TEST_CASE(get_next_work) BOOST_AUTO_TEST_CASE(get_next_work_blossom) { - const Consensus::Params& params = ActivateBlossom(); + const Consensus::Params& params = ActivateBlossom(true); BOOST_CHECK_EQUAL(75, params.PoWTargetSpacing(0)); int64_t nLastRetargetTime = 1000000000; // NOTE: Not an actual block time @@ -77,7 +61,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_pow_limit) BOOST_AUTO_TEST_CASE(get_next_work_pow_limit_blossom) { - const Consensus::Params& params = ActivateBlossom(); + const Consensus::Params& params = ActivateBlossom(true); int64_t nLastRetargetTime = 1231006505; int64_t nThisTime = 1233061996; @@ -107,7 +91,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual) BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual_blossom) { - const Consensus::Params& params = ActivateBlossom(); + const Consensus::Params& params = ActivateBlossom(true); int64_t nLastRetargetTime = 1000000000; // NOTE: Not an actual block time int64_t nThisTime = 1000000458; @@ -136,7 +120,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual) BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual_blossom) { - const Consensus::Params& params = ActivateBlossom(); + const Consensus::Params& params = ActivateBlossom(true); int64_t nLastRetargetTime = 1000000000; // NOTE: Not an actual block time int64_t nThisTime = 1000002908; @@ -176,7 +160,7 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test_blossom) { - GetBlockProofEquivalentTimeImpl(ActivateBlossom()); + GetBlockProofEquivalentTimeImpl(ActivateBlossom(true)); DeactivateBlossom(); } diff --git a/src/utiltest.cpp b/src/utiltest.cpp index 997137b1a78..7c503f388a6 100644 --- a/src/utiltest.cpp +++ b/src/utiltest.cpp @@ -200,6 +200,26 @@ void RegtestDeactivateSapling() { UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); } +const Consensus::Params& ActivateBlossom(bool updatePow) { + SelectParams(CBaseChainParams::REGTEST); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_BLOSSOM, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + if (updatePow) { + UpdateRegtestPow(32, 16, uint256S("0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); + } + return Params().GetConsensus(); +} + +void DeactivateBlossom() { + UpdateRegtestPow(0, 0, uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f")); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_BLOSSOM, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); + SelectParams(CBaseChainParams::MAIN); +} + + libzcash::SaplingExtendedSpendingKey GetTestMasterSaplingSpendingKey() { std::vector> rawSeed(32); HDSeed seed(rawSeed); diff --git a/src/utiltest.h b/src/utiltest.h index 5480c559eb8..9fd3b661361 100644 --- a/src/utiltest.h +++ b/src/utiltest.h @@ -43,6 +43,10 @@ const Consensus::Params& RegtestActivateSapling(); void RegtestDeactivateSapling(); +const Consensus::Params& ActivateBlossom(bool updatePow); + +void DeactivateBlossom(); + libzcash::SaplingExtendedSpendingKey GetTestMasterSaplingSpendingKey(); CKey AddTestCKeyToKeyStore(CBasicKeyStore& keyStore); From 102dafdf89aa6b6ad07ef30695e466c70d7098c1 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 29 Jul 2019 13:44:53 -0600 Subject: [PATCH 13/50] Update block subsidy halving for zip208 --- qa/rpc-tests/shorter_block_times.py | 4 ++-- src/chainparams.cpp | 28 +++++++++++++++------- src/consensus/params.h | 36 +++++++++++++++++++++++++---- src/gtest/test_foundersreward.cpp | 8 +++---- src/main.cpp | 33 ++++++++++++++++++++++---- src/metrics.cpp | 2 +- src/miner.cpp | 2 +- src/rpc/mining.cpp | 2 +- src/test/main_tests.cpp | 12 +++++----- 9 files changed, 95 insertions(+), 32 deletions(-) diff --git a/qa/rpc-tests/shorter_block_times.py b/qa/rpc-tests/shorter_block_times.py index 26599d30c1a..74857740112 100755 --- a/qa/rpc-tests/shorter_block_times.py +++ b/qa/rpc-tests/shorter_block_times.py @@ -27,11 +27,11 @@ def setup_chain(self): def run_test(self): print "Mining blocks..." - self.nodes[0].generate(100) + self.nodes[0].generate(99) self.sync_all() # Sanity-check the block height - assert_equal(self.nodes[0].getblockcount(), 100) + assert_equal(self.nodes[0].getblockcount(), 99) print "Mining last pre-Blossom block" # Activate blossom diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 476385539e7..67ed810786c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -85,7 +85,8 @@ class CMainParams : public CChainParams { bip44CoinType = 133; // As registered in https://github.com/satoshilabs/slips/blob/master/slip-0044.md consensus.fCoinbaseMustBeProtected = true; consensus.nSubsidySlowStartInterval = 20000; - consensus.nSubsidyHalvingInterval = 840000; + consensus.nPreBlossomSubsidyHalvingInterval = Consensus::PRE_BLOSSOM_HALVING_INTERVAL; + consensus.nPostBlossomSubsidyHalvingInterval = Consensus::POST_BLOSSOM_HALVING_INTERVAL; consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 4000; @@ -261,7 +262,7 @@ class CMainParams : public CChainParams { // "t3T4WmAp6nrLkJ24iPpGeCe1fSWTPv47ASG", /* main-index: 53*/ // "t3fP6GrDM4QVwdjFhmCxGNbe7jXXXSDQ5dv", /* main-index: 54*/ }; - assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight()); + assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight(0)); } }; static CMainParams mainParams; @@ -277,7 +278,8 @@ class CTestNetParams : public CChainParams { bip44CoinType = 1; consensus.fCoinbaseMustBeProtected = true; consensus.nSubsidySlowStartInterval = 20000; - consensus.nSubsidyHalvingInterval = 840000; + consensus.nPreBlossomSubsidyHalvingInterval = Consensus::PRE_BLOSSOM_HALVING_INTERVAL; + consensus.nPostBlossomSubsidyHalvingInterval = Consensus::POST_BLOSSOM_HALVING_INTERVAL; consensus.nMajorityEnforceBlockUpgrade = 51; consensus.nMajorityRejectBlockOutdated = 75; consensus.nMajorityWindow = 400; @@ -394,7 +396,7 @@ class CTestNetParams : public CChainParams { "t2KXJVVyyrjVxxSeazbY9ksGyft4qsXUNm9", "t2J9YYtH31cveiLZzjaE4AcuwVho6qjTNzp", "t2QgvW4sP9zaGpPMH1GRzy7cpydmuRfB4AZ", "t2NDTJP9MosKpyFPHJmfjc5pGCvAU58XGa4", "t29pHDBWq7qN4EjwSEHg8wEqYe9pkmVrtRP", "t2Ez9KM8VJLuArcxuEkNRAkhNvidKkzXcjJ", "t2D5y7J5fpXajLbGrMBQkFg2mFN8fo3n8cX", "t2UV2wr1PTaUiybpkV3FdSdGxUJeZdZztyt", }; - assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight()); + assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight(0)); } }; static CTestNetParams testNetParams; @@ -410,7 +412,8 @@ class CRegTestParams : public CChainParams { bip44CoinType = 1; consensus.fCoinbaseMustBeProtected = false; consensus.nSubsidySlowStartInterval = 0; - consensus.nSubsidyHalvingInterval = 150; + consensus.nPreBlossomSubsidyHalvingInterval = Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL; + consensus.nPostBlossomSubsidyHalvingInterval = Consensus::POST_BLOSSOM_REGTEST_HALVING_INTERVAL; consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; @@ -495,7 +498,7 @@ class CRegTestParams : public CChainParams { // Founders reward script expects a vector of 2-of-3 multisig addresses vFoundersRewardAddress = { "t2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg" }; - assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight()); + assert(vFoundersRewardAddress.size() <= consensus.GetLastFoundersRewardBlockHeight(0)); } void UpdateNetworkUpgradeParameters(Consensus::UpgradeIndex idx, int nActivationHeight) @@ -568,7 +571,16 @@ bool SelectParamsFromCommandLine() // Block height must be >0 and <=last founders reward block height // Index variable i ranges from 0 - (vFoundersRewardAddress.size()-1) std::string CChainParams::GetFoundersRewardAddressAtHeight(int nHeight) const { - int maxHeight = consensus.GetLastFoundersRewardBlockHeight(); + int maxHeight = consensus.GetLastFoundersRewardBlockHeight(nHeight); + // zip208 + // FounderAddressAdjustedHeight(height) := + // height, if not IsBlossomActivated(height) + // BlossomActivationHeight + floor((height - BlossomActivationHeight) / BlossomPoWTargetSpacingRatio), otherwise + bool blossomActive = NetworkUpgradeActive(nHeight, consensus, Consensus::UPGRADE_BLOSSOM); + if (blossomActive) { + int blossomActivationHeight = consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; + nHeight = blossomActivationHeight + ((nHeight - blossomActivationHeight) / Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO); + } assert(nHeight > 0 && nHeight <= maxHeight); size_t addressChangeInterval = (maxHeight + vFoundersRewardAddress.size()) / vFoundersRewardAddress.size(); @@ -579,7 +591,7 @@ std::string CChainParams::GetFoundersRewardAddressAtHeight(int nHeight) const { // Block height must be >0 and <=last founders reward block height // The founders reward address is expected to be a multisig (P2SH) address CScript CChainParams::GetFoundersRewardScriptAtHeight(int nHeight) const { - assert(nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight()); + assert(nHeight > 0 && nHeight <= consensus.GetLastFoundersRewardBlockHeight(nHeight)); CTxDestination address = DecodeDestination(GetFoundersRewardAddressAtHeight(nHeight).c_str()); assert(IsValidDestination(address)); diff --git a/src/consensus/params.h b/src/consensus/params.h index ea517536fe8..b5cfe9177b9 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -73,6 +73,11 @@ struct NetworkUpgrade { static const unsigned int PRE_BLOSSOM_POW_TARGET_SPACING = 150; static const unsigned int POST_BLOSSOM_POW_TARGET_SPACING = 75; BOOST_STATIC_ASSERT(POST_BLOSSOM_POW_TARGET_SPACING < PRE_BLOSSOM_POW_TARGET_SPACING); +static const unsigned int PRE_BLOSSOM_HALVING_INTERVAL = 840000; +static const unsigned int PRE_BLOSSOM_REGTEST_HALVING_INTERVAL = 150; +static const unsigned int BLOSSOM_POW_TARGET_SPACING_RATIO = PRE_BLOSSOM_POW_TARGET_SPACING / POST_BLOSSOM_POW_TARGET_SPACING; +static const unsigned int POST_BLOSSOM_HALVING_INTERVAL = PRE_BLOSSOM_HALVING_INTERVAL * BLOSSOM_POW_TARGET_SPACING_RATIO; +static const unsigned int POST_BLOSSOM_REGTEST_HALVING_INTERVAL = PRE_BLOSSOM_REGTEST_HALVING_INTERVAL * BLOSSOM_POW_TARGET_SPACING_RATIO; /** * Parameters that influence chain consensus. @@ -92,14 +97,34 @@ struct Params { * * t_s = nSubsidySlowStartInterval * t_r = number of blocks between end of slow start and first halving - * t_h = nSubsidyHalvingInterval + * t_h = nPreBlossomSubsidyHalvingInterval * t_c = SubsidySlowStartShift() */ int SubsidySlowStartShift() const { return nSubsidySlowStartInterval / 2; } - int nSubsidyHalvingInterval; - int GetLastFoundersRewardBlockHeight() const { - return nSubsidyHalvingInterval + SubsidySlowStartShift() - 1; + int nPreBlossomSubsidyHalvingInterval; + int nPostBlossomSubsidyHalvingInterval; + + int GetLastFoundersRewardBlockHeight(int nHeight) const { + // zip208 + // FoundersRewardLastBlockHeight := max({ height ⦂ N | Halving(height) < 1 }) + // H := blossom activation height; SS := SubsidySlowStartShift(); R := BLOSSOM_POW_TARGET_SPACING_RATIO + // preBlossom: + // 1 = (height - SS) / preInterval + // height = preInterval + SS + // postBlossom: + // 1 = (H - SS) / preInterval + (height - H) / postInterval + // height = H + postInterval + (SS - H) * (postInterval / preInterval) + // height = H + postInterval + (SS - H) / R + bool blossomActive = NetworkUpgradeActive(nHeight, *this, Consensus::UPGRADE_BLOSSOM); + if (blossomActive) { + int blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; + return blossomActivationHeight + nPostBlossomSubsidyHalvingInterval + - (SubsidySlowStartShift() - blossomActivationHeight) / BLOSSOM_POW_TARGET_SPACING_RATIO - 1; + } else { + return nPreBlossomSubsidyHalvingInterval + SubsidySlowStartShift() - 1; + } } + /** Used to check majorities for block version upgrade */ int nMajorityEnforceBlockUpgrade; int nMajorityRejectBlockOutdated; @@ -117,6 +142,9 @@ struct Params { int64_t nPostBlossomPowTargetSpacing; int64_t PoWTargetSpacing(int nHeight) const { + // PoWTargetSpacing(height) := + // PreBlossomPoWTargetSpacing, if not IsBlossomActivated(height) + // PostBlossomPoWTargetSpacing, otherwise. bool blossomActive = NetworkUpgradeActive(nHeight, *this, Consensus::UPGRADE_BLOSSOM); return blossomActive ? nPostBlossomPowTargetSpacing : nPreBlossomPowTargetSpacing; } diff --git a/src/gtest/test_foundersreward.cpp b/src/gtest/test_foundersreward.cpp index 12c16ad897b..15e2c81b779 100644 --- a/src/gtest/test_foundersreward.cpp +++ b/src/gtest/test_foundersreward.cpp @@ -85,7 +85,7 @@ TEST(founders_reward_test, create_testnet_2of3multisig) { // Utility method to check the number of unique addresses from height 1 to maxHeight void checkNumberOfUniqueAddresses(int nUnique) { - int maxHeight = Params().GetConsensus().GetLastFoundersRewardBlockHeight(); + int maxHeight = Params().GetConsensus().GetLastFoundersRewardBlockHeight(0); std::set addresses; for (int i = 1; i <= maxHeight; i++) { addresses.insert(Params().GetFoundersRewardAddressAtHeight(i)); @@ -110,7 +110,7 @@ TEST(founders_reward_test, general) { EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(53127)), "a91455d64928e69829d9376c776550b6cc710d42715387"); EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(53127), "t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy"); - int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(); + int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(0); // If the block height parameter is out of bounds, there is an assert. EXPECT_DEATH(params.GetFoundersRewardScriptAtHeight(0), "nHeight"); @@ -151,7 +151,7 @@ TEST(founders_reward_test, slow_start_subsidy) { SelectParams(CBaseChainParams::MAIN); CChainParams params = Params(); - int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(); + int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(0); CAmount totalSubsidy = 0; for (int nHeight = 1; nHeight <= maxHeight; nHeight++) { CAmount nSubsidy = GetBlockSubsidy(nHeight, params.GetConsensus()) / 5; @@ -166,7 +166,7 @@ TEST(founders_reward_test, slow_start_subsidy) { // Verify the number of rewards each individual address receives. void verifyNumberOfRewards() { CChainParams params = Params(); - int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(); + int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(0); std::multiset ms; for (int nHeight = 1; nHeight <= maxHeight; nHeight++) { ms.insert(params.GetFoundersRewardAddressAtHeight(nHeight)); diff --git a/src/main.cpp b/src/main.cpp index fa28964e300..fbce29a91a2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1761,14 +1761,37 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) } assert(nHeight > consensusParams.SubsidySlowStartShift()); - int halvings = (nHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nSubsidyHalvingInterval; + + // zip208 + // Halving(height) := + // floor((height - SlowStartShift) / PreBlossomHalvingInterval), if not IsBlossomActivated(height) + // floor((BlossomActivationHeight - SlowStartShift) / PreBlossomHalvingInterval + (height - BlossomActivationHeight) / PostBlossomHalvingInterval), otherwise + bool blossomActive = NetworkUpgradeActive(nHeight, consensusParams, Consensus::UPGRADE_BLOSSOM); + int halvings; + if (blossomActive) { + int blossomActivationHeight = consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; + halvings = (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval + + (nHeight - blossomActivationHeight) / consensusParams.nPostBlossomSubsidyHalvingInterval; + } else { + halvings = (nHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval; + } + // Force block reward to zero when right shift is undefined. if (halvings >= 64) return 0; - // Subsidy is cut in half every 840,000 blocks which will occur approximately every 4 years. - nSubsidy >>= halvings; - return nSubsidy; + // zip208 + // BlockSubsidy(height) := + // SlowStartRate · height, if height < SlowStartInterval / 2 + // SlowStartRate · (height + 1), if SlowStartInterval / 2 ≤ height and height < SlowStartInterval + // floor(MaxBlockSubsidy / 2^Halving(height)), if SlowStartInterval ≤ height and not IsBlossomActivated(height) + // floor(MaxBlockSubsidy / (BlossomPoWTargetSpacingRatio · 2^Halving(height))), otherwise + if (blossomActive) { + return (nSubsidy / Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO) >> halvings; + } else { + // Subsidy is cut in half every 840,000 blocks which will occur approximately every 4 years. + return nSubsidy >> halvings; + } } bool IsInitialBlockDownload(const CChainParams& chainParams) @@ -3902,7 +3925,7 @@ bool ContextualCheckBlock( // reward block is reached, with exception of the genesis block. // The last founders reward block is defined as the block just before the // first subsidy halving block, which occurs at halving_interval + slow_start_shift - if ((nHeight > 0) && (nHeight <= consensusParams.GetLastFoundersRewardBlockHeight())) { + if ((nHeight > 0) && (nHeight <= consensusParams.GetLastFoundersRewardBlockHeight(nHeight))) { bool found = false; BOOST_FOREACH(const CTxOut& output, block.vtx[0].vout) { diff --git a/src/metrics.cpp b/src/metrics.cpp index a47f4538c80..877167de947 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -331,7 +331,7 @@ int printMetrics(size_t cols, bool mining) chainActive.Contains(mapBlockIndex[hash])) { int height = mapBlockIndex[hash]->nHeight; CAmount subsidy = GetBlockSubsidy(height, consensusParams); - if ((height > 0) && (height <= consensusParams.GetLastFoundersRewardBlockHeight())) { + if ((height > 0) && (height <= consensusParams.GetLastFoundersRewardBlockHeight(height))) { subsidy -= subsidy/5; } if (std::max(0, COINBASE_MATURITY - (tipHeight - height)) > 0) { diff --git a/src/miner.cpp b/src/miner.cpp index aa3306524ad..e9795ec6d19 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -405,7 +405,7 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s // Set to 0 so expiry height does not apply to coinbase txs txNew.nExpiryHeight = 0; - if ((nHeight > 0) && (nHeight <= chainparams.GetConsensus().GetLastFoundersRewardBlockHeight())) { + if ((nHeight > 0) && (nHeight <= chainparams.GetConsensus().GetLastFoundersRewardBlockHeight(nHeight))) { // Founders reward is 20% of the block subsidy auto vFoundersReward = txNew.vout[0].nValue / 5; // Take some reward away from us diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index a75ab5924b1..6eb2e2f3950 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -884,7 +884,7 @@ UniValue getblocksubsidy(const UniValue& params, bool fHelp) CAmount nReward = GetBlockSubsidy(nHeight, Params().GetConsensus()); CAmount nFoundersReward = 0; - if ((nHeight > 0) && (nHeight <= Params().GetConsensus().GetLastFoundersRewardBlockHeight())) { + if ((nHeight > 0) && (nHeight <= Params().GetConsensus().GetLastFoundersRewardBlockHeight(nHeight))) { nFoundersReward = nReward/5; nReward -= nFoundersReward; } diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp index ec02352e8b5..b731e89131e 100644 --- a/src/test/main_tests.cpp +++ b/src/test/main_tests.cpp @@ -22,7 +22,7 @@ static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams) for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) { int nHeight; if (nHalvings > 0) // Check subsidy right at halvings - nHeight = nHalvings * consensusParams.nSubsidyHalvingInterval + consensusParams.SubsidySlowStartShift(); + nHeight = nHalvings * consensusParams.nPreBlossomSubsidyHalvingInterval + consensusParams.SubsidySlowStartShift(); else // Check subsidy just after end of slow start nHeight = consensusParams.nSubsidySlowStartInterval; CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams); @@ -30,14 +30,14 @@ static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams) BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2); nPreviousSubsidy = nSubsidy; } - BOOST_CHECK_EQUAL(GetBlockSubsidy((maxHalvings * consensusParams.nSubsidyHalvingInterval) + consensusParams.SubsidySlowStartShift(), consensusParams), 0); + BOOST_CHECK_EQUAL(GetBlockSubsidy((maxHalvings * consensusParams.nPreBlossomSubsidyHalvingInterval) + consensusParams.SubsidySlowStartShift(), consensusParams), 0); } -static void TestBlockSubsidyHalvings(int nSubsidySlowStartInterval, int nSubsidyHalvingInterval) +static void TestBlockSubsidyHalvings(int nSubsidySlowStartInterval, int nPreBlossomSubsidyHalvingInterval) { Consensus::Params consensusParams; consensusParams.nSubsidySlowStartInterval = nSubsidySlowStartInterval; - consensusParams.nSubsidyHalvingInterval = nSubsidyHalvingInterval; + consensusParams.nPreBlossomSubsidyHalvingInterval = nPreBlossomSubsidyHalvingInterval; TestBlockSubsidyHalvings(consensusParams); } @@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE(subsidy_limit_test) } BOOST_CHECK_EQUAL(nSum, 12500000000000ULL); // Remainder of first period - for (int nHeight = consensusParams.nSubsidySlowStartInterval; nHeight < consensusParams.nSubsidyHalvingInterval + consensusParams.SubsidySlowStartShift(); nHeight ++) { + for (int nHeight = consensusParams.nSubsidySlowStartInterval; nHeight < consensusParams.nPreBlossomSubsidyHalvingInterval + consensusParams.SubsidySlowStartShift(); nHeight ++) { CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams); BOOST_CHECK(nSubsidy <= 12.5 * COIN); nSum += nSubsidy; @@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(subsidy_limit_test) } BOOST_CHECK_EQUAL(nSum, 1050000000000000ULL); // Regular mining - for (int nHeight = consensusParams.nSubsidyHalvingInterval + consensusParams.SubsidySlowStartShift(); nHeight < 56000000; nHeight += 1000) { + for (int nHeight = consensusParams.nPreBlossomSubsidyHalvingInterval + consensusParams.SubsidySlowStartShift(); nHeight < 56000000; nHeight += 1000) { CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams); BOOST_CHECK(nSubsidy <= 12.5 * COIN); nSum += nSubsidy * 1000; From 2c6c55261de16189a6da376cfc6ebe72bbf65686 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 29 Jul 2019 14:47:06 -0600 Subject: [PATCH 14/50] Make NetworkUpgradeAvailable a method of Params --- src/Makefile.am | 1 + src/chainparams.cpp | 2 +- src/consensus/params.cpp | 50 ++++++++++++++++ src/consensus/params.h | 59 ++++--------------- src/consensus/upgrades.cpp | 10 +--- src/consensus/upgrades.h | 10 ---- src/main.cpp | 20 +++---- src/rpc/rawtransaction.cpp | 4 +- .../asyncrpcoperation_mergetoaddress.cpp | 2 +- src/wallet/asyncrpcoperation_sendmany.cpp | 2 +- .../asyncrpcoperation_shieldcoinbase.cpp | 2 +- src/wallet/rpcwallet.cpp | 22 +++---- src/wallet/wallet.cpp | 10 ++-- 13 files changed, 93 insertions(+), 101 deletions(-) create mode 100644 src/consensus/params.cpp diff --git a/src/Makefile.am b/src/Makefile.am index a7c7b12bc5d..45a6a883455 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -367,6 +367,7 @@ libbitcoin_common_a_SOURCES = \ chainparams.cpp \ coins.cpp \ compressor.cpp \ + consensus/params.cpp \ consensus/upgrades.cpp \ core_read.cpp \ core_write.cpp \ diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 67ed810786c..50af3616baf 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -576,7 +576,7 @@ std::string CChainParams::GetFoundersRewardAddressAtHeight(int nHeight) const { // FounderAddressAdjustedHeight(height) := // height, if not IsBlossomActivated(height) // BlossomActivationHeight + floor((height - BlossomActivationHeight) / BlossomPoWTargetSpacingRatio), otherwise - bool blossomActive = NetworkUpgradeActive(nHeight, consensus, Consensus::UPGRADE_BLOSSOM); + bool blossomActive = consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM); if (blossomActive) { int blossomActivationHeight = consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; nHeight = blossomActivationHeight + ((nHeight - blossomActivationHeight) / Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO); diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp new file mode 100644 index 00000000000..4703a5549a4 --- /dev/null +++ b/src/consensus/params.cpp @@ -0,0 +1,50 @@ +#include "params.h" +#include "upgrades.h" + +namespace Consensus { + bool Params::NetworkUpgradeActive(int nHeight, Consensus::UpgradeIndex idx) const { + return NetworkUpgradeState(nHeight, *this, idx) == UPGRADE_ACTIVE; + } + + int Params::GetLastFoundersRewardBlockHeight(int nHeight) const { + // zip208 + // FoundersRewardLastBlockHeight := max({ height ⦂ N | Halving(height) < 1 }) + // H := blossom activation height; SS := SubsidySlowStartShift(); R := BLOSSOM_POW_TARGET_SPACING_RATIO + // preBlossom: + // 1 = (height - SS) / preInterval + // height = preInterval + SS + // postBlossom: + // 1 = (H - SS) / preInterval + (height - H) / postInterval + // height = H + postInterval + (SS - H) * (postInterval / preInterval) + // height = H + postInterval + (SS - H) / R + bool blossomActive = NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM); + if (blossomActive) { + int blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; + return blossomActivationHeight + nPostBlossomSubsidyHalvingInterval + - (SubsidySlowStartShift() - blossomActivationHeight) / BLOSSOM_POW_TARGET_SPACING_RATIO - 1; + } else { + return nPreBlossomSubsidyHalvingInterval + SubsidySlowStartShift() - 1; + } + } + + int64_t Params::PoWTargetSpacing(int nHeight) const { + // zip208 + // PoWTargetSpacing(height) := + // PreBlossomPoWTargetSpacing, if not IsBlossomActivated(height) + // PostBlossomPoWTargetSpacing, otherwise. + bool blossomActive = NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM); + return blossomActive ? nPostBlossomPowTargetSpacing : nPreBlossomPowTargetSpacing; + } + + int64_t Params::AveragingWindowTimespan(int nHeight) const { + return nPowAveragingWindow * PoWTargetSpacing(nHeight); + } + + int64_t Params::MinActualTimespan(int nHeight) const { + return (AveragingWindowTimespan(nHeight) * (100 - nPowMaxAdjustUp)) / 100; + } + + int64_t Params::MaxActualTimespan(int nHeight) const { + return (AveragingWindowTimespan(nHeight) * (100 + nPowMaxAdjustDown)) / 100; + } +} \ No newline at end of file diff --git a/src/consensus/params.h b/src/consensus/params.h index b5cfe9177b9..764b0efd49c 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -10,14 +10,6 @@ #include -// Forward declaration. Enum requires storage type. -namespace Consensus { - struct Params; - enum UpgradeIndex : uint32_t; -} -bool NetworkUpgradeActive(int nHeight, const Consensus::Params& params, Consensus::UpgradeIndex idx); - - namespace Consensus { /** @@ -83,6 +75,13 @@ static const unsigned int POST_BLOSSOM_REGTEST_HALVING_INTERVAL = PRE_BLOSSOM_RE * Parameters that influence chain consensus. */ struct Params { + /** + * 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; + uint256 hashGenesisBlock; bool fCoinbaseMustBeProtected; @@ -104,26 +103,7 @@ struct Params { int nPreBlossomSubsidyHalvingInterval; int nPostBlossomSubsidyHalvingInterval; - int GetLastFoundersRewardBlockHeight(int nHeight) const { - // zip208 - // FoundersRewardLastBlockHeight := max({ height ⦂ N | Halving(height) < 1 }) - // H := blossom activation height; SS := SubsidySlowStartShift(); R := BLOSSOM_POW_TARGET_SPACING_RATIO - // preBlossom: - // 1 = (height - SS) / preInterval - // height = preInterval + SS - // postBlossom: - // 1 = (H - SS) / preInterval + (height - H) / postInterval - // height = H + postInterval + (SS - H) * (postInterval / preInterval) - // height = H + postInterval + (SS - H) / R - bool blossomActive = NetworkUpgradeActive(nHeight, *this, Consensus::UPGRADE_BLOSSOM); - if (blossomActive) { - int blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; - return blossomActivationHeight + nPostBlossomSubsidyHalvingInterval - - (SubsidySlowStartShift() - blossomActivationHeight) / BLOSSOM_POW_TARGET_SPACING_RATIO - 1; - } else { - return nPreBlossomSubsidyHalvingInterval + SubsidySlowStartShift() - 1; - } - } + int GetLastFoundersRewardBlockHeight(int nHeight) const; /** Used to check majorities for block version upgrade */ int nMajorityEnforceBlockUpgrade; @@ -141,25 +121,10 @@ struct Params { int64_t nPreBlossomPowTargetSpacing; int64_t nPostBlossomPowTargetSpacing; - int64_t PoWTargetSpacing(int nHeight) const { - // PoWTargetSpacing(height) := - // PreBlossomPoWTargetSpacing, if not IsBlossomActivated(height) - // PostBlossomPoWTargetSpacing, otherwise. - bool blossomActive = NetworkUpgradeActive(nHeight, *this, Consensus::UPGRADE_BLOSSOM); - return blossomActive ? nPostBlossomPowTargetSpacing : nPreBlossomPowTargetSpacing; - } - - int64_t AveragingWindowTimespan(int nHeight) const { - return nPowAveragingWindow * PoWTargetSpacing(nHeight); - } - - int64_t MinActualTimespan(int nHeight) const { - return (AveragingWindowTimespan(nHeight) * (100 - nPowMaxAdjustUp)) / 100; - } - - int64_t MaxActualTimespan(int nHeight) const { - return (AveragingWindowTimespan(nHeight) * (100 + nPowMaxAdjustDown)) / 100; - } + 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; }; diff --git a/src/consensus/upgrades.cpp b/src/consensus/upgrades.cpp index e11aaa260e4..b86fbc23bd4 100644 --- a/src/consensus/upgrades.cpp +++ b/src/consensus/upgrades.cpp @@ -65,17 +65,9 @@ UpgradeState NetworkUpgradeState( } } -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))) { + if (params.NetworkUpgradeActive(nHeight, Consensus::UpgradeIndex(idxInt))) { return idxInt; } } diff --git a/src/consensus/upgrades.h b/src/consensus/upgrades.h index 920ec1ea896..f773ecae4a0 100644 --- a/src/consensus/upgrades.h +++ b/src/consensus/upgrades.h @@ -38,16 +38,6 @@ UpgradeState NetworkUpgradeState( 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 diff --git a/src/main.cpp b/src/main.cpp index fbce29a91a2..5a8b7983d87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -657,8 +657,8 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRE bool IsStandardTx(const CTransaction& tx, string& reason, const CChainParams& chainparams, const int nHeight) { - bool overwinterActive = NetworkUpgradeActive(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_OVERWINTER); - bool saplingActive = NetworkUpgradeActive(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_SAPLING); + bool overwinterActive = chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_OVERWINTER); + bool saplingActive = chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_SAPLING); if (saplingActive) { // Sapling standard rules apply @@ -897,8 +897,8 @@ bool ContextualCheckTransaction( const int dosLevel, bool (*isInitBlockDownload)(const CChainParams&)) { - bool overwinterActive = NetworkUpgradeActive(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_OVERWINTER); - bool saplingActive = NetworkUpgradeActive(nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_SAPLING); + bool overwinterActive = chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_OVERWINTER); + bool saplingActive = chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_SAPLING); bool isSprout = !overwinterActive; // If Sprout rules apply, reject transactions which are intended for Overwinter and beyond @@ -1367,7 +1367,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Node operator can choose to reject tx by number of transparent inputs static_assert(std::numeric_limits::max() >= std::numeric_limits::max(), "size_t too small"); size_t limit = (size_t) GetArg("-mempooltxinputlimit", 0); - if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + if (Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER)) { limit = 0; } if (limit > 0) { @@ -1766,7 +1766,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) // Halving(height) := // floor((height - SlowStartShift) / PreBlossomHalvingInterval), if not IsBlossomActivated(height) // floor((BlossomActivationHeight - SlowStartShift) / PreBlossomHalvingInterval + (height - BlossomActivationHeight) / PostBlossomHalvingInterval), otherwise - bool blossomActive = NetworkUpgradeActive(nHeight, consensusParams, Consensus::UPGRADE_BLOSSOM); + bool blossomActive = consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM); int halvings; if (blossomActive) { int blossomActivationHeight = consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; @@ -2392,7 +2392,7 @@ static DisconnectResult DisconnectBlock(const CBlock& block, CValidationState& s // However, this is only reliable if the last block was on or after // the Sapling activation height. Otherwise, the last anchor was the // empty root. - if (NetworkUpgradeActive(pindex->pprev->nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_SAPLING)) { + if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->pprev->nHeight, Consensus::UPGRADE_SAPLING)) { view.PopAnchor(pindex->pprev->hashFinalSaplingRoot, SAPLING); } else { view.PopAnchor(SaplingMerkleTree::empty_root(), SAPLING); @@ -2800,7 +2800,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // If Sapling is active, block.hashFinalSaplingRoot must be the // same as the root of the Sapling tree - if (NetworkUpgradeActive(pindex->nHeight, chainparams.GetConsensus(), Consensus::UPGRADE_SAPLING)) { + if (chainparams.GetConsensus().NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_SAPLING)) { if (block.hashFinalSaplingRoot != sapling_tree.root()) { return state.DoS(100, error("ConnectBlock(): block's hashFinalSaplingRoot is incorrect"), @@ -6670,7 +6670,7 @@ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Para CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight, int nExpiryDelta) { CMutableTransaction mtx; - bool isOverwintered = NetworkUpgradeActive(nHeight, consensusParams, Consensus::UPGRADE_OVERWINTER); + bool isOverwintered = consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_OVERWINTER); if (isOverwintered) { mtx.fOverwintered = true; mtx.nExpiryHeight = nHeight + nExpiryDelta; @@ -6683,7 +6683,7 @@ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Para // of the current epoch (see below: Overwinter->Sapling), the transaction will be rejected if it falls within // the expiring soon threshold of 3 blocks (for DoS mitigation) based on the current height. // TODO: Generalise this code so behaviour applies to all post-Overwinter epochs - if (NetworkUpgradeActive(nHeight, consensusParams, Consensus::UPGRADE_SAPLING)) { + if (consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_SAPLING)) { mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID; mtx.nVersion = SAPLING_TX_VERSION; } else { diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 612323abc46..d951d91bf95 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -531,7 +531,7 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) } if (params.size() > 3 && !params[3].isNull()) { - if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + if (Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER)) { int64_t nExpiryHeight = params[3].get_int64(); if (nExpiryHeight < 0 || nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, expiryheight must be nonnegative and less than %d.", TX_EXPIRY_HEIGHT_THRESHOLD)); @@ -1046,7 +1046,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) // DoS mitigation: reject transactions expiring soon if (tx.nExpiryHeight > 0) { int nextBlockHeight = chainActive.Height() + 1; - if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + if (Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER)) { if (nextBlockHeight + TX_EXPIRING_SOON_THRESHOLD > tx.nExpiryHeight) { throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("tx-expiring-soon: expiryheight is %d but should be at least %d to avoid transaction expiring soon", diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index fda81aa6dc6..4152f5be958 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -217,7 +217,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl() size_t limit = (size_t)GetArg("-mempooltxinputlimit", 0); { LOCK(cs_main); - if (NetworkUpgradeActive(chainActive.Height() + 1, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + if (Params().GetConsensus().NetworkUpgradeActive(chainActive.Height() + 1, Consensus::UPGRADE_OVERWINTER)) { limit = 0; } } diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 7e0a9dd50ce..e1bf32594c9 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -318,7 +318,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { size_t limit = (size_t)GetArg("-mempooltxinputlimit", 0); { LOCK(cs_main); - if (NetworkUpgradeActive(chainActive.Height() + 1, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + if (Params().GetConsensus().NetworkUpgradeActive(chainActive.Height() + 1, Consensus::UPGRADE_OVERWINTER)) { limit = 0; } } diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp index 0b2f0174b12..9b9d8ce20ea 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp @@ -180,7 +180,7 @@ bool AsyncRPCOperation_shieldcoinbase::main_impl() { size_t limit = (size_t)GetArg("-mempooltxinputlimit", 0); { LOCK(cs_main); - if (NetworkUpgradeActive(chainActive.Height() + 1, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + if (Params().GetConsensus().NetworkUpgradeActive(chainActive.Height() + 1, Consensus::UPGRADE_OVERWINTER)) { limit = 0; } } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5e07e85882d..67caf89cc09 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3790,8 +3790,8 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID; mtx.nVersion = SAPLING_TX_VERSION; unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING; - if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { - if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + if (!Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING)) { + if (Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER)) { mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nVersion = OVERWINTER_TX_VERSION; } else { @@ -3805,10 +3805,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS_BEFORE_SAPLING) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs"); } - } - - // If Sapling is not active, do not allow sending from or sending to Sapling addresses. - if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { + // If Sapling is not active, do not allow sending from or sending to Sapling addresses. if (fromSapling || containsSaplingOutput) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated"); } @@ -4122,15 +4119,12 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) } int nextBlockHeight = chainActive.Height() + 1; - bool overwinterActive = NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER); + bool overwinterActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER); unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING; - if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { + if (!Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING)) { max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING; - } - - // If Sapling is not active, do not allow sending to a Sapling address. - if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { auto res = DecodePaymentAddress(destaddress); + // If Sapling is not active, do not allow sending to a Sapling address. if (IsValidPaymentAddress(res)) { bool toSapling = boost::get(&res) != nullptr; if (toSapling) { @@ -4388,8 +4382,8 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) } const int nextBlockHeight = chainActive.Height() + 1; - const bool overwinterActive = NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER); - const bool saplingActive = NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING); + const bool overwinterActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER); + const bool saplingActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING); // Validate the destination address auto destaddress = params[1].get_str(); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 480547d9577..6133f56076d 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -595,7 +595,7 @@ void CWallet::ChainTip(const CBlockIndex *pindex, } void CWallet::RunSaplingMigration(int blockHeight) { - if (!NetworkUpgradeActive(blockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { + if (!Params().GetConsensus().NetworkUpgradeActive(blockHeight, Consensus::UPGRADE_SAPLING)) { return; } LOCK(cs_wallet); @@ -2526,7 +2526,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) // state on the path to the tip of our chain assert(pcoinsTip->GetSproutAnchorAt(pindex->hashSproutAnchor, sproutTree)); if (pindex->pprev) { - if (NetworkUpgradeActive(pindex->pprev->nHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { + if (Params().GetConsensus().NetworkUpgradeActive(pindex->pprev->nHeight, Consensus::UPGRADE_SAPLING)) { assert(pcoinsTip->GetSaplingAnchorAt(pindex->pprev->hashFinalSaplingRoot, saplingTree)); } } @@ -3303,7 +3303,7 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt Params().GetConsensus(), nextBlockHeight); // Activates after Overwinter network upgrade - if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + if (Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_OVERWINTER)) { if (txNew.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD){ strFailReason = _("nExpiryHeight must be less than TX_EXPIRY_HEIGHT_THRESHOLD."); return false; @@ -3311,7 +3311,7 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt } unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING; - if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { + if (!Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_SAPLING)) { max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING; } @@ -3502,7 +3502,7 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt size_t limit = (size_t)GetArg("-mempooltxinputlimit", 0); { LOCK(cs_main); - if (NetworkUpgradeActive(chainActive.Height() + 1, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) { + if (Params().GetConsensus().NetworkUpgradeActive(chainActive.Height() + 1, Consensus::UPGRADE_OVERWINTER)) { limit = 0; } } From 07851670b4d907198b15fca476a16d197f5e90c9 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 29 Jul 2019 15:04:34 -0600 Subject: [PATCH 15/50] Temporarily disable test --- qa/pull-tester/rpc-tests.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index 3b6d411aead..e724c93fa95 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -73,7 +73,8 @@ testScripts=( 'p2p_node_bloom.py' 'regtest_signrawtransaction.py' 'finalsaplingroot.py' - 'shorter_block_times.py' + # TODO: enable the following test when updating PROTOCOL_VERSION in version.h for Blossom + # 'shorter_block_times.py' 'sprout_sapling_migration.py' 'turnstile.py' ); From c0d27cb3f2cee056218a1d51a825d740ddbcbfcb Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 29 Jul 2019 18:29:39 -0600 Subject: [PATCH 16/50] Simplify PartitionCheck --- src/init.cpp | 2 +- src/main.cpp | 37 +++++++++++++------------------------ src/main.h | 2 +- src/test/alert_tests.cpp | 21 ++++++++++++--------- 4 files changed, 27 insertions(+), 35 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 6d6fd1f4a5d..7b6b2ab03b4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1863,7 +1863,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) // Monitor the chain every minute, and alert if we get blocks much quicker or slower than expected. CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload, - boost::ref(cs_main), boost::cref(pindexBestHeader), 0); + boost::ref(cs_main), boost::cref(pindexBestHeader)); scheduler.scheduleEvery(f, 60); #ifdef ENABLE_MINING diff --git a/src/main.cpp b/src/main.cpp index 5a8b7983d87..04a817c1ce7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2458,13 +2458,8 @@ void ThreadScriptCheck() { // Called periodically asynchronously; alerts if it smells like // we're being fed a bad chain (blocks being generated much // too slowly or too quickly). -// -// When parameter nPowTargetSpacing is not set, the default value of 0 -// means use the block height of the best header to determine target spacing. -// Setting the parameter value is useful for testing. void PartitionCheck(bool (*initialDownloadCheck)(const CChainParams&), - CCriticalSection& cs, const CBlockIndex *const &bestHeader, - int64_t nPowTargetSpacing) + CCriticalSection& cs, const CBlockIndex *const &bestHeader) { if (bestHeader == NULL || initialDownloadCheck(Params())) return; @@ -2477,26 +2472,20 @@ void PartitionCheck(bool (*initialDownloadCheck)(const CChainParams&), LOCK(cs); - int bestHeaderHeight = bestHeader->nHeight; - int blossomHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; - if (nPowTargetSpacing == 0) { - nPowTargetSpacing = Params().GetConsensus().PoWTargetSpacing(bestHeaderHeight); - blossomHeight = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; - } - - int BLOCKS_EXPECTED = SPAN_SECONDS / nPowTargetSpacing; + Consensus::Params consensusParams = Params().GetConsensus(); + int BLOCKS_EXPECTED; + // TODO: This can be simplified when the Blossom activation height is set + int nBlossomBlocks = consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight == Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT ? + 0 : std::max(0, bestHeader->nHeight - consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight); + int blossomBlockTime = nBlossomBlocks * consensusParams.nPostBlossomPowTargetSpacing; // If the span period includes Blossom activation, adjust the number of expected blocks. - if (blossomHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT && - bestHeaderHeight > blossomHeight) - { - int t = SPAN_SECONDS; - int nBlossomBlocks = bestHeaderHeight - blossomHeight; - t -= nBlossomBlocks * Consensus::POST_BLOSSOM_POW_TARGET_SPACING; - if (t > 0) { - int nPreBlossomBlocks = t / Consensus::PRE_BLOSSOM_POW_TARGET_SPACING; - BLOCKS_EXPECTED = nPreBlossomBlocks + nBlossomBlocks; - } + if (blossomBlockTime < SPAN_SECONDS) { + // If there are 0 blossomBlocks the following is equivalent to + // BLOCKS_EXPECTED = SPAN_SECONDS / consensusParams.nPreBlossomPowTargetSpacing + BLOCKS_EXPECTED = nBlossomBlocks + (SPAN_SECONDS - blossomBlockTime) / consensusParams.nPreBlossomPowTargetSpacing; + } else { + BLOCKS_EXPECTED = SPAN_SECONDS / consensusParams.nPostBlossomPowTargetSpacing; } boost::math::poisson_distribution poisson(BLOCKS_EXPECTED); diff --git a/src/main.h b/src/main.h index deda1276c7b..ff15180ccdb 100644 --- a/src/main.h +++ b/src/main.h @@ -234,7 +234,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle); /** Run an instance of the script checking thread */ void ThreadScriptCheck(); /** Try to detect Partition (network isolation) attacks against us */ -void PartitionCheck(bool (*initialDownloadCheck)(const CChainParams&), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing = 0); +void PartitionCheck(bool (*initialDownloadCheck)(const CChainParams&), CCriticalSection& cs, const CBlockIndex *const &bestHeader); /** Check whether we are doing an initial block download (synchronizing from disk or network) */ bool IsInitialBlockDownload(const CChainParams& chainParams); /** Format a string that describes several potential problems detected by the core */ diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index f50f7c49725..9be91645c19 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -410,23 +410,25 @@ BOOST_AUTO_TEST_CASE(PartitionAlert) // Test 1: chain with blocks every nPowTargetSpacing seconds, // as normal, no worries: - PartitionCheck(falseFunc, csDummy, &indexDummy[399], nPowTargetSpacing); - BOOST_CHECK(strMiscWarning.empty()); + strMiscWarning = ""; + PartitionCheck(falseFunc, csDummy, &indexDummy[399]); + BOOST_CHECK_EQUAL("", strMiscWarning); // Test 2: go 3.5 hours without a block, expect a warning: now += 3*60*60+30*60; SetMockTime(now); - PartitionCheck(falseFunc, csDummy, &indexDummy[399], nPowTargetSpacing); - BOOST_CHECK(!strMiscWarning.empty()); - BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning); strMiscWarning = ""; + PartitionCheck(falseFunc, csDummy, &indexDummy[399]); + BOOST_CHECK_EQUAL("WARNING: check your network connection, 12 blocks received in the last 4 hours (96 expected)", strMiscWarning); + BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning); // Test 3: test the "partition alerts only go off once per day" // code: now += 60*10; SetMockTime(now); - PartitionCheck(falseFunc, csDummy, &indexDummy[399], nPowTargetSpacing); - BOOST_CHECK(strMiscWarning.empty()); + strMiscWarning = ""; + PartitionCheck(falseFunc, csDummy, &indexDummy[399]); + BOOST_CHECK_EQUAL("", strMiscWarning); // Test 4: get 2.5 times as many blocks as expected: now += 60*60*24; // Pretend it is a day later @@ -434,8 +436,9 @@ BOOST_AUTO_TEST_CASE(PartitionAlert) int64_t quickSpacing = nPowTargetSpacing*2/5; for (int i = 0; i < 400; i++) // Tweak chain timestamps: indexDummy[i].nTime = now - (400-i)*quickSpacing; - PartitionCheck(falseFunc, csDummy, &indexDummy[399], nPowTargetSpacing); - BOOST_CHECK(!strMiscWarning.empty()); + strMiscWarning = ""; + PartitionCheck(falseFunc, csDummy, &indexDummy[399]); + BOOST_CHECK_EQUAL("WARNING: abnormally high number of blocks generated, 240 blocks received in the last 4 hours (96 expected)", strMiscWarning); BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning); strMiscWarning = ""; From e6b63d1f784ea019568fea0ad6a1ec12d522812c Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 29 Jul 2019 19:05:41 -0600 Subject: [PATCH 17/50] Use static_assert --- src/consensus/params.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/consensus/params.h b/src/consensus/params.h index 764b0efd49c..a3657da6135 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -64,7 +64,7 @@ struct NetworkUpgrade { /** 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; -BOOST_STATIC_ASSERT(POST_BLOSSOM_POW_TARGET_SPACING < PRE_BLOSSOM_POW_TARGET_SPACING); +static_assert(POST_BLOSSOM_POW_TARGET_SPACING < PRE_BLOSSOM_POW_TARGET_SPACING); static const unsigned int PRE_BLOSSOM_HALVING_INTERVAL = 840000; static const unsigned int PRE_BLOSSOM_REGTEST_HALVING_INTERVAL = 150; static const unsigned int BLOSSOM_POW_TARGET_SPACING_RATIO = PRE_BLOSSOM_POW_TARGET_SPACING / POST_BLOSSOM_POW_TARGET_SPACING; From 68e9d2164cd46ffe306d41d7923b73f13a4af441 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 29 Jul 2019 19:07:27 -0600 Subject: [PATCH 18/50] Add missing new line at end of file --- src/consensus/params.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp index 4703a5549a4..1d6003a1a82 100644 --- a/src/consensus/params.cpp +++ b/src/consensus/params.cpp @@ -47,4 +47,4 @@ namespace Consensus { int64_t Params::MaxActualTimespan(int nHeight) const { return (AveragingWindowTimespan(nHeight) * (100 + nPowMaxAdjustDown)) / 100; } -} \ No newline at end of file +} From 0bb79ea1914afba2e51e80162ec0459d1e731075 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 29 Jul 2019 19:07:56 -0600 Subject: [PATCH 19/50] pow test cleanup --- src/gtest/test_pow.cpp | 14 +++++++------- src/test/pow_tests.cpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gtest/test_pow.cpp b/src/gtest/test_pow.cpp index 4a09ac69dd9..281701892e3 100644 --- a/src/gtest/test_pow.cpp +++ b/src/gtest/test_pow.cpp @@ -16,7 +16,7 @@ void TestDifficultyAveragigingImpl(const Consensus::Params& params) for (int i = 0; i <= lastBlk; i++) { blocks[i].pprev = i ? &blocks[i - 1] : nullptr; blocks[i].nHeight = i; - blocks[i].nTime = 1269211443 + i * params.PoWTargetSpacing(blocks[i].nHeight); + blocks[i].nTime = i ? blocks[i - 1].nTime + params.PoWTargetSpacing(i) : 1269211443; blocks[i].nBits = 0x1e7fffff; /* target 0x007fffff000... */ blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0); } @@ -33,12 +33,12 @@ void TestDifficultyAveragigingImpl(const Consensus::Params& params) // Result should be unchanged, modulo integer division precision loss arith_uint256 bnRes; bnRes.SetCompact(0x1e7fffff); - bnRes /= params.AveragingWindowTimespan(blocks[lastBlk].nHeight); - bnRes *= params.AveragingWindowTimespan(blocks[lastBlk].nHeight); + bnRes /= params.AveragingWindowTimespan(blocks[lastBlk].nHeight + 1); + bnRes *= params.AveragingWindowTimespan(blocks[lastBlk].nHeight + 1); EXPECT_EQ(bnRes.GetCompact(), GetNextWorkRequired(&blocks[lastBlk], nullptr, params)); // Randomise the final block time (plus 1 to ensure it is always different) - blocks[lastBlk].nTime += GetRand(params.PoWTargetSpacing(blocks[lastBlk].nHeight)/2) + 1; + blocks[lastBlk].nTime += GetRand(params.PoWTargetSpacing(blocks[lastBlk].nHeight + 1)/2) + 1; // Result should be the same as if last difficulty was used bnAvg.SetCompact(blocks[lastBlk].nBits); @@ -94,7 +94,7 @@ TEST(PoW, MinDifficultyRules) { for (int i = 0; i <= lastBlk; i++) { blocks[i].pprev = i ? &blocks[i - 1] : nullptr; blocks[i].nHeight = params.nPowAllowMinDifficultyBlocksAfterHeight.get() + i; - blocks[i].nTime = 1269211443 + i * params.PoWTargetSpacing(blocks[i].nHeight); + blocks[i].nTime = i ? blocks[i - 1].nTime + params.PoWTargetSpacing(i) : 1269211443; blocks[i].nBits = 0x1e7fffff; /* target 0x007fffff000... */ blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0); } @@ -106,8 +106,8 @@ TEST(PoW, MinDifficultyRules) { // Result should be unchanged, modulo integer division precision loss arith_uint256 bnRes; bnRes.SetCompact(0x1e7fffff); - bnRes /= params.AveragingWindowTimespan(blocks[lastBlk].nHeight); - bnRes *= params.AveragingWindowTimespan(blocks[lastBlk].nHeight); + bnRes /= params.AveragingWindowTimespan(blocks[lastBlk].nHeight + 1); + bnRes *= params.AveragingWindowTimespan(blocks[lastBlk].nHeight + 1); EXPECT_EQ(GetNextWorkRequired(&blocks[lastBlk], &next, params), bnRes.GetCompact()); // Delay last block up to the edge of the min-difficulty limit diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index 626aaf5955f..416b4ac7c17 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -137,7 +137,7 @@ void GetBlockProofEquivalentTimeImpl(const Consensus::Params& params) { for (int i = 0; i < 10000; i++) { blocks[i].pprev = i ? &blocks[i - 1] : NULL; blocks[i].nHeight = i; - blocks[i].nTime = 1269211443 + i * params.PoWTargetSpacing(blocks[i].nHeight); + blocks[i].nTime = i ? blocks[i - 1].nTime + params.PoWTargetSpacing(i) : 1269211443; blocks[i].nBits = 0x207fffff; /* target 0x7fffff000... */ blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0); } From c5ac4321f994fd243834a2bbc273798be889d990 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 29 Jul 2019 23:25:08 -0600 Subject: [PATCH 20/50] Add message to static_assert --- src/consensus/params.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/consensus/params.h b/src/consensus/params.h index a3657da6135..9bb2fe6c740 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -64,7 +64,7 @@ struct NetworkUpgrade { /** 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(POST_BLOSSOM_POW_TARGET_SPACING < PRE_BLOSSOM_POW_TARGET_SPACING); +static_assert(POST_BLOSSOM_POW_TARGET_SPACING < PRE_BLOSSOM_POW_TARGET_SPACING, "Blossom target spacing must be less than pre-Blossom target spacing."); static const unsigned int PRE_BLOSSOM_HALVING_INTERVAL = 840000; static const unsigned int PRE_BLOSSOM_REGTEST_HALVING_INTERVAL = 150; static const unsigned int BLOSSOM_POW_TARGET_SPACING_RATIO = PRE_BLOSSOM_POW_TARGET_SPACING / POST_BLOSSOM_POW_TARGET_SPACING; From 8865f4b6f61cc888968ac3e514f16fbee917d1d5 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 30 Jul 2019 01:16:37 -0600 Subject: [PATCH 21/50] Update expiry height for shorter block times --- src/consensus/params.cpp | 6 ++++ src/consensus/params.h | 2 ++ src/gtest/test_checktransaction.cpp | 12 +++---- src/gtest/test_transaction_builder.cpp | 34 +++++++++---------- src/init.cpp | 13 ++++--- src/main.cpp | 9 ++--- src/main.h | 13 +++---- src/rpc/rawtransaction.cpp | 4 ++- src/test/rpc_wallet_tests.cpp | 2 +- src/transaction_builder.cpp | 9 +++-- src/transaction_builder.h | 3 +- src/utiltest.cpp | 2 +- .../asyncrpcoperation_saplingmigration.cpp | 4 +-- src/wallet/gtest/test_wallet.cpp | 24 ++++++------- src/wallet/rpcwallet.cpp | 6 ++-- 15 files changed, 80 insertions(+), 63 deletions(-) diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp index 1d6003a1a82..2179a30d3d8 100644 --- a/src/consensus/params.cpp +++ b/src/consensus/params.cpp @@ -1,4 +1,6 @@ #include "params.h" + +#include "main.h" #include "upgrades.h" namespace Consensus { @@ -27,6 +29,10 @@ namespace Consensus { } } + unsigned int Params::DefaultExpiryDelta(int nHeight) const { + return NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM) ? DEFAULT_POST_BLOSSOM_TX_EXPIRY_DELTA : DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA; + } + int64_t Params::PoWTargetSpacing(int nHeight) const { // zip208 // PoWTargetSpacing(height) := diff --git a/src/consensus/params.h b/src/consensus/params.h index 9bb2fe6c740..7ececeeb7c0 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -105,6 +105,8 @@ struct Params { int GetLastFoundersRewardBlockHeight(int nHeight) const; + unsigned int DefaultExpiryDelta(int nHeight) const; + /** Used to check majorities for block version upgrade */ int nMajorityEnforceBlockUpgrade; int nMajorityRejectBlockOutdated; diff --git a/src/gtest/test_checktransaction.cpp b/src/gtest/test_checktransaction.cpp index 45580a0824c..e4b3d33617c 100644 --- a/src/gtest/test_checktransaction.cpp +++ b/src/gtest/test_checktransaction.cpp @@ -906,18 +906,18 @@ TEST(checktransaction_tests, OverwinteredContextualCreateTx) { // Overwinter activates { CMutableTransaction mtx = CreateNewContextualCMutableTransaction( - consensusParams, activationHeight ); + consensusParams, activationHeight); EXPECT_EQ(mtx.nVersion, 3); EXPECT_EQ(mtx.fOverwintered, true); EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); - EXPECT_EQ(mtx.nExpiryHeight, activationHeight + expiryDelta); + EXPECT_EQ(mtx.nExpiryHeight, activationHeight + DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA); } // Close to Sapling activation { CMutableTransaction mtx = CreateNewContextualCMutableTransaction( - consensusParams, saplingActivationHeight - expiryDelta - 2); + consensusParams, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA - 2); EXPECT_EQ(mtx.fOverwintered, true); EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); @@ -927,7 +927,7 @@ TEST(checktransaction_tests, OverwinteredContextualCreateTx) { { CMutableTransaction mtx = CreateNewContextualCMutableTransaction( - consensusParams, saplingActivationHeight - expiryDelta - 1); + consensusParams, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA - 1); EXPECT_EQ(mtx.fOverwintered, true); EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); @@ -937,7 +937,7 @@ TEST(checktransaction_tests, OverwinteredContextualCreateTx) { { CMutableTransaction mtx = CreateNewContextualCMutableTransaction( - consensusParams, saplingActivationHeight - expiryDelta); + consensusParams, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA); EXPECT_EQ(mtx.fOverwintered, true); EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); @@ -964,7 +964,7 @@ TEST(checktransaction_tests, OverwinteredContextualCreateTx) { EXPECT_EQ(mtx.fOverwintered, true); EXPECT_EQ(mtx.nVersionGroupId, SAPLING_VERSION_GROUP_ID); EXPECT_EQ(mtx.nVersion, SAPLING_TX_VERSION); - EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight + expiryDelta); + EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight + DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA); } // Revert to default diff --git a/src/gtest/test_transaction_builder.cpp b/src/gtest/test_transaction_builder.cpp index d8c44ba1f88..332c194f85a 100644 --- a/src/gtest/test_transaction_builder.cpp +++ b/src/gtest/test_transaction_builder.cpp @@ -93,7 +93,7 @@ TEST(TransactionBuilder, TransparentToSapling) // Create a shielding transaction from transparent to Sapling // 0.0005 t-ZEC in, 0.0004 z-ZEC out, 0.0001 t-ZEC fee - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); + auto builder = TransactionBuilder(consensusParams, 1, &keystore); builder.AddTransparentInput(COutPoint(), scriptPubKey, 50000); builder.AddSaplingOutput(fvk_from.ovk, pk, 40000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -125,7 +125,7 @@ TEST(TransactionBuilder, SaplingToSapling) { // Create a Sapling-only transaction // 0.0004 z-ZEC in, 0.00025 z-ZEC out, 0.0001 t-ZEC fee, 0.00005 z-ZEC change - auto builder = TransactionBuilder(consensusParams, 2, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 2); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); // Check that trying to add a different anchor fails @@ -166,7 +166,7 @@ TEST(TransactionBuilder, SaplingToSprout) { // - 0.0004 Sapling-ZEC in - 0.00025 Sprout-ZEC out // - 0.00005 Sapling-ZEC change // - 0.0001 t-ZEC fee - auto builder = TransactionBuilder(consensusParams, 2, expiryDelta, nullptr, params); + auto builder = TransactionBuilder(consensusParams, 2, nullptr, params); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSproutOutput(sproutAddr, 25000); auto tx = builder.Build().GetTxOrThrow(); @@ -218,7 +218,7 @@ TEST(TransactionBuilder, SproutToSproutAndSapling) { // - 0.00005 Sprout-ZEC change // - 0.00005 Sapling-ZEC out // - 0.00005 t-ZEC fee - auto builder = TransactionBuilder(consensusParams, 2, expiryDelta, nullptr, params, &view); + auto builder = TransactionBuilder(consensusParams, 2, nullptr, params, &view); builder.SetFee(5000); builder.AddSproutInput(sproutSk, sproutNote, sproutWitness); builder.AddSproutOutput(sproutAddr, 6000); @@ -255,7 +255,7 @@ TEST(TransactionBuilder, ThrowsOnSproutOutputWithoutParams) auto sk = libzcash::SproutSpendingKey::random(); auto addr = sk.address(); - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); ASSERT_THROW(builder.AddSproutOutput(addr, 10), std::runtime_error); } @@ -264,7 +264,7 @@ TEST(TransactionBuilder, ThrowsOnTransparentInputWithoutKeyStore) SelectParams(CBaseChainParams::REGTEST); auto consensusParams = Params().GetConsensus(); - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); ASSERT_THROW(builder.AddTransparentInput(COutPoint(), CScript(), 1), std::runtime_error); } @@ -275,7 +275,7 @@ TEST(TransactionBuilder, RejectsInvalidTransparentOutput) // Default CTxDestination type is an invalid address CTxDestination taddr; - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); ASSERT_THROW(builder.AddTransparentOutput(taddr, 50), UniValue); } @@ -286,7 +286,7 @@ TEST(TransactionBuilder, RejectsInvalidTransparentChangeAddress) // Default CTxDestination type is an invalid address CTxDestination taddr; - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); ASSERT_THROW(builder.SendChangeTo(taddr), UniValue); } @@ -311,13 +311,13 @@ TEST(TransactionBuilder, FailsWithNegativeChange) // Fail if there is only a Sapling output // 0.0005 z-ZEC out, 0.0001 t-ZEC fee - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); builder.AddSaplingOutput(fvk.ovk, pa, 50000, {}); EXPECT_EQ("Change cannot be negative", builder.Build().GetError()); // Fail if there is only a transparent output // 0.0005 t-ZEC out, 0.0001 t-ZEC fee - builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); + builder = TransactionBuilder(consensusParams, 1, &keystore); builder.AddTransparentOutput(taddr, 50000); EXPECT_EQ("Change cannot be negative", builder.Build().GetError()); @@ -359,14 +359,14 @@ TEST(TransactionBuilder, ChangeOutput) // No change address and no Sapling spends { - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); + auto builder = TransactionBuilder(consensusParams, 1, &keystore); builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000); EXPECT_EQ("Could not determine change address", builder.Build().GetError()); } // Change to the same address as the first Sapling spend { - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); + auto builder = TransactionBuilder(consensusParams, 1, &keystore); builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); auto tx = builder.Build().GetTxOrThrow(); @@ -381,7 +381,7 @@ TEST(TransactionBuilder, ChangeOutput) // Change to a Sapling address { - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); + auto builder = TransactionBuilder(consensusParams, 1, &keystore); builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000); builder.SendChangeTo(zChangeAddr, fvkOut.ovk); auto tx = builder.Build().GetTxOrThrow(); @@ -396,7 +396,7 @@ TEST(TransactionBuilder, ChangeOutput) // Change to a transparent address { - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); + auto builder = TransactionBuilder(consensusParams, 1, &keystore); builder.AddTransparentInput(COutPoint(), scriptPubKey, 25000); builder.SendChangeTo(taddr); auto tx = builder.Build().GetTxOrThrow(); @@ -428,7 +428,7 @@ TEST(TransactionBuilder, SetFee) // Default fee { - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSaplingOutput(fvk.ovk, pa, 25000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -443,7 +443,7 @@ TEST(TransactionBuilder, SetFee) // Configured fee { - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSaplingOutput(fvk.ovk, pa, 25000, {}); builder.SetFee(20000); @@ -472,7 +472,7 @@ TEST(TransactionBuilder, CheckSaplingTxVersion) auto pk = sk.default_address(); // Cannot add Sapling outputs to a non-Sapling transaction - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); try { builder.AddSaplingOutput(uint256(), pk, 12345, {}); } catch (std::runtime_error const & err) { diff --git a/src/init.cpp b/src/init.cpp index 7b6b2ab03b4..a1f5c30e30d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -418,7 +418,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0)); strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), 1)); strUsage += HelpMessageOpt("-txconfirmtarget=", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET)); - strUsage += HelpMessageOpt("-txexpirydelta", strprintf(_("Set the number of blocks after which a transaction that has not been mined will become invalid (min: %u, default: %u)"), TX_EXPIRING_SOON_THRESHOLD + 1, DEFAULT_TX_EXPIRY_DELTA)); + strUsage += HelpMessageOpt("-txexpirydelta", strprintf(_("Set the number of blocks after which a transaction that has not been mined will become invalid (min: %u, default: %u (pre-Blossom) or %u (post-Blossom))"), TX_EXPIRING_SOON_THRESHOLD + 1, DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA, DEFAULT_POST_BLOSSOM_TX_EXPIRY_DELTA)); strUsage += HelpMessageOpt("-maxtxfee=", strprintf(_("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)"), CURRENCY_UNIT, FormatMoney(maxTxFee))); strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format") + " " + _("on startup")); @@ -1065,10 +1065,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); - expiryDelta = GetArg("-txexpirydelta", DEFAULT_TX_EXPIRY_DELTA); - uint32_t minExpiryDelta = TX_EXPIRING_SOON_THRESHOLD + 1; - if (expiryDelta < minExpiryDelta) { - return InitError(strprintf(_("Invalid value for -expiryDelta='%u' (must be least %u)"), expiryDelta, minExpiryDelta)); + if (mapArgs.count("-txexpirydelta")) { + int64_t expiryDelta = atoi64(mapArgs["txexpirydelta"]); + uint32_t minExpiryDelta = TX_EXPIRING_SOON_THRESHOLD + 1; + if (expiryDelta < minExpiryDelta) { + return InitError(strprintf(_("Invalid value for -txexpirydelta='%u' (must be least %u)"), expiryDelta, minExpiryDelta)); + } + expiryDeltaArg = expiryDelta; } bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", true); fSendFreeTransactions = GetBoolArg("-sendfreetransactions", false); diff --git a/src/main.cpp b/src/main.cpp index 04a817c1ce7..1537a76b113 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -84,7 +84,7 @@ bool fAlerts = DEFAULT_ALERTS; */ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; -unsigned int expiryDelta = DEFAULT_TX_EXPIRY_DELTA; +boost::optional expiryDeltaArg = boost::none; /** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */ CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); @@ -6654,16 +6654,13 @@ static class CMainCleanup // Set default values of new CMutableTransaction based on consensus rules at given height. CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight) { - return CreateNewContextualCMutableTransaction(consensusParams, nHeight, expiryDelta); -} - -CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight, int nExpiryDelta) { CMutableTransaction mtx; bool isOverwintered = consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_OVERWINTER); if (isOverwintered) { mtx.fOverwintered = true; - mtx.nExpiryHeight = nHeight + nExpiryDelta; + mtx.nExpiryHeight = nHeight + (expiryDeltaArg ? expiryDeltaArg.get() : consensusParams.DefaultExpiryDelta(nHeight)); + // Review: Should the following if() be checking the expiry delta rather than the transaction height? if (mtx.nExpiryHeight <= 0 || mtx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { throw new std::runtime_error("CreateNewContextualCMutableTransaction: invalid expiry height"); } diff --git a/src/main.h b/src/main.h index ff15180ccdb..85d1782c673 100644 --- a/src/main.h +++ b/src/main.h @@ -73,7 +73,8 @@ static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 100; /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; /** Default for -txexpirydelta, in number of blocks */ -static const unsigned int DEFAULT_TX_EXPIRY_DELTA = 20; +static const unsigned int DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA = 20; +static const unsigned int DEFAULT_POST_BLOSSOM_TX_EXPIRY_DELTA = DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA * Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO; /** The number of blocks within expiry height when a tx is considered to be expiring soon */ static constexpr uint32_t TX_EXPIRING_SOON_THRESHOLD = 3; /** The maximum size of a blk?????.dat file (since 0.8) */ @@ -119,7 +120,7 @@ struct BlockHasher size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); } }; -extern unsigned int expiryDelta; +extern boost::optional expiryDeltaArg; extern CScript COINBASE_FLAGS; extern CCriticalSection cs_main; extern CTxMemPool mempool; @@ -518,10 +519,10 @@ int GetSpendHeight(const CCoinsViewCache& inputs); uint64_t CalculateCurrentUsage(); -/** Return a CMutableTransaction with contextual default values based on set of consensus rules at nHeight, and the default expiry delta. */ +/** + * Return a CMutableTransaction with contextual default values based on set of consensus rules at nHeight. The expiryDelta will + * either be based on the command-line argument '-txexpirydelta' or derived from consensusParams. + */ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight); -/** Return a CMutableTransaction with contextual default values based on set of consensus rules at nHeight, and given expiry delta. */ -CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight, int nExpiryDelta); - #endif // BITCOIN_MAIN_H diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index d951d91bf95..065d1498292 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -502,7 +502,9 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) " ,...\n" " }\n" "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n" - "4. expiryheight (numeric, optional, default=nextblockheight+" + strprintf("%d", DEFAULT_TX_EXPIRY_DELTA) + ") Expiry height of transaction (if Overwinter is active)\n" + "4. expiryheight (numeric, optional, default=nextblockheight+" + + strprintf("%d (pre-Blossom) or %d (post-Blossom)", DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA, DEFAULT_POST_BLOSSOM_TX_EXPIRY_DELTA) + ") " + "Expiry height of transaction (if Overwinter is active)\n" "\nResult:\n" "\"transaction\" (string) hex string of the transaction\n" diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index f04d3f2c216..f2cc09903d4 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -1302,7 +1302,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_taddr_to_sapling) pwalletMain->AddToWallet(wtx, true, NULL); // Context that z_sendmany requires - auto builder = TransactionBuilder(consensusParams, nextBlockHeight, expiryDelta, pwalletMain); + auto builder = TransactionBuilder(consensusParams, nextBlockHeight, pwalletMain); mtx = CreateNewContextualCMutableTransaction(consensusParams, nextBlockHeight); std::vector recipients = { SendManyRecipient(zaddr1, 1 * COIN, "ABCD") }; diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp index aa34ffb15e5..f81bcc4debb 100644 --- a/src/transaction_builder.cpp +++ b/src/transaction_builder.cpp @@ -50,7 +50,6 @@ std::string TransactionBuilderResult::GetError() { TransactionBuilder::TransactionBuilder( const Consensus::Params& consensusParams, int nHeight, - int nExpiryDelta, CKeyStore* keystore, ZCJoinSplit* sproutParams, CCoinsViewCache* coinsView, @@ -62,7 +61,7 @@ TransactionBuilder::TransactionBuilder( coinsView(coinsView), cs_coinsView(cs_coinsView) { - mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight, nExpiryDelta); + mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight); } // This exception is thrown in certain scenarios when building JoinSplits fails. @@ -76,6 +75,12 @@ struct JSDescException : public std::exception std::string msg; }; + +void TransactionBuilder::SetExpiryHeight(uint32_t nExpiryHeight) +{ + mtx.nExpiryHeight = nExpiryHeight; +} + void TransactionBuilder::AddSaplingSpend( libzcash::SaplingExpandedSpendingKey expsk, libzcash::SaplingNote note, diff --git a/src/transaction_builder.h b/src/transaction_builder.h index 46f38481ecc..7cd12bee843 100644 --- a/src/transaction_builder.h +++ b/src/transaction_builder.h @@ -95,12 +95,13 @@ class TransactionBuilder TransactionBuilder( const Consensus::Params& consensusParams, int nHeight, - int nExpiryDelta, CKeyStore* keyStore = nullptr, ZCJoinSplit* sproutParams = nullptr, CCoinsViewCache* coinsView = nullptr, CCriticalSection* cs_coinsView = nullptr); + void SetExpiryHeight(uint32_t nExpiryHeight); + void SetFee(CAmount fee); // Throws if the anchor does not match the anchor used by diff --git a/src/utiltest.cpp b/src/utiltest.cpp index 7c503f388a6..9e382d08425 100644 --- a/src/utiltest.cpp +++ b/src/utiltest.cpp @@ -252,7 +252,7 @@ CWalletTx GetValidSaplingReceive(const Consensus::Params& consensusParams, auto fvk = sk.expsk.full_viewing_key(); auto pa = sk.DefaultAddress(); - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keyStore); + auto builder = TransactionBuilder(consensusParams, 1, &keyStore); builder.SetFee(0); builder.AddTransparentInput(COutPoint(), scriptPubKey, value); builder.AddSaplingOutput(fvk.ovk, pa, value, {}); diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index 7b28295bd9e..a8ac453ad51 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -103,8 +103,8 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { CCoinsViewCache coinsView(pcoinsTip); do { CAmount amountToSend = chooseAmount(availableFunds); - auto builder = TransactionBuilder(consensusParams, targetHeight_, MIGRATION_EXPIRY_DELTA, pwalletMain, pzcashParams, - &coinsView, &cs_main); + auto builder = TransactionBuilder(consensusParams, targetHeight_, pwalletMain, pzcashParams, &coinsView, &cs_main); + builder.SetExpiryHeight(targetHeight_ + MIGRATION_EXPIRY_DELTA); LogPrint("zrpcunsafe", "%s: Beginning creating transaction with Sapling output amount=%s\n", getId(), FormatMoney(amountToSend - FEE)); std::vector fromNotes; CAmount fromNoteAmount = 0; diff --git a/src/wallet/gtest/test_wallet.cpp b/src/wallet/gtest/test_wallet.cpp index df95a676c75..b5b9a237ae0 100644 --- a/src/wallet/gtest/test_wallet.cpp +++ b/src/wallet/gtest/test_wallet.cpp @@ -379,7 +379,7 @@ TEST(WalletTests, SetSaplingNoteAddrsInCWalletTx) { ASSERT_TRUE(nf); uint256 nullifier = nf.get(); - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); builder.AddSaplingSpend(expsk, note, anchor, witness); builder.AddSaplingOutput(fvk.ovk, pk, 50000, {}); builder.SetFee(0); @@ -506,7 +506,7 @@ TEST(WalletTests, FindMySaplingNotes) { auto testNote = GetTestSaplingNote(pa, 50000); // Generate transaction - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSaplingOutput(fvk.ovk, pa, 25000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -638,7 +638,7 @@ TEST(WalletTests, GetConflictedSaplingNotes) { auto witness = saplingTree.witness(); // Generate tx to create output note B - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); builder.AddSaplingSpend(expsk, note, anchor, witness); builder.AddSaplingOutput(fvk.ovk, pk, 35000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -692,13 +692,13 @@ TEST(WalletTests, GetConflictedSaplingNotes) { anchor = saplingTree.root(); // Create transaction to spend note B - auto builder2 = TransactionBuilder(consensusParams, 2, expiryDelta); + auto builder2 = TransactionBuilder(consensusParams, 2); builder2.AddSaplingSpend(expsk, note2, anchor, spend_note_witness); builder2.AddSaplingOutput(fvk.ovk, pk, 20000, {}); auto tx2 = builder2.Build().GetTxOrThrow(); // Create conflicting transaction which also spends note B - auto builder3 = TransactionBuilder(consensusParams, 2, expiryDelta); + auto builder3 = TransactionBuilder(consensusParams, 2); builder3.AddSaplingSpend(expsk, note2, anchor, spend_note_witness); builder3.AddSaplingOutput(fvk.ovk, pk, 19999, {}); auto tx3 = builder3.Build().GetTxOrThrow(); @@ -785,7 +785,7 @@ TEST(WalletTests, SaplingNullifierIsSpent) { auto testNote = GetTestSaplingNote(pa, 50000); // Generate transaction - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSaplingOutput(fvk.ovk, pa, 25000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -868,7 +868,7 @@ TEST(WalletTests, NavigateFromSaplingNullifierToNote) { auto testNote = GetTestSaplingNote(pa, 50000); // Generate transaction - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSaplingOutput(fvk.ovk, pa, 25000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -996,7 +996,7 @@ TEST(WalletTests, SpentSaplingNoteIsFromMe) { auto witness = saplingTree.witness(); // Generate transaction, which sends funds to note B - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); builder.AddSaplingSpend(expsk, note, anchor, witness); builder.AddSaplingOutput(fvk.ovk, pk, 25000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -1066,7 +1066,7 @@ TEST(WalletTests, SpentSaplingNoteIsFromMe) { anchor = saplingTree.root(); // Create transaction to spend note B - auto builder2 = TransactionBuilder(consensusParams, 2, expiryDelta); + auto builder2 = TransactionBuilder(consensusParams, 2); builder2.AddSaplingSpend(expsk, note2, anchor, spend_note_witness); builder2.AddSaplingOutput(fvk.ovk, pk, 12500, {}); auto tx2 = builder2.Build().GetTxOrThrow(); @@ -1771,7 +1771,7 @@ TEST(WalletTests, UpdatedSaplingNoteData) { auto testNote = GetTestSaplingNote(pa, 50000); // Generate transaction - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta); + auto builder = TransactionBuilder(consensusParams, 1); builder.AddSaplingSpend(expsk, testNote.note, testNote.tree.root(), testNote.tree.witness()); builder.AddSaplingOutput(fvk.ovk, pa2, 25000, {}); auto tx = builder.Build().GetTxOrThrow(); @@ -1912,7 +1912,7 @@ TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) { // Generate shielding tx from transparent to Sapling // 0.0005 t-ZEC in, 0.0004 z-ZEC out, 0.0001 t-ZEC fee - auto builder = TransactionBuilder(consensusParams, 1, expiryDelta, &keystore); + auto builder = TransactionBuilder(consensusParams, 1, &keystore); builder.AddTransparentInput(COutPoint(), scriptPubKey, 50000); builder.AddSaplingOutput(fvk.ovk, pk, 40000, {}); auto tx1 = builder.Build().GetTxOrThrow(); @@ -1967,7 +1967,7 @@ TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) { // Create a Sapling-only transaction // 0.0004 z-ZEC in, 0.00025 z-ZEC out, 0.0001 t-ZEC fee, 0.00005 z-ZEC change - auto builder2 = TransactionBuilder(consensusParams, 2, expiryDelta); + auto builder2 = TransactionBuilder(consensusParams, 2); builder2.AddSaplingSpend(expsk, note, anchor, witness); builder2.AddSaplingOutput(fvk.ovk, pk, 25000, {}); auto tx2 = builder2.Build().GetTxOrThrow(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 67caf89cc09..973646efc2d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3885,7 +3885,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) // Builder (used if Sapling addresses are involved) boost::optional builder; if (noSproutAddrs) { - builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, expiryDelta, pwalletMain); + builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain); } // Contextual transaction we will build on @@ -4222,7 +4222,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) // Builder (used if Sapling addresses are involved) TransactionBuilder builder = TransactionBuilder( - Params().GetConsensus(), nextBlockHeight, expiryDelta, pwalletMain); + Params().GetConsensus(), nextBlockHeight, pwalletMain); // Contextual transaction we will build on // (used if no Sapling addresses are involved) @@ -4648,7 +4648,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) // Builder (used if Sapling addresses are involved) boost::optional builder; if (isToSaplingZaddr || saplingNoteInputs.size() > 0) { - builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, expiryDelta, pwalletMain); + builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain); } // Create operation and add to global queue std::shared_ptr q = getAsyncRPCQueue(); From 1188c9adf7bcbecabe9bd70357d76992872f486b Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 30 Jul 2019 17:41:33 -0600 Subject: [PATCH 22/50] Fix zip208 founders reward calculation and update test --- src/consensus/params.cpp | 4 ++-- src/consensus/params.h | 2 +- src/gtest/test_foundersreward.cpp | 12 +++++++++++- src/gtest/test_pow.cpp | 4 ++-- src/test/pow_tests.cpp | 20 ++++++++++---------- src/utiltest.cpp | 6 +++--- src/utiltest.h | 4 ++-- 7 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp index 2179a30d3d8..35cc6c9d24e 100644 --- a/src/consensus/params.cpp +++ b/src/consensus/params.cpp @@ -18,12 +18,12 @@ namespace Consensus { // postBlossom: // 1 = (H - SS) / preInterval + (height - H) / postInterval // height = H + postInterval + (SS - H) * (postInterval / preInterval) - // height = H + postInterval + (SS - H) / R + // height = H + postInterval + (SS - H) * R bool blossomActive = NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM); if (blossomActive) { int blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; return blossomActivationHeight + nPostBlossomSubsidyHalvingInterval - - (SubsidySlowStartShift() - blossomActivationHeight) / BLOSSOM_POW_TARGET_SPACING_RATIO - 1; + + (SubsidySlowStartShift() - blossomActivationHeight) * BLOSSOM_POW_TARGET_SPACING_RATIO - 1; } else { return nPreBlossomSubsidyHalvingInterval + SubsidySlowStartShift() - 1; } diff --git a/src/consensus/params.h b/src/consensus/params.h index 7ececeeb7c0..979d294bff6 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -67,7 +67,7 @@ static const unsigned int POST_BLOSSOM_POW_TARGET_SPACING = 75; static_assert(POST_BLOSSOM_POW_TARGET_SPACING < PRE_BLOSSOM_POW_TARGET_SPACING, "Blossom target spacing must be less than pre-Blossom target spacing."); static const unsigned int PRE_BLOSSOM_HALVING_INTERVAL = 840000; static const unsigned int PRE_BLOSSOM_REGTEST_HALVING_INTERVAL = 150; -static const unsigned int BLOSSOM_POW_TARGET_SPACING_RATIO = PRE_BLOSSOM_POW_TARGET_SPACING / POST_BLOSSOM_POW_TARGET_SPACING; +static const int BLOSSOM_POW_TARGET_SPACING_RATIO = PRE_BLOSSOM_POW_TARGET_SPACING / POST_BLOSSOM_POW_TARGET_SPACING; static const unsigned int POST_BLOSSOM_HALVING_INTERVAL = PRE_BLOSSOM_HALVING_INTERVAL * BLOSSOM_POW_TARGET_SPACING_RATIO; static const unsigned int POST_BLOSSOM_REGTEST_HALVING_INTERVAL = PRE_BLOSSOM_REGTEST_HALVING_INTERVAL * BLOSSOM_POW_TARGET_SPACING_RATIO; diff --git a/src/gtest/test_foundersreward.cpp b/src/gtest/test_foundersreward.cpp index 15e2c81b779..1f4f8241125 100644 --- a/src/gtest/test_foundersreward.cpp +++ b/src/gtest/test_foundersreward.cpp @@ -13,6 +13,7 @@ #include #include #include "util.h" +#include "utiltest.h" // To run tests: // ./zcash-gtest --gtest_filter="founders_reward_test.*" @@ -119,6 +120,15 @@ TEST(founders_reward_test, general) { EXPECT_DEATH(params.GetFoundersRewardAddressAtHeight(maxHeight+1), "nHeight"); } +TEST(founders_reward_test, get_last_block_blossom) { + int blossomActivationHeight = /*slowStartShift*/ + Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL / 2; // = 75 + auto params = RegtestActivateBlossom(false, blossomActivationHeight); + int slowStartShift = params.SubsidySlowStartShift(); // 0 for regtest + EXPECT_EQ(Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL + slowStartShift - 1, params.GetLastFoundersRewardBlockHeight(0)); + EXPECT_EQ(Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL + slowStartShift - 1, params.GetLastFoundersRewardBlockHeight(blossomActivationHeight - 1)); + int blossomBlocks = (Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL- blossomActivationHeight) * Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO; + EXPECT_EQ(blossomActivationHeight + blossomBlocks + slowStartShift - 1, params.GetLastFoundersRewardBlockHeight(blossomActivationHeight)); +} #define NUM_MAINNET_FOUNDER_ADDRESSES 48 @@ -147,7 +157,7 @@ TEST(founders_reward_test, regtest) { // Test that 10% founders reward is fully rewarded after the first halving and slow start shift. // On Mainnet, this would be 2,100,000 ZEC after 850,000 blocks (840,000 + 10,000). -TEST(founders_reward_test, slow_start_subsidy) { +TEST(founders_reward_test, slow_start_subsidy) { // TODO: Update this test when the Blossom activation height is set SelectParams(CBaseChainParams::MAIN); CChainParams params = Params(); diff --git a/src/gtest/test_pow.cpp b/src/gtest/test_pow.cpp index 281701892e3..4e0e8fcdc5c 100644 --- a/src/gtest/test_pow.cpp +++ b/src/gtest/test_pow.cpp @@ -79,8 +79,8 @@ TEST(PoW, DifficultyAveraging) { } TEST(PoW, DifficultyAveragingBlossom) { - TestDifficultyAveragigingImpl(ActivateBlossom(true)); - DeactivateBlossom(); + TestDifficultyAveragigingImpl(RegtestActivateBlossom(true)); + RegtestDeactivateBlossom(); } TEST(PoW, MinDifficultyRules) { diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index 416b4ac7c17..3aebbc00d9a 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -32,7 +32,7 @@ BOOST_AUTO_TEST_CASE(get_next_work) BOOST_AUTO_TEST_CASE(get_next_work_blossom) { - const Consensus::Params& params = ActivateBlossom(true); + const Consensus::Params& params = RegtestActivateBlossom(true); BOOST_CHECK_EQUAL(75, params.PoWTargetSpacing(0)); int64_t nLastRetargetTime = 1000000000; // NOTE: Not an actual block time @@ -42,7 +42,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_blossom) BOOST_CHECK_GT(0x1d011998, CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); - DeactivateBlossom(); + RegtestDeactivateBlossom(); } /* Test the constraint on the upper bound for next work */ @@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_pow_limit) BOOST_AUTO_TEST_CASE(get_next_work_pow_limit_blossom) { - const Consensus::Params& params = ActivateBlossom(true); + const Consensus::Params& params = RegtestActivateBlossom(true); int64_t nLastRetargetTime = 1231006505; int64_t nThisTime = 1233061996; @@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_pow_limit_blossom) BOOST_CHECK_EQUAL(0x1f07ffff, CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); - DeactivateBlossom(); + RegtestDeactivateBlossom(); } /* Test the constraint on the lower bound for actual time taken */ @@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual) BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual_blossom) { - const Consensus::Params& params = ActivateBlossom(true); + const Consensus::Params& params = RegtestActivateBlossom(true); int64_t nLastRetargetTime = 1000000000; // NOTE: Not an actual block time int64_t nThisTime = 1000000458; @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual_blossom) BOOST_CHECK_EQUAL(0x1c04bceb, CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); - DeactivateBlossom(); + RegtestDeactivateBlossom(); } /* Test the constraint on the upper bound for actual time taken */ @@ -120,7 +120,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual) BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual_blossom) { - const Consensus::Params& params = ActivateBlossom(true); + const Consensus::Params& params = RegtestActivateBlossom(true); int64_t nLastRetargetTime = 1000000000; // NOTE: Not an actual block time int64_t nThisTime = 1000002908; @@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual_blossom) BOOST_CHECK_EQUAL(0x1c4a93bb, CalculateNextWorkRequired(bnAvg, nThisTime, nLastRetargetTime, params, 0)); - DeactivateBlossom(); + RegtestDeactivateBlossom(); } void GetBlockProofEquivalentTimeImpl(const Consensus::Params& params) { @@ -160,8 +160,8 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test_blossom) { - GetBlockProofEquivalentTimeImpl(ActivateBlossom(true)); - DeactivateBlossom(); + GetBlockProofEquivalentTimeImpl(RegtestActivateBlossom(true)); + RegtestDeactivateBlossom(); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/utiltest.cpp b/src/utiltest.cpp index 9e382d08425..d8e1e441099 100644 --- a/src/utiltest.cpp +++ b/src/utiltest.cpp @@ -200,18 +200,18 @@ void RegtestDeactivateSapling() { UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); } -const Consensus::Params& ActivateBlossom(bool updatePow) { +const Consensus::Params& RegtestActivateBlossom(bool updatePow, int blossomActivationHeight) { SelectParams(CBaseChainParams::REGTEST); UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_BLOSSOM, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_BLOSSOM, blossomActivationHeight); if (updatePow) { UpdateRegtestPow(32, 16, uint256S("0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); } return Params().GetConsensus(); } -void DeactivateBlossom() { +void RegtestDeactivateBlossom() { UpdateRegtestPow(0, 0, uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f")); UpdateNetworkUpgradeParameters(Consensus::UPGRADE_BLOSSOM, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); diff --git a/src/utiltest.h b/src/utiltest.h index 9fd3b661361..df060362e55 100644 --- a/src/utiltest.h +++ b/src/utiltest.h @@ -43,9 +43,9 @@ const Consensus::Params& RegtestActivateSapling(); void RegtestDeactivateSapling(); -const Consensus::Params& ActivateBlossom(bool updatePow); +const Consensus::Params& RegtestActivateBlossom(bool updatePow, int blossomActivationHeight = Consensus::NetworkUpgrade::ALWAYS_ACTIVE); -void DeactivateBlossom(); +void RegtestDeactivateBlossom(); libzcash::SaplingExtendedSpendingKey GetTestMasterSaplingSpendingKey(); From e358e89db9d1893fbeb52a342ced7bf237137f26 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Wed, 31 Jul 2019 12:20:15 -0600 Subject: [PATCH 23/50] PartitionCheck tests for shorter block times --- src/test/alert_tests.cpp | 70 +++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index 9be91645c19..83e966cda94 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -19,6 +19,7 @@ #include "streams.h" #include "util.h" #include "utilstrencodings.h" +#include "utiltest.h" #include "test/test_bitcoin.h" @@ -385,41 +386,40 @@ BOOST_AUTO_TEST_CASE(AlertDisablesRPC) static bool falseFunc(const CChainParams&) { return false; } -BOOST_AUTO_TEST_CASE(PartitionAlert) +void PartitionAlertTestImpl(const Consensus::Params& params, int startTime, int expectedTotal, int expectedSlow, int expectedFast) { // Test PartitionCheck CCriticalSection csDummy; - CBlockIndex indexDummy[400]; - CChainParams& params = Params(CBaseChainParams::MAIN); - int64_t nPowTargetSpacing = params.GetConsensus().PoWTargetSpacing(0); // First 400 blocks are pre-Blossom + CBlockIndex indexDummy[800]; - // Generate fake blockchain timestamps relative to - // an arbitrary time: - int64_t now = 1427379054; - SetMockTime(now); - for (int i = 0; i < 400; i++) + int64_t start = startTime; + for (int i = 0; i < 800; i++) { indexDummy[i].phashBlock = NULL; - if (i == 0) indexDummy[i].pprev = NULL; - else indexDummy[i].pprev = &indexDummy[i-1]; + indexDummy[i].pprev = i ? &indexDummy[i-1] : NULL; indexDummy[i].nHeight = i; - indexDummy[i].nTime = now - (400-i)*nPowTargetSpacing; + indexDummy[i].nTime = i ? indexDummy[i - 1].nTime + params.PoWTargetSpacing(i) : start; // Other members don't matter, the partition check code doesn't // use them } + // Generate fake blockchain timestamps relative to + // an arbitrary time: + int64_t now = indexDummy[799].nTime + params.PoWTargetSpacing(800); + SetMockTime(now); // Test 1: chain with blocks every nPowTargetSpacing seconds, // as normal, no worries: strMiscWarning = ""; - PartitionCheck(falseFunc, csDummy, &indexDummy[399]); + PartitionCheck(falseFunc, csDummy, &indexDummy[799]); BOOST_CHECK_EQUAL("", strMiscWarning); // Test 2: go 3.5 hours without a block, expect a warning: now += 3*60*60+30*60; SetMockTime(now); strMiscWarning = ""; - PartitionCheck(falseFunc, csDummy, &indexDummy[399]); - BOOST_CHECK_EQUAL("WARNING: check your network connection, 12 blocks received in the last 4 hours (96 expected)", strMiscWarning); + PartitionCheck(falseFunc, csDummy, &indexDummy[799]); + std::string expectedSlowErr = strprintf("WARNING: check your network connection, %d blocks received in the last 4 hours (%d expected)", expectedSlow, expectedTotal); + BOOST_CHECK_EQUAL(expectedSlowErr, strMiscWarning); BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning); // Test 3: test the "partition alerts only go off once per day" @@ -427,24 +427,50 @@ BOOST_AUTO_TEST_CASE(PartitionAlert) now += 60*10; SetMockTime(now); strMiscWarning = ""; - PartitionCheck(falseFunc, csDummy, &indexDummy[399]); + PartitionCheck(falseFunc, csDummy, &indexDummy[799]); BOOST_CHECK_EQUAL("", strMiscWarning); // Test 4: get 2.5 times as many blocks as expected: - now += 60*60*24; // Pretend it is a day later + start = now + 60*60*24; // Pretend it is a day later + for (int i = 0; i < 800; i++) { + // Tweak chain timestamps: + indexDummy[i].nTime = i ? indexDummy[i - 1].nTime + params.PoWTargetSpacing(i) * 2/5 : start; + } + now = indexDummy[799].nTime + params.PoWTargetSpacing(0) * 2/5; SetMockTime(now); - int64_t quickSpacing = nPowTargetSpacing*2/5; - for (int i = 0; i < 400; i++) // Tweak chain timestamps: - indexDummy[i].nTime = now - (400-i)*quickSpacing; + strMiscWarning = ""; - PartitionCheck(falseFunc, csDummy, &indexDummy[399]); - BOOST_CHECK_EQUAL("WARNING: abnormally high number of blocks generated, 240 blocks received in the last 4 hours (96 expected)", strMiscWarning); + PartitionCheck(falseFunc, csDummy, &indexDummy[799]); + std::string expectedFastErr = strprintf("WARNING: abnormally high number of blocks generated, %d blocks received in the last 4 hours (%d expected)", expectedFast, expectedTotal); + BOOST_CHECK_EQUAL(expectedFastErr, strMiscWarning); BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning); strMiscWarning = ""; SetMockTime(0); } +BOOST_AUTO_TEST_CASE(PartitionAlert) +{ + CChainParams& params = Params(CBaseChainParams::MAIN); + PartitionAlertTestImpl(params.GetConsensus(), 1000000000, 96, 12, 240); +} + +BOOST_AUTO_TEST_CASE(PartitionAlertBlossomOnly) +{ + PartitionAlertTestImpl(RegtestActivateBlossom(false), 1500000000, 96 * 2, 12 * 2, 240 * 2); + RegtestDeactivateBlossom(); +} + +BOOST_AUTO_TEST_CASE(PartitionAlertBlossomActivates) +{ + // 48 pre blossom blocks, 96 blossom blocks will take 48 * 150s + 96 * 75s = 4hrs + // in the slow case, all of the blocks will be blossom blocks + // in the fast case, 96 blocks will be blossom => 96 * 75s * 2/5 = 2880s spent on on blossom + // => (14400 - 2880) / (150 * 2/5) = 11520 / 60 = 192 pre blossom blocks + PartitionAlertTestImpl(RegtestActivateBlossom(false, 799 - 96), 2000000000, 144, 12 * 2, 192 + 96); + RegtestDeactivateBlossom(); +} + BOOST_AUTO_TEST_SUITE_END() #endif From ecfcb817ae7f4d9b91e6764e0eab3f671c817250 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Wed, 31 Jul 2019 14:34:48 -0600 Subject: [PATCH 24/50] Add test for Blossom default tx expiry delta --- src/gtest/test_checktransaction.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/gtest/test_checktransaction.cpp b/src/gtest/test_checktransaction.cpp index e4b3d33617c..7e6eb9a84a5 100644 --- a/src/gtest/test_checktransaction.cpp +++ b/src/gtest/test_checktransaction.cpp @@ -691,6 +691,14 @@ TEST(checktransaction_tests, OverwinterExpiryHeight) { } } +TEST(checktransaction_tests, BlossomExpiryHeight) { + const Consensus::Params& params = RegtestActivateBlossom(false, 100); + CMutableTransaction preBlossomMtx = CreateNewContextualCMutableTransaction(params, 99); + EXPECT_EQ(preBlossomMtx.nExpiryHeight, 99 + 20); + CMutableTransaction blossomMtx = CreateNewContextualCMutableTransaction(params, 100); + EXPECT_EQ(blossomMtx.nExpiryHeight, 100 + 40); + RegtestDeactivateBlossom(); +} // Test that a Sprout tx with a negative version number is detected // given the new Overwinter logic From 6c1df957ba476e8e996b888721354ccf23b8c45c Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Wed, 31 Jul 2019 15:16:25 -0600 Subject: [PATCH 25/50] Update metrics block height estimation for shorter block times --- src/gtest/test_metrics.cpp | 52 ++++++++++---------------------------- src/metrics.cpp | 47 +++++++++++++--------------------- src/metrics.h | 5 ++-- 3 files changed, 33 insertions(+), 71 deletions(-) diff --git a/src/gtest/test_metrics.cpp b/src/gtest/test_metrics.cpp index 143fe46d601..b818e4c132b 100644 --- a/src/gtest/test_metrics.cpp +++ b/src/gtest/test_metrics.cpp @@ -1,6 +1,7 @@ #include #include "metrics.h" +#include "utiltest.h" #include "utiltime.h" @@ -93,43 +94,16 @@ TEST(Metrics, GetLocalSolPS) { EXPECT_EQ(1, GetLocalSolPS()); } -TEST(Metrics, EstimateNetHeightInner) { - // Ensure that the (rounded) current height is returned if the tip is current - SetMockTime(15000); - EXPECT_EQ(100, EstimateNetHeightInner(100, 14100, 50, 7500, 0, 150)); - SetMockTime(15150); - EXPECT_EQ(100, EstimateNetHeightInner(101, 14250, 50, 7500, 0, 150)); - - // Ensure that correct estimates are returned if the tip is in the past - SetMockTime(15300); // Tip is 2 blocks behind - EXPECT_EQ(100, EstimateNetHeightInner(100, 14100, 50, 7500, 0, 150)); - SetMockTime(15900); // Tip is 6 blocks behind - EXPECT_EQ(110, EstimateNetHeightInner(100, 14100, 50, 7500, 0, 150)); - - // Check estimates during resync - SetMockTime(15000); - EXPECT_EQ(100, EstimateNetHeightInner( 0, 0, 50, 7500, 0, 150)); - EXPECT_EQ(100, EstimateNetHeightInner( 7, 600, 50, 7500, 0, 150)); - EXPECT_EQ(100, EstimateNetHeightInner( 8, 600, 50, 7500, 0, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(10, 750, 50, 7500, 0, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(11, 900, 50, 7500, 0, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(20, 2100, 50, 7500, 0, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(49, 6450, 50, 7500, 0, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(50, 6600, 50, 7500, 0, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(51, 6750, 50, 7500, 0, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(55, 7350, 50, 7500, 0, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(56, 7500, 50, 7500, 0, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(57, 7650, 50, 7500, 0, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(75, 10350, 50, 7500, 0, 150)); - - // More complex calculations: - SetMockTime(20000); - // - Checkpoint spacing: 200 - // -> Average spacing: 175 - // -> estimated height: 127 -> 130 - EXPECT_EQ(130, EstimateNetHeightInner(100, 14100, 50, 5250, 0, 150)); - // - Checkpoint spacing: 50 - // -> Average spacing: 100 - // -> estimated height: 153 -> 150 - EXPECT_EQ(150, EstimateNetHeightInner(100, 14100, 50, 12000, 0, 150)); +TEST(Metrics, EstimateNetHeight) { + auto params = RegtestActivateBlossom(false, 200); + int64_t blockTimes[400]; + for (int i = 0; i < 400; i++) { + blockTimes[i] = i ? blockTimes[i - 1] + params.PoWTargetSpacing(i) : 0; + } + SetMockTime(blockTimes[399]); + for (int i = 0; i < 400; i++) { + // Check that we are within 1 of the correct height + EXPECT_LT(std::abs(399 - EstimateNetHeight(params, i, blockTimes[i])), 2); + } + RegtestDeactivateBlossom(); } diff --git a/src/metrics.cpp b/src/metrics.cpp index 877167de947..40cc06260aa 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -7,6 +7,7 @@ #include "chainparams.h" #include "checkpoints.h" #include "main.h" +#include "timedata.h" #include "ui_interface.h" #include "util.h" #include "utiltime.h" @@ -108,34 +109,22 @@ double GetLocalSolPS() return miningTimer.rate(solutionTargetChecks); } -int EstimateNetHeightInner(int height, int64_t tipmediantime, - int heightLastCheckpoint, int64_t timeLastCheckpoint, - int64_t genesisTime, int64_t targetSpacing) +int EstimateNetHeight(const Consensus::Params& params, int currentBlockHeight, int64_t currentBlockTime) { - // We average the target spacing with the observed spacing to the last - // checkpoint (either from below or above depending on the current height), - // and use that to estimate the current network height. - int medianHeight = height > CBlockIndex::nMedianTimeSpan ? - height - (1 + ((CBlockIndex::nMedianTimeSpan - 1) / 2)) : - height / 2; - double checkpointSpacing = medianHeight > heightLastCheckpoint ? - (double (tipmediantime - timeLastCheckpoint)) / (medianHeight - heightLastCheckpoint) : - (double (timeLastCheckpoint - genesisTime)) / heightLastCheckpoint; - double averageSpacing = (targetSpacing + checkpointSpacing) / 2; - int netheight = medianHeight + ((GetTime() - tipmediantime) / averageSpacing); - // Round to nearest ten to reduce noise - return ((netheight + 5) / 10) * 10; -} + int64_t now = GetAdjustedTime(); -int EstimateNetHeight(int height, int64_t tipmediantime, CChainParams chainParams) -{ - auto checkpointData = chainParams.Checkpoints(); - return EstimateNetHeightInner( - height, tipmediantime, - Checkpoints::GetTotalBlocksEstimate(checkpointData), - checkpointData.nTimeLastCheckpoint, - chainParams.GenesisBlock().nTime, - chainParams.GetConsensus().PoWTargetSpacing(height)); + int estimatedHeight = currentBlockHeight + (now - currentBlockTime) / params.PoWTargetSpacing(currentBlockHeight); + + int blossomActivationHeight = params.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; + if (currentBlockHeight >= blossomActivationHeight || estimatedHeight <= blossomActivationHeight) { + return estimatedHeight; + } + + int numPreBlossomBlocks = blossomActivationHeight - currentBlockHeight; + int64_t preBlossomTime = numPreBlossomBlocks * params.PoWTargetSpacing(blossomActivationHeight - 1); + int64_t blossomActivationTime = currentBlockTime + preBlossomTime; + + return blossomActivationHeight + (now - blossomActivationTime) / params.PoWTargetSpacing(blossomActivationHeight); } void TriggerRefresh() @@ -204,20 +193,20 @@ int printStats(bool mining) int lines = 4; int height; - int64_t tipmediantime; + int64_t time; size_t connections; int64_t netsolps; { LOCK2(cs_main, cs_vNodes); height = chainActive.Height(); - tipmediantime = chainActive.Tip()->GetMedianTimePast(); + time = chainActive.Tip()->GetBlockTime(); connections = vNodes.size(); netsolps = GetNetworkHashPS(120, -1); } auto localsolps = GetLocalSolPS(); if (IsInitialBlockDownload(Params())) { - int netheight = EstimateNetHeight(height, tipmediantime, Params()); + int netheight = EstimateNetHeight(Params().GetConsensus(), height, time); int downloadPercent = height * 100 / netheight; std::cout << " " << _("Downloading blocks") << " | " << height << " / ~" << netheight << " (" << downloadPercent << "%)" << std::endl; } else { diff --git a/src/metrics.h b/src/metrics.h index 2d60d30ca6a..7a99102cb37 100644 --- a/src/metrics.h +++ b/src/metrics.h @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "uint256.h" +#include "consensus/params.h" #include #include @@ -63,9 +64,7 @@ void TrackMinedBlock(uint256 hash); void MarkStartTime(); double GetLocalSolPS(); -int EstimateNetHeightInner(int height, int64_t tipmediantime, - int heightLastCheckpoint, int64_t timeLastCheckpoint, - int64_t genesisTime, int64_t targetSpacing); +int EstimateNetHeight(const Consensus::Params& params, int currentBlockHeight, int64_t currentBlockTime); void TriggerRefresh(); From 65df6225a693fe0c387c41ab3f6a846ac494eb3f Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 2 Aug 2019 16:01:20 -0600 Subject: [PATCH 26/50] Do not create transactions that will expire after the next epoch --- qa/rpc-tests/shorter_block_times.py | 32 +++++++++++++++++++++++++---- src/bitcoin-tx.cpp | 3 ++- src/main.cpp | 24 ++++++++++++---------- src/transaction_builder.cpp | 4 ++++ 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/qa/rpc-tests/shorter_block_times.py b/qa/rpc-tests/shorter_block_times.py index 74857740112..b34882e2621 100755 --- a/qa/rpc-tests/shorter_block_times.py +++ b/qa/rpc-tests/shorter_block_times.py @@ -5,11 +5,14 @@ import sys; assert sys.version_info < (3,), ur"This script does not run under Python 3. Please use Python 2.7.x." +from decimal import Decimal from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, + get_coinbase_address, initialize_chain_clean, start_nodes, + wait_and_assert_operationid_status, ) @@ -18,7 +21,7 @@ def setup_nodes(self): return start_nodes(4, self.options.tmpdir, [[ '-nuparams=5ba81b19:0', # Overwinter '-nuparams=76b809bb:0', # Sapling - '-nuparams=2bb40e60:101', # Blossom + '-nuparams=2bb40e60:103', # Blossom ]] * 4) def setup_chain(self): @@ -27,24 +30,45 @@ def setup_chain(self): def run_test(self): print "Mining blocks..." - self.nodes[0].generate(99) + self.nodes[0].generate(101) self.sync_all() # Sanity-check the block height - assert_equal(self.nodes[0].getblockcount(), 99) + assert_equal(self.nodes[0].getblockcount(), 101) + + # Make sure we can send a transaction on the last pre-Blossom block + node0_taddr = get_coinbase_address(self.nodes[0]) + node0_zaddr = self.nodes[0].z_getnewaddress('sapling') + recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}] + myopid = self.nodes[0].z_sendmany(node0_taddr, recipients, 1, Decimal('0')) + txid = wait_and_assert_operationid_status(self.nodes[0], myopid) + assert_equal(105, self.nodes[0].getrawtransaction(txid, 1)['expiryheight']) # Blossom activation - 1 + 3 + self.sync_all() print "Mining last pre-Blossom block" # Activate blossom self.nodes[1].generate(1) self.sync_all() - assert_equal(10, self.nodes[1].getwalletinfo()['immature_balance']) + # Check that the last pre-Blossom transaction was mined + assert_equal(10, Decimal(self.nodes[0].z_gettotalbalance()['private'])) + # Check that we received a pre-Blossom mining reward + assert_equal(10, Decimal(self.nodes[1].getwalletinfo()['immature_balance'])) # After blossom activation the block reward will be halved print "Mining first Blossom block" self.nodes[1].generate(1) self.sync_all() + # Check that we received an additional Blossom mining reward assert_equal(15, self.nodes[1].getwalletinfo()['immature_balance']) + # Send and mine a transaction after activation + myopid = self.nodes[0].z_sendmany(node0_taddr, recipients, 1, Decimal('0')) + txid = wait_and_assert_operationid_status(self.nodes[0], myopid) + assert_equal(144, self.nodes[0].getrawtransaction(txid, 1)['expiryheight']) # height + 1 + 40 + self.nodes[1].generate(1) + self.sync_all() + assert_equal(20, Decimal(self.nodes[0].z_gettotalbalance()['private'])) + if __name__ == '__main__': ShorterBlockTimes().main() diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 3ee3c01697c..8b7c2ac3543 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -174,7 +174,8 @@ static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal) static void MutateTxExpiry(CMutableTransaction& tx, const std::string& cmdVal) { int64_t newExpiry = atoi64(cmdVal); - if (newExpiry >= TX_EXPIRY_HEIGHT_THRESHOLD) { + // Review: is newExpiry == 0 allowed? Is this coinbase only? + if (newExpiry <= 0 || newExpiry >= TX_EXPIRY_HEIGHT_THRESHOLD) { throw std::runtime_error("Invalid TX expiry requested"); } tx.nExpiryHeight = (int) newExpiry; diff --git a/src/main.cpp b/src/main.cpp index 1537a76b113..970dbe05277 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6658,9 +6658,17 @@ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Para bool isOverwintered = consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_OVERWINTER); if (isOverwintered) { mtx.fOverwintered = true; + if (consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_SAPLING)) { + mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID; + mtx.nVersion = SAPLING_TX_VERSION; + } else { + mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; + mtx.nVersion = OVERWINTER_TX_VERSION; + } + mtx.nExpiryHeight = nHeight + (expiryDeltaArg ? expiryDeltaArg.get() : consensusParams.DefaultExpiryDelta(nHeight)); - // Review: Should the following if() be checking the expiry delta rather than the transaction height? + // Review: is mtx.nExpiryHeight == 0 allowed? Is this coinbase only? if (mtx.nExpiryHeight <= 0 || mtx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { throw new std::runtime_error("CreateNewContextualCMutableTransaction: invalid expiry height"); } @@ -6668,16 +6676,10 @@ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Para // NOTE: If the expiry height crosses into an incompatible consensus epoch, and it is changed to the last block // of the current epoch (see below: Overwinter->Sapling), the transaction will be rejected if it falls within // the expiring soon threshold of 3 blocks (for DoS mitigation) based on the current height. - // TODO: Generalise this code so behaviour applies to all post-Overwinter epochs - if (consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_SAPLING)) { - mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID; - mtx.nVersion = SAPLING_TX_VERSION; - } else { - mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; - mtx.nVersion = OVERWINTER_TX_VERSION; - mtx.nExpiryHeight = std::min( - mtx.nExpiryHeight, - static_cast(consensusParams.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight - 1)); + auto nextActivationHeight = NextActivationHeight(nHeight, consensusParams); + if (nextActivationHeight) { + // We need to add TX_EXPIRING_SOON_THRESHOLD otherwise we cannot send transactions just prior to the next epoch + mtx.nExpiryHeight = std::min(mtx.nExpiryHeight, static_cast(nextActivationHeight.get()) - 1 + TX_EXPIRING_SOON_THRESHOLD); } } return mtx; diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp index f81bcc4debb..b3e6cdb77f9 100644 --- a/src/transaction_builder.cpp +++ b/src/transaction_builder.cpp @@ -79,6 +79,10 @@ struct JSDescException : public std::exception void TransactionBuilder::SetExpiryHeight(uint32_t nExpiryHeight) { mtx.nExpiryHeight = nExpiryHeight; + // Review: is mtx.nExpiryHeight == 0 allowed? Is this coinbase only? + if (mtx.nExpiryHeight <= 0 || mtx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { + throw new std::runtime_error("TransactionBuilder::SetExpiryHeight: invalid expiry height"); + } } void TransactionBuilder::AddSaplingSpend( From e6c0f743aa80e7e0dfa415bed451eb22b2df5716 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 2 Aug 2019 16:12:42 -0600 Subject: [PATCH 27/50] Do not send migration transactions that would expire after a network upgrade --- src/wallet/asyncrpcoperation_saplingmigration.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/wallet/asyncrpcoperation_saplingmigration.cpp b/src/wallet/asyncrpcoperation_saplingmigration.cpp index a8ac453ad51..3bb57fab8b4 100644 --- a/src/wallet/asyncrpcoperation_saplingmigration.cpp +++ b/src/wallet/asyncrpcoperation_saplingmigration.cpp @@ -69,6 +69,14 @@ void AsyncRPCOperation_saplingmigration::main() { bool AsyncRPCOperation_saplingmigration::main_impl() { LogPrint("zrpcunsafe", "%s: Beginning AsyncRPCOperation_saplingmigration.\n", getId()); + auto consensusParams = Params().GetConsensus(); + auto nextActivationHeight = NextActivationHeight(targetHeight_, consensusParams); + if (nextActivationHeight && targetHeight_ + MIGRATION_EXPIRY_DELTA >= nextActivationHeight.get()) { + LogPrint("zrpcunsafe", "%s: Migration txs would be created before a NU activation but may expire after. Skipping this round.\n", getId()); + setMigrationResult(0, 0, std::vector()); + return true; + } + std::vector sproutEntries; std::vector saplingEntries; { @@ -93,7 +101,6 @@ bool AsyncRPCOperation_saplingmigration::main_impl() { HDSeed seed = pwalletMain->GetHDSeedForRPC(); libzcash::SaplingPaymentAddress migrationDestAddress = getMigrationDestAddress(seed); - auto consensusParams = Params().GetConsensus(); // Up to the limit of 5, as many transactions are sent as are needed to migrate the remaining funds int numTxCreated = 0; From 27ee4d64f270a24fcd3526562436ebcb2059da4f Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 2 Aug 2019 19:35:53 -0600 Subject: [PATCH 28/50] Fix integer truncation in Blossom halving calculation --- src/main.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 970dbe05277..fbdbf980ee8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1770,8 +1770,15 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) int halvings; if (blossomActive) { int blossomActivationHeight = consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; - halvings = (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval - + (nHeight - blossomActivationHeight) / consensusParams.nPostBlossomSubsidyHalvingInterval; + // // Ideally we would say: + // halvings = (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval + // + (nHeight - blossomActivationHeight) / consensusParams.nPostBlossomSubsidyHalvingInterval; + // But, (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval + // needs to be a treated rational number or this does not work. + // Define scaledHalvings := halvings * consensusParams.nPreBlossomSubsidyHalvingInterval; + int scaledHalvings = (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) + + (nHeight - blossomActivationHeight) / Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO; + halvings = scaledHalvings / consensusParams.nPreBlossomSubsidyHalvingInterval; } else { halvings = (nHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval; } From 797713284c52d6fb8c1a43a4c38f56255c3feaee Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 2 Aug 2019 19:37:02 -0600 Subject: [PATCH 29/50] Update main_tests for shorter block times --- src/test/main_tests.cpp | 83 ++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp index b731e89131e..8af388473c3 100644 --- a/src/test/main_tests.cpp +++ b/src/test/main_tests.cpp @@ -10,78 +10,101 @@ #include #include + BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup) +const CAmount INITIAL_SUBSIDY = 12.5 * COIN; + +static int GetTotalHalvings(const Consensus::Params& consensusParams) { + return consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight == Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT ? 64 : 65; +} + static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams) { - int maxHalvings = 64; - CAmount nInitialSubsidy = 12.5 * COIN; - - CAmount nPreviousSubsidy = nInitialSubsidy * 2; // for height == 0 - BOOST_CHECK_EQUAL(nPreviousSubsidy, nInitialSubsidy * 2); - for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) { - int nHeight; - if (nHalvings > 0) // Check subsidy right at halvings + bool blossomActive = false; + int blossomActivationHeight = consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; + int nHeight = consensusParams.nSubsidySlowStartInterval; + BOOST_CHECK_EQUAL(GetBlockSubsidy(nHeight, consensusParams), INITIAL_SUBSIDY); + CAmount nPreviousSubsidy = INITIAL_SUBSIDY; + for (int nHalvings = 1; nHalvings < GetTotalHalvings(consensusParams); nHalvings++) { + if (blossomActive) { + if (nHeight == blossomActivationHeight) { + int preBlossomHeight = (nHalvings - 1) * consensusParams.nPreBlossomSubsidyHalvingInterval + consensusParams.SubsidySlowStartShift(); + nHeight += (preBlossomHeight - blossomActivationHeight) * Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO; + } else { + nHeight += consensusParams.nPostBlossomSubsidyHalvingInterval; + } + } else { nHeight = nHalvings * consensusParams.nPreBlossomSubsidyHalvingInterval + consensusParams.SubsidySlowStartShift(); - else // Check subsidy just after end of slow start - nHeight = consensusParams.nSubsidySlowStartInterval; + if (consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM)) { + nHeight = blossomActivationHeight; + blossomActive = true; + } + } + BOOST_CHECK_EQUAL(GetBlockSubsidy(nHeight - 1, consensusParams), nPreviousSubsidy); CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams); - BOOST_CHECK(nSubsidy <= nInitialSubsidy); + BOOST_CHECK(nSubsidy <= INITIAL_SUBSIDY); BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2); nPreviousSubsidy = nSubsidy; } - BOOST_CHECK_EQUAL(GetBlockSubsidy((maxHalvings * consensusParams.nPreBlossomSubsidyHalvingInterval) + consensusParams.SubsidySlowStartShift(), consensusParams), 0); + BOOST_CHECK_EQUAL(GetBlockSubsidy(nHeight, consensusParams), 0); } -static void TestBlockSubsidyHalvings(int nSubsidySlowStartInterval, int nPreBlossomSubsidyHalvingInterval) +static void TestBlockSubsidyHalvings(int nSubsidySlowStartInterval, int nPreBlossomSubsidyHalvingInterval, int blossomActivationHeight) { Consensus::Params consensusParams; consensusParams.nSubsidySlowStartInterval = nSubsidySlowStartInterval; consensusParams.nPreBlossomSubsidyHalvingInterval = nPreBlossomSubsidyHalvingInterval; + consensusParams.nPostBlossomSubsidyHalvingInterval = nPreBlossomSubsidyHalvingInterval * 2; + consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight = blossomActivationHeight; TestBlockSubsidyHalvings(consensusParams); } BOOST_AUTO_TEST_CASE(block_subsidy_test) { TestBlockSubsidyHalvings(Params(CBaseChainParams::MAIN).GetConsensus()); // As in main - TestBlockSubsidyHalvings(50, 150); // As in regtest - TestBlockSubsidyHalvings(500, 1000); // Just another interval + TestBlockSubsidyHalvings(20000, Consensus::PRE_BLOSSOM_HALVING_INTERVAL, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); // Pre-Blossom + TestBlockSubsidyHalvings(50, 150, 80); // As in regtest + TestBlockSubsidyHalvings(500, 1000, 900); // Just another interval + TestBlockSubsidyHalvings(500, 1000, 3000); // Multiple halvings before activation } BOOST_AUTO_TEST_CASE(subsidy_limit_test) { const Consensus::Params& consensusParams = Params(CBaseChainParams::MAIN).GetConsensus(); + CAmount nSum = 0; + int nHeight = 0; // Mining slow start - for (int nHeight = 0; nHeight < consensusParams.nSubsidySlowStartInterval; nHeight ++) { + for (; nHeight < consensusParams.nSubsidySlowStartInterval; nHeight++) { CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams); BOOST_CHECK(nSubsidy <= 12.5 * COIN); nSum += nSubsidy; BOOST_CHECK(MoneyRange(nSum)); } BOOST_CHECK_EQUAL(nSum, 12500000000000ULL); - // Remainder of first period - for (int nHeight = consensusParams.nSubsidySlowStartInterval; nHeight < consensusParams.nPreBlossomSubsidyHalvingInterval + consensusParams.SubsidySlowStartShift(); nHeight ++) { - CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams); - BOOST_CHECK(nSubsidy <= 12.5 * COIN); - nSum += nSubsidy; - BOOST_CHECK(MoneyRange(nSum)); - } - BOOST_CHECK_EQUAL(nSum, 1050000000000000ULL); + // Regular mining - for (int nHeight = consensusParams.nPreBlossomSubsidyHalvingInterval + consensusParams.SubsidySlowStartShift(); nHeight < 56000000; nHeight += 1000) { - CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams); - BOOST_CHECK(nSubsidy <= 12.5 * COIN); - nSum += nSubsidy * 1000; - BOOST_CHECK(MoneyRange(nSum)); - } + CAmount nSubsidy; + do { + nSubsidy = GetBlockSubsidy(nHeight, consensusParams); + nSum += nSubsidy; + BOOST_ASSERT(MoneyRange(nSum)); + ++nHeight; + } while (nSubsidy > 0); + // Changing the block interval from 10 to 2.5 minutes causes truncation // effects to occur earlier (from the 9th halving interval instead of the // 11th), decreasing the total monetary supply by 0.0693 ZEC. If the // transaction output field is widened, this discrepancy will become smaller // or disappear entirely. //BOOST_CHECK_EQUAL(nSum, 2099999997690000ULL); + // Reducing the interval further to 1.25 minutes has a similar effect, + // decreasing the total monetary supply by another 0.09240 ZEC. + // TODO Change this assert when setting the blossom activation height + // Note that these numbers may or may not change depending on the activation height BOOST_CHECK_EQUAL(nSum, 2099999990760000ULL); + // BOOST_CHECK_EQUAL(nSum, 2099999981520000LL); } bool ReturnFalse() { return false; } From 3eb90d4040f21259672961df777d6e6a9daa7a9d Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 2 Aug 2019 20:53:41 -0600 Subject: [PATCH 30/50] Use pre-Blossom max FR height when calculating address change interval --- src/chainparams.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 50af3616baf..82d60af3182 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -571,7 +571,7 @@ bool SelectParamsFromCommandLine() // Block height must be >0 and <=last founders reward block height // Index variable i ranges from 0 - (vFoundersRewardAddress.size()-1) std::string CChainParams::GetFoundersRewardAddressAtHeight(int nHeight) const { - int maxHeight = consensus.GetLastFoundersRewardBlockHeight(nHeight); + int preBlossomMaxHeight = consensus.GetLastFoundersRewardBlockHeight(0); // zip208 // FounderAddressAdjustedHeight(height) := // height, if not IsBlossomActivated(height) @@ -581,9 +581,8 @@ std::string CChainParams::GetFoundersRewardAddressAtHeight(int nHeight) const { int blossomActivationHeight = consensus.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; nHeight = blossomActivationHeight + ((nHeight - blossomActivationHeight) / Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO); } - assert(nHeight > 0 && nHeight <= maxHeight); - - size_t addressChangeInterval = (maxHeight + vFoundersRewardAddress.size()) / vFoundersRewardAddress.size(); + assert(nHeight > 0 && nHeight <= preBlossomMaxHeight); + size_t addressChangeInterval = (preBlossomMaxHeight + vFoundersRewardAddress.size()) / vFoundersRewardAddress.size(); size_t i = nHeight / addressChangeInterval; return vFoundersRewardAddress[i]; } From 93452c97bfad8c8c475b99850cce55f96d880f48 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 2 Aug 2019 20:54:52 -0600 Subject: [PATCH 31/50] Make founders reward tests pass before and after Blossom activation height is set --- src/gtest/test_foundersreward.cpp | 37 +++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/gtest/test_foundersreward.cpp b/src/gtest/test_foundersreward.cpp index 1f4f8241125..726129b66cb 100644 --- a/src/gtest/test_foundersreward.cpp +++ b/src/gtest/test_foundersreward.cpp @@ -84,14 +84,19 @@ TEST(founders_reward_test, create_testnet_2of3multisig) { #endif +static int GetLastFoundersRewardHeight(const Consensus::Params& params){ + int blossomActivationHeight = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; + bool blossom = blossomActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + return params.GetLastFoundersRewardBlockHeight(blossom ? blossomActivationHeight : 0); +} + // Utility method to check the number of unique addresses from height 1 to maxHeight void checkNumberOfUniqueAddresses(int nUnique) { - int maxHeight = Params().GetConsensus().GetLastFoundersRewardBlockHeight(0); std::set addresses; - for (int i = 1; i <= maxHeight; i++) { + for (int i = 1; i <= GetLastFoundersRewardHeight(Params().GetConsensus()); i++) { addresses.insert(Params().GetFoundersRewardAddressAtHeight(i)); } - ASSERT_TRUE(addresses.size() == nUnique); + EXPECT_EQ(addresses.size(), nUnique); } @@ -157,11 +162,14 @@ TEST(founders_reward_test, regtest) { // Test that 10% founders reward is fully rewarded after the first halving and slow start shift. // On Mainnet, this would be 2,100,000 ZEC after 850,000 blocks (840,000 + 10,000). -TEST(founders_reward_test, slow_start_subsidy) { // TODO: Update this test when the Blossom activation height is set +TEST(founders_reward_test, slow_start_subsidy) { SelectParams(CBaseChainParams::MAIN); CChainParams params = Params(); - int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(0); + int blossomActivationHeight = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; + bool blossom = blossomActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; + int maxHeight = Params().GetConsensus().GetLastFoundersRewardBlockHeight(blossom ? blossomActivationHeight : 0); + CAmount totalSubsidy = 0; for (int nHeight = 1; nHeight <= maxHeight; nHeight++) { CAmount nSubsidy = GetBlockSubsidy(nHeight, params.GetConsensus()) / 5; @@ -176,17 +184,22 @@ TEST(founders_reward_test, slow_start_subsidy) { // TODO: Update this test when // Verify the number of rewards each individual address receives. void verifyNumberOfRewards() { CChainParams params = Params(); - int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(0); - std::multiset ms; + int maxHeight = GetLastFoundersRewardHeight(params.GetConsensus()); + std::map ms; for (int nHeight = 1; nHeight <= maxHeight; nHeight++) { - ms.insert(params.GetFoundersRewardAddressAtHeight(nHeight)); + std::string addr = params.GetFoundersRewardAddressAtHeight(nHeight); + if (ms.count(addr) == 0) { + ms[addr] = 0; + } + ms[addr] = ms[addr] + GetBlockSubsidy(nHeight, params.GetConsensus()) / 5; } - ASSERT_TRUE(ms.count(params.GetFoundersRewardAddressAtIndex(0)) == 17708); - for (int i = 1; i <= 46; i++) { - ASSERT_TRUE(ms.count(params.GetFoundersRewardAddressAtIndex(i)) == 17709); + EXPECT_EQ(ms[params.GetFoundersRewardAddressAtIndex(0)], 1960039937500); + EXPECT_EQ(ms[params.GetFoundersRewardAddressAtIndex(1)], 4394460062500); + for (int i = 2; i <= 46; i++) { + EXPECT_EQ(ms[params.GetFoundersRewardAddressAtIndex(i)], 17709 * COIN * 2.5); } - ASSERT_TRUE(ms.count(params.GetFoundersRewardAddressAtIndex(47)) == 17677); + EXPECT_EQ(ms[params.GetFoundersRewardAddressAtIndex(47)], 17677 * COIN * 2.5); } // Verify the number of rewards going to each mainnet address From f9d6b3e7ef58e238506ea572b34f75b4ef34ba92 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 2 Aug 2019 21:37:48 -0600 Subject: [PATCH 32/50] Extract Halvings method and add tests --- src/consensus/params.cpp | 21 +++++++++++++++++++++ src/consensus/params.h | 2 ++ src/gtest/test_foundersreward.cpp | 20 +++++++++++++------- src/main.cpp | 23 ++--------------------- 4 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp index 35cc6c9d24e..08bd3f72236 100644 --- a/src/consensus/params.cpp +++ b/src/consensus/params.cpp @@ -8,6 +8,27 @@ namespace Consensus { return NetworkUpgradeState(nHeight, *this, idx) == UPGRADE_ACTIVE; } + int Params::Halvings(int nHeight) const { + // zip208 + // Halving(height) := + // floor((height - SlowStartShift) / PreBlossomHalvingInterval), if not IsBlossomActivated(height) + // floor((BlossomActivationHeight - SlowStartShift) / PreBlossomHalvingInterval + (height - BlossomActivationHeight) / PostBlossomHalvingInterval), otherwise + if (NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM)) { + int blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; + // // Ideally we would say: + // halvings = (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval + // + (nHeight - blossomActivationHeight) / consensusParams.nPostBlossomSubsidyHalvingInterval; + // But, (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval + // needs to be a treated rational number or this does not work. + // Define scaledHalvings := halvings * consensusParams.nPreBlossomSubsidyHalvingInterval; + int scaledHalvings = (blossomActivationHeight - SubsidySlowStartShift()) + + (nHeight - blossomActivationHeight) / Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO; + return scaledHalvings / nPreBlossomSubsidyHalvingInterval; + } else { + return (nHeight - SubsidySlowStartShift()) / nPreBlossomSubsidyHalvingInterval; + } + } + int Params::GetLastFoundersRewardBlockHeight(int nHeight) const { // zip208 // FoundersRewardLastBlockHeight := max({ height ⦂ N | Halving(height) < 1 }) diff --git a/src/consensus/params.h b/src/consensus/params.h index 979d294bff6..8644b087f26 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -103,6 +103,8 @@ struct Params { int nPreBlossomSubsidyHalvingInterval; int nPostBlossomSubsidyHalvingInterval; + int Halvings(int nHeight) const; + int GetLastFoundersRewardBlockHeight(int nHeight) const; unsigned int DefaultExpiryDelta(int nHeight) const; diff --git a/src/gtest/test_foundersreward.cpp b/src/gtest/test_foundersreward.cpp index 726129b66cb..3b745647995 100644 --- a/src/gtest/test_foundersreward.cpp +++ b/src/gtest/test_foundersreward.cpp @@ -125,14 +125,20 @@ TEST(founders_reward_test, general) { EXPECT_DEATH(params.GetFoundersRewardAddressAtHeight(maxHeight+1), "nHeight"); } -TEST(founders_reward_test, get_last_block_blossom) { - int blossomActivationHeight = /*slowStartShift*/ + Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL / 2; // = 75 +TEST(founders_reward_test, regtest_get_last_block_blossom) { + int blossomActivationHeight = Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL / 2; // = 75 auto params = RegtestActivateBlossom(false, blossomActivationHeight); - int slowStartShift = params.SubsidySlowStartShift(); // 0 for regtest - EXPECT_EQ(Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL + slowStartShift - 1, params.GetLastFoundersRewardBlockHeight(0)); - EXPECT_EQ(Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL + slowStartShift - 1, params.GetLastFoundersRewardBlockHeight(blossomActivationHeight - 1)); - int blossomBlocks = (Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL- blossomActivationHeight) * Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO; - EXPECT_EQ(blossomActivationHeight + blossomBlocks + slowStartShift - 1, params.GetLastFoundersRewardBlockHeight(blossomActivationHeight)); + int lastFRHeight = params.GetLastFoundersRewardBlockHeight(blossomActivationHeight); + EXPECT_EQ(0, params.Halvings(lastFRHeight)); + EXPECT_EQ(1, params.Halvings(lastFRHeight + 1)); +} + +TEST(founders_reward_test, mainnet_get_last_block) { + SelectParams(CBaseChainParams::MAIN); + auto params = Params().GetConsensus(); + int lastFRHeight = GetLastFoundersRewardHeight(params); + EXPECT_EQ(0, params.Halvings(lastFRHeight)); + EXPECT_EQ(1, params.Halvings(lastFRHeight + 1)); } #define NUM_MAINNET_FOUNDER_ADDRESSES 48 diff --git a/src/main.cpp b/src/main.cpp index fbdbf980ee8..01478ce976c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1762,26 +1762,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) assert(nHeight > consensusParams.SubsidySlowStartShift()); - // zip208 - // Halving(height) := - // floor((height - SlowStartShift) / PreBlossomHalvingInterval), if not IsBlossomActivated(height) - // floor((BlossomActivationHeight - SlowStartShift) / PreBlossomHalvingInterval + (height - BlossomActivationHeight) / PostBlossomHalvingInterval), otherwise - bool blossomActive = consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM); - int halvings; - if (blossomActive) { - int blossomActivationHeight = consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; - // // Ideally we would say: - // halvings = (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval - // + (nHeight - blossomActivationHeight) / consensusParams.nPostBlossomSubsidyHalvingInterval; - // But, (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval - // needs to be a treated rational number or this does not work. - // Define scaledHalvings := halvings * consensusParams.nPreBlossomSubsidyHalvingInterval; - int scaledHalvings = (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) - + (nHeight - blossomActivationHeight) / Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO; - halvings = scaledHalvings / consensusParams.nPreBlossomSubsidyHalvingInterval; - } else { - halvings = (nHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval; - } + int halvings = consensusParams.Halvings(nHeight); // Force block reward to zero when right shift is undefined. if (halvings >= 64) @@ -1793,7 +1774,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) // SlowStartRate · (height + 1), if SlowStartInterval / 2 ≤ height and height < SlowStartInterval // floor(MaxBlockSubsidy / 2^Halving(height)), if SlowStartInterval ≤ height and not IsBlossomActivated(height) // floor(MaxBlockSubsidy / (BlossomPoWTargetSpacingRatio · 2^Halving(height))), otherwise - if (blossomActive) { + if (consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM)) { return (nSubsidy / Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO) >> halvings; } else { // Subsidy is cut in half every 840,000 blocks which will occur approximately every 4 years. From 297252132345525bc668ecd2e63022ade49ea917 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 2 Aug 2019 21:43:17 -0600 Subject: [PATCH 33/50] Add comments and fix typos --- src/consensus/params.cpp | 6 +++++- src/gtest/test_pow.cpp | 6 +++--- src/test/alert_tests.cpp | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp index 08bd3f72236..553e5451db3 100644 --- a/src/consensus/params.cpp +++ b/src/consensus/params.cpp @@ -29,9 +29,12 @@ namespace Consensus { } } - int Params::GetLastFoundersRewardBlockHeight(int nHeight) const { + int Params::GetLastFoundersRewardBlockHeight(int nHeight) const { // zip208 // FoundersRewardLastBlockHeight := max({ height ⦂ N | Halving(height) < 1 }) + // Halving(h) is defined as floor(f(h)) where f is a strictly increasing rational + // function, so it's sufficient to solve for f(height) = 1 in the rationals and + // then take ceiling(height - 1). // H := blossom activation height; SS := SubsidySlowStartShift(); R := BLOSSOM_POW_TARGET_SPACING_RATIO // preBlossom: // 1 = (height - SS) / preInterval @@ -43,6 +46,7 @@ namespace Consensus { bool blossomActive = NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM); if (blossomActive) { int blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; + // The following calculation depends on BLOSSOM_POW_TARGET_SPACING_RATIO being an integer. return blossomActivationHeight + nPostBlossomSubsidyHalvingInterval + (SubsidySlowStartShift() - blossomActivationHeight) * BLOSSOM_POW_TARGET_SPACING_RATIO - 1; } else { diff --git a/src/gtest/test_pow.cpp b/src/gtest/test_pow.cpp index 4e0e8fcdc5c..709296f7802 100644 --- a/src/gtest/test_pow.cpp +++ b/src/gtest/test_pow.cpp @@ -6,7 +6,7 @@ #include "random.h" #include "utiltest.h" -void TestDifficultyAveragigingImpl(const Consensus::Params& params) +void TestDifficultyAveragingImpl(const Consensus::Params& params) { size_t lastBlk = 2*params.nPowAveragingWindow; size_t firstBlk = lastBlk - params.nPowAveragingWindow; @@ -75,11 +75,11 @@ void TestDifficultyAveragigingImpl(const Consensus::Params& params) TEST(PoW, DifficultyAveraging) { SelectParams(CBaseChainParams::MAIN); - TestDifficultyAveragigingImpl(Params().GetConsensus()); + TestDifficultyAveragingImpl(Params().GetConsensus()); } TEST(PoW, DifficultyAveragingBlossom) { - TestDifficultyAveragigingImpl(RegtestActivateBlossom(true)); + TestDifficultyAveragingImpl(RegtestActivateBlossom(true)); RegtestDeactivateBlossom(); } diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index 83e966cda94..c8ecbd58dde 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -465,7 +465,7 @@ BOOST_AUTO_TEST_CASE(PartitionAlertBlossomActivates) { // 48 pre blossom blocks, 96 blossom blocks will take 48 * 150s + 96 * 75s = 4hrs // in the slow case, all of the blocks will be blossom blocks - // in the fast case, 96 blocks will be blossom => 96 * 75s * 2/5 = 2880s spent on on blossom + // in the fast case, 96 blocks will be blossom => 96 * 75s * 2/5 = 2880s spent on blossom // => (14400 - 2880) / (150 * 2/5) = 11520 / 60 = 192 pre blossom blocks PartitionAlertTestImpl(RegtestActivateBlossom(false, 799 - 96), 2000000000, 144, 12 * 2, 192 + 96); RegtestDeactivateBlossom(); From bde2e4807c8b577e99c480e66047b208aa613f9c Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 2 Aug 2019 22:51:21 -0600 Subject: [PATCH 34/50] Improve EstimateNetHeight calculation --- src/metrics.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index 40cc06260aa..e6390572662 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -112,6 +112,9 @@ double GetLocalSolPS() int EstimateNetHeight(const Consensus::Params& params, int currentBlockHeight, int64_t currentBlockTime) { int64_t now = GetAdjustedTime(); + if (currentBlockTime >= now) { + return currentBlockHeight; + } int estimatedHeight = currentBlockHeight + (now - currentBlockTime) / params.PoWTargetSpacing(currentBlockHeight); @@ -123,6 +126,9 @@ int EstimateNetHeight(const Consensus::Params& params, int currentBlockHeight, i int numPreBlossomBlocks = blossomActivationHeight - currentBlockHeight; int64_t preBlossomTime = numPreBlossomBlocks * params.PoWTargetSpacing(blossomActivationHeight - 1); int64_t blossomActivationTime = currentBlockTime + preBlossomTime; + if (blossomActivationTime >= now) { + return blossomActivationHeight; + } return blossomActivationHeight + (now - blossomActivationTime) / params.PoWTargetSpacing(blossomActivationHeight); } @@ -193,20 +199,20 @@ int printStats(bool mining) int lines = 4; int height; - int64_t time; + int64_t blockTime; size_t connections; int64_t netsolps; { LOCK2(cs_main, cs_vNodes); - height = chainActive.Height(); - time = chainActive.Tip()->GetBlockTime(); + height = pindexBestHeader->nHeight; + blockTime = pindexBestHeader->nTime; connections = vNodes.size(); netsolps = GetNetworkHashPS(120, -1); } auto localsolps = GetLocalSolPS(); if (IsInitialBlockDownload(Params())) { - int netheight = EstimateNetHeight(Params().GetConsensus(), height, time); + int netheight = EstimateNetHeight(Params().GetConsensus(), height, blockTime); int downloadPercent = height * 100 / netheight; std::cout << " " << _("Downloading blocks") << " | " << height << " / ~" << netheight << " (" << downloadPercent << "%)" << std::endl; } else { From 8068491d2c5e813ecaaf50f4eefd6501795fad2d Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Sun, 4 Aug 2019 14:35:47 -0600 Subject: [PATCH 35/50] Fix check transaction tests --- src/gtest/test_checktransaction.cpp | 113 ++++++++++------------------ src/main.cpp | 2 + 2 files changed, 42 insertions(+), 73 deletions(-) diff --git a/src/gtest/test_checktransaction.cpp b/src/gtest/test_checktransaction.cpp index 7e6eb9a84a5..3f4b7b0a8ff 100644 --- a/src/gtest/test_checktransaction.cpp +++ b/src/gtest/test_checktransaction.cpp @@ -694,7 +694,7 @@ TEST(checktransaction_tests, OverwinterExpiryHeight) { TEST(checktransaction_tests, BlossomExpiryHeight) { const Consensus::Params& params = RegtestActivateBlossom(false, 100); CMutableTransaction preBlossomMtx = CreateNewContextualCMutableTransaction(params, 99); - EXPECT_EQ(preBlossomMtx.nExpiryHeight, 99 + 20); + EXPECT_EQ(preBlossomMtx.nExpiryHeight, 100 - 1 + TX_EXPIRING_SOON_THRESHOLD); CMutableTransaction blossomMtx = CreateNewContextualCMutableTransaction(params, 100); EXPECT_EQ(blossomMtx.nExpiryHeight, 100 + 40); RegtestDeactivateBlossom(); @@ -891,89 +891,56 @@ TEST(checktransaction_tests, OverwinterInvalidSoftForkVersion) { } } +static void ContextualCreateTxCheck(const Consensus::Params& params, int nHeight, + int expectedVersion, bool expectedOverwintered, int expectedVersionGroupId, int expectedExpiryHeight) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(params, nHeight); + EXPECT_EQ(mtx.nVersion, expectedVersion); + EXPECT_EQ(mtx.fOverwintered, expectedOverwintered); + EXPECT_EQ(mtx.nVersionGroupId, expectedVersionGroupId); + EXPECT_EQ(mtx.nExpiryHeight, expectedExpiryHeight); +} + // Test CreateNewContextualCMutableTransaction sets default values based on height TEST(checktransaction_tests, OverwinteredContextualCreateTx) { SelectParams(CBaseChainParams::REGTEST); - const Consensus::Params& consensusParams = Params().GetConsensus(); - int activationHeight = 5; + const Consensus::Params& params = Params().GetConsensus(); + int overwinterActivationHeight = 5; int saplingActivationHeight = 30; - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, activationHeight); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, overwinterActivationHeight); UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, saplingActivationHeight); - { - CMutableTransaction mtx = CreateNewContextualCMutableTransaction( - consensusParams, activationHeight - 1); - - EXPECT_EQ(mtx.nVersion, 1); - EXPECT_EQ(mtx.fOverwintered, false); - EXPECT_EQ(mtx.nVersionGroupId, 0); - EXPECT_EQ(mtx.nExpiryHeight, 0); - } - + ContextualCreateTxCheck(params, overwinterActivationHeight - 1, + 1, false, 0, 0); // Overwinter activates - { - CMutableTransaction mtx = CreateNewContextualCMutableTransaction( - consensusParams, activationHeight); - - EXPECT_EQ(mtx.nVersion, 3); - EXPECT_EQ(mtx.fOverwintered, true); - EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); - EXPECT_EQ(mtx.nExpiryHeight, activationHeight + DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA); - } - + ContextualCreateTxCheck(params, overwinterActivationHeight, + 3, true, OVERWINTER_VERSION_GROUP_ID, overwinterActivationHeight + DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA); // Close to Sapling activation - { - CMutableTransaction mtx = CreateNewContextualCMutableTransaction( - consensusParams, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA - 2); - - EXPECT_EQ(mtx.fOverwintered, true); - EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); - EXPECT_EQ(mtx.nVersion, OVERWINTER_TX_VERSION); - EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight - 2); - } - - { - CMutableTransaction mtx = CreateNewContextualCMutableTransaction( - consensusParams, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA - 1); - - EXPECT_EQ(mtx.fOverwintered, true); - EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); - EXPECT_EQ(mtx.nVersion, OVERWINTER_TX_VERSION); - EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight - 1); - } - - { - CMutableTransaction mtx = CreateNewContextualCMutableTransaction( - consensusParams, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA); - - EXPECT_EQ(mtx.fOverwintered, true); - EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); - EXPECT_EQ(mtx.nVersion, OVERWINTER_TX_VERSION); - EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight - 1); - } - + ContextualCreateTxCheck(params, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA - 2, + 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 2); + ContextualCreateTxCheck(params, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA - 1, + 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1); + ContextualCreateTxCheck(params, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA, + 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight); + ContextualCreateTxCheck(params, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA + 1, + 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight + 1); + ContextualCreateTxCheck(params, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA + 2, + 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight + 2); + ContextualCreateTxCheck(params, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA + 3, + 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1 + TX_EXPIRING_SOON_THRESHOLD); // Just before Sapling activation - { - CMutableTransaction mtx = CreateNewContextualCMutableTransaction( - consensusParams, saplingActivationHeight - 1); - - EXPECT_EQ(mtx.fOverwintered, true); - EXPECT_EQ(mtx.nVersionGroupId, OVERWINTER_VERSION_GROUP_ID); - EXPECT_EQ(mtx.nVersion, OVERWINTER_TX_VERSION); - EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight - 1); - } - + ContextualCreateTxCheck(params, saplingActivationHeight - 4, + 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1 + TX_EXPIRING_SOON_THRESHOLD); + ContextualCreateTxCheck(params, saplingActivationHeight - 3, + 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1 + TX_EXPIRING_SOON_THRESHOLD); + ContextualCreateTxCheck(params, saplingActivationHeight - 2, + 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1 + TX_EXPIRING_SOON_THRESHOLD); + ContextualCreateTxCheck(params, saplingActivationHeight - 1, + 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1 + TX_EXPIRING_SOON_THRESHOLD); // Sapling activates - { - CMutableTransaction mtx = CreateNewContextualCMutableTransaction( - consensusParams, saplingActivationHeight); - - EXPECT_EQ(mtx.fOverwintered, true); - EXPECT_EQ(mtx.nVersionGroupId, SAPLING_VERSION_GROUP_ID); - EXPECT_EQ(mtx.nVersion, SAPLING_TX_VERSION); - EXPECT_EQ(mtx.nExpiryHeight, saplingActivationHeight + DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA); - } + ContextualCreateTxCheck(params, saplingActivationHeight, + SAPLING_TX_VERSION, true, SAPLING_VERSION_GROUP_ID, saplingActivationHeight + DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA); // Revert to default RegtestDeactivateSapling(); diff --git a/src/main.cpp b/src/main.cpp index 01478ce976c..1e6ce458ac5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6667,6 +6667,8 @@ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Para auto nextActivationHeight = NextActivationHeight(nHeight, consensusParams); if (nextActivationHeight) { // We need to add TX_EXPIRING_SOON_THRESHOLD otherwise we cannot send transactions just prior to the next epoch + // The idea is that the transaction will not be rejected as expiring soon until the same block that it is + // The rejected for being created during the last epoch. mtx.nExpiryHeight = std::min(mtx.nExpiryHeight, static_cast(nextActivationHeight.get()) - 1 + TX_EXPIRING_SOON_THRESHOLD); } } From 2c35e162a60bca6f44360f776e5a3f9158808c37 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Sun, 4 Aug 2019 17:03:48 -0600 Subject: [PATCH 36/50] Make sure to deactivate blossom in test case --- src/gtest/test_foundersreward.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gtest/test_foundersreward.cpp b/src/gtest/test_foundersreward.cpp index 3b745647995..d4b45a15716 100644 --- a/src/gtest/test_foundersreward.cpp +++ b/src/gtest/test_foundersreward.cpp @@ -131,6 +131,7 @@ TEST(founders_reward_test, regtest_get_last_block_blossom) { int lastFRHeight = params.GetLastFoundersRewardBlockHeight(blossomActivationHeight); EXPECT_EQ(0, params.Halvings(lastFRHeight)); EXPECT_EQ(1, params.Halvings(lastFRHeight + 1)); + RegtestDeactivateBlossom(); } TEST(founders_reward_test, mainnet_get_last_block) { From 82c291b6df2e3d9999c1c6b88db7d3df84bca5e4 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Sun, 4 Aug 2019 17:11:31 -0600 Subject: [PATCH 37/50] Fix parsing txexpirydelta argument --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index a1f5c30e30d..c9ebe0617fd 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1066,7 +1066,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); if (mapArgs.count("-txexpirydelta")) { - int64_t expiryDelta = atoi64(mapArgs["txexpirydelta"]); + int64_t expiryDelta = atoi64(mapArgs["-txexpirydelta"]); uint32_t minExpiryDelta = TX_EXPIRING_SOON_THRESHOLD + 1; if (expiryDelta < minExpiryDelta) { return InitError(strprintf(_("Invalid value for -txexpirydelta='%u' (must be least %u)"), expiryDelta, minExpiryDelta)); From 9f70b7469241aaa88f10e36c232bf5780cd39cb2 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 5 Aug 2019 11:50:05 -0600 Subject: [PATCH 38/50] Do not add expiring soon threshold to expiry height of txs near NU activation --- src/gtest/test_checktransaction.cpp | 24 ++++++++++++------------ src/main.cpp | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/gtest/test_checktransaction.cpp b/src/gtest/test_checktransaction.cpp index 3f4b7b0a8ff..762686ef589 100644 --- a/src/gtest/test_checktransaction.cpp +++ b/src/gtest/test_checktransaction.cpp @@ -694,7 +694,7 @@ TEST(checktransaction_tests, OverwinterExpiryHeight) { TEST(checktransaction_tests, BlossomExpiryHeight) { const Consensus::Params& params = RegtestActivateBlossom(false, 100); CMutableTransaction preBlossomMtx = CreateNewContextualCMutableTransaction(params, 99); - EXPECT_EQ(preBlossomMtx.nExpiryHeight, 100 - 1 + TX_EXPIRING_SOON_THRESHOLD); + EXPECT_EQ(preBlossomMtx.nExpiryHeight, 100 - 1); CMutableTransaction blossomMtx = CreateNewContextualCMutableTransaction(params, 100); EXPECT_EQ(blossomMtx.nExpiryHeight, 100 + 40); RegtestDeactivateBlossom(); @@ -915,29 +915,29 @@ TEST(checktransaction_tests, OverwinteredContextualCreateTx) { 1, false, 0, 0); // Overwinter activates ContextualCreateTxCheck(params, overwinterActivationHeight, - 3, true, OVERWINTER_VERSION_GROUP_ID, overwinterActivationHeight + DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA); + OVERWINTER_TX_VERSION, true, OVERWINTER_VERSION_GROUP_ID, overwinterActivationHeight + DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA); // Close to Sapling activation ContextualCreateTxCheck(params, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA - 2, - 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 2); + OVERWINTER_TX_VERSION, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 2); ContextualCreateTxCheck(params, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA - 1, - 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1); + OVERWINTER_TX_VERSION, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1); ContextualCreateTxCheck(params, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA, - 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight); + OVERWINTER_TX_VERSION, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1); ContextualCreateTxCheck(params, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA + 1, - 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight + 1); + OVERWINTER_TX_VERSION, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1); ContextualCreateTxCheck(params, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA + 2, - 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight + 2); + OVERWINTER_TX_VERSION, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1); ContextualCreateTxCheck(params, saplingActivationHeight - DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA + 3, - 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1 + TX_EXPIRING_SOON_THRESHOLD); + OVERWINTER_TX_VERSION, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1); // Just before Sapling activation ContextualCreateTxCheck(params, saplingActivationHeight - 4, - 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1 + TX_EXPIRING_SOON_THRESHOLD); + OVERWINTER_TX_VERSION, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1); ContextualCreateTxCheck(params, saplingActivationHeight - 3, - 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1 + TX_EXPIRING_SOON_THRESHOLD); + OVERWINTER_TX_VERSION, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1); ContextualCreateTxCheck(params, saplingActivationHeight - 2, - 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1 + TX_EXPIRING_SOON_THRESHOLD); + OVERWINTER_TX_VERSION, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1); ContextualCreateTxCheck(params, saplingActivationHeight - 1, - 3, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1 + TX_EXPIRING_SOON_THRESHOLD); + OVERWINTER_TX_VERSION, true, OVERWINTER_VERSION_GROUP_ID, saplingActivationHeight - 1); // Sapling activates ContextualCreateTxCheck(params, saplingActivationHeight, SAPLING_TX_VERSION, true, SAPLING_VERSION_GROUP_ID, saplingActivationHeight + DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA); diff --git a/src/main.cpp b/src/main.cpp index 1e6ce458ac5..3819afd3beb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6669,7 +6669,7 @@ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Para // We need to add TX_EXPIRING_SOON_THRESHOLD otherwise we cannot send transactions just prior to the next epoch // The idea is that the transaction will not be rejected as expiring soon until the same block that it is // The rejected for being created during the last epoch. - mtx.nExpiryHeight = std::min(mtx.nExpiryHeight, static_cast(nextActivationHeight.get()) - 1 + TX_EXPIRING_SOON_THRESHOLD); + mtx.nExpiryHeight = std::min(mtx.nExpiryHeight, static_cast(nextActivationHeight.get()) - 1); } } return mtx; From 7ddcf427c00d92c051cf41a940bac525f5bf0cac Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 5 Aug 2019 12:41:31 -0600 Subject: [PATCH 39/50] Fix/update comments --- src/consensus/params.cpp | 4 ++-- src/main.cpp | 7 ++----- src/test/alert_tests.cpp | 4 ++-- src/test/main_tests.cpp | 2 +- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp index 553e5451db3..c0e332892c9 100644 --- a/src/consensus/params.cpp +++ b/src/consensus/params.cpp @@ -15,11 +15,11 @@ namespace Consensus { // floor((BlossomActivationHeight - SlowStartShift) / PreBlossomHalvingInterval + (height - BlossomActivationHeight) / PostBlossomHalvingInterval), otherwise if (NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM)) { int blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; - // // Ideally we would say: + // Ideally we would say: // halvings = (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval // + (nHeight - blossomActivationHeight) / consensusParams.nPostBlossomSubsidyHalvingInterval; // But, (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval - // needs to be a treated rational number or this does not work. + // would need to be treated as a rational number in order for this to work. // Define scaledHalvings := halvings * consensusParams.nPreBlossomSubsidyHalvingInterval; int scaledHalvings = (blossomActivationHeight - SubsidySlowStartShift()) + (nHeight - blossomActivationHeight) / Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO; diff --git a/src/main.cpp b/src/main.cpp index 3819afd3beb..44ac8db0d70 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6662,13 +6662,10 @@ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Para } // NOTE: If the expiry height crosses into an incompatible consensus epoch, and it is changed to the last block - // of the current epoch (see below: Overwinter->Sapling), the transaction will be rejected if it falls within - // the expiring soon threshold of 3 blocks (for DoS mitigation) based on the current height. + // of the current epoch, the transaction will be rejected if it falls within the expiring soon threshold of + // TX_EXPIRING_SOON_THRESHOLD (3) blocks (for DoS mitigation) based on the current height. auto nextActivationHeight = NextActivationHeight(nHeight, consensusParams); if (nextActivationHeight) { - // We need to add TX_EXPIRING_SOON_THRESHOLD otherwise we cannot send transactions just prior to the next epoch - // The idea is that the transaction will not be rejected as expiring soon until the same block that it is - // The rejected for being created during the last epoch. mtx.nExpiryHeight = std::min(mtx.nExpiryHeight, static_cast(nextActivationHeight.get()) - 1); } } diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index c8ecbd58dde..ffbc46b65f9 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -392,6 +392,8 @@ void PartitionAlertTestImpl(const Consensus::Params& params, int startTime, int CCriticalSection csDummy; CBlockIndex indexDummy[800]; + // Generate fake blockchain timestamps relative to + // an arbitrary time: int64_t start = startTime; for (int i = 0; i < 800; i++) { @@ -402,8 +404,6 @@ void PartitionAlertTestImpl(const Consensus::Params& params, int startTime, int // Other members don't matter, the partition check code doesn't // use them } - // Generate fake blockchain timestamps relative to - // an arbitrary time: int64_t now = indexDummy[799].nTime + params.PoWTargetSpacing(800); SetMockTime(now); diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp index 8af388473c3..b3930e55090 100644 --- a/src/test/main_tests.cpp +++ b/src/test/main_tests.cpp @@ -66,7 +66,7 @@ BOOST_AUTO_TEST_CASE(block_subsidy_test) TestBlockSubsidyHalvings(20000, Consensus::PRE_BLOSSOM_HALVING_INTERVAL, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); // Pre-Blossom TestBlockSubsidyHalvings(50, 150, 80); // As in regtest TestBlockSubsidyHalvings(500, 1000, 900); // Just another interval - TestBlockSubsidyHalvings(500, 1000, 3000); // Multiple halvings before activation + TestBlockSubsidyHalvings(500, 1000, 3000); // Multiple halvings before Blossom activation } BOOST_AUTO_TEST_CASE(subsidy_limit_test) From 0f0512128cc661cbba3b250f956eba204920281d Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 5 Aug 2019 12:57:10 -0600 Subject: [PATCH 40/50] Make sure that expiry height is not less than height --- src/bitcoin-tx.cpp | 1 - src/main.cpp | 2 +- src/transaction_builder.cpp | 5 ++--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 8b7c2ac3543..799d3cb91fd 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -174,7 +174,6 @@ static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal) static void MutateTxExpiry(CMutableTransaction& tx, const std::string& cmdVal) { int64_t newExpiry = atoi64(cmdVal); - // Review: is newExpiry == 0 allowed? Is this coinbase only? if (newExpiry <= 0 || newExpiry >= TX_EXPIRY_HEIGHT_THRESHOLD) { throw std::runtime_error("Invalid TX expiry requested"); } diff --git a/src/main.cpp b/src/main.cpp index 44ac8db0d70..615998d45e4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6656,7 +6656,7 @@ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Para mtx.nExpiryHeight = nHeight + (expiryDeltaArg ? expiryDeltaArg.get() : consensusParams.DefaultExpiryDelta(nHeight)); - // Review: is mtx.nExpiryHeight == 0 allowed? Is this coinbase only? + // mtx.nExpiryHeight == 0 is valid for coinbase transactions if (mtx.nExpiryHeight <= 0 || mtx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { throw new std::runtime_error("CreateNewContextualCMutableTransaction: invalid expiry height"); } diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp index b3e6cdb77f9..dca951dd455 100644 --- a/src/transaction_builder.cpp +++ b/src/transaction_builder.cpp @@ -78,11 +78,10 @@ struct JSDescException : public std::exception void TransactionBuilder::SetExpiryHeight(uint32_t nExpiryHeight) { - mtx.nExpiryHeight = nExpiryHeight; - // Review: is mtx.nExpiryHeight == 0 allowed? Is this coinbase only? - if (mtx.nExpiryHeight <= 0 || mtx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { + if (nExpiryHeight < nHeight || nExpiryHeight <= 0 || nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { throw new std::runtime_error("TransactionBuilder::SetExpiryHeight: invalid expiry height"); } + mtx.nExpiryHeight = nExpiryHeight; } void TransactionBuilder::AddSaplingSpend( From 609bb38ad82c7a228a9d27c6014fe416e610c24a Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 5 Aug 2019 13:01:01 -0600 Subject: [PATCH 41/50] Clarify documentation --- src/rpc/rawtransaction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 065d1498292..156bfe87435 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -502,8 +502,8 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp) " ,...\n" " }\n" "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n" - "4. expiryheight (numeric, optional, default=nextblockheight+" - + strprintf("%d (pre-Blossom) or %d (post-Blossom)", DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA, DEFAULT_POST_BLOSSOM_TX_EXPIRY_DELTA) + ") " + "4. expiryheight (numeric, optional, default=" + + strprintf("nextblockheight+%d (pre-Blossom) or nextblockheight+%d (post-Blossom)", DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA, DEFAULT_POST_BLOSSOM_TX_EXPIRY_DELTA) + ") " "Expiry height of transaction (if Overwinter is active)\n" "\nResult:\n" "\"transaction\" (string) hex string of the transaction\n" From 832134f4cd4a564d7e438478335a512ba8380a37 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 5 Aug 2019 13:16:13 -0600 Subject: [PATCH 42/50] Update PoW related assertions --- src/chainparams.cpp | 1 - src/consensus/params.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 82d60af3182..f85786be707 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -509,7 +509,6 @@ class CRegTestParams : public CChainParams { void UpdateRegtestPow(int64_t nPowMaxAdjustDown, int64_t nPowMaxAdjustUp, uint256 powLimit) { - assert(strNetworkID == "regtest"); consensus.nPowMaxAdjustDown = nPowMaxAdjustDown; consensus.nPowMaxAdjustUp = nPowMaxAdjustUp; consensus.powLimit = powLimit; diff --git a/src/consensus/params.h b/src/consensus/params.h index 8644b087f26..5599d6cbe09 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -68,6 +68,7 @@ static_assert(POST_BLOSSOM_POW_TARGET_SPACING < PRE_BLOSSOM_POW_TARGET_SPACING, static const unsigned int PRE_BLOSSOM_HALVING_INTERVAL = 840000; static const unsigned int PRE_BLOSSOM_REGTEST_HALVING_INTERVAL = 150; 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 POST_BLOSSOM_HALVING_INTERVAL = PRE_BLOSSOM_HALVING_INTERVAL * BLOSSOM_POW_TARGET_SPACING_RATIO; static const unsigned int POST_BLOSSOM_REGTEST_HALVING_INTERVAL = PRE_BLOSSOM_REGTEST_HALVING_INTERVAL * BLOSSOM_POW_TARGET_SPACING_RATIO; From 8f0a54c142ba2d535373e56fa95bd28e0af4904c Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 5 Aug 2019 13:40:06 -0600 Subject: [PATCH 43/50] Remove DefaultExpiryDelta method --- src/consensus/params.cpp | 5 ----- src/consensus/params.h | 2 -- src/main.cpp | 6 ++++-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp index c0e332892c9..3987260ae4c 100644 --- a/src/consensus/params.cpp +++ b/src/consensus/params.cpp @@ -1,6 +1,5 @@ #include "params.h" -#include "main.h" #include "upgrades.h" namespace Consensus { @@ -54,10 +53,6 @@ namespace Consensus { } } - unsigned int Params::DefaultExpiryDelta(int nHeight) const { - return NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM) ? DEFAULT_POST_BLOSSOM_TX_EXPIRY_DELTA : DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA; - } - int64_t Params::PoWTargetSpacing(int nHeight) const { // zip208 // PoWTargetSpacing(height) := diff --git a/src/consensus/params.h b/src/consensus/params.h index 5599d6cbe09..84fff232a42 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -108,8 +108,6 @@ struct Params { int GetLastFoundersRewardBlockHeight(int nHeight) const; - unsigned int DefaultExpiryDelta(int nHeight) const; - /** Used to check majorities for block version upgrade */ int nMajorityEnforceBlockUpgrade; int nMajorityRejectBlockOutdated; diff --git a/src/main.cpp b/src/main.cpp index 615998d45e4..3ebe6b3712f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6653,8 +6653,10 @@ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Para mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID; mtx.nVersion = OVERWINTER_TX_VERSION; } - - mtx.nExpiryHeight = nHeight + (expiryDeltaArg ? expiryDeltaArg.get() : consensusParams.DefaultExpiryDelta(nHeight)); + + bool blossomActive = consensusParams.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM); + unsigned int defaultExpiryDelta = blossomActive ? DEFAULT_POST_BLOSSOM_TX_EXPIRY_DELTA : DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA; + mtx.nExpiryHeight = nHeight + (expiryDeltaArg ? expiryDeltaArg.get() : defaultExpiryDelta); // mtx.nExpiryHeight == 0 is valid for coinbase transactions if (mtx.nExpiryHeight <= 0 || mtx.nExpiryHeight >= TX_EXPIRY_HEIGHT_THRESHOLD) { From f97b9c5d9f4d9479eebcc386cc1172eac376d354 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 5 Aug 2019 14:02:31 -0600 Subject: [PATCH 44/50] Algebraic improvements related to halving --- src/consensus/params.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp index 3987260ae4c..b0ae2b9ea36 100644 --- a/src/consensus/params.cpp +++ b/src/consensus/params.cpp @@ -19,10 +19,10 @@ namespace Consensus { // + (nHeight - blossomActivationHeight) / consensusParams.nPostBlossomSubsidyHalvingInterval; // But, (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval // would need to be treated as a rational number in order for this to work. - // Define scaledHalvings := halvings * consensusParams.nPreBlossomSubsidyHalvingInterval; - int scaledHalvings = (blossomActivationHeight - SubsidySlowStartShift()) - + (nHeight - blossomActivationHeight) / Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO; - return scaledHalvings / nPreBlossomSubsidyHalvingInterval; + // Define scaledHalvings := halvings * consensusParams.nPostBlossomSubsidyHalvingInterval; + int scaledHalvings = ((blossomActivationHeight - SubsidySlowStartShift()) * Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO) + + (nHeight - blossomActivationHeight); + return scaledHalvings / nPostBlossomSubsidyHalvingInterval; } else { return (nHeight - SubsidySlowStartShift()) / nPreBlossomSubsidyHalvingInterval; } @@ -40,14 +40,15 @@ namespace Consensus { // height = preInterval + SS // postBlossom: // 1 = (H - SS) / preInterval + (height - H) / postInterval - // height = H + postInterval + (SS - H) * (postInterval / preInterval) - // height = H + postInterval + (SS - H) * R + // height = H + postInterval - (H - SS) * (postInterval / preInterval) + // height = H + postInterval - (H - SS) * R + // Note: This depends on R being an integer bool blossomActive = NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM); if (blossomActive) { int blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; // The following calculation depends on BLOSSOM_POW_TARGET_SPACING_RATIO being an integer. return blossomActivationHeight + nPostBlossomSubsidyHalvingInterval - + (SubsidySlowStartShift() - blossomActivationHeight) * BLOSSOM_POW_TARGET_SPACING_RATIO - 1; + - (blossomActivationHeight - SubsidySlowStartShift()) * BLOSSOM_POW_TARGET_SPACING_RATIO - 1; } else { return nPreBlossomSubsidyHalvingInterval + SubsidySlowStartShift() - 1; } From 5a93638981972059bfd301eb08bf8a026f323e86 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 5 Aug 2019 14:20:25 -0600 Subject: [PATCH 45/50] Distinguish between height and current header height on metrics screen --- src/metrics.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index e6390572662..e92734d003a 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -109,28 +109,29 @@ double GetLocalSolPS() return miningTimer.rate(solutionTargetChecks); } -int EstimateNetHeight(const Consensus::Params& params, int currentBlockHeight, int64_t currentBlockTime) +int EstimateNetHeight(const Consensus::Params& params, int currentHeadersHeight, int64_t currentHeadersTime) { int64_t now = GetAdjustedTime(); - if (currentBlockTime >= now) { - return currentBlockHeight; + if (currentHeadersTime >= now) { + return currentHeadersHeight; } - int estimatedHeight = currentBlockHeight + (now - currentBlockTime) / params.PoWTargetSpacing(currentBlockHeight); + int estimatedHeight = currentHeadersHeight + (now - currentHeadersTime) / params.PoWTargetSpacing(currentHeadersHeight); int blossomActivationHeight = params.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; - if (currentBlockHeight >= blossomActivationHeight || estimatedHeight <= blossomActivationHeight) { + if (currentHeadersHeight >= blossomActivationHeight || estimatedHeight <= blossomActivationHeight) { return estimatedHeight; } - int numPreBlossomBlocks = blossomActivationHeight - currentBlockHeight; + int numPreBlossomBlocks = blossomActivationHeight - currentHeadersHeight; int64_t preBlossomTime = numPreBlossomBlocks * params.PoWTargetSpacing(blossomActivationHeight - 1); - int64_t blossomActivationTime = currentBlockTime + preBlossomTime; + int64_t blossomActivationTime = currentHeadersTime + preBlossomTime; if (blossomActivationTime >= now) { return blossomActivationHeight; } - return blossomActivationHeight + (now - blossomActivationTime) / params.PoWTargetSpacing(blossomActivationHeight); + int netheight = blossomActivationHeight + (now - blossomActivationTime) / params.PoWTargetSpacing(blossomActivationHeight); + return ((netheight + 5) / 10) * 10; } void TriggerRefresh() @@ -199,20 +200,22 @@ int printStats(bool mining) int lines = 4; int height; - int64_t blockTime; + int64_t currentHeadersHeight; + int64_t currentHeadersTime; size_t connections; int64_t netsolps; { LOCK2(cs_main, cs_vNodes); - height = pindexBestHeader->nHeight; - blockTime = pindexBestHeader->nTime; + height = chainActive.Tip()->nHeight; + currentHeadersHeight = pindexBestHeader->nHeight; + currentHeadersTime = pindexBestHeader->nTime; connections = vNodes.size(); netsolps = GetNetworkHashPS(120, -1); } auto localsolps = GetLocalSolPS(); if (IsInitialBlockDownload(Params())) { - int netheight = EstimateNetHeight(Params().GetConsensus(), height, blockTime); + int netheight = EstimateNetHeight(Params().GetConsensus(), currentHeadersHeight, currentHeadersTime); int downloadPercent = height * 100 / netheight; std::cout << " " << _("Downloading blocks") << " | " << height << " / ~" << netheight << " (" << downloadPercent << "%)" << std::endl; } else { From 42a21ef0045a04f01b35c9c8714c5a1645bee20c Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 5 Aug 2019 14:52:34 -0600 Subject: [PATCH 46/50] Test clean up and fixes --- qa/rpc-tests/shorter_block_times.py | 16 +++++++++------- src/gtest/test_foundersreward.cpp | 10 +++------- src/test/main_tests.cpp | 7 +++++-- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/qa/rpc-tests/shorter_block_times.py b/qa/rpc-tests/shorter_block_times.py index b34882e2621..8e807e4661a 100755 --- a/qa/rpc-tests/shorter_block_times.py +++ b/qa/rpc-tests/shorter_block_times.py @@ -21,7 +21,7 @@ def setup_nodes(self): return start_nodes(4, self.options.tmpdir, [[ '-nuparams=5ba81b19:0', # Overwinter '-nuparams=76b809bb:0', # Sapling - '-nuparams=2bb40e60:103', # Blossom + '-nuparams=2bb40e60:106', # Blossom ]] * 4) def setup_chain(self): @@ -36,21 +36,23 @@ def run_test(self): # Sanity-check the block height assert_equal(self.nodes[0].getblockcount(), 101) - # Make sure we can send a transaction on the last pre-Blossom block node0_taddr = get_coinbase_address(self.nodes[0]) node0_zaddr = self.nodes[0].z_getnewaddress('sapling') recipients = [{'address': node0_zaddr, 'amount': Decimal('10')}] myopid = self.nodes[0].z_sendmany(node0_taddr, recipients, 1, Decimal('0')) txid = wait_and_assert_operationid_status(self.nodes[0], myopid) - assert_equal(105, self.nodes[0].getrawtransaction(txid, 1)['expiryheight']) # Blossom activation - 1 + 3 + assert_equal(105, self.nodes[0].getrawtransaction(txid, 1)['expiryheight']) # Blossom activation - 1 self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + assert_equal(10, Decimal(self.nodes[0].z_gettotalbalance()['private'])) - print "Mining last pre-Blossom block" + self.nodes[0].generate(2) + self.sync_all() + print "Mining last pre-Blossom blocks" # Activate blossom self.nodes[1].generate(1) self.sync_all() - # Check that the last pre-Blossom transaction was mined - assert_equal(10, Decimal(self.nodes[0].z_gettotalbalance()['private'])) # Check that we received a pre-Blossom mining reward assert_equal(10, Decimal(self.nodes[1].getwalletinfo()['immature_balance'])) @@ -64,7 +66,7 @@ def run_test(self): # Send and mine a transaction after activation myopid = self.nodes[0].z_sendmany(node0_taddr, recipients, 1, Decimal('0')) txid = wait_and_assert_operationid_status(self.nodes[0], myopid) - assert_equal(144, self.nodes[0].getrawtransaction(txid, 1)['expiryheight']) # height + 1 + 40 + assert_equal(147, self.nodes[0].getrawtransaction(txid, 1)['expiryheight']) # height + 1 + 40 self.nodes[1].generate(1) self.sync_all() assert_equal(20, Decimal(self.nodes[0].z_gettotalbalance()['private'])) diff --git a/src/gtest/test_foundersreward.cpp b/src/gtest/test_foundersreward.cpp index d4b45a15716..7eeb7fa0df4 100644 --- a/src/gtest/test_foundersreward.cpp +++ b/src/gtest/test_foundersreward.cpp @@ -84,7 +84,7 @@ TEST(founders_reward_test, create_testnet_2of3multisig) { #endif -static int GetLastFoundersRewardHeight(const Consensus::Params& params){ +static int GetLastFoundersRewardHeight(const Consensus::Params& params) { int blossomActivationHeight = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; bool blossom = blossomActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; return params.GetLastFoundersRewardBlockHeight(blossom ? blossomActivationHeight : 0); @@ -116,7 +116,7 @@ TEST(founders_reward_test, general) { EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(53127)), "a91455d64928e69829d9376c776550b6cc710d42715387"); EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(53127), "t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy"); - int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(0); + int maxHeight = GetLastFoundersRewardHeight(params.GetConsensus()); // If the block height parameter is out of bounds, there is an assert. EXPECT_DEATH(params.GetFoundersRewardScriptAtHeight(0), "nHeight"); @@ -173,12 +173,8 @@ TEST(founders_reward_test, slow_start_subsidy) { SelectParams(CBaseChainParams::MAIN); CChainParams params = Params(); - int blossomActivationHeight = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; - bool blossom = blossomActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; - int maxHeight = Params().GetConsensus().GetLastFoundersRewardBlockHeight(blossom ? blossomActivationHeight : 0); - CAmount totalSubsidy = 0; - for (int nHeight = 1; nHeight <= maxHeight; nHeight++) { + for (int nHeight = 1; nHeight <= GetLastFoundersRewardHeight(Params().GetConsensus()); nHeight++) { CAmount nSubsidy = GetBlockSubsidy(nHeight, params.GetConsensus()) / 5; totalSubsidy += nSubsidy; } diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp index b3930e55090..5e2cb8a86b8 100644 --- a/src/test/main_tests.cpp +++ b/src/test/main_tests.cpp @@ -16,6 +16,8 @@ BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup) const CAmount INITIAL_SUBSIDY = 12.5 * COIN; static int GetTotalHalvings(const Consensus::Params& consensusParams) { + // This assumes that BLOSSOM_POW_TARGET_SPACING_RATIO == 2 + // and treats blossom activation as a halving event return consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight == Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT ? 64 : 65; } @@ -55,7 +57,7 @@ static void TestBlockSubsidyHalvings(int nSubsidySlowStartInterval, int nPreBlos Consensus::Params consensusParams; consensusParams.nSubsidySlowStartInterval = nSubsidySlowStartInterval; consensusParams.nPreBlossomSubsidyHalvingInterval = nPreBlossomSubsidyHalvingInterval; - consensusParams.nPostBlossomSubsidyHalvingInterval = nPreBlossomSubsidyHalvingInterval * 2; + consensusParams.nPostBlossomSubsidyHalvingInterval = nPreBlossomSubsidyHalvingInterval * Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO; consensusParams.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight = blossomActivationHeight; TestBlockSubsidyHalvings(consensusParams); } @@ -78,7 +80,7 @@ BOOST_AUTO_TEST_CASE(subsidy_limit_test) // Mining slow start for (; nHeight < consensusParams.nSubsidySlowStartInterval; nHeight++) { CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams); - BOOST_CHECK(nSubsidy <= 12.5 * COIN); + BOOST_CHECK(nSubsidy <= INITIAL_SUBSIDY); nSum += nSubsidy; BOOST_CHECK(MoneyRange(nSum)); } @@ -88,6 +90,7 @@ BOOST_AUTO_TEST_CASE(subsidy_limit_test) CAmount nSubsidy; do { nSubsidy = GetBlockSubsidy(nHeight, consensusParams); + BOOST_CHECK(nSubsidy <= INITIAL_SUBSIDY); nSum += nSubsidy; BOOST_ASSERT(MoneyRange(nSum)); ++nHeight; From 2f007290613dc5d40d3646ee770590fecea8c399 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Mon, 5 Aug 2019 19:05:11 -0600 Subject: [PATCH 47/50] Add copyright info --- qa/rpc-tests/shorter_block_times.py | 2 +- src/consensus/params.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/qa/rpc-tests/shorter_block_times.py b/qa/rpc-tests/shorter_block_times.py index 8e807e4661a..3141a7e7701 100755 --- a/qa/rpc-tests/shorter_block_times.py +++ b/qa/rpc-tests/shorter_block_times.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # Copyright (c) 2019 The Zcash developers # Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# file COPYING or https://www.opensource.org/licenses/mit-license.php . import sys; assert sys.version_info < (3,), ur"This script does not run under Python 3. Please use Python 2.7.x." diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp index b0ae2b9ea36..b0f2079e730 100644 --- a/src/consensus/params.cpp +++ b/src/consensus/params.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2019 The Zcash developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php . + #include "params.h" #include "upgrades.h" From cdb6757095467f36c47b256ac6540a993d7cef4d Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 6 Aug 2019 09:45:17 -0600 Subject: [PATCH 48/50] NPE defense in metrics screen --- src/metrics.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index e92734d003a..9268013e8ec 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -120,7 +120,7 @@ int EstimateNetHeight(const Consensus::Params& params, int currentHeadersHeight, int blossomActivationHeight = params.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; if (currentHeadersHeight >= blossomActivationHeight || estimatedHeight <= blossomActivationHeight) { - return estimatedHeight; + return ((estimatedHeight + 5) / 10) * 10; } int numPreBlossomBlocks = blossomActivationHeight - currentHeadersHeight; @@ -206,9 +206,9 @@ int printStats(bool mining) int64_t netsolps; { LOCK2(cs_main, cs_vNodes); - height = chainActive.Tip()->nHeight; - currentHeadersHeight = pindexBestHeader->nHeight; - currentHeadersTime = pindexBestHeader->nTime; + height = chainActive.Height(); + currentHeadersHeight = pindexBestHeader ? pindexBestHeader->nHeight: -1; + currentHeadersTime = pindexBestHeader ? pindexBestHeader->nTime : 0; connections = vNodes.size(); netsolps = GetNetworkHashPS(120, -1); } From d9ef43dc2549072767f568313fd78d7a08272686 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Wed, 7 Aug 2019 10:04:30 -0600 Subject: [PATCH 49/50] Do not estimate height if there is no best header --- src/metrics.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/metrics.cpp b/src/metrics.cpp index 9268013e8ec..9e03735b6d9 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -215,7 +215,8 @@ int printStats(bool mining) auto localsolps = GetLocalSolPS(); if (IsInitialBlockDownload(Params())) { - int netheight = EstimateNetHeight(Params().GetConsensus(), currentHeadersHeight, currentHeadersTime); + int netheight = currentHeadersHeight == -1 || currentHeadersTime == 0 ? + 0 : EstimateNetHeight(Params().GetConsensus(), currentHeadersHeight, currentHeadersTime); int downloadPercent = height * 100 / netheight; std::cout << " " << _("Downloading blocks") << " | " << height << " / ~" << netheight << " (" << downloadPercent << "%)" << std::endl; } else { From b99003c1ecc1917989e8bcaf53ee19cfaf79e73e Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Wed, 7 Aug 2019 10:05:01 -0600 Subject: [PATCH 50/50] Rename method and use int64_t --- src/consensus/params.cpp | 8 ++++---- src/consensus/params.h | 2 +- src/gtest/test_foundersreward.cpp | 8 ++++---- src/main.cpp | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp index b0f2079e730..1062df349c7 100644 --- a/src/consensus/params.cpp +++ b/src/consensus/params.cpp @@ -11,22 +11,22 @@ namespace Consensus { return NetworkUpgradeState(nHeight, *this, idx) == UPGRADE_ACTIVE; } - int Params::Halvings(int nHeight) const { + int Params::Halving(int nHeight) const { // zip208 // Halving(height) := // floor((height - SlowStartShift) / PreBlossomHalvingInterval), if not IsBlossomActivated(height) // floor((BlossomActivationHeight - SlowStartShift) / PreBlossomHalvingInterval + (height - BlossomActivationHeight) / PostBlossomHalvingInterval), otherwise if (NetworkUpgradeActive(nHeight, Consensus::UPGRADE_BLOSSOM)) { - int blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; + int64_t blossomActivationHeight = vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight; // Ideally we would say: // halvings = (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval // + (nHeight - blossomActivationHeight) / consensusParams.nPostBlossomSubsidyHalvingInterval; // But, (blossomActivationHeight - consensusParams.SubsidySlowStartShift()) / consensusParams.nPreBlossomSubsidyHalvingInterval // would need to be treated as a rational number in order for this to work. // Define scaledHalvings := halvings * consensusParams.nPostBlossomSubsidyHalvingInterval; - int scaledHalvings = ((blossomActivationHeight - SubsidySlowStartShift()) * Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO) + int64_t scaledHalvings = ((blossomActivationHeight - SubsidySlowStartShift()) * Consensus::BLOSSOM_POW_TARGET_SPACING_RATIO) + (nHeight - blossomActivationHeight); - return scaledHalvings / nPostBlossomSubsidyHalvingInterval; + return (int) (scaledHalvings / nPostBlossomSubsidyHalvingInterval); } else { return (nHeight - SubsidySlowStartShift()) / nPreBlossomSubsidyHalvingInterval; } diff --git a/src/consensus/params.h b/src/consensus/params.h index 84fff232a42..a3bbbd3134c 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -104,7 +104,7 @@ struct Params { int nPreBlossomSubsidyHalvingInterval; int nPostBlossomSubsidyHalvingInterval; - int Halvings(int nHeight) const; + int Halving(int nHeight) const; int GetLastFoundersRewardBlockHeight(int nHeight) const; diff --git a/src/gtest/test_foundersreward.cpp b/src/gtest/test_foundersreward.cpp index 7eeb7fa0df4..70826ae2a76 100644 --- a/src/gtest/test_foundersreward.cpp +++ b/src/gtest/test_foundersreward.cpp @@ -129,8 +129,8 @@ TEST(founders_reward_test, regtest_get_last_block_blossom) { int blossomActivationHeight = Consensus::PRE_BLOSSOM_REGTEST_HALVING_INTERVAL / 2; // = 75 auto params = RegtestActivateBlossom(false, blossomActivationHeight); int lastFRHeight = params.GetLastFoundersRewardBlockHeight(blossomActivationHeight); - EXPECT_EQ(0, params.Halvings(lastFRHeight)); - EXPECT_EQ(1, params.Halvings(lastFRHeight + 1)); + EXPECT_EQ(0, params.Halving(lastFRHeight)); + EXPECT_EQ(1, params.Halving(lastFRHeight + 1)); RegtestDeactivateBlossom(); } @@ -138,8 +138,8 @@ TEST(founders_reward_test, mainnet_get_last_block) { SelectParams(CBaseChainParams::MAIN); auto params = Params().GetConsensus(); int lastFRHeight = GetLastFoundersRewardHeight(params); - EXPECT_EQ(0, params.Halvings(lastFRHeight)); - EXPECT_EQ(1, params.Halvings(lastFRHeight + 1)); + EXPECT_EQ(0, params.Halving(lastFRHeight)); + EXPECT_EQ(1, params.Halving(lastFRHeight + 1)); } #define NUM_MAINNET_FOUNDER_ADDRESSES 48 diff --git a/src/main.cpp b/src/main.cpp index 3ebe6b3712f..7447e2f32d5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1762,7 +1762,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) assert(nHeight > consensusParams.SubsidySlowStartShift()); - int halvings = consensusParams.Halvings(nHeight); + int halvings = consensusParams.Halving(nHeight); // Force block reward to zero when right shift is undefined. if (halvings >= 64)