x/gov: gRPC query Service (#6491)

* WIP: adding gRPC for gov

* removed passing new store

* fixed error

* added register query service in module

* order of imports changed

* order of imports changed

* Fix proto file

* added get all proposals grpc

* added more tests

* added doc in tests

* added grpc for votes

* Added grpc for Deposits

* updated protos

* added grpc for proposal, vote, deposit, tally

* WIP: adding params grpc

* added params in gRPC

* updated error messages

* fixed error check

* added more tests

* updated tests

* added yaml types

* review changes and lint issues

* updated tests

* code cleanup

* removed cosmos.gov prefixes

* added more checks

* added more test checks

* added filtered pagination

* removed test check

* added tests for filtered pagination

* Fix Proposals

* lint

* fixed error in tests

* lint issues

* Add nil check for params

* Added unpacker

* removed casttypes

* review changes

* use suite in grpc query tests

* migrated tests to use suite

* fix non-determinism

* tests migrated to table driven tests

* fixed doc typo

* revert change

* Merge branch 'master' of github.com:cosmos/cosmos-sdk into atheesh/5921-grpc-x-gov

* review changes

* review changes

* review changes

* review change

* review changes

* docs updated

* review change

* review changes

* review changes

* review changes

* Update x/gov/keeper/keeper_test.go

Co-authored-by: sahith-narahari <sahithnarahari@gmail.com>
Co-authored-by: Anil Kumar Kammari <anil@vitwit.com>
Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
atheeshp 2020-07-16 14:46:23 +05:30 committed by GitHub
parent ab162a6d38
commit 28269908d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 6003 additions and 98 deletions

View File

@ -6,6 +6,7 @@ import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types";
option (gogoproto.goproto_stringer_all) = false;
@ -160,3 +161,57 @@ message Vote {
bytes voter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
VoteOption option = 3;
}
// DepositParams defines the params around deposits for governance
message DepositParams {
// Minimum deposit for a proposal to enter voting period.
repeated cosmos.Coin min_deposit = 1 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.moretags) = "yaml:\"min_deposit\"",
(gogoproto.jsontag) = "min_deposit,omitempty"
];
// Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months.
google.protobuf.Duration max_deposit_period = 2 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.jsontag) = "max_deposit_period,omitempty",
(gogoproto.moretags) = "yaml:\"max_deposit_period\""
];
}
// VotingParams defines the params around Voting in governance
message VotingParams {
// Length of the voting period.
google.protobuf.Duration voting_period = 1 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.jsontag) = "voting_period,omitempty",
(gogoproto.moretags) = "yaml:\"voting_period\""
];
}
// TallyParams defines the params around Tallying votes in governance
message TallyParams {
// Minimum percentage of total stake needed to vote for a result to be considered valid.
bytes quorum = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "quorum,omitempty"
];
// Minimum proportion of Yes votes for proposal to pass. Initial value: 0.5.
bytes threshold = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "threshold,omitempty"
];
// Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3.
bytes veto = 3 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "veto,omitempty"
];
}

View File

@ -0,0 +1,148 @@
syntax = "proto3";
package cosmos.gov;
import "cosmos/query/pagination.proto";
import "gogoproto/gogo.proto";
import "cosmos/gov/gov.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/gov/types";
// Query defines the gRPC querier service for gov module
service Query {
// Proposal queries proposal details based on ProposalID
rpc Proposal (QueryProposalRequest) returns (QueryProposalResponse) {}
// Proposals queries all proposals based on given status
rpc Proposals (QueryProposalsRequest) returns (QueryProposalsResponse) {}
// Vote queries Voted information based on proposalID, voterAddr
rpc Vote(QueryVoteRequest) returns (QueryVoteResponse) {}
// Votes queries votes of a given proposal
rpc Votes (QueryVotesRequest) returns (QueryVotesResponse) {}
// Params queries all params
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {}
// Deposit queries single deposit information based proposalID, depositAddr
rpc Deposit(QueryDepositRequest) returns (QueryDepositResponse) {}
// Deposits queries all deposits of a single proposal
rpc Deposits(QueryDepositsRequest) returns (QueryDepositsResponse) {}
// TallyResult queries the tally of a proposal vote
rpc TallyResult(QueryTallyResultRequest) returns (QueryTallyResultResponse) {}
}
// QueryProposalRequest is the request type for the Query/Proposal RPC method
message QueryProposalRequest {
// unique id of the proposal
uint64 proposal_id = 1;
}
// QueryProposalResponse is the response type for the Query/Proposal RPC method
message QueryProposalResponse {
Proposal proposal = 1 [(gogoproto.nullable) = false];
}
// QueryProposalsRequest is the request type for the Query/Proposals RPC method
message QueryProposalsRequest {
// status of the proposals.
ProposalStatus proposal_status = 1 ;
// Voter address for the proposals.
bytes voter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
// Deposit addresses from the proposals.
bytes depositor = 3 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
cosmos.query.PageRequest req = 4;
}
// QueryProposalsResponse is the response type for the Query/Proposals RPC method
message QueryProposalsResponse {
repeated Proposal proposals = 1 [(gogoproto.nullable) = false];
cosmos.query.PageResponse res = 2;
}
// QueryVoteRequest is the request type for the Query/Vote RPC method
message QueryVoteRequest {
// unique id of the proposal
uint64 proposal_id = 1;
// Voter address for the proposals.
bytes voter = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
}
// QueryVoteResponse is the response type for the Query/Vote RPC method
message QueryVoteResponse {
Vote vote = 1 [(gogoproto.nullable) = false];
}
// QueryVotesRequest is the request type for the Query/Votes RPC method
message QueryVotesRequest {
// unique id of the proposal
uint64 proposal_id = 1;
cosmos.query.PageRequest req = 2;
}
// QueryVotesResponse is the response type for the Query/Votes RPC method
message QueryVotesResponse {
repeated Vote votes = 1 [(gogoproto.nullable) = false];
cosmos.query.PageResponse res = 2;
}
// QueryParamsRequest is the request type for the Query/Params RPC method
message QueryParamsRequest {
string params_type = 1;
}
// QueryParamsResponse is the response type for the Query/Params RPC method
message QueryParamsResponse {
VotingParams voting_params = 1 [(gogoproto.nullable) = false];
DepositParams deposit_params = 2 [(gogoproto.nullable) = false];
TallyParams tally_params = 3 [(gogoproto.nullable) = false];
}
// QueryDepositRequest is the request type for the Query/Deposit RPC method
message QueryDepositRequest {
// unique id of the proposal
uint64 proposal_id = 1;
// Deposit addresses from the proposals.
bytes depositor = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
}
// QueryDepositResponse is the response type for the Query/Deposit RPC method
message QueryDepositResponse {
Deposit deposit = 1 [(gogoproto.nullable) = false];
}
// QueryDepositsRequest is the request type for the Query/Deposits RPC method
message QueryDepositsRequest {
// unique id of the proposal
uint64 proposal_id = 1;
cosmos.query.PageRequest req = 2;
}
// QueryDepositsResponse is the response type for the Query/Deposits RPC method
message QueryDepositsResponse {
repeated Deposit deposits = 1 [(gogoproto.nullable) = false];
cosmos.query.PageResponse res = 2;
}
// QueryTallyResultRequest is the request type for the Query/Tally RPC method
message QueryTallyResultRequest {
// unique id of the proposal
uint64 proposal_id = 1;
}
// QueryTallyResultResponse is the response type for the Query/Tally RPC method
message QueryTallyResultResponse {
TallyResult tally = 1 [(gogoproto.nullable) = false];
}

260
x/gov/keeper/grpc_query.go Normal file
View File

