From 043335f11afcd49522707d96e9584349a5bf0d51 Mon Sep 17 00:00:00 2001 From: PaulVMo Date: Thu, 15 Jul 2021 09:24:26 -0500 Subject: [PATCH] HIP-28 support - add consensus reward grace period --- .../v1/blockchain_txn_vars_v1.erl | 2 +- .../v2/blockchain_txn_rewards_v2.erl | 61 ++++++++++++++++++- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/transactions/v1/blockchain_txn_vars_v1.erl b/src/transactions/v1/blockchain_txn_vars_v1.erl index 737fd285ca..766ebce82a 100644 --- a/src/transactions/v1/blockchain_txn_vars_v1.erl +++ b/src/transactions/v1/blockchain_txn_vars_v1.erl @@ -987,7 +987,7 @@ validate_var(?poc_reward_decay_rate, Value) -> validate_float(Value, "poc_reward_decay_rate", 0.0, 1.0); validate_var(?reward_version, Value) -> case Value of - N when is_integer(N), N >= 1, N =< 5 -> + N when is_integer(N), N >= 1, N =< 6 -> ok; _ -> throw({error, {invalid_reward_version, Value}}) diff --git a/src/transactions/v2/blockchain_txn_rewards_v2.erl b/src/transactions/v2/blockchain_txn_rewards_v2.erl index 8923630b5d..f780387323 100644 --- a/src/transactions/v2/blockchain_txn_rewards_v2.erl +++ b/src/transactions/v2/blockchain_txn_rewards_v2.erl @@ -277,10 +277,18 @@ calculate_rewards_metadata(Start, End, Chain) -> Results0 = fold_blocks_for_rewards(Start, End, Chain, Vars, Ledger, AccInit), - %% Forcing calculation of the EpochReward amount for the CG to always + %% Prior to HIP 28 (reward_version <6), force EpochReward amount for the CG to always %% be around ElectionInterval (30 blocks) so that there is less incentive - %% to stay in the consensus group - ConsensusEpochReward = calculate_epoch_reward(1, Start, End, Ledger), + %% to stay in the consensus group. With HIP 28, relax that to be up to election_interval + + %% election_retry_interval to allow for time for election to complete. + ConsensusEpochReward = + case maps:get(reward_version,Vars) of + RewardVersion when RewardVersion >= 6 -> + calculate_consensus_epoch_reward(Start, End, Vars); + _ -> + calculate_epoch_reward(1, Start, End, Ledger) + end, + Vars1 = Vars#{ consensus_epoch_reward => ConsensusEpochReward }, Results = finalize_reward_calculations(Results0, Ledger, Vars1), @@ -667,6 +675,16 @@ calculate_epoch_reward(Version, Start, End, Ledger) -> -spec calculate_epoch_reward(pos_integer(), pos_integer(), pos_integer(), pos_integer(), pos_integer(), pos_integer()) -> float(). +calculate_epoch_reward(Version, Start, End, BlockTime0, _ElectionInterval, MonthlyReward) when Version >= 6 -> + BlockTime1 = (BlockTime0/1000), + % Convert to blocks per min + BlockPerMin = 60/BlockTime1, + % Convert to blocks per hour + BlockPerHour = BlockPerMin*60, + % Calculate election interval in blocks + ElectionInterval = End - Start + 1, % epoch is inclusive of start and end + ElectionPerHour = BlockPerHour/ElectionInterval, + MonthlyReward/30/24/ElectionPerHour; calculate_epoch_reward(Version, Start, End, BlockTime0, _ElectionInterval, MonthlyReward) when Version >= 2 -> BlockTime1 = (BlockTime0/1000), % Convert to blocks per min @@ -687,6 +705,24 @@ calculate_epoch_reward(_Version, _Start, _End, BlockTime0, ElectionInterval, Mon ElectionPerHour = BlockPerHour/ElectionInterval, MonthlyReward/30/24/ElectionPerHour. + + +-spec calculate_consensus_epoch_reward(pos_integer(), pos_integer(), reward_vars()) -> float(). +calculate_consensus_epoch_reward(Start, End, #{ block_time := BlockTime0, + election_interval := ElectionInterval, + election_restart_interval := ElectionRestartInterval, + monthly_reward := MonthlyReward }) -> + + BlockTime1 = (BlockTime0/1000), + % Convert to blocks per min + BlockPerMin = 60/BlockTime1, + % Convert to blocks per month + BlockPerMonth = BlockPerMin*60*24*30, + % Calculate epoch length in blocks, cap at election interval + grace period + EpochLength = erlang:min(End - Start + 1, ElectionInterval + ElectionRestartInterval), + MonthlyReward/BlockPerMonth*EpochLength. + + -spec consensus_members_rewards(blockchain_ledger_v1:ledger(), reward_vars(), non_neg_integer()) -> rewards_map(). @@ -1819,4 +1855,23 @@ common_poc_vars() -> ?poc_v5_target_prob_randomness_wt => 0.0 }. + +hip28_calc_test() -> + % set test vars such that rewards are 1 per block + Vars = #{ block_time => 60000, + election_interval => 30, + election_restart_interval => 5, + monthly_reward => 43200, + reward_version => 6 }, + ?assertEqual(30.0, calculate_consensus_epoch_reward(1,30,Vars)), + ?assertEqual(35.0, calculate_consensus_epoch_reward(1,50,Vars)). + +consensus_epoch_reward_test() -> + % using test values such that reward is 1 per block + % should always return the election interval as the answer + ?assertEqual(30.0,calculate_epoch_reward(1,1,25,60000,30,43200)), + + % more than 30 blocks should return 30 + ?assertEqual(30.0,calculate_epoch_reward(1,1,50,60000,30,43200)). + -endif.