/
module.go
139 lines (121 loc) · 4.25 KB
/
module.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package governance
import (
"context"
"fmt"
"time"
"cosmossdk.io/collections"
"cosmossdk.io/core/appmodule"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
gov "github.com/cosmos/cosmos-sdk/x/gov"
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
)
const (
AttributeValueProposalForbidden = "proposal_forbidden"
)
var (
_ module.AppModule = AppModule{}
_ module.AppModuleSimulation = AppModule{}
_ appmodule.HasEndBlocker = AppModule{}
)
// AppModule embeds the Cosmos SDK's x/governance AppModule
type AppModule struct {
// embed the Cosmos SDK's x/governance AppModule
gov.AppModule
keeper govkeeper.Keeper
isLegacyProposalWhitelisted func(govv1beta1.Content) bool
isModuleWhiteList func(string) bool
}
type ParamChangeKey struct {
MsgType, Key string
}
// NewAppModule creates a new AppModule object using the native x/governance module AppModule constructor.
func NewAppModule(cdc codec.Codec,
keeper govkeeper.Keeper,
ak govtypes.AccountKeeper,
bk govtypes.BankKeeper,
isProposalWhitelisted func(govv1beta1.Content) bool,
ss govtypes.ParamSubspace,
isModuleWhiteList func(string) bool,
) AppModule {
govAppModule := gov.NewAppModule(cdc, &keeper, ak, bk, ss)
return AppModule{
AppModule: govAppModule,
keeper: keeper,
isLegacyProposalWhitelisted: isProposalWhitelisted,
isModuleWhiteList: isModuleWhiteList,
}
}
func (am AppModule) EndBlock(c context.Context) error {
ctx := sdk.UnwrapSDKContext(c)
rng := collections.NewPrefixUntilPairRange[time.Time, uint64](ctx.BlockTime())
keeper := am.keeper
// if there are forbidden proposals in active proposals queue, refund deposit, delete votes for that proposal
// and delete proposal from all storages
err := am.keeper.ActiveProposalsQueue.Walk(ctx, rng, func(key collections.Pair[time.Time, uint64], _ uint64) (bool, error) {
proposal, err := keeper.Proposals.Get(ctx, key.K2())
if err != nil {
return false, err
}
deleteForbiddenProposal(ctx, am, proposal)
return false, nil
})
if err != nil {
return err
}
return am.AppModule.EndBlock(ctx)
}
// isProposalWhitelisted checks whether a proposal is whitelisted
func isProposalWhitelisted(ctx sdk.Context, am AppModule, proposal govv1.Proposal) bool {
messages := proposal.GetMessages()
// iterate over all the proposal messages
for _, message := range messages {
sdkMsg, isLegacyProposal := message.GetCachedValue().(*govv1.MsgExecLegacyContent)
if isLegacyProposal {
// legacy gov proposal content
content, err := govv1.LegacyContentFromMessage(sdkMsg)
if err != nil {
continue
}
if !am.isLegacyProposalWhitelisted(content) {
// not whitelisted
return false
}
// not legacy gov proposal content
} else if !am.isModuleWhiteList(message.TypeUrl) {
// not whitelisted
return false
}
}
return true
}
// deleteForbiddenProposal removes proposals that are not whitelisted
func deleteForbiddenProposal(ctx sdk.Context, am AppModule, proposal govv1.Proposal) {
if isProposalWhitelisted(ctx, am, proposal) {
return
}
// delete the votes related to the proposal calling Tally
// Tally's return result won't be used in decision if the tokens will be burned or refunded (they are always refunded), but
// this function needs to be called to delete the votes related to the given proposal, since the deleteVote function is
// private and cannot be called directly from the overridden app module
am.keeper.Tally(ctx, proposal)
am.keeper.DeleteProposal(ctx, proposal.Id)
am.keeper.RefundAndDeleteDeposits(ctx, proposal.Id)
ctx.EventManager().EmitEvent(
sdk.NewEvent(
govtypes.EventTypeActiveProposal,
sdk.NewAttribute(govtypes.AttributeKeyProposalID, fmt.Sprintf("%d", proposal.Id)),
sdk.NewAttribute(govtypes.AttributeKeyProposalResult, AttributeValueProposalForbidden),
),
)
logger := am.keeper.Logger(ctx)
logger.Info(
"proposal is not whitelisted; deleted",
"proposal", proposal.Id,
"title", proposal.GetTitle(),
"total_deposit", proposal.TotalDeposit)
}