improve permission types

This commit is contained in:
rhuairahrighairigh 2020-03-27 15:27:45 +00:00
parent c50f6bc9fa
commit 77553ed299
6 changed files with 130 additions and 74 deletions

View File

@ -38,6 +38,7 @@ var (
DefaultGenesisState = types.DefaultGenesisState DefaultGenesisState = types.DefaultGenesisState
GetKeyFromID = types.GetKeyFromID GetKeyFromID = types.GetKeyFromID
GetVoteKey = types.GetVoteKey GetVoteKey = types.GetVoteKey
NewCommittee = types.NewCommittee
NewCommitteeChangeProposal = types.NewCommitteeChangeProposal NewCommitteeChangeProposal = types.NewCommitteeChangeProposal
NewCommitteeDeleteProposal = types.NewCommitteeDeleteProposal NewCommitteeDeleteProposal = types.NewCommitteeDeleteProposal
NewGenesisState = types.NewGenesisState NewGenesisState = types.NewGenesisState
@ -46,7 +47,9 @@ var (
NewQueryCommitteeParams = types.NewQueryCommitteeParams NewQueryCommitteeParams = types.NewQueryCommitteeParams
NewQueryProposalParams = types.NewQueryProposalParams NewQueryProposalParams = types.NewQueryProposalParams
NewQueryVoteParams = types.NewQueryVoteParams NewQueryVoteParams = types.NewQueryVoteParams
RegisterCodec = types.RegisterCodec RegisterAppCodec = types.RegisterAppCodec
RegisterModuleCodec = types.RegisterModuleCodec
RegisterProposalTypeCodec = types.RegisterProposalTypeCodec
Uint64FromBytes = types.Uint64FromBytes Uint64FromBytes = types.Uint64FromBytes
// variable aliases // variable aliases
@ -61,22 +64,23 @@ var (
) )
type ( type (
Keeper = keeper.Keeper Keeper = keeper.Keeper
Committee = types.Committee AllowedParam = types.AllowedParam
CommitteeChangeProposal = types.CommitteeChangeProposal AllowedParams = types.AllowedParams
CommitteeDeleteProposal = types.CommitteeDeleteProposal Committee = types.Committee
GeneralShutdownPermission = types.GeneralShutdownPermission CommitteeChangeProposal = types.CommitteeChangeProposal
GenesisState = types.GenesisState CommitteeDeleteProposal = types.CommitteeDeleteProposal
GodPermission = types.GodPermission GenesisState = types.GenesisState
InflationRateChangePermission = types.InflationRateChangePermission GodPermission = types.GodPermission
MsgSubmitProposal = types.MsgSubmitProposal MsgSubmitProposal = types.MsgSubmitProposal
MsgVote = types.MsgVote MsgVote = types.MsgVote
Permission = types.Permission ParamChangePermission = types.ParamChangePermission
Proposal = types.Proposal Permission = types.Permission
PubProposal = types.PubProposal Proposal = types.Proposal
QueryCommitteeParams = types.QueryCommitteeParams PubProposal = types.PubProposal
QueryProposalParams = types.QueryProposalParams QueryCommitteeParams = types.QueryCommitteeParams
QueryVoteParams = types.QueryVoteParams QueryProposalParams = types.QueryProposalParams
ShutdownCDPDepsitPermission = types.ShutdownCDPDepsitPermission QueryVoteParams = types.QueryVoteParams
Vote = types.Vote ShutdownPermission = types.ShutdownPermission
Vote = types.Vote
) )

View File

@ -32,7 +32,7 @@ func (AppModuleBasic) Name() string {
// RegisterCodec register module codec // RegisterCodec register module codec
func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
RegisterCodec(cdc) RegisterAppCodec(cdc)
} }
// DefaultGenesis default genesis state // DefaultGenesis default genesis state

View File