@ -0,0 +1,260 @@
package keeper
import (
"context"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/x/gov/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var _ types.QueryServer = Keeper{}
// Proposal returns proposal details based on ProposalID
func (q Keeper) Proposal(c context.Context, req *types.QueryProposalRequest) (*types.QueryProposalResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
if req.ProposalId == 0 {
return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0")
}
ctx := sdk.UnwrapSDKContext(c)
proposal, found := q.GetProposal(ctx, req.ProposalId)
if !found {
return nil, status.Errorf(codes.NotFound, "proposal %d doesn't exist", req.ProposalId)
}
return &types.QueryProposalResponse{Proposal: proposal}, nil
}
// Proposals implements the Query/Proposals gRPC method
func (q Keeper) Proposals(c context.Context, req *types.QueryProposalsRequest) (*types.QueryProposalsResponse, error) {
var filteredProposals types.Proposals
ctx := sdk.UnwrapSDKContext(c)
store := ctx.KVStore(q.storeKey)
proposalStore := prefix.NewStore(store, types.ProposalsKeyPrefix)
res, err := query.FilteredPaginate(proposalStore, req.Req, func(key []byte, value []byte, accumulate bool) (bool, error) {
var p types.Proposal
if err := q.cdc.UnmarshalBinaryBare(value, &p); err != nil {
return false, status.Error(codes.Internal, err.Error())
}
matchVoter, matchDepositor, matchStatus := true, true, true
// match status (if supplied/valid)
if types.ValidProposalStatus(req.ProposalStatus) {
matchStatus = p.Status == req.ProposalStatus
}
// match voter address (if supplied)
if len(req.Voter) > 0 {
_, matchVoter = q.GetVote(ctx, p.ProposalID, req.Voter)
}
// match depositor (if supplied)
if len(req.Depositor) > 0 {
_, matchDepositor = q.GetDeposit(ctx, p.ProposalID, req.Depositor)
}
if matchVoter && matchDepositor && matchStatus {
if accumulate {
filteredProposals = append(filteredProposals, p)
}
return true, nil
}
return false, nil
})
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &types.QueryProposalsResponse{Proposals: filteredProposals, Res: res}, nil
}
// Vote returns Voted information based on proposalID, voterAddr
func (q Keeper) Vote(c context.Context, req *types.QueryVoteRequest) (*types.QueryVoteResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
if req.ProposalId == 0 {
return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0")
}
if req.Voter == nil {
return nil, status.Error(codes.InvalidArgument, "empty voter address")
}
ctx := sdk.UnwrapSDKContext(c)
vote, found := q.GetVote(ctx, req.ProposalId, req.Voter)
if !found {
return nil, status.Errorf(codes.InvalidArgument,
"voter: %v not found for proposal: %v", req.Voter, req.ProposalId)
}
return &types.QueryVoteResponse{Vote: vote}, nil
}
// Votes returns single proposal's votes
func (q Keeper) Votes(c context.Context, req *types.QueryVotesRequest) (*types.QueryVotesResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
if req.ProposalId == 0 {
return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0")
}
var votes types.Votes
ctx := sdk.UnwrapSDKContext(c)
store := ctx.KVStore(q.storeKey)
votesStore := prefix.NewStore(store, types.VotesKey(req.ProposalId))
res, err := query.Paginate(votesStore, req.Req, func(key []byte, value []byte) error {
var vote types.Vote
if err := q.cdc.UnmarshalBinaryBare(value, &vote); err != nil {
return err
}
votes = append(votes, vote)
return nil
})
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &types.QueryVotesResponse{Votes: votes, Res: res}, nil
}
// Params queries all params
func (q Keeper) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
ctx := sdk.UnwrapSDKContext(c)
switch req.ParamsType {
case types.ParamDeposit:
depositParmas := q.GetDepositParams(ctx)
return &types.QueryParamsResponse{DepositParams: depositParmas}, nil
case types.ParamVoting:
votingParmas := q.GetVotingParams(ctx)
return &types.QueryParamsResponse{VotingParams: votingParmas}, nil
case types.ParamTallying:
tallyParams := q.GetTallyParams(ctx)
return &types.QueryParamsResponse{TallyParams: tallyParams}, nil
default:
return nil, status.Errorf(codes.InvalidArgument,
"%s is not a valid parameter type", req.ParamsType)
}
}
// Deposit queries single deposit information based proposalID, depositAddr
func (q Keeper) Deposit(c context.Context, req *types.QueryDepositRequest) (*types.QueryDepositResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
if req.ProposalId == 0 {
return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0")
}
if req.Depositor == nil {
return nil, status.Error(codes.InvalidArgument, "empty depositor address")
}
ctx := sdk.UnwrapSDKContext(c)
deposit, found := q.GetDeposit(ctx, req.ProposalId, req.Depositor)
if !found {
return nil, status.Errorf(codes.InvalidArgument,
"depositer: %v not found for proposal: %v", req.Depositor, req.ProposalId)
}
return &types.QueryDepositResponse{Deposit: deposit}, nil
}
// Deposits returns single proposal's all deposits
func (q Keeper) Deposits(c context.Context, req *types.QueryDepositsRequest) (*types.QueryDepositsResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
if req.ProposalId == 0 {
return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0")
}
var deposits types.Deposits
ctx := sdk.UnwrapSDKContext(c)
store := ctx.KVStore(q.storeKey)
depositStore := prefix.NewStore(store, types.DepositsKey(req.ProposalId))
res, err := query.Paginate(depositStore, req.Req, func(key []byte, value []byte) error {
var deposit types.Deposit
if err := q.cdc.UnmarshalBinaryBare(value, &deposit); err != nil {
return err
}
deposits = append(deposits, deposit)
return nil
})
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &types.QueryDepositsResponse{Deposits: deposits, Res: res}, nil
}
// TallyResult queries the tally of a proposal vote
func (q Keeper) TallyResult(c context.Context, req *types.QueryTallyResultRequest) (*types.QueryTallyResultResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
if req.ProposalId == 0 {
return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0")
}
ctx := sdk.UnwrapSDKContext(c)
proposal, ok := q.GetProposal(ctx, req.ProposalId)
if !ok {
return nil, status.Errorf(codes.NotFound, "proposal %d doesn't exist", req.ProposalId)
}
var tallyResult types.TallyResult
switch {
case proposal.Status == types.StatusDepositPeriod:
tallyResult = types.EmptyTallyResult()
case proposal.Status == types.StatusPassed || proposal.Status == types.StatusRejected:
tallyResult = proposal.FinalTallyResult
default:
// proposal is in voting period
_, _, tallyResult = q.Tally(ctx, proposal)
}
return &types.QueryTallyResultResponse{Tally: tallyResult}, nil
}

View File

