diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 6faf486d34..1f85d79637 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -165,14 +165,16 @@ func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) ab // application updates every end block // nolint: unparam func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { - tags := gov.EndBlocker(ctx, app.govKeeper) - validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper) // distribute rewards distr.EndBlocker(ctx, app.distrKeeper) + tags := gov.EndBlocker(ctx, app.govKeeper) + validatorUpdates := stake.EndBlocker(ctx, app.stakeKeeper) + // Add these new validators to the addr -> pubkey map. app.slashingKeeper.AddValidators(ctx, validatorUpdates) + return abci.ResponseEndBlock{ ValidatorUpdates: validatorUpdates, Tags: tags, diff --git a/docs/spec/distribution/end_block.md b/docs/spec/distribution/end_block.md index 2b74cd3e90..7f54ee9723 100644 --- a/docs/spec/distribution/end_block.md +++ b/docs/spec/distribution/end_block.md @@ -1,7 +1,7 @@ # End Block At each endblock, the fees received are allocated to the proposer, community fund, -and pool. When the validator is the proposer of the round, that +and global pool. When the validator is the proposer of the round, that validator (and their delegators) receives between 1% and 5% of fee rewards, the reserve community tax is then charged, then the remainder is distributed proportionally by voting power to all bonded validators independent of whether diff --git a/docs/spec/distribution/state.md b/docs/spec/distribution/state.md index 0909ac7584..576f5390ba 100644 --- a/docs/spec/distribution/state.md +++ b/docs/spec/distribution/state.md @@ -42,7 +42,7 @@ Validator distribution information for the relevant validator is updated each ti ```golang type ValidatorDistInfo struct { - FewPoolWithdrawalHeight int64 // last height this validator withdrew from the global fee pool + FeePoolWithdrawalHeight int64 // last height this validator withdrew from the global fee pool Pool DecCoins // rewards owed to delegators, commission has already been charged (includes proposer reward) PoolCommission DecCoins // commission collected by this validator (pending withdrawal) diff --git a/x/distribution/abci_app.go b/x/distribution/abci_app.go index e4a90fa5fc..2ac2c57c63 100644 --- a/x/distribution/abci_app.go +++ b/x/distribution/abci_app.go @@ -13,13 +13,21 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k keeper.Keeper) k.SetProposerConsAddr(ctx, consAddr) // determine the total number of signed power - sumPrecommitPower := int64(0) + totalPower, sumPrecommitPower := int64(0), int64(0) for _, voteInfo := range req.LastCommitInfo.GetVotes() { + totalPower += voteInfo.Validator.Power if voteInfo.SignedLastBlock { sumPrecommitPower += voteInfo.Validator.Power } } - k.SetSumPrecommitPower(ctx, sumPrecommitPower) + + if totalPower == 0 { + k.SetPercentPrecommitVotes(ctx, sdk.ZeroDec()) + return + } + + percentPrecommitVotes := sdk.NewDec(sumPrecommitPower).Quo(sdk.NewDec(totalPower)) + k.SetPercentPrecommitVotes(ctx, percentPrecommitVotes) } // allocate fees diff --git a/x/distribution/keeper/allocation.go b/x/distribution/keeper/allocation.go index d80a6aac38..545285ae7e 100644 --- a/x/distribution/keeper/allocation.go +++ b/x/distribution/keeper/allocation.go @@ -11,12 +11,6 @@ import ( func (k Keeper) AllocateFees(ctx sdk.Context) { ctx.Logger().With("module", "x/distribution").Error(fmt.Sprintf("allocation height: %v", ctx.BlockHeight())) - // if there is no power in the system nothing should be allocated - bondedTokens := k.stakeKeeper.TotalPower(ctx).TruncateInt() - if bondedTokens.IsZero() { - return - } - // get the proposer of this block proposerConsAddr := k.GetProposerConsAddr(ctx) proposerValidator := k.stakeKeeper.ValidatorByConsAddr(ctx, proposerConsAddr) @@ -28,20 +22,14 @@ func (k Keeper) AllocateFees(ctx sdk.Context) { feesCollectedDec := types.NewDecCoins(feesCollected) // allocated rewards to proposer - sumPowerPrecommitValidators := k.GetSumPrecommitPower(ctx) - percentVoting := sdk.NewDec(sumPowerPrecommitValidators).QuoInt(bondedTokens) + percentVotes := k.GetPercentPrecommitVotes(ctx) - // rare edge case for rounding tendermint power vs bonded decimal power - if percentVoting.GT(sdk.OneDec()) { - percentVoting = sdk.OneDec() - } - - proposerMultiplier := sdk.NewDecWithPrec(1, 2).Add(sdk.NewDecWithPrec(4, 2).Mul(percentVoting)) + proposerMultiplier := sdk.NewDecWithPrec(1, 2).Add(sdk.NewDecWithPrec(4, 2).Mul(percentVotes)) proposerReward := feesCollectedDec.MulDec(proposerMultiplier) // apply commission commission := proposerReward.MulDec(proposerValidator.GetCommission()) - remaining := proposerReward.MulDec(sdk.OneDec().Sub(proposerValidator.GetCommission())) + remaining := proposerReward.Minus(commission) proposerDist.PoolCommission = proposerDist.PoolCommission.Plus(commission) proposerDist.Pool = proposerDist.Pool.Plus(remaining) diff --git a/x/distribution/keeper/allocation_test.go b/x/distribution/keeper/allocation_test.go index e1da170fd8..62c3e2d661 100644 --- a/x/distribution/keeper/allocation_test.go +++ b/x/distribution/keeper/allocation_test.go @@ -42,7 +42,7 @@ func TestAllocateFeesBasic(t *testing.T) { fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, totalPower) + keeper.SetPercentPrecommitVotes(ctx, sdk.OneDec()) keeper.AllocateFees(ctx) // verify that these fees have been received by the feePool @@ -68,7 +68,7 @@ func TestAllocateFeesWithCommunityTax(t *testing.T) { feeInputs := sdk.NewInt(100) fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, totalPower) + keeper.SetPercentPrecommitVotes(ctx, sdk.OneDec()) keeper.AllocateFees(ctx) // verify that these fees have been received by the feePool @@ -95,7 +95,7 @@ func TestAllocateFeesWithPartialPrecommitPower(t *testing.T) { feeInputs := sdk.NewInt(100) fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, 25) // 25% precommit power + keeper.SetPercentPrecommitVotes(ctx, sdk.NewDecWithPrec(25, 2)) keeper.AllocateFees(ctx) // verify that these fees have been received by the feePool diff --git a/x/distribution/keeper/delegation_test.go b/x/distribution/keeper/delegation_test.go index 4319bf280c..3eecfafdd2 100644 --- a/x/distribution/keeper/delegation_test.go +++ b/x/distribution/keeper/delegation_test.go @@ -26,14 +26,12 @@ func TestWithdrawDelegationRewardBasic(t *testing.T) { amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom) require.Equal(t, int64(90), amt.Int64()) - totalPower := int64(20) - // allocate 100 denom of fees feeInputs := sdk.NewInt(100) fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, totalPower) + keeper.SetPercentPrecommitVotes(ctx, sdk.OneDec()) keeper.AllocateFees(ctx) // withdraw delegation @@ -64,14 +62,12 @@ func TestWithdrawDelegationRewardWithCommission(t *testing.T) { amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom) require.Equal(t, int64(90), amt.Int64()) - totalPower := int64(20) - // allocate 100 denom of fees feeInputs := sdk.NewInt(100) fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, totalPower) + keeper.SetPercentPrecommitVotes(ctx, sdk.OneDec()) keeper.AllocateFees(ctx) // withdraw delegation @@ -108,14 +104,12 @@ func TestWithdrawDelegationRewardTwoDelegators(t *testing.T) { amt = accMapper.GetAccount(ctx, delAddr2).GetCoins().AmountOf(denom) require.Equal(t, int64(80), amt.Int64()) - totalPower := int64(40) - // allocate 100 denom of fees feeInputs := sdk.NewInt(100) fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, totalPower) + keeper.SetPercentPrecommitVotes(ctx, sdk.OneDec()) keeper.AllocateFees(ctx) // delegator 1 withdraw delegation @@ -154,14 +148,12 @@ func TestWithdrawDelegationRewardTwoDelegatorsUneven(t *testing.T) { amt = accMapper.GetAccount(ctx, delAddr2).GetCoins().AmountOf(denom) require.Equal(t, int64(90), amt.Int64()) - totalPower := int64(30) - // allocate 100 denom of fees feeInputs := sdk.NewInt(90) fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, totalPower) + keeper.SetPercentPrecommitVotes(ctx, sdk.OneDec()) keeper.AllocateFees(ctx) ctx = ctx.WithBlockHeight(1) @@ -177,7 +169,7 @@ func TestWithdrawDelegationRewardTwoDelegatorsUneven(t *testing.T) { fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, totalPower) + keeper.SetPercentPrecommitVotes(ctx, sdk.OneDec()) keeper.AllocateFees(ctx) ctx = ctx.WithBlockHeight(2) @@ -240,17 +232,14 @@ func TestWithdrawDelegationRewardsAll(t *testing.T) { // validator 1: 10 (self) + 10 (delegator) = 20 // validator 2: 50 (self) + 20 (delegator) = 70 // validator 3: 40 (self) + 30 (delegator) = 70 - // // grand total: 160 - totalPower := int64(160) - // allocate 100 denom of fees feeInputs := sdk.NewInt(1000) fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, totalPower) + keeper.SetPercentPrecommitVotes(ctx, sdk.OneDec()) keeper.AllocateFees(ctx) // withdraw delegation diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index bedda08bfb..74d05842c9 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -82,23 +82,23 @@ func (k Keeper) SetProposerConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) { //______________________________________________________________________ // set the proposer public key for this block -func (k Keeper) GetSumPrecommitPower(ctx sdk.Context) (sumPrecommitPower int64) { +func (k Keeper) GetPercentPrecommitVotes(ctx sdk.Context) (percentPrecommitVotes sdk.Dec) { tstore := ctx.KVStore(k.storeTKey) - b := tstore.Get(SumPrecommitPowerKey) + b := tstore.Get(PercentPrecommitVotesKey) if b == nil { panic("Proposer cons address was likely not set in begin block") } - k.cdc.MustUnmarshalBinary(b, &sumPrecommitPower) + k.cdc.MustUnmarshalBinary(b, &percentPrecommitVotes) return } // get the proposer public key for this block -func (k Keeper) SetSumPrecommitPower(ctx sdk.Context, sumPrecommitPower int64) { +func (k Keeper) SetPercentPrecommitVotes(ctx sdk.Context, percentPrecommitVotes sdk.Dec) { tstore := ctx.KVStore(k.storeTKey) - b := k.cdc.MustMarshalBinary(sumPrecommitPower) - tstore.Set(SumPrecommitPowerKey, b) + b := k.cdc.MustMarshalBinary(percentPrecommitVotes) + tstore.Set(PercentPrecommitVotesKey, b) } //______________________________________________________________________ diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index 2a188bae36..b2ebb6581c 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -16,12 +16,13 @@ func TestSetGetProposerConsAddr(t *testing.T) { require.True(t, res.Equals(valConsAddr1), "expected: %v got: %v", valConsAddr1.String(), res.String()) } -func TestSetGetSumPrecommitPower(t *testing.T) { +func TestSetGetPercentPrecommitVotes(t *testing.T) { ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 0) - keeper.SetSumPrecommitPower(ctx, 333) - res := keeper.GetSumPrecommitPower(ctx) - require.Equal(t, int64(333), res) + someDec := sdk.NewDec(333) + keeper.SetPercentPrecommitVotes(ctx, someDec) + res := keeper.GetPercentPrecommitVotes(ctx) + require.True(sdk.DecEq(t, someDec, res)) } func TestSetGetCommunityTax(t *testing.T) { diff --git a/x/distribution/keeper/key.go b/x/distribution/keeper/key.go index bd24bff031..3c667e7083 100644 --- a/x/distribution/keeper/key.go +++ b/x/distribution/keeper/key.go @@ -12,8 +12,8 @@ var ( DelegatorWithdrawInfoKey = []byte{0x03} // prefix for each key to a delegator withdraw info // transient - ProposerKey = []byte{0x00} // key for storing the proposer operator address - SumPrecommitPowerKey = []byte{0x01} // key for storing the power of the precommit validators + ProposerKey = []byte{0x00} // key for storing the proposer operator address + PercentPrecommitVotesKey = []byte{0x01} // key for storing the power of the precommit validators ) // nolint diff --git a/x/distribution/keeper/validator_test.go b/x/distribution/keeper/validator_test.go index 7dd79805e2..bdac19b93f 100644 --- a/x/distribution/keeper/validator_test.go +++ b/x/distribution/keeper/validator_test.go @@ -19,14 +19,12 @@ func TestWithdrawValidatorRewardsAllNoDelegator(t *testing.T) { require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) _ = sk.ApplyAndReturnValidatorSetUpdates(ctx) - totalPower := int64(10) - // allocate 100 denom of fees feeInputs := sdk.NewInt(100) fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, totalPower) + keeper.SetPercentPrecommitVotes(ctx, sdk.OneDec()) keeper.AllocateFees(ctx) // withdraw self-delegation reward @@ -55,14 +53,12 @@ func TestWithdrawValidatorRewardsAllDelegatorNoCommission(t *testing.T) { amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom) require.Equal(t, int64(90), amt.Int64()) - totalPower := int64(20) - // allocate 100 denom of fees feeInputs := sdk.NewInt(100) fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, totalPower) + keeper.SetPercentPrecommitVotes(ctx, sdk.OneDec()) keeper.AllocateFees(ctx) // withdraw self-delegation reward @@ -93,14 +89,12 @@ func TestWithdrawValidatorRewardsAllDelegatorWithCommission(t *testing.T) { amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom) require.Equal(t, int64(90), amt.Int64()) - totalPower := int64(20) - // allocate 100 denom of fees feeInputs := sdk.NewInt(100) fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, totalPower) + keeper.SetPercentPrecommitVotes(ctx, sdk.OneDec()) keeper.AllocateFees(ctx) // withdraw validator reward @@ -137,14 +131,12 @@ func TestWithdrawValidatorRewardsAllMultipleValidator(t *testing.T) { _ = sk.ApplyAndReturnValidatorSetUpdates(ctx) - totalPower := int64(100) - // allocate 100 denom of fees feeInputs := sdk.NewInt(1000) fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, totalPower) + keeper.SetPercentPrecommitVotes(ctx, sdk.OneDec()) keeper.AllocateFees(ctx) // withdraw validator reward @@ -187,14 +179,12 @@ func TestWithdrawValidatorRewardsAllMultipleDelegator(t *testing.T) { amt = accMapper.GetAccount(ctx, delAddr2).GetCoins().AmountOf(denom) require.Equal(t, int64(80), amt.Int64()) - totalPower := int64(40) - // allocate 100 denom of fees feeInputs := sdk.NewInt(100) fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) keeper.SetProposerConsAddr(ctx, valConsAddr1) - keeper.SetSumPrecommitPower(ctx, totalPower) + keeper.SetPercentPrecommitVotes(ctx, sdk.OneDec()) keeper.AllocateFees(ctx) // withdraw validator reward