refactor(group): Distinguish Voting period and Execution period for group policies (#11198)

## Description

Closes: #11092

## TODOs

I'm thinking to do the 2 todos in a separate PR, or else this PR is too big. WDYT?

- [ ] #11246 This involves adding a new index ProposalsByVotingPeriodEnd, so might be better to do in another PR
- [ ] #11245  Also should be done in a separate PR (as it needs the above index)

### Main change 1: Group policy proto defs have `voting_period` and `min_execution_period`

For group policies:

```diff
- // Within this times votes and exec messages can be submitted.
- // timeout is the duration from submission of a proposal to the end of voting period
- google.protobuf.Duration timeout = 2 [(gogoproto.stdduration) = true, (gogoproto.nullable) = false];

+  // voting_period is the duration from submission of a proposal to the end of voting period
+  // Within this times votes can be submitted with MsgVote.
+  google.protobuf.Duration voting_period = 2 [(gogoproto.stdduration) = true, (gogoproto.nullable) = false];

+  // min_execution_period is the minimum duration after the proposal submission
+  // where members can start sending MsgExec. This means that the window for
+  // sending a MsgExec transaction is:
+  // `[ submission + min_execution_period ; submission + voting_period + max_execution_period]`
+  // where max_execution_period is a app-specific config, defined in the keeper.
+  // If not set, min_execution_period will default to 0.
+  google.protobuf.Duration min_execution_period = 3 [(gogoproto.stdduration) = true, (gogoproto.nullable) = false];
```

### Main Change 2: We don't update proposal's FinalTallyResult result on MsgVote/MsgSubmitProposal

Unless the msg has TryExec set to true, in which case the FinalTallyResult is updated ONLY if the tally is final.

### Main Change 3: Add a keeper-level `MaxExecutionPeriod`

MsgExecs will be rejected if they are sent after `voting_period_end + MaxExecutionPeriod`



---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules)
- [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
This commit is contained in:
Amaury 2022-03-02 13:00:59 +01:00 committed by GitHub
parent 26c9a2d06d
commit da36c46f3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1937 additions and 743 deletions

View File

@ -3,15 +3,14 @@ package appv1alpha1
import (
fmt "fmt"
io "io"
reflect "reflect"
sync "sync"
runtime "github.com/cosmos/cosmos-proto/runtime"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoiface "google.golang.org/protobuf/runtime/protoiface"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
descriptorpb "google.golang.org/protobuf/types/descriptorpb"
io "io"
reflect "reflect"
sync "sync"
)
var _ protoreflect.List = (*_ModuleDescriptor_2_list)(nil)

View File

@ -4076,10 +4076,12 @@ type SnapshotIAVLItem struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
Version int64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"`
Height int32 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
// version is block height
Version int64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"`
// height is depth of the tree.
Height int32 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"`
}
func (x *SnapshotIAVLItem) Reset() {

File diff suppressed because it is too large Load Diff

View File

@ -3,16 +3,14 @@ package modulev1alpha1
import (
fmt "fmt"
io "io"
reflect "reflect"
sync "sync"
runtime "github.com/cosmos/cosmos-proto/runtime"
_ "github.com/cosmos/cosmos-sdk/api/cosmos/app/v1alpha1"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoiface "google.golang.org/protobuf/runtime/protoiface"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
_ "github.com/cosmos/cosmos-sdk/api/cosmos/app/v1alpha1"
io "io"
reflect "reflect"
sync "sync"
)
var (

View File

@ -3,15 +3,14 @@ package ormv1alpha1
import (
fmt "fmt"
io "io"
reflect "reflect"
sync "sync"
runtime "github.com/cosmos/cosmos-proto/runtime"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoiface "google.golang.org/protobuf/runtime/protoiface"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
descriptorpb "google.golang.org/protobuf/types/descriptorpb"
io "io"
reflect "reflect"
sync "sync"
)
var _ protoreflect.List = (*_TableDescriptor_2_list)(nil)

View File

@ -3,15 +3,14 @@ package ormv1alpha1
import (
fmt "fmt"
io "io"
reflect "reflect"
sync "sync"
runtime "github.com/cosmos/cosmos-proto/runtime"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoiface "google.golang.org/protobuf/runtime/protoiface"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
descriptorpb "google.golang.org/protobuf/types/descriptorpb"
io "io"
reflect "reflect"
sync "sync"
)
var _ protoreflect.List = (*_ModuleSchemaDescriptor_1_list)(nil)

View File

@ -41,9 +41,8 @@ message ThresholdDecisionPolicy {
// threshold is the minimum weighted sum of yes votes that must be met or exceeded for a proposal to succeed.
string threshold = 1;
// timeout is the duration from submission of a proposal to the end of voting period
// Within this times votes and exec messages can be submitted.
google.protobuf.Duration timeout = 2 [(gogoproto.stdduration) = true, (gogoproto.nullable) = false];
// windows defines the different windows for voting and execution.
DecisionPolicyWindows windows = 2;
}
// PercentageDecisionPolicy implements the DecisionPolicy interface
@ -53,9 +52,28 @@ message PercentageDecisionPolicy {
// percentage is the minimum percentage the weighted sum of yes votes must meet for a proposal to succeed.
string percentage = 1;
// timeout is the duration from submission of a proposal to the end of voting period
// Within these times votes and exec messages can be submitted.
google.protobuf.Duration timeout = 2 [(gogoproto.stdduration) = true, (gogoproto.nullable) = false];
// windows defines the different windows for voting and execution.
DecisionPolicyWindows windows = 2;
}
// DecisionPolicyWindows defines the different windows for voting and execution.
message DecisionPolicyWindows {
// voting_period is the duration from submission of a proposal to the end of voting period
// Within this times votes can be submitted with MsgVote.
google.protobuf.Duration voting_period = 1 [(gogoproto.stdduration) = true, (gogoproto.nullable) = false];
// min_execution_period is the minimum duration after the proposal submission
// where members can start sending MsgExec. This means that the window for
// sending a MsgExec transaction is:
// `[ submission + min_execution_period ; submission + voting_period + max_execution_period]`
// where max_execution_period is a app-specific config, defined in the keeper.
// If not set, min_execution_period will default to 0.
//
// Please make sure to set a `min_execution_period` that is smaller than
// `voting_period + max_execution_period`, or else the above execution window
// is empty, meaning that all proposals created with this decision policy
// won't be able to be executed.
google.protobuf.Duration min_execution_period = 2 [(gogoproto.stdduration) = true, (gogoproto.nullable) = false];
}
// VoteOption enumerates the valid vote options for a given proposal.
@ -184,11 +202,12 @@ message Proposal {
// has ended.
TallyResult final_tally_result = 10 [(gogoproto.nullable) = false];
// timeout is the timestamp before which both voting and execution must be
// done. If this timestamp is passed, then the proposal cannot be executed
// anymore and should be considered pending delete. This timestamp is checked
// against the block header's timestamp.
google.protobuf.Timestamp timeout = 11 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
// voting_period_end is the timestamp before which voting must be done.
// Unless a successfull MsgExec is called before (to execute a proposal whose
// tally is successful before the voting period ends), tallying will be done
// at this point, and the `final_tally_result`, as well
// as `status` and `result` fields will be accordingly updated.
google.protobuf.Timestamp voting_period_end = 11 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
// executor_result is the final result based on the votes and election rule. Initial value is NotRun.
ProposalExecutorResult executor_result = 12;

View File

@ -295,7 +295,7 @@ func NewSimApp(
app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec, app.msgSvcRouter, app.AccountKeeper)
groupConfig := groupkeeper.DefaultConfig()
groupConfig := group.DefaultConfig()
/*
Example of setting group params:
groupConfig.MaxMetadataLen = 1000

View File

@ -306,10 +306,12 @@ func (m *SnapshotStoreItem) GetName() string {
// SnapshotIAVLItem is an exported IAVL node.
type SnapshotIAVLItem struct {
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
Version int64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"`
Height int32 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"`
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
// version is block height
Version int64 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"`
// height is depth of the tree.
Height int32 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"`
}
func (m *SnapshotIAVLItem) Reset() { *m = SnapshotIAVLItem{} }

View File

@ -553,6 +553,8 @@ func (m *GetTxResponse) GetTxResponse() *types.TxResponse {
// GetBlockWithTxsRequest is the request type for the Service.GetBlockWithTxs
// RPC method.
//
// Since: cosmos-sdk 0.45.2
type GetBlockWithTxsRequest struct {
// height is the height of the block to query.
Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"`
@ -608,6 +610,8 @@ func (m *GetBlockWithTxsRequest) GetPagination() *query.PageRequest {
}
// GetBlockWithTxsResponse is the response type for the Service.GetBlockWithTxs method.
//
// Since: cosmos-sdk 0.45.2
type GetBlockWithTxsResponse struct {
// txs are the transactions in the block.
Txs []*Tx `protobuf:"bytes,1,rep,name=txs,proto3" json:"txs,omitempty"`

View File

@ -120,7 +120,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
val.Address.String(),
"1",
validMetadata,
fmt.Sprintf("{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"%d\", \"timeout\":\"30000s\"}", threshold),
fmt.Sprintf("{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"%d\", \"windows\":{\"voting_period\":\"30000s\"}}", threshold),
},
commonFlags...,
),
@ -140,7 +140,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
val.Address.String(),
"1",
validMetadata,
fmt.Sprintf("{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"%f\", \"timeout\":\"30000s\"}", percentage),
fmt.Sprintf("{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"%f\", \"windows\":{\"voting_period\":\"30000s\"}}", percentage),
},
commonFlags...,
),
@ -746,7 +746,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupWithPolicy() {
validMetadata,
validMetadata,
validMembersFile.Name(),
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
fmt.Sprintf("--%s=%v", client.FlagGroupPolicyAsAdmin, false),
},
commonFlags...,
@ -764,7 +764,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupWithPolicy() {
validMetadata,
validMetadata,
validMembersFile.Name(),
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
fmt.Sprintf("--%s=%v", client.FlagGroupPolicyAsAdmin, true),
},
commonFlags...,
@ -782,7 +782,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupWithPolicy() {
validMetadata,
validMetadata,
validMembersFile.Name(),
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
fmt.Sprintf("--%s=%v", client.FlagGroupPolicyAsAdmin, false),
fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
},
@ -801,7 +801,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupWithPolicy() {
strings.Repeat("a", 256),
validMetadata,
validMembersFile.Name(),
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
fmt.Sprintf("--%s=%v", client.FlagGroupPolicyAsAdmin, false),
},
commonFlags...,
@ -819,7 +819,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupWithPolicy() {
validMetadata,
strings.Repeat("a", 256),
validMembersFile.Name(),
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
fmt.Sprintf("--%s=%v", client.FlagGroupPolicyAsAdmin, false),
},
commonFlags...,
@ -837,7 +837,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupWithPolicy() {
validMetadata,
validMetadata,
invalidMembersAddressFile.Name(),
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
fmt.Sprintf("--%s=%v", client.FlagGroupPolicyAsAdmin, false),
},
commonFlags...,
@ -855,7 +855,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupWithPolicy() {
validMetadata,
validMetadata,
invalidMembersWeightFile.Name(),
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
fmt.Sprintf("--%s=%v", client.FlagGroupPolicyAsAdmin, false),
},
commonFlags...,
@ -873,7 +873,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupWithPolicy() {
validMetadata,
validMetadata,
invalidMembersMetadataFile.Name(),
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
fmt.Sprintf("--%s=%v", client.FlagGroupPolicyAsAdmin, false),
},
commonFlags...,
@ -932,7 +932,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupPolicy() {
val.Address.String(),
fmt.Sprintf("%v", groupID),
validMetadata,
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
},
commonFlags...,
),
@ -948,7 +948,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupPolicy() {
val.Address.String(),
fmt.Sprintf("%v", groupID),
validMetadata,
"{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"0.5\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"0.5\", \"windows\":{\"voting_period\":\"1s\"}}",
},
commonFlags...,
),
@ -964,7 +964,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupPolicy() {
val.Address.String(),
fmt.Sprintf("%v", groupID),
validMetadata,
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
},
commonFlags...,
@ -981,7 +981,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupPolicy() {
wrongAdmin.String(),
fmt.Sprintf("%v", groupID),
validMetadata,
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
},
commonFlags...,
),
@ -997,7 +997,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupPolicy() {
val.Address.String(),
fmt.Sprintf("%v", groupID),
strings.Repeat("a", 500),
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
},
commonFlags...,
),
@ -1013,7 +1013,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupPolicy() {
val.Address.String(),
"10",
validMetadata,
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
},
commonFlags...,
),
@ -1029,7 +1029,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupPolicy() {
val.Address.String(),
fmt.Sprintf("%v", groupID),
validMetadata,
"{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"-0.5\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"-0.5\", \"windows\":{\"voting_period\":\"1s\"}}",
},
commonFlags...,
),
@ -1045,7 +1045,7 @@ func (s *IntegrationTestSuite) TestTxCreateGroupPolicy() {
val.Address.String(),
fmt.Sprintf("%v", groupID),
validMetadata,
"{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"2\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"2\", \"windows\":{\"voting_period\":\"1s\"}}",
},
commonFlags...,
),
@ -1205,7 +1205,7 @@ func (s *IntegrationTestSuite) TestTxUpdateGroupPolicyDecisionPolicy() {
[]string{
groupPolicy.Admin,
groupPolicy.Address,
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"40000s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"40000s\"}}",
},
commonFlags...,
),
@ -1220,7 +1220,7 @@ func (s *IntegrationTestSuite) TestTxUpdateGroupPolicyDecisionPolicy() {
[]string{
groupPolicy.Admin,
groupPolicy.Address,
"{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"0.5\", \"timeout\":\"40000s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"0.5\", \"windows\":{\"voting_period\":\"40000s\"}}",
},
commonFlags...,
),
@ -1235,7 +1235,7 @@ func (s *IntegrationTestSuite) TestTxUpdateGroupPolicyDecisionPolicy() {
[]string{
groupPolicy.Admin,
groupPolicy.Address,
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"50000s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"50000s\"}}",
fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
},
commonFlags...,
@ -1251,7 +1251,7 @@ func (s *IntegrationTestSuite) TestTxUpdateGroupPolicyDecisionPolicy() {
[]string{
newAdmin.String(),
groupPolicy.Address,
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
},
commonFlags...,
),
@ -1266,7 +1266,7 @@ func (s *IntegrationTestSuite) TestTxUpdateGroupPolicyDecisionPolicy() {
[]string{
groupPolicy.Admin,
newAdmin.String(),
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.ThresholdDecisionPolicy\", \"threshold\":\"1\", \"windows\":{\"voting_period\":\"1s\"}}",
},
commonFlags...,
),
@ -1281,7 +1281,7 @@ func (s *IntegrationTestSuite) TestTxUpdateGroupPolicyDecisionPolicy() {
[]string{
groupPolicy.Admin,
groupPolicy.Address,
"{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"-0.5\", \"timeout\":\"1s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"-0.5\", \"windows\":{\"voting_period\":\"1s\"}}",
},
commonFlags...,
),
@ -1296,7 +1296,7 @@ func (s *IntegrationTestSuite) TestTxUpdateGroupPolicyDecisionPolicy() {
[]string{
groupPolicy.Admin,
groupPolicy.Address,
"{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"2\", \"timeout\":\"40000s\"}",
"{\"@type\":\"/cosmos.group.v1beta1.PercentageDecisionPolicy\", \"percentage\":\"2\", \"windows\":{\"voting_period\":\"40000s\"}}",
},
commonFlags...,
),

View File

@ -1,7 +1,12 @@
package keeper
package group
import "time"
// Config is a config struct used for intialising the group module to avoid using globals.
type Config struct {
// MaxExecutionPeriod defines the max duration after a proposal's voting
// period ends that members can send a MsgExec to execute the proposal.
MaxExecutionPeriod time.Duration
// MaxMetadataLen defines the max length of the metadata bytes field for various entities within the group module. Defaults to 255 if not explicitly set.
MaxMetadataLen uint64
}
@ -9,6 +14,7 @@ type Config struct {
// DefaultConfig returns the default config for group.
func DefaultConfig() Config {
return Config{
MaxMetadataLen: 255,
MaxExecutionPeriod: 2 * time.Hour * 24 * 7, // Two weeks.
MaxMetadataLen: 255,
}
}

View File

@ -31,7 +31,9 @@ func TestGenesisStateValidate(t *testing.T) {
}
err := groupPolicy.SetDecisionPolicy(&ThresholdDecisionPolicy{
Threshold: "1",
Timeout: time.Second,
Windows: &DecisionPolicyWindows{
VotingPeriod: time.Second,
},
})
require.NoError(t, err)
@ -45,7 +47,9 @@ func TestGenesisStateValidate(t *testing.T) {
}
err = groupPolicy2.SetDecisionPolicy(&ThresholdDecisionPolicy{
Threshold: "1",
Timeout: 0,
Windows: &DecisionPolicyWindows{
VotingPeriod: 0,
},
})
require.NoError(t, err)
@ -67,8 +71,8 @@ func TestGenesisStateValidate(t *testing.T) {
AbstainCount: "0",
NoWithVetoCount: "0",
},
Timeout: timeout,
ExecutorResult: PROPOSAL_EXECUTOR_RESULT_SUCCESS,
VotingPeriodEnd: timeout,
ExecutorResult: PROPOSAL_EXECUTOR_RESULT_SUCCESS,
}
err = proposal.SetMsgs([]sdk.Msg{&banktypes.MsgSend{
FromAddress: accAddr.String(),

View File

@ -73,7 +73,9 @@ func (s *GenesisTestSuite) TestInitExportGenesis() {
}
err := groupPolicy.SetDecisionPolicy(&group.ThresholdDecisionPolicy{
Threshold: "1",
Timeout: time.Second,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second,
},
})
s.Require().NoError(err)
@ -95,8 +97,8 @@ func (s *GenesisTestSuite) TestInitExportGenesis() {
AbstainCount: "0",
NoWithVetoCount: "0",
},
Timeout: timeout,
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_SUCCESS,
VotingPeriodEnd: timeout,
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_SUCCESS,
}
err = proposal.SetMsgs([]sdk.Msg{&banktypes.MsgSend{
FromAddress: accAddr.String(),
@ -216,7 +218,7 @@ func (s *GenesisTestSuite) assertProposalsEqual(g *group.Proposal, other *group.
require.Equal(g.Status, other.Status)
require.Equal(g.Result, other.Result)
require.Equal(g.FinalTallyResult, other.FinalTallyResult)
require.Equal(g.Timeout, other.Timeout)
require.Equal(g.VotingPeriodEnd, other.VotingPeriodEnd)
require.Equal(g.ExecutorResult, other.ExecutorResult)
require.Equal(g.GetMsgs(), other.GetMsgs())
}

View File

@ -10,6 +10,7 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/x/group"
"github.com/cosmos/cosmos-sdk/x/group/errors"
"github.com/cosmos/cosmos-sdk/x/group/internal/orm"
)
@ -303,3 +304,55 @@ func (q Keeper) getVotesByProposal(ctx sdk.Context, proposalID uint64, pageReque
func (q Keeper) getVotesByVoter(ctx sdk.Context, voter sdk.AccAddress, pageRequest *query.PageRequest) (orm.Iterator, error) {
return q.voteByVoterIndex.GetPaginated(ctx.KVStore(q.key), voter.Bytes(), pageRequest)
}
// Tally is a function that tallies a proposal by iterating through its votes,
// and returns the tally result without modifying the proposal or any state.
// TODO Merge with https://github.com/cosmos/cosmos-sdk/issues/11151
func (q Keeper) Tally(ctx sdk.Context, p group.Proposal, groupId uint64) (group.TallyResult, error) {
// If proposal has already been tallied and updated, then its status is
// closed, in which case we just return the previously stored result.
if p.Status == group.PROPOSAL_STATUS_CLOSED {
return p.FinalTallyResult, nil
}
it, err := q.voteByProposalIndex.Get(ctx.KVStore(q.key), p.Id)
if err != nil {
return group.TallyResult{}, err
}
defer it.Close()
tallyResult := group.DefaultTallyResult()
var vote group.Vote
for {
_, err = it.LoadNext(&vote)
if errors.ErrORMIteratorDone.Is(err) {
break
}
if err != nil {
return group.TallyResult{}, err
}
var member group.GroupMember
err := q.groupMemberTable.GetOne(ctx.KVStore(q.key), orm.PrimaryKey(&group.GroupMember{
GroupId: groupId,
Member: &group.Member{Address: vote.Voter},
}), &member)
switch {
case sdkerrors.ErrNotFound.Is(err):
// If the member left the group after voting, then we simply skip the
// vote.
continue
case err != nil:
// For any other errors, we stop and return the error.
return group.TallyResult{}, err
}
if err := tallyResult.Add(vote, member.Member.Weight); err != nil {
return group.TallyResult{}, sdkerrors.Wrap(err, "add new vote")
}
}
return tallyResult, nil
}

View File

@ -25,10 +25,9 @@ import (
type invariantTestSuite struct {
suite.Suite
ctx sdk.Context
cdc *codec.ProtoCodec
key *storetypes.KVStoreKey
blockTime time.Time
ctx sdk.Context
cdc *codec.ProtoCodec
key *storetypes.KVStoreKey
}
func TestInvariantTestSuite(t *testing.T) {
@ -81,7 +80,7 @@ func (s *invariantTestSuite) TestTallyVotesInvariant() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{YesCount: "1", NoCount: "0", AbstainCount: "0", NoWithVetoCount: "0"},
Timeout: prevCtx.BlockTime().Add(time.Second * 600),
VotingPeriodEnd: prevCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
},
@ -95,7 +94,7 @@ func (s *invariantTestSuite) TestTallyVotesInvariant() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{YesCount: "2", NoCount: "0", AbstainCount: "0", NoWithVetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
VotingPeriodEnd: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
},
},
@ -110,7 +109,7 @@ func (s *invariantTestSuite) TestTallyVotesInvariant() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{YesCount: "2", NoCount: "0", AbstainCount: "0", NoWithVetoCount: "0"},
Timeout: prevCtx.BlockTime().Add(time.Second * 600),
VotingPeriodEnd: prevCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
},
curProposal: &group.Proposal{
@ -123,7 +122,7 @@ func (s *invariantTestSuite) TestTallyVotesInvariant() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{YesCount: "1", NoCount: "0", AbstainCount: "0", NoWithVetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
VotingPeriodEnd: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
},
expBroken: true,
@ -139,7 +138,7 @@ func (s *invariantTestSuite) TestTallyVotesInvariant() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{YesCount: "0", NoCount: "2", AbstainCount: "0", NoWithVetoCount: "0"},
Timeout: prevCtx.BlockTime().Add(time.Second * 600),
VotingPeriodEnd: prevCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
},
curProposal: &group.Proposal{
@ -152,7 +151,7 @@ func (s *invariantTestSuite) TestTallyVotesInvariant() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{YesCount: "0", NoCount: "1", AbstainCount: "0", NoWithVetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
VotingPeriodEnd: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
},
expBroken: true,
@ -168,7 +167,7 @@ func (s *invariantTestSuite) TestTallyVotesInvariant() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{YesCount: "0", NoCount: "0", AbstainCount: "2", NoWithVetoCount: "0"},
Timeout: prevCtx.BlockTime().Add(time.Second * 600),
VotingPeriodEnd: prevCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
},
curProposal: &group.Proposal{
@ -181,7 +180,7 @@ func (s *invariantTestSuite) TestTallyVotesInvariant() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{YesCount: "0", NoCount: "0", AbstainCount: "1", NoWithVetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
VotingPeriodEnd: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
},
expBroken: true,
@ -197,7 +196,7 @@ func (s *invariantTestSuite) TestTallyVotesInvariant() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{YesCount: "0", NoCount: "0", AbstainCount: "0", NoWithVetoCount: "2"},
Timeout: prevCtx.BlockTime().Add(time.Second * 600),
VotingPeriodEnd: prevCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
},
curProposal: &group.Proposal{
@ -210,7 +209,7 @@ func (s *invariantTestSuite) TestTallyVotesInvariant() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{YesCount: "0", NoCount: "0", AbstainCount: "0", NoWithVetoCount: "1"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
VotingPeriodEnd: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
},
expBroken: true,
@ -413,7 +412,7 @@ func (s *invariantTestSuite) TestTallyVotesSumInvariant() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{YesCount: "4", NoCount: "3", AbstainCount: "0", NoWithVetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
VotingPeriodEnd: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
},
votes: []*group.Vote{
@ -471,7 +470,7 @@ func (s *invariantTestSuite) TestTallyVotesSumInvariant() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{YesCount: "6", NoCount: "0", AbstainCount: "0", NoWithVetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
VotingPeriodEnd: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
},
votes: []*group.Vote{
@ -529,7 +528,7 @@ func (s *invariantTestSuite) TestTallyVotesSumInvariant() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{YesCount: "4", NoCount: "3", AbstainCount: "0", NoWithVetoCount: "0"},
Timeout: curCtx.BlockTime().Add(time.Second * 600),
VotingPeriodEnd: curCtx.BlockTime().Add(time.Second * 600),
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
},
votes: []*group.Vote{
@ -561,7 +560,7 @@ func (s *invariantTestSuite) TestTallyVotesSumInvariant() {
_, err := groupTable.Create(cacheCurCtx.KVStore(key), groupsInfo)
s.Require().NoError(err)
err = groupPolicy.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Second))
err = groupPolicy.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Second, 0))
s.Require().NoError(err)
err = groupPolicyTable.Create(cacheCurCtx.KVStore(key), groupPolicy)
s.Require().NoError(err)

View File

@ -74,10 +74,10 @@ type Keeper struct {
router *authmiddleware.MsgServiceRouter
config Config
config group.Config
}
func NewKeeper(storeKey storetypes.StoreKey, cdc codec.Codec, router *authmiddleware.MsgServiceRouter, accKeeper group.AccountKeeper, config Config) Keeper {
func NewKeeper(storeKey storetypes.StoreKey, cdc codec.Codec, router *authmiddleware.MsgServiceRouter, accKeeper group.AccountKeeper, config group.Config) Keeper {
k := Keeper{
key: storeKey,
router: router,
@ -207,7 +207,10 @@ func NewKeeper(storeKey storetypes.StoreKey, cdc codec.Codec, router *authmiddle
k.voteTable = *voteTable
if config.MaxMetadataLen == 0 {
config.MaxMetadataLen = DefaultConfig().MaxMetadataLen
config.MaxMetadataLen = group.DefaultConfig().MaxMetadataLen
}
if config.MaxExecutionPeriod == 0 {
config.MaxExecutionPeriod = group.DefaultConfig().MaxExecutionPeriod
}
k.config = config

View File

@ -61,6 +61,7 @@ func (s *TestSuite) SetupTest() {
policy := group.NewThresholdDecisionPolicy(
"2",
time.Second,
0,
)
policyReq := &group.MsgCreateGroupPolicy{
Admin: s.addrs[0].String(),
@ -693,6 +694,7 @@ func (s *TestSuite) TestCreateGroupWithPolicy() {
policy: group.NewThresholdDecisionPolicy(
"1",
time.Second,
0,
),
},
"group policy as admin is true": {
@ -704,6 +706,7 @@ func (s *TestSuite) TestCreateGroupWithPolicy() {
policy: group.NewThresholdDecisionPolicy(
"1",
time.Second,
0,
),
},
"group metadata too long": {
@ -716,6 +719,7 @@ func (s *TestSuite) TestCreateGroupWithPolicy() {
policy: group.NewThresholdDecisionPolicy(
"1",
time.Second,
0,
),
expErr: true,
expErrMsg: "limit exceeded",
@ -730,6 +734,7 @@ func (s *TestSuite) TestCreateGroupWithPolicy() {
policy: group.NewThresholdDecisionPolicy(
"1",
time.Second,
0,
),
expErr: true,
expErrMsg: "limit exceeded",
@ -747,6 +752,7 @@ func (s *TestSuite) TestCreateGroupWithPolicy() {
policy: group.NewThresholdDecisionPolicy(
"1",
time.Second,
0,
),
expErr: true,
expErrMsg: "limit exceeded",
@ -763,6 +769,7 @@ func (s *TestSuite) TestCreateGroupWithPolicy() {
policy: group.NewThresholdDecisionPolicy(
"1",
time.Second,
0,
),
expErr: true,
expErrMsg: "expected a positive decimal",
@ -776,6 +783,7 @@ func (s *TestSuite) TestCreateGroupWithPolicy() {
policy: group.NewThresholdDecisionPolicy(
"10",
time.Second,
0,
),
expErr: false,
},
@ -876,6 +884,7 @@ func (s *TestSuite) TestCreateGroupPolicy() {
policy: group.NewThresholdDecisionPolicy(
"1",
time.Second,
0,
),
},
"all good with percentage decision policy": {
@ -886,6 +895,7 @@ func (s *TestSuite) TestCreateGroupPolicy() {
policy: group.NewPercentageDecisionPolicy(
"0.5",
time.Second,
0,
),
},
"decision policy threshold > total group weight": {
@ -896,6 +906,7 @@ func (s *TestSuite) TestCreateGroupPolicy() {
policy: group.NewThresholdDecisionPolicy(
"10",
time.Second,
0,
),
},
"group id does not exists": {
@ -906,6 +917,7 @@ func (s *TestSuite) TestCreateGroupPolicy() {
policy: group.NewThresholdDecisionPolicy(
"1",
time.Second,
0,
),
expErr: true,
expErrMsg: "not found",
@ -918,6 +930,7 @@ func (s *TestSuite) TestCreateGroupPolicy() {
policy: group.NewThresholdDecisionPolicy(
"1",
time.Second,
0,
),
expErr: true,
expErrMsg: "not group admin",
@ -931,6 +944,7 @@ func (s *TestSuite) TestCreateGroupPolicy() {
policy: group.NewThresholdDecisionPolicy(
"1",
time.Second,
0,
),
expErr: true,
expErrMsg: "limit exceeded",
@ -943,6 +957,7 @@ func (s *TestSuite) TestCreateGroupPolicy() {
policy: group.NewPercentageDecisionPolicy(
"-0.5",
time.Second,
0,
),
expErr: true,
expErrMsg: "expected a positive decimal",
@ -955,6 +970,7 @@ func (s *TestSuite) TestCreateGroupPolicy() {
policy: group.NewPercentageDecisionPolicy(
"2",
time.Second,
0,
),
expErr: true,
expErrMsg: "percentage must be > 0 and <= 1",
@ -1194,6 +1210,7 @@ func (s *TestSuite) TestUpdateGroupPolicyDecisionPolicy() {
policy: group.NewThresholdDecisionPolicy(
"2",
time.Duration(2)*time.Second,
0,
),
expGroupPolicy: &group.GroupPolicyInfo{
Admin: admin.String(),
@ -1216,6 +1233,7 @@ func (s *TestSuite) TestUpdateGroupPolicyDecisionPolicy() {
policy: group.NewPercentageDecisionPolicy(
"0.5",
time.Duration(2)*time.Second,
0,
),
expGroupPolicy: &group.GroupPolicyInfo{
Admin: admin.String(),
@ -1278,14 +1296,17 @@ func (s *TestSuite) TestGroupPoliciesByAdminOrGroup() {
group.NewThresholdDecisionPolicy(
"1",
time.Second,
0,
),
group.NewThresholdDecisionPolicy(
"10",
time.Second,
0,
),
group.NewPercentageDecisionPolicy(
"0.5",
time.Second,
0,
),
}
@ -1376,6 +1397,7 @@ func (s *TestSuite) TestSubmitProposal() {
policy := group.NewThresholdDecisionPolicy(
"100",
time.Second,
0,
)
err := policyReq.SetDecisionPolicy(policy)
s.Require().NoError(err)
@ -1523,7 +1545,7 @@ func (s *TestSuite) TestSubmitProposal() {
Status: group.PROPOSAL_STATUS_SUBMITTED,
Result: group.PROPOSAL_RESULT_UNFINALIZED,
FinalTallyResult: group.TallyResult{
YesCount: "1",
YesCount: "0", // Since tally doesn't pass Allow(), we consider the proposal not final
NoCount: "0",
AbstainCount: "0",
NoWithVetoCount: "0",
@ -1562,7 +1584,7 @@ func (s *TestSuite) TestSubmitProposal() {
s.Assert().Equal(spec.expProposal.Result, proposal.Result)
s.Assert().Equal(spec.expProposal.FinalTallyResult, proposal.FinalTallyResult)
s.Assert().Equal(spec.expProposal.ExecutorResult, proposal.ExecutorResult)
s.Assert().Equal(s.blockTime.Add(time.Second), proposal.Timeout)
s.Assert().Equal(s.blockTime.Add(time.Second), proposal.VotingPeriodEnd)
if spec.msgs == nil { // then empty list is ok
s.Assert().Len(proposal.GetMsgs(), 0)
@ -1684,6 +1706,7 @@ func (s *TestSuite) TestVote() {
policy := group.NewThresholdDecisionPolicy(
"2",
time.Duration(2),
0,
)
policyReq := &group.MsgCreateGroupPolicy{
Admin: addr1.String(),
@ -1732,23 +1755,19 @@ func (s *TestSuite) TestVote() {
s.Assert().Equal(uint64(1), proposals[0].GroupPolicyVersion)
s.Assert().Equal(group.PROPOSAL_STATUS_SUBMITTED, proposals[0].Status)
s.Assert().Equal(group.PROPOSAL_RESULT_UNFINALIZED, proposals[0].Result)
s.Assert().Equal(group.TallyResult{
YesCount: "0",
NoCount: "0",
AbstainCount: "0",
NoWithVetoCount: "0",
}, proposals[0].FinalTallyResult)
s.Assert().Equal(group.DefaultTallyResult(), proposals[0].FinalTallyResult)
specs := map[string]struct {
srcCtx sdk.Context
expFinalTallyResult group.TallyResult
req *group.MsgVote
doBefore func(ctx context.Context)
postRun func(sdkCtx sdk.Context)
expProposalStatus group.ProposalStatus
expResult group.ProposalResult
expExecutorResult group.ProposalExecutorResult
expErr bool
srcCtx sdk.Context
expTallyResult group.TallyResult // expected after tallying
isFinal bool // is the tally result final?
req *group.MsgVote
doBefore func(ctx context.Context)
postRun func(sdkCtx sdk.Context)
expProposalStatus group.ProposalStatus // expected after tallying
expResult group.ProposalResult // expected after tallying
expExecutorResult group.ProposalExecutorResult // expected after tallying
expErr bool
}{
"vote yes": {
req: &group.MsgVote{
@ -1756,7 +1775,7 @@ func (s *TestSuite) TestVote() {
Voter: addr4.String(),
Option: group.VOTE_OPTION_YES,
},
expFinalTallyResult: group.TallyResult{
expTallyResult: group.TallyResult{
YesCount: "1",
NoCount: "0",
AbstainCount: "0",
@ -1774,12 +1793,13 @@ func (s *TestSuite) TestVote() {
Option: group.VOTE_OPTION_YES,
Exec: group.Exec_EXEC_TRY,
},
expFinalTallyResult: group.TallyResult{
expTallyResult: group.TallyResult{
YesCount: "2",
NoCount: "0",
AbstainCount: "0",
NoWithVetoCount: "0",
},
isFinal: true,
expProposalStatus: group.PROPOSAL_STATUS_CLOSED,
expResult: group.PROPOSAL_RESULT_ACCEPTED,
expExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_SUCCESS,
@ -1797,7 +1817,7 @@ func (s *TestSuite) TestVote() {
Option: group.VOTE_OPTION_YES,
Exec: group.Exec_EXEC_TRY,
},
expFinalTallyResult: group.TallyResult{
expTallyResult: group.TallyResult{
YesCount: "1",
NoCount: "0",
AbstainCount: "0",
@ -1814,7 +1834,7 @@ func (s *TestSuite) TestVote() {
Voter: addr4.String(),
Option: group.VOTE_OPTION_NO,
},
expFinalTallyResult: group.TallyResult{
expTallyResult: group.TallyResult{
YesCount: "0",
NoCount: "1",
AbstainCount: "0",
@ -1831,7 +1851,7 @@ func (s *TestSuite) TestVote() {
Voter: addr4.String(),
Option: group.VOTE_OPTION_ABSTAIN,
},
expFinalTallyResult: group.TallyResult{
expTallyResult: group.TallyResult{
YesCount: "0",
NoCount: "0",
AbstainCount: "1",
@ -1848,7 +1868,7 @@ func (s *TestSuite) TestVote() {
Voter: addr4.String(),
Option: group.VOTE_OPTION_NO_WITH_VETO,
},
expFinalTallyResult: group.TallyResult{
expTallyResult: group.TallyResult{
YesCount: "0",
NoCount: "0",
AbstainCount: "0",
@ -1865,7 +1885,7 @@ func (s *TestSuite) TestVote() {
Voter: addr3.String(),
Option: group.VOTE_OPTION_YES,
},
expFinalTallyResult: group.TallyResult{
expTallyResult: group.TallyResult{
YesCount: "2",
NoCount: "0",
AbstainCount: "0",
@ -1887,6 +1907,7 @@ func (s *TestSuite) TestVote() {
ProposalId: myProposalID,
Voter: addr3.String(),
Option: group.VOTE_OPTION_NO_WITH_VETO,
Exec: 1, // Execute the proposal so that its status is final
})
s.Require().NoError(err)
},
@ -1947,7 +1968,7 @@ func (s *TestSuite) TestVote() {
expErr: true,
postRun: func(sdkCtx sdk.Context) {},
},
"on timeout": {
"on voting period end": {
req: &group.MsgVote{
ProposalId: myProposalID,
Voter: addr4.String(),
@ -1968,6 +1989,7 @@ func (s *TestSuite) TestVote() {
ProposalId: myProposalID,
Voter: addr3.String(),
Option: group.VOTE_OPTION_YES,
Exec: 1, // Execute to close the proposal.
})
s.Require().NoError(err)
},
@ -2019,7 +2041,9 @@ func (s *TestSuite) TestVote() {
groupPolicy,
&group.ThresholdDecisionPolicy{
Threshold: "1",
Timeout: time.Second,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second,
},
},
)
s.Require().NoError(err)
@ -2093,16 +2117,26 @@ func (s *TestSuite) TestVote() {
s.Assert().Equal(spec.req.Metadata, votesByVoter[0].Metadata)
s.Assert().Equal(s.blockTime, votesByVoter[0].SubmitTime)
// and proposal is updated
proposalRes, err := s.keeper.Proposal(ctx, &group.QueryProposalRequest{
ProposalId: spec.req.ProposalId,
})
s.Require().NoError(err)
proposal := proposalRes.Proposal
s.Assert().Equal(spec.expFinalTallyResult, proposal.FinalTallyResult)
s.Assert().Equal(spec.expResult, proposal.Result)
s.Assert().Equal(spec.expProposalStatus, proposal.Status)
s.Assert().Equal(spec.expExecutorResult, proposal.ExecutorResult)
if spec.isFinal {
s.Assert().Equal(spec.expTallyResult, proposal.FinalTallyResult)
s.Assert().Equal(spec.expResult, proposal.Result)
s.Assert().Equal(spec.expProposalStatus, proposal.Status)
s.Assert().Equal(spec.expExecutorResult, proposal.ExecutorResult)
} else {
s.Assert().Equal(group.DefaultTallyResult(), proposal.FinalTallyResult) // Make sure proposal isn't mutated.
// do a round of tallying
tallyResult, err := s.keeper.Tally(sdkCtx, *proposal, myGroupID)
s.Require().NoError(err)
s.Assert().Equal(spec.expTallyResult, tallyResult)
}
spec.postRun(sdkCtx)
})
@ -2370,6 +2404,7 @@ func createGroupAndGroupPolicy(
policy := group.NewThresholdDecisionPolicy(
"1",
time.Second,
0,
)
err = groupPolicy.SetDecisionPolicy(policy)
s.Require().NoError(err)

View File

@ -467,16 +467,11 @@ func (k Keeper) SubmitProposal(goCtx context.Context, req *group.MsgSubmitPropos
}
// Prevent proposal that can not succeed.
err = policy.Validate(g)
err = policy.Validate(g, k.config)
if err != nil {
return nil, err
}
// Define proposal timout.
// The voting window begins as soon as the proposal is submitted.
timeout := policy.GetTimeout()
window := timeout
m := &group.Proposal{
Id: k.proposalTable.Sequence().PeekNextVal(ctx.KVStore(k.key)),
Address: req.Address,
@ -488,14 +483,10 @@ func (k Keeper) SubmitProposal(goCtx context.Context, req *group.MsgSubmitPropos
Result: group.PROPOSAL_RESULT_UNFINALIZED,
Status: group.PROPOSAL_STATUS_SUBMITTED,
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
Timeout: ctx.BlockTime().Add(window),
FinalTallyResult: group.TallyResult{
YesCount: "0",
NoCount: "0",
AbstainCount: "0",
NoWithVetoCount: "0",
},
VotingPeriodEnd: ctx.BlockTime().Add(policy.GetVotingPeriod()), // The voting window begins as soon as the proposal is submitted.
FinalTallyResult: group.DefaultTallyResult(),
}
if err := m.SetMsgs(msgs); err != nil {
return nil, sdkerrors.Wrap(err, "create proposal")
}
@ -524,6 +515,7 @@ func (k Keeper) SubmitProposal(goCtx context.Context, req *group.MsgSubmitPropos
return &group.MsgSubmitProposalResponse{ProposalId: id}, sdkerrors.Wrap(err, "The proposal was created but failed on vote")
}
}
// Then try to execute the proposal
_, err = k.Exec(sdk.WrapSDKContext(ctx), &group.MsgExec{
ProposalId: id,
@ -619,15 +611,7 @@ func (k Keeper) Vote(goCtx context.Context, req *group.MsgVote) (*group.MsgVoteR
if proposal.Status != group.PROPOSAL_STATUS_SUBMITTED {
return nil, sdkerrors.Wrap(errors.ErrInvalid, "proposal not open for voting")
}
proposalTimeout, err := gogotypes.TimestampProto(proposal.Timeout)
if err != nil {
return nil, err
}
votingPeriodEnd, err := gogotypes.TimestampFromProto(proposalTimeout)
if err != nil {
return nil, err
}
if votingPeriodEnd.Before(ctx.BlockTime()) || votingPeriodEnd.Equal(ctx.BlockTime()) {
if ctx.BlockTime().After(proposal.VotingPeriodEnd) {
return nil, sdkerrors.Wrap(errors.ErrExpired, "voting period has ended already")
}
@ -663,9 +647,6 @@ func (k Keeper) Vote(goCtx context.Context, req *group.MsgVote) (*group.MsgVoteR
Metadata: metadata,
SubmitTime: ctx.BlockTime(),
}
if err := proposal.FinalTallyResult.Add(newVote, voter.Member.Weight); err != nil {
return nil, sdkerrors.Wrap(err, "add new vote")
}
// The ORM will return an error if the vote already exists,
// making sure than a voter hasn't already voted.
@ -673,15 +654,6 @@ func (k Keeper) Vote(goCtx context.Context, req *group.MsgVote) (*group.MsgVoteR
return nil, sdkerrors.Wrap(err, "store vote")
}
// Run tally with new votes to close early.
if err := doTally(ctx, &proposal, electorate, policyInfo); err != nil {
return nil, err
}
if err = k.proposalTable.Update(ctx.KVStore(k.key), id, &proposal); err != nil {
return nil, err
}
err = ctx.EventManager().EmitTypedEvent(&group.EventVote{ProposalId: id})
if err != nil {
return nil, err
@ -701,8 +673,9 @@ func (k Keeper) Vote(goCtx context.Context, req *group.MsgVote) (*group.MsgVoteR
return &group.MsgVoteResponse{}, nil
}
// doTally updates the proposal status and tally if necessary based on the group policy's decision policy.
func doTally(ctx sdk.Context, p *group.Proposal, electorate group.GroupInfo, policyInfo group.GroupPolicyInfo) error {
// doTallyAndUpdate performs a tally, and updates the proposal's
// `FinalTallyResult` field only if the tally is final.
func (k Keeper) doTallyAndUpdate(ctx sdk.Context, p *group.Proposal, electorate group.GroupInfo, policyInfo group.GroupPolicyInfo) error {
policy := policyInfo.GetDecisionPolicy()
pSubmittedAt, err := gogotypes.TimestampProto(p.SubmitTime)
if err != nil {
@ -712,16 +685,25 @@ func doTally(ctx sdk.Context, p *group.Proposal, electorate group.GroupInfo, pol
if err != nil {
return err
}
switch result, err := policy.Allow(p.FinalTallyResult, electorate.TotalWeight, ctx.BlockTime().Sub(submittedAt)); {
tallyResult, err := k.Tally(ctx, *p, policyInfo.GroupId)
if err != nil {
return err
}
switch result, err := policy.Allow(tallyResult, electorate.TotalWeight, ctx.BlockTime().Sub(submittedAt)); {
case err != nil:
return sdkerrors.Wrap(err, "policy execution")
case result.Allow && result.Final:
p.FinalTallyResult = tallyResult
p.Result = group.PROPOSAL_RESULT_ACCEPTED
p.Status = group.PROPOSAL_STATUS_CLOSED
case !result.Allow && result.Final:
p.FinalTallyResult = tallyResult
p.Result = group.PROPOSAL_RESULT_REJECTED
p.Status = group.PROPOSAL_STATUS_CLOSED
}
return nil
}
@ -770,7 +752,8 @@ func (k Keeper) Exec(goCtx context.Context, req *group.MsgExec) (*group.MsgExecR
proposal.Status = group.PROPOSAL_STATUS_ABORTED
return storeUpdates()
}
if err := doTally(ctx, &proposal, electorate, policyInfo); err != nil {
if err := k.doTallyAndUpdate(ctx, &proposal, electorate, policyInfo); err != nil {
return nil, err
}
}

View File

@ -11,6 +11,16 @@ import (
// doExecuteMsgs routes the messages to the registered handlers. Messages are limited to those that require no authZ or
// by the account of group policy only. Otherwise this gives access to other peoples accounts as the sdk ant handler is bypassed
func (s Keeper) doExecuteMsgs(ctx sdk.Context, router *authmiddleware.MsgServiceRouter, proposal group.Proposal, groupPolicyAcc sdk.AccAddress) ([]sdk.Result, error) {
// Ensure it's not too late to execute the messages.
// After https://github.com/cosmos/cosmos-sdk/issues/11245, proposals should
// be pruned automatically, so this function should not even be called, as
// the proposal doesn't exist in state. For sanity check, we can still keep
// this simple and cheap check.
expiryDate := proposal.VotingPeriodEnd.Add(s.config.MaxExecutionPeriod)
if expiryDate.Before(ctx.BlockTime()) {
return nil, grouperrors.ErrExpired.Wrapf("proposal expired on %s", expiryDate)
}
msgs := proposal.GetMsgs()
results := make([]sdk.Result, len(msgs))

View File

@ -367,7 +367,7 @@ func TestMsgCreateGroupWithPolicy(t *testing.T) {
"invalid admin address",
func() *group.MsgCreateGroupWithPolicy {
admin := "admin"
policy := group.NewThresholdDecisionPolicy("1", time.Second)
policy := group.NewThresholdDecisionPolicy("1", time.Second, 0)
members := []group.Member{
{
Address: member1.String(),
@ -385,7 +385,7 @@ func TestMsgCreateGroupWithPolicy(t *testing.T) {
{
"invalid member address",
func() *group.MsgCreateGroupWithPolicy {
policy := group.NewThresholdDecisionPolicy("1", time.Second)
policy := group.NewThresholdDecisionPolicy("1", time.Second, 0)
members := []group.Member{
{
Address: "invalid_address",
@ -403,7 +403,7 @@ func TestMsgCreateGroupWithPolicy(t *testing.T) {
{
"negative member's weight not allowed",
func() *group.MsgCreateGroupWithPolicy {
policy := group.NewThresholdDecisionPolicy("1", time.Second)
policy := group.NewThresholdDecisionPolicy("1", time.Second, 0)
members := []group.Member{
{
Address: member1.String(),
@ -421,7 +421,7 @@ func TestMsgCreateGroupWithPolicy(t *testing.T) {
{
"zero member's weight not allowed",
func() *group.MsgCreateGroupWithPolicy {
policy := group.NewThresholdDecisionPolicy("1", time.Second)
policy := group.NewThresholdDecisionPolicy("1", time.Second, 0)
members := []group.Member{
{
Address: member1.String(),
@ -439,7 +439,7 @@ func TestMsgCreateGroupWithPolicy(t *testing.T) {
{
"duplicate member not allowed",
func() *group.MsgCreateGroupWithPolicy {
policy := group.NewThresholdDecisionPolicy("1", time.Second)
policy := group.NewThresholdDecisionPolicy("1", time.Second, 0)
members := []group.Member{
{
Address: member1.String(),
@ -462,7 +462,7 @@ func TestMsgCreateGroupWithPolicy(t *testing.T) {
{
"invalid threshold policy",
func() *group.MsgCreateGroupWithPolicy {
policy := group.NewThresholdDecisionPolicy("-1", time.Second)
policy := group.NewThresholdDecisionPolicy("-1", time.Second, 0)
members := []group.Member{
{
Address: member1.String(),
@ -480,7 +480,7 @@ func TestMsgCreateGroupWithPolicy(t *testing.T) {
{
"valid test case with single member",
func() *group.MsgCreateGroupWithPolicy {
policy := group.NewThresholdDecisionPolicy("1", time.Second)
policy := group.NewThresholdDecisionPolicy("1", time.Second, 0)
members := []group.Member{
{
Address: member1.String(),
@ -498,7 +498,7 @@ func TestMsgCreateGroupWithPolicy(t *testing.T) {
{
"valid test case with multiple members",
func() *group.MsgCreateGroupWithPolicy {
policy := group.NewThresholdDecisionPolicy("1", time.Second)
policy := group.NewThresholdDecisionPolicy("1", time.Second, 0)
members := []group.Member{
{
Address: member1.String(),
@ -566,7 +566,7 @@ func TestMsgCreateGroupPolicy(t *testing.T) {
{
"invalid threshold policy",
func() *group.MsgCreateGroupPolicy {
policy := group.NewThresholdDecisionPolicy("-1", time.Second)
policy := group.NewThresholdDecisionPolicy("-1", time.Second, 0)
req, err := group.NewMsgCreateGroupPolicy(admin, 1, "metadata", policy)
require.NoError(t, err)
return req
@ -575,9 +575,53 @@ func TestMsgCreateGroupPolicy(t *testing.T) {
"expected a positive decimal",
},
{
"valid test case",
"invalid voting period",
func() *group.MsgCreateGroupPolicy {
policy := group.NewThresholdDecisionPolicy("1", time.Second)
policy := group.NewThresholdDecisionPolicy("-1", time.Duration(0), 0)
req, err := group.NewMsgCreateGroupPolicy(admin, 1, "metadata", policy)
require.NoError(t, err)
return req
},
true,
"expected a positive decimal",
},
{
"invalid execution period",
func() *group.MsgCreateGroupPolicy {
policy := group.NewThresholdDecisionPolicy("-1", time.Minute, 0)
req, err := group.NewMsgCreateGroupPolicy(admin, 1, "metadata", policy)
require.NoError(t, err)
return req
},
true,
"expected a positive decimal",
},
{
"valid test case, only voting period",
func() *group.MsgCreateGroupPolicy {
policy := group.NewThresholdDecisionPolicy("1", time.Second, 0)
req, err := group.NewMsgCreateGroupPolicy(admin, 1, "metadata", policy)
require.NoError(t, err)
return req
},
false,
"",
},
{
"valid test case, voting and execution, empty min exec period",
func() *group.MsgCreateGroupPolicy {
policy := group.NewThresholdDecisionPolicy("1", time.Second, 0)
req, err := group.NewMsgCreateGroupPolicy(admin, 1, "metadata", policy)
require.NoError(t, err)
return req
},
false,
"",
},
{
"valid test case, voting and execution, non-empty min exec period",
func() *group.MsgCreateGroupPolicy {
policy := group.NewThresholdDecisionPolicy("1", time.Second, time.Minute)
req, err := group.NewMsgCreateGroupPolicy(admin, 1, "metadata", policy)
require.NoError(t, err)
return req
@ -588,7 +632,7 @@ func TestMsgCreateGroupPolicy(t *testing.T) {
{
"invalid percentage decision policy with zero value",
func() *group.MsgCreateGroupPolicy {
percentagePolicy := group.NewPercentageDecisionPolicy("0", time.Second)
percentagePolicy := group.NewPercentageDecisionPolicy("0", time.Second, 0)
req, err := group.NewMsgCreateGroupPolicy(admin, 1, "metadata", percentagePolicy)
require.NoError(t, err)
return req
@ -599,7 +643,7 @@ func TestMsgCreateGroupPolicy(t *testing.T) {
{
"invalid percentage decision policy with negative value",
func() *group.MsgCreateGroupPolicy {
percentagePolicy := group.NewPercentageDecisionPolicy("-0.2", time.Second)
percentagePolicy := group.NewPercentageDecisionPolicy("-0.2", time.Second, 0)
req, err := group.NewMsgCreateGroupPolicy(admin, 1, "metadata", percentagePolicy)
require.NoError(t, err)
return req
@ -610,7 +654,7 @@ func TestMsgCreateGroupPolicy(t *testing.T) {
{
"invalid percentage decision policy with value greater than 1",
func() *group.MsgCreateGroupPolicy {
percentagePolicy := group.NewPercentageDecisionPolicy("2", time.Second)
percentagePolicy := group.NewPercentageDecisionPolicy("2", time.Second, 0)
req, err := group.NewMsgCreateGroupPolicy(admin, 1, "metadata", percentagePolicy)
require.NoError(t, err)
return req
@ -621,7 +665,7 @@ func TestMsgCreateGroupPolicy(t *testing.T) {
{
"valid test case with percentage decision policy",
func() *group.MsgCreateGroupPolicy {
percentagePolicy := group.NewPercentageDecisionPolicy("0.5", time.Second)
percentagePolicy := group.NewPercentageDecisionPolicy("0.5", time.Second, 0)
req, err := group.NewMsgCreateGroupPolicy(admin, 1, "metadata", percentagePolicy)
require.NoError(t, err)
return req
@ -647,23 +691,23 @@ func TestMsgCreateGroupPolicy(t *testing.T) {
}
func TestMsgUpdateGroupPolicyDecisionPolicy(t *testing.T) {
validPolicy := group.NewThresholdDecisionPolicy("1", time.Second)
validPolicy := group.NewThresholdDecisionPolicy("1", time.Second, 0)
msg1, err := group.NewMsgUpdateGroupPolicyDecisionPolicyRequest(admin, member1, validPolicy)
require.NoError(t, err)
invalidPolicy := group.NewThresholdDecisionPolicy("-1", time.Second)
invalidPolicy := group.NewThresholdDecisionPolicy("-1", time.Second, 0)
msg2, err := group.NewMsgUpdateGroupPolicyDecisionPolicyRequest(admin, member2, invalidPolicy)
require.NoError(t, err)
validPercentagePolicy := group.NewPercentageDecisionPolicy("0.7", time.Second)
validPercentagePolicy := group.NewPercentageDecisionPolicy("0.7", time.Second, 0)
msg3, err := group.NewMsgUpdateGroupPolicyDecisionPolicyRequest(admin, member3, validPercentagePolicy)
require.NoError(t, err)
invalidPercentagePolicy := group.NewPercentageDecisionPolicy("-0.1", time.Second)
invalidPercentagePolicy := group.NewPercentageDecisionPolicy("-0.1", time.Second, 0)
msg4, err := group.NewMsgUpdateGroupPolicyDecisionPolicyRequest(admin, member4, invalidPercentagePolicy)
require.NoError(t, err)
invalidPercentagePolicy2 := group.NewPercentageDecisionPolicy("2", time.Second)
invalidPercentagePolicy2 := group.NewPercentageDecisionPolicy("2", time.Second, 0)
msg5, err := group.NewMsgUpdateGroupPolicyDecisionPolicyRequest(admin, member5, invalidPercentagePolicy2)
require.NoError(t, err)

View File

@ -56,7 +56,7 @@ func getGroupPolicies(r *rand.Rand, simState *module.SimulationState) []*group.G
groupPolicies := make([]*group.GroupPolicyInfo, 3)
for i := 0; i < 3; i++ {
acc, _ := simtypes.RandomAcc(r, simState.Accounts)
any, err := codectypes.NewAnyWithValue(group.NewThresholdDecisionPolicy("10", time.Second*time.Duration(1)))
any, err := codectypes.NewAnyWithValue(group.NewThresholdDecisionPolicy("10", time.Second, 0))
if err != nil {
panic(err)
}
@ -97,10 +97,10 @@ func getProposals(r *rand.Rand, simState *module.SimulationState) []*group.Propo
AbstainCount: "1",
NoWithVetoCount: "0",
},
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
Metadata: simtypes.RandStringOfLength(r, 50),
SubmitTime: submittedAt,
Timeout: timeout,
ExecutorResult: group.PROPOSAL_EXECUTOR_RESULT_NOT_RUN,
Metadata: simtypes.RandStringOfLength(r, 50),
SubmitTime: submittedAt,
VotingPeriodEnd: timeout,
}
err := proposal.SetMsgs([]sdk.Msg{&banktypes.MsgSend{
FromAddress: fromAddr,

View File

@ -285,7 +285,9 @@ func SimulateMsgCreateGroupWithPolicy(ak group.AccountKeeper, bk group.BankKeepe
members := genGroupMembers(r, accounts)
decisionPolicy := &group.ThresholdDecisionPolicy{
Threshold: fmt.Sprintf("%d", simtypes.RandIntBetween(r, 1, 10)),
Timeout: time.Second * time.Duration(30*24*60*60),
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * time.Duration(30*24*60*60),
},
}
msg := &group.MsgCreateGroupWithPolicy{
@ -349,7 +351,9 @@ func SimulateMsgCreateGroupPolicy(ak group.AccountKeeper, bk group.BankKeeper, k
simtypes.RandStringOfLength(r, 10),
&group.ThresholdDecisionPolicy{
Threshold: fmt.Sprintf("%d", simtypes.RandIntBetween(r, 1, 10)),
Timeout: time.Second * time.Duration(30*24*60*60),
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * time.Duration(30*24*60*60),
},
},
)
if err != nil {
@ -400,7 +404,7 @@ func SimulateMsgSubmitProposal(ak group.AccountKeeper, bk group.BankKeeper, k ke
// Return a no-op if we know the proposal cannot be created
policy := groupPolicy.GetDecisionPolicy()
err = policy.Validate(*g)
err = policy.Validate(*g, group.DefaultConfig())
if err != nil {
return simtypes.NoOpMsg(group.ModuleName, TypeMsgSubmitProposal, ""), nil, nil
}
@ -721,7 +725,9 @@ func SimulateMsgUpdateGroupPolicyDecisionPolicy(ak group.AccountKeeper,
msg, err := group.NewMsgUpdateGroupPolicyDecisionPolicyRequest(acc.Address, groupPolicyBech32, &group.ThresholdDecisionPolicy{
Threshold: fmt.Sprintf("%d", simtypes.RandIntBetween(r, 1, 10)),
Timeout: time.Second * time.Duration(simtypes.RandIntBetween(r, 100, 1000)),
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * time.Duration(simtypes.RandIntBetween(r, 100, 1000)),
},
})
if err != nil {
return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyDecisionPolicy, err.Error()), nil, err
@ -820,7 +826,7 @@ func SimulateMsgWithdrawProposal(ak group.AccountKeeper,
ctx := sdk.WrapSDKContext(sdkCtx)
policy := groupPolicy.GetDecisionPolicy()
err = policy.Validate(*g)
err = policy.Validate(*g, group.DefaultConfig())
if err != nil {
return simtypes.NoOpMsg(group.ModuleName, TypeMsgWithdrawProposal, err.Error()), nil, nil
}
@ -840,7 +846,7 @@ func SimulateMsgWithdrawProposal(ak group.AccountKeeper,
for _, p := range proposals {
if p.Status == group.PROPOSAL_STATUS_SUBMITTED {
timeout := p.Timeout
timeout := p.VotingPeriodEnd
proposal = p
proposalID = int(p.Id)
if timeout.Before(sdkCtx.BlockTime()) || timeout.Equal(sdkCtx.BlockTime()) {
@ -959,7 +965,7 @@ func SimulateMsgVote(ak group.AccountKeeper,
for _, p := range proposals {
if p.Status == group.PROPOSAL_STATUS_SUBMITTED {
timeout := p.Timeout
timeout := p.VotingPeriodEnd
proposal = p
proposalID = int(p.Id)
if timeout.Before(sdkCtx.BlockTime()) || timeout.Equal(sdkCtx.BlockTime()) {
@ -1032,27 +1038,27 @@ func SimulateMsgExec(ak group.AccountKeeper,
r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
_, groupPolicy, acc, account, err := randomGroupPolicy(r, k, ak, sdkCtx, accounts)
if err != nil {
return simtypes.NoOpMsg(group.ModuleName, TypeMsgExec, ""), nil, err
return simtypes.NoOpMsg(TypeMsgExec, TypeMsgExec, ""), nil, err
}
if groupPolicy == nil {
return simtypes.NoOpMsg(group.ModuleName, TypeMsgExec, "no group policy found"), nil, nil
return simtypes.NoOpMsg(TypeMsgExec, TypeMsgExec, "no group policy found"), nil, nil
}
groupPolicyAddr := groupPolicy.Address
spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress())
fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins)
if err != nil {
return simtypes.NoOpMsg(group.ModuleName, TypeMsgExec, "fee error"), nil, err
return simtypes.NoOpMsg(TypeMsgExec, TypeMsgExec, "fee error"), nil, err
}
ctx := sdk.WrapSDKContext(sdkCtx)
proposalsResult, err := k.ProposalsByGroupPolicy(ctx, &group.QueryProposalsByGroupPolicyRequest{Address: groupPolicyAddr})
if err != nil {
return simtypes.NoOpMsg(group.ModuleName, TypeMsgExec, "fail to query group info"), nil, err
return simtypes.NoOpMsg(TypeMsgExec, TypeMsgExec, "fail to query group info"), nil, err
}
proposals := proposalsResult.GetProposals()
if len(proposals) == 0 {
return simtypes.NoOpMsg(group.ModuleName, TypeMsgExec, "no proposals found"), nil, nil
return simtypes.NoOpMsg(TypeMsgExec, TypeMsgExec, "no proposals found"), nil, nil
}
proposalID := -1
@ -1066,7 +1072,7 @@ func SimulateMsgExec(ak group.AccountKeeper,
// return no-op if no proposal found
if proposalID == -1 {
return simtypes.NoOpMsg(group.ModuleName, TypeMsgExec, "no proposals found"), nil, nil
return simtypes.NoOpMsg(TypeMsgExec, TypeMsgExec, "no proposals found"), nil, nil
}
msg := group.MsgExec{

View File

@ -221,7 +221,7 @@ func (suite *SimTestSuite) TestSimulateSubmitProposal() {
Admin: acc.Address.String(),
GroupId: groupRes.GroupId,
}
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour))
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour, 0))
suite.Require().NoError(err)
groupPolicyRes, err := suite.app.GroupKeeper.CreateGroupPolicy(ctx, accountReq)
suite.Require().NoError(err)
@ -275,7 +275,7 @@ func (suite *SimTestSuite) TestWithdrawProposal() {
Admin: addr,
GroupId: groupRes.GroupId,
}
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour))
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour, 0))
suite.Require().NoError(err)
groupPolicyRes, err := suite.app.GroupKeeper.CreateGroupPolicy(ctx, accountReq)
suite.Require().NoError(err)
@ -342,7 +342,7 @@ func (suite *SimTestSuite) TestSimulateVote() {
GroupId: groupRes.GroupId,
Metadata: "",
}
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour))
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour, 0))
suite.Require().NoError(err)
groupPolicyRes, err := suite.app.GroupKeeper.CreateGroupPolicy(ctx, accountReq)
suite.Require().NoError(err)
@ -408,7 +408,7 @@ func (suite *SimTestSuite) TestSimulateExec() {
Admin: addr,
GroupId: groupRes.GroupId,
}
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour))
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour, 0))
suite.Require().NoError(err)
groupPolicyRes, err := suite.app.GroupKeeper.CreateGroupPolicy(ctx, accountReq)
suite.Require().NoError(err)
@ -430,6 +430,7 @@ func (suite *SimTestSuite) TestSimulateExec() {
ProposalId: proposalRes.ProposalId,
Voter: addr,
Option: group.VOTE_OPTION_YES,
Exec: 1,
})
suite.Require().NoError(err)
@ -607,7 +608,7 @@ func (suite *SimTestSuite) TestSimulateUpdateGroupPolicyAdmin() {
Admin: acc.Address.String(),
GroupId: groupRes.GroupId,
}
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour))
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour, 0))
suite.Require().NoError(err)
groupPolicyRes, err := suite.app.GroupKeeper.CreateGroupPolicy(ctx, accountReq)
suite.Require().NoError(err)
@ -660,7 +661,7 @@ func (suite *SimTestSuite) TestSimulateUpdateGroupPolicyDecisionPolicy() {
Admin: acc.Address.String(),
GroupId: groupRes.GroupId,
}
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour))
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour, 0))
suite.Require().NoError(err)
groupPolicyRes, err := suite.app.GroupKeeper.CreateGroupPolicy(ctx, accountReq)
suite.Require().NoError(err)
@ -713,7 +714,7 @@ func (suite *SimTestSuite) TestSimulateUpdateGroupPolicyMetadata() {
Admin: acc.Address.String(),
GroupId: groupRes.GroupId,
}
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour))
err = accountReq.SetDecisionPolicy(group.NewThresholdDecisionPolicy("1", time.Hour, 0))
suite.Require().NoError(err)
groupPolicyRes, err := suite.app.GroupKeeper.CreateGroupPolicy(ctx, accountReq)
suite.Require().NoError(err)

View File

@ -24,18 +24,28 @@ type DecisionPolicyResult struct {
type DecisionPolicy interface {
codec.ProtoMarshaler
// GetVotingPeriod returns the duration after proposal submission where
// votes are accepted.
GetVotingPeriod() time.Duration
// Allow defines policy-specific logic to allow a proposal to pass or not,
// based on its tally result, the group's total power and the time since
// the proposal was submitted.
Allow(tallyResult TallyResult, totalPower string, sinceSubmission time.Duration) (DecisionPolicyResult, error)
ValidateBasic() error
GetTimeout() time.Duration
Allow(tallyResult TallyResult, totalPower string, votingDuration time.Duration) (DecisionPolicyResult, error)
Validate(g GroupInfo) error
Validate(g GroupInfo, config Config) error
}
// Implements DecisionPolicy Interface
var _ DecisionPolicy = &ThresholdDecisionPolicy{}
// NewThresholdDecisionPolicy creates a threshold DecisionPolicy
func NewThresholdDecisionPolicy(threshold string, timeout time.Duration) DecisionPolicy {
return &ThresholdDecisionPolicy{threshold, timeout}
func NewThresholdDecisionPolicy(threshold string, votingPeriod time.Duration, minExecutionPeriod time.Duration) DecisionPolicy {
return &ThresholdDecisionPolicy{threshold, &DecisionPolicyWindows{votingPeriod, minExecutionPeriod}}
}
func (p ThresholdDecisionPolicy) GetVotingPeriod() time.Duration {
return p.Windows.VotingPeriod
}
func (p ThresholdDecisionPolicy) ValidateBasic() error {
@ -43,19 +53,17 @@ func (p ThresholdDecisionPolicy) ValidateBasic() error {
return sdkerrors.Wrap(err, "threshold")
}
timeout := p.Timeout
if timeout <= time.Nanosecond {
return sdkerrors.Wrap(errors.ErrInvalid, "timeout")
if p.Windows == nil || p.Windows.VotingPeriod == 0 {
return sdkerrors.Wrap(errors.ErrInvalid, "voting period cannot be zero")
}
return nil
}
// Allow allows a proposal to pass when the tally of yes votes equals or exceeds the threshold before the timeout.
func (p ThresholdDecisionPolicy) Allow(tallyResult TallyResult, totalPower string, votingDuration time.Duration) (DecisionPolicyResult, error) {
timeout := p.Timeout
if timeout <= votingDuration {
return DecisionPolicyResult{Allow: false, Final: true}, nil
func (p ThresholdDecisionPolicy) Allow(tallyResult TallyResult, totalPower string, sinceSubmission time.Duration) (DecisionPolicyResult, error) {
if sinceSubmission < p.Windows.MinExecutionPeriod {
return DecisionPolicyResult{}, errors.ErrUnauthorized.Wrapf("must wait %s after submission before execution, currently at %s", p.Windows.MinExecutionPeriod, sinceSubmission)
}
threshold, err := math.NewPositiveDecFromString(p.Threshold)
@ -93,7 +101,7 @@ func (p ThresholdDecisionPolicy) Allow(tallyResult TallyResult, totalPower strin
}
// Validate returns an error if policy threshold is greater than the total group weight
func (p *ThresholdDecisionPolicy) Validate(g GroupInfo) error {
func (p *ThresholdDecisionPolicy) Validate(g GroupInfo, config Config) error {
threshold, err := math.NewPositiveDecFromString(p.Threshold)
if err != nil {
return sdkerrors.Wrap(err, "threshold")
@ -105,6 +113,9 @@ func (p *ThresholdDecisionPolicy) Validate(g GroupInfo) error {
if threshold.Cmp(totalWeight) > 0 {
return sdkerrors.Wrapf(errors.ErrInvalid, "policy threshold %s should not be greater than the total group weight %s", p.Threshold, g.TotalWeight)
}
if p.Windows.MinExecutionPeriod > p.Windows.VotingPeriod+config.MaxExecutionPeriod {
return sdkerrors.Wrap(errors.ErrInvalid, "min_execution_period should be smaller than voting_period + max_execution_period")
}
return nil
}
@ -112,8 +123,12 @@ func (p *ThresholdDecisionPolicy) Validate(g GroupInfo) error {
var _ DecisionPolicy = &PercentageDecisionPolicy{}
// NewPercentageDecisionPolicy creates a new percentage DecisionPolicy
func NewPercentageDecisionPolicy(percentage string, timeout time.Duration) DecisionPolicy {
return &PercentageDecisionPolicy{percentage, timeout}
func NewPercentageDecisionPolicy(percentage string, votingPeriod time.Duration, executionPeriod time.Duration) DecisionPolicy {
return &PercentageDecisionPolicy{percentage, &DecisionPolicyWindows{votingPeriod, executionPeriod}}
}
func (p PercentageDecisionPolicy) GetVotingPeriod() time.Duration {
return p.Windows.VotingPeriod
}
func (p PercentageDecisionPolicy) ValidateBasic() error {
@ -125,22 +140,24 @@ func (p PercentageDecisionPolicy) ValidateBasic() error {
return sdkerrors.Wrap(errors.ErrInvalid, "percentage must be > 0 and <= 1")
}
timeout := p.Timeout
if timeout <= time.Nanosecond {
return sdkerrors.Wrap(errors.ErrInvalid, "timeout")
if p.Windows == nil || p.Windows.VotingPeriod == 0 {
return sdkerrors.Wrap(errors.ErrInvalid, "voting period cannot be 0")
}
return nil
}
func (p *PercentageDecisionPolicy) Validate(g GroupInfo, config Config) error {
if p.Windows.MinExecutionPeriod > p.Windows.VotingPeriod+config.MaxExecutionPeriod {
return sdkerrors.Wrap(errors.ErrInvalid, "min_execution_period should be smaller than voting_period + max_execution_period")
}
return nil
}
func (p *PercentageDecisionPolicy) Validate(g GroupInfo) error {
return nil
}
// Allow allows a proposal to pass when the tally of yes votes equals or exceeds the percentage threshold before the timeout.
func (p PercentageDecisionPolicy) Allow(tally TallyResult, totalPower string, votingDuration time.Duration) (DecisionPolicyResult, error) {
timeout := p.Timeout
if timeout <= votingDuration {
return DecisionPolicyResult{Allow: false, Final: true}, nil
func (p PercentageDecisionPolicy) Allow(tally TallyResult, totalPower string, sinceSubmission time.Duration) (DecisionPolicyResult, error) {
if sinceSubmission < p.Windows.MinExecutionPeriod {
return DecisionPolicyResult{}, errors.ErrUnauthorized.Wrapf("must wait %s after submission before execution, currently at %s", p.Windows.MinExecutionPeriod, sinceSubmission)
}
percentage, err := math.NewPositiveDecFromString(p.Percentage)
@ -535,6 +552,16 @@ func (t TallyResult) TotalCounts() (math.Dec, error) {
return totalCounts, nil
}
// DefaultTallyResult returns a TallyResult with all counts set to 0.
func DefaultTallyResult() TallyResult {
return TallyResult{
YesCount: "0",
NoCount: "0",
NoWithVetoCount: "0",
AbstainCount: "0",
}
}
// VoteOptionFromString returns a VoteOption from a string. It returns an error
// if the string is invalid.
func VoteOptionFromString(str string) (VoteOption, error) {

View File

@ -307,9 +307,8 @@ func (m *Members) GetMembers() []Member {
type ThresholdDecisionPolicy struct {
// threshold is the minimum weighted sum of yes votes that must be met or exceeded for a proposal to succeed.
Threshold string `protobuf:"bytes,1,opt,name=threshold,proto3" json:"threshold,omitempty"`
// timeout is the duration from submission of a proposal to the end of voting period
// Within this times votes and exec messages can be submitted.
Timeout time.Duration `protobuf:"bytes,2,opt,name=timeout,proto3,stdduration" json:"timeout"`
// windows defines the different windows for voting and execution.
Windows *DecisionPolicyWindows `protobuf:"bytes,2,opt,name=windows,proto3" json:"windows,omitempty"`
}
func (m *ThresholdDecisionPolicy) Reset() { *m = ThresholdDecisionPolicy{} }
@ -352,20 +351,19 @@ func (m *ThresholdDecisionPolicy) GetThreshold() string {
return ""
}
func (m *ThresholdDecisionPolicy) GetTimeout() time.Duration {
func (m *ThresholdDecisionPolicy) GetWindows() *DecisionPolicyWindows {
if m != nil {
return m.Timeout
return m.Windows
}
return 0
return nil
}
// PercentageDecisionPolicy implements the DecisionPolicy interface
type PercentageDecisionPolicy struct {
// percentage is the minimum percentage the weighted sum of yes votes must meet for a proposal to succeed.
Percentage string `protobuf:"bytes,1,opt,name=percentage,proto3" json:"percentage,omitempty"`
// timeout is the duration from submission of a proposal to the end of voting period
// Within these times votes and exec messages can be submitted.
Timeout time.Duration `protobuf:"bytes,2,opt,name=timeout,proto3,stdduration" json:"timeout"`
// windows defines the different windows for voting and execution.
Windows *DecisionPolicyWindows `protobuf:"bytes,2,opt,name=windows,proto3" json:"windows,omitempty"`
}
func (m *PercentageDecisionPolicy) Reset() { *m = PercentageDecisionPolicy{} }
@ -408,9 +406,75 @@ func (m *PercentageDecisionPolicy) GetPercentage() string {
return ""
}
func (m *PercentageDecisionPolicy) GetTimeout() time.Duration {
func (m *PercentageDecisionPolicy) GetWindows() *DecisionPolicyWindows {
if m != nil {
return m.Timeout
return m.Windows
}
return nil
}
// DecisionPolicyWindows defines the different windows for voting and execution.
type DecisionPolicyWindows struct {
// voting_period is the duration from submission of a proposal to the end of voting period
// Within this times votes can be submitted with MsgVote.
VotingPeriod time.Duration `protobuf:"bytes,1,opt,name=voting_period,json=votingPeriod,proto3,stdduration" json:"voting_period"`
// min_execution_period is the minimum duration after the proposal submission
// where members can start sending MsgExec. This means that the window for
// sending a MsgExec transaction is:
// `[ submission + min_execution_period ; submission + voting_period + max_execution_period]`
// where max_execution_period is a app-specific config, defined in the keeper.
// If not set, min_execution_period will default to 0.
//
// Please make sure to set a `min_execution_period` that is smaller than
// `voting_period + max_execution_period`, or else the above execution window
// is empty, meaning that all proposals created with this decision policy
// won't be able to be executed.
MinExecutionPeriod time.Duration `protobuf:"bytes,2,opt,name=min_execution_period,json=minExecutionPeriod,proto3,stdduration" json:"min_execution_period"`
}
func (m *DecisionPolicyWindows) Reset() { *m = DecisionPolicyWindows{} }
func (m *DecisionPolicyWindows) String() string { return proto.CompactTextString(m) }
func (*DecisionPolicyWindows) ProtoMessage() {}
func (*DecisionPolicyWindows) Descriptor() ([]byte, []int) {
return fileDescriptor_e091dfce5c49c8b6, []int{4}
}
func (m *DecisionPolicyWindows) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *DecisionPolicyWindows) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_DecisionPolicyWindows.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *DecisionPolicyWindows) XXX_Merge(src proto.Message) {
xxx_messageInfo_DecisionPolicyWindows.Merge(m, src)
}
func (m *DecisionPolicyWindows) XXX_Size() int {
return m.Size()
}
func (m *DecisionPolicyWindows) XXX_DiscardUnknown() {
xxx_messageInfo_DecisionPolicyWindows.DiscardUnknown(m)
}
var xxx_messageInfo_DecisionPolicyWindows proto.InternalMessageInfo
func (m *DecisionPolicyWindows) GetVotingPeriod() time.Duration {
if m != nil {
return m.VotingPeriod
}
return 0
}
func (m *DecisionPolicyWindows) GetMinExecutionPeriod() time.Duration {
if m != nil {
return m.MinExecutionPeriod
}
return 0
}
@ -438,7 +502,7 @@ func (m *GroupInfo) Reset() { *m = GroupInfo{} }
func (m *GroupInfo) String() string { return proto.CompactTextString(m) }
func (*GroupInfo) ProtoMessage() {}
func (*GroupInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_e091dfce5c49c8b6, []int{4}
return fileDescriptor_e091dfce5c49c8b6, []int{5}
}
func (m *GroupInfo) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -521,7 +585,7 @@ func (m *GroupMember) Reset() { *m = GroupMember{} }
func (m *GroupMember) String() string { return proto.CompactTextString(m) }
func (*GroupMember) ProtoMessage() {}
func (*GroupMember) Descriptor() ([]byte, []int) {
return fileDescriptor_e091dfce5c49c8b6, []int{5}
return fileDescriptor_e091dfce5c49c8b6, []int{6}
}
func (m *GroupMember) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -587,7 +651,7 @@ func (m *GroupPolicyInfo) Reset() { *m = GroupPolicyInfo{} }
func (m *GroupPolicyInfo) String() string { return proto.CompactTextString(m) }
func (*GroupPolicyInfo) ProtoMessage() {}
func (*GroupPolicyInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_e091dfce5c49c8b6, []int{6}
return fileDescriptor_e091dfce5c49c8b6, []int{7}
}
func (m *GroupPolicyInfo) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -647,11 +711,12 @@ type Proposal struct {
// via gRPC, this field is not populated until the proposal's voting period
// has ended.
FinalTallyResult TallyResult `protobuf:"bytes,10,opt,name=final_tally_result,json=finalTallyResult,proto3" json:"final_tally_result"`
// timeout is the timestamp before which both voting and execution must be
// done. If this timestamp is passed, then the proposal cannot be executed
// anymore and should be considered pending delete. This timestamp is checked
// against the block header's timestamp.
Timeout time.Time `protobuf:"bytes,11,opt,name=timeout,proto3,stdtime" json:"timeout"`
// voting_period_end is the timestamp before which voting must be done.
// Unless a successfull MsgExec is called before (to execute a proposal whose
// tally is successful before the voting period ends), tallying will be done
// at this point, and the `final_tally_result`, as well
// as `status` and `result` fields will be accordingly updated.
VotingPeriodEnd time.Time `protobuf:"bytes,11,opt,name=voting_period_end,json=votingPeriodEnd,proto3,stdtime" json:"voting_period_end"`
// executor_result is the final result based on the votes and election rule. Initial value is NotRun.
ExecutorResult ProposalExecutorResult `protobuf:"varint,12,opt,name=executor_result,json=executorResult,proto3,enum=cosmos.group.v1beta1.ProposalExecutorResult" json:"executor_result,omitempty"`
// messages is a list of Msgs that will be executed if the proposal passes.
@ -662,7 +727,7 @@ func (m *Proposal) Reset() { *m = Proposal{} }
func (m *Proposal) String() string { return proto.CompactTextString(m) }
func (*Proposal) ProtoMessage() {}
func (*Proposal) Descriptor() ([]byte, []int) {
return fileDescriptor_e091dfce5c49c8b6, []int{7}
return fileDescriptor_e091dfce5c49c8b6, []int{8}
}
func (m *Proposal) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -707,7 +772,7 @@ func (m *TallyResult) Reset() { *m = TallyResult{} }
func (m *TallyResult) String() string { return proto.CompactTextString(m) }
func (*TallyResult) ProtoMessage() {}
func (*TallyResult) Descriptor() ([]byte, []int) {
return fileDescriptor_e091dfce5c49c8b6, []int{8}
return fileDescriptor_e091dfce5c49c8b6, []int{9}
}
func (m *TallyResult) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -754,7 +819,7 @@ func (m *Vote) Reset() { *m = Vote{} }
func (m *Vote) String() string { return proto.CompactTextString(m) }
func (*Vote) ProtoMessage() {}
func (*Vote) Descriptor() ([]byte, []int) {
return fileDescriptor_e091dfce5c49c8b6, []int{9}
return fileDescriptor_e091dfce5c49c8b6, []int{10}
}
func (m *Vote) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@ -827,6 +892,7 @@ func init() {
proto.RegisterType((*Members)(nil), "cosmos.group.v1beta1.Members")
proto.RegisterType((*ThresholdDecisionPolicy)(nil), "cosmos.group.v1beta1.ThresholdDecisionPolicy")
proto.RegisterType((*PercentageDecisionPolicy)(nil), "cosmos.group.v1beta1.PercentageDecisionPolicy")
proto.RegisterType((*DecisionPolicyWindows)(nil), "cosmos.group.v1beta1.DecisionPolicyWindows")
proto.RegisterType((*GroupInfo)(nil), "cosmos.group.v1beta1.GroupInfo")
proto.RegisterType((*GroupMember)(nil), "cosmos.group.v1beta1.GroupMember")
proto.RegisterType((*GroupPolicyInfo)(nil), "cosmos.group.v1beta1.GroupPolicyInfo")
@ -838,87 +904,91 @@ func init() {
func init() { proto.RegisterFile("cosmos/group/v1beta1/types.proto", fileDescriptor_e091dfce5c49c8b6) }
var fileDescriptor_e091dfce5c49c8b6 = []byte{
// 1274 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4f, 0x6f, 0x1b, 0x45,
0x14, 0xf7, 0x3a, 0x8e, 0xff, 0x3c, 0xa7, 0x8e, 0x35, 0x8d, 0xda, 0x4d, 0x1a, 0x6c, 0xd7, 0xe4,
0x10, 0x15, 0x6a, 0xb7, 0x01, 0x21, 0x54, 0x95, 0xa2, 0xb5, 0xb3, 0x2d, 0x46, 0xa9, 0x6d, 0x76,
0xd7, 0x09, 0xf4, 0xc0, 0x6a, 0xed, 0x9d, 0x3a, 0x2b, 0xec, 0x1d, 0x6b, 0x77, 0x9c, 0xd6, 0xdf,
0xa0, 0x42, 0x42, 0xf4, 0xc0, 0x81, 0x0b, 0x52, 0x25, 0xee, 0x48, 0x48, 0x3d, 0xf1, 0x09, 0x2a,
0x4e, 0x15, 0x27, 0x4e, 0x80, 0xd2, 0x4b, 0xb9, 0xf3, 0x01, 0xd0, 0xce, 0xcc, 0xfa, 0x5f, 0x5d,
0xab, 0xad, 0xe0, 0x64, 0xcf, 0xbc, 0xdf, 0x9b, 0xf7, 0x7b, 0xef, 0xfd, 0xe6, 0x8d, 0x16, 0x0a,
0x1d, 0xe2, 0xf7, 0x89, 0x5f, 0xee, 0x7a, 0x64, 0x38, 0x28, 0x9f, 0x5c, 0x6d, 0x63, 0x6a, 0x5d,
0x2d, 0xd3, 0xd1, 0x00, 0xfb, 0xa5, 0x81, 0x47, 0x28, 0x41, 0x1b, 0x1c, 0x51, 0x62, 0x88, 0x92,
0x40, 0x6c, 0x6d, 0x74, 0x49, 0x97, 0x30, 0x40, 0x39, 0xf8, 0xc7, 0xb1, 0x5b, 0xb9, 0x2e, 0x21,
0xdd, 0x1e, 0x2e, 0xb3, 0x55, 0x7b, 0x78, 0xb7, 0x6c, 0x0f, 0x3d, 0x8b, 0x3a, 0xc4, 0x15, 0xf6,
0xfc, 0xbc, 0x9d, 0x3a, 0x7d, 0xec, 0x53, 0xab, 0x3f, 0x10, 0x80, 0x4d, 0x1e, 0xcc, 0xe4, 0x27,
0x8b, 0xc8, 0xc2, 0x34, 0xef, 0x6b, 0xb9, 0x23, 0x6e, 0x2a, 0xfe, 0x2c, 0x41, 0xfc, 0x36, 0xee,
0xb7, 0xb1, 0x87, 0xf6, 0x20, 0x61, 0xd9, 0xb6, 0x87, 0x7d, 0x5f, 0x96, 0x0a, 0xd2, 0x6e, 0xaa,
0x22, 0xff, 0xf6, 0xf8, 0x72, 0x98, 0x82, 0xc2, 0x2d, 0x3a, 0xf5, 0x1c, 0xb7, 0xab, 0x85, 0x40,
0x74, 0x0e, 0xe2, 0xf7, 0xb0, 0xd3, 0x3d, 0xa6, 0x72, 0x34, 0x70, 0xd1, 0xc4, 0x0a, 0x6d, 0x41,
0xb2, 0x8f, 0xa9, 0x65, 0x5b, 0xd4, 0x92, 0x57, 0x98, 0x65, 0xbc, 0x46, 0x1f, 0x43, 0xd2, 0xb2,
0x6d, 0x6c, 0x9b, 0x16, 0x95, 0x63, 0x05, 0x69, 0x37, 0xbd, 0xb7, 0x55, 0xe2, 0x04, 0x4b, 0x21,
0xc1, 0x92, 0x11, 0x26, 0x57, 0x49, 0x3e, 0xf9, 0x23, 0x1f, 0x79, 0xf8, 0x67, 0x5e, 0x62, 0x41,
0xb1, 0xad, 0xd0, 0xe2, 0x2d, 0x48, 0x70, 0xca, 0x3e, 0xba, 0x0e, 0x89, 0x3e, 0xff, 0x2b, 0x4b,
0x85, 0x95, 0xdd, 0xf4, 0xde, 0x76, 0x69, 0x51, 0xcd, 0x4b, 0x1c, 0x5f, 0x89, 0x05, 0x87, 0x69,
0xa1, 0x4b, 0xf1, 0x6b, 0x09, 0xce, 0x1b, 0xc7, 0x1e, 0xf6, 0x8f, 0x49, 0xcf, 0xde, 0xc7, 0x1d,
0xc7, 0x77, 0x88, 0xdb, 0x24, 0x3d, 0xa7, 0x33, 0x42, 0xdb, 0x90, 0xa2, 0xa1, 0x89, 0xd7, 0x43,
0x9b, 0x6c, 0xa0, 0x8f, 0x20, 0x11, 0xd4, 0x9f, 0x0c, 0x79, 0xe2, 0xe9, 0xbd, 0xcd, 0x17, 0x52,
0xd8, 0x17, 0xfd, 0xe3, 0x19, 0x7c, 0xcf, 0x32, 0x10, 0x3e, 0xd7, 0xd0, 0xaf, 0x8f, 0x2f, 0x67,
0x66, 0x03, 0x16, 0xbf, 0x91, 0x40, 0x6e, 0x62, 0xaf, 0x83, 0x5d, 0x6a, 0x75, 0xf1, 0x1c, 0x9b,
0x1c, 0xc0, 0x60, 0x6c, 0x13, 0x74, 0xa6, 0x76, 0xfe, 0x0f, 0x3e, 0x7f, 0x4b, 0x90, 0xba, 0x15,
0x14, 0xb1, 0xe6, 0xde, 0x25, 0x28, 0x03, 0x51, 0x87, 0xd7, 0x21, 0xa6, 0x45, 0x1d, 0x1b, 0x95,
0x60, 0xd5, 0xb2, 0xfb, 0x8e, 0xcb, 0xfb, 0xbe, 0x44, 0x2a, 0x1c, 0xb6, 0x54, 0x10, 0x32, 0x24,
0x4e, 0xb0, 0x17, 0x84, 0x66, 0x7a, 0x88, 0x69, 0xe1, 0x12, 0x5d, 0x84, 0x35, 0x4a, 0xa8, 0xd5,
0x33, 0x85, 0xc8, 0x56, 0x99, 0x67, 0x9a, 0xed, 0x1d, 0x71, 0xa5, 0x55, 0x01, 0x3a, 0x1e, 0xb6,
0x28, 0xd7, 0x53, 0xfc, 0x35, 0xf4, 0x94, 0x12, 0x7e, 0x0a, 0x2d, 0x7e, 0x09, 0x69, 0x96, 0xaa,
0xb8, 0x09, 0x9b, 0x90, 0x64, 0xf2, 0x31, 0xc7, 0x29, 0x27, 0xd8, 0xba, 0x66, 0xa3, 0xf7, 0x21,
0xce, 0xd5, 0x23, 0xea, 0xbc, 0x54, 0x6f, 0x9a, 0xc0, 0x16, 0x9f, 0x47, 0x61, 0x9d, 0x05, 0xe0,
0xb5, 0x65, 0x15, 0x7d, 0x93, 0xeb, 0x36, 0x4d, 0x2c, 0x3a, 0x4b, 0x6c, 0xdc, 0x90, 0x95, 0xd7,
0x6f, 0x48, 0xec, 0xe5, 0x0d, 0x59, 0x9d, 0x6d, 0xc8, 0x67, 0xb0, 0x6e, 0x0b, 0x99, 0x98, 0x03,
0x96, 0x8b, 0x28, 0xf9, 0xc6, 0x0b, 0x25, 0x57, 0xdc, 0x51, 0x65, 0x81, 0xae, 0xb4, 0x8c, 0x3d,
0x2b, 0xed, 0xd9, 0x06, 0x26, 0xde, 0xa8, 0x81, 0xd7, 0x92, 0x0f, 0x1e, 0xe5, 0x23, 0xcf, 0x1f,
0xe5, 0xa5, 0xe2, 0xe9, 0x2a, 0x24, 0x9b, 0x1e, 0x19, 0x10, 0xdf, 0xea, 0xbd, 0xa0, 0xda, 0xa9,
0x9a, 0x47, 0x5f, 0xb5, 0xe6, 0xcb, 0x94, 0xfb, 0x01, 0xa4, 0x06, 0x2c, 0x56, 0x30, 0x80, 0x62,
0x85, 0x95, 0xa5, 0x27, 0x4e, 0xa0, 0x48, 0x85, 0xb4, 0x3f, 0x6c, 0xf7, 0x1d, 0x6a, 0x06, 0x37,
0x90, 0x15, 0xf9, 0x55, 0x93, 0x06, 0xee, 0x18, 0x98, 0xd0, 0xdb, 0x70, 0x86, 0xcb, 0x21, 0xec,
0x56, 0x9c, 0x65, 0xba, 0xc6, 0x36, 0x0f, 0x45, 0xcb, 0xae, 0xc0, 0x06, 0x07, 0xf1, 0x7e, 0x8d,
0xb1, 0x09, 0x86, 0x45, 0xdd, 0x89, 0x2c, 0x43, 0x8f, 0xeb, 0x10, 0xf7, 0xa9, 0x45, 0x87, 0xbe,
0x9c, 0x2c, 0x48, 0xbb, 0x99, 0xbd, 0x9d, 0xc5, 0x1a, 0x0f, 0xab, 0xac, 0x33, 0xac, 0x26, 0x7c,
0x02, 0x6f, 0x0f, 0xfb, 0xc3, 0x1e, 0x95, 0x53, 0xaf, 0xe2, 0xad, 0x31, 0xac, 0x26, 0x7c, 0x50,
0x0b, 0xd0, 0x5d, 0xc7, 0xb5, 0x7a, 0x26, 0xb5, 0x7a, 0xbd, 0x91, 0x29, 0x4e, 0x02, 0x56, 0xa0,
0x8b, 0x8b, 0x4f, 0x32, 0x02, 0x24, 0x3f, 0x46, 0x0c, 0xf8, 0x2c, 0x3b, 0x62, 0x6a, 0x1f, 0xdd,
0x98, 0xcc, 0xc7, 0xf4, 0xeb, 0x3c, 0x39, 0xc2, 0x09, 0xb5, 0x60, 0x1d, 0xdf, 0xc7, 0x9d, 0x21,
0x25, 0x5e, 0xc8, 0x69, 0x8d, 0x65, 0xf7, 0xee, 0xf2, 0xec, 0x54, 0xe1, 0x24, 0xb2, 0xcc, 0xe0,
0x99, 0x35, 0xba, 0x12, 0x68, 0xcb, 0xf7, 0xad, 0x2e, 0xf6, 0xe5, 0x33, 0xec, 0xfd, 0x5a, 0x78,
0x8f, 0xb4, 0x31, 0xea, 0x5a, 0x2c, 0x10, 0x7a, 0xf1, 0x07, 0x09, 0xd2, 0xd3, 0xe9, 0x5d, 0x80,
0xd4, 0x08, 0xfb, 0x66, 0x87, 0x0c, 0x5d, 0x2a, 0x5e, 0x87, 0xe4, 0x08, 0xfb, 0xd5, 0x60, 0x1d,
0xa8, 0xc4, 0x6a, 0xfb, 0xd4, 0x72, 0x5c, 0x01, 0xe0, 0x4f, 0xf5, 0x9a, 0xd8, 0xe4, 0xa0, 0x4d,
0x48, 0xba, 0x44, 0xd8, 0xb9, 0xca, 0x13, 0x2e, 0xe1, 0xa6, 0x77, 0x00, 0xb9, 0xc4, 0xbc, 0xe7,
0xd0, 0x63, 0xf3, 0x04, 0xd3, 0x10, 0xc4, 0x67, 0xc6, 0xba, 0x4b, 0x8e, 0x1c, 0x7a, 0x7c, 0x88,
0x29, 0x07, 0x0b, 0x7e, 0xff, 0x48, 0x10, 0x3b, 0x24, 0x14, 0xa3, 0x3c, 0xa4, 0x07, 0xa2, 0x14,
0x93, 0x61, 0x0a, 0xe1, 0x16, 0x1f, 0x5b, 0x27, 0x84, 0x8a, 0x71, 0xba, 0x74, 0x6c, 0x31, 0x18,
0xfa, 0x10, 0xe2, 0x64, 0x10, 0x3c, 0x63, 0x8c, 0x65, 0x66, 0xaf, 0xb0, 0xb8, 0xfe, 0x41, 0xf0,
0x06, 0xc3, 0x69, 0x02, 0xbf, 0x74, 0xe0, 0xfd, 0x37, 0xf7, 0xf1, 0xd2, 0xb7, 0x12, 0xc0, 0x24,
0x32, 0xba, 0x00, 0xe7, 0x0f, 0x1b, 0x86, 0x6a, 0x36, 0x9a, 0x46, 0xad, 0x51, 0x37, 0x5b, 0x75,
0xbd, 0xa9, 0x56, 0x6b, 0x37, 0x6b, 0xea, 0x7e, 0x36, 0x82, 0xce, 0xc2, 0xfa, 0xb4, 0xf1, 0x0b,
0x55, 0xcf, 0x4a, 0xe8, 0x3c, 0x9c, 0x9d, 0xde, 0x54, 0x2a, 0xba, 0xa1, 0xd4, 0xea, 0xd9, 0x28,
0x42, 0x90, 0x99, 0x36, 0xd4, 0x1b, 0xd9, 0x15, 0xb4, 0x0d, 0xf2, 0xec, 0x9e, 0x79, 0x54, 0x33,
0x3e, 0x31, 0x0f, 0x55, 0xa3, 0x91, 0x8d, 0x6d, 0xc5, 0x1e, 0xfc, 0x98, 0x8b, 0x5c, 0xfa, 0x49,
0x82, 0xcc, 0xec, 0x3d, 0x45, 0x79, 0xb8, 0xd0, 0xd4, 0x1a, 0xcd, 0x86, 0xae, 0x1c, 0x98, 0xba,
0xa1, 0x18, 0x2d, 0x7d, 0x8e, 0xd9, 0x5b, 0xb0, 0x39, 0x0f, 0xd0, 0x5b, 0x95, 0xdb, 0x35, 0xc3,
0x50, 0xf7, 0xb3, 0x12, 0xda, 0x82, 0x73, 0xf3, 0xe6, 0xea, 0x41, 0x43, 0x57, 0xf7, 0xb3, 0xd1,
0x20, 0xe3, 0x79, 0x9b, 0x52, 0x69, 0x68, 0x81, 0xe3, 0xca, 0xa2, 0x73, 0x03, 0xc2, 0xfb, 0x9a,
0x72, 0x54, 0x1f, 0x13, 0xfe, 0x6e, 0x8a, 0xb0, 0x10, 0xf7, 0x34, 0x61, 0x4d, 0xd5, 0x5b, 0x07,
0xc6, 0x1c, 0xe1, 0x85, 0x80, 0x9b, 0xb5, 0xba, 0x72, 0x50, 0xbb, 0xc3, 0x28, 0x6f, 0x83, 0x3c,
0x0f, 0x50, 0xaa, 0x55, 0xb5, 0x69, 0x30, 0xd2, 0x0b, 0xac, 0x9a, 0xfa, 0xa9, 0x5a, 0x65, 0xac,
0x05, 0xad, 0x5f, 0x24, 0x38, 0xb7, 0xf8, 0x4e, 0xa3, 0x5d, 0xd8, 0x19, 0xbb, 0xab, 0x9f, 0xab,
0xd5, 0x96, 0xd1, 0xd0, 0x16, 0xf3, 0xdc, 0x81, 0xc2, 0x4b, 0x91, 0xf5, 0x86, 0x61, 0x6a, 0xad,
0x7a, 0x56, 0x5a, 0x8a, 0xd2, 0x5b, 0xd5, 0xaa, 0xaa, 0xeb, 0xd9, 0xe8, 0x52, 0xd4, 0x4d, 0xa5,
0x76, 0xd0, 0xd2, 0xd4, 0x90, 0x7c, 0xe5, 0xc6, 0x93, 0xd3, 0x9c, 0xf4, 0xf4, 0x34, 0x27, 0xfd,
0x75, 0x9a, 0x93, 0x1e, 0x3e, 0xcb, 0x45, 0x9e, 0x3e, 0xcb, 0x45, 0x7e, 0x7f, 0x96, 0x8b, 0xdc,
0xd9, 0xe9, 0x3a, 0xf4, 0x78, 0xd8, 0x2e, 0x75, 0x48, 0x5f, 0x7c, 0x31, 0x88, 0x9f, 0xcb, 0xbe,
0xfd, 0x55, 0xf9, 0x3e, 0xff, 0xb4, 0x69, 0xc7, 0xd9, 0x05, 0x78, 0xef, 0xdf, 0x00, 0x00, 0x00,
0xff, 0xff, 0x7b, 0x95, 0x5a, 0x6f, 0xf1, 0x0c, 0x00, 0x00,
// 1344 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4d, 0x6f, 0x1b, 0x45,
0x18, 0xf6, 0x3a, 0x8e, 0x3f, 0x5e, 0xa7, 0x8e, 0x99, 0x86, 0x76, 0x93, 0x06, 0xdb, 0x35, 0x39,
0x44, 0x2d, 0xb5, 0x5b, 0x83, 0x10, 0xaa, 0x2a, 0x90, 0xed, 0x6c, 0x5b, 0xa3, 0xd4, 0x36, 0xbb,
0xeb, 0x04, 0x7a, 0x60, 0xb5, 0xf6, 0x4e, 0x9d, 0x15, 0xf6, 0x8e, 0xb5, 0x3b, 0x4e, 0xea, 0x7f,
0xd0, 0x1b, 0x15, 0x02, 0x89, 0x0b, 0x52, 0x25, 0xee, 0x48, 0x48, 0x3d, 0x20, 0x7e, 0x41, 0xc5,
0xa9, 0xe2, 0xc4, 0x09, 0x50, 0x7b, 0x29, 0xf7, 0xfe, 0x00, 0xb4, 0x33, 0xb3, 0x8e, 0xed, 0xba,
0x56, 0x52, 0xc1, 0xa9, 0x99, 0x79, 0x9f, 0xe7, 0x9d, 0xe7, 0xfd, 0xdc, 0x1a, 0x72, 0x1d, 0xe2,
0xf5, 0x89, 0x57, 0xec, 0xba, 0x64, 0x38, 0x28, 0x1e, 0x5e, 0x6b, 0x63, 0x6a, 0x5e, 0x2b, 0xd2,
0xd1, 0x00, 0x7b, 0x85, 0x81, 0x4b, 0x28, 0x41, 0x6b, 0x1c, 0x51, 0x60, 0x88, 0x82, 0x40, 0x6c,
0xac, 0x75, 0x49, 0x97, 0x30, 0x40, 0xd1, 0xff, 0x8b, 0x63, 0x37, 0x32, 0x5d, 0x42, 0xba, 0x3d,
0x5c, 0x64, 0xa7, 0xf6, 0xf0, 0x5e, 0xd1, 0x1a, 0xba, 0x26, 0xb5, 0x89, 0x23, 0xec, 0xd9, 0x59,
0x3b, 0xb5, 0xfb, 0xd8, 0xa3, 0x66, 0x7f, 0x20, 0x00, 0xeb, 0xfc, 0x31, 0x83, 0x7b, 0x16, 0x2f,
0x0b, 0xd3, 0x2c, 0xd7, 0x74, 0x46, 0xdc, 0x94, 0xff, 0x59, 0x82, 0xe8, 0x1d, 0xdc, 0x6f, 0x63,
0x17, 0x95, 0x20, 0x66, 0x5a, 0x96, 0x8b, 0x3d, 0x4f, 0x96, 0x72, 0xd2, 0x76, 0xa2, 0x22, 0xff,
0xfe, 0xf8, 0x4a, 0x10, 0x42, 0x99, 0x5b, 0x34, 0xea, 0xda, 0x4e, 0x57, 0x0d, 0x80, 0xe8, 0x1c,
0x44, 0x8f, 0xb0, 0xdd, 0x3d, 0xa0, 0x72, 0xd8, 0xa7, 0xa8, 0xe2, 0x84, 0x36, 0x20, 0xde, 0xc7,
0xd4, 0xb4, 0x4c, 0x6a, 0xca, 0x4b, 0xcc, 0x32, 0x3e, 0xa3, 0x4f, 0x20, 0x6e, 0x5a, 0x16, 0xb6,
0x0c, 0x93, 0xca, 0x91, 0x9c, 0xb4, 0x9d, 0x2c, 0x6d, 0x14, 0xb8, 0xc0, 0x42, 0x20, 0xb0, 0xa0,
0x07, 0xc1, 0x55, 0xe2, 0x4f, 0xfe, 0xcc, 0x86, 0x1e, 0xfe, 0x95, 0x95, 0xd8, 0xa3, 0xd8, 0x2a,
0xd3, 0xfc, 0x2d, 0x88, 0x71, 0xc9, 0x1e, 0xba, 0x01, 0xb1, 0x3e, 0xff, 0x53, 0x96, 0x72, 0x4b,
0xdb, 0xc9, 0xd2, 0x66, 0x61, 0x5e, 0xce, 0x0b, 0x1c, 0x5f, 0x89, 0xf8, 0xce, 0xd4, 0x80, 0x92,
0xff, 0x46, 0x82, 0xf3, 0xfa, 0x81, 0x8b, 0xbd, 0x03, 0xd2, 0xb3, 0x76, 0x70, 0xc7, 0xf6, 0x6c,
0xe2, 0x34, 0x49, 0xcf, 0xee, 0x8c, 0xd0, 0x26, 0x24, 0x68, 0x60, 0xe2, 0xf9, 0x50, 0x8f, 0x2f,
0x90, 0x02, 0xb1, 0x23, 0xdb, 0xb1, 0xc8, 0x91, 0xc7, 0x02, 0x4f, 0x96, 0x2e, 0xcf, 0x7f, 0x77,
0xda, 0xe9, 0x3e, 0xa7, 0xa8, 0x01, 0xf7, 0x3a, 0xfa, 0xed, 0xf1, 0x95, 0xd4, 0x34, 0x26, 0xff,
0x9d, 0x04, 0x72, 0x13, 0xbb, 0x1d, 0xec, 0x50, 0xb3, 0x8b, 0x67, 0x54, 0x65, 0x00, 0x06, 0x63,
0x9b, 0x90, 0x35, 0x71, 0xf3, 0x7f, 0xea, 0xfa, 0x45, 0x82, 0xb7, 0xe7, 0xd2, 0xd0, 0x6d, 0x38,
0x73, 0x48, 0xa8, 0xed, 0x74, 0x8d, 0x01, 0x76, 0x6d, 0xc2, 0xd3, 0x95, 0x2c, 0xad, 0xbf, 0x52,
0xd5, 0x1d, 0xd1, 0xd2, 0xbc, 0xa8, 0xdf, 0xfb, 0x45, 0x5d, 0xe1, 0xcc, 0x26, 0x23, 0xa2, 0x16,
0xac, 0xf5, 0x6d, 0xc7, 0xc0, 0xf7, 0x71, 0x67, 0xe8, 0x03, 0x03, 0x87, 0xe1, 0x93, 0x3b, 0x44,
0x7d, 0xdb, 0x51, 0x02, 0x3e, 0x77, 0x9b, 0xff, 0x47, 0x82, 0xc4, 0x2d, 0x3f, 0xfe, 0x9a, 0x73,
0x8f, 0xa0, 0x14, 0x84, 0x6d, 0xae, 0x31, 0xa2, 0x86, 0x6d, 0x0b, 0x15, 0x60, 0xd9, 0xb4, 0xfa,
0xb6, 0xc3, 0x5b, 0x78, 0x41, 0xd7, 0x73, 0xd8, 0xc2, 0xde, 0x96, 0x21, 0x76, 0x88, 0x5d, 0x3f,
0x45, 0xac, 0xb5, 0x23, 0x6a, 0x70, 0x44, 0x17, 0x61, 0x85, 0x12, 0x6a, 0xf6, 0x0c, 0x31, 0x2f,
0xcb, 0x8c, 0x99, 0x64, 0x77, 0xfb, 0x7c, 0x68, 0xaa, 0x00, 0x1d, 0x17, 0x9b, 0x94, 0x8f, 0x46,
0xf4, 0x14, 0xa3, 0x91, 0x10, 0xbc, 0x32, 0xcd, 0x7f, 0x09, 0x49, 0x16, 0xaa, 0x18, 0xea, 0x75,
0x88, 0xb3, 0xca, 0x1b, 0xe3, 0x90, 0x63, 0xec, 0x5c, 0xb3, 0xd0, 0x07, 0x10, 0xe5, 0x83, 0x20,
0xd2, 0xbb, 0x70, 0x74, 0x54, 0x81, 0xcd, 0xbf, 0x08, 0xc3, 0x2a, 0x7b, 0x80, 0xf7, 0x00, 0xcb,
0xe8, 0x9b, 0x6c, 0x8e, 0x49, 0x61, 0xe1, 0x69, 0x61, 0xe3, 0x82, 0x2c, 0x9d, 0xbe, 0x20, 0x91,
0xd7, 0x17, 0x64, 0x79, 0xba, 0x20, 0x9f, 0xc1, 0xaa, 0x25, 0xda, 0xd9, 0x18, 0xb0, 0x58, 0x44,
0xca, 0xd7, 0x5e, 0x49, 0x79, 0xd9, 0x19, 0x55, 0xe6, 0x8c, 0x84, 0x9a, 0xb2, 0xa6, 0xa7, 0x73,
0xba, 0x80, 0xb1, 0x37, 0x2a, 0xe0, 0xf5, 0xf8, 0x83, 0x47, 0xd9, 0xd0, 0x8b, 0x47, 0x59, 0x29,
0xff, 0x72, 0x19, 0xe2, 0x4d, 0x97, 0x0c, 0x88, 0x67, 0xf6, 0x5e, 0xe9, 0xda, 0x89, 0x9c, 0x87,
0x4f, 0x9a, 0xf3, 0x45, 0x9d, 0xfb, 0x21, 0x24, 0x06, 0xec, 0x2d, 0x7f, 0x97, 0x46, 0x72, 0x4b,
0x0b, 0x3d, 0x1e, 0x43, 0x91, 0x02, 0x49, 0x6f, 0xd8, 0xee, 0xdb, 0xd4, 0xf0, 0x3f, 0x48, 0x2c,
0xc9, 0x27, 0x0d, 0x1a, 0x38, 0xd1, 0x37, 0xa1, 0x77, 0xe1, 0x0c, 0x6f, 0x87, 0xa0, 0x5a, 0x51,
0x16, 0xe9, 0x0a, 0xbb, 0xdc, 0x13, 0x25, 0xbb, 0x0a, 0x6b, 0x1c, 0xc4, 0xeb, 0x35, 0xc6, 0xc6,
0x18, 0x16, 0x75, 0x8f, 0xdb, 0x32, 0x60, 0xdc, 0x80, 0xa8, 0x47, 0x4d, 0x3a, 0xf4, 0xe4, 0x78,
0x4e, 0xda, 0x4e, 0x95, 0xb6, 0xe6, 0xf7, 0x78, 0x90, 0x65, 0x8d, 0x61, 0x55, 0xc1, 0xf1, 0xd9,
0x2e, 0xf6, 0x86, 0x3d, 0x2a, 0x27, 0x4e, 0xc2, 0x56, 0x19, 0x56, 0x15, 0x1c, 0xd4, 0x02, 0x74,
0xcf, 0x76, 0xcc, 0x9e, 0x41, 0xcd, 0x5e, 0x6f, 0x64, 0x08, 0x4f, 0xc0, 0x12, 0x74, 0x71, 0xbe,
0x27, 0xdd, 0x47, 0x72, 0x37, 0xe2, 0x5b, 0x95, 0x66, 0x2e, 0x26, 0xee, 0x51, 0x13, 0xde, 0x9a,
0xda, 0xb6, 0x06, 0x76, 0x2c, 0x39, 0x79, 0x8a, 0xb4, 0xaf, 0x4e, 0xae, 0x5c, 0xc5, 0xf1, 0xb7,
0xee, 0x2a, 0xdf, 0xb8, 0xc4, 0x0d, 0x54, 0xae, 0xb0, 0x78, 0xdf, 0x5b, 0x1c, 0xaf, 0x22, 0x48,
0x22, 0xee, 0x14, 0x9e, 0x3a, 0xa3, 0xab, 0x7e, 0xb7, 0x79, 0x9e, 0xd9, 0xc5, 0x9e, 0x7c, 0x86,
0x7d, 0x9c, 0xe7, 0x4e, 0x96, 0x3a, 0x46, 0x5d, 0x8f, 0xf8, 0xad, 0x9f, 0xff, 0x41, 0x82, 0xe4,
0x64, 0xc0, 0x17, 0x20, 0x31, 0xc2, 0x9e, 0xd1, 0x21, 0x43, 0x87, 0x8a, 0x4f, 0x5e, 0x7c, 0x84,
0xbd, 0xaa, 0x7f, 0xf6, 0xfb, 0xc6, 0x6c, 0x7b, 0xd4, 0xb4, 0x1d, 0x01, 0xe0, 0xff, 0x0f, 0x59,
0x11, 0x97, 0x1c, 0xb4, 0x0e, 0x71, 0x87, 0x08, 0x3b, 0xef, 0xfb, 0x98, 0x43, 0xb8, 0xe9, 0x32,
0x20, 0x87, 0x18, 0x47, 0x36, 0x3d, 0x30, 0x0e, 0x31, 0x0d, 0x40, 0x7c, 0x8b, 0xac, 0x3a, 0x64,
0xdf, 0xa6, 0x07, 0x7b, 0x98, 0x72, 0xb0, 0xd0, 0xf7, 0x52, 0x82, 0xc8, 0x1e, 0xa1, 0x18, 0x65,
0x21, 0x39, 0x10, 0xa9, 0x38, 0x5e, 0xaf, 0x10, 0x5c, 0xf1, 0x45, 0x76, 0x48, 0xa8, 0x58, 0xb0,
0x0b, 0x17, 0x19, 0x83, 0xa1, 0x8f, 0x20, 0x4a, 0x06, 0xfe, 0x77, 0x8b, 0xa9, 0x4c, 0x95, 0x72,
0xf3, 0xf3, 0xef, 0x3f, 0xde, 0x60, 0x38, 0x55, 0xe0, 0x17, 0xae, 0xc0, 0xff, 0x66, 0x42, 0x2f,
0x7d, 0x2d, 0x01, 0x1c, 0xbf, 0x8c, 0x2e, 0xc0, 0xf9, 0xbd, 0x86, 0xae, 0x18, 0x8d, 0xa6, 0x5e,
0x6b, 0xd4, 0x8d, 0x56, 0x5d, 0x6b, 0x2a, 0xd5, 0xda, 0xcd, 0x9a, 0xb2, 0x93, 0x0e, 0xa1, 0xb3,
0xb0, 0x3a, 0x69, 0xfc, 0x42, 0xd1, 0xd2, 0x12, 0x3a, 0x0f, 0x67, 0x27, 0x2f, 0xcb, 0x15, 0x4d,
0x2f, 0xd7, 0xea, 0xe9, 0x30, 0x42, 0x90, 0x9a, 0x34, 0xd4, 0x1b, 0xe9, 0x25, 0xb4, 0x09, 0xf2,
0xf4, 0x9d, 0xb1, 0x5f, 0xd3, 0x6f, 0x1b, 0x7b, 0x8a, 0xde, 0x48, 0x47, 0x36, 0x22, 0x0f, 0x7e,
0xcc, 0x84, 0x2e, 0xfd, 0x24, 0x41, 0x6a, 0x7a, 0x72, 0x51, 0x16, 0x2e, 0x34, 0xd5, 0x46, 0xb3,
0xa1, 0x95, 0x77, 0x0d, 0x4d, 0x2f, 0xeb, 0x2d, 0x6d, 0x46, 0xd9, 0x3b, 0xb0, 0x3e, 0x0b, 0xd0,
0x5a, 0x95, 0x3b, 0x35, 0x5d, 0x57, 0x76, 0xd2, 0x12, 0xda, 0x80, 0x73, 0xb3, 0xe6, 0xea, 0x6e,
0x43, 0x53, 0x76, 0xd2, 0x61, 0x3f, 0xe2, 0x59, 0x5b, 0xb9, 0xd2, 0x50, 0x7d, 0xe2, 0xd2, 0x3c,
0xbf, 0xbe, 0xe0, 0x1d, 0xb5, 0xbc, 0x5f, 0x1f, 0x0b, 0xfe, 0x76, 0x42, 0xb0, 0x68, 0xee, 0x49,
0xc1, 0xaa, 0xa2, 0xb5, 0x76, 0xf5, 0x19, 0xc1, 0x73, 0x01, 0x37, 0x6b, 0xf5, 0xf2, 0x6e, 0xed,
0x2e, 0x93, 0xbc, 0x09, 0xf2, 0x2c, 0xa0, 0x5c, 0xad, 0x2a, 0x4d, 0x9d, 0x89, 0x9e, 0x63, 0x55,
0x95, 0x4f, 0x95, 0x2a, 0x53, 0x2d, 0x64, 0xfd, 0x2a, 0xc1, 0xb9, 0xf9, 0x33, 0x8d, 0xb6, 0x61,
0x6b, 0x4c, 0x57, 0x3e, 0x57, 0xaa, 0x2d, 0xbd, 0xa1, 0xce, 0xd7, 0xb9, 0x05, 0xb9, 0xd7, 0x22,
0xeb, 0x0d, 0xdd, 0x50, 0x5b, 0xf5, 0xb4, 0xb4, 0x10, 0xa5, 0xb5, 0xaa, 0x55, 0x45, 0xd3, 0xd2,
0xe1, 0x85, 0xa8, 0x9b, 0xe5, 0xda, 0x6e, 0x4b, 0x55, 0x02, 0xf1, 0x95, 0x8f, 0x9f, 0x3c, 0xcb,
0x48, 0x4f, 0x9f, 0x65, 0xa4, 0xbf, 0x9f, 0x65, 0xa4, 0x87, 0xcf, 0x33, 0xa1, 0xa7, 0xcf, 0x33,
0xa1, 0x3f, 0x9e, 0x67, 0x42, 0x77, 0xb7, 0xba, 0x36, 0x3d, 0x18, 0xb6, 0x0b, 0x1d, 0xd2, 0x17,
0x3f, 0x87, 0xc4, 0x3f, 0x57, 0x3c, 0xeb, 0xab, 0xe2, 0x7d, 0xfe, 0xbb, 0xad, 0x1d, 0x65, 0x03,
0xf0, 0xfe, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf7, 0x5a, 0xf3, 0xf9, 0xce, 0x0d, 0x00, 0x00,
}
func (this *GroupPolicyInfo) Equal(that interface{}) bool {
@ -1072,14 +1142,18 @@ func (m *ThresholdDecisionPolicy) MarshalToSizedBuffer(dAtA []byte) (int, error)
_ = i
var l int
_ = l
n2, err2 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.Timeout, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.Timeout):])
if err2 != nil {
return 0, err2
if m.Windows != nil {
{
size, err := m.Windows.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintTypes(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
}
i -= n2
i = encodeVarintTypes(dAtA, i, uint64(n2))
i--
dAtA[i] = 0x12
if len(m.Threshold) > 0 {
i -= len(m.Threshold)
copy(dAtA[i:], m.Threshold)
@ -1110,14 +1184,18 @@ func (m *PercentageDecisionPolicy) MarshalToSizedBuffer(dAtA []byte) (int, error
_ = i
var l int
_ = l
n3, err3 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.Timeout, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.Timeout):])
if err3 != nil {
return 0, err3
if m.Windows != nil {
{
size, err := m.Windows.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintTypes(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
}
i -= n3
i = encodeVarintTypes(dAtA, i, uint64(n3))
i--
dAtA[i] = 0x12
if len(m.Percentage) > 0 {
i -= len(m.Percentage)
copy(dAtA[i:], m.Percentage)
@ -1128,6 +1206,45 @@ func (m *PercentageDecisionPolicy) MarshalToSizedBuffer(dAtA []byte) (int, error
return len(dAtA) - i, nil
}
func (m *DecisionPolicyWindows) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *DecisionPolicyWindows) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *DecisionPolicyWindows) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
n4, err4 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.MinExecutionPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.MinExecutionPeriod):])
if err4 != nil {
return 0, err4
}
i -= n4
i = encodeVarintTypes(dAtA, i, uint64(n4))
i--
dAtA[i] = 0x12
n5, err5 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.VotingPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.VotingPeriod):])
if err5 != nil {
return 0, err5
}
i -= n5
i = encodeVarintTypes(dAtA, i, uint64(n5))
i--
dAtA[i] = 0xa
return len(dAtA) - i, nil
}
func (m *GroupInfo) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@ -1148,12 +1265,12 @@ func (m *GroupInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
n4, err4 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):])
if err4 != nil {
return 0, err4
n6, err6 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):])
if err6 != nil {
return 0, err6
}
i -= n4
i = encodeVarintTypes(dAtA, i, uint64(n4))
i -= n6
i = encodeVarintTypes(dAtA, i, uint64(n6))
i--
dAtA[i] = 0x32
if len(m.TotalWeight) > 0 {
@ -1250,12 +1367,12 @@ func (m *GroupPolicyInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
n6, err6 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):])
if err6 != nil {
return 0, err6
n8, err8 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt):])
if err8 != nil {
return 0, err8
}
i -= n6
i = encodeVarintTypes(dAtA, i, uint64(n6))
i -= n8
i = encodeVarintTypes(dAtA, i, uint64(n8))
i--
dAtA[i] = 0x3a
if m.DecisionPolicy != nil {
@ -1343,12 +1460,12 @@ func (m *Proposal) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i--
dAtA[i] = 0x60
}
n8, err8 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Timeout, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Timeout):])
if err8 != nil {
return 0, err8
n10, err10 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.VotingPeriodEnd, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingPeriodEnd):])
if err10 != nil {
return 0, err10
}
i -= n8
i = encodeVarintTypes(dAtA, i, uint64(n8))
i -= n10
i = encodeVarintTypes(dAtA, i, uint64(n10))
i--
dAtA[i] = 0x5a
{
@ -1381,12 +1498,12 @@ func (m *Proposal) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i--
dAtA[i] = 0x30
}
n10, err10 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.SubmitTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.SubmitTime):])
if err10 != nil {
return 0, err10
n12, err12 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.SubmitTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.SubmitTime):])
if err12 != nil {
return 0, err12
}
i -= n10
i = encodeVarintTypes(dAtA, i, uint64(n10))
i -= n12
i = encodeVarintTypes(dAtA, i, uint64(n12))
i--
dAtA[i] = 0x2a
if len(m.Proposers) > 0 {
@ -1491,12 +1608,12 @@ func (m *Vote) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
n11, err11 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.SubmitTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.SubmitTime):])
if err11 != nil {
return 0, err11
n13, err13 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.SubmitTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.SubmitTime):])
if err13 != nil {
return 0, err13
}
i -= n11
i = encodeVarintTypes(dAtA, i, uint64(n11))
i -= n13
i = encodeVarintTypes(dAtA, i, uint64(n13))
i--
dAtA[i] = 0x2a
if len(m.Metadata) > 0 {
@ -1585,8 +1702,10 @@ func (m *ThresholdDecisionPolicy) Size() (n int) {
if l > 0 {
n += 1 + l + sovTypes(uint64(l))
}
l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.Timeout)
n += 1 + l + sovTypes(uint64(l))
if m.Windows != nil {
l = m.Windows.Size()
n += 1 + l + sovTypes(uint64(l))
}
return n
}
@ -1600,7 +1719,22 @@ func (m *PercentageDecisionPolicy) Size() (n int) {
if l > 0 {
n += 1 + l + sovTypes(uint64(l))
}
l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.Timeout)
if m.Windows != nil {
l = m.Windows.Size()
n += 1 + l + sovTypes(uint64(l))
}
return n
}
func (m *DecisionPolicyWindows) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.VotingPeriod)
n += 1 + l + sovTypes(uint64(l))
l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.MinExecutionPeriod)
n += 1 + l + sovTypes(uint64(l))
return n
}
@ -1722,7 +1856,7 @@ func (m *Proposal) Size() (n int) {
}
l = m.FinalTallyResult.Size()
n += 1 + l + sovTypes(uint64(l))
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.Timeout)
l = github_com_gogo_protobuf_types.SizeOfStdTime(m.VotingPeriodEnd)
n += 1 + l + sovTypes(uint64(l))
if m.ExecutorResult != 0 {
n += 1 + sovTypes(uint64(m.ExecutorResult))
@ -2118,7 +2252,7 @@ func (m *ThresholdDecisionPolicy) Unmarshal(dAtA []byte) error {
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Timeout", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field Windows", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
@ -2145,7 +2279,10 @@ func (m *ThresholdDecisionPolicy) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.Timeout, dAtA[iNdEx:postIndex]); err != nil {
if m.Windows == nil {
m.Windows = &DecisionPolicyWindows{}
}
if err := m.Windows.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -2233,7 +2370,7 @@ func (m *PercentageDecisionPolicy) Unmarshal(dAtA []byte) error {
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Timeout", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field Windows", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
@ -2260,7 +2397,126 @@ func (m *PercentageDecisionPolicy) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.Timeout, dAtA[iNdEx:postIndex]); err != nil {
if m.Windows == nil {
m.Windows = &DecisionPolicyWindows{}
}
if err := m.Windows.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipTypes(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *DecisionPolicyWindows) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: DecisionPolicyWindows: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: DecisionPolicyWindows: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field VotingPeriod", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthTypes
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthTypes
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.VotingPeriod, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field MinExecutionPeriod", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthTypes
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthTypes
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.MinExecutionPeriod, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
@ -3148,7 +3404,7 @@ func (m *Proposal) Unmarshal(dAtA []byte) error {
iNdEx = postIndex
case 11:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Timeout", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field VotingPeriodEnd", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
@ -3175,7 +3431,7 @@ func (m *Proposal) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.Timeout, dAtA[iNdEx:postIndex]); err != nil {
if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.VotingPeriodEnd, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex

View File

@ -9,6 +9,105 @@ import (
"github.com/stretchr/testify/require"
)
func TestThresholdDecisionPolicyValidate(t *testing.T) {
g := group.GroupInfo{
TotalWeight: "10",
}
config := group.DefaultConfig()
testCases := []struct {
name string
policy group.ThresholdDecisionPolicy
expErr bool
}{
{
"threshold bigger than total weight",
group.ThresholdDecisionPolicy{
Threshold: "12",
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second,
},
},
true,
},
{
"min exec period too big",
group.ThresholdDecisionPolicy{
Threshold: "5",
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second,
MinExecutionPeriod: time.Hour * 24 * 30,
},
},
true,
},
{
"all good",
group.ThresholdDecisionPolicy{
Threshold: "5",
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Hour,
MinExecutionPeriod: time.Hour * 24,
},
},
false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := tc.policy.Validate(g, config)
if tc.expErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
})
}
}
func TestPercentageDecisionPolicyValidate(t *testing.T) {
g := group.GroupInfo{}
config := group.DefaultConfig()
testCases := []struct {
name string
policy group.PercentageDecisionPolicy
expErr bool
}{
{
"min exec period too big",
group.PercentageDecisionPolicy{
Percentage: "0.5",
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second,
MinExecutionPeriod: time.Hour * 24 * 30,
},
},
true,
},
{
"all good",
group.PercentageDecisionPolicy{
Percentage: "0.5",
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Hour,
MinExecutionPeriod: time.Hour * 24,
},
},
false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := tc.policy.Validate(g, config)
if tc.expErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
})
}
}
func TestPercentageDecisionPolicyAllow(t *testing.T) {
testCases := []struct {
name string
@ -17,12 +116,15 @@ func TestPercentageDecisionPolicyAllow(t *testing.T) {
totalPower string
votingDuration time.Duration
result group.DecisionPolicyResult
expErr bool
}{
{
"YesCount percentage > decision policy percentage",
&group.PercentageDecisionPolicy{
Percentage: "0.5",
Timeout: time.Second * 100,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * 100,
},
},
&group.TallyResult{
YesCount: "2",
@ -36,12 +138,15 @@ func TestPercentageDecisionPolicyAllow(t *testing.T) {
Allow: true,
Final: true,
},
false,
},
{
"YesCount percentage == decision policy percentage",
&group.PercentageDecisionPolicy{
Percentage: "0.5",
Timeout: time.Second * 100,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * 100,
},
},
&group.TallyResult{
YesCount: "2",
@ -55,12 +160,15 @@ func TestPercentageDecisionPolicyAllow(t *testing.T) {
Allow: true,
Final: true,
},
false,
},
{
"YesCount percentage < decision policy percentage",
&group.PercentageDecisionPolicy{
Percentage: "0.5",
Timeout: time.Second * 100,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * 100,
},
},
&group.TallyResult{
YesCount: "1",
@ -74,12 +182,15 @@ func TestPercentageDecisionPolicyAllow(t *testing.T) {
Allow: false,
Final: false,
},
false,
},
{
"sum percentage (YesCount + undecided votes percentage) < decision policy percentage",
&group.PercentageDecisionPolicy{
Percentage: "0.5",
Timeout: time.Second * 100,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * 100,
},
},
&group.TallyResult{
YesCount: "1",
@ -93,12 +204,15 @@ func TestPercentageDecisionPolicyAllow(t *testing.T) {
Allow: false,
Final: true,
},
false,
},
{
"sum percentage = decision policy percentage",
&group.PercentageDecisionPolicy{
Percentage: "0.5",
Timeout: time.Second * 100,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * 100,
},
},
&group.TallyResult{
YesCount: "1",
@ -112,12 +226,15 @@ func TestPercentageDecisionPolicyAllow(t *testing.T) {
Allow: false,
Final: false,
},
false,
},
{
"sum percentage > decision policy percentage",
&group.PercentageDecisionPolicy{
Percentage: "0.5",
Timeout: time.Second * 100,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * 100,
},
},
&group.TallyResult{
YesCount: "1",
@ -131,12 +248,16 @@ func TestPercentageDecisionPolicyAllow(t *testing.T) {
Allow: false,
Final: false,
},
false,
},
{
"decision policy timeout <= voting duration",
"time since submission < min execution period",
&group.PercentageDecisionPolicy{
Percentage: "0.5",
Timeout: time.Second * 10,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * 10,
MinExecutionPeriod: time.Minute,
},
},
&group.TallyResult{
YesCount: "2",
@ -146,17 +267,19 @@ func TestPercentageDecisionPolicyAllow(t *testing.T) {
},
"3",
time.Duration(time.Second * 50),
group.DecisionPolicyResult{
Allow: false,
Final: true,
},
group.DecisionPolicyResult{},
true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
policyResult, err := tc.policy.Allow(*tc.tally, tc.totalPower, tc.votingDuration)
require.NoError(t, err)
require.Equal(t, tc.result, policyResult)
if tc.expErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, tc.result, policyResult)
}
})
}
}
@ -169,12 +292,15 @@ func TestThresholdDecisionPolicyAllow(t *testing.T) {
totalPower string
votingDuration time.Duration
result group.DecisionPolicyResult
expErr bool
}{
{
"YesCount >= threshold decision policy",
&group.ThresholdDecisionPolicy{
Threshold: "3",
Timeout: time.Second * 100,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * 100,
},
},
&group.TallyResult{
YesCount: "3",
@ -188,12 +314,15 @@ func TestThresholdDecisionPolicyAllow(t *testing.T) {
Allow: true,
Final: true,
},
false,
},
{
"YesCount < threshold decision policy",
&group.ThresholdDecisionPolicy{
Threshold: "3",
Timeout: time.Second * 100,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * 100,
},
},
&group.TallyResult{
YesCount: "1",
@ -207,12 +336,15 @@ func TestThresholdDecisionPolicyAllow(t *testing.T) {
Allow: false,
Final: false,
},
false,
},
{
"sum votes < threshold decision policy",
&group.ThresholdDecisionPolicy{
Threshold: "3",
Timeout: time.Second * 100,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * 100,
},
},
&group.TallyResult{
YesCount: "1",
@ -226,12 +358,15 @@ func TestThresholdDecisionPolicyAllow(t *testing.T) {
Allow: false,
Final: true,
},
false,
},
{
"sum votes >= threshold decision policy",
&group.ThresholdDecisionPolicy{
Threshold: "3",
Timeout: time.Second * 100,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * 100,
},
},
&group.TallyResult{
YesCount: "1",
@ -245,12 +380,16 @@ func TestThresholdDecisionPolicyAllow(t *testing.T) {
Allow: false,
Final: false,
},
false,
},
{
"decision policy timeout <= voting duration",
"time since submission < min execution period",
&group.ThresholdDecisionPolicy{
Threshold: "3",
Timeout: time.Second * 10,
Windows: &group.DecisionPolicyWindows{
VotingPeriod: time.Second * 10,
MinExecutionPeriod: time.Minute,
},
},
&group.TallyResult{
YesCount: "3",
@ -264,13 +403,18 @@ func TestThresholdDecisionPolicyAllow(t *testing.T) {
Allow: false,
Final: true,
},
true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
policyResult, err := tc.policy.Allow(*tc.tally, tc.totalPower, tc.votingDuration)
require.NoError(t, err)
require.Equal(t, tc.result, policyResult)
if tc.expErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, tc.result, policyResult)
}
})
}
}