@ -12,32 +12,47 @@ var ModuleCdc *codec.Codec
func init() { func init() {
cdc := codec.New() cdc := codec.New()
RegisterModuleCodec(cdc)
ModuleCdc = cdc.Seal()
}
// TODO decide if not using gov's Content type would be better
func RegisterModuleCodec(cdc *codec.Codec) {
cdc.RegisterInterface((*gov.Content)(nil), nil) // registering the Content interface on the ModuleCdc will not conflict with gov. cdc.RegisterInterface((*gov.Content)(nil), nil) // registering the Content interface on the ModuleCdc will not conflict with gov.
// TODO ideally dist and params would register their proposals on here at their init. However can't change them so: // Ideally dist and params would register their proposals on here at their init. However can't change them so:
cdc.RegisterConcrete(distribution.CommunityPoolSpendProposal{}, "cosmos-sdk/CommunityPoolSpendProposal", nil) cdc.RegisterConcrete(distribution.CommunityPoolSpendProposal{}, "cosmos-sdk/CommunityPoolSpendProposal", nil)
cdc.RegisterConcrete(params.ParameterChangeProposal{}, "cosmos-sdk/ParameterChangeProposal", nil) cdc.RegisterConcrete(params.ParameterChangeProposal{}, "cosmos-sdk/ParameterChangeProposal", nil)
cdc.RegisterConcrete(gov.TextProposal{}, "cosmos-sdk/TextProposal", nil) cdc.RegisterConcrete(gov.TextProposal{}, "cosmos-sdk/TextProposal", nil)
cdc.RegisterConcrete(gov.SoftwareUpgradeProposal{}, "cosmos-sdk/SoftwareUpgradeProposal", nil) cdc.RegisterConcrete(gov.SoftwareUpgradeProposal{}, "cosmos-sdk/SoftwareUpgradeProposal", nil)
RegisterCodec(cdc) RegisterAppCodec(cdc)
ModuleCdc = cdc.Seal()
} }
// RegisterCodec registers the necessary types for the module // RegisterCodec registers the necessary types for the module
func RegisterCodec(cdc *codec.Codec) { func RegisterAppCodec(cdc *codec.Codec) {
// Proposals
// The app codec needs the gov.Content type registered. This is done by the gov module. // The app codec needs the gov.Content type registered. This is done by the gov module.
// Ideally it would registered here as well in case these modules are ever used separately. // Ideally it would registered here as well in case these modules are ever used separately.
// However amino panics if you register the same interface a second time. So leaving it out for now. // However amino panics if you register the same interface a second time. So leaving it out for now.
// cdc.RegisterInterface((*gov.Content)(nil), nil)
//cdc.RegisterInterface((*gov.Content)(nil), nil)
cdc.RegisterConcrete(CommitteeChangeProposal{}, "kava/CommitteeChangeProposal", nil) cdc.RegisterConcrete(CommitteeChangeProposal{}, "kava/CommitteeChangeProposal", nil)
cdc.RegisterConcrete(CommitteeDeleteProposal{}, "kava/CommitteeDeleteProposal", nil) cdc.RegisterConcrete(CommitteeDeleteProposal{}, "kava/CommitteeDeleteProposal", nil)
// Permissions
cdc.RegisterInterface((*Permission)(nil), nil) cdc.RegisterInterface((*Permission)(nil), nil)
cdc.RegisterConcrete(GodPermission{}, "kava/GodPermission", nil) cdc.RegisterConcrete(GodPermission{}, "kava/GodPermission", nil)
cdc.RegisterConcrete(ParamChangePermission{}, "kava/ParamChangePermission", nil)
cdc.RegisterConcrete(ShutdownPermission{}, "kava/ShutdownPermission", nil)
// Msgs
cdc.RegisterConcrete(MsgSubmitProposal{}, "kava/MsgSubmitProposal", nil) cdc.RegisterConcrete(MsgSubmitProposal{}, "kava/MsgSubmitProposal", nil)
cdc.RegisterConcrete(MsgVote{}, "kava/MsgVote", nil) cdc.RegisterConcrete(MsgVote{}, "kava/MsgVote", nil)
} }
// RegisterProposalTypeCodec registers an external proposal content type defined
// in another module for the internal ModuleCdc. This allows the MsgSubmitProposal
// to be correctly Amino encoded and decoded.
func RegisterProposalTypeCodec(o interface{}, name string) {
ModuleCdc.RegisterConcrete(o, name, nil)
}

View File

