diff --git a/types/decimal.go b/types/decimal.go index a4d1e40ed..bd3f34075 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -241,6 +241,16 @@ func (d Dec) Quo(d2 Dec) Dec { return Dec{chopped} } +// quotient +func (d Dec) QuoInt(i Int) Dec { + mul := new(big.Int).Quo(d.Int, i.i) + + if mul.BitLen() > 255+DecimalPrecisionBits { + panic("Int overflow") + } + return Dec{mul} +} + func (d Dec) String() string { str := d.ToLeftPaddedWithDecimals(Precision) placement := len(str) - Precision diff --git a/x/distribution/abci_app.go b/x/distribution/abci_app.go index 0b634be87..e4a90fa5f 100644 --- a/x/distribution/abci_app.go +++ b/x/distribution/abci_app.go @@ -12,8 +12,14 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k keeper.Keeper) consAddr := sdk.ConsAddress(req.Header.ProposerAddress) k.SetProposerConsAddr(ctx, consAddr) - // XXX TODO actually calculate this - k.SetSumPrecommitPower(ctx, sdk.NewDec(1)) + // determine the total number of signed power + sumPrecommitPower := int64(0) + for _, voteInfo := range req.LastCommitInfo.GetVotes() { + if voteInfo.SignedLastBlock { + sumPrecommitPower += voteInfo.Validator.Power + } + } + k.SetSumPrecommitPower(ctx, sumPrecommitPower) } // allocate fees diff --git a/x/distribution/keeper/allocation.go b/x/distribution/keeper/allocation.go index 1acd3e730..d80a6aac3 100644 --- a/x/distribution/keeper/allocation.go +++ b/x/distribution/keeper/allocation.go @@ -12,7 +12,7 @@ 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) + bondedTokens := k.stakeKeeper.TotalPower(ctx).TruncateInt() if bondedTokens.IsZero() { return } @@ -29,8 +29,14 @@ func (k Keeper) AllocateFees(ctx sdk.Context) { // allocated rewards to proposer sumPowerPrecommitValidators := k.GetSumPrecommitPower(ctx) - proposerMultiplier := sdk.NewDecWithPrec(1, 2).Add(sdk.NewDecWithPrec(4, 2).Mul( - sumPowerPrecommitValidators).Quo(bondedTokens)) + percentVoting := sdk.NewDec(sumPowerPrecommitValidators).QuoInt(bondedTokens) + + // 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)) proposerReward := feesCollectedDec.MulDec(proposerMultiplier) // apply commission @@ -46,7 +52,7 @@ func (k Keeper) AllocateFees(ctx sdk.Context) { feePool.CommunityPool = feePool.CommunityPool.Plus(communityFunding) // set the global pool within the distribution module - poolReceived := feesCollectedDec.MulDec(sdk.OneDec().Sub(proposerMultiplier).Sub(communityTax)) + poolReceived := feesCollectedDec.Minus(proposerReward).Minus(communityFunding) feePool.Pool = feePool.Pool.Plus(poolReceived) k.SetValidatorDistInfo(ctx, proposerDist) diff --git a/x/distribution/keeper/allocation_test.go b/x/distribution/keeper/allocation_test.go index 773e3db06..e1da170fd 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, totalPowerDec) + keeper.SetSumPrecommitPower(ctx, totalPower) keeper.AllocateFees(ctx) // verify that these fees have been received by the feePool @@ -59,7 +59,6 @@ func TestAllocateFeesWithCommunityTax(t *testing.T) { //first make a validator totalPower := int64(10) - totalPowerDec := sdk.NewDec(totalPower) msgCreateValidator := stake.NewTestMsgCreateValidator(valOpAddr1, valConsPk1, totalPower) got := stakeHandler(ctx, msgCreateValidator) require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) @@ -69,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, totalPowerDec) + keeper.SetSumPrecommitPower(ctx, totalPower) keeper.AllocateFees(ctx) // verify that these fees have been received by the feePool @@ -86,8 +85,7 @@ func TestAllocateFeesWithPartialPrecommitPower(t *testing.T) { denom := sk.GetParams(ctx).BondDenom //first make a validator - totalPower := int64(10) - totalPowerDec := sdk.NewDec(totalPower) + totalPower := int64(100) msgCreateValidator := stake.NewTestMsgCreateValidator(valOpAddr1, valConsPk1, totalPower) got := stakeHandler(ctx, msgCreateValidator) require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) @@ -97,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, totalPowerDec.Mul(sdk.NewDecWithPrec(25, 2))) // 25% precommit power + keeper.SetSumPrecommitPower(ctx, 25) // 25% precommit power 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 b41245f3b..4319bf280 100644 --- a/x/distribution/keeper/delegation_test.go +++ b/x/distribution/keeper/delegation_test.go @@ -27,14 +27,13 @@ func TestWithdrawDelegationRewardBasic(t *testing.T) { require.Equal(t, int64(90), amt.Int64()) totalPower := int64(20) - totalPowerDec := sdk.NewDec(totalPower) // 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, totalPowerDec) + keeper.SetSumPrecommitPower(ctx, totalPower) keeper.AllocateFees(ctx) // withdraw delegation @@ -66,14 +65,13 @@ func TestWithdrawDelegationRewardWithCommission(t *testing.T) { require.Equal(t, int64(90), amt.Int64()) totalPower := int64(20) - totalPowerDec := sdk.NewDec(totalPower) // 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, totalPowerDec) + keeper.SetSumPrecommitPower(ctx, totalPower) keeper.AllocateFees(ctx) // withdraw delegation @@ -111,14 +109,13 @@ func TestWithdrawDelegationRewardTwoDelegators(t *testing.T) { require.Equal(t, int64(80), amt.Int64()) totalPower := int64(40) - totalPowerDec := sdk.NewDec(totalPower) // 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, totalPowerDec) + keeper.SetSumPrecommitPower(ctx, totalPower) keeper.AllocateFees(ctx) // delegator 1 withdraw delegation @@ -158,14 +155,13 @@ func TestWithdrawDelegationRewardTwoDelegatorsUneven(t *testing.T) { require.Equal(t, int64(90), amt.Int64()) totalPower := int64(30) - totalPowerDec := sdk.NewDec(totalPower) // 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, totalPowerDec) + keeper.SetSumPrecommitPower(ctx, totalPower) keeper.AllocateFees(ctx) ctx = ctx.WithBlockHeight(1) @@ -181,7 +177,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, totalPowerDec) + keeper.SetSumPrecommitPower(ctx, totalPower) keeper.AllocateFees(ctx) ctx = ctx.WithBlockHeight(2) @@ -248,14 +244,13 @@ func TestWithdrawDelegationRewardsAll(t *testing.T) { // grand total: 160 totalPower := int64(160) - totalPowerDec := sdk.NewDec(totalPower) // 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, totalPowerDec) + keeper.SetSumPrecommitPower(ctx, totalPower) keeper.AllocateFees(ctx) // withdraw delegation diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 6dd41e326..bedda08bf 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -82,7 +82,7 @@ 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 sdk.Dec) { +func (k Keeper) GetSumPrecommitPower(ctx sdk.Context) (sumPrecommitPower int64) { tstore := ctx.KVStore(k.storeTKey) b := tstore.Get(SumPrecommitPowerKey) @@ -95,7 +95,7 @@ func (k Keeper) GetSumPrecommitPower(ctx sdk.Context) (sumPrecommitPower sdk.Dec } // get the proposer public key for this block -func (k Keeper) SetSumPrecommitPower(ctx sdk.Context, sumPrecommitPower sdk.Dec) { +func (k Keeper) SetSumPrecommitPower(ctx sdk.Context, sumPrecommitPower int64) { tstore := ctx.KVStore(k.storeTKey) b := k.cdc.MustMarshalBinary(sumPrecommitPower) tstore.Set(SumPrecommitPowerKey, b) diff --git a/x/distribution/keeper/keeper_test.go b/x/distribution/keeper/keeper_test.go index ce9ceb807..2a188bae3 100644 --- a/x/distribution/keeper/keeper_test.go +++ b/x/distribution/keeper/keeper_test.go @@ -19,10 +19,9 @@ func TestSetGetProposerConsAddr(t *testing.T) { func TestSetGetSumPrecommitPower(t *testing.T) { ctx, _, keeper, _, _ := CreateTestInputDefault(t, false, 0) - someDec := sdk.NewDec(333) - keeper.SetSumPrecommitPower(ctx, someDec) + keeper.SetSumPrecommitPower(ctx, 333) res := keeper.GetSumPrecommitPower(ctx) - require.True(sdk.DecEq(t, someDec, res)) + require.Equal(t, int64(333), res) } func TestSetGetCommunityTax(t *testing.T) { diff --git a/x/distribution/keeper/validator_test.go b/x/distribution/keeper/validator_test.go index 32f5a2686..7dd79805e 100644 --- a/x/distribution/keeper/validator_test.go +++ b/x/distribution/keeper/validator_test.go @@ -20,14 +20,13 @@ func TestWithdrawValidatorRewardsAllNoDelegator(t *testing.T) { _ = sk.ApplyAndReturnValidatorSetUpdates(ctx) totalPower := int64(10) - totalPowerDec := sdk.NewDec(totalPower) // 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, totalPowerDec) + keeper.SetSumPrecommitPower(ctx, totalPower) keeper.AllocateFees(ctx) // withdraw self-delegation reward @@ -57,14 +56,13 @@ func TestWithdrawValidatorRewardsAllDelegatorNoCommission(t *testing.T) { require.Equal(t, int64(90), amt.Int64()) totalPower := int64(20) - totalPowerDec := sdk.NewDec(totalPower) // 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, totalPowerDec) + keeper.SetSumPrecommitPower(ctx, totalPower) keeper.AllocateFees(ctx) // withdraw self-delegation reward @@ -96,14 +94,13 @@ func TestWithdrawValidatorRewardsAllDelegatorWithCommission(t *testing.T) { require.Equal(t, int64(90), amt.Int64()) totalPower := int64(20) - totalPowerDec := sdk.NewDec(totalPower) // 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, totalPowerDec) + keeper.SetSumPrecommitPower(ctx, totalPower) keeper.AllocateFees(ctx) // withdraw validator reward @@ -141,14 +138,13 @@ func TestWithdrawValidatorRewardsAllMultipleValidator(t *testing.T) { _ = sk.ApplyAndReturnValidatorSetUpdates(ctx) totalPower := int64(100) - totalPowerDec := sdk.NewDec(totalPower) // 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, totalPowerDec) + keeper.SetSumPrecommitPower(ctx, totalPower) keeper.AllocateFees(ctx) // withdraw validator reward @@ -192,14 +188,13 @@ func TestWithdrawValidatorRewardsAllMultipleDelegator(t *testing.T) { require.Equal(t, int64(80), amt.Int64()) totalPower := int64(40) - totalPowerDec := sdk.NewDec(totalPower) // 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, totalPowerDec) + keeper.SetSumPrecommitPower(ctx, totalPower) keeper.AllocateFees(ctx) // withdraw validator reward diff --git a/x/slashing/tick.go b/x/slashing/tick.go index 007d93788..03bd094af 100644 --- a/x/slashing/tick.go +++ b/x/slashing/tick.go @@ -18,7 +18,7 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, sk Keeper) (tags tags = sdk.NewTags("height", heightBytes) // Iterate over all the validators which *should* have signed this block - // Store whether or not they have actually signed it and slash/unbond any + // store whether or not they have actually signed it and slash/unbond any // which have missed too many blocks in a row (downtime slashing) for _, voteInfo := range req.LastCommitInfo.GetVotes() { sk.handleValidatorSignature(ctx, voteInfo.Validator.Address, voteInfo.Validator.Power, voteInfo.SignedLastBlock)