feat(gov,group): improve metadata checks and add docs (#16235)

This commit is contained in:
Julien Robert 2023-05-22 13:54:42 +02:00 committed by GitHub
parent 38f27e3d1a
commit 2c702e6563
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 127 additions and 16 deletions

View File

@ -122,6 +122,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### State Machine Breaking
* (x/group,x/gov) [#16235](https://github.com/cosmos/cosmos-sdk/pull/16235) A group and gov proposal is rejected if the proposal metadata title and summary do not match the proposal title and summary.
* (x/staking) [#15701](https://github.com/cosmos/cosmos-sdk/pull/15701) The `HistoricalInfoKey` has been updated to use a binary format.
* (x/slashing) [#15580](https://github.com/cosmos/cosmos-sdk/pull/15580) The validator slashing window now stores "chunked" bitmap entries for each validator's signing window instead of a single boolean entry per signing window index.
* (x/feegrant) [#14294](https://github.com/cosmos/cosmos-sdk/pull/14294) Moved the logic of rejecting duplicate grant from `msg_server` to `keeper` method.
@ -202,19 +203,19 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/gov) [#16106](https://github.com/cosmos/cosmos-sdk/pull/16106) Remove gRPC query methods from Keeper
* (x/gov) [#16118](https://github.com/cosmos/cosmos-sdk/pull/16118/) Use collections for constituion and params state management.
* (x/gov) [#16127](https://github.com/cosmos/cosmos-sdk/pull/16127) Use collections for deposit state management:
- The following methods are removed from the gov keeper: `GetDeposit`, `GetAllDeposits`, `IterateAllDeposits`.
- The following functions are removed from the gov types: `DepositKey`, `DepositsKey`.
* The following methods are removed from the gov keeper: `GetDeposit`, `GetAllDeposits`, `IterateAllDeposits`.
* The following functions are removed from the gov types: `DepositKey`, `DepositsKey`.
* (x/gov) [#16164](https://github.com/cosmos/cosmos-sdk/pull/16164) Use collections for vote state management:
- Removed: types `VoteKey`, `VoteKeys`
- Removed: keeper `IterateVotes`, `IterateAllVotes`, `GetVotes`, `GetVote`, `SetVote`
* Removed: types `VoteKey`, `VoteKeys`
* Removed: keeper `IterateVotes`, `IterateAllVotes`, `GetVotes`, `GetVote`, `SetVote`
* (x/gov) [#16171](https://github.com/cosmos/cosmos-sdk/pull/16171) Use collections for proposal state management (part 1):
- Removed: keeper: `GetProposal`, `UnmarshalProposal`, `MarshalProposal`, `IterateProposal`, `GetProposal`, `GetProposalFiltered`, `GetProposals`, `GetProposalID`, `SetProposalID`
- Remove: errors unused errors
* Removed: keeper: `GetProposal`, `UnmarshalProposal`, `MarshalProposal`, `IterateProposal`, `GetProposal`, `GetProposalFiltered`, `GetProposals`, `GetProposalID`, `SetProposalID`
* Remove: errors unused errors
* (sims) [#16155](https://github.com/cosmos/cosmos-sdk/pull/16155)
* `simulation.NewOperationMsg` now marshals the operation msg as proto bytes instead of legacy amino JSON bytes.
* `simulation.NewOperationMsg` is now 2-arity instead of 3-arity with the obsolete argument `codec.ProtoCodec` removed.
* The field `OperationMsg.Msg` is now of type `[]byte` instead of `json.RawMessage`.
* `simulation.NewOperationMsg` now marshals the operation msg as proto bytes instead of legacy amino JSON bytes.
* `simulation.NewOperationMsg` is now 2-arity instead of 3-arity with the obsolete argument `codec.ProtoCodec` removed.
* The field `OperationMsg.Msg` is now of type `[]byte` instead of `json.RawMessage`.
* (cli) [#16209](https://github.com/cosmos/cosmos-sdk/pull/16209) Add API `StartCmdWithOptions` to create customized start command.

View File

@ -7118,6 +7118,7 @@ type Proposal struct {
// voting_end_time is the end time of voting on a proposal.
VotingEndTime *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=voting_end_time,json=votingEndTime,proto3" json:"voting_end_time,omitempty"`
// metadata is any arbitrary metadata attached to the proposal.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/gov#proposal-3
Metadata string `protobuf:"bytes,10,opt,name=metadata,proto3" json:"metadata,omitempty"`
// title is the title of the proposal
//
@ -7332,7 +7333,8 @@ type Vote struct {
Voter string `protobuf:"bytes,2,opt,name=voter,proto3" json:"voter,omitempty"`
// options is the weighted vote options.
Options []*WeightedVoteOption `protobuf:"bytes,4,rep,name=options,proto3" json:"options,omitempty"`
// metadata is any arbitrary metadata to attached to the vote.
// metadata is any arbitrary metadata to attached to the vote.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/gov#vote-5
Metadata string `protobuf:"bytes,5,opt,name=metadata,proto3" json:"metadata,omitempty"`
}

View File

@ -7832,6 +7832,7 @@ type GroupInfo struct {
// admin is the account address of the group's admin.
Admin string `protobuf:"bytes,2,opt,name=admin,proto3" json:"admin,omitempty"`
// metadata is any arbitrary metadata to attached to the group.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/group#group-1
Metadata string `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"`
// version is used to track changes to a group's membership structure that
// would break existing proposals. Whenever any members weight is changed,
@ -7965,6 +7966,7 @@ type GroupPolicyInfo struct {
// admin is the account address of the group admin.
Admin string `protobuf:"bytes,3,opt,name=admin,proto3" json:"admin,omitempty"`
// metadata is any arbitrary metadata attached to the group policy.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/group#decision-policy-1
Metadata string `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"`
// version is used to track changes to a group's GroupPolicyInfo structure that
// would create a different result on a running proposal.
@ -8058,6 +8060,7 @@ type Proposal struct {
// group_policy_address is the account address of group policy.
GroupPolicyAddress string `protobuf:"bytes,2,opt,name=group_policy_address,json=groupPolicyAddress,proto3" json:"group_policy_address,omitempty"`
// metadata is any arbitrary metadata attached to the proposal.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/group#proposal-4
Metadata string `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"`
// proposers are the account addresses of the proposers.
Proposers []string `protobuf:"bytes,4,rep,name=proposers,proto3" json:"proposers,omitempty"`
@ -8280,7 +8283,7 @@ func (x *TallyResult) GetNoWithVetoCount() string {
return ""
}
// Vote represents a vote for a proposal.
// Vote represents a vote for a proposal.string metadata
type Vote struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -8293,6 +8296,7 @@ type Vote struct {
// option is the voter's choice on the proposal.
Option VoteOption `protobuf:"varint,3,opt,name=option,proto3,enum=cosmos.group.v1.VoteOption" json:"option,omitempty"`
// metadata is any arbitrary metadata attached to the vote.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/group#vote-2
Metadata string `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"`
// submit_time is the timestamp when the vote was submitted.
SubmitTime *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=submit_time,json=submitTime,proto3" json:"submit_time,omitempty"`

View File

@ -80,6 +80,7 @@ message Proposal {
google.protobuf.Timestamp voting_end_time = 9 [(gogoproto.stdtime) = true];
// metadata is any arbitrary metadata attached to the proposal.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/gov#proposal-3
string metadata = 10;
// title is the title of the proposal
@ -150,7 +151,8 @@ message Vote {
// options is the weighted vote options.
repeated WeightedVoteOption options = 4;
// metadata is any arbitrary metadata to attached to the vote.
// metadata is any arbitrary metadata to attached to the vote.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/gov#vote-5
string metadata = 5;
}

View File

@ -131,6 +131,7 @@ message GroupInfo {
string admin = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// metadata is any arbitrary metadata to attached to the group.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/group#group-1
string metadata = 3;
// version is used to track changes to a group's membership structure that
@ -171,6 +172,7 @@ message GroupPolicyInfo {
string admin = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// metadata is any arbitrary metadata attached to the group policy.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/group#decision-policy-1
string metadata = 4;
// version is used to track changes to a group's GroupPolicyInfo structure that
@ -199,6 +201,7 @@ message Proposal {
string group_policy_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// metadata is any arbitrary metadata attached to the proposal.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/group#proposal-4
string metadata = 3;
// proposers are the account addresses of the proposers.
@ -313,7 +316,7 @@ message TallyResult {
string no_with_veto_count = 4;
}
// Vote represents a vote for a proposal.
// Vote represents a vote for a proposal.string metadata
message Vote {
// proposal is the unique ID of the proposal.
uint64 proposal_id = 1;
@ -325,6 +328,7 @@ message Vote {
VoteOption option = 3;
// metadata is any arbitrary metadata attached to the vote.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/group#vote-2
string metadata = 4;
// submit_time is the timestamp when the vote was submitted.

View File

@ -2,6 +2,7 @@ package keeper
import (
"context"
"encoding/json"
"fmt"
"strconv"
@ -47,11 +48,28 @@ func (k msgServer) SubmitProposal(goCtx context.Context, msg *v1.MsgSubmitPropos
return nil, err
}
// Check that either metadata or Msgs length is non nil.
// check that either metadata or Msgs length is non nil.
if len(msg.Messages) == 0 && len(msg.Metadata) == 0 {
return nil, errors.Wrap(govtypes.ErrNoProposalMsgs, "either metadata or Msgs length must be non-nil")
}
// verify that if present, the metadata title and summary equals the proposal title and summary
if len(msg.Metadata) != 0 {
proposalMetadata := govtypes.ProposalMetadata{}
if err := json.Unmarshal([]byte(msg.Metadata), &proposalMetadata); err == nil {
if proposalMetadata.Title != msg.Title {
return nil, errors.Wrapf(govtypes.ErrInvalidProposalContent, "metadata title '%s' must equal proposal title '%s'", proposalMetadata.Title, msg.Title)
}
if proposalMetadata.Summary != msg.Summary {
return nil, errors.Wrapf(govtypes.ErrInvalidProposalContent, "metadata summary '%s' must equal proposal summary '%s'", proposalMetadata.Summary, msg.Summary)
}
}
// if we can't unmarshal the metadata, this means the client didn't use the recommended metadata format
// nothing can be done here, and this is still a valid case, so we ignore the error
}
proposalMsgs, err := msg.GetMsgs()
if err != nil {
return nil, err

View File

@ -102,6 +102,36 @@ func (suite *KeeperTestSuite) TestSubmitProposalReq() {
expErr: true,
expErrMsg: "proposal summary cannot be empty",
},
"title != metadata.title": {
preRun: func() (*v1.MsgSubmitProposal, error) {
return v1.NewMsgSubmitProposal(
[]sdk.Msg{bankMsg},
initialDeposit,
proposer.String(),
"{\"title\":\"Proposal\", \"description\":\"description of proposal\"}",
"Proposal2",
"description of proposal",
false,
)
},
expErr: true,
expErrMsg: "metadata title 'Proposal' must equal proposal title 'Proposal2",
},
"summary != metadata.summary": {
preRun: func() (*v1.MsgSubmitProposal, error) {
return v1.NewMsgSubmitProposal(
[]sdk.Msg{bankMsg},
initialDeposit,
proposer.String(),
"{\"title\":\"Proposal\", \"description\":\"description of proposal\"}",
"Proposal",
"description",
false,
)
},
expErr: true,
expErrMsg: "metadata summary '' must equal proposal summary 'description'",
},
"metadata too long": {
preRun: func() (*v1.MsgSubmitProposal, error) {
return v1.NewMsgSubmitProposal(

View File

@ -264,6 +264,7 @@ type Proposal struct {
// voting_end_time is the end time of voting on a proposal.
VotingEndTime *time.Time `protobuf:"bytes,9,opt,name=voting_end_time,json=votingEndTime,proto3,stdtime" json:"voting_end_time,omitempty"`
// metadata is any arbitrary metadata attached to the proposal.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/gov#proposal-3
Metadata string `protobuf:"bytes,10,opt,name=metadata,proto3" json:"metadata,omitempty"`
// title is the title of the proposal
//
@ -496,7 +497,8 @@ type Vote struct {
Voter string `protobuf:"bytes,2,opt,name=voter,proto3" json:"voter,omitempty"`
// options is the weighted vote options.
Options []*WeightedVoteOption `protobuf:"bytes,4,rep,name=options,proto3" json:"options,omitempty"`
// metadata is any arbitrary metadata to attached to the vote.
// metadata is any arbitrary metadata to attached to the vote.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/gov#vote-5
Metadata string `protobuf:"bytes,5,opt,name=metadata,proto3" json:"metadata,omitempty"`
}

View File

@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/binary"
"encoding/json"
"fmt"
"strings"
@ -16,6 +17,8 @@ import (
"github.com/cosmos/cosmos-sdk/x/group/errors"
"github.com/cosmos/cosmos-sdk/x/group/internal/math"
"github.com/cosmos/cosmos-sdk/x/group/internal/orm"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
)
var _ group.MsgServer = Keeper{}
@ -527,6 +530,23 @@ func (k Keeper) SubmitProposal(goCtx context.Context, msg *group.MsgSubmitPropos
return nil, err
}
// verify that if present, the metadata title and summary equals the proposal title and summary
if len(msg.Metadata) != 0 {
proposalMetadata := govtypes.ProposalMetadata{}
if err := json.Unmarshal([]byte(msg.Metadata), &proposalMetadata); err == nil {
if proposalMetadata.Title != msg.Title {
return nil, fmt.Errorf("metadata title '%s' must equal proposal title '%s'", proposalMetadata.Title, msg.Title)
}
if proposalMetadata.Summary != msg.Summary {
return nil, fmt.Errorf("metadata summary '%s' must equal proposal summary '%s'", proposalMetadata.Summary, msg.Summary)
}
}
// if we can't unmarshal the metadata, this means the client didn't use the recommended metadata format
// nothing can be done here, and this is still a valid case, so we ignore the error
}
msgs, err := msg.GetMsgs()
if err != nil {
return nil, errorsmod.Wrap(err, "request msgs")

View File

@ -1695,6 +1695,30 @@ func (s *TestSuite) TestSubmitProposal() {
expProposal: defaultProposal,
postRun: func(sdkCtx sdk.Context) {},
},
"title != metadata.title": {
req: &group.MsgSubmitProposal{
GroupPolicyAddress: accountAddr.String(),
Proposers: []string{addr2.String()},
Metadata: "{\"title\":\"title\",\"summary\":\"description\"}",
Title: "title2",
Summary: "description",
},
expErr: true,
expErrMsg: "metadata title 'title' must equal proposal title 'title2'",
postRun: func(sdkCtx sdk.Context) {},
},
"summary != metadata.summary": {
req: &group.MsgSubmitProposal{
GroupPolicyAddress: accountAddr.String(),
Proposers: []string{addr2.String()},
Metadata: "{\"title\":\"title\",\"summary\":\"description of proposal\"}",
Title: "title",
Summary: "description",
},
expErr: true,
expErrMsg: "metadata summary 'description of proposal' must equal proposal summary 'description'",
postRun: func(sdkCtx sdk.Context) {},
},
"metadata too long": {
req: &group.MsgSubmitProposal{
GroupPolicyAddress: accountAddr.String(),

View File

@ -491,6 +491,7 @@ type GroupInfo struct {
// admin is the account address of the group's admin.
Admin string `protobuf:"bytes,2,opt,name=admin,proto3" json:"admin,omitempty"`
// metadata is any arbitrary metadata to attached to the group.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/group#group-1
Metadata string `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"`
// version is used to track changes to a group's membership structure that
// would break existing proposals. Whenever any members weight is changed,
@ -642,6 +643,7 @@ type GroupPolicyInfo struct {
// admin is the account address of the group admin.
Admin string `protobuf:"bytes,3,opt,name=admin,proto3" json:"admin,omitempty"`
// metadata is any arbitrary metadata attached to the group policy.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/group#decision-policy-1
Metadata string `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"`
// version is used to track changes to a group's GroupPolicyInfo structure that
// would create a different result on a running proposal.
@ -695,6 +697,7 @@ type Proposal struct {
// group_policy_address is the account address of group policy.
GroupPolicyAddress string `protobuf:"bytes,2,opt,name=group_policy_address,json=groupPolicyAddress,proto3" json:"group_policy_address,omitempty"`
// metadata is any arbitrary metadata attached to the proposal.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/group#proposal-4
Metadata string `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"`
// proposers are the account addresses of the proposers.
Proposers []string `protobuf:"bytes,4,rep,name=proposers,proto3" json:"proposers,omitempty"`
@ -813,7 +816,7 @@ func (m *TallyResult) XXX_DiscardUnknown() {
var xxx_messageInfo_TallyResult proto.InternalMessageInfo
// Vote represents a vote for a proposal.
// Vote represents a vote for a proposal.string metadata
type Vote struct {
// proposal is the unique ID of the proposal.
ProposalId uint64 `protobuf:"varint,1,opt,name=proposal_id,json=proposalId,proto3" json:"proposal_id,omitempty"`
@ -822,6 +825,7 @@ type Vote struct {
// option is the voter's choice on the proposal.
Option VoteOption `protobuf:"varint,3,opt,name=option,proto3,enum=cosmos.group.v1.VoteOption" json:"option,omitempty"`
// metadata is any arbitrary metadata attached to the vote.
// the recommended format of the metadata is to be found here: https://docs.cosmos.network/v0.47/modules/group#vote-2
Metadata string `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"`
// submit_time is the timestamp when the vote was submitted.
SubmitTime time.Time `protobuf:"bytes,5,opt,name=submit_time,json=submitTime,proto3,stdtime" json:"submit_time"`