2019-02-08 18:33:06 -08:00
|
|
|
package gov
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2020-07-17 08:34:37 -07:00
|
|
|
"time"
|
2019-02-08 18:33:06 -08:00
|
|
|
|
2020-06-18 11:12:44 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/telemetry"
|
2019-02-08 18:33:06 -08:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2020-06-13 02:07:51 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/gov/keeper"
|
2019-06-26 09:03:25 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/gov/types"
|
2019-02-08 18:33:06 -08:00
|
|
|
)
|
|
|
|
|
2019-06-26 09:03:25 -07:00
|
|
|
// EndBlocker called every block, process inflation, update validator set.
|
2020-06-13 02:07:51 -07:00
|
|
|
func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) {
|
2020-07-17 12:33:50 -07:00
|
|
|
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker)
|
2020-06-18 11:12:44 -07:00
|
|
|
|
2019-04-15 20:58:06 -07:00
|
|
|
logger := keeper.Logger(ctx)
|
2019-02-08 18:33:06 -08:00
|
|
|
|
2019-06-04 11:38:11 -07:00
|
|
|
// delete inactive proposal from store and its deposits
|
2020-06-13 02:07:51 -07:00
|
|
|
keeper.IterateInactiveProposalsQueue(ctx, ctx.BlockHeader().Time, func(proposal types.Proposal) bool {
|
2020-08-14 01:55:54 -07:00
|
|
|
keeper.DeleteProposal(ctx, proposal.ProposalId)
|
|
|
|
keeper.DeleteDeposits(ctx, proposal.ProposalId)
|
2019-02-08 18:33:06 -08:00
|
|
|
|
2019-06-26 09:03:25 -07:00
|
|
|
ctx.EventManager().EmitEvent(
|
|
|
|
sdk.NewEvent(
|
|
|
|
types.EventTypeInactiveProposal,
|
2020-08-14 01:55:54 -07:00
|
|
|
sdk.NewAttribute(types.AttributeKeyProposalID, fmt.Sprintf("%d", proposal.ProposalId)),
|
2019-06-26 09:03:25 -07:00
|
|
|
sdk.NewAttribute(types.AttributeKeyProposalResult, types.AttributeValueProposalDropped),
|
|
|
|
),
|
|
|
|
)
|
2019-02-08 18:33:06 -08:00
|
|
|
|
|
|
|
logger.Info(
|
2020-12-03 15:17:21 -08:00
|
|
|
"proposal did not meet minimum deposit; deleted",
|
|
|
|
"proposal", proposal.ProposalId,
|
|
|
|
"title", proposal.GetTitle(),
|
|
|
|
"min_deposit", keeper.GetDepositParams(ctx).MinDeposit.String(),
|
|
|
|
"total_deposit", proposal.TotalDeposit.String(),
|
2019-02-08 18:33:06 -08:00
|
|
|
)
|
2020-12-03 15:17:21 -08:00
|
|
|
|
2019-06-04 11:38:11 -07:00
|
|
|
return false
|
|
|
|
})
|
2019-02-08 18:33:06 -08:00
|
|
|
|
|
|
|
// fetch active proposals whose voting periods have ended (are passed the block time)
|
2020-06-13 02:07:51 -07:00
|
|
|
keeper.IterateActiveProposalsQueue(ctx, ctx.BlockHeader().Time, func(proposal types.Proposal) bool {
|
2019-04-30 09:31:38 -07:00
|
|
|
var tagValue, logMsg string
|
|
|
|
|
2019-08-08 12:51:18 -07:00
|
|
|
passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal)
|
2019-06-04 11:38:11 -07:00
|
|
|
|
2019-05-20 07:13:50 -07:00
|
|
|
if burnDeposits {
|
2020-08-14 01:55:54 -07:00
|
|
|
keeper.DeleteDeposits(ctx, proposal.ProposalId)
|
2019-05-20 07:13:50 -07:00
|
|
|
} else {
|
2020-08-14 01:55:54 -07:00
|
|
|
keeper.RefundDeposits(ctx, proposal.ProposalId)
|
2019-05-20 07:13:50 -07:00
|
|
|
}
|
2019-04-30 09:31:38 -07:00
|
|
|
|
2019-05-20 07:13:50 -07:00
|
|
|
if passes {
|
2019-08-08 12:51:18 -07:00
|
|
|
handler := keeper.Router().GetRoute(proposal.ProposalRoute())
|
2019-04-30 09:31:38 -07:00
|
|
|
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.
|
2020-05-19 13:17:29 -07:00
|
|
|
err := handler(cacheCtx, proposal.GetContent())
|
2019-04-30 09:31:38 -07:00
|
|
|
if err == nil {
|
2020-06-13 02:07:51 -07:00
|
|
|
proposal.Status = types.StatusPassed
|
2019-06-26 09:03:25 -07:00
|
|
|
tagValue = types.AttributeValueProposalPassed
|
2019-04-30 09:31:38 -07:00
|
|
|
logMsg = "passed"
|
|
|
|
|
2020-02-06 13:19:26 -08:00
|
|
|
// 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())
|
|
|
|
|
2019-04-30 09:31:38 -07:00
|
|
|
// write state to the underlying multi-store
|
|
|
|
writeCache()
|
|
|
|
} else {
|
2020-06-13 02:07:51 -07:00
|
|
|
proposal.Status = types.StatusFailed
|
2019-06-26 09:03:25 -07:00
|
|
|
tagValue = types.AttributeValueProposalFailed
|
2019-12-27 09:57:54 -08:00
|
|
|
logMsg = fmt.Sprintf("passed, but failed on execution: %s", err)
|
2019-04-30 09:31:38 -07:00
|
|
|
}
|
2019-02-08 18:33:06 -08:00
|
|
|
} else {
|
2020-06-13 02:07:51 -07:00
|
|
|
proposal.Status = types.StatusRejected
|
2019-06-26 09:03:25 -07:00
|
|
|
tagValue = types.AttributeValueProposalRejected
|
2019-04-30 09:31:38 -07:00
|
|
|
logMsg = "rejected"
|
2019-02-08 18:33:06 -08:00
|
|
|
}
|
|
|
|
|
2019-06-04 11:38:11 -07:00
|
|
|
proposal.FinalTallyResult = tallyResults
|
2019-04-30 09:31:38 -07:00
|
|
|
|
2019-06-04 11:38:11 -07:00
|
|
|
keeper.SetProposal(ctx, proposal)
|
2020-08-14 01:55:54 -07:00
|
|
|
keeper.RemoveFromActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime)
|
2019-02-08 18:33:06 -08:00
|
|
|
|
|
|
|
logger.Info(
|
2020-12-03 15:17:21 -08:00
|
|
|
"proposal tallied",
|
|
|
|
"proposal", proposal.ProposalId,
|
|
|
|
"title", proposal.GetTitle(),
|
|
|
|
"result", logMsg,
|
2019-02-08 18:33:06 -08:00
|
|
|
)
|
|
|
|
|
2019-06-26 09:03:25 -07:00
|
|
|
ctx.EventManager().EmitEvent(
|
|
|
|
sdk.NewEvent(
|
|
|
|
types.EventTypeActiveProposal,
|
2020-08-14 01:55:54 -07:00
|
|
|
sdk.NewAttribute(types.AttributeKeyProposalID, fmt.Sprintf("%d", proposal.ProposalId)),
|
2019-06-26 09:03:25 -07:00
|
|
|
sdk.NewAttribute(types.AttributeKeyProposalResult, tagValue),
|
|
|
|
),
|
|
|
|
)
|
2019-06-04 11:38:11 -07:00
|
|
|
return false
|
|
|
|
})
|
2019-02-08 18:33:06 -08:00
|
|
|
}
|