109 lines
3.4 KiB
Go
109 lines
3.4 KiB
Go
package gov
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/cosmos/cosmos-sdk/telemetry"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/cosmos/cosmos-sdk/x/gov/keeper"
|
|
"github.com/cosmos/cosmos-sdk/x/gov/types"
|
|
)
|
|
|
|
// EndBlocker called every block, process inflation, update validator set.
|
|
func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) {
|
|
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker)
|
|
|
|
logger := keeper.Logger(ctx)
|
|
|
|
// delete inactive proposal from store and its deposits
|
|
keeper.IterateInactiveProposalsQueue(ctx, ctx.BlockHeader().Time, func(proposal types.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 types.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.GetContent())
|
|
if err == nil {
|
|
proposal.Status = types.StatusPassed
|
|
tagValue = types.AttributeValueProposalPassed
|
|
logMsg = "passed"
|
|
|
|
// The cached context is created with a new EventManager. However, since
|
|
// the proposal handler execution was successful, we want to track/keep
|
|
// any events emitted, so we re-emit to "merge" the events into the
|
|
// original Context's EventManager.
|
|
ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events())
|
|
|
|
// write state to the underlying multi-store
|
|
writeCache()
|
|
} else {
|
|
proposal.Status = types.StatusFailed
|
|
tagValue = types.AttributeValueProposalFailed
|
|
logMsg = fmt.Sprintf("passed, but failed on execution: %s", err)
|
|
}
|
|
} else {
|
|
proposal.Status = types.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
|
|
})
|
|
}
|