Co-authored-by: son trinh <trinhleson2000@gmail.com>
This commit is contained in:
parent
68ec945293
commit
9adce9e987
@ -2204,8 +2204,6 @@ Example Output:
|
||||
|
||||
The `params` endpoint allows users to query all parameters for the `gov` module.
|
||||
|
||||
<!-- TODO: #10197 Querying governance params outputs nil values -->
|
||||
|
||||
Using legacy v1beta1:
|
||||
|
||||
```bash
|
||||
@ -2225,16 +2223,6 @@ Example Output:
|
||||
"voting_params": {
|
||||
"voting_period": "172800s"
|
||||
},
|
||||
"deposit_params": {
|
||||
"min_deposit": [
|
||||
],
|
||||
"max_deposit_period": "0s"
|
||||
},
|
||||
"tally_params": {
|
||||
"quorum": "0.000000000000000000",
|
||||
"threshold": "0.000000000000000000",
|
||||
"veto_threshold": "0.000000000000000000"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -2270,6 +2258,8 @@ Example Output:
|
||||
}
|
||||
```
|
||||
|
||||
Note: `params_type` are deprecated in v1 since all params are stored in Params.
|
||||
|
||||
#### deposits
|
||||
|
||||
The `deposits` endpoint allows users to query a deposit for a given proposal from a given depositor.
|
||||
|
||||
@ -2,6 +2,9 @@ package utils_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/cometbft/cometbft/rpc/client/mock"
|
||||
@ -13,6 +16,7 @@ import (
|
||||
"cosmossdk.io/x/gov"
|
||||
"cosmossdk.io/x/gov/client/utils"
|
||||
v1 "cosmossdk.io/x/gov/types/v1"
|
||||
"cosmossdk.io/x/gov/types/v1beta1"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil"
|
||||
@ -24,9 +28,12 @@ type TxSearchMock struct {
|
||||
txConfig client.TxConfig
|
||||
mock.Client
|
||||
txs []cmttypes.Tx
|
||||
|
||||
// use for filter tx with query conditions
|
||||
msgsSet [][]sdk.Msg
|
||||
}
|
||||
|
||||
func (mock TxSearchMock) TxSearch(ctx context.Context, query string, prove bool, page, perPage *int, orderBy string) (*coretypes.ResultTxSearch, error) {
|
||||
func (mock TxSearchMock) TxSearch(ctx context.Context, query string, _ bool, page, perPage *int, _ string) (*coretypes.ResultTxSearch, error) {
|
||||
if page == nil {
|
||||
*page = 0
|
||||
}
|
||||
@ -40,8 +47,11 @@ func (mock TxSearchMock) TxSearch(ctx context.Context, query string, prove bool,
|
||||
// nil result with nil error crashes utils.QueryTxsByEvents
|
||||
return &coretypes.ResultTxSearch{}, nil
|
||||
}
|
||||
txs, err := mock.filterTxs(query, start, end)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txs := mock.txs[start:end]
|
||||
rst := &coretypes.ResultTxSearch{Txs: make([]*coretypes.ResultTx, len(txs)), TotalCount: len(txs)}
|
||||
for i := range txs {
|
||||
rst.Txs[i] = &coretypes.ResultTx{Tx: txs[i]}
|
||||
@ -54,6 +64,74 @@ func (mock TxSearchMock) Block(ctx context.Context, height *int64) (*coretypes.R
|
||||
return &coretypes.ResultBlock{Block: &cmttypes.Block{}}, nil
|
||||
}
|
||||
|
||||
// mock applying the query string in TxSearch
|
||||
func (mock TxSearchMock) filterTxs(query string, start, end int) ([]cmttypes.Tx, error) {
|
||||
filterTxs := []cmttypes.Tx{}
|
||||
proposalIdStr, senderAddr := getQueryAttributes(query)
|
||||
if senderAddr != "" {
|
||||
proposalId, err := strconv.ParseUint(proposalIdStr, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i, msgs := range mock.msgsSet {
|
||||
for _, msg := range msgs {
|
||||
if voteMsg, ok := msg.(*v1beta1.MsgVote); ok {
|
||||
if voteMsg.Voter == senderAddr && voteMsg.ProposalId == proposalId {
|
||||
filterTxs = append(filterTxs, mock.txs[i])
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if voteMsg, ok := msg.(*v1.MsgVote); ok {
|
||||
if voteMsg.Voter == senderAddr && voteMsg.ProposalId == proposalId {
|
||||
filterTxs = append(filterTxs, mock.txs[i])
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if voteWeightedMsg, ok := msg.(*v1beta1.MsgVoteWeighted); ok {
|
||||
if voteWeightedMsg.Voter == senderAddr && voteWeightedMsg.ProposalId == proposalId {
|
||||
filterTxs = append(filterTxs, mock.txs[i])
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if voteWeightedMsg, ok := msg.(*v1.MsgVoteWeighted); ok {
|
||||
if voteWeightedMsg.Voter == senderAddr && voteWeightedMsg.ProposalId == proposalId {
|
||||
filterTxs = append(filterTxs, mock.txs[i])
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
filterTxs = append(filterTxs, mock.txs...)
|
||||
}
|
||||
|
||||
if len(filterTxs) < end {
|
||||
return filterTxs, nil
|
||||
}
|
||||
|
||||
return filterTxs[start:end], nil
|
||||
}
|
||||
|
||||
// getQueryAttributes extracts value from query string
|
||||
func getQueryAttributes(q string) (proposalId, senderAddr string) {
|
||||
splitStr := strings.Split(q, " OR ")
|
||||
if len(splitStr) >= 2 {
|
||||
keySender := strings.Trim(splitStr[1], ")")
|
||||
senderAddr = strings.Trim(strings.Split(keySender, "=")[1], "'")
|
||||
|
||||
keyProposal := strings.Split(q, " AND ")[0]
|
||||
proposalId = strings.Trim(strings.Split(keyProposal, "=")[1], "'")
|
||||
} else {
|
||||
proposalId = strings.Trim(strings.Split(splitStr[0], "=")[1], "'")
|
||||
}
|
||||
|
||||
return proposalId, senderAddr
|
||||
}
|
||||
|
||||
func TestGetPaginatedVotes(t *testing.T) {
|
||||
cdcOpts := codectestutil.CodecOptions{}
|
||||
encCfg := moduletestutil.MakeTestEncodingConfig(cdcOpts, gov.AppModule{})
|
||||
@ -178,3 +256,113 @@ func TestGetPaginatedVotes(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSingleVote(t *testing.T) {
|
||||
cdcOpts := codectestutil.CodecOptions{}
|
||||
encCfg := moduletestutil.MakeTestEncodingConfig(cdcOpts, gov.AppModule{})
|
||||
|
||||
type testCase struct {
|
||||
description string
|
||||
msgs [][]sdk.Msg
|
||||
votes []v1.Vote
|
||||
expErr string
|
||||
}
|
||||
acc1 := make(sdk.AccAddress, 20)
|
||||
acc1[0] = 1
|
||||
acc1Str, err := cdcOpts.GetAddressCodec().BytesToString(acc1)
|
||||
require.NoError(t, err)
|
||||
acc2 := make(sdk.AccAddress, 20)
|
||||
acc2[0] = 2
|
||||
acc2Str, err := cdcOpts.GetAddressCodec().BytesToString(acc2)
|
||||
require.NoError(t, err)
|
||||
acc1Msgs := []sdk.Msg{
|
||||
v1.NewMsgVote(acc1Str, 0, v1.OptionYes, ""),
|
||||
v1.NewMsgVote(acc1Str, 0, v1.OptionYes, ""),
|
||||
v1.NewMsgDeposit(acc1Str, 0, sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(10)))), // should be ignored
|
||||
}
|
||||
acc2Msgs := []sdk.Msg{
|
||||
v1.NewMsgVote(acc2Str, 0, v1.OptionYes, ""),
|
||||
v1.NewMsgVoteWeighted(acc2Str, 0, v1.NewNonSplitVoteOption(v1.OptionYes), ""),
|
||||
v1beta1.NewMsgVoteWeighted(acc2Str, 0, v1beta1.NewNonSplitVoteOption(v1beta1.OptionYes)),
|
||||
}
|
||||
for _, tc := range []testCase{
|
||||
{
|
||||
description: "no vote found: no msgVote",
|
||||
msgs: [][]sdk.Msg{
|
||||
acc1Msgs[:1],
|
||||
},
|
||||
votes: []v1.Vote{},
|
||||
expErr: "did not vote on proposalID",
|
||||
},
|
||||
{
|
||||
description: "no vote found: wrong proposal ID",
|
||||
msgs: [][]sdk.Msg{
|
||||
acc1Msgs[:1],
|
||||
},
|
||||
votes: []v1.Vote{},
|
||||
expErr: "did not vote on proposalID",
|
||||
},
|
||||
{
|
||||
description: "query 2 voter vote",
|
||||
msgs: [][]sdk.Msg{
|
||||
acc1Msgs,
|
||||
acc2Msgs[:1],
|
||||
},
|
||||
votes: []v1.Vote{
|
||||
v1.NewVote(0, acc1Str, v1.NewNonSplitVoteOption(v1.OptionYes), ""),
|
||||
v1.NewVote(0, acc2Str, v1.NewNonSplitVoteOption(v1.OptionYes), ""),
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "query 2 voter vote with v1beta1",
|
||||
msgs: [][]sdk.Msg{
|
||||
acc1Msgs,
|
||||
acc2Msgs[2:],
|
||||
},
|
||||
votes: []v1.Vote{
|
||||
v1.NewVote(0, acc1Str, v1.NewNonSplitVoteOption(v1.OptionYes), ""),
|
||||
v1.NewVote(0, acc2Str, v1.NewNonSplitVoteOption(v1.OptionYes), ""),
|
||||
},
|
||||
},
|
||||
} {
|
||||
tc := tc
|
||||
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
marshaled := make([]cmttypes.Tx, len(tc.msgs))
|
||||
cli := TxSearchMock{txs: marshaled, txConfig: encCfg.TxConfig, msgsSet: tc.msgs}
|
||||
clientCtx := client.Context{}.
|
||||
WithLegacyAmino(encCfg.Amino).
|
||||
WithClient(cli).
|
||||
WithTxConfig(encCfg.TxConfig).
|
||||
WithAddressCodec(cdcOpts.GetAddressCodec()).
|
||||
WithCodec(encCfg.Codec)
|
||||
|
||||
for i := range tc.msgs {
|
||||
txBuilder := clientCtx.TxConfig.NewTxBuilder()
|
||||
err := txBuilder.SetMsgs(tc.msgs[i]...)
|
||||
require.NoError(t, err)
|
||||
|
||||
tx, err := clientCtx.TxConfig.TxEncoder()(txBuilder.GetTx())
|
||||
require.NoError(t, err)
|
||||
marshaled[i] = tx
|
||||
}
|
||||
|
||||
// testing query single vote
|
||||
for i, v := range tc.votes {
|
||||
accAddr, err := clientCtx.AddressCodec.StringToBytes(v.Voter)
|
||||
require.NoError(t, err)
|
||||
voteParams := utils.QueryVoteParams{ProposalID: 0, Voter: accAddr}
|
||||
voteData, err := utils.QueryVoteByTxQuery(clientCtx, voteParams)
|
||||
if tc.expErr != "" {
|
||||
require.Error(t, err)
|
||||
require.True(t, strings.Contains(err.Error(), tc.expErr))
|
||||
continue
|
||||
}
|
||||
require.NoError(t, err)
|
||||
vote := v1.Vote{}
|
||||
require.NoError(t, clientCtx.Codec.UnmarshalJSON(voteData, &vote))
|
||||
require.Equal(t, v, vote, fmt.Sprintf("vote should be equal at entry %v", i))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
package gov_test
|
||||
|
||||
import (
|
||||
"cosmossdk.io/math"
|
||||
"cosmossdk.io/x/gov/types/v1beta1"
|
||||
stakingtypes "cosmossdk.io/x/staking/types"
|
||||
)
|
||||
|
||||
var (
|
||||
TestProposal = v1beta1.NewTextProposal("Test", "description")
|
||||
TestDescription = stakingtypes.NewDescription("T", "E", "S", "T", "Z")
|
||||
TestCommissionRates = stakingtypes.NewCommissionRates(math.LegacyZeroDec(), math.LegacyZeroDec(), math.LegacyZeroDec())
|
||||
)
|
||||
@ -157,6 +157,11 @@ func (k Keeper) AddDeposit(ctx context.Context, proposalID uint64, depositorAddr
|
||||
activatedVotingPeriod = true
|
||||
}
|
||||
|
||||
addr, err := k.authKeeper.AddressCodec().BytesToString(depositorAddr)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Add or update deposit object
|
||||
deposit, err := k.Deposits.Get(ctx, collections.Join(proposalID, depositorAddr))
|
||||
switch {
|
||||
@ -165,10 +170,6 @@ func (k Keeper) AddDeposit(ctx context.Context, proposalID uint64, depositorAddr
|
||||
deposit.Amount = sdk.NewCoins(deposit.Amount...).Add(depositAmount...)
|
||||
case errors.IsOf(err, collections.ErrNotFound):
|
||||
// deposit doesn't exist
|
||||
addr, err := k.authKeeper.AddressCodec().BytesToString(depositorAddr)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
deposit = v1.NewDeposit(proposalID, addr, depositAmount)
|
||||
default:
|
||||
// failed to get deposit
|
||||
@ -181,14 +182,9 @@ func (k Keeper) AddDeposit(ctx context.Context, proposalID uint64, depositorAddr
|
||||
return false, err
|
||||
}
|
||||
|
||||
depositorStrAddr, err := k.authKeeper.AddressCodec().BytesToString(depositorAddr)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if err := k.EventService.EventManager(ctx).EmitKV(
|
||||
types.EventTypeProposalDeposit,
|
||||
event.NewAttribute(types.AttributeKeyDepositor, depositorStrAddr),
|
||||
event.NewAttribute(types.AttributeKeyDepositor, addr),
|
||||
event.NewAttribute(sdk.AttributeKeyAmount, depositAmount.String()),
|
||||
event.NewAttribute(types.AttributeKeyProposalID, fmt.Sprintf("%d", proposalID)),
|
||||
); err != nil {
|
||||
|
||||
@ -27,11 +27,15 @@ func (k Keeper) SubmitProposal(ctx context.Context, messages []sdk.Msg, metadata
|
||||
return v1.Proposal{}, err
|
||||
}
|
||||
|
||||
proposerAddr, err := k.authKeeper.AddressCodec().BytesToString(proposer)
|
||||
if err != nil {
|
||||
return v1.Proposal{}, err
|
||||
}
|
||||
|
||||
// additional checks per proposal types
|
||||
switch proposalType {
|
||||
case v1.ProposalType_PROPOSAL_TYPE_OPTIMISTIC:
|
||||
proposerStr, _ := k.authKeeper.AddressCodec().BytesToString(proposer)
|
||||
if len(params.OptimisticAuthorizedAddresses) > 0 && !slices.Contains(params.OptimisticAuthorizedAddresses, proposerStr) {
|
||||
if len(params.OptimisticAuthorizedAddresses) > 0 && !slices.Contains(params.OptimisticAuthorizedAddresses, proposerAddr) {
|
||||
return v1.Proposal{}, errorsmod.Wrap(types.ErrInvalidProposer, "proposer is not authorized to submit optimistic proposal")
|
||||
}
|
||||
case v1.ProposalType_PROPOSAL_TYPE_MULTIPLE_CHOICE:
|
||||
@ -43,20 +47,35 @@ func (k Keeper) SubmitProposal(ctx context.Context, messages []sdk.Msg, metadata
|
||||
msgs := make([]string, 0, len(messages)) // will hold a string slice of all Msg type URLs.
|
||||
|
||||
// Loop through all messages and confirm that each has a handler and the gov module account as the only signer
|
||||
var currentMessagedBasedParams *v1.MessageBasedParams
|
||||
for _, msg := range messages {
|
||||
msgs = append(msgs, sdk.MsgTypeURL(msg))
|
||||
|
||||
// check if any of the message has message based params
|
||||
hasMessagedBasedParams, err := k.MessageBasedParams.Has(ctx, sdk.MsgTypeURL(msg))
|
||||
hasMessagedBasedParams := true
|
||||
messagedBasedParams, err := k.MessageBasedParams.Get(ctx, sdk.MsgTypeURL(msg))
|
||||
if err != nil {
|
||||
return v1.Proposal{}, err
|
||||
if !errorsmod.IsOf(err, collections.ErrNotFound) {
|
||||
return v1.Proposal{}, err
|
||||
}
|
||||
|
||||
hasMessagedBasedParams = false
|
||||
}
|
||||
|
||||
if hasMessagedBasedParams {
|
||||
// TODO(@julienrbrt), in the future, we can check if all messages have the same params
|
||||
// and if so, we can allow the proposal.
|
||||
if len(messages) > 1 {
|
||||
return v1.Proposal{}, errorsmod.Wrap(types.ErrInvalidProposalMsg, "cannot submit multiple messages proposal with message based params")
|
||||
// set initial value for currentMessagedBasedParams
|
||||
if currentMessagedBasedParams == nil {
|
||||
currentMessagedBasedParams = &messagedBasedParams
|
||||
}
|
||||
|
||||
// check if newly fetched messagedBasedParams is different from the previous fetched params
|
||||
isEqual, err := currentMessagedBasedParams.Equal(&messagedBasedParams)
|
||||
if err != nil {
|
||||
return v1.Proposal{}, err
|
||||
}
|
||||
|
||||
if len(messages) > 1 && !isEqual {
|
||||
return v1.Proposal{}, errorsmod.Wrap(types.ErrInvalidProposalMsg, "cannot submit multiple messages proposal with different message based params")
|
||||
}
|
||||
|
||||
if proposalType != v1.ProposalType_PROPOSAL_TYPE_STANDARD {
|
||||
@ -131,10 +150,6 @@ func (k Keeper) SubmitProposal(ctx context.Context, messages []sdk.Msg, metadata
|
||||
return v1.Proposal{}, err
|
||||
}
|
||||
|
||||
proposerAddr, err := k.authKeeper.AddressCodec().BytesToString(proposer)
|
||||
if err != nil {
|
||||
return v1.Proposal{}, err
|
||||
}
|
||||
submitTime := k.HeaderService.HeaderInfo(ctx).Time
|
||||
proposal, err := v1.NewProposal(messages, proposalID, submitTime, submitTime.Add(*params.MaxDepositPeriod), metadata, title, summary, proposerAddr, proposalType)
|
||||
if err != nil {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -18,38 +19,6 @@ import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// TODO(tip): remove this
|
||||
func (suite *KeeperTestSuite) TestDeleteProposal() {
|
||||
testCases := map[string]struct {
|
||||
proposalType v1.ProposalType
|
||||
}{
|
||||
"unspecified proposal type": {},
|
||||
"regular proposal": {
|
||||
proposalType: v1.ProposalType_PROPOSAL_TYPE_STANDARD,
|
||||
},
|
||||
"expedited proposal": {
|
||||
proposalType: v1.ProposalType_PROPOSAL_TYPE_EXPEDITED,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
// delete non-existing proposal
|
||||
suite.Require().ErrorIs(suite.govKeeper.DeleteProposal(suite.ctx, 10), collections.ErrNotFound)
|
||||
|
||||
tp := TestProposal
|
||||
proposal, err := suite.govKeeper.SubmitProposal(suite.ctx, tp, "", "test", "summary", suite.addrs[0], tc.proposalType)
|
||||
suite.Require().NoError(err)
|
||||
proposalID := proposal.Id
|
||||
err = suite.govKeeper.Proposals.Set(suite.ctx, proposal.Id, proposal)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.Require().NotPanics(func() {
|
||||
err := suite.govKeeper.DeleteProposal(suite.ctx, proposalID)
|
||||
suite.Require().NoError(err)
|
||||
}, "")
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestActivateVotingPeriod() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
@ -147,6 +116,24 @@ func (suite *KeeperTestSuite) TestSubmitProposal() {
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// add 1 more messageBasedParams with the same value as above
|
||||
err = suite.govKeeper.MessageBasedParams.Set(suite.ctx, sdk.MsgTypeURL(&v1.MsgSudoExec{}), v1.MessageBasedParams{
|
||||
VotingPeriod: func() *time.Duration { t := time.Hour * 24 * 7; return &t }(),
|
||||
Quorum: "0.4",
|
||||
Threshold: "0.50",
|
||||
VetoThreshold: "0.66",
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// add 1 more messageBasedParams with different value as above
|
||||
err = suite.govKeeper.MessageBasedParams.Set(suite.ctx, sdk.MsgTypeURL(&v1.MsgCancelProposal{}), v1.MessageBasedParams{
|
||||
VotingPeriod: func() *time.Duration { t := time.Hour * 24 * 7; return &t }(),
|
||||
Quorum: "0.2",
|
||||
Threshold: "0.4",
|
||||
VetoThreshold: "0.7",
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
testCases := []struct {
|
||||
msgs []sdk.Msg
|
||||
metadata string
|
||||
@ -156,6 +143,12 @@ func (suite *KeeperTestSuite) TestSubmitProposal() {
|
||||
{legacyProposal(&tp, govAcct), "", v1.ProposalType_PROPOSAL_TYPE_STANDARD, nil},
|
||||
// normal proposal with msg with custom params
|
||||
{[]sdk.Msg{&v1.MsgUpdateParams{Authority: govAcct}}, "", v1.ProposalType_PROPOSAL_TYPE_STANDARD, nil},
|
||||
// normal proposal with 2 identical msgs with custom params
|
||||
{[]sdk.Msg{&v1.MsgUpdateParams{Authority: govAcct}, &v1.MsgUpdateParams{Authority: govAcct}}, "", v1.ProposalType_PROPOSAL_TYPE_STANDARD, nil},
|
||||
// normal proposal with 2 msgs with custom params shared the same value
|
||||
{[]sdk.Msg{&v1.MsgUpdateParams{Authority: govAcct}, &v1.MsgSudoExec{Authority: govAcct}}, "", v1.ProposalType_PROPOSAL_TYPE_STANDARD, nil},
|
||||
// normal proposal with 2 msgs with different custom params
|
||||
{[]sdk.Msg{&v1.MsgUpdateParams{Authority: govAcct}, &v1.MsgCancelProposal{}}, "", v1.ProposalType_PROPOSAL_TYPE_STANDARD, errors.New("cannot submit multiple messages proposal with different message based params")},
|
||||
{legacyProposal(&tp, govAcct), "", v1.ProposalType_PROPOSAL_TYPE_EXPEDITED, nil},
|
||||
{nil, "", v1.ProposalType_PROPOSAL_TYPE_MULTIPLE_CHOICE, nil},
|
||||
// Keeper does not check the validity of title and description, no error
|
||||
|
||||
@ -98,7 +98,7 @@ func (k Keeper) tallyStandard(ctx context.Context, proposal v1.Proposal, totalVo
|
||||
}
|
||||
|
||||
// If no one votes (everyone abstains), proposal fails
|
||||
if totalVoterPower.Sub(results[v1.OptionAbstain]).Equal(math.LegacyZeroDec()) {
|
||||
if totalVoterPower.Equal(results[v1.OptionAbstain]) {
|
||||
return false, false, tallyResults, nil
|
||||
}
|
||||
|
||||
@ -142,7 +142,7 @@ func (k Keeper) tallyExpedited(totalVoterPower math.LegacyDec, totalBonded math.
|
||||
}
|
||||
|
||||
// If no one votes (everyone abstains), proposal fails
|
||||
if totalVoterPower.Sub(results[v1.OptionAbstain]).Equal(math.LegacyZeroDec()) {
|
||||
if totalVoterPower.Equal(results[v1.OptionAbstain]) {
|
||||
return false, false, tallyResults, nil
|
||||
}
|
||||
|
||||
@ -160,7 +160,6 @@ func (k Keeper) tallyExpedited(totalVoterPower math.LegacyDec, totalBonded math.
|
||||
|
||||
// If more than 2/3 of non-abstaining voters vote Yes, proposal passes
|
||||
threshold, _ := math.LegacyNewDecFromStr(params.GetExpeditedThreshold())
|
||||
|
||||
if results[v1.OptionYes].Quo(totalVoterPower.Sub(results[v1.OptionAbstain])).GT(threshold) {
|
||||
return true, false, tallyResults, nil
|
||||
}
|
||||
@ -206,7 +205,6 @@ func (k Keeper) tallyMultipleChoice(totalVoterPower math.LegacyDec, totalBonded
|
||||
}
|
||||
|
||||
// a multiple choice proposal always passes unless it was spam or quorum was not reached.
|
||||
|
||||
return true, false, tallyResults, nil
|
||||
}
|
||||
|
||||
|
||||
@ -57,9 +57,9 @@ func (k Keeper) AddVote(ctx context.Context, proposalID uint64, voterAddr sdk.Ac
|
||||
}
|
||||
|
||||
// verify votes only on existing votes
|
||||
if proposalOptionsStr.OptionOne == "" && option.Option == v1.OptionOne { // should never trigger option one is always mandatory
|
||||
if proposalOptionsStr.OptionOne == "" && option.Option == v1.OptionOne {
|
||||
return errors.Wrap(types.ErrInvalidVote, "invalid vote option")
|
||||
} else if proposalOptionsStr.OptionTwo == "" && option.Option == v1.OptionTwo { // should never trigger option two is always mandatory
|
||||
} else if proposalOptionsStr.OptionTwo == "" && option.Option == v1.OptionTwo {
|
||||
return errors.Wrap(types.ErrInvalidVote, "invalid vote option")
|
||||
} else if proposalOptionsStr.OptionThree == "" && option.Option == v1.OptionThree {
|
||||
return errors.Wrap(types.ErrInvalidVote, "invalid vote option")
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"cosmossdk.io/core/address"
|
||||
"cosmossdk.io/errors"
|
||||
sdkmath "cosmossdk.io/math"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -332,3 +333,104 @@ func (p MessageBasedParams) ValidateBasic() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p MessageBasedParams) Equal(params *MessageBasedParams) (bool, error) {
|
||||
if p.VotingPeriod != nil && params.VotingPeriod != nil {
|
||||
if p.VotingPeriod.Seconds() != params.VotingPeriod.Seconds() {
|
||||
return false, nil
|
||||
}
|
||||
} else if p.VotingPeriod == nil && params.VotingPeriod != nil ||
|
||||
p.VotingPeriod != nil && params.VotingPeriod == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
quorum1, err := sdkmath.LegacyNewDecFromStr(p.Quorum)
|
||||
if err != nil {
|
||||
if !errors.IsOf(err, sdkmath.ErrLegacyEmptyDecimalStr) {
|
||||
return false, fmt.Errorf("invalid quorum string: %w", err)
|
||||
}
|
||||
|
||||
quorum1 = sdkmath.LegacyZeroDec()
|
||||
}
|
||||
|
||||
quorum2, err := sdkmath.LegacyNewDecFromStr(params.Quorum)
|
||||
if err != nil {
|
||||
if !errors.IsOf(err, sdkmath.ErrLegacyEmptyDecimalStr) {
|
||||
return false, fmt.Errorf("invalid compared quorum string: %w", err)
|
||||
}
|
||||
|
||||
quorum2 = sdkmath.LegacyZeroDec()
|
||||
}
|
||||
|
||||
if !quorum1.Equal(quorum2) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
yesQuorum1, err := sdkmath.LegacyNewDecFromStr(p.YesQuorum)
|
||||
if err != nil {
|
||||
if !errors.IsOf(err, sdkmath.ErrLegacyEmptyDecimalStr) {
|
||||
return false, fmt.Errorf("invalid yes quorum string: %w", err)
|
||||
}
|
||||
|
||||
yesQuorum1 = sdkmath.LegacyZeroDec()
|
||||
}
|
||||
|
||||
yesQuorum2, err := sdkmath.LegacyNewDecFromStr(params.YesQuorum)
|
||||
if err != nil {
|
||||
if !errors.IsOf(err, sdkmath.ErrLegacyEmptyDecimalStr) {
|
||||
return false, fmt.Errorf("invalid compared yes quorum string: %w", err)
|
||||
}
|
||||
|
||||
yesQuorum2 = sdkmath.LegacyZeroDec()
|
||||
}
|
||||
|
||||
if !yesQuorum1.Equal(yesQuorum2) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
threshold1, err := sdkmath.LegacyNewDecFromStr(p.Threshold)
|
||||
if err != nil {
|
||||
if !errors.IsOf(err, sdkmath.ErrLegacyEmptyDecimalStr) {
|
||||
return false, fmt.Errorf("invalid vote threshold string: %w", err)
|
||||
}
|
||||
|
||||
threshold1 = sdkmath.LegacyZeroDec()
|
||||
}
|
||||
|
||||
threshold2, err := sdkmath.LegacyNewDecFromStr(params.Threshold)
|
||||
if err != nil {
|
||||
if !errors.IsOf(err, sdkmath.ErrLegacyEmptyDecimalStr) {
|
||||
return false, fmt.Errorf("invalid compared vote threshold string: %w", err)
|
||||
}
|
||||
|
||||
threshold2 = sdkmath.LegacyZeroDec()
|
||||
}
|
||||
|
||||
if !threshold1.Equal(threshold2) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
vetoThreshold1, err := sdkmath.LegacyNewDecFromStr(p.VetoThreshold)
|
||||
if err != nil {
|
||||
if !errors.IsOf(err, sdkmath.ErrLegacyEmptyDecimalStr) {
|
||||
return false, fmt.Errorf("invalid veto threshold string: %w", err)
|
||||
}
|
||||
|
||||
vetoThreshold1 = sdkmath.LegacyZeroDec()
|
||||
}
|
||||
|
||||
vetoThreshold2, err := sdkmath.LegacyNewDecFromStr(params.VetoThreshold)
|
||||
if err != nil {
|
||||
if !errors.IsOf(err, sdkmath.ErrLegacyEmptyDecimalStr) {
|
||||
return false, fmt.Errorf("invalid compared veto threshold string: %w", err)
|
||||
}
|
||||
|
||||
vetoThreshold2 = sdkmath.LegacyZeroDec()
|
||||
}
|
||||
|
||||
if !vetoThreshold1.Equal(vetoThreshold2) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ func (p Proposal) GetMsgs() ([]sdk.Msg, error) {
|
||||
// the proposal is expedited. Otherwise, returns the regular min deposit from
|
||||
// gov params.
|
||||
func (p Proposal) GetMinDepositFromParams(params Params) sdk.Coins {
|
||||
if p.Expedited {
|
||||
if p.ProposalType == ProposalType_PROPOSAL_TYPE_EXPEDITED {
|
||||
return params.ExpeditedMinDeposit
|
||||
}
|
||||
return params.MinDeposit
|
||||
|
||||
@ -9,8 +9,6 @@ import (
|
||||
var _ Router = (*router)(nil)
|
||||
|
||||
// Router implements a governance Handler router.
|
||||
//
|
||||
// TODO: Use generic router (ref #3976).
|
||||
type Router interface {
|
||||
AddRoute(r string, h Handler) (rtr Router)
|
||||
HasRoute(r string) bool
|
||||
|
||||
Loading…
Reference in New Issue
Block a user