From 7fc2ed61d76daaafbcc9b90f9289b0ac511b3dd0 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Sun, 29 Jul 2018 22:11:21 -0700 Subject: [PATCH] Merge pull request #1859: slashing to governance for non-voting validators * added slashing to governance non voting * minor formatting --- PENDING.md | 1 + cmd/gaia/app/app.go | 3 +-- x/gov/endblocker_test.go | 47 ++++++++++++++++++++++++++++++++++++++++ x/gov/handler.go | 14 ++++++++++-- x/gov/test_common.go | 2 +- 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/PENDING.md b/PENDING.md index 5857c8225..557a5e457 100644 --- a/PENDING.md +++ b/PENDING.md @@ -37,6 +37,7 @@ FEATURES * This allows SDK users to initialize a new project repository. * [tests] Remotenet commands for AWS (awsnet) * [store] Add transient store +* [gov] Add slashing for validators who do not vote on a proposal IMPROVEMENTS * [baseapp] Allow any alphanumeric character in route diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 45d92c340..bb4dc67f5 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -146,9 +146,8 @@ 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) - tags, _ := gov.EndBlocker(ctx, app.govKeeper) return abci.ResponseEndBlock{ ValidatorUpdates: validatorUpdates, diff --git a/x/gov/endblocker_test.go b/x/gov/endblocker_test.go index 0070bb577..877479190 100644 --- a/x/gov/endblocker_test.go +++ b/x/gov/endblocker_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/stake" abci "github.com/tendermint/tendermint/abci/types" ) @@ -166,3 +167,49 @@ func TestTickPassedVotingPeriod(t *testing.T) { depositsIterator.Close() require.Equal(t, StatusRejected, keeper.GetProposal(ctx, proposalID).GetStatus()) } + +func TestSlashing(t *testing.T) { + mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10) + SortAddresses(addrs) + mapp.BeginBlock(abci.RequestBeginBlock{}) + ctx := mapp.BaseApp.NewContext(false, abci.Header{}) + govHandler := NewHandler(keeper) + stakeHandler := stake.NewHandler(sk) + + createValidators(t, stakeHandler, ctx, addrs[:3], []int64{25, 6, 7}) + + initTotalPower := keeper.ds.GetValidatorSet().TotalPower(ctx) + val0Initial := keeper.ds.GetValidatorSet().Validator(ctx, addrs[0]).GetPower().Quo(initTotalPower) + val1Initial := keeper.ds.GetValidatorSet().Validator(ctx, addrs[1]).GetPower().Quo(initTotalPower) + val2Initial := keeper.ds.GetValidatorSet().Validator(ctx, addrs[2]).GetPower().Quo(initTotalPower) + + newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewCoin("steak", 15)}) + + res := govHandler(ctx, newProposalMsg) + require.True(t, res.IsOK()) + var proposalID int64 + keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID) + + ctx = ctx.WithBlockHeight(10) + require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus()) + + newVoteMsg := NewMsgVote(addrs[0], proposalID, OptionYes) + res = govHandler(ctx, newVoteMsg) + require.True(t, res.IsOK()) + + EndBlocker(ctx, keeper) + + ctx = ctx.WithBlockHeight(215) + require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus()) + + EndBlocker(ctx, keeper) + + endTotalPower := keeper.ds.GetValidatorSet().TotalPower(ctx) + val0End := keeper.ds.GetValidatorSet().Validator(ctx, addrs[0]).GetPower().Quo(endTotalPower) + val1End := keeper.ds.GetValidatorSet().Validator(ctx, addrs[1]).GetPower().Quo(endTotalPower) + val2End := keeper.ds.GetValidatorSet().Validator(ctx, addrs[2]).GetPower().Quo(endTotalPower) + + require.True(t, val0End.GTE(val0Initial)) + require.True(t, val1End.LT(val1Initial)) + require.True(t, val2End.LT(val2Initial)) +} diff --git a/x/gov/handler.go b/x/gov/handler.go index 58e062d0d..747671cba 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -94,7 +94,7 @@ func handleMsgVote(ctx sdk.Context, keeper Keeper, msg MsgVote) sdk.Result { } // Called every block, process inflation, update validator set -func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags, nonVotingVals []sdk.AccAddress) { +func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) { resTags = sdk.NewTags() @@ -112,6 +112,7 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags, nonVotingVals } var passes bool + var nonVotingVals []sdk.AccAddress // Check if earliest Active Proposal ended voting period yet for shouldPopActiveProposalQueue(ctx, keeper) { @@ -137,11 +138,20 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags, nonVotingVals } keeper.SetProposal(ctx, activeProposal) + for _, valAddr := range nonVotingVals { + val := keeper.ds.GetValidatorSet().Validator(ctx, valAddr) + keeper.ds.GetValidatorSet().Slash(ctx, + val.GetPubKey(), + ctx.BlockHeight(), + val.GetPower().RoundInt64(), + keeper.GetTallyingProcedure(ctx).GovernancePenalty) + } + resTags.AppendTag(tags.Action, action) resTags.AppendTag(tags.ProposalID, proposalIDBytes) } - return resTags, nonVotingVals + return resTags } func shouldPopInactiveProposalQueue(ctx sdk.Context, keeper Keeper) bool { depositProcedure := keeper.GetDepositProcedure(ctx) diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 6c418f683..de577ef62 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -50,7 +50,7 @@ func getMockApp(t *testing.T, numGenAccs int) (*mock.App, Keeper, stake.Keeper, // gov and stake endblocker func getEndBlocker(keeper Keeper) sdk.EndBlocker { return func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { - tags, _ := EndBlocker(ctx, keeper) + tags := EndBlocker(ctx, keeper) return abci.ResponseEndBlock{ Tags: tags, }