Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

testing: add testing for rewards rate calculation #3336

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions data/bookkeeping/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,3 +461,65 @@ func TestInitialRewardsRateCalculation(t *testing.T) {
consensusParams.InitialRewardsRateCalculation = true
require.True(t, runTest())
}

func performRewardsRateCalculation(
t *testing.T, consensusParams config.ConsensusParams,
curRewardsState RewardsState,
incentivePoolBalance uint64, totalRewardUnits uint64, startingRound uint64) {
require.GreaterOrEqual(t, incentivePoolBalance, consensusParams.MinBalance)

for rnd := startingRound; rnd < startingRound+uint64(consensusParams.RewardsRateRefreshInterval)*3; rnd++ {
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(nextRewardState.RewardsLevel, curRewardsState.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)

require.GreaterOrEqual(t, incentivePoolBalance, consensusParams.MinBalance)
// prepare for the next iteration
curRewardsState = nextRewardState
}
}

// TestInitialRewardsRateCalculationRealValues performs a similar to test for initial rewards calculations but uses
// real values taken from mainnet
func TestInitialRewardsRateCalculationRealValues(t *testing.T) {
partitiontest.PartitionTest(t)

tests := []struct {
name string
rewardsRate uint64
rewardsLevel uint64
rewardsResidue uint64
rewardsRecalculationRound basics.Round
incentivePoolBalance uint64
totalRewardUnits uint64
startingRound uint64
}{
// Real values gathered from mainnet
{"1", 0, 215332, 0, 18500000, config.Consensus[protocol.ConsensusCurrentVersion].MinBalance, 6756334087, 18063999},
{"2", 24000000, 215332, 545321700, 18500000, 10464550021728, 6756334087, 18063999},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that NextRewardsState() logs overflow errors. Did you collect all these parameters atomically?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Under /ledger/internal/eval.go:529 I logged all parameters needed on a node that was sync'd with mainnet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have ideas why NextRewardsState() logs overflow errors?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't particularly, they showed up after I changed the round count to be multiplied by 3

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there is one issue in the test and one issue in the code.

In the test, the parameters {"2", 24000000, 215332, 545321700, 18500000, 10464550021728, 6756334087, are the ones calculated after round 18063999 is processed. However, the first time NextRewardsState() is called, it is given nextRound = 18063999. It should be one higher.

In the code at https://github.com/AlgoStephenAkiki/go-algorand/blob/feature/3284-test-rewards-rate-calculation/data/bookkeeping/block.go#L321 RewardsRate should be taken from res, not s.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you examine the block headers from mainnet, find the corresponding rounds and verify the above numbers are correct ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was wrong about the test code issue, the parameters are for given round - 1. However, the rewards residue for test "4" seems wrong.

{"3", 24000000, 215332, 521321700, 18500000, 10464550021728, 6756334078, 18063998},
{"4", 24000000, 215332, 401321700, 18500000, 10464550021728, 6756334079, 18063994},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
consensusParams := config.Consensus[protocol.ConsensusCurrentVersion]

curRewardsState := RewardsState{
RewardsLevel: test.rewardsLevel,
RewardsResidue: test.rewardsResidue,
RewardsRecalculationRound: test.rewardsRecalculationRound,
RewardsRate: test.rewardsRate,
}

performRewardsRateCalculation(t, consensusParams, curRewardsState, test.incentivePoolBalance, test.totalRewardUnits, test.startingRound)
})
}
}