From b169819b810f186b25130ce88e176a5700cf3b2a Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Thu, 19 Oct 2023 11:23:16 +0200 Subject: [PATCH 1/2] refactor(x/gov)!: let hooks return an error --- x/gov/abci.go | 16 ++++++++++++++-- x/gov/keeper/deposit.go | 5 ++++- x/gov/keeper/hooks_test.go | 15 ++++++++++----- x/gov/keeper/proposal.go | 5 ++++- x/gov/keeper/vote.go | 5 ++++- x/gov/types/expected_keepers.go | 10 +++++----- x/gov/types/hooks.go | 32 ++++++++++++++++++++++---------- 7 files changed, 63 insertions(+), 25 deletions(-) diff --git a/x/gov/abci.go b/x/gov/abci.go index c678a2e80a39..f7e5499fc342 100644 --- a/x/gov/abci.go +++ b/x/gov/abci.go @@ -65,7 +65,13 @@ func EndBlocker(ctx sdk.Context, keeper *keeper.Keeper) error { } // called when proposal become inactive - keeper.Hooks().AfterProposalFailedMinDeposit(ctx, proposal.Id) + cacheCtx, writeCache := ctx.CacheContext() + err = keeper.Hooks().AfterProposalFailedMinDeposit(cacheCtx, proposal.Id) + if err == nil { // purposely ignoring the error here not to halt the chain if the hook fails + writeCache() + } else { + keeper.Logger(ctx).Error("failed to execute AfterProposalFailedMinDeposit hook", "error", err) + } ctx.EventManager().EmitEvent( sdk.NewEvent( @@ -228,7 +234,13 @@ func EndBlocker(ctx sdk.Context, keeper *keeper.Keeper) error { } // when proposal become active - keeper.Hooks().AfterProposalVotingPeriodEnded(ctx, proposal.Id) + cacheCtx, writeCache := ctx.CacheContext() + err = keeper.Hooks().AfterProposalVotingPeriodEnded(cacheCtx, proposal.Id) + if err == nil { // purposely ignoring the error here not to halt the chain if the hook fails + writeCache() + } else { + keeper.Logger(ctx).Error("failed to execute AfterProposalVotingPeriodEnded hook", "error", err) + } logger.Info( "proposal tallied", diff --git a/x/gov/keeper/deposit.go b/x/gov/keeper/deposit.go index 1bd80ea689b4..a0af97427dff 100644 --- a/x/gov/keeper/deposit.go +++ b/x/gov/keeper/deposit.go @@ -115,7 +115,10 @@ func (keeper Keeper) AddDeposit(ctx context.Context, proposalID uint64, deposito } // called when deposit has been added to a proposal, however the proposal may not be active - keeper.Hooks().AfterProposalDeposit(ctx, proposalID, depositorAddr) + err = keeper.Hooks().AfterProposalDeposit(ctx, proposalID, depositorAddr) + if err != nil { + return false, err + } sdkCtx := sdk.UnwrapSDKContext(ctx) sdkCtx.EventManager().EmitEvent( diff --git a/x/gov/keeper/hooks_test.go b/x/gov/keeper/hooks_test.go index 72fe3b8ddcc9..d611e914932f 100644 --- a/x/gov/keeper/hooks_test.go +++ b/x/gov/keeper/hooks_test.go @@ -27,24 +27,29 @@ type MockGovHooksReceiver struct { AfterProposalVotingPeriodEndedValid bool } -func (h *MockGovHooksReceiver) AfterProposalSubmission(ctx context.Context, proposalID uint64) { +func (h *MockGovHooksReceiver) AfterProposalSubmission(ctx context.Context, proposalID uint64) error { h.AfterProposalSubmissionValid = true + return nil } -func (h *MockGovHooksReceiver) AfterProposalDeposit(ctx context.Context, proposalID uint64, depositorAddr sdk.AccAddress) { +func (h *MockGovHooksReceiver) AfterProposalDeposit(ctx context.Context, proposalID uint64, depositorAddr sdk.AccAddress) error { h.AfterProposalDepositValid = true + return nil } -func (h *MockGovHooksReceiver) AfterProposalVote(ctx context.Context, proposalID uint64, voterAddr sdk.AccAddress) { +func (h *MockGovHooksReceiver) AfterProposalVote(ctx context.Context, proposalID uint64, voterAddr sdk.AccAddress) error { h.AfterProposalVoteValid = true + return nil } -func (h *MockGovHooksReceiver) AfterProposalFailedMinDeposit(ctx context.Context, proposalID uint64) { +func (h *MockGovHooksReceiver) AfterProposalFailedMinDeposit(ctx context.Context, proposalID uint64) error { h.AfterProposalFailedMinDepositValid = true + return nil } -func (h *MockGovHooksReceiver) AfterProposalVotingPeriodEnded(ctx context.Context, proposalID uint64) { +func (h *MockGovHooksReceiver) AfterProposalVotingPeriodEnded(ctx context.Context, proposalID uint64) error { h.AfterProposalVotingPeriodEndedValid = true + return nil } func TestHooks(t *testing.T) { diff --git a/x/gov/keeper/proposal.go b/x/gov/keeper/proposal.go index a2c186ec5ccf..1717e234d7c0 100644 --- a/x/gov/keeper/proposal.go +++ b/x/gov/keeper/proposal.go @@ -114,7 +114,10 @@ func (keeper Keeper) SubmitProposal(ctx context.Context, messages []sdk.Msg, met } // called right after a proposal is submitted - keeper.Hooks().AfterProposalSubmission(ctx, proposalID) + err = keeper.Hooks().AfterProposalSubmission(ctx, proposalID) + if err != nil { + return v1.Proposal{}, err + } sdkCtx.EventManager().EmitEvent( sdk.NewEvent( diff --git a/x/gov/keeper/vote.go b/x/gov/keeper/vote.go index 0bc99653d509..466fe4c2a27a 100644 --- a/x/gov/keeper/vote.go +++ b/x/gov/keeper/vote.go @@ -42,7 +42,10 @@ func (keeper Keeper) AddVote(ctx context.Context, proposalID uint64, voterAddr s } // called after a vote on a proposal is cast - keeper.Hooks().AfterProposalVote(ctx, proposalID, voterAddr) + err = keeper.Hooks().AfterProposalVote(ctx, proposalID, voterAddr) + if err != nil { + return err + } sdkCtx := sdk.UnwrapSDKContext(ctx) sdkCtx.EventManager().EmitEvent( diff --git a/x/gov/types/expected_keepers.go b/x/gov/types/expected_keepers.go index 30e4d086c60f..e104038b14fc 100644 --- a/x/gov/types/expected_keepers.go +++ b/x/gov/types/expected_keepers.go @@ -61,11 +61,11 @@ type PoolKeeper interface { // GovHooks event hooks for governance proposal object (noalias) type GovHooks interface { - AfterProposalSubmission(ctx context.Context, proposalID uint64) // Must be called after proposal is submitted - AfterProposalDeposit(ctx context.Context, proposalID uint64, depositorAddr sdk.AccAddress) // Must be called after a deposit is made - AfterProposalVote(ctx context.Context, proposalID uint64, voterAddr sdk.AccAddress) // Must be called after a vote on a proposal is cast - AfterProposalFailedMinDeposit(ctx context.Context, proposalID uint64) // Must be called when proposal fails to reach min deposit - AfterProposalVotingPeriodEnded(ctx context.Context, proposalID uint64) // Must be called when proposal's finishes it's voting period + AfterProposalSubmission(ctx context.Context, proposalID uint64) error // Must be called after proposal is submitted + AfterProposalDeposit(ctx context.Context, proposalID uint64, depositorAddr sdk.AccAddress) error // Must be called after a deposit is made + AfterProposalVote(ctx context.Context, proposalID uint64, voterAddr sdk.AccAddress) error // Must be called after a vote on a proposal is cast + AfterProposalFailedMinDeposit(ctx context.Context, proposalID uint64) error // Must be called when proposal fails to reach min deposit + AfterProposalVotingPeriodEnded(ctx context.Context, proposalID uint64) error // Must be called when proposal's finishes it's voting period } type GovHooksWrapper struct{ GovHooks } diff --git a/x/gov/types/hooks.go b/x/gov/types/hooks.go index 099e7d0da1db..7749e83b4cce 100644 --- a/x/gov/types/hooks.go +++ b/x/gov/types/hooks.go @@ -2,6 +2,7 @@ package types import ( "context" + "errors" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -15,32 +16,43 @@ func NewMultiGovHooks(hooks ...GovHooks) MultiGovHooks { return hooks } -func (h MultiGovHooks) AfterProposalSubmission(ctx context.Context, proposalID uint64) { +func (h MultiGovHooks) AfterProposalSubmission(ctx context.Context, proposalID uint64) error { + var errs error for i := range h { - h[i].AfterProposalSubmission(ctx, proposalID) + errs = errors.Join(errs, h[i].AfterProposalSubmission(ctx, proposalID)) } + + return errs } -func (h MultiGovHooks) AfterProposalDeposit(ctx context.Context, proposalID uint64, depositorAddr sdk.AccAddress) { +func (h MultiGovHooks) AfterProposalDeposit(ctx context.Context, proposalID uint64, depositorAddr sdk.AccAddress) error { + var errs error for i := range h { - h[i].AfterProposalDeposit(ctx, proposalID, depositorAddr) + errs = errors.Join(errs, h[i].AfterProposalDeposit(ctx, proposalID, depositorAddr)) } + return errs } -func (h MultiGovHooks) AfterProposalVote(ctx context.Context, proposalID uint64, voterAddr sdk.AccAddress) { +func (h MultiGovHooks) AfterProposalVote(ctx context.Context, proposalID uint64, voterAddr sdk.AccAddress) error { + var errs error for i := range h { - h[i].AfterProposalVote(ctx, proposalID, voterAddr) + errs = errors.Join(errs, h[i].AfterProposalVote(ctx, proposalID, voterAddr)) } + return errs } -func (h MultiGovHooks) AfterProposalFailedMinDeposit(ctx context.Context, proposalID uint64) { +func (h MultiGovHooks) AfterProposalFailedMinDeposit(ctx context.Context, proposalID uint64) error { + var errs error for i := range h { - h[i].AfterProposalFailedMinDeposit(ctx, proposalID) + errs = errors.Join(errs, h[i].AfterProposalFailedMinDeposit(ctx, proposalID)) } + return errs } -func (h MultiGovHooks) AfterProposalVotingPeriodEnded(ctx context.Context, proposalID uint64) { +func (h MultiGovHooks) AfterProposalVotingPeriodEnded(ctx context.Context, proposalID uint64) error { + var errs error for i := range h { - h[i].AfterProposalVotingPeriodEnded(ctx, proposalID) + errs = errors.Join(errs, h[i].AfterProposalVotingPeriodEnded(ctx, proposalID)) } + return errs } From 18772a15510da9e3bd6137d485f126981fec6686 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Thu, 19 Oct 2023 11:27:32 +0200 Subject: [PATCH 2/2] updates --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c135540fea6..b6218b2daad3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes +* (x/gov) [#18173](https://github.com/cosmos/cosmos-sdk/pull/18173) Gov Hooks now returns error and are "blocking" if they fail. Expect for `AfterProposalFailedMinDeposit` and `AfterProposalVotingPeriodEnded` that will log the error and continue. * (x/gov/testutil) [#17986](https://github.com/cosmos/cosmos-sdk/pull/18036) `MsgDeposit` has been removed because of AutoCLI migration. * (x/staking/testutil) [#17986](https://github.com/cosmos/cosmos-sdk/pull/17986) `MsgRedelegateExec`, `MsgUnbondExec` has been removed because of AutoCLI migration. * (x/bank/testutil) [#17868](https://github.com/cosmos/cosmos-sdk/pull/17868) `MsgSendExec` has been removed because of AutoCLI migration.