@ -0,0 +1,815 @@
package keeper_test
import (
gocontext "context"
"fmt"
"strconv"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/x/gov/types"
)
func (suite *KeeperTestSuite) TestGRPCQueryProposal() {
app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient
var (
req *types.QueryProposalRequest
expProposal types.Proposal
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"empty request",
func() {
req = &types.QueryProposalRequest{}
},
false,
},
{
"non existing proposal request",
func() {
req = &types.QueryProposalRequest{ProposalId: 3}
},
false,
},
{
"zero proposal id request",
func() {
req = &types.QueryProposalRequest{ProposalId: 0}
},
false,
},
{
"valid request",
func() {
req = &types.QueryProposalRequest{ProposalId: 1}
testProposal := types.NewTextProposal("Proposal", "testing proposal")
submittedProposal, err := app.GovKeeper.SubmitProposal(ctx, testProposal)
suite.Require().NoError(err)
suite.Require().NotEmpty(submittedProposal)
expProposal = submittedProposal
},
true,
},
}
for _, testCase := range testCases {
suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() {
testCase.malleate()
proposalRes, err := queryClient.Proposal(gocontext.Background(), req)
if testCase.expPass {
suite.Require().NoError(err)
suite.Require().Equal(expProposal.String(), proposalRes.Proposal.String())
} else {
suite.Require().Error(err)
suite.Require().Nil(proposalRes)
}
})
}
}
func (suite *KeeperTestSuite) TestGRPCQueryProposals() {
app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.queryClient, suite.addrs
testProposals := []types.Proposal{}
var (
req *types.QueryProposalsRequest
expRes *types.QueryProposalsResponse
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"empty state request",
func() {
req = &types.QueryProposalsRequest{}
},
true,
},
{
"request proposals with limit 3",
func() {
// create 5 test proposals
for i := 0; i < 5; i++ {
num := strconv.Itoa(i + 1)
testProposal := types.NewTextProposal("Proposal"+num, "testing proposal "+num)
proposal, err := app.GovKeeper.SubmitProposal(ctx, testProposal)
suite.Require().NotEmpty(proposal)
suite.Require().NoError(err)
testProposals = append(testProposals, proposal)
}
req = &types.QueryProposalsRequest{
Req: &query.PageRequest{Limit: 3},
}
expRes = &types.QueryProposalsResponse{
Proposals: testProposals[:3],
}
},
true,
},
{
"request 2nd page with limit 4",
func() {
req = &types.QueryProposalsRequest{
Req: &query.PageRequest{Offset: 3, Limit: 3},
}
expRes = &types.QueryProposalsResponse{
Proposals: testProposals[3:],
}
},
true,
},
{
"request with limit 2 and count true",
func() {
req = &types.QueryProposalsRequest{
Req: &query.PageRequest{Limit: 2, CountTotal: true},
}
expRes = &types.QueryProposalsResponse{
Proposals: testProposals[:2],
}
},
true,
},
{
"request with filter of status deposit period",
func() {
req = &types.QueryProposalsRequest{
ProposalStatus: types.StatusDepositPeriod,
}
expRes = &types.QueryProposalsResponse{
Proposals: testProposals,
}
},
true,
},
{
"request with filter of deposit address",
func() {
depositCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(20)))
deposit := types.NewDeposit(testProposals[0].ProposalID, addrs[0], depositCoins)
app.GovKeeper.SetDeposit(ctx, deposit)
req = &types.QueryProposalsRequest{
Depositor: addrs[0],
}
expRes = &types.QueryProposalsResponse{
Proposals: testProposals[:1],
}
},
true,
},
{
"request with filter of deposit address",
func() {
testProposals[1].Status = types.StatusVotingPeriod
app.GovKeeper.SetProposal(ctx, testProposals[1])
suite.Require().NoError(app.GovKeeper.AddVote(ctx, testProposals[1].ProposalID, addrs[0], types.OptionAbstain))
req = &types.QueryProposalsRequest{
Voter: addrs[0],
}
expRes = &types.QueryProposalsResponse{
Proposals: testProposals[1:2],
}
},
true,
},
}
for _, testCase := range testCases {
suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() {
testCase.malleate()
proposals, err := queryClient.Proposals(gocontext.Background(), req)
if testCase.expPass {
suite.Require().NoError(err)
suite.Require().Len(proposals.GetProposals(), len(expRes.GetProposals()))
for i := 0; i < len(proposals.GetProposals()); i++ {
suite.Require().Equal(proposals.GetProposals()[i].String(), expRes.GetProposals()[i].String())
}
} else {
suite.Require().Error(err)
suite.Require().Nil(proposals)
}
})
}
}
func (suite *KeeperTestSuite) TestGRPCQueryVote() {
app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.queryClient, suite.addrs
var (
req *types.QueryVoteRequest
expRes *types.QueryVoteResponse
proposal types.Proposal
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"empty request",
func() {
req = &types.QueryVoteRequest{}
},
false,
},
{
"zero proposal id request",
func() {
req = &types.QueryVoteRequest{
ProposalId: 0,
Voter: addrs[0],
}
},
false,
},
{
"empty voter request",
func() {
req = &types.QueryVoteRequest{
ProposalId: 1,
Voter: nil,
}
},
false,
},
{
"non existed proposal",
func() {
req = &types.QueryVoteRequest{
ProposalId: 3,
Voter: addrs[0],
}
},
false,
},
{
"no votes present",
func() {
var err error
proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal)
suite.Require().NoError(err)
req = &types.QueryVoteRequest{
ProposalId: proposal.ProposalID,
Voter: addrs[0],
}
expRes = &types.QueryVoteResponse{}
},
false,
},
{
"valid request",
func() {
proposal.Status = types.StatusVotingPeriod
app.GovKeeper.SetProposal(ctx, proposal)
suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalID, addrs[0], types.OptionAbstain))
req = &types.QueryVoteRequest{
ProposalId: proposal.ProposalID,
Voter: addrs[0],
}
expRes = &types.QueryVoteResponse{Vote: types.NewVote(proposal.ProposalID, addrs[0], types.OptionAbstain)}
},
true,
},
{
"wrong voter id request",
func() {
req = &types.QueryVoteRequest{
ProposalId: proposal.ProposalID,
Voter: addrs[1],
}
expRes = &types.QueryVoteResponse{}
},
false,
},
}
for _, testCase := range testCases {
suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() {
testCase.malleate()
vote, err := queryClient.Vote(gocontext.Background(), req)
if testCase.expPass {
suite.Require().NoError(err)
suite.Require().Equal(expRes, vote)
} else {
suite.Require().Error(err)
suite.Require().Nil(vote)
}
})
}
}
func (suite *KeeperTestSuite) TestGRPCQueryVotes() {
app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient
addrs := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(30000000))
var (
req *types.QueryVotesRequest
expRes *types.QueryVotesResponse
proposal types.Proposal
votes types.Votes
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"empty request",
func() {
req = &types.QueryVotesRequest{}
},
false,
},
{
"zero proposal id request",
func() {
req = &types.QueryVotesRequest{
ProposalId: 0,
}
},
false,
},
{
"non existed proposals",
func() {
req = &types.QueryVotesRequest{
ProposalId: 2,
}
},
true,
},
{
"create a proposal and get votes",
func() {
var err error
proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal)
suite.Require().NoError(err)
req = &types.QueryVotesRequest{
ProposalId: proposal.ProposalID,
}
},
true,
},
{
"request after adding 2 votes",
func() {
proposal.Status = types.StatusVotingPeriod
app.GovKeeper.SetProposal(ctx, proposal)
votes = []types.Vote{
{proposal.ProposalID, addrs[0], types.OptionAbstain},
{proposal.ProposalID, addrs[1], types.OptionYes},
}
suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalID, votes[0].Voter, votes[0].Option))
suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalID, votes[1].Voter, votes[1].Option))
req = &types.QueryVotesRequest{
ProposalId: proposal.ProposalID,
}
expRes = &types.QueryVotesResponse{
Votes: votes,
}
},
true,
},
}
for _, testCase := range testCases {
suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() {
testCase.malleate()
votes, err := queryClient.Votes(gocontext.Background(), req)
if testCase.expPass {
suite.Require().NoError(err)
suite.Require().Equal(expRes.GetVotes(), votes.GetVotes())
} else {
suite.Require().Error(err)
suite.Require().Nil(votes)
}
})
}
}
func (suite *KeeperTestSuite) TestGRPCQueryParams() {
queryClient := suite.queryClient
var (
req *types.QueryParamsRequest
expRes *types.QueryParamsResponse
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"empty request",
func() {
req = &types.QueryParamsRequest{}
},
false,
},
{
"deposit params request",
func() {
req = &types.QueryParamsRequest{ParamsType: types.ParamDeposit}
expRes = &types.QueryParamsResponse{
DepositParams: types.DefaultDepositParams(),
TallyParams: types.NewTallyParams(sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0)),
}
},
true,
},
{
"voting params request",
func() {
req = &types.QueryParamsRequest{ParamsType: types.ParamVoting}
expRes = &types.QueryParamsResponse{
VotingParams: types.DefaultVotingParams(),
TallyParams: types.NewTallyParams(sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0)),
}
},
true,
},
{
"tally params request",
func() {
req = &types.QueryParamsRequest{ParamsType: types.ParamTallying}
expRes = &types.QueryParamsResponse{
TallyParams: types.DefaultTallyParams(),
}
},
true,
},
{
"invalid request",
func() {
req = &types.QueryParamsRequest{ParamsType: "wrongPath"}
expRes = &types.QueryParamsResponse{}
},
false,
},
}
for _, testCase := range testCases {
suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() {
testCase.malleate()
params, err := queryClient.Params(gocontext.Background(), req)
if testCase.expPass {
suite.Require().NoError(err)
suite.Require().Equal(expRes.GetDepositParams(), params.GetDepositParams())
suite.Require().Equal(expRes.GetVotingParams(), params.GetVotingParams())
suite.Require().Equal(expRes.GetTallyParams(), params.GetTallyParams())
} else {
suite.Require().Error(err)
suite.Require().Nil(params)
}
})
}
}
func (suite *KeeperTestSuite) TestGRPCQueryDeposit() {
app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.queryClient, suite.addrs
var (
req *types.QueryDepositRequest
expRes *types.QueryDepositResponse
proposal types.Proposal
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"empty request",
func() {
req = &types.QueryDepositRequest{}
},
false,
},
{
"zero proposal id request",
func() {
req = &types.QueryDepositRequest{
ProposalId: 0,
Depositor: addrs[0],
}
},
false,
},
{
"empty deposit address request",
func() {
req = &types.QueryDepositRequest{
ProposalId: 1,
Depositor: nil,
}
},
false,
},
{
"non existed proposal",
func() {
req = &types.QueryDepositRequest{
ProposalId: 2,
Depositor: addrs[0],
}
},
false,
},
{
"no deposits proposal",
func() {
var err error
proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal)
suite.Require().NoError(err)
suite.Require().NotNil(proposal)
req = &types.QueryDepositRequest{
ProposalId: proposal.ProposalID,
Depositor: addrs[0],
}
},
false,
},
{
"valid request",
func() {
depositCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(20)))
deposit := types.NewDeposit(proposal.ProposalID, addrs[0], depositCoins)
app.GovKeeper.SetDeposit(ctx, deposit)
req = &types.QueryDepositRequest{
ProposalId: proposal.ProposalID,
Depositor: addrs[0],
}
expRes = &types.QueryDepositResponse{Deposit: deposit}
},
true,
},
}
for _, testCase := range testCases {
suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() {
testCase.malleate()
deposit, err := queryClient.Deposit(gocontext.Background(), req)
if testCase.expPass {
suite.Require().NoError(err)
suite.Require().Equal(deposit.GetDeposit(), expRes.GetDeposit())
} else {
suite.Require().Error(err)
suite.Require().Nil(expRes)
}
})
}
}
func (suite *KeeperTestSuite) TestGRPCQueryDeposits() {
app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.queryClient, suite.addrs
var (
req *types.QueryDepositsRequest
expRes *types.QueryDepositsResponse
proposal types.Proposal
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"empty request",
func() {
req = &types.QueryDepositsRequest{}
},
false,
},
{
"zero proposal id request",
func() {
req = &types.QueryDepositsRequest{
ProposalId: 0,
}
},
false,
},
{
"non existed proposal",
func() {
req = &types.QueryDepositsRequest{
ProposalId: 2,
}
},
true,
},
{
"create a proposal and get deposits",
func() {
var err error
proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal)
suite.Require().NoError(err)
req = &types.QueryDepositsRequest{
ProposalId: proposal.ProposalID,
}
},
true,
},
{
"get deposits with default limit",
func() {
depositAmount1 := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(20)))
deposit1 := types.NewDeposit(proposal.ProposalID, addrs[0], depositAmount1)
app.GovKeeper.SetDeposit(ctx, deposit1)
depositAmount2 := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(30)))
deposit2 := types.NewDeposit(proposal.ProposalID, addrs[1], depositAmount2)
app.GovKeeper.SetDeposit(ctx, deposit2)
deposits := types.Deposits{deposit1, deposit2}
req = &types.QueryDepositsRequest{
ProposalId: proposal.ProposalID,
}
expRes = &types.QueryDepositsResponse{
Deposits: deposits,
}
},
true,
},
}
for _, testCase := range testCases {
suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() {
testCase.malleate()
deposits, err := queryClient.Deposits(gocontext.Background(), req)
if testCase.expPass {
suite.Require().NoError(err)
suite.Require().Equal(expRes.GetDeposits(), deposits.GetDeposits())
} else {
suite.Require().Error(err)
suite.Require().Nil(deposits)
}
})
}
}
func (suite *KeeperTestSuite) TestGRPCQueryTally() {
app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient
addrs, _ := createValidators(ctx, app, []int64{5, 5, 5})
var (
req *types.QueryTallyResultRequest
expRes *types.QueryTallyResultResponse
proposal types.Proposal
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"empty request",
func() {
req = &types.QueryTallyResultRequest{}
},
false,
},
{
"zero proposal id request",
func() {
req = &types.QueryTallyResultRequest{ProposalId: 0}
},
false,
},
{
"query non existed proposal",
func() {
req = &types.QueryTallyResultRequest{ProposalId: 1}
},
false,
},
{
"create a proposal and get tally",
func() {
var err error
proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal)
suite.Require().NoError(err)
suite.Require().NotNil(proposal)
req = &types.QueryTallyResultRequest{ProposalId: proposal.ProposalID}
expRes = &types.QueryTallyResultResponse{
Tally: types.EmptyTallyResult(),
}
},
true,
},
{
"request tally after few votes",
func() {
proposal.Status = types.StatusVotingPeriod
app.GovKeeper.SetProposal(ctx, proposal)
suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalID, addrs[0], types.OptionYes))
suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalID, addrs[1], types.OptionYes))
suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalID, addrs[2], types.OptionYes))
req = &types.QueryTallyResultRequest{ProposalId: proposal.ProposalID}
expRes = &types.QueryTallyResultResponse{
Tally: types.TallyResult{
Yes: sdk.NewInt(3 * 5 * 1000000),
},
}
},
true,
},
{
"request final tally after status changed",
func() {
proposal.Status = types.StatusPassed
app.GovKeeper.SetProposal(ctx, proposal)
proposal, _ = app.GovKeeper.GetProposal(ctx, proposal.ProposalID)
req = &types.QueryTallyResultRequest{ProposalId: proposal.ProposalID}
expRes = &types.QueryTallyResultResponse{
Tally: proposal.FinalTallyResult,
}
},
true,
},
}
for _, testCase := range testCases {
suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() {
testCase.malleate()
tally, err := queryClient.TallyResult(gocontext.Background(), req)
if testCase.expPass {
suite.Require().NoError(err)
suite.Require().Equal(expRes.String(), tally.String())
} else {
suite.Require().Error(err)
suite.Require().Nil(tally)
}
})
}
}