@ -25,15 +25,6 @@ func init() {
// Gov proposals need to be registered on gov's ModuleCdc so MsgSubmitProposal can be encoded. // Gov proposals need to be registered on gov's ModuleCdc so MsgSubmitProposal can be encoded.
govtypes.RegisterProposalType(ProposalTypeCommitteeChange) govtypes.RegisterProposalType(ProposalTypeCommitteeChange)
govtypes.RegisterProposalTypeCodec(CommitteeChangeProposal{}, "kava/CommitteeChangeProposal") govtypes.RegisterProposalTypeCodec(CommitteeChangeProposal{}, "kava/CommitteeChangeProposal")
// Since these proposals include Permissions that needs to be registered as well (including the interface and concrete types)
govtypes.ModuleCdc.RegisterInterface((*Permission)(nil), nil)
govtypes.RegisterProposalTypeCodec(GodPermission{}, "kava/GodPermission")
// TODO register other permissions here
// TODO write these
//RegisterProposalType(ProposalTypeCommitteeChange)
//RegisterProposalTypeCodec(CommitteeChangeProposal{}, "kava/CommitteeChangeProposal")
// How will we register distribution and params proposals on this codec?
} }
func NewCommitteeChangeProposal(title string, description string, newCommittee Committee) CommitteeChangeProposal { func NewCommitteeChangeProposal(title string, description string, newCommittee Committee) CommitteeChangeProposal {
@ -83,12 +74,9 @@ type CommitteeDeleteProposal struct {
var _ govtypes.Content = CommitteeDeleteProposal{} var _ govtypes.Content = CommitteeDeleteProposal{}
func init() { func init() {
// Gov proposals need to be registered on gov's ModuleCdc so MsgSubmitProposal can be encoded.
govtypes.RegisterProposalType(ProposalTypeCommitteeDelete) govtypes.RegisterProposalType(ProposalTypeCommitteeDelete)
govtypes.RegisterProposalTypeCodec(CommitteeDeleteProposal{}, "kava/CommitteeDeleteProposal") govtypes.RegisterProposalTypeCodec(CommitteeDeleteProposal{}, "kava/CommitteeDeleteProposal")
// TODO write these
//RegisterProposalType(ProposalTypeCommitteeDelete)
//RegisterProposalTypeCodec(CommitteeDeleteProposal{}, "kava/CommitteeDeleteProposal")
// How will we register distribution and params proposals on this codec?
} }
func NewCommitteeDeleteProposal(title string, description string, committeeID uint64) CommitteeDeleteProposal { func NewCommitteeDeleteProposal(title string, description string, committeeID uint64) CommitteeDeleteProposal {

View File

@ -6,64 +6,110 @@ import (
sdtypes "github.com/kava-labs/kava/x/shutdown/types" sdtypes "github.com/kava-labs/kava/x/shutdown/types"
) )
// EXAMPLE PERMISSIONS ------------------------------ func init() {
// Gov proposals need to be registered on gov's ModuleCdc.
// But since proposals contain Permissions, those types also need registering.
gov.ModuleCdc.RegisterInterface((*Permission)(nil), nil)
gov.RegisterProposalTypeCodec(GodPermission{}, "kava/GodPermission")
gov.RegisterProposalTypeCodec(ParamChangePermission{}, "kava/ParamChangePermission")
gov.RegisterProposalTypeCodec(ShutdownPermission{}, "kava/ShutdownPermission")
}
// GodPermission allows any governance proposal. It is used mainly for testing.
type GodPermission struct{} type GodPermission struct{}
var _ Permission = GodPermission{}
func (GodPermission) Allows(gov.Content) bool { return true } func (GodPermission) Allows(gov.Content) bool { return true }
// Allow only changes to inflation_rate func (GodPermission) MarshalYAML() (interface{}, error) {
type InflationRateChangePermission struct{} valueToMarshal := struct {
Type string `yaml:"type"`
}{
Type: "god_permission",
}
return valueToMarshal, nil
}
var _ Permission = InflationRateChangePermission{} // ParamChangeProposal only allows changes to certain params
type ParamChangePermission struct {
AllowedParams AllowedParams `json:"allowed_params" yaml:"allowed_params"`
}
func (InflationRateChangePermission) Allows(p gov.Content) bool { var _ Permission = ParamChangePermission{}
pcp, ok := p.(params.ParameterChangeProposal)
func (perm ParamChangePermission) Allows(p gov.Content) bool {
proposal, ok := p.(params.ParameterChangeProposal)
if !ok { if !ok {
return false return false
} }
for _, pc := range pcp.Changes { for _, change := range proposal.Changes {
if pc.Key == "inflation_rate" { if !perm.AllowedParams.Contains(change) {
return false
}
}
return true
}
func (perm ParamChangePermission) MarshalYAML() (interface{}, error) {
valueToMarshal := struct {
Type string `yaml:"type"`
AllowedParams AllowedParams `yaml:"allowed_params`
}{
Type: "param_change_permission",
AllowedParams: perm.AllowedParams,
}
return valueToMarshal, nil
}
type AllowedParam struct {
Subspace string `json:"subspace" yaml:"subspace"`
Key string `json:"key" yaml:"key"`
Subkey string `json:"subkey,omitempty" yaml:"subkey,omitempty"`
}
type AllowedParams []AllowedParam
func (allowed AllowedParams) Contains(paramChange params.ParamChange) bool {
for _, p := range allowed {
if paramChange.Subspace == p.Subspace && paramChange.Key == p.Key && paramChange.Subkey == p.Subkey {
return true return true
} }
} }
return false return false
} }
// Allow only shutdown of the CDP Deposit msg // ShutdownPermission allows certain message types to be disabled
type ShutdownCDPDepsitPermission struct{} type ShutdownPermission struct {
var _ Permission = ShutdownCDPDepsitPermission{}
func (ShutdownCDPDepsitPermission) Allows(p gov.Content) bool {
sdp, ok := p.(sdtypes.ShutdownProposal)
if !ok {
return false
}
for _, r := range sdp.MsgRoutes {
if r.Route == "cdp" && r.Msg == "MsgCDPDeposit" {
return true
}
}
return false
}
// Same as above but the route isn't static
type GeneralShutdownPermission struct {
MsgRoute sdtypes.MsgRoute `json:"msg_route" yaml:"msg_route"` MsgRoute sdtypes.MsgRoute `json:"msg_route" yaml:"msg_route"`
} }
var _ Permission = GeneralShutdownPermission{} var _ Permission = ShutdownPermission{}
func (perm GeneralShutdownPermission) Allows(p gov.Content) bool { func (perm ShutdownPermission) Allows(p gov.Content) bool {
sdp, ok := p.(sdtypes.ShutdownProposal) proposal, ok := p.(sdtypes.ShutdownProposal)
if !ok { if !ok {
return false return false
} }
for _, r := range sdp.MsgRoutes { for _, r := range proposal.MsgRoutes {
if r == perm.MsgRoute { if r == perm.MsgRoute {
return true return true
} }
} }
return false return false
} }
func (perm ShutdownPermission) MarshalYAML() (interface{}, error) {
valueToMarshal := struct {
Type string `yaml:"type"`
MsgRoute sdtypes.MsgRoute `yaml:"msg_route"`
}{
Type: "shutdown_permission",
MsgRoute: perm.MsgRoute,
}
return valueToMarshal, nil
}
// TODO add more permissions?
// - limit parameter changes to bew withing small ranges or fixed sets
// - allow community spend proposals
// - allow committee change proposals

View File

@ -19,9 +19,12 @@ var (
// A Committee is a collection of addresses that are allowed to vote and enact any governance proposal that passes their permissions. // A Committee is a collection of addresses that are allowed to vote and enact any governance proposal that passes their permissions.
type Committee struct { type Committee struct {
ID uint64 `json:"id" yaml:"id"` // TODO or a name? ID uint64 `json:"id" yaml:"id"`
//Description string `json:"description" yaml:"description"`
Members []sdk.AccAddress `json:"members" yaml:"members"` Members []sdk.AccAddress `json:"members" yaml:"members"`
Permissions []Permission `json:"permissions" yaml:"permissions"` Permissions []Permission `json:"permissions" yaml:"permissions"`
// VoteThreshold sdk.Dec `json:"vote_threshold" yaml:"vote_threshold"`
// MaxProposalDuration time.Duration `json:"max_proposal_duration" yaml:"max_proposal_duration"`
} }
func NewCommittee(id uint64, members []sdk.AccAddress, permissions []Permission) Committee { func NewCommittee(id uint64, members []sdk.AccAddress, permissions []Permission) Committee {