Skip to content

Commit

Permalink
Rewrite GRC::GetConstantBlockReward
Browse files Browse the repository at this point in the history
This refactors GetConstantBlockReward to use the blockchain
consensus paramters, and also removes the lookback limitation
for block v13+ to correspond with the removal of the contract
lookback window for protocol entries.
  • Loading branch information
jamescowens committed Oct 20, 2024
1 parent e7835f5 commit 486b23b
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 26 deletions.
8 changes: 4 additions & 4 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ class CMainParams : public CChainParams {
consensus.BlockV13Height = std::numeric_limits<int>::max();
consensus.PollV3Height = 2671700;
consensus.ProjectV2Height = 2671700;
consensus.DefaultConstantBlockReward = 10;
consensus.DefaultConstantBlockReward = 10 * COIN;
consensus.ConstantBlockRewardFloor = 0;
consensus.ConstantBlockRewardCeiling = 100;
consensus.ConstantBlockRewardCeiling = 100 * COIN;
consensus.InitialMRCFeeFractionPostZeroInterval = Fraction(2, 5);
consensus.MRCZeroPaymentInterval = 14 * 24 * 60 * 60;
consensus.MaxMandatorySideStakeTotalAlloc = Fraction(1, 4);
Expand Down Expand Up @@ -185,9 +185,9 @@ class CTestNetParams : public CChainParams {
consensus.BlockV13Height = std::numeric_limits<int>::max();
consensus.PollV3Height = 1944820;
consensus.ProjectV2Height = 1944820;
consensus.DefaultConstantBlockReward = 10;
consensus.DefaultConstantBlockReward = 10 * COIN;
consensus.ConstantBlockRewardFloor = 0;
consensus.ConstantBlockRewardCeiling = 100;
consensus.ConstantBlockRewardCeiling = 100 * COIN;
consensus.InitialMRCFeeFractionPostZeroInterval = Fraction(2, 5);
consensus.MRCZeroPaymentInterval = 10 * 60;
consensus.MaxMandatorySideStakeTotalAlloc = Fraction(1, 4);
Expand Down
55 changes: 41 additions & 14 deletions src/gridcoin/staking/reward.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,52 @@ CAmount GetCoinYearReward(int64_t nTime)

CAmount GRC::GetConstantBlockReward(const CBlockIndex* index)
{
CAmount reward = Params().GetConsensus().DefaultConstantBlockReward;
CAmount MIN_CBR = 0;
CAmount MAX_CBR = 0;

ProtocolEntryOption reward_entry = GetProtocolRegistry().Try("blockreward1");

// The constant block reward is set to a default, voted on value, but this can
// be overridden using an admin message. This allows us to change the reward
// amount without having to release a mandatory with updated rules. In the case
// there is a breach or leaked admin keys the rewards are clamped to twice that
// of the default value.
const CAmount MIN_CBR = 0;
const CAmount MAX_CBR = DEFAULT_CBR * 2;
// there is a breach or leaked admin keys the rewards are clamped.

CAmount reward = DEFAULT_CBR;
AppCacheEntry oCBReward = GetProtocolRegistry().GetProtocolEntryByKeyLegacy("blockreward1");
// Note that the use of the IsV13Enabled test here on the block index does not consider the possibility of
// an administrative contract entry prior to v13 that has aged out from the lookback window which could affect consensus.
// However this possibility is actually covered because 5.4.8.0 was actually a mandatory due to a problem with
// message contracts, and this included the registry for protocol entries, eliminating the lookback window limitation.
// There has been no administrative entry to change the CBR in mainnet prior to 5.4.8.0, so in fact this is a moot issue.
if (IsV13Enabled(index->nHeight)) {
// The clamp for block v13+ is controlled by blockchain consensus parameters.
MIN_CBR = Params().GetConsensus().ConstantBlockRewardFloor;
MAX_CBR = Params().GetConsensus().ConstantBlockRewardCeiling;

if (reward_entry != nullptr) {
// There is no contract lookback limitation v13+.
if (!ParseInt64(reward_entry->m_value, &reward)) {
error("%s: Cannot parse constant block reward from protocol entry: %s",
__func__, reward_entry->m_value);
}
}
} else {
// This is the clamp pre block v13. Note that an administrative entry to change the CBR prior to block v13 that is
// outside the pre v13 clamp rules could cause the CBR to change at the v13 height as the new clamp rules above would
// then apply on the existing protocol entry.
MIN_CBR = 0;
MAX_CBR = Params().GetConsensus().DefaultConstantBlockReward * 2;

//TODO: refactor the expire checking to subroutine
//Note: time constant is same as GetBeaconPublicKey
if ((index->nTime - oCBReward.timestamp) <= (60 * 24 * 30 * 6 * 60)) {
// This is a little slippery, because if we ever change CAmount from a int64_t, this will
// break. It is unlikely to ever change, however, and avoids an extra copy/implicit cast.
if (!ParseInt64(oCBReward.value, &reward)) {
error("%s: Cannot parse constant block reward from protocol entry: %s",
__func__, oCBReward.value);
if (reward_entry != nullptr) {
// The contract lookback window here for block version less than v13 is the same as the standard contract
// replay lookback.
if (index->nTime - reward_entry->m_timestamp <= Params().GetConsensus().StandardContractReplayLookback) {
// This is a little slippery, because if we ever change CAmount from a int64_t, this will
// break. It is unlikely to ever change, however, and avoids an extra copy/implicit cast.
if (!ParseInt64(reward_entry->m_value, &reward)) {
error("%s: Cannot parse constant block reward from protocol entry: %s",
__func__, reward_entry->m_value);
}
}
}
}

Expand Down
2 changes: 0 additions & 2 deletions src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ class MRC;
typedef std::optional<Claim> ClaimOption;
}

static const int64_t DEFAULT_CBR = 10 * COIN;

/** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */
static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC

Expand Down
69 changes: 63 additions & 6 deletions src/test/gridcoin_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ BOOST_AUTO_TEST_CASE(gridcoin_DefaultCBRShouldBe10)
CBlockIndex index;
index.nTime = 1538066417;

BOOST_CHECK_EQUAL(GRC::GetConstantBlockReward(&index), DEFAULT_CBR);
BOOST_CHECK_EQUAL(GRC::GetConstantBlockReward(&index), Params().GetConsensus().DefaultConstantBlockReward);
}

// Note that payload versions 1 and 2 alternate here. This is to test the constructors and
Expand Down Expand Up @@ -212,7 +212,7 @@ BOOST_AUTO_TEST_CASE(gridcoin_ConfigurableCBRShouldClampTo2xDefault)

auto& registry = GRC::GetProtocolRegistry();

AddProtocolEntry(2, "blockreward1", ToString(DEFAULT_CBR * 3), index, false);
AddProtocolEntry(2, "blockreward1", ToString(Params().GetConsensus().DefaultConstantBlockReward * 3), index, false);

if (GRC::ProtocolEntryOption entry = registry.TryActive("blockreward1")) {
LogPrint(BCLog::LogFlags::CONTRACT, "INFO: %s: Protocol entry: m_key %s, m_value %s, m_hash %s, m_previous_hash %s, "
Expand All @@ -227,11 +227,36 @@ BOOST_AUTO_TEST_CASE(gridcoin_ConfigurableCBRShouldClampTo2xDefault)
);
}

BOOST_CHECK_EQUAL(GRC::GetConstantBlockReward(&index), DEFAULT_CBR * 2);
BOOST_CHECK_EQUAL(GRC::GetConstantBlockReward(&index), Params().GetConsensus().DefaultConstantBlockReward * 2);
}

BOOST_AUTO_TEST_CASE(gridcoin_ConfigurableCBRShouldClampToConstantBlockRewardCeilingForV13)
{
const int64_t time = 123456;
CBlockIndex index;
index.nTime = time + 3;
index.nHeight = Params().GetConsensus().BlockV13Height;

auto& registry = GRC::GetProtocolRegistry();

AddProtocolEntry(2, "blockreward1", ToString(Params().GetConsensus().ConstantBlockRewardCeiling * 2), index, false);

if (GRC::ProtocolEntryOption entry = registry.TryActive("blockreward1")) {
LogPrint(BCLog::LogFlags::CONTRACT, "INFO: %s: Protocol entry: m_key %s, m_value %s, m_hash %s, m_previous_hash %s, "
"m_timestamp %" PRId64 ", m_status string %s",
__func__,
entry->m_key,
entry->m_value,
entry->m_hash.ToString(),
entry->m_previous_hash.ToString(),
entry->m_timestamp,
entry->StatusToString()
);
}

BOOST_CHECK_EQUAL(GRC::GetConstantBlockReward(&index), Params().GetConsensus().ConstantBlockRewardCeiling);
}

// TODO: when the 180 day lookback is removed, this should be removed as a test as it will
// be irrelevant and invalid.
BOOST_AUTO_TEST_CASE(gridcoin_ObsoleteConfigurableCBRShouldResortToDefault)
{
CBlockIndex index_check;
Expand Down Expand Up @@ -260,7 +285,39 @@ BOOST_AUTO_TEST_CASE(gridcoin_ObsoleteConfigurableCBRShouldResortToDefault)
);
}

BOOST_CHECK_EQUAL(GRC::GetConstantBlockReward(&index_check), DEFAULT_CBR);
BOOST_CHECK_EQUAL(GRC::GetConstantBlockReward(&index_check), Params().GetConsensus().DefaultConstantBlockReward);
}

