diff --git a/src/consensus/funding.cpp b/src/consensus/funding.cpp index 7b2cd01e5..4e0ba62af 100644 --- a/src/consensus/funding.cpp +++ b/src/consensus/funding.cpp @@ -59,8 +59,8 @@ int GetMaxFundingStreamHeight(const Consensus::Params& params) { int result = 0; for (int idx = Consensus::FIRST_FUNDING_STREAM; idx < Consensus::MAX_FUNDING_STREAMS; idx++) { auto fs = params.vFundingStreams[idx]; - if (fs && result < fs.get().GetEndHeight()) { - result = fs.get().GetEndHeight(); + if (fs && result < fs.get().GetEndHeight() - 1) { + result = fs.get().GetEndHeight() - 1; } } diff --git a/src/consensus/params.cpp b/src/consensus/params.cpp index 23a37aa3b..ee9cc6dac 100644 --- a/src/consensus/params.cpp +++ b/src/consensus/params.cpp @@ -100,9 +100,9 @@ namespace Consensus { boost::variant FundingStream::ValidateFundingStream( const Consensus::Params& params, - int startHeight, - int endHeight, - std::vector addresses + const int startHeight, + const int endHeight, + const std::vector& addresses ) { if (!params.NetworkUpgradeActive(startHeight, Consensus::UPGRADE_CANOPY)) { return FundingStreamError::CANOPY_NOT_ACTIVE; @@ -112,7 +112,7 @@ namespace Consensus { return FundingStreamError::ILLEGAL_RANGE; } - if (params.FundingPeriodIndex(startHeight, endHeight) >= addresses.size()) { + if (params.FundingPeriodIndex(startHeight, endHeight - 1) >= addresses.size()) { return FundingStreamError::INSUFFICIENT_ADDRESSES; } @@ -141,8 +141,8 @@ namespace Consensus { FundingStream FundingStream::ParseFundingStream( const Consensus::Params& params, - int startHeight, - int endHeight, + const int startHeight, + const int endHeight, const std::vector strAddresses) { // Parse the address strings into concrete types. diff --git a/src/consensus/params.h b/src/consensus/params.h index 4c6710fd9..f7348818d 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -116,15 +116,15 @@ public: static boost::variant ValidateFundingStream( const Consensus::Params& params, - int startHeight, - int endHeight, - std::vector addresses + const int startHeight, + const int endHeight, + const std::vector& addresses ); static FundingStream ParseFundingStream( const Consensus::Params& params, - int startHeight, - int endHeight, + const int startHeight, + const int endHeight, const std::vector strAddresses); int GetStartHeight() const { return startHeight; }; diff --git a/src/gtest/test_foundersreward.cpp b/src/gtest/test_foundersreward.cpp index d190d50a6..3ccae312f 100644 --- a/src/gtest/test_foundersreward.cpp +++ b/src/gtest/test_foundersreward.cpp @@ -234,7 +234,7 @@ TEST(FundingStreamsRewardTest, Zip207Distribution) { Consensus::FundingStream::ParseFundingStream( consensus, minHeight, - minHeight + 100, + minHeight + 12, { "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", EncodePaymentAddress(sk.default_address()) @@ -256,3 +256,23 @@ TEST(FundingStreamsRewardTest, Zip207Distribution) { EXPECT_EQ(totalFunding, blockSubsidy / 5); } } + +TEST(FundingStreamsRewardTest, ParseFundingStream) { + auto consensus = RegtestActivateCanopy(false, 200); + + int minHeight = GetLastFoundersRewardHeight(consensus) + 1; + + auto sk = libzcash::SaplingSpendingKey(uint256()); + ASSERT_THROW( + Consensus::FundingStream::ParseFundingStream( + consensus, + minHeight, + minHeight + 13, + { + "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi", + EncodePaymentAddress(sk.default_address()) + } + ), + std::runtime_error + ); +} diff --git a/src/main.cpp b/src/main.cpp index 415d308c6..ca9e33626 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -906,11 +906,16 @@ bool ContextualCheckTransaction( // From Canopy onward, coinbase transaction must include outputs corresponding to the // ZIP 207 consensus funding streams active at the current block height. To avoid // double-decrypting, we detect any shielded funding streams during the Heartwood - // consensus check. If Canopy is not yet active, requiredStream will be empty. - auto fundingStreamElements = Consensus::GetActiveFundingStreamElements( - nHeight, - GetBlockSubsidy(nHeight, chainparams.GetConsensus()), - chainparams.GetConsensus()); + // consensus check. If Canopy is not yet active, requiredStreams will be empty. + std::set fundingStreamElements; + if (canopyActive) { + fundingStreamElements = Consensus::GetActiveFundingStreamElements( + nHeight, + // GetBlockSubsidy must be guarded because it will throw + // if called at slow-start period heights. + GetBlockSubsidy(nHeight, chainparams.GetConsensus()), + chainparams.GetConsensus()); + } // Rules that apply to Heartwood or later: if (heartwoodActive) {