package gov import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/types" ) // EndBlocker called every block, process inflation, update validator set. func EndBlocker(ctx sdk.Context, keeper Keeper) { logger := keeper.Logger(ctx) // delete inactive proposal from store and its deposits keeper.IterateInactiveProposalsQueue(ctx, ctx.BlockHeader().Time, func(proposal Proposal) bool { keeper.DeleteProposal(ctx, proposal.ProposalID) keeper.DeleteDeposits(ctx, proposal.ProposalID) ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeInactiveProposal, sdk.NewAttribute(types.AttributeKeyProposalID, fmt.Sprintf("%d", proposal.ProposalID)), sdk.NewAttribute(types.AttributeKeyProposalResult, types.AttributeValueProposalDropped), ), ) logger.Info( fmt.Sprintf("proposal %d (%s) didn't meet minimum deposit of %s (had only %s); deleted", proposal.ProposalID, proposal.GetTitle(), keeper.GetDepositParams(ctx).MinDeposit, proposal.TotalDeposit, ), ) return false }) // fetch active proposals whose voting periods have ended (are passed the block time) keeper.IterateActiveProposalsQueue(ctx, ctx.BlockHeader().Time, func(proposal Proposal) bool { var tagValue, logMsg string passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal) if burnDeposits { keeper.DeleteDeposits(ctx, proposal.ProposalID) } else { keeper.RefundDeposits(ctx, proposal.ProposalID) } if passes { handler := keeper.Router().GetRoute(proposal.ProposalRoute()) cacheCtx, writeCache := ctx.CacheContext() // The proposal handler may execute state mutating logic depending // on the proposal content. If the handler fails, no state mutation // is written and the error message is logged. err := handler(cacheCtx, proposal.Content) if err == nil { proposal.Status = StatusPassed tagValue = types.AttributeValueProposalPassed logMsg = "passed" // write state to the underlying multi-store writeCache() } else { proposal.Status = StatusFailed tagValue = types.AttributeValueProposalFailed logMsg = fmt.Sprintf("passed, but failed on execution: %s", err.ABCILog()) } } else { proposal.Status = StatusRejected tagValue = types.AttributeValueProposalRejected logMsg = "rejected" } proposal.FinalTallyResult = tallyResults keeper.SetProposal(ctx, proposal) keeper.RemoveFromActiveProposalQueue(ctx, proposal.ProposalID, proposal.VotingEndTime) logger.Info( fmt.Sprintf( "proposal %d (%s) tallied; result: %s", proposal.ProposalID, proposal.GetTitle(), logMsg, ), ) ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeActiveProposal, sdk.NewAttribute(types.AttributeKeyProposalID, fmt.Sprintf("%d", proposal.ProposalID)), sdk.NewAttribute(types.AttributeKeyProposalResult, tagValue), ), ) return false }) }