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

refactor(x/gov)!: let hooks return an error (backport #18173) #18174

Merged
merged 2 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
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
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,18 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Features

* (server) [#18162](https://github.com/cosmos/cosmos-sdk/pull/18162) Start gRPC & API server in standalone mode
* (server) [#18162](https://github.com/cosmos/cosmos-sdk/pull/18162) Start gRPC & API server in standalone mode.

### Improvements

* (x/staking/keeper) [#]18049(https://github.com/cosmos/cosmos-sdk/pull/18049) return early if Slash encounters zero tokens to burn.
* (x/staking/keeper) [#18035](https://github.com/cosmos/cosmos-sdk/pull/18035) Hoisted out of the redelegation loop, the non-changing validator and delegator addresses parsing.
* (x/staking) [#18049](https://github.com/cosmos/cosmos-sdk/pull/18049) Return early if Slash encounters zero tokens to burn.
* (x/staking) [#18035](https://github.com/cosmos/cosmos-sdk/pull/18035) Hoisted out of the redelegation loop, the non-changing validator and delegator addresses parsing.
* (keyring) [#17913](https://github.com/cosmos/cosmos-sdk/pull/17913) Add `NewAutoCLIKeyring` for creating an AutoCLI keyring from a SDK keyring.
* (x/consensus) [#18041](https://github.com/cosmos/cosmos-sdk/pull/18041) Let `ToProtoConsensusParams()` return an error.

### Bug Fixes

* (x/gov) [#18173](https://github.com/cosmos/cosmos-sdk/pull/18173) Gov hooks now return an error and are *blocking* when they fail. Expect for `AfterProposalFailedMinDeposit` and `AfterProposalVotingPeriodEnded` which log the error and continue.
* (x/gov) [#17873](https://github.com/cosmos/cosmos-sdk/pull/17873) Fail any inactive and active proposals that cannot be decoded.
* (x/slashing) [#18016](https://github.com/cosmos/cosmos-sdk/pull/18016) Fixed builder function for missed blocks key (`validatorMissedBlockBitArrayPrefixKey`) in slashing/migration/v4
* (x/bank) [#18107](https://github.com/cosmos/cosmos-sdk/pull/18107) Add missing keypair of SendEnabled to restore legacy param set before migration.
Expand Down
16 changes: 14 additions & 2 deletions x/gov/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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",
Expand Down
5 changes: 4 additions & 1 deletion x/gov/keeper/deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
15 changes: 10 additions & 5 deletions x/gov/keeper/hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
5 changes: 4 additions & 1 deletion x/gov/keeper/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
5 changes: 4 additions & 1 deletion x/gov/keeper/vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
10 changes: 5 additions & 5 deletions x/gov/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ type BankKeeper 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 }
Expand Down
32 changes: 22 additions & 10 deletions x/gov/types/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package types

import (
"context"
"errors"

sdk "github.com/cosmos/cosmos-sdk/types"
)
Expand All @@ -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
}
Loading