View File

@ -4,12 +4,38 @@ import (
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/gov/types"
)
type KeeperTestSuite struct {
suite.Suite
app *simapp.SimApp
ctx sdk.Context
queryClient types.QueryClient
addrs []sdk.AccAddress
}
func (suite *KeeperTestSuite) SetupTest() {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, abci.Header{})
queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, app.GovKeeper)
queryClient := types.NewQueryClient(queryHelper)
suite.app = app
suite.ctx = ctx
suite.queryClient = queryClient
suite.addrs = simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(30000000))
}
func TestIncrementProposalNumber(t *testing.T) {
app := simapp.Setup(false)
ctx := app.BaseApp.NewContext(false, abci.Header{})
@ -60,3 +86,7 @@ func TestProposalQueues(t *testing.T) {
activeIterator.Close()
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}

View File

@ -150,7 +150,9 @@ func (am AppModule) NewQuerierHandler() sdk.Querier {
return keeper.NewQuerier(am.keeper)
}
func (am AppModule) RegisterQueryService(grpc.Server) {}
func (am AppModule) RegisterQueryService(server grpc.Server) {
types.RegisterQueryServer(server, am.keeper)
}
// InitGenesis performs genesis initialization for the gov module. It returns
// no validator updates.

View File

@ -12,6 +12,7 @@ import (
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
github_com_gogo_protobuf_types "github.com/gogo/protobuf/types"
_ "github.com/golang/protobuf/ptypes/duration"
_ "github.com/golang/protobuf/ptypes/timestamp"
_ "github.com/regen-network/cosmos-proto"
io "io"
@ -429,6 +430,126 @@ func (m *Vote) XXX_DiscardUnknown() {
var xxx_messageInfo_Vote proto.InternalMessageInfo
// DepositParams defines the params around deposits for governance
type DepositParams struct {
// Minimum deposit for a proposal to enter voting period.
MinDeposit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=min_deposit,json=minDeposit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"min_deposit,omitempty" yaml:"min_deposit"`
// Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months.
MaxDepositPeriod time.Duration `protobuf:"bytes,2,opt,name=max_deposit_period,json=maxDepositPeriod,proto3,stdduration" json:"max_deposit_period,omitempty" yaml:"max_deposit_period"`
}
func (m *DepositParams) Reset() { *m = DepositParams{} }
func (*DepositParams) ProtoMessage() {}
func (*DepositParams) Descriptor() ([]byte, []int) {
return fileDescriptor_67fb57f9a603bed5, []int{8}
}
func (m *DepositParams) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *DepositParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_DepositParams.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 *DepositParams) XXX_Merge(src proto.Message) {
xxx_messageInfo_DepositParams.Merge(m, src)
}
func (m *DepositParams) XXX_Size() int {
return m.Size()
}
func (m *DepositParams) XXX_DiscardUnknown() {
xxx_messageInfo_DepositParams.DiscardUnknown(m)
}
var xxx_messageInfo_DepositParams proto.InternalMessageInfo
// VotingParams defines the params around Voting in governance
type VotingParams struct {
// Length of the voting period.
VotingPeriod time.Duration `protobuf:"bytes,1,opt,name=voting_period,json=votingPeriod,proto3,stdduration" json:"voting_period,omitempty" yaml:"voting_period"`
}
func (m *VotingParams) Reset() { *m = VotingParams{} }
func (*VotingParams) ProtoMessage() {}
func (*VotingParams) Descriptor() ([]byte, []int) {
return fileDescriptor_67fb57f9a603bed5, []int{9}
}
func (m *VotingParams) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *VotingParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_VotingParams.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 *VotingParams) XXX_Merge(src proto.Message) {
xxx_messageInfo_VotingParams.Merge(m, src)
}
func (m *VotingParams) XXX_Size() int {
return m.Size()
}
func (m *VotingParams) XXX_DiscardUnknown() {
xxx_messageInfo_VotingParams.DiscardUnknown(m)
}
var xxx_messageInfo_VotingParams proto.InternalMessageInfo
// TallyParams defines the params around Tallying votes in governance
type TallyParams struct {
// Minimum percentage of total stake needed to vote for a result to be considered valid.
Quorum github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=quorum,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"quorum,omitempty"`
// Minimum proportion of Yes votes for proposal to pass. Initial value: 0.5.
Threshold github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=threshold,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"threshold,omitempty"`
// Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3.
Veto github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=veto,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"veto,omitempty"`
}
func (m *TallyParams) Reset() { *m = TallyParams{} }
func (*TallyParams) ProtoMessage() {}
func (*TallyParams) Descriptor() ([]byte, []int) {
return fileDescriptor_67fb57f9a603bed5, []int{10}
}
func (m *TallyParams) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *TallyParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_TallyParams.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 *TallyParams) XXX_Merge(src proto.Message) {
xxx_messageInfo_TallyParams.Merge(m, src)
}
func (m *TallyParams) XXX_Size() int {
return m.Size()
}
func (m *TallyParams) XXX_DiscardUnknown() {
xxx_messageInfo_TallyParams.DiscardUnknown(m)
}
var xxx_messageInfo_TallyParams proto.InternalMessageInfo
func init() {
proto.RegisterEnum("cosmos.gov.VoteOption", VoteOption_name, VoteOption_value)
proto.RegisterEnum("cosmos.gov.ProposalStatus", ProposalStatus_name, ProposalStatus_value)
@ -440,90 +561,107 @@ func init() {
proto.RegisterType((*Proposal)(nil), "cosmos.gov.Proposal")
proto.RegisterType((*TallyResult)(nil), "cosmos.gov.TallyResult")
proto.RegisterType((*Vote)(nil), "cosmos.gov.Vote")
proto.RegisterType((*DepositParams)(nil), "cosmos.gov.DepositParams")
proto.RegisterType((*VotingParams)(nil), "cosmos.gov.VotingParams")
proto.RegisterType((*TallyParams)(nil), "cosmos.gov.TallyParams")
}
func init() { proto.RegisterFile("cosmos/gov/gov.proto", fileDescriptor_67fb57f9a603bed5) }
var fileDescriptor_67fb57f9a603bed5 = []byte{
// 1247 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xcf, 0x6f, 0x1b, 0x45,
0x14, 0xf6, 0x6e, 0x7e, 0x3f, 0x3b, 0xc9, 0x76, 0x12, 0x25, 0xee, 0x22, 0xd6, 0x5b, 0x53, 0xa1,
0xa8, 0x6a, 0x9d, 0x92, 0x9e, 0x28, 0x12, 0xc2, 0x8e, 0xb7, 0xad, 0xab, 0xc6, 0xb6, 0xd6, 0x5b,
0x57, 0x85, 0xc3, 0x6a, 0x63, 0x4f, 0x9d, 0x05, 0x7b, 0xc7, 0xf2, 0x4e, 0x42, 0x2d, 0x2e, 0x70,
0x43, 0x3e, 0x95, 0x3f, 0xc0, 0x12, 0x12, 0x3d, 0x00, 0x27, 0x0e, 0xfc, 0x11, 0x11, 0xe2, 0x50,
0x21, 0x0e, 0x15, 0x07, 0x97, 0xa6, 0x12, 0x42, 0x1c, 0x38, 0xf4, 0xc8, 0x05, 0xb4, 0x33, 0xb3,
0xf5, 0xda, 0x89, 0x68, 0xcd, 0x0f, 0x21, 0x71, 0x88, 0xe4, 0x7d, 0xf3, 0x7d, 0xdf, 0x9b, 0xf7,
0xed, 0x9b, 0x37, 0x1b, 0x58, 0xad, 0x11, 0xbf, 0x45, 0xfc, 0xcd, 0x06, 0x39, 0x08, 0xfe, 0x32,
0xed, 0x0e, 0xa1, 0x04, 0x01, 0x8f, 0x66, 0x1a, 0xe4, 0x40, 0x5d, 0x11, 0x08, 0x11, 0x62, 0x00,
0x75, 0xb5, 0x41, 0x1a, 0x84, 0xfd, 0xdc, 0x0c, 0x7e, 0x89, 0xe8, 0x69, 0x8e, 0xb1, 0xf9, 0xc2,
0x08, 0x21, 0xd5, 0x20, 0xa4, 0xd1, 0xc4, 0x9b, 0xec, 0x69, 0x77, 0xff, 0xce, 0x26, 0x75, 0x5b,
0xd8, 0xa7, 0x4e, 0xab, 0x1d, 0x72, 0xc7, 0x01, 0x8e, 0xd7, 0xe5, 0x4b, 0xe9, 0x2f, 0x64, 0x38,
0xb5, 0xe3, 0x37, 0x2a, 0xfb, 0xbb, 0x2d, 0x97, 0x96, 0x3b, 0xa4, 0x4d, 0x7c, 0xa7, 0x89, 0xde,
0x80, 0xb9, 0x1a, 0xf1, 0x28, 0xf6, 0x68, 0x52, 0xd2, 0xa5, 0x8d, 0xf8, 0xd6, 0x6a, 0x86, 0x4b,
0x64, 0x42, 0x89, 0x4c, 0xd6, 0xeb, 0xe6, 0xe2, 0xdf, 0x7c, 0x7d, 0x61, 0x6e, 0x9b, 0x03, 0xcd,
0x90, 0x81, 0x3e, 0x92, 0x60, 0xd9, 0xf5, 0x5c, 0xea, 0x3a, 0x4d, 0xbb, 0x8e, 0xdb, 0xc4, 0x77,
0x69, 0x52, 0xd6, 0xa7, 0x36, 0xe2, 0x5b, 0x89, 0x8c, 0xd8, 0xf7, 0x36, 0x71, 0xbd, 0xdc, 0xf5,
0xc3, 0x41, 0x2a, 0xf6, 0x74, 0x90, 0x5a, 0xeb, 0x3a, 0xad, 0xe6, 0xe5, 0xf4, 0x18, 0x25, 0xfd,
0xe5, 0xa3, 0xd4, 0x46, 0xc3, 0xa5, 0x7b, 0xfb, 0xbb, 0x99, 0x1a, 0x69, 0x6d, 0x8e, 0x38, 0x75,
0xc1, 0xaf, 0xbf, 0xb7, 0x49, 0xbb, 0x6d, 0xcc, 0xa5, 0x7c, 0x73, 0x49, 0xb0, 0xf3, 0x9c, 0x8c,
0x76, 0x60, 0xbe, 0xcd, 0x8a, 0xc1, 0x9d, 0xe4, 0x94, 0x2e, 0x6d, 0x24, 0x72, 0xaf, 0xfd, 0x36,
0x48, 0x5d, 0x78, 0x01, 0xbd, 0x6c, 0xad, 0x96, 0xad, 0xd7, 0x3b, 0xd8, 0xf7, 0xcd, 0x67, 0x12,
0x97, 0xa7, 0x7f, 0xfe, 0x34, 0x25, 0xa5, 0x07, 0x12, 0xcc, 0xed, 0xf8, 0x8d, 0x2a, 0xa1, 0x18,
0x59, 0x10, 0x6f, 0x0b, 0xb7, 0x6c, 0xb7, 0xce, 0x5c, 0x9a, 0xce, 0x5d, 0x3a, 0x1a, 0xa4, 0x20,
0x34, 0xb1, 0x90, 0xff, 0x65, 0x90, 0x8a, 0x82, 0x9e, 0x0e, 0x52, 0x88, 0x97, 0x1a, 0x09, 0xa6,
0x4d, 0x08, 0x9f, 0x0a, 0x75, 0x74, 0x15, 0x66, 0x0e, 0x08, 0xc5, 0x9d, 0xa4, 0xfc, 0x57, 0xf7,
0xcc, 0xf9, 0x28, 0x03, 0xb3, 0xa4, 0x4d, 0x5d, 0xe2, 0xb1, 0xea, 0x97, 0xb6, 0xd6, 0x32, 0xc3,
0xae, 0xcb, 0x04, 0x05, 0x94, 0xd8, 0xaa, 0x29, 0x50, 0xa2, 0xc0, 0x4f, 0x64, 0x80, 0x1d, 0xbf,
0x11, 0x9a, 0xf8, 0xef, 0xd4, 0x58, 0x82, 0x05, 0xf1, 0x8a, 0xc9, 0xdf, 0xa8, 0x73, 0xa8, 0x81,
0xaa, 0x30, 0xeb, 0xb4, 0xc8, 0xbe, 0x47, 0x93, 0x53, 0x27, 0x74, 0xd9, 0xc5, 0xa0, 0xcb, 0x26,
0xea, 0x25, 0xa1, 0x26, 0x3c, 0xb9, 0x05, 0x09, 0x0b, 0xdf, 0x1d, 0x1e, 0x8d, 0x55, 0x98, 0xa1,
0x2e, 0x6d, 0x62, 0x66, 0xc7, 0x82, 0xc9, 0x1f, 0x90, 0x0e, 0xf1, 0x3a, 0xf6, 0x6b, 0x1d, 0x97,
0x9b, 0x2e, 0xb3, 0xb5, 0x68, 0xe8, 0xf2, 0x72, 0xa0, 0xf6, 0xdd, 0xf0, 0xbc, 0xa4, 0x7f, 0x97,
0x60, 0x2e, 0x74, 0xda, 0x38, 0xc9, 0xe9, 0xb3, 0xa3, 0x4e, 0xff, 0xff, 0xac, 0xfd, 0x69, 0x16,
0xe6, 0x9f, 0xf9, 0x9a, 0x3b, 0xc9, 0x82, 0x33, 0xc7, 0x9a, 0x4d, 0x66, 0x3d, 0xb6, 0x20, 0x46,
0xc6, 0x58, 0xfd, 0x91, 0xb1, 0x25, 0x4f, 0x3c, 0xb6, 0x8a, 0x30, 0xeb, 0x53, 0x87, 0xee, 0xfb,
0xe2, 0xc8, 0xa8, 0xd1, 0x23, 0x13, 0xee, 0xa1, 0xc2, 0x10, 0x39, 0x75, 0x38, 0xb6, 0x9e, 0x6d,
0x9a, 0x93, 0xd3, 0xa6, 0x50, 0x41, 0x7b, 0x80, 0xee, 0xb8, 0x9e, 0xd3, 0xb4, 0xa9, 0xd3, 0x6c,
0x76, 0xed, 0x0e, 0xf6, 0xf7, 0x9b, 0x34, 0x39, 0xcd, 0xf6, 0xb5, 0x1e, 0xd5, 0xb6, 0x82, 0x75,
0x93, 0x2d, 0xe7, 0xce, 0x88, 0x99, 0x78, 0x9a, 0x8b, 0x1f, 0x17, 0x48, 0x9b, 0x0a, 0x0b, 0x46,
0x48, 0xe8, 0x1d, 0x88, 0xfb, 0x6c, 0x7e, 0xdb, 0xc1, 0xe0, 0x4f, 0xce, 0xb0, 0x14, 0xea, 0xb1,
0xd2, 0xad, 0xf0, 0x56, 0xc8, 0x69, 0x22, 0x8b, 0xe8, 0xa7, 0x08, 0x39, 0x7d, 0xef, 0x51, 0x4a,
0x32, 0x81, 0x47, 0x02, 0x02, 0x72, 0x41, 0x11, 0xfd, 0x60, 0x63, 0xaf, 0xce, 0x33, 0xcc, 0x3e,
0x37, 0xc3, 0x2b, 0x22, 0xc3, 0x3a, 0xcf, 0x30, 0xae, 0xc0, 0xd3, 0x2c, 0x89, 0xb0, 0xe1, 0xd5,
0x59, 0xaa, 0x0f, 0x60, 0x91, 0x12, 0x1a, 0xb9, 0x35, 0xe6, 0x4e, 0x68, 0xba, 0x6b, 0x42, 0x79,
0x95, 0x2b, 0x8f, 0x10, 0x26, 0xbb, 0x33, 0x12, 0x8c, 0x1b, 0x1e, 0xc1, 0x26, 0x9c, 0x3a, 0x20,
0xd4, 0xf5, 0x1a, 0xc1, 0x8b, 0xec, 0x08, 0x2b, 0xe7, 0x9f, 0x5b, 0xe8, 0x59, 0xb1, 0x9d, 0x24,
0xdf, 0xce, 0x31, 0x09, 0x5e, 0xe9, 0x32, 0x8f, 0x57, 0x82, 0x30, 0x2b, 0xf5, 0x0e, 0x88, 0xd0,
0xd0, 0xd4, 0x85, 0xe7, 0xe6, 0x4a, 0x8f, 0x5e, 0x98, 0x63, 0x02, 0x3c, 0xd3, 0x22, 0x8f, 0x0a,
0x4b, 0xc5, 0x41, 0x3b, 0x94, 0x21, 0x1e, 0x6d, 0x98, 0xb7, 0x60, 0xaa, 0x8b, 0x7d, 0x3e, 0xc1,
0x72, 0x99, 0x40, 0xf5, 0x87, 0x41, 0xea, 0xd5, 0x17, 0x30, 0xae, 0xe0, 0x51, 0x33, 0xa0, 0xa2,
0x6b, 0x30, 0xe7, 0xec, 0xfa, 0xd4, 0x71, 0xc5, 0xac, 0x9b, 0x58, 0x25, 0xa4, 0xa3, 0x37, 0x41,
0xf6, 0x08, 0x3b, 0x72, 0x93, 0x8b, 0xc8, 0x1e, 0x41, 0x0d, 0x48, 0x78, 0xc4, 0x7e, 0xdf, 0xa5,
0x7b, 0xf6, 0x01, 0xa6, 0x84, 0x1d, 0xb0, 0x85, 0x9c, 0x31, 0x99, 0xd2, 0xd3, 0x41, 0x6a, 0x85,
0x9b, 0x1a, 0xd5, 0x4a, 0x9b, 0xe0, 0x91, 0x5b, 0x2e, 0xdd, 0xab, 0x62, 0x4a, 0x84, 0x95, 0xdf,
0x4a, 0x30, 0xcd, 0x3e, 0x00, 0xfe, 0xa1, 0x91, 0xfd, 0xdf, 0xde, 0xf8, 0xe7, 0x7e, 0x95, 0x00,
0x86, 0x8b, 0xe8, 0x3c, 0xac, 0x57, 0x4b, 0x96, 0x61, 0x97, 0xca, 0x56, 0xa1, 0x54, 0xb4, 0x6f,
0x16, 0x2b, 0x65, 0x63, 0xbb, 0x70, 0xa5, 0x60, 0xe4, 0x95, 0x98, 0xba, 0xdc, 0xeb, 0xeb, 0x71,
0x0e, 0x34, 0x5a, 0x6d, 0xda, 0x45, 0x69, 0x58, 0x8e, 0xa2, 0x6f, 0x1b, 0x15, 0x45, 0x52, 0x17,
0x7b, 0x7d, 0x7d, 0x81, 0xa3, 0x6e, 0x63, 0x1f, 0x9d, 0x83, 0x95, 0x28, 0x26, 0x9b, 0xab, 0x58,
0xd9, 0x42, 0x51, 0x91, 0xd5, 0x53, 0xbd, 0xbe, 0xbe, 0xc8, 0x71, 0x59, 0xd1, 0x0a, 0x3a, 0x2c,
0x45, 0xb1, 0xc5, 0x92, 0x32, 0xa5, 0x26, 0x7a, 0x7d, 0x7d, 0x9e, 0xc3, 0x8a, 0x04, 0x6d, 0x41,
0x72, 0x14, 0x61, 0xdf, 0x2a, 0x58, 0xd7, 0xec, 0xaa, 0x61, 0x95, 0x94, 0x69, 0x75, 0xb5, 0xd7,
0xd7, 0x95, 0x10, 0x1b, 0xbe, 0x37, 0x35, 0xf1, 0xf1, 0x67, 0x5a, 0xec, 0xf3, 0xfb, 0x5a, 0xec,
0xab, 0xfb, 0x5a, 0xec, 0xdc, 0xf7, 0x32, 0x2c, 0x8d, 0x0e, 0x73, 0x94, 0x81, 0x97, 0xca, 0x66,
0xa9, 0x5c, 0xaa, 0x64, 0x6f, 0xd8, 0x15, 0x2b, 0x6b, 0xdd, 0xac, 0x8c, 0x15, 0xce, 0x4a, 0xe2,
0xe0, 0xa2, 0x1b, 0x7c, 0x1c, 0x6b, 0xe3, 0xf8, 0xbc, 0x51, 0x2e, 0x55, 0x0a, 0x96, 0x5d, 0x36,
0xcc, 0x42, 0x29, 0xaf, 0x48, 0xea, 0x7a, 0xaf, 0xaf, 0xaf, 0x70, 0x8a, 0x18, 0x30, 0x65, 0xdc,
0x71, 0x49, 0x1d, 0xbd, 0x0e, 0x2f, 0x8f, 0x93, 0xab, 0x25, 0xab, 0x50, 0xbc, 0x1a, 0x72, 0x65,
0x75, 0xad, 0xd7, 0xd7, 0x11, 0xe7, 0x56, 0xd9, 0x61, 0x16, 0xd4, 0xf3, 0xb0, 0x36, 0x4e, 0x2d,
0x67, 0x2b, 0x15, 0x23, 0xaf, 0x4c, 0xa9, 0x4a, 0xaf, 0xaf, 0x27, 0x38, 0xa7, 0xec, 0xf8, 0x3e,
0xae, 0xa3, 0x8b, 0x90, 0x1c, 0x47, 0x9b, 0xc6, 0x75, 0x63, 0xdb, 0x32, 0xf2, 0xca, 0xb4, 0x8a,
0x7a, 0x7d, 0x7d, 0x89, 0xe3, 0x4d, 0xfc, 0x2e, 0xae, 0x51, 0x7c, 0xa2, 0xfe, 0x95, 0x6c, 0xe1,
0x86, 0x91, 0x57, 0x66, 0xa2, 0xfa, 0x57, 0x1c, 0xb7, 0x89, 0xeb, 0xa3, 0xb6, 0xe6, 0x8a, 0x87,
0x8f, 0xb5, 0xd8, 0xc3, 0xc7, 0x5a, 0xec, 0xc3, 0x23, 0x2d, 0x76, 0x78, 0xa4, 0x49, 0x0f, 0x8e,
0x34, 0xe9, 0xc7, 0x23, 0x4d, 0xba, 0xf7, 0x44, 0x8b, 0x3d, 0x78, 0xa2, 0xc5, 0x1e, 0x3e, 0xd1,
0x62, 0x6f, 0xff, 0xf9, 0x6c, 0xbe, 0xcb, 0xfe, 0x51, 0x62, 0xfd, 0xbd, 0x3b, 0xcb, 0xc6, 0xdf,
0xa5, 0x3f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xa5, 0x92, 0x7f, 0x43, 0x0d, 0x00, 0x00,
// 1468 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x58, 0xcf, 0x6b, 0x1b, 0xd7,
0x16, 0xd6, 0xc8, 0xbf, 0x8f, 0x64, 0x7b, 0x72, 0xed, 0x67, 0x2b, 0xf3, 0xde, 0x9b, 0x51, 0xf4,
0xc2, 0xc3, 0x84, 0x44, 0xce, 0x73, 0x56, 0x2f, 0x81, 0x47, 0x24, 0x6b, 0x92, 0x28, 0xc4, 0x92,
0x18, 0x4d, 0x14, 0x92, 0xb7, 0x18, 0xc6, 0xd2, 0x44, 0x9e, 0x56, 0x33, 0x57, 0xd5, 0x5c, 0xb9,
0x36, 0xd9, 0xb4, 0xbb, 0xa2, 0x42, 0x48, 0x77, 0xdd, 0x08, 0x0a, 0xcd, 0xa2, 0xed, 0xaa, 0x85,
0xfe, 0x11, 0xa6, 0x74, 0x11, 0x4a, 0x17, 0xa1, 0x0b, 0xa5, 0x71, 0xa0, 0x14, 0x2f, 0xba, 0xc8,
0xb2, 0x9b, 0x96, 0xb9, 0xf7, 0x8e, 0x35, 0x92, 0x4d, 0x1d, 0xf5, 0x07, 0x85, 0x2e, 0x02, 0xd2,
0xb9, 0xe7, 0xfb, 0xee, 0x39, 0x9f, 0xce, 0x77, 0x66, 0x62, 0x58, 0xac, 0x62, 0xcf, 0xc1, 0xde,
0x6a, 0x1d, 0x6f, 0xfb, 0xff, 0xd2, 0xcd, 0x16, 0x26, 0x18, 0x01, 0x8b, 0xa6, 0xeb, 0x78, 0x5b,
0x5a, 0xe0, 0x19, 0x3c, 0x44, 0x13, 0xa4, 0xc5, 0x3a, 0xae, 0x63, 0xfa, 0x71, 0xd5, 0xff, 0xc4,
0xa3, 0xa7, 0x59, 0x8e, 0xc1, 0x0e, 0x06, 0x00, 0x4a, 0x1d, 0xe3, 0x7a, 0xc3, 0x5a, 0xa5, 0xdf,
0x36, 0xdb, 0xf7, 0x57, 0x89, 0xed, 0x58, 0x1e, 0x31, 0x9d, 0x66, 0x80, 0x1d, 0x4e, 0x30, 0xdd,
0x5d, 0x7e, 0x24, 0x0f, 0x1f, 0xd5, 0xda, 0x2d, 0x93, 0xd8, 0xd8, 0x65, 0xe7, 0xa9, 0x8f, 0xa3,
0x70, 0x6a, 0xc3, 0xab, 0x97, 0xdb, 0x9b, 0x8e, 0x4d, 0x4a, 0x2d, 0xdc, 0xc4, 0x9e, 0xd9, 0x40,
0x57, 0x60, 0xaa, 0x8a, 0x5d, 0x62, 0xb9, 0x24, 0x21, 0x24, 0x85, 0x95, 0xd8, 0xda, 0x62, 0x9a,
0xf1, 0xa4, 0x03, 0x9e, 0x74, 0xc6, 0xdd, 0xcd, 0xc6, 0xbe, 0xf8, 0xfc, 0xc2, 0xd4, 0x3a, 0x4b,
0xd4, 0x02, 0x04, 0x7a, 0x5b, 0x80, 0x79, 0xdb, 0xb5, 0x89, 0x6d, 0x36, 0x8c, 0x9a, 0xd5, 0xc4,
0x9e, 0x4d, 0x12, 0xd1, 0xe4, 0xd8, 0x4a, 0x6c, 0x2d, 0x9e, 0xe6, 0x7d, 0xad, 0x63, 0xdb, 0xcd,
0xde, 0xdc, 0xeb, 0x29, 0x91, 0x97, 0x3d, 0x65, 0x69, 0xd7, 0x74, 0x1a, 0x97, 0x53, 0x43, 0x90,
0xd4, 0x27, 0xcf, 0x94, 0x95, 0xba, 0x4d, 0xb6, 0xda, 0x9b, 0xe9, 0x2a, 0x76, 0x56, 0x07, 0x94,
0xbc, 0xe0, 0xd5, 0x5e, 0x5f, 0x25, 0xbb, 0x4d, 0x8b, 0x51, 0x79, 0xda, 0x1c, 0x47, 0xe7, 0x18,
0x18, 0x6d, 0xc0, 0x74, 0x93, 0x36, 0x63, 0xb5, 0x12, 0x63, 0x49, 0x61, 0x25, 0x9e, 0xfd, 0xcf,
0x8f, 0x3d, 0xe5, 0xc2, 0x2b, 0xf0, 0x65, 0xaa, 0xd5, 0x4c, 0xad, 0xd6, 0xb2, 0x3c, 0x4f, 0x3b,
0xa4, 0xb8, 0x3c, 0xfe, 0xfd, 0x07, 0x8a, 0x90, 0xea, 0x09, 0x30, 0xb5, 0xe1, 0xd5, 0x2b, 0x98,
0x58, 0x48, 0x87, 0x58, 0x93, 0xab, 0x65, 0xd8, 0x35, 0xaa, 0xd2, 0x78, 0xf6, 0xd2, 0x7e, 0x4f,
0x81, 0x40, 0xc4, 0x7c, 0xee, 0xa0, 0xa7, 0x84, 0x93, 0x5e, 0xf6, 0x14, 0xc4, 0x5a, 0x0d, 0x05,
0x53, 0x1a, 0x04, 0xdf, 0xf2, 0x35, 0x74, 0x1d, 0x26, 0xb6, 0x31, 0xb1, 0x5a, 0x89, 0xe8, 0xaf,
0xad, 0x99, 0xe1, 0x51, 0x1a, 0x26, 0x71, 0xd3, 0xff, 0x99, 0x69, 0xf7, 0x73, 0x6b, 0x4b, 0xe9,
0xfe, 0x54, 0xa6, 0xfd, 0x06, 0x8a, 0xf4, 0x54, 0xe3, 0x59, 0xbc, 0xc1, 0xf7, 0xa2, 0x00, 0x1b,
0x5e, 0x3d, 0x10, 0xf1, 0x8f, 0xe9, 0xb1, 0x08, 0x33, 0xfc, 0x27, 0xc6, 0xbf, 0xa1, 0xcf, 0x3e,
0x07, 0xaa, 0xc0, 0xa4, 0xe9, 0xe0, 0xb6, 0x4b, 0x12, 0x63, 0xc7, 0x4c, 0xd9, 0x45, 0x7f, 0xca,
0x46, 0x9a, 0x25, 0xce, 0xc6, 0x35, 0xb9, 0x03, 0x71, 0xdd, 0xda, 0xe9, 0x5b, 0x63, 0x11, 0x26,
0x88, 0x4d, 0x1a, 0x16, 0x95, 0x63, 0x46, 0x63, 0x5f, 0x50, 0x12, 0x62, 0x35, 0xcb, 0xab, 0xb6,
0x6c, 0x26, 0x7a, 0x94, 0x9e, 0x85, 0x43, 0x97, 0xe7, 0x7d, 0xb6, 0xaf, 0xfa, 0x7e, 0x49, 0xfd,
0x24, 0xc0, 0x54, 0xa0, 0xb4, 0x7a, 0x9c, 0xd2, 0x67, 0x07, 0x95, 0xfe, 0xeb, 0x49, 0xfb, 0xdd,
0x24, 0x4c, 0x1f, 0xea, 0x9a, 0x3d, 0x4e, 0x82, 0x33, 0x47, 0x86, 0x2d, 0x4a, 0x67, 0x6c, 0x86,
0xaf, 0x8c, 0xa1, 0xfe, 0x43, 0x6b, 0x2b, 0x3a, 0xf2, 0xda, 0x2a, 0xc0, 0xa4, 0x47, 0x4c, 0xd2,
0xf6, 0xb8, 0x65, 0xa4, 0xb0, 0x65, 0x82, 0x1a, 0xca, 0x34, 0x23, 0x2b, 0xf5, 0xd7, 0xd6, 0x61,
0xd1, 0x0c, 0x9c, 0xd2, 0x38, 0x0b, 0xda, 0x02, 0x74, 0xdf, 0x76, 0xcd, 0x86, 0x41, 0xcc, 0x46,
0x63, 0xd7, 0x68, 0x59, 0x5e, 0xbb, 0x41, 0x12, 0xe3, 0xb4, 0xae, 0xe5, 0x30, 0xb7, 0xee, 0x9f,
0x6b, 0xf4, 0x38, 0x7b, 0x86, 0xef, 0xc4, 0xd3, 0x8c, 0xfc, 0x28, 0x41, 0x4a, 0x13, 0x69, 0x30,
0x04, 0x42, 0xff, 0x87, 0x98, 0x47, 0xf7, 0xb7, 0xe1, 0x3f, 0x18, 0x12, 0x13, 0xf4, 0x0a, 0xe9,
0x48, 0xeb, 0x7a, 0xf0, 0xd4, 0xc8, 0xca, 0xfc, 0x16, 0x3e, 0x4f, 0x21, 0x70, 0xea, 0xd1, 0x33,
0x45, 0xd0, 0x80, 0x45, 0x7c, 0x00, 0xb2, 0x41, 0xe4, 0xf3, 0x60, 0x58, 0x6e, 0x8d, 0xdd, 0x30,
0x79, 0xe2, 0x0d, 0xff, 0xe2, 0x37, 0x2c, 0xb3, 0x1b, 0x86, 0x19, 0xd8, 0x35, 0x73, 0x3c, 0xac,
0xba, 0x35, 0x7a, 0xd5, 0x03, 0x98, 0x25, 0x98, 0x84, 0x9e, 0x1a, 0x53, 0xc7, 0x0c, 0xdd, 0x0d,
0xce, 0xbc, 0xc8, 0x98, 0x07, 0x00, 0xa3, 0x3d, 0x33, 0xe2, 0x14, 0x1b, 0x58, 0xb0, 0x01, 0xa7,
0xb6, 0x31, 0xb1, 0xdd, 0xba, 0xff, 0x43, 0xb6, 0xb8, 0x94, 0xd3, 0x27, 0x36, 0x7a, 0x96, 0x97,
0x93, 0x60, 0xe5, 0x1c, 0xa1, 0x60, 0x9d, 0xce, 0xb3, 0x78, 0xd9, 0x0f, 0xd3, 0x56, 0xef, 0x03,
0x0f, 0xf5, 0x45, 0x9d, 0x39, 0xf1, 0xae, 0xd4, 0xe0, 0x03, 0x73, 0x88, 0x80, 0xdd, 0x34, 0xcb,
0xa2, 0x5c, 0x52, 0x6e, 0xb4, 0xbd, 0x28, 0xc4, 0xc2, 0x03, 0x73, 0x15, 0xc6, 0x76, 0x2d, 0x8f,
0x6d, 0xb0, 0x6c, 0xda, 0x67, 0xfd, 0xa6, 0xa7, 0xfc, 0xfb, 0x15, 0x84, 0xcb, 0xbb, 0x44, 0xf3,
0xa1, 0xe8, 0x06, 0x4c, 0x99, 0x9b, 0x1e, 0x31, 0x6d, 0xbe, 0xeb, 0x46, 0x66, 0x09, 0xe0, 0xe8,
0x7f, 0x10, 0x75, 0x31, 0xb5, 0xdc, 0xe8, 0x24, 0x51, 0x17, 0xa3, 0x3a, 0xc4, 0x5d, 0x6c, 0xbc,
0x69, 0x93, 0x2d, 0x63, 0xdb, 0x22, 0x98, 0x1a, 0x6c, 0x26, 0xab, 0x8e, 0xc6, 0xf4, 0xb2, 0xa7,
0x2c, 0x30, 0x51, 0xc3, 0x5c, 0x29, 0x0d, 0x5c, 0x7c, 0xc7, 0x26, 0x5b, 0x15, 0x8b, 0x60, 0x2e,
0xe5, 0x97, 0x02, 0x8c, 0xd3, 0x17, 0x80, 0xdf, 0x69, 0x65, 0xff, 0xc9, 0x4f, 0xfc, 0xcf, 0xa2,
0x30, 0xcb, 0x1d, 0x50, 0x32, 0x5b, 0xa6, 0xe3, 0xa1, 0x87, 0x02, 0xc4, 0x1c, 0xdb, 0x3d, 0xf4,
0xa0, 0x70, 0x8c, 0x07, 0x0d, 0x5f, 0xdd, 0x83, 0x9e, 0xf2, 0xb7, 0x50, 0xe2, 0x79, 0xec, 0xd8,
0xc4, 0x72, 0x9a, 0x64, 0xb7, 0xdf, 0x75, 0xe8, 0x78, 0x34, 0x6b, 0x82, 0x63, 0xbb, 0x81, 0x31,
0x1f, 0x0a, 0x80, 0x1c, 0x73, 0x27, 0x20, 0x32, 0x9a, 0x56, 0xcb, 0xc6, 0x35, 0xbe, 0xe0, 0x4f,
0x1f, 0xb1, 0x4b, 0x8e, 0xbf, 0xdf, 0xb2, 0x11, 0x38, 0xe8, 0x29, 0xff, 0x38, 0x0a, 0x1e, 0xa8,
0x95, 0xaf, 0xda, 0xa3, 0x59, 0xa9, 0xf7, 0x7d, 0x43, 0x89, 0x8e, 0xb9, 0x13, 0x28, 0xc4, 0xc2,
0xef, 0x0a, 0x10, 0xaf, 0x50, 0x97, 0x71, 0xc9, 0x1e, 0x00, 0x77, 0x5d, 0x50, 0x9b, 0x70, 0x52,
0x6d, 0x57, 0x78, 0x6d, 0xcb, 0x03, 0xb8, 0x81, 0xb2, 0x16, 0x07, 0x4c, 0x1e, 0xae, 0x28, 0xce,
0x62, 0xbc, 0x9a, 0xc7, 0x81, 0xb7, 0x79, 0x31, 0xf7, 0x60, 0xf2, 0x8d, 0x36, 0x6e, 0xb5, 0x1d,
0x5a, 0x45, 0x3c, 0x9b, 0x1d, 0xc1, 0x09, 0x39, 0xab, 0x7a, 0xd0, 0x53, 0x44, 0x86, 0xef, 0x57,
0xa3, 0x71, 0x46, 0x54, 0x85, 0x19, 0xb2, 0xd5, 0xb2, 0xbc, 0x2d, 0xdc, 0xa8, 0xf1, 0x81, 0x55,
0x47, 0xa6, 0x5f, 0x38, 0xa4, 0x08, 0xdd, 0xd0, 0xe7, 0x45, 0x3a, 0x8c, 0x53, 0x23, 0xb3, 0xd7,
0xf6, 0xab, 0x23, 0xf3, 0xcf, 0xf9, 0xe8, 0x10, 0x35, 0x65, 0x3b, 0xf7, 0x83, 0x00, 0xd0, 0x77,
0x01, 0x3a, 0x0f, 0xcb, 0x95, 0xa2, 0xae, 0x1a, 0xc5, 0x92, 0x9e, 0x2f, 0x16, 0x8c, 0xdb, 0x85,
0x72, 0x49, 0x5d, 0xcf, 0x5f, 0xcb, 0xab, 0x39, 0x31, 0x22, 0xcd, 0x77, 0xba, 0xc9, 0x18, 0x4b,
0x54, 0x7d, 0x0a, 0x94, 0x82, 0xf9, 0x70, 0xf6, 0x5d, 0xb5, 0x2c, 0x0a, 0xd2, 0x6c, 0xa7, 0x9b,
0x9c, 0x61, 0x59, 0x77, 0x2d, 0x0f, 0x9d, 0x83, 0x85, 0x70, 0x4e, 0x26, 0x5b, 0xd6, 0x33, 0xf9,
0x82, 0x18, 0x95, 0x4e, 0x75, 0xba, 0xc9, 0x59, 0x96, 0x97, 0xe1, 0x3b, 0x2f, 0x09, 0x73, 0xe1,
0xdc, 0x42, 0x51, 0x1c, 0x93, 0xe2, 0x9d, 0x6e, 0x72, 0x9a, 0xa5, 0x15, 0x30, 0x5a, 0x83, 0xc4,
0x60, 0x86, 0x71, 0x27, 0xaf, 0xdf, 0x30, 0x2a, 0xaa, 0x5e, 0x14, 0xc7, 0xa5, 0xc5, 0x4e, 0x37,
0x29, 0x06, 0xb9, 0xc1, 0x82, 0x92, 0xe2, 0xef, 0x7c, 0x28, 0x47, 0x3e, 0x7a, 0x2c, 0x47, 0x3e,
0x7d, 0x2c, 0x47, 0xce, 0x7d, 0x1d, 0x85, 0xb9, 0xc1, 0xb7, 0x16, 0x94, 0x86, 0xbf, 0x97, 0xb4,
0x62, 0xa9, 0x58, 0xce, 0xdc, 0x32, 0xca, 0x7a, 0x46, 0xbf, 0x5d, 0x1e, 0x6a, 0x9c, 0xb6, 0xc4,
0x92, 0x0b, 0xb6, 0xff, 0xbf, 0x40, 0x79, 0x38, 0x3f, 0xa7, 0x96, 0x8a, 0xe5, 0xbc, 0x6e, 0x94,
0x54, 0x2d, 0x5f, 0xcc, 0x89, 0x82, 0xb4, 0xdc, 0xe9, 0x26, 0x17, 0x18, 0x64, 0xc0, 0x25, 0xe8,
0xbf, 0xf0, 0xcf, 0x61, 0x70, 0xa5, 0xa8, 0xe7, 0x0b, 0xd7, 0x03, 0x6c, 0x54, 0x5a, 0xea, 0x74,
0x93, 0x88, 0x61, 0x2b, 0xa1, 0x91, 0x46, 0xe7, 0x61, 0x69, 0x18, 0x5a, 0xca, 0x94, 0xcb, 0x6a,
0x4e, 0x1c, 0x93, 0xc4, 0x4e, 0x37, 0x19, 0x67, 0x98, 0x92, 0xe9, 0x79, 0x56, 0x0d, 0x5d, 0x84,
0xc4, 0x70, 0xb6, 0xa6, 0xde, 0x54, 0xd7, 0x75, 0x35, 0x27, 0x8e, 0x4b, 0xa8, 0xd3, 0x4d, 0xce,
0xb1, 0x7c, 0xcd, 0x7a, 0xcd, 0xaa, 0x12, 0xeb, 0x58, 0xfe, 0x6b, 0x99, 0xfc, 0x2d, 0x35, 0x27,
0x4e, 0x84, 0xf9, 0xaf, 0x99, 0x76, 0xc3, 0xaa, 0x0d, 0xca, 0x9a, 0x2d, 0xec, 0x3d, 0x97, 0x23,
0x4f, 0x9f, 0xcb, 0x91, 0xb7, 0xf6, 0xe5, 0xc8, 0xde, 0xbe, 0x2c, 0x3c, 0xd9, 0x97, 0x85, 0x6f,
0xf7, 0x65, 0xe1, 0xd1, 0x0b, 0x39, 0xf2, 0xe4, 0x85, 0x1c, 0x79, 0xfa, 0x42, 0x8e, 0xdc, 0xfb,
0xe5, 0x4d, 0xb7, 0x43, 0xff, 0x62, 0x40, 0x67, 0x76, 0x73, 0x92, 0x2e, 0x87, 0x4b, 0x3f, 0x07,
0x00, 0x00, 0xff, 0xff, 0xc6, 0x9e, 0x45, 0x50, 0x4c, 0x10, 0x00, 0x00,
}
func (this *MsgSubmitProposal) Equal(that interface{}) bool {
@ -1239,6 +1377,135 @@ func (m *Vote) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *DepositParams) 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 *DepositParams) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *DepositParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
n8, err8 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.MaxDepositPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.MaxDepositPeriod):])
if err8 != nil {
return 0, err8
}
i -= n8
i = encodeVarintGov(dAtA, i, uint64(n8))
i--
dAtA[i] = 0x12
if len(m.MinDeposit) > 0 {
for iNdEx := len(m.MinDeposit) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.MinDeposit[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGov(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
func (m *VotingParams) 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 *VotingParams) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *VotingParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
n9, err9 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.VotingPeriod, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.VotingPeriod):])
if err9 != nil {
return 0, err9
}
i -= n9
i = encodeVarintGov(dAtA, i, uint64(n9))
i--
dAtA[i] = 0xa
return len(dAtA) - i, nil
}
func (m *TallyParams) 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 *TallyParams) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *TallyParams) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
{
size := m.Veto.Size()
i -= size
if _, err := m.Veto.MarshalTo(dAtA[i:]); err != nil {
return 0, err
}
i = encodeVarintGov(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x1a
{
size := m.Threshold.Size()
i -= size
if _, err := m.Threshold.MarshalTo(dAtA[i:]); err != nil {
return 0, err
}
i = encodeVarintGov(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
{
size := m.Quorum.Size()
i -= size
if _, err := m.Quorum.MarshalTo(dAtA[i:]); err != nil {
return 0, err
}
i = encodeVarintGov(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
return len(dAtA) - i, nil
}
func encodeVarintGov(dAtA []byte, offset int, v uint64) int {
offset -= sovGov(v)
base := offset
@ -1424,6 +1691,49 @@ func (m *Vote) Size() (n int) {
return n
}
func (m *DepositParams) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if len(m.MinDeposit) > 0 {
for _, e := range m.MinDeposit {
l = e.Size()
n += 1 + l + sovGov(uint64(l))
}
}
l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.MaxDepositPeriod)
n += 1 + l + sovGov(uint64(l))
return n
}
func (m *VotingParams) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = github_com_gogo_protobuf_types.SizeOfStdDuration(m.VotingPeriod)
n += 1 + l + sovGov(uint64(l))
return n
}
func (m *TallyParams) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = m.Quorum.Size()
n += 1 + l + sovGov(uint64(l))
l = m.Threshold.Size()
n += 1 + l + sovGov(uint64(l))
l = m.Veto.Size()
n += 1 + l + sovGov(uint64(l))
return n
}
func sovGov(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
@ -2749,6 +3059,364 @@ func (m *Vote) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *DepositParams) 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 ErrIntOverflowGov
}
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: DepositParams: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: DepositParams: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field MinDeposit", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGov
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGov
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGov
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.MinDeposit = append(m.MinDeposit, types1.Coin{})
if err := m.MinDeposit[len(m.MinDeposit)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field MaxDepositPeriod", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGov
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGov
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGov
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := github_com_gogo_protobuf_types.StdDurationUnmarshal(&m.MaxDepositPeriod, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGov(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGov
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthGov
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *VotingParams) 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 ErrIntOverflowGov
}
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: VotingParams: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: VotingParams: 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 ErrIntOverflowGov
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGov
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGov
}
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
default:
iNdEx = preIndex
skippy, err := skipGov(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGov
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthGov
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *TallyParams) 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 ErrIntOverflowGov
}
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: TallyParams: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: TallyParams: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Quorum", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGov
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthGov
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthGov
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.Quorum.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Threshold", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGov
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthGov
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthGov
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.Threshold.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Veto", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGov
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthGov
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthGov
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.Veto.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGov(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGov
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthGov
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipGov(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0

View File

@ -39,12 +39,6 @@ func ParamKeyTable() paramtypes.KeyTable {
)
}
// DepositParams defines the params around deposits for governance
type DepositParams struct {
MinDeposit sdk.Coins `json:"min_deposit,omitempty" yaml:"min_deposit,omitempty"` // Minimum deposit for a proposal to enter voting period.
MaxDepositPeriod time.Duration `json:"max_deposit_period,omitempty" yaml:"max_deposit_period,omitempty"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months
}
// NewDepositParams creates a new DepositParams object
func NewDepositParams(minDeposit sdk.Coins, maxDepositPeriod time.Duration) DepositParams {
return DepositParams{
@ -88,13 +82,6 @@ func validateDepositParams(i interface{}) error {
return nil
}
// TallyParams defines the params around Tallying votes in governance
type TallyParams struct {
Quorum sdk.Dec `json:"quorum,omitempty" yaml:"quorum,omitempty"` // Minimum percentage of total stake needed to vote for a result to be considered valid
Threshold sdk.Dec `json:"threshold,omitempty" yaml:"threshold,omitempty"` // Minimum proportion of Yes votes for proposal to pass. Initial value: 0.5
Veto sdk.Dec `json:"veto,omitempty" yaml:"veto,omitempty"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3
}
// NewTallyParams creates a new TallyParams object
func NewTallyParams(quorum, threshold, veto sdk.Dec) TallyParams {
return TallyParams{
@ -148,11 +135,6 @@ func validateTallyParams(i interface{}) error {
return nil
}
// VotingParams defines the params around Voting in governance
type VotingParams struct {
VotingPeriod time.Duration `json:"voting_period,omitempty" yaml:"voting_period,omitempty"` // Length of the voting period.
}
// NewVotingParams creates a new VotingParams object
func NewVotingParams(votingPeriod time.Duration) VotingParams {
return VotingParams{

3945
x/gov/types/query.pb.go Normal file

File diff suppressed because it is too large Load Diff