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
2021-07-30 10:37:38 -07:00
// delete dead proposals from store and burn theirs deposits. A proposal is dead when it's inactive and didn't get enough deposit on time to get into voting phase.
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 )
2021-07-30 10:37:38 -07:00
keeper . DeleteAndBurnDeposits ( ctx , proposal . ProposalId )
2019-02-08 18:33:06 -08:00
2021-04-21 09:59:30 -07:00
// called when proposal become inactive
keeper . AfterProposalFailedMinDeposit ( ctx , proposal . ProposalId )
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 {
2021-07-30 10:37:38 -07:00
keeper . DeleteAndBurnDeposits ( ctx , proposal . ProposalId )
2019-05-20 07:13:50 -07:00
} else {
2021-07-30 10:37:38 -07:00
keeper . RefundAndDeleteDeposits ( 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
2021-04-21 09:59:30 -07:00
// when proposal become active
keeper . AfterProposalVotingPeriodEnded ( ctx , proposal . ProposalId )
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
}