From ab04d760f0e0cd5acc3db178aa7d3c08cb3023a6 Mon Sep 17 00:00:00 2001 From: Tsachi Herman Date: Fri, 12 Feb 2021 16:39:33 -0500 Subject: [PATCH 1/7] Fix reward pool min balance calculation --- config/consensus.go | 6 +++++ data/bookkeeping/block.go | 19 ++++++++++++-- data/bookkeeping/block_test.go | 48 ++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/config/consensus.go b/config/consensus.go index 948b1c5760..374fe6b7c1 100644 --- a/config/consensus.go +++ b/config/consensus.go @@ -345,6 +345,9 @@ type ConsensusParams struct { // EnableAssetCloseAmount adds an extra field to the ApplyData. The field contains the amount of the remaining // asset that were sent to the close-to address. EnableAssetCloseAmount bool + + // update the rewards per round calculation to ensure we safely maintain a minimum balance in the reward pool + RewardPoolMinBalance bool } // PaysetCommitType enumerates possible ways for the block header to commit to @@ -865,6 +868,9 @@ func initConsensusProtocols() { vFuture.CompactCertWeightThreshold = (1 << 32) * 30 / 100 vFuture.CompactCertSecKQ = 128 + // enable the RewardPoolMinBalance fix + vFuture.RewardPoolMinBalance = true + Consensus[protocol.ConsensusFuture] = vFuture } diff --git a/data/bookkeeping/block.go b/data/bookkeeping/block.go index 149364f8e5..6cf4c56d3c 100644 --- a/data/bookkeeping/block.go +++ b/data/bookkeeping/block.go @@ -305,8 +305,23 @@ func (s RewardsState) NextRewardsState(nextRound basics.Round, nextProto config. var ot basics.OverflowTracker rewardsWithResidue := ot.Add(s.RewardsRate, s.RewardsResidue) - nextRewardLevel := ot.Add(s.RewardsLevel, rewardsWithResidue/totalRewardUnits) - nextResidue := rewardsWithResidue % totalRewardUnits + var nextRewardLevel uint64 + var nextResidue uint64 + if nextProto.RewardPoolMinBalance { + if rewardsWithResidue >= nextProto.MinBalance { + rewardsWithResidue = rewardsWithResidue - nextProto.MinBalance + nextRewardLevel = ot.Add(s.RewardsLevel, rewardsWithResidue/totalRewardUnits) + nextResidue = nextProto.MinBalance + (rewardsWithResidue % totalRewardUnits) + } else { + // we don't have enough money, so keep previous level + nextRewardLevel = s.RewardsLevel + // and accumulate the rewards. + nextResidue = rewardsWithResidue + } + } else { + nextRewardLevel = ot.Add(s.RewardsLevel, rewardsWithResidue/totalRewardUnits) + nextResidue = rewardsWithResidue % totalRewardUnits + } if ot.Overflowed { logging.Base().Errorf("could not compute next reward level (current level %v, adding %v MicroAlgos in total, number of reward units %v) using old level", diff --git a/data/bookkeeping/block_test.go b/data/bookkeeping/block_test.go index c3ab8a8ec5..caaf4dd02c 100644 --- a/data/bookkeeping/block_test.go +++ b/data/bookkeeping/block_test.go @@ -375,3 +375,51 @@ func TestDecodeMalformedSignedTxn(t *testing.T) { _, _, err = b.DecodeSignedTxn(txib2) require.Error(t, err) } + +func TestRewardPoolMinBalance(t *testing.T) { + consensusParams := config.Consensus[protocol.ConsensusCurrentVersion] + + runTest := func() bool { + incentivePoolBalance := uint64(125000000000000) + totalRewardUnits := uint64(10000000000) + require.GreaterOrEqual(t, incentivePoolBalance, consensusParams.MinBalance) + + rs := RewardsState{ + RewardsLevel: 0, + RewardsRate: incentivePoolBalance / uint64(consensusParams.RewardsRateRefreshInterval), + RewardsResidue: 0, + RewardsRecalculationRound: basics.Round(consensusParams.RewardsRateRefreshInterval), + } + for rnd := 1; rnd < int(consensusParams.RewardsRateRefreshInterval+2); rnd++ { + newrs := rs.NextRewardsState(basics.Round(rnd), consensusParams, basics.MicroAlgos{Raw: incentivePoolBalance}, totalRewardUnits) + // adjust the incentive pool balance + var ot basics.OverflowTracker + + // get number of rewards per unit + rewardsPerUnit := ot.Sub(newrs.RewardsLevel, rs.RewardsLevel) + require.False(t, ot.Overflowed) + + // subtract the total dispersed funds from the pool balance + incentivePoolBalance = ot.Sub(incentivePoolBalance, ot.Mul(totalRewardUnits, rewardsPerUnit)) + require.False(t, ot.Overflowed) + + // make sure the pool retain at least the min balance + ot.Sub(incentivePoolBalance, consensusParams.MinBalance) + if ot.Overflowed { + return false + } + + // prepare for the next iteration + rs = newrs + } + return true + } + + // test expected failuire + consensusParams.RewardPoolMinBalance = false + require.False(t, runTest()) + + // test expected success + consensusParams.RewardPoolMinBalance = true + require.True(t, runTest()) +} From c4e1269f9350e94892e0fe72d31e37745b4bb230 Mon Sep 17 00:00:00 2001 From: Tsachi Herman Date: Fri, 12 Feb 2021 16:48:12 -0500 Subject: [PATCH 2/7] better comments. --- data/bookkeeping/block.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/data/bookkeeping/block.go b/data/bookkeeping/block.go index 6cf4c56d3c..208be7c8ac 100644 --- a/data/bookkeeping/block.go +++ b/data/bookkeeping/block.go @@ -309,8 +309,11 @@ func (s RewardsState) NextRewardsState(nextRound basics.Round, nextProto config. var nextResidue uint64 if nextProto.RewardPoolMinBalance { if rewardsWithResidue >= nextProto.MinBalance { + // remove the min balance out, so that we won't be spending it. rewardsWithResidue = rewardsWithResidue - nextProto.MinBalance + // calculate the new effective rewards level nextRewardLevel = ot.Add(s.RewardsLevel, rewardsWithResidue/totalRewardUnits) + // calculate the next residue by figuring how many algos were not included in the previous level(s), and add back the min balance that we kept aside. nextResidue = nextProto.MinBalance + (rewardsWithResidue % totalRewardUnits) } else { // we don't have enough money, so keep previous level From f8e36606e57aeac64482205a5d03ea03617bd4c1 Mon Sep 17 00:00:00 2001 From: Tsachi Herman Date: Fri, 12 Feb 2021 16:54:27 -0500 Subject: [PATCH 3/7] Better testing code styles --- data/bookkeeping/block_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/data/bookkeeping/block_test.go b/data/bookkeeping/block_test.go index caaf4dd02c..13e2462312 100644 --- a/data/bookkeeping/block_test.go +++ b/data/bookkeeping/block_test.go @@ -376,6 +376,8 @@ func TestDecodeMalformedSignedTxn(t *testing.T) { require.Error(t, err) } +// TestRewardPoolMinBalance perform positive and negative testing for the RewardPoolMinBalance fix by +// running the rounds in the same way eval() is executing them over RewardsRateRefreshInterval rounds. func TestRewardPoolMinBalance(t *testing.T) { consensusParams := config.Consensus[protocol.ConsensusCurrentVersion] @@ -384,19 +386,19 @@ func TestRewardPoolMinBalance(t *testing.T) { totalRewardUnits := uint64(10000000000) require.GreaterOrEqual(t, incentivePoolBalance, consensusParams.MinBalance) - rs := RewardsState{ + curRewardsState := RewardsState{ RewardsLevel: 0, RewardsRate: incentivePoolBalance / uint64(consensusParams.RewardsRateRefreshInterval), RewardsResidue: 0, RewardsRecalculationRound: basics.Round(consensusParams.RewardsRateRefreshInterval), } for rnd := 1; rnd < int(consensusParams.RewardsRateRefreshInterval+2); rnd++ { - newrs := rs.NextRewardsState(basics.Round(rnd), consensusParams, basics.MicroAlgos{Raw: incentivePoolBalance}, totalRewardUnits) + nextRewardState := curRewardsState.NextRewardsState(basics.Round(rnd), consensusParams, basics.MicroAlgos{Raw: incentivePoolBalance}, totalRewardUnits) // adjust the incentive pool balance var ot basics.OverflowTracker // get number of rewards per unit - rewardsPerUnit := ot.Sub(newrs.RewardsLevel, rs.RewardsLevel) + rewardsPerUnit := ot.Sub(nextRewardState.RewardsLevel, curRewardsState.RewardsLevel) require.False(t, ot.Overflowed) // subtract the total dispersed funds from the pool balance @@ -410,7 +412,7 @@ func TestRewardPoolMinBalance(t *testing.T) { } // prepare for the next iteration - rs = newrs + curRewardsState = nextRewardState } return true } From 7659103876f0a9b1fe8acac8b3f98f2b0e8de5d1 Mon Sep 17 00:00:00 2001 From: Tsachi Herman Date: Fri, 12 Feb 2021 17:54:51 -0500 Subject: [PATCH 4/7] update fix --- data/bookkeeping/block.go | 22 ++-------------------- data/bookkeeping/block_test.go | 3 +++ data/ledger.go | 4 ++++ ledger/ledger_test.go | 2 +- 4 files changed, 10 insertions(+), 21 deletions(-) diff --git a/data/bookkeeping/block.go b/data/bookkeeping/block.go index 208be7c8ac..149364f8e5 100644 --- a/data/bookkeeping/block.go +++ b/data/bookkeeping/block.go @@ -305,26 +305,8 @@ func (s RewardsState) NextRewardsState(nextRound basics.Round, nextProto config. var ot basics.OverflowTracker rewardsWithResidue := ot.Add(s.RewardsRate, s.RewardsResidue) - var nextRewardLevel uint64 - var nextResidue uint64 - if nextProto.RewardPoolMinBalance { - if rewardsWithResidue >= nextProto.MinBalance { - // remove the min balance out, so that we won't be spending it. - rewardsWithResidue = rewardsWithResidue - nextProto.MinBalance - // calculate the new effective rewards level - nextRewardLevel = ot.Add(s.RewardsLevel, rewardsWithResidue/totalRewardUnits) - // calculate the next residue by figuring how many algos were not included in the previous level(s), and add back the min balance that we kept aside. - nextResidue = nextProto.MinBalance + (rewardsWithResidue % totalRewardUnits) - } else { - // we don't have enough money, so keep previous level - nextRewardLevel = s.RewardsLevel - // and accumulate the rewards. - nextResidue = rewardsWithResidue - } - } else { - nextRewardLevel = ot.Add(s.RewardsLevel, rewardsWithResidue/totalRewardUnits) - nextResidue = rewardsWithResidue % totalRewardUnits - } + nextRewardLevel := ot.Add(s.RewardsLevel, rewardsWithResidue/totalRewardUnits) + nextResidue := rewardsWithResidue % totalRewardUnits if ot.Overflowed { logging.Base().Errorf("could not compute next reward level (current level %v, adding %v MicroAlgos in total, number of reward units %v) using old level", diff --git a/data/bookkeeping/block_test.go b/data/bookkeeping/block_test.go index 13e2462312..b0118c5d5b 100644 --- a/data/bookkeeping/block_test.go +++ b/data/bookkeeping/block_test.go @@ -392,6 +392,9 @@ func TestRewardPoolMinBalance(t *testing.T) { RewardsResidue: 0, RewardsRecalculationRound: basics.Round(consensusParams.RewardsRateRefreshInterval), } + if consensusParams.RewardPoolMinBalance == true { + curRewardsState.RewardsRate = (incentivePoolBalance - consensusParams.MinBalance) / uint64(consensusParams.RewardsRateRefreshInterval) + } for rnd := 1; rnd < int(consensusParams.RewardsRateRefreshInterval+2); rnd++ { nextRewardState := curRewardsState.NextRewardsState(basics.Round(rnd), consensusParams, basics.MicroAlgos{Raw: incentivePoolBalance}, totalRewardUnits) // adjust the incentive pool balance diff --git a/data/ledger.go b/data/ledger.go index 204de12387..4c7d9b5190 100644 --- a/data/ledger.go +++ b/data/ledger.go @@ -94,6 +94,10 @@ func makeGenesisBlock(proto protocol.ConsensusVersion, genesisBal GenesisBalance RewardsRecalculationRound: basics.Round(params.RewardsRateRefreshInterval), } + if params.RewardPoolMinBalance { + genesisRewardsState.RewardsRate = (incentivePoolBalanceAtGenesis.Raw - params.MinBalance) / uint64(params.RewardsRateRefreshInterval) + } + genesisProtoState := bookkeeping.UpgradeState{ CurrentProtocol: proto, } diff --git a/ledger/ledger_test.go b/ledger/ledger_test.go index 0f5a6fe4da..268c5a7124 100644 --- a/ledger/ledger_test.go +++ b/ledger/ledger_test.go @@ -92,7 +92,7 @@ func testGenerateInitState(tb testing.TB, proto protocol.ConsensusVersion) (gene initAccounts[sinkAddr] = basics.MakeAccountData(basics.NotParticipating, basics.MicroAlgos{Raw: 7654321}) incentivePoolBalanceAtGenesis := initAccounts[poolAddr].MicroAlgos - initialRewardsPerRound := incentivePoolBalanceAtGenesis.Raw / uint64(params.RewardsRateRefreshInterval) + initialRewardsPerRound := (incentivePoolBalanceAtGenesis.Raw - params.MinBalance) / uint64(params.RewardsRateRefreshInterval) initBlock := bookkeeping.Block{ BlockHeader: bookkeeping.BlockHeader{ From 932b4f29ea9d2629eec732e1fe86b65612fc83dc Mon Sep 17 00:00:00 2001 From: Tsachi Herman Date: Fri, 12 Feb 2021 17:59:35 -0500 Subject: [PATCH 5/7] update test. --- data/ledger.go | 3 ++- ledger/ledger_test.go | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/data/ledger.go b/data/ledger.go index 4c7d9b5190..5aee0ccd30 100644 --- a/data/ledger.go +++ b/data/ledger.go @@ -89,13 +89,14 @@ func makeGenesisBlock(proto protocol.ConsensusVersion, genesisBal GenesisBalance FeeSink: genesisBal.feeSink, RewardsPool: genesisBal.rewardsPool, RewardsLevel: 0, - RewardsRate: incentivePoolBalanceAtGenesis.Raw / uint64(params.RewardsRateRefreshInterval), RewardsResidue: 0, RewardsRecalculationRound: basics.Round(params.RewardsRateRefreshInterval), } if params.RewardPoolMinBalance { genesisRewardsState.RewardsRate = (incentivePoolBalanceAtGenesis.Raw - params.MinBalance) / uint64(params.RewardsRateRefreshInterval) + } else { + genesisRewardsState.RewardsRate = incentivePoolBalanceAtGenesis.Raw / uint64(params.RewardsRateRefreshInterval) } genesisProtoState := bookkeeping.UpgradeState{ diff --git a/ledger/ledger_test.go b/ledger/ledger_test.go index 268c5a7124..31a749e1a3 100644 --- a/ledger/ledger_test.go +++ b/ledger/ledger_test.go @@ -92,7 +92,12 @@ func testGenerateInitState(tb testing.TB, proto protocol.ConsensusVersion) (gene initAccounts[sinkAddr] = basics.MakeAccountData(basics.NotParticipating, basics.MicroAlgos{Raw: 7654321}) incentivePoolBalanceAtGenesis := initAccounts[poolAddr].MicroAlgos - initialRewardsPerRound := (incentivePoolBalanceAtGenesis.Raw - params.MinBalance) / uint64(params.RewardsRateRefreshInterval) + var initialRewardsPerRound uint64 + if params.RewardPoolMinBalance { + initialRewardsPerRound = (incentivePoolBalanceAtGenesis.Raw - params.MinBalance) / uint64(params.RewardsRateRefreshInterval) + } else { + initialRewardsPerRound = incentivePoolBalanceAtGenesis.Raw / uint64(params.RewardsRateRefreshInterval) + } initBlock := bookkeeping.Block{ BlockHeader: bookkeeping.BlockHeader{ From f42aae661552c2f1d821d10e5a6f34ae63fe034b Mon Sep 17 00:00:00 2001 From: Tsachi Herman Date: Fri, 12 Feb 2021 18:24:56 -0500 Subject: [PATCH 6/7] use SubSaturate --- data/bookkeeping/block_test.go | 7 ++++--- data/ledger.go | 2 +- ledger/ledger_test.go | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/data/bookkeeping/block_test.go b/data/bookkeeping/block_test.go index b0118c5d5b..608d174a70 100644 --- a/data/bookkeeping/block_test.go +++ b/data/bookkeeping/block_test.go @@ -388,12 +388,13 @@ func TestRewardPoolMinBalance(t *testing.T) { curRewardsState := RewardsState{ RewardsLevel: 0, - RewardsRate: incentivePoolBalance / uint64(consensusParams.RewardsRateRefreshInterval), RewardsResidue: 0, RewardsRecalculationRound: basics.Round(consensusParams.RewardsRateRefreshInterval), } - if consensusParams.RewardPoolMinBalance == true { - curRewardsState.RewardsRate = (incentivePoolBalance - consensusParams.MinBalance) / uint64(consensusParams.RewardsRateRefreshInterval) + if consensusParams.RewardPoolMinBalance { + curRewardsState.RewardsRate = basics.SubSaturate(incentivePoolBalance, consensusParams.MinBalance) / uint64(consensusParams.RewardsRateRefreshInterval) + } else { + curRewardsState.RewardsRate = incentivePoolBalance / uint64(consensusParams.RewardsRateRefreshInterval) } for rnd := 1; rnd < int(consensusParams.RewardsRateRefreshInterval+2); rnd++ { nextRewardState := curRewardsState.NextRewardsState(basics.Round(rnd), consensusParams, basics.MicroAlgos{Raw: incentivePoolBalance}, totalRewardUnits) diff --git a/data/ledger.go b/data/ledger.go index 5aee0ccd30..b50c7ea150 100644 --- a/data/ledger.go +++ b/data/ledger.go @@ -94,7 +94,7 @@ func makeGenesisBlock(proto protocol.ConsensusVersion, genesisBal GenesisBalance } if params.RewardPoolMinBalance { - genesisRewardsState.RewardsRate = (incentivePoolBalanceAtGenesis.Raw - params.MinBalance) / uint64(params.RewardsRateRefreshInterval) + genesisRewardsState.RewardsRate = basics.SubSaturate(incentivePoolBalanceAtGenesis.Raw, params.MinBalance) / uint64(params.RewardsRateRefreshInterval) } else { genesisRewardsState.RewardsRate = incentivePoolBalanceAtGenesis.Raw / uint64(params.RewardsRateRefreshInterval) } diff --git a/ledger/ledger_test.go b/ledger/ledger_test.go index 31a749e1a3..54b211a03e 100644 --- a/ledger/ledger_test.go +++ b/ledger/ledger_test.go @@ -94,7 +94,7 @@ func testGenerateInitState(tb testing.TB, proto protocol.ConsensusVersion) (gene incentivePoolBalanceAtGenesis := initAccounts[poolAddr].MicroAlgos var initialRewardsPerRound uint64 if params.RewardPoolMinBalance { - initialRewardsPerRound = (incentivePoolBalanceAtGenesis.Raw - params.MinBalance) / uint64(params.RewardsRateRefreshInterval) + initialRewardsPerRound = basics.SubSaturate(incentivePoolBalanceAtGenesis.Raw, params.MinBalance) / uint64(params.RewardsRateRefreshInterval) } else { initialRewardsPerRound = incentivePoolBalanceAtGenesis.Raw / uint64(params.RewardsRateRefreshInterval) } From f208eecdbd1b1ab97bb328bb1f9a58795049697c Mon Sep 17 00:00:00 2001 From: Tsachi Herman Date: Fri, 12 Feb 2021 18:40:20 -0500 Subject: [PATCH 7/7] rename to InitialRewardsRateCalculation --- config/consensus.go | 8 ++++---- data/bookkeeping/block_test.go | 10 +++++----- data/ledger.go | 2 +- ledger/ledger_test.go | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/config/consensus.go b/config/consensus.go index 374fe6b7c1..64ef0a73a6 100644 --- a/config/consensus.go +++ b/config/consensus.go @@ -346,8 +346,8 @@ type ConsensusParams struct { // asset that were sent to the close-to address. EnableAssetCloseAmount bool - // update the rewards per round calculation to ensure we safely maintain a minimum balance in the reward pool - RewardPoolMinBalance bool + // update the initial rewards rate calculation to take the reward pool minimum balance into account + InitialRewardsRateCalculation bool } // PaysetCommitType enumerates possible ways for the block header to commit to @@ -868,8 +868,8 @@ func initConsensusProtocols() { vFuture.CompactCertWeightThreshold = (1 << 32) * 30 / 100 vFuture.CompactCertSecKQ = 128 - // enable the RewardPoolMinBalance fix - vFuture.RewardPoolMinBalance = true + // enable the InitialRewardsRateCalculation fix + vFuture.InitialRewardsRateCalculation = true Consensus[protocol.ConsensusFuture] = vFuture } diff --git a/data/bookkeeping/block_test.go b/data/bookkeeping/block_test.go index 608d174a70..4bce02f715 100644 --- a/data/bookkeeping/block_test.go +++ b/data/bookkeeping/block_test.go @@ -376,9 +376,9 @@ func TestDecodeMalformedSignedTxn(t *testing.T) { require.Error(t, err) } -// TestRewardPoolMinBalance perform positive and negative testing for the RewardPoolMinBalance fix by +// TestInitialRewardsRateCalculation perform positive and negative testing for the InitialRewardsRateCalculation fix by // running the rounds in the same way eval() is executing them over RewardsRateRefreshInterval rounds. -func TestRewardPoolMinBalance(t *testing.T) { +func TestInitialRewardsRateCalculation(t *testing.T) { consensusParams := config.Consensus[protocol.ConsensusCurrentVersion] runTest := func() bool { @@ -391,7 +391,7 @@ func TestRewardPoolMinBalance(t *testing.T) { RewardsResidue: 0, RewardsRecalculationRound: basics.Round(consensusParams.RewardsRateRefreshInterval), } - if consensusParams.RewardPoolMinBalance { + if consensusParams.InitialRewardsRateCalculation { curRewardsState.RewardsRate = basics.SubSaturate(incentivePoolBalance, consensusParams.MinBalance) / uint64(consensusParams.RewardsRateRefreshInterval) } else { curRewardsState.RewardsRate = incentivePoolBalance / uint64(consensusParams.RewardsRateRefreshInterval) @@ -422,10 +422,10 @@ func TestRewardPoolMinBalance(t *testing.T) { } // test expected failuire - consensusParams.RewardPoolMinBalance = false + consensusParams.InitialRewardsRateCalculation = false require.False(t, runTest()) // test expected success - consensusParams.RewardPoolMinBalance = true + consensusParams.InitialRewardsRateCalculation = true require.True(t, runTest()) } diff --git a/data/ledger.go b/data/ledger.go index b50c7ea150..9da66ac12c 100644 --- a/data/ledger.go +++ b/data/ledger.go @@ -93,7 +93,7 @@ func makeGenesisBlock(proto protocol.ConsensusVersion, genesisBal GenesisBalance RewardsRecalculationRound: basics.Round(params.RewardsRateRefreshInterval), } - if params.RewardPoolMinBalance { + if params.InitialRewardsRateCalculation { genesisRewardsState.RewardsRate = basics.SubSaturate(incentivePoolBalanceAtGenesis.Raw, params.MinBalance) / uint64(params.RewardsRateRefreshInterval) } else { genesisRewardsState.RewardsRate = incentivePoolBalanceAtGenesis.Raw / uint64(params.RewardsRateRefreshInterval) diff --git a/ledger/ledger_test.go b/ledger/ledger_test.go index 54b211a03e..114839c753 100644 --- a/ledger/ledger_test.go +++ b/ledger/ledger_test.go @@ -93,7 +93,7 @@ func testGenerateInitState(tb testing.TB, proto protocol.ConsensusVersion) (gene incentivePoolBalanceAtGenesis := initAccounts[poolAddr].MicroAlgos var initialRewardsPerRound uint64 - if params.RewardPoolMinBalance { + if params.InitialRewardsRateCalculation { initialRewardsPerRound = basics.SubSaturate(incentivePoolBalanceAtGenesis.Raw, params.MinBalance) / uint64(params.RewardsRateRefreshInterval) } else { initialRewardsPerRound = incentivePoolBalanceAtGenesis.Raw / uint64(params.RewardsRateRefreshInterval)