BOOST_AUTO_TEST_CASE(gridcoin_PriorObsoleteConfigurableCBRShouldNotResortToDefaultforV13)
{
CBlockIndex index_check;
index_check.nTime = 1538066417;
index_check.nHeight = Params().GetConsensus().BlockV13Height;
const int64_t max_message_age = 60 * 60 * 24 * 180;

CBlockIndex index_add;
index_add.nTime = index_check.nTime - max_message_age - 1;
index_add.nHeight = 5;

auto& registry = GRC::GetProtocolRegistry();

AddProtocolEntry(2, "blockreward1", ToString(3 * COIN), index_add, false);

if (GRC::ProtocolEntryOption entry = registry.TryActive("blockreward1")) {
LogPrint(BCLog::LogFlags::CONTRACT, "INFO: %s: Protocol entry: m_key %s, m_value %s, m_hash %s, m_previous_hash %s, "
"m_timestamp %" PRId64 ", m_status string %s",
__func__,
entry->m_key,
entry->m_value,
entry->m_hash.ToString(),
entry->m_previous_hash.ToString(),
entry->m_timestamp,
entry->StatusToString()
);
}

BOOST_CHECK_EQUAL(GRC::GetConstantBlockReward(&index_check), 3 * COIN);
}


BOOST_AUTO_TEST_SUITE_END()

0 comments on commit 486b23b

Please sign in to comment.