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

View File

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

View File

@ -12,32 +12,47 @@ var ModuleCdc *codec.Codec
func init() {
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.
// 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(params.ParameterChangeProposal{}, "cosmos-sdk/ParameterChangeProposal", nil)
cdc.RegisterConcrete(gov.TextProposal{}, "cosmos-sdk/TextProposal", nil)
cdc.RegisterConcrete(gov.SoftwareUpgradeProposal{}, "cosmos-sdk/SoftwareUpgradeProposal", nil)
RegisterCodec(cdc)
ModuleCdc = cdc.Seal()
RegisterAppCodec(cdc)
}
// 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.
// 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.
//cdc.RegisterInterface((*gov.Content)(nil), nil)
// cdc.RegisterInterface((*gov.Content)(nil), nil)
cdc.RegisterConcrete(CommitteeChangeProposal{}, "kava/CommitteeChangeProposal", nil)
cdc.RegisterConcrete(CommitteeDeleteProposal{}, "kava/CommitteeDeleteProposal", nil)
// Permissions
cdc.RegisterInterface((*Permission)(nil), 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(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.
govtypes.RegisterProposalType(ProposalTypeCommitteeChange)
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 {
@ -83,12 +74,9 @@ type CommitteeDeleteProposal struct {
var _ govtypes.Content = CommitteeDeleteProposal{}
func init() {
// Gov proposals need to be registered on gov's ModuleCdc so MsgSubmitProposal can be encoded.
govtypes.RegisterProposalType(ProposalTypeCommitteeDelete)
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 {

View File

@ -6,64 +6,110 @@ import (
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{}
var _ Permission = GodPermission{}
func (GodPermission) Allows(gov.Content) bool { return true }
// Allow only changes to inflation_rate
type InflationRateChangePermission struct{}
func (GodPermission) MarshalYAML() (interface{}, error) {
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 {
pcp, ok := p.(params.ParameterChangeProposal)
var _ Permission = ParamChangePermission{}
func (perm ParamChangePermission) Allows(p gov.Content) bool {
proposal, ok := p.(params.ParameterChangeProposal)
if !ok {
return false
}
for _, pc := range pcp.Changes {
if pc.Key == "inflation_rate" {
for _, change := range proposal.Changes {
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 false
}
// Allow only shutdown of the CDP Deposit msg
type ShutdownCDPDepsitPermission 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 {
// ShutdownPermission allows certain message types to be disabled
type ShutdownPermission struct {
MsgRoute sdtypes.MsgRoute `json:"msg_route" yaml:"msg_route"`
}
var _ Permission = GeneralShutdownPermission{}
var _ Permission = ShutdownPermission{}
func (perm GeneralShutdownPermission) Allows(p gov.Content) bool {
sdp, ok := p.(sdtypes.ShutdownProposal)
func (perm ShutdownPermission) Allows(p gov.Content) bool {
proposal, ok := p.(sdtypes.ShutdownProposal)
if !ok {
return false
}
for _, r := range sdp.MsgRoutes {
for _, r := range proposal.MsgRoutes {
if r == perm.MsgRoute {
return true
}
}
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.
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"`
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 {