diff --git a/go.mod b/go.mod index 1ae1c66ac..55ec0236f 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/golang/mock v1.6.0 github.com/google/gofuzz v1.2.0 github.com/gorilla/mux v1.8.1 + github.com/hexops/gotextdiff v1.0.3 github.com/manifoldco/promptui v0.9.0 github.com/ory/dockertest/v3 v3.10.0 github.com/rakyll/statik v0.1.7 diff --git a/go.sum b/go.sum index 1b51101ae..16c0cf34a 100644 --- a/go.sum +++ b/go.sum @@ -787,6 +787,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU= github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= diff --git a/proto/atomone/gov/v1/query.proto b/proto/atomone/gov/v1/query.proto index 59da0c67b..e8e595cdf 100644 --- a/proto/atomone/gov/v1/query.proto +++ b/proto/atomone/gov/v1/query.proto @@ -14,7 +14,7 @@ option go_package = "github.com/atomone-hub/atomone/x/gov/types/v1"; service Query { // Constitution queries the chain's constitution. rpc Constitution(QueryConstitutionRequest) returns (QueryConstitutionResponse) { - option (google.api.http).get = "/cosmos/gov/v1/constitution"; + option (google.api.http).get = "/atomone/gov/v1/constitution"; } // Proposal queries proposal details based on ProposalID. diff --git a/proto/atomone/gov/v1/tx.proto b/proto/atomone/gov/v1/tx.proto index a5991e813..f05db7f93 100644 --- a/proto/atomone/gov/v1/tx.proto +++ b/proto/atomone/gov/v1/tx.proto @@ -213,6 +213,9 @@ message MsgProposeConstitutionAmendment { // authority is the address that controls the module (defaults to x/gov unless // overwritten). string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // amendment is the amendment to the constitution. It must be in valid GNU patch format. + string amendment = 2; } // MsgProposeConstitutionAmendmentResponse defines the response structure for executing a diff --git a/tests/e2e/e2e_gov_test.go b/tests/e2e/e2e_gov_test.go index c7f0f0190..83a4d188d 100644 --- a/tests/e2e/e2e_gov_test.go +++ b/tests/e2e/e2e_gov_test.go @@ -1,9 +1,11 @@ package e2e import ( + "context" "fmt" "path/filepath" "strconv" + "strings" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -12,6 +14,7 @@ import ( upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" govtypes "github.com/atomone-hub/atomone/x/gov/types" + govtypesv1 "github.com/atomone-hub/atomone/x/gov/types/v1" govtypesv1beta1 "github.com/atomone-hub/atomone/x/gov/types/v1beta1" ) @@ -176,6 +179,34 @@ func (s *IntegrationTestSuite) testGovParamChange() { }) } +func (s *IntegrationTestSuite) testGovConstitutionAmendment() { + s.Run("constitution amendment", func() { + chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp")) + senderAddress, _ := s.chainA.validators[0].keyInfo.GetAddress() + sender := senderAddress.String() + + newConstitution := "New test constitution" + amendmentMsg := s.generateConstitutionAmendment(s.chainA, newConstitution) + + s.writeGovConstitutionAmendmentProposal(s.chainA, amendmentMsg.Amendment) + // Gov tests may be run in arbitrary order, each test must increment proposalCounter to have the correct proposal id to submit and query + proposalCounter++ + submitGovFlags := []string{configFile(proposalConstitutionAmendmentFilename)} + depositGovFlags := []string{strconv.Itoa(proposalCounter), depositAmount.String()} + voteGovFlags := []string{strconv.Itoa(proposalCounter), "yes"} + s.submitGovProposal(chainAAPIEndpoint, sender, proposalCounter, "gov/MsgSubmitProposal", submitGovFlags, depositGovFlags, voteGovFlags, "vote") + + s.Require().Eventually( + func() bool { + res := s.queryConstitution(chainAAPIEndpoint) + return res.Constitution == newConstitution + }, + 10*time.Second, + time.Second, + ) + }) +} + func (s *IntegrationTestSuite) submitLegacyGovProposal(chainAAPIEndpoint, sender string, proposalID int, proposalType string, submitFlags []string, depositFlags []string, voteFlags []string, voteCommand string, withDeposit bool) { s.T().Logf("Submitting Gov Proposal: %s", proposalType) // min deposit of 1000uatone is required in e2e tests, otherwise the gov antehandler causes the proposal to be dropped @@ -283,3 +314,67 @@ func (s *IntegrationTestSuite) writeStakingParamChangeProposal(c *chain, params err := writeFile(filepath.Join(c.validators[0].configDir(), "config", proposalParamChangeFilename), []byte(propMsgBody)) s.Require().NoError(err) } + +func (s *IntegrationTestSuite) writeGovConstitutionAmendmentProposal(c *chain, amendment string) { + govModuleAddress := authtypes.NewModuleAddress(govtypes.ModuleName).String() + // escape newlines in amendment + amendment = strings.ReplaceAll(amendment, "\n", "\\n") + template := ` + { + "messages":[ + { + "@type": "/atomone.gov.v1.MsgProposeConstitutionAmendment", + "authority": "%s", + "amendment": "%s" + } + ], + "deposit": "100uatone", + "proposer": "Proposing validator address", + "metadata": "Constitution Amendment", + "title": "Constitution Amendment", + "summary": "summary" + } + ` + propMsgBody := fmt.Sprintf(template, govModuleAddress, amendment) + err := writeFile(filepath.Join(c.validators[0].configDir(), "config", proposalConstitutionAmendmentFilename), []byte(propMsgBody)) + s.Require().NoError(err) +} + +func (s *IntegrationTestSuite) generateConstitutionAmendment(c *chain, newConstitution string) govtypesv1.MsgProposeConstitutionAmendment { + err := writeFile(filepath.Join(c.validators[0].configDir(), "config", newConstitutionFilename), []byte(newConstitution)) + s.Require().NoError(err) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + govCommand := "generate-constitution-amendment" + cmd := []string{ + atomonedBinary, + txCommand, + govtypes.ModuleName, + govCommand, + configFile(newConstitutionFilename), + } + + s.T().Logf("Executing atomoned tx gov %s on chain %s", govCommand, c.id) + var msg govtypesv1.MsgProposeConstitutionAmendment + s.executeAtomoneTxCommand(ctx, c, cmd, 0, s.parseGenerateConstitutionAmendmentOutput(&msg)) + s.T().Logf("Successfully executed %s", govCommand) + + s.Require().NoError(err) + return msg +} + +func (s *IntegrationTestSuite) parseGenerateConstitutionAmendmentOutput(msg *govtypesv1.MsgProposeConstitutionAmendment) func([]byte, []byte) bool { + return func(stdOut []byte, stdErr []byte) bool { + if len(stdErr) > 0 { + s.T().Logf("Error: %s", string(stdErr)) + return false + } + + err := cdc.UnmarshalJSON(stdOut, msg) + s.Require().NoError(err) + + return true + } +} diff --git a/tests/e2e/e2e_setup_test.go b/tests/e2e/e2e_setup_test.go index 6aad487c0..db34c1d5c 100644 --- a/tests/e2e/e2e_setup_test.go +++ b/tests/e2e/e2e_setup_test.go @@ -61,10 +61,12 @@ const ( numberOfEvidences = 10 slashingShares int64 = 10000 - proposalBypassMsgFilename = "proposal_bypass_msg.json" - proposalMaxTotalBypassFilename = "proposal_max_total_bypass.json" - proposalCommunitySpendFilename = "proposal_community_spend.json" - proposalParamChangeFilename = "param_change.json" + proposalBypassMsgFilename = "proposal_bypass_msg.json" + proposalMaxTotalBypassFilename = "proposal_max_total_bypass.json" + proposalCommunitySpendFilename = "proposal_community_spend.json" + proposalParamChangeFilename = "param_change.json" + proposalConstitutionAmendmentFilename = "constitution_amendment.json" + newConstitutionFilename = "new_constitution.md" // hermesBinary = "hermes" // hermesConfigWithGasPrices = "/root/.hermes/config.toml" diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index 04cc39eb7..a42a68e96 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -58,6 +58,7 @@ func (s *IntegrationTestSuite) TestGov() { s.testGovCancelSoftwareUpgrade() s.testGovCommunityPoolSpend() s.testGovParamChange() + s.testGovConstitutionAmendment() } func (s *IntegrationTestSuite) TestSlashing() { diff --git a/tests/e2e/genesis.go b/tests/e2e/genesis.go index 50fe13d77..2e034d573 100644 --- a/tests/e2e/genesis.go +++ b/tests/e2e/genesis.go @@ -143,6 +143,7 @@ func modifyGenesis(path, moniker, amountStr string, addrAll []sdk.AccAddress, de govv1.DefaultQuorumTimeout, govv1.DefaultMaxVotingPeriodExtension, govv1.DefaultQuorumCheckCount, ), ) + govGenState.Constitution = "This is a test constitution" govGenStateBz, err := cdc.MarshalJSON(govGenState) if err != nil { return fmt.Errorf("failed to marshal gov genesis state: %w", err) diff --git a/tests/e2e/query_test.go b/tests/e2e/query_test.go index 236232bf7..de8288f6d 100644 --- a/tests/e2e/query_test.go +++ b/tests/e2e/query_test.go @@ -15,6 +15,7 @@ import ( evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + govtypesv1 "github.com/atomone-hub/atomone/x/gov/types/v1" govtypesv1beta1 "github.com/atomone-hub/atomone/x/gov/types/v1beta1" ) @@ -268,3 +269,12 @@ func (s *IntegrationTestSuite) queryStakingParams(endpoint string) stakingtypes. s.Require().NoError(err) return res } + +func (s *IntegrationTestSuite) queryConstitution(endpoint string) govtypesv1.QueryConstitutionResponse { + var res govtypesv1.QueryConstitutionResponse + body, err := httpGet(fmt.Sprintf("%s/atomone/gov/v1/constitution", endpoint)) + s.Require().NoError(err) + err = cdc.UnmarshalJSON(body, &res) + s.Require().NoError(err) + return res +} diff --git a/x/gov/client/cli/prompt.go b/x/gov/client/cli/prompt.go index 6f1249c9b..e485a4358 100644 --- a/x/gov/client/cli/prompt.go +++ b/x/gov/client/cli/prompt.go @@ -13,7 +13,6 @@ import ( "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -320,7 +319,6 @@ func NewCmdDraftProposal() *cobra.Command { }, } - flags.AddTxFlagsToCmd(cmd) cmd.Flags().Bool(flagSkipMetadata, false, "skip metadata prompt") return cmd diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index f9f98a6b7..f1362de35 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govutils "github.com/atomone-hub/atomone/x/gov/client/utils" "github.com/atomone-hub/atomone/x/gov/types" @@ -72,6 +73,7 @@ func NewTxCmd(legacyPropCmds []*cobra.Command) *cobra.Command { NewCmdWeightedVote(), NewCmdSubmitProposal(), NewCmdDraftProposal(), + NewCmdGenerateConstitutionAmendment(), // Deprecated cmdSubmitLegacyProp, @@ -375,3 +377,96 @@ $ %s tx gov weighted-vote 1 yes=0.6,no=0.3,abstain=0.1 --from mykey return cmd } + +// NewCmdConstitutionAmendmentMsg returns the command to generate the sdk.Msg +// required for a constitution amendment proposal generating the unified diff +// between the current constitution (queried) and the updated constitution +// from the provided markdown file. +func NewCmdGenerateConstitutionAmendment() *cobra.Command { + flagCurrentConstitution := "current-constitution" + + cmd := &cobra.Command{ + Use: "generate-constitution-amendment [path/to/updated/constitution.md]", + Args: cobra.ExactArgs(1), + Short: "Generate a constitution amendment proposal message", + Long: strings.TrimSpace( + fmt.Sprintf(`Generate a constitution amendment proposal message from the current +constitution and the provided updated constitution. +Queries the current constitution from the node (unless --current-constitution is used) +and generates a valid constitution amendment proposal message containing the unified diff +between the current constitution and the updated constitution provided +in a markdown file. + +NOTE: this is just a utility command, it is not able to generate or +submit a valid Tx. Use the 'tx gov submit-proposal' command in +conjunction with the result of this one to submit the proposal. +See also 'tx gov draft-proposal' for a more general proposal drafting tool. + +Example: +$ %s tx gov generate-constitution-amendment path/to/updated/constitution.md +`, + version.AppName, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + // Read the updated constitution from the provided markdown file + updatedConstitution, err := readFromMarkdownFile(args[0]) + if err != nil { + return err + } + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + var currentConstitution string + currentConstitutionPath, err := cmd.Flags().GetString(flagCurrentConstitution) + if err != nil { + return err + } + + if currentConstitutionPath != "" { + // Read the current constitution from the provided file + currentConstitution, err = readFromMarkdownFile(currentConstitutionPath) + if err != nil { + return err + } + } else { + // Query the current constitution from the node + queryClient := v1.NewQueryClient(clientCtx) + resp, err := queryClient.Constitution(cmd.Context(), &v1.QueryConstitutionRequest{}) + if err != nil { + return err + } + currentConstitution = resp.Constitution + } + + // Generate the unified diff between the current and updated constitutions + diff, err := govutils.GenerateUnifiedDiff(currentConstitution, updatedConstitution) + if err != nil { + return err + } + + // Generate the sdk.Msg for the constitution amendment proposal + msg := v1.NewMsgProposeConstitutionAmendment(authtypes.NewModuleAddress(types.ModuleName), diff) + return clientCtx.PrintProto(msg) + }, + } + + // This is not a tx command (but a utility for the proposal tx), so we don't need to add tx flags. + // It might actually be confusing, so we just add the query flags. + flags.AddQueryFlagsToCmd(cmd) + // query commands have the FlagOutput default to "text", but we want to override it to "json" + // in this case. + cmd.Flags().Lookup(flags.FlagOutput).DefValue = "json" + err := cmd.Flags().Set(flags.FlagOutput, "json") + if err != nil { + panic(err) + } + // add flag to pass input constitution file instead of querying node + // for the current constitution + cmd.Flags().String(flagCurrentConstitution, "", "Path to the current constitution markdown file (optional, if not provided, the current constitution will be queried from the node)") + + return cmd +} diff --git a/x/gov/client/cli/tx_test.go b/x/gov/client/cli/tx_test.go index 7772362ec..ed8a2c1ff 100644 --- a/x/gov/client/cli/tx_test.go +++ b/x/gov/client/cli/tx_test.go @@ -496,3 +496,32 @@ func (s *CLITestSuite) TestNewCmdWeightedVote() { }) } } + +func (s *CLITestSuite) TestCmdGenerateConstitutionAmendment() { + newConstitution := `Modified Constitution` + newConstitutionFile := testutil.WriteToNewTempFile(s.T(), newConstitution) + defer newConstitutionFile.Close() + + testCases := []struct { + name string + args []string + expCmdOutput string + }{ + { + "generate constitution amendment", + []string{newConstitutionFile.Name()}, + "{\"authority\":\"cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn\",\"amendment\":\"--- src\\n+++ dst\\n@@ -1 +1 @@\\n-\\n+Modified Constitution\\n\"}", + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.NewCmdGenerateConstitutionAmendment() + out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args) + s.Require().NoError(err) + s.Require().Contains(out.String(), tc.expCmdOutput) + }) + } +} diff --git a/x/gov/client/cli/util.go b/x/gov/client/cli/util.go index 15dfec1e1..f357c5a75 100644 --- a/x/gov/client/cli/util.go +++ b/x/gov/client/cli/util.go @@ -170,3 +170,30 @@ func ReadGovPropFlags(clientCtx client.Context, flagSet *pflag.FlagSet) (*govv1. return rv, nil } + +// readFromMarkdownFile reads the contents of a markdown file +// and returns it as a string. +func readFromMarkdownFile(filePath string) (string, error) { + file, err := os.Open(filePath) + if err != nil { + return "", fmt.Errorf("failed to open file: %w", err) + } + defer file.Close() + + stat, err := file.Stat() + if err != nil { + return "", fmt.Errorf("failed to get file info: %w", err) + } + + if stat.Size() == 0 { + return "", fmt.Errorf("file is empty") + } + + contents := make([]byte, stat.Size()) + _, err = file.Read(contents) + if err != nil { + return "", fmt.Errorf("failed to read file: %w", err) + } + + return string(contents), nil +} diff --git a/x/gov/client/utils/unified_diff.go b/x/gov/client/utils/unified_diff.go new file mode 100644 index 000000000..80af12a63 --- /dev/null +++ b/x/gov/client/utils/unified_diff.go @@ -0,0 +1,35 @@ +package utils + +import ( + "fmt" + + "github.com/hexops/gotextdiff" + "github.com/hexops/gotextdiff/myers" + "github.com/hexops/gotextdiff/span" +) + +// GenerateUnifiedDiff generates a unified diff from src and dst strings using gotextdiff. +// This is the only function that uses the gotextdiff library as its primary use is for +// clients. +func GenerateUnifiedDiff(src, dst string) (string, error) { + // Create spans for the source and destination texts + srcURI := span.URIFromPath("src") + + if src == "" || src[len(src)-1] != '\n' { + src += "\n" // Add an EOL to src if it's empty or newline is missing + } + if dst == "" || dst[len(dst)-1] != '\n' { + dst += "\n" // Add an EOL to dst if it's empty or newline is missing + } + + // Compute the edits using the Myers diff algorithm + eds := myers.ComputeEdits(srcURI, src, dst) + + // Generate the unified diff string + diff := gotextdiff.ToUnified("src", "dst", src, eds) + + // Convert the diff to a string + diffStr := fmt.Sprintf("%v", diff) + + return diffStr, nil +} diff --git a/x/gov/client/utils/unified_diff_test.go b/x/gov/client/utils/unified_diff_test.go new file mode 100644 index 000000000..3a96d724d --- /dev/null +++ b/x/gov/client/utils/unified_diff_test.go @@ -0,0 +1,93 @@ +package utils_test + +import ( + "strings" + "testing" + + "github.com/atomone-hub/atomone/x/gov/client/utils" + "github.com/atomone-hub/atomone/x/gov/types" + "github.com/stretchr/testify/require" +) + +func TestGenerateUnifiedDiff(t *testing.T) { + tests := []struct { + name string + src string + dst string + expected string + }{ + { + name: "No changes", + src: "Line one\nLine two\nLine three", + dst: "Line one\nLine two\nLine three", + expected: ``, + }, + { + name: "Line added", + src: "Line one\nLine two", + dst: "Line one\nLine two\nLine three", + expected: `@@ -1,2 +1,3 @@ + Line one + Line two ++Line three +`, + }, + { + name: "Line deleted", + src: "Line one\nLine two\nLine three", + dst: "Line one\nLine three", + expected: `@@ -1,3 +1,2 @@ + Line one +-Line two + Line three +`, + }, + { + name: "Line modified", + src: "Line one\nLine two\nLine three", + dst: "Line one\nLine two modified\nLine three", + expected: `@@ -1,3 +1,3 @@ + Line one +-Line two ++Line two modified + Line three +`, + }, + { + name: "Multiple changes", + src: "Line one\nLine two\nLine three", + dst: "Line zero\nLine one\nLine three\nLine four", + expected: `@@ -1,3 +1,4 @@ ++Line zero + Line one +-Line two + Line three ++Line four +`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + diff, err := utils.GenerateUnifiedDiff(tt.src, tt.dst) + require.NoError(t, err) + + diffContent := strings.TrimPrefix(diff, "--- src\n+++ dst\n") + expectedContent := strings.TrimPrefix(tt.expected, "--- src\n+++ dst\n") + + require.Equal(t, expectedContent, diffContent) + }) + } +} + +func TestUnifiedDiffIntegration(t *testing.T) { + src := "Line one\nLine two\nLine three" + dst := "Line zero\nLine one\nLine three\nLine four" + + diffStr, err := utils.GenerateUnifiedDiff(src, dst) + require.NoError(t, err) + + result, err := types.ApplyUnifiedDiff(src, diffStr) + require.NoError(t, err) + require.Equal(t, dst, result) +} diff --git a/x/gov/keeper/common_test.go b/x/gov/keeper/common_test.go index b91cbf608..ca86503ce 100644 --- a/x/gov/keeper/common_test.go +++ b/x/gov/keeper/common_test.go @@ -50,13 +50,12 @@ func getTestProposal() []sdk.Msg { // getTestConstitutionAmendmentProposal creates and returns a test constitution amendment proposal message. func getTestConstitutionAmendmentProposal() []sdk.Msg { - proposalMsg := v1.MsgProposeConstitutionAmendment{ - Authority: authtypes.NewModuleAddress(types.ModuleName).String(), - } + amendment := "@@ -1 +1 @@\n-\n+Test" + proposalMsg := v1.NewMsgProposeConstitutionAmendment(authtypes.NewModuleAddress(types.ModuleName), amendment) return []sdk.Msg{ banktypes.NewMsgSend(govAcct, addr, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000)))), - &proposalMsg, + proposalMsg, } } diff --git a/x/gov/keeper/constitution.go b/x/gov/keeper/constitution.go index 143c54752..0c133e692 100644 --- a/x/gov/keeper/constitution.go +++ b/x/gov/keeper/constitution.go @@ -17,3 +17,19 @@ func (keeper Keeper) SetConstitution(ctx sdk.Context, constitution string) { store := ctx.KVStore(keeper.storeKey) store.Set(types.KeyConstitution, []byte(constitution)) } + +// ApplyConstitutionAmendment applies the amendment as a patch against the current constitution +// and returns the updated constitution. If the amendment cannot be applied cleanly, an error is returned. +func (k Keeper) ApplyConstitutionAmendment(ctx sdk.Context, amendment string) (updatedConstitution string, err error) { + if amendment == "" { + return "", types.ErrInvalidConstitutionAmendment.Wrap("amendment cannot be empty") + } + + currentConstitution := k.GetConstitution(ctx) + updatedConstitution, err = types.ApplyUnifiedDiff(currentConstitution, amendment) + if err != nil { + return "", types.ErrInvalidConstitutionAmendment.Wrapf("failed to apply amendment: %v", err) + } + + return updatedConstitution, nil +} diff --git a/x/gov/keeper/constitution_test.go b/x/gov/keeper/constitution_test.go new file mode 100644 index 000000000..191be32c2 --- /dev/null +++ b/x/gov/keeper/constitution_test.go @@ -0,0 +1,53 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestApplyConstitutionAmendment(t *testing.T) { + govKeeper, _, _, ctx := setupGovKeeper(t) + + tests := []struct { + name string + initialConstitution string + amendment string + expectedResult string + expectError bool + }{ + { + name: "failed patch application", + initialConstitution: "Hello World", + amendment: "Hi World", + expectError: true, + }, + { + name: "successful patch application", + initialConstitution: "Hello\nWorld", + amendment: "@@ -1,2 +1,2 @@\n-Hello\n+Hi\n World", + expectError: false, + expectedResult: "Hi\nWorld", + }, + { + name: "successful patch application with multiple hunks", + initialConstitution: "Line one\nLine two\nLine three\nLine four\nLine five\nLine six\nLine seven\nLine eight\nLine nine", + amendment: "--- src\n+++ dst\n@@ -1,2 +1,2 @@\n-Line one\n+Line one modified\n Line two\n@@ -8,2 +8,2 @@\n Line eight\n-Line nine\n+Line nine modified", + expectError: false, + expectedResult: "Line one modified\nLine two\nLine three\nLine four\nLine five\nLine six\nLine seven\nLine eight\nLine nine modified", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + govKeeper.SetConstitution(ctx, tt.initialConstitution) + updatedConstitution, err := govKeeper.ApplyConstitutionAmendment(ctx, tt.amendment) + if tt.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tt.expectedResult, updatedConstitution) + } + }) + } +} diff --git a/x/gov/keeper/msg_server.go b/x/gov/keeper/msg_server.go index 86d442146..6ef0bc5dd 100644 --- a/x/gov/keeper/msg_server.go +++ b/x/gov/keeper/msg_server.go @@ -203,7 +203,15 @@ func (k msgServer) ProposeConstitutionAmendment(goCtx context.Context, msg *v1.M if k.authority != msg.Authority { return nil, errors.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", k.authority, msg.Authority) } - // only a no-op for now + if msg.Amendment == "" { + return nil, govtypes.ErrInvalidProposalMsg.Wrap("amendment cannot be empty") + } + ctx := sdk.UnwrapSDKContext(goCtx) + constitution, err := k.ApplyConstitutionAmendment(ctx, msg.Amendment) + if err != nil { + return nil, govtypes.ErrInvalidProposalMsg.Wrap(err.Error()) + } + k.SetConstitution(ctx, constitution) return &v1.MsgProposeConstitutionAmendmentResponse{}, nil } diff --git a/x/gov/keeper/msg_server_test.go b/x/gov/keeper/msg_server_test.go index 41d610654..a04c7f1ce 100644 --- a/x/gov/keeper/msg_server_test.go +++ b/x/gov/keeper/msg_server_test.go @@ -10,6 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govtypes "github.com/atomone-hub/atomone/x/gov/types" v1 "github.com/atomone-hub/atomone/x/gov/types/v1" "github.com/atomone-hub/atomone/x/gov/types/v1beta1" ) @@ -1300,3 +1301,61 @@ func (suite *KeeperTestSuite) TestSubmitProposal_InitialDeposit() { }) } } + +func (suite *KeeperTestSuite) TestProposeConstitutionAmendment() { + ctx := suite.ctx + suite.govKeeper.SetConstitution(ctx, "Hello World") + + cases := map[string]struct { + msg *v1.MsgProposeConstitutionAmendment + expErr bool + expErrMsg string + expResult string + }{ + "successful amendment": { + msg: v1.NewMsgProposeConstitutionAmendment( + suite.govKeeper.GetGovernanceAccount(ctx).GetAddress(), + "@@ -1 +1 @@\n-Hello World\n+Hi World", + ), + expErr: false, + expResult: "Hi World", + }, + "failed amendment": { + msg: v1.NewMsgProposeConstitutionAmendment( + suite.govKeeper.GetGovernanceAccount(ctx).GetAddress(), + "@@ -1 +1 @@\n-Hello World\n+Hi World", + ), + expErr: true, + }, + "invalid patch": { + msg: v1.NewMsgProposeConstitutionAmendment( + suite.govKeeper.GetGovernanceAccount(ctx).GetAddress(), + "invalid patch", + ), + expErr: true, + }, + "invalid authority": { + msg: v1.NewMsgProposeConstitutionAmendment( + sdk.AccAddress("invalid"), + "@@ -1 +1 @@\n-Hello World\n+Hi World", + ), + expErr: true, + expErrMsg: govtypes.ErrInvalidSigner.Error(), + }, + } + + for name, tc := range cases { + suite.Run(name, func() { + _, err := suite.msgSrvr.ProposeConstitutionAmendment(sdk.WrapSDKContext(ctx), tc.msg) + if tc.expErr { + suite.Require().Error(err) + if tc.expErrMsg != "" { + suite.Require().Contains(err.Error(), tc.expErrMsg) + } + } else { + suite.Require().NoError(err) + suite.Require().Equal(tc.expResult, suite.govKeeper.GetConstitution(ctx)) + } + }) + } +} diff --git a/x/gov/simulation/genesis_test.go b/x/gov/simulation/genesis_test.go index 0ffeda598..7b42943b5 100644 --- a/x/gov/simulation/genesis_test.go +++ b/x/gov/simulation/genesis_test.go @@ -70,6 +70,7 @@ func TestRandomizedGenState(t *testing.T) { require.Equal(t, []*v1.Deposit{}, govGenesis.Deposits) require.Equal(t, []*v1.Vote{}, govGenesis.Votes) require.Equal(t, []*v1.Proposal{}, govGenesis.Proposals) + require.Equal(t, "", govGenesis.Constitution) } // TestRandomizedGenState tests abnormal scenarios of applying RandomizedGenState. diff --git a/x/gov/simulation/proposals.go b/x/gov/simulation/proposals.go index e31b580b3..a6a0aa8d3 100644 --- a/x/gov/simulation/proposals.go +++ b/x/gov/simulation/proposals.go @@ -73,10 +73,9 @@ func SimulateLegacyTextProposalContent(r *rand.Rand, _ sdk.Context, _ []simtypes } // SimulateConstitutionAmendmentProposal returns a random constitution amendment proposal. -func SimulateConstitutionAmendmentProposal(_ *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { - return &v1.MsgProposeConstitutionAmendment{ - Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), - } +func SimulateConstitutionAmendmentProposal(_ *rand.Rand, ctx sdk.Context, _ []simtypes.Account) sdk.Msg { + emptyAmendment := "@@ -1 +1 @@\n-\n+\n" // valid diff with no changes + return v1.NewMsgProposeConstitutionAmendment(authtypes.NewModuleAddress(govtypes.ModuleName), emptyAmendment) } // SimulateLawProposal returns a random law proposal. diff --git a/x/gov/types/errors.go b/x/gov/types/errors.go index 19b410820..c00889dc6 100644 --- a/x/gov/types/errors.go +++ b/x/gov/types/errors.go @@ -10,16 +10,17 @@ var ( ErrInactiveProposal = sdkerrors.Register(ModuleName, 30, "inactive proposal") //nolint:staticcheck ErrAlreadyActiveProposal = sdkerrors.Register(ModuleName, 40, "proposal already active") //nolint:staticcheck // Errors 5 & 6 are legacy errors related to v1beta1.Proposal. - ErrInvalidProposalContent = sdkerrors.Register(ModuleName, 50, "invalid proposal content") //nolint:staticcheck - ErrInvalidProposalType = sdkerrors.Register(ModuleName, 60, "invalid proposal type") //nolint:staticcheck - ErrInvalidVote = sdkerrors.Register(ModuleName, 70, "invalid vote option") //nolint:staticcheck - ErrInvalidGenesis = sdkerrors.Register(ModuleName, 80, "invalid genesis state") //nolint:staticcheck - ErrNoProposalHandlerExists = sdkerrors.Register(ModuleName, 90, "no handler exists for proposal type") //nolint:staticcheck - ErrUnroutableProposalMsg = sdkerrors.Register(ModuleName, 100, "proposal message not recognized by router") //nolint:staticcheck - ErrNoProposalMsgs = sdkerrors.Register(ModuleName, 110, "no messages proposed") //nolint:staticcheck - ErrInvalidProposalMsg = sdkerrors.Register(ModuleName, 120, "invalid proposal message") //nolint:staticcheck - ErrInvalidSigner = sdkerrors.Register(ModuleName, 130, "expected gov account as only signer for proposal message") //nolint:staticcheck - ErrInvalidSignalMsg = sdkerrors.Register(ModuleName, 140, "signal message is invalid") //nolint:staticcheck - ErrMetadataTooLong = sdkerrors.Register(ModuleName, 150, "metadata too long") //nolint:staticcheck - ErrMinDepositTooSmall = sdkerrors.Register(ModuleName, 160, "minimum deposit is too small") //nolint:staticcheck + ErrInvalidProposalContent = sdkerrors.Register(ModuleName, 50, "invalid proposal content") //nolint:staticcheck + ErrInvalidProposalType = sdkerrors.Register(ModuleName, 60, "invalid proposal type") //nolint:staticcheck + ErrInvalidVote = sdkerrors.Register(ModuleName, 70, "invalid vote option") //nolint:staticcheck + ErrInvalidGenesis = sdkerrors.Register(ModuleName, 80, "invalid genesis state") //nolint:staticcheck + ErrNoProposalHandlerExists = sdkerrors.Register(ModuleName, 90, "no handler exists for proposal type") //nolint:staticcheck + ErrUnroutableProposalMsg = sdkerrors.Register(ModuleName, 100, "proposal message not recognized by router") //nolint:staticcheck + ErrNoProposalMsgs = sdkerrors.Register(ModuleName, 110, "no messages proposed") //nolint:staticcheck + ErrInvalidProposalMsg = sdkerrors.Register(ModuleName, 120, "invalid proposal message") //nolint:staticcheck + ErrInvalidSigner = sdkerrors.Register(ModuleName, 130, "expected gov account as only signer for proposal message") //nolint:staticcheck + ErrInvalidSignalMsg = sdkerrors.Register(ModuleName, 140, "signal message is invalid") //nolint:staticcheck + ErrMetadataTooLong = sdkerrors.Register(ModuleName, 150, "metadata too long") //nolint:staticcheck + ErrMinDepositTooSmall = sdkerrors.Register(ModuleName, 160, "minimum deposit is too small") //nolint:staticcheck + ErrInvalidConstitutionAmendment = sdkerrors.Register(ModuleName, 170, "invalid constitution amendment") //nolint:staticcheck ) diff --git a/x/gov/types/unified_diff.go b/x/gov/types/unified_diff.go new file mode 100644 index 000000000..c7dd0858b --- /dev/null +++ b/x/gov/types/unified_diff.go @@ -0,0 +1,269 @@ +package types + +import ( + "fmt" + "strconv" + "strings" +) + +// Hunk represents a single change hunk in a unified diff. +type Hunk struct { + SrcLine int + SrcSpan int + DstLine int + DstSpan int + Lines []string +} + +// ParseUnifiedDiff parses the unified diff string into hunks with validation. +func ParseUnifiedDiff(diffStr string) ([]Hunk, error) { + var ( + hunks []Hunk + hunk *Hunk + ) + + diffLines := strings.Split(diffStr, "\n") + // remove any trailing empty lines + for len(diffLines) > 0 && diffLines[len(diffLines)-1] == "" { + diffLines = diffLines[:len(diffLines)-1] + } + + for i := 0; i < len(diffLines); i++ { + line := diffLines[i] + + if strings.HasPrefix(line, "@@") { + // Start of a new hunk + hunkHeader := line + h, err := parseHunkHeader(hunkHeader) + if err != nil { + return nil, fmt.Errorf("invalid hunk header at line %d: %v", i+1, err) + } + if hunk != nil { + // Validate the previous hunk before starting a new one + if err := validateHunk(hunk); err != nil { + return nil, fmt.Errorf("invalid hunk ending at line %d: %v", i, err) + } + hunks = append(hunks, *hunk) + } + hunk = h + continue + } + + if hunk != nil { + if len(line) > 0 { + prefix := line[0] + if prefix != ' ' && prefix != '-' && prefix != '+' { + return nil, fmt.Errorf("invalid line prefix '%c' at line %d", prefix, i+1) + } + hunk.Lines = append(hunk.Lines, line) + } else { + // Empty line (could be a valid diff line with no content) + hunk.Lines = append(hunk.Lines, line) + } + } else if strings.TrimSpace(line) != "" && !strings.HasPrefix(line, "---") && !strings.HasPrefix(line, "+++") { + // Non-empty line outside of a hunk and not a file header + return nil, fmt.Errorf("unexpected content outside of hunks at line %d", i+1) + } + } + + // Validate and append the last hunk + if hunk != nil { + if err := validateHunk(hunk); err != nil { + return nil, fmt.Errorf("invalid hunk at end of diff: %v", err) + } + hunks = append(hunks, *hunk) + } + + if len(hunks) == 0 { + return nil, fmt.Errorf("no valid hunks found in the diff") + } + + return hunks, nil +} + +// parseHunkHeader parses the hunk header line and returns a Hunk. +func parseHunkHeader(header string) (*Hunk, error) { + // Remove the leading and trailing '@' symbols and any surrounding spaces + header = strings.TrimPrefix(header, "@@") + header = strings.TrimSuffix(header, "@@") + header = strings.TrimSpace(header) + + // Split the header into source and destination parts + parts := strings.Fields(header) + if len(parts) < 2 { + return nil, fmt.Errorf("invalid hunk header format") + } + + srcPart := parts[0] + dstPart := parts[1] + + h := &Hunk{} + + // Parse source part + srcLine, srcSpan, err := parseHunkRange(srcPart) + if err != nil { + return nil, fmt.Errorf("invalid source range: %v", err) + } + h.SrcLine = srcLine + h.SrcSpan = srcSpan + + // Parse destination part + dstLine, dstSpan, err := parseHunkRange(dstPart) + if err != nil { + return nil, fmt.Errorf("invalid destination range: %v", err) + } + h.DstLine = dstLine + h.DstSpan = dstSpan + + return h, nil +} + +// parseHunkRange parses a range string like "-srcLine,srcSpan" or "+dstLine" +func parseHunkRange(rangeStr string) (line int, span int, err error) { + if len(rangeStr) == 0 { + return 0, 0, fmt.Errorf("empty range string") + } + + // The range string starts with '-' or '+' + prefix := rangeStr[0] + if prefix != '-' && prefix != '+' { + return 0, 0, fmt.Errorf("invalid range prefix '%c'", prefix) + } + + rangeStr = rangeStr[1:] // Remove the prefix + + // Split the range into line and span if ',' is present + if strings.Contains(rangeStr, ",") { + parts := strings.Split(rangeStr, ",") + if len(parts) != 2 { + return 0, 0, fmt.Errorf("invalid range format") + } + line, err = strconv.Atoi(parts[0]) + if err != nil { + return 0, 0, fmt.Errorf("invalid line number: %v", err) + } + span, err = strconv.Atoi(parts[1]) + if err != nil { + return 0, 0, fmt.Errorf("invalid span number: %v", err) + } + } else { + // No span provided, default to span = 1 + line, err = strconv.Atoi(rangeStr) + if err != nil { + return 0, 0, fmt.Errorf("invalid line number: %v", err) + } + span = 1 + } + + if span < 0 { + return 0, 0, fmt.Errorf("negative span") + } + + line-- // Adjust line number to 0-based index + + return line, span, nil +} + +// validateHunk validates the hunk's content against its header. +func validateHunk(hunk *Hunk) error { + srcCount := 0 + dstCount := 0 + + for _, line := range hunk.Lines { + if len(line) == 0 { + // Empty line, does not contribute to counts + continue + } + switch line[0] { + case ' ': + srcCount++ + dstCount++ + case '-': + srcCount++ + case '+': + dstCount++ + default: + return fmt.Errorf("invalid line prefix '%c'", line[0]) + } + } + + if srcCount != hunk.SrcSpan { + return fmt.Errorf("source line count (%d) does not match SrcSpan (%d)", srcCount, hunk.SrcSpan) + } + if dstCount != hunk.DstSpan { + return fmt.Errorf("destination line count (%d) does not match DstSpan (%d)", dstCount, hunk.DstSpan) + } + + return nil +} + +// applyHunks applies the parsed hunks to the source lines. +func applyHunks(srcStr string, hunks []Hunk) ([]string, error) { + srcLines := strings.Split(srcStr, "\n") + result := make([]string, 0) + srcIndex := 0 + + for _, hunk := range hunks { + // Add unchanged lines before the hunk + for srcIndex < hunk.SrcLine { + result = append(result, srcLines[srcIndex]) + srcIndex++ + } + + // Apply hunk lines + for _, line := range hunk.Lines { + if len(line) == 0 { + continue + } + prefix := line[0] + content := line[1:] + + switch prefix { + case ' ': + // Context line, should match source + if srcIndex >= len(srcLines) || srcLines[srcIndex] != content { + return nil, fmt.Errorf("context line mismatch at line %d", srcIndex+1) + } + result = append(result, content) + srcIndex++ + case '-': + // Deletion, skip source line + if srcIndex >= len(srcLines) || srcLines[srcIndex] != content { + return nil, fmt.Errorf("deletion line mismatch at line %d", srcIndex+1) + } + srcIndex++ + case '+': + // Insertion, add to result + result = append(result, content) + default: + return nil, fmt.Errorf("invalid diff line: %s", line) + } + } + } + + // Add any remaining lines + for srcIndex < len(srcLines) { + result = append(result, srcLines[srcIndex]) + srcIndex++ + } + + return result, nil +} + +// ApplyUnifiedDiff applies a unified diff patch to the src string and returns the result. +// Does not make use of any external libraries to ensure deterministic behavior. +func ApplyUnifiedDiff(src, diffStr string) (string, error) { + // Parse the unified diff into hunks + hunks, err := ParseUnifiedDiff(diffStr) + if err != nil { + return "", err + } + + // Apply the hunks to the source lines + resultLines, err := applyHunks(src, hunks) + if err != nil { + return "", err + } + + return strings.Join(resultLines, "\n"), nil +} diff --git a/x/gov/types/unified_diff_test.go b/x/gov/types/unified_diff_test.go new file mode 100644 index 000000000..a486b0295 --- /dev/null +++ b/x/gov/types/unified_diff_test.go @@ -0,0 +1,351 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestApplyUnifiedDiff(t *testing.T) { + tests := []struct { + name string + src string + diffStr string + expected string + wantErr bool + }{ + { + name: "Apply addition", + src: "Line one\nLine two", + diffStr: `--- src ++++ dst +@@ -1,2 +1,3 @@ + Line one + Line two ++Line three +`, + expected: "Line one\nLine two\nLine three", + wantErr: false, + }, + { + name: "Apply deletion", + src: "Line one\nLine two\nLine three", + diffStr: `@@ -1,3 +1,2 @@ + Line one +-Line two + Line three +`, + expected: "Line one\nLine three", + wantErr: false, + }, + { + name: "Apply modification", + src: "Line one\nLine two\nLine three", + diffStr: `--- a ++++ b +@@ -2 +2 @@ +-Line two ++Line two modified +`, + expected: "Line one\nLine two modified\nLine three", + wantErr: false, + }, + { + name: "Apply multiple changes", + src: "Line one\nLine two\nLine three", + diffStr: `@@ -1,3 +1,4 @@ ++Line zero + Line one +-Line two + Line three ++Line four +`, + expected: "Line zero\nLine one\nLine three\nLine four", + wantErr: false, + }, + { + name: "Apply multiple hunks", + src: "Line one\nLine two\nLine three\nLine four\nLine five\nLine six\nLine seven\nLine eight\nLine nine", + diffStr: `@@ -1,4 +1,4 @@ +-Line one ++Line one modified + Line two + Line three + Line four +@@ -6,4 +6,4 @@ + Line six + Line seven + Line eight +-Line nine ++Line nine modified +`, + expected: "Line one modified\nLine two\nLine three\nLine four\nLine five\nLine six\nLine seven\nLine eight\nLine nine modified", + wantErr: false, + }, + { + name: "Malformed diff", + src: "Line one\nLine two", + diffStr: `@@ -1,2 +1,3 @@ + Line one ++Line three +`, + expected: "", + wantErr: true, + }, + { + name: "Context line mismatch", + src: "Line one\nLine two", + diffStr: `@@ -1,2 +1,2 @@ + Line zero + Line two +`, + expected: "", + wantErr: true, + }, + { + name: "Empty diff", + src: "Line one\nLine two", + diffStr: `--- src ++++ dst +`, + wantErr: true, + }, + { + name: "Empty source", + src: "", + diffStr: `--- src ++++ dst +@@ -1 +1 @@ +- ++Line one +`, + expected: "Line one", + wantErr: false, + }, + { + name: "Empty source and no-op dst", + src: "", + diffStr: `--- src ++++ dst +@@ -1 +1 @@ +- ++ +`, + expected: "", + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := ApplyUnifiedDiff(tt.src, tt.diffStr) + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tt.expected, result) + } + }) + } +} + +func TestParseUnifiedDiff(t *testing.T) { + diffStr := `@@ -1,3 +1,4 @@ ++Line zero + Line one +-Line two + Line three ++Line four +` + + expectedHunks := []Hunk{ + { + SrcLine: 0, + SrcSpan: 3, + DstLine: 0, + DstSpan: 4, + Lines: []string{ + "+Line zero", + " Line one", + "-Line two", + " Line three", + "+Line four", + }, + }, + } + + t.Run("Hunk with spans", func(t *testing.T) { + hunks, err := ParseUnifiedDiff(diffStr) + require.NoError(t, err) + require.Equal(t, expectedHunks, hunks) + }) + + diffWithoutSpans := `@@ -2 +2 @@ +-Line two ++Line two modified +` + + expectedHunksWithoutSpans := []Hunk{ + { + SrcLine: 1, + SrcSpan: 1, + DstLine: 1, + DstSpan: 1, + Lines: []string{ + "-Line two", + "+Line two modified", + }, + }, + } + + t.Run("Hunk header without spans", func(t *testing.T) { + hunks, err := ParseUnifiedDiff(diffWithoutSpans) + require.NoError(t, err) + require.Equal(t, expectedHunksWithoutSpans, hunks) + }) + + invalidDiffs := []struct { + name string + diffStr string + wantErr bool + errorMsg string + }{ + { + name: "Invalid hunk header format", + diffStr: `@@ invalid header @@ + Line one +`, + wantErr: true, + errorMsg: "invalid hunk header", + }, + { + name: "Negative span in hunk header", + diffStr: `@@ -1,-2 +1,2 @@ + Line one +`, + wantErr: true, + errorMsg: "negative span", + }, + { + name: "Invalid line prefix", + diffStr: `@@ -1,1 +1,1 @@ +?Line one +`, + wantErr: true, + errorMsg: "invalid line prefix", + }, + { + name: "Source line count mismatch", + diffStr: `@@ -1,2 +1,2 @@ + Line one ++Line two +`, + wantErr: true, + errorMsg: "source line count", + }, + { + name: "Destination line count mismatch", + diffStr: `@@ -1,2 +1,2 @@ +-Line one + Line two +`, + wantErr: true, + errorMsg: "destination line count", + }, + { + name: "No hunks", + diffStr: ``, + wantErr: true, + errorMsg: "no valid hunks", + }, + { + name: "Unexpected content outside hunks", + diffStr: `Unexpected line +@@ -1,1 +1,1 @@ + Line one +`, + wantErr: true, + errorMsg: "unexpected content outside of hunks", + }, + } + + for _, tt := range invalidDiffs { + t.Run(tt.name, func(t *testing.T) { + _, err := ParseUnifiedDiff(tt.diffStr) + if tt.wantErr { + require.Error(t, err) + require.Contains(t, err.Error(), tt.errorMsg) + } else { + require.NoError(t, err) + } + }) + } +} + +// TestParseHunkHeader tests the parseHunkHeader function. +func TestParseHunkHeader(t *testing.T) { + tests := []struct { + name string + header string + expected *Hunk + wantErr bool + }{ + { + name: "Header with spans", + header: "@@ -1,3 +1,4 @@", + expected: &Hunk{ + SrcLine: 0, + SrcSpan: 3, + DstLine: 0, + DstSpan: 4, + }, + wantErr: false, + }, + { + name: "Header without spans", + header: "@@ -2 +2 @@", + expected: &Hunk{ + SrcLine: 1, + SrcSpan: 1, + DstLine: 1, + DstSpan: 1, + }, + wantErr: false, + }, + { + name: "Header with zero spans", + header: "@@ -0,0 +1,2 @@", + expected: &Hunk{ + SrcLine: -1, + SrcSpan: 0, + DstLine: 0, + DstSpan: 2, + }, + wantErr: false, + }, + { + name: "Invalid header format", + header: "@@ invalid header @@", + expected: nil, + wantErr: true, + }, + { + name: "Negative span", + header: "@@ -1,-2 +1,2 @@", + expected: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + hunk, err := parseHunkHeader(tt.header) + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tt.expected, hunk) + } + }) + } +} diff --git a/x/gov/types/v1/msgs.go b/x/gov/types/v1/msgs.go index 3e4dd5c1a..6b0103719 100644 --- a/x/gov/types/v1/msgs.go +++ b/x/gov/types/v1/msgs.go @@ -323,6 +323,13 @@ func (msg MsgUpdateParams) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{authority} } +func NewMsgProposeConstitutionAmendment(authority sdk.AccAddress, amendment string) *MsgProposeConstitutionAmendment { + return &MsgProposeConstitutionAmendment{ + Authority: authority.String(), + Amendment: amendment, + } +} + // Route implements the sdk.Msg interface. func (msg MsgProposeConstitutionAmendment) Route() string { return types.RouterKey } @@ -335,6 +342,15 @@ func (msg MsgProposeConstitutionAmendment) ValidateBasic() error { return sdkerrors.ErrInvalidAddress.Wrapf("invalid authority address: %s", err) } + if msg.Amendment == "" { + return types.ErrInvalidProposalContent.Wrap("amendment cannot be empty") + } + + _, err := types.ParseUnifiedDiff(msg.Amendment) + if err != nil { + return types.ErrInvalidProposalContent.Wrap(err.Error()) + } + return nil } diff --git a/x/gov/types/v1/msgs_test.go b/x/gov/types/v1/msgs_test.go index d8cffa7eb..f3b2370ce 100644 --- a/x/gov/types/v1/msgs_test.go +++ b/x/gov/types/v1/msgs_test.go @@ -210,3 +210,28 @@ func TestMsgSubmitProposal_GetSignBytes(t *testing.T) { }) } } + +func TestMsgProposeConstitutionAmendment_ValidateBasic(t *testing.T) { + tests := []struct { + name string + proposer string + amendment string + expErr bool + }{ + {"invalid proposer", "", "amendment", true}, + {"empty amendment", addrs[0].String(), "", true}, + {"valid", addrs[0].String(), "@@ -1 +1 @@\n-\n+Test", false}, + } + + for _, tc := range tests { + msg := v1.MsgProposeConstitutionAmendment{ + Authority: tc.proposer, + Amendment: tc.amendment, + } + if tc.expErr { + require.Error(t, msg.ValidateBasic(), "test: %s", tc.name) + } else { + require.NoError(t, msg.ValidateBasic(), "test: %s", tc.name) + } + } +} diff --git a/x/gov/types/v1/query.pb.go b/x/gov/types/v1/query.pb.go index 884a45380..83c14285a 100644 --- a/x/gov/types/v1/query.pb.go +++ b/x/gov/types/v1/query.pb.go @@ -999,72 +999,72 @@ func init() { func init() { proto.RegisterFile("atomone/gov/v1/query.proto", fileDescriptor_2290d0188dd70223) } var fileDescriptor_2290d0188dd70223 = []byte{ - // 1033 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x5f, 0x6f, 0xdc, 0x44, - 0x10, 0x8f, 0x2f, 0x7f, 0x9a, 0x9b, 0xa4, 0x01, 0x86, 0xd0, 0x3a, 0x4e, 0x7b, 0xb4, 0x6e, 0x48, - 0xd2, 0x8a, 0xd8, 0x5c, 0x4a, 0x5a, 0x84, 0x28, 0x88, 0x50, 0x1a, 0xfa, 0x80, 0x14, 0xdc, 0x8a, - 0x07, 0x5e, 0x22, 0x27, 0x67, 0xb9, 0x96, 0x2e, 0x5e, 0xf7, 0x76, 0xef, 0x44, 0x14, 0x4e, 0x95, - 0x90, 0x90, 0x80, 0xa7, 0x22, 0x84, 0x10, 0xfd, 0x1c, 0x7c, 0x08, 0x1e, 0x2b, 0x78, 0xe1, 0x11, - 0x25, 0x7c, 0x0d, 0x24, 0xe4, 0xdd, 0xb1, 0xcf, 0x76, 0x7c, 0x7f, 0x52, 0x45, 0x7d, 0xf4, 0xee, - 0x6f, 0x7e, 0xf3, 0x9b, 0xd9, 0xd9, 0x99, 0x35, 0x18, 0xae, 0x60, 0xfb, 0x2c, 0xf4, 0x6c, 0x9f, - 0x75, 0xec, 0x4e, 0xdd, 0x7e, 0xdc, 0xf6, 0x5a, 0x07, 0x56, 0xd4, 0x62, 0x82, 0xe1, 0x1c, 0xed, - 0x59, 0x3e, 0xeb, 0x58, 0x9d, 0xba, 0x71, 0x63, 0x8f, 0xf1, 0x7d, 0xc6, 0xed, 0x5d, 0x97, 0x7b, - 0x0a, 0x68, 0x77, 0xea, 0xbb, 0x9e, 0x70, 0xeb, 0x76, 0xe4, 0xfa, 0x41, 0xe8, 0x8a, 0x80, 0x85, - 0xca, 0xd6, 0xb8, 0xe4, 0x33, 0xe6, 0x37, 0x3d, 0xdb, 0x8d, 0x02, 0xdb, 0x0d, 0x43, 0x26, 0xe4, - 0x26, 0xa7, 0x5d, 0xbd, 0xe0, 0x35, 0x76, 0xa0, 0x76, 0x16, 0x94, 0x8f, 0x1d, 0xf9, 0x65, 0xab, - 0x0f, 0xb5, 0x65, 0x1a, 0xa0, 0x7f, 0x11, 0x3b, 0xfd, 0x84, 0x85, 0x5c, 0x04, 0xa2, 0x1d, 0x13, - 0x3a, 0xde, 0xe3, 0xb6, 0xc7, 0x85, 0xf9, 0x11, 0x2c, 0x94, 0xec, 0xf1, 0x88, 0x85, 0xdc, 0x43, - 0x13, 0x66, 0xf7, 0x32, 0xeb, 0xba, 0x76, 0x45, 0x5b, 0xad, 0x3a, 0xb9, 0x35, 0xf3, 0x36, 0xcc, - 0x4b, 0x82, 0xed, 0x16, 0x8b, 0x18, 0x77, 0x9b, 0x44, 0x8c, 0x6f, 0xc2, 0x4c, 0x44, 0x4b, 0x3b, - 0x41, 0x43, 0x9a, 0x4e, 0x38, 0x90, 0x2c, 0xdd, 0x6f, 0x98, 0x9f, 0xc3, 0x1b, 0x05, 0x43, 0xf2, - 0xfa, 0x2e, 0x4c, 0x27, 0x30, 0x69, 0x36, 0xb3, 0xae, 0x5b, 0xf9, 0x84, 0x5a, 0xa9, 0x4d, 0x8a, - 0x34, 0x9f, 0x56, 0x0a, 0x7c, 0x3c, 0x51, 0xb2, 0x05, 0xaf, 0xa4, 0x4a, 0xb8, 0x70, 0x45, 0x9b, - 0x4b, 0xda, 0xb9, 0xf5, 0x5a, 0x3f, 0xda, 0x07, 0x12, 0xe5, 0xcc, 0x45, 0xb9, 0x6f, 0xb4, 0x60, - 0xb2, 0xc3, 0x84, 0xd7, 0xd2, 0x2b, 0x71, 0x1e, 0x36, 0xf5, 0x3f, 0x7f, 0x5f, 0x9b, 0xa7, 0x44, - 0x7f, 0xdc, 0x68, 0xb4, 0x3c, 0xce, 0x1f, 0x88, 0x56, 0x10, 0xfa, 0x8e, 0x82, 0xe1, 0x2d, 0xa8, - 0x36, 0xbc, 0x88, 0xf1, 0x40, 0xb0, 0x96, 0x3e, 0x3e, 0xc4, 0xa6, 0x07, 0xc5, 0x7b, 0x00, 0xbd, - 0xb2, 0xd0, 0x27, 0x64, 0x0a, 0x96, 0x2d, 0xb2, 0x8a, 0x6b, 0xc8, 0x52, 0xc5, 0x46, 0x35, 0x64, - 0x6d, 0xbb, 0xbe, 0x47, 0xc1, 0x3a, 0x19, 0x4b, 0xf3, 0x37, 0x0d, 0x2e, 0x14, 0x53, 0x42, 0x39, - 0xbe, 0x05, 0xd5, 0x24, 0xb8, 0x38, 0x1b, 0xe3, 0x03, 0x93, 0xdc, 0x83, 0xe2, 0x56, 0x4e, 0x5a, - 0x45, 0x4a, 0x5b, 0x19, 0x2a, 0x4d, 0x39, 0xcd, 0x69, 0xdb, 0x83, 0x57, 0xa5, 0xb4, 0x2f, 0x99, - 0xf0, 0x46, 0x2d, 0x99, 0xd3, 0x1e, 0x80, 0x79, 0x07, 0x5e, 0xcb, 0x38, 0xa1, 0xd0, 0x57, 0x61, - 0x22, 0xde, 0xa5, 0xd2, 0x9a, 0x2f, 0x46, 0x2d, 0xb1, 0x12, 0x61, 0x7e, 0x93, 0x31, 0xe7, 0x23, - 0x8b, 0xbc, 0x57, 0x92, 0xa2, 0x17, 0x39, 0xbd, 0x1f, 0x34, 0xc0, 0xac, 0x7b, 0x92, 0x7f, 0x43, - 0xe5, 0x20, 0x39, 0xb5, 0x72, 0xfd, 0x0a, 0x72, 0x76, 0xa7, 0xb5, 0x41, 0x52, 0xb6, 0xdd, 0x96, - 0xbb, 0x9f, 0x4b, 0x85, 0x5c, 0xd8, 0x11, 0x07, 0x91, 0x47, 0xdd, 0x01, 0xd4, 0xd2, 0xc3, 0x83, - 0xc8, 0x33, 0x9f, 0x55, 0xe0, 0xf5, 0x9c, 0x1d, 0xc5, 0xf0, 0x29, 0x9c, 0xef, 0x30, 0x11, 0x84, - 0xfe, 0x8e, 0x02, 0xd3, 0x59, 0x5c, 0x2a, 0x89, 0x25, 0x08, 0x7d, 0x65, 0xbc, 0x59, 0xd1, 0x35, - 0x67, 0xb6, 0x93, 0x59, 0xc1, 0xcf, 0x60, 0x8e, 0x2e, 0x4d, 0xc2, 0xa3, 0x42, 0xbc, 0x5c, 0xe4, - 0xb9, 0xab, 0x50, 0x19, 0xa2, 0xf3, 0x8d, 0xec, 0x12, 0x6e, 0xc2, 0xac, 0x70, 0x9b, 0xcd, 0x83, - 0x84, 0x67, 0x5c, 0xf2, 0x2c, 0x16, 0x79, 0x1e, 0xc6, 0x98, 0x0c, 0xcb, 0x8c, 0xe8, 0x2d, 0xa0, - 0x05, 0x53, 0x64, 0xad, 0x6e, 0xec, 0x85, 0x13, 0xf7, 0x49, 0x25, 0x81, 0x50, 0x66, 0x48, 0xb9, - 0x21, 0x71, 0x23, 0xd7, 0x57, 0xae, 0xab, 0x54, 0x46, 0xee, 0x2a, 0xe6, 0x7d, 0x6a, 0xd4, 0xa9, - 0x3f, 0x3a, 0x8c, 0x3a, 0x9c, 0x23, 0x10, 0x1d, 0xc3, 0xc5, 0x3e, 0xe9, 0x73, 0x12, 0x9c, 0xf9, - 0x24, 0x4f, 0xf5, 0xf2, 0xef, 0xc6, 0x2f, 0x1a, 0x35, 0xfb, 0x9e, 0x02, 0x8a, 0xe6, 0x26, 0x4c, - 0x93, 0xca, 0xe4, 0x86, 0xf4, 0x0d, 0x27, 0x05, 0x9e, 0xdd, 0x3d, 0x79, 0x1f, 0x2e, 0x4a, 0x59, - 0xb2, 0x50, 0x1c, 0x8f, 0xb7, 0x9b, 0xe2, 0x14, 0xf3, 0x50, 0x3f, 0x69, 0x9b, 0x9e, 0xd1, 0xa4, - 0x2c, 0x35, 0x3a, 0xa1, 0xf2, 0xc2, 0x24, 0x1b, 0x85, 0x5c, 0xff, 0xaf, 0x0a, 0x93, 0x92, 0x0f, - 0xbf, 0xd7, 0x60, 0x36, 0x3b, 0xde, 0x71, 0xb5, 0x68, 0xde, 0xef, 0x75, 0x60, 0x5c, 0x1f, 0x01, - 0xa9, 0x24, 0x9a, 0xd7, 0xbe, 0xfd, 0xeb, 0xdf, 0x9f, 0x2b, 0x97, 0x71, 0x91, 0xde, 0x1e, 0xc9, - 0x0b, 0x25, 0xfb, 0x58, 0x88, 0xa5, 0x4c, 0x27, 0x63, 0x05, 0x97, 0x4a, 0xc9, 0x0b, 0xef, 0x08, - 0xe3, 0xad, 0x21, 0x28, 0x72, 0x6f, 0x4b, 0xf7, 0xd7, 0x71, 0xc5, 0x2e, 0xbc, 0x90, 0xd2, 0xd9, - 0x65, 0x1f, 0x66, 0xf2, 0xdf, 0xc5, 0x2e, 0x54, 0xd3, 0xb1, 0x88, 0x83, 0x9d, 0x24, 0xf5, 0x6d, - 0x2c, 0x0f, 0x83, 0x91, 0x98, 0xab, 0x52, 0xcc, 0x22, 0x2e, 0xf4, 0x15, 0x83, 0x3f, 0x6a, 0x30, - 0x11, 0xb7, 0x6a, 0xbc, 0x52, 0xca, 0x99, 0x19, 0x8b, 0xc6, 0xd5, 0x01, 0x08, 0x72, 0x78, 0x47, - 0x3a, 0xbc, 0x8d, 0x1b, 0x23, 0x46, 0x6f, 0xcb, 0xf9, 0x60, 0x1f, 0xca, 0x31, 0xd9, 0xc5, 0xef, - 0x34, 0x98, 0x94, 0x53, 0x06, 0xfb, 0xfb, 0x4a, 0x93, 0x60, 0x0e, 0x82, 0x90, 0x9e, 0x0d, 0xa9, - 0xc7, 0xc6, 0xb5, 0x53, 0xe9, 0xc1, 0x27, 0x30, 0x45, 0xcd, 0xb4, 0xdc, 0x49, 0x6e, 0xfc, 0x18, - 0xd7, 0x06, 0x62, 0x48, 0xc9, 0xdb, 0x52, 0xc9, 0x32, 0x2e, 0x9d, 0x50, 0x22, 0x71, 0xf6, 0x61, - 0x66, 0x82, 0x75, 0xf1, 0x99, 0x06, 0xe7, 0xa8, 0x3d, 0x60, 0x39, 0x7d, 0xbe, 0x5b, 0x1b, 0x4b, - 0x83, 0x41, 0x24, 0xe2, 0xae, 0x14, 0xf1, 0x21, 0x7e, 0x30, 0x6a, 0x3a, 0x92, 0xce, 0x64, 0x1f, - 0xa6, 0xfd, 0xbb, 0x8b, 0x3f, 0x69, 0x30, 0x9d, 0xf4, 0x3b, 0x1c, 0xe8, 0x98, 0x0f, 0xbe, 0x3c, - 0xc5, 0xa6, 0x69, 0xbe, 0x27, 0xf5, 0xad, 0xe3, 0x3b, 0xa7, 0xd5, 0x87, 0xbf, 0x6a, 0x30, 0x93, - 0x69, 0x3e, 0xb8, 0x52, 0xea, 0xf0, 0x64, 0x3b, 0x34, 0x56, 0x87, 0x03, 0x5f, 0xb4, 0x96, 0x64, - 0xff, 0xdb, 0xdc, 0xfa, 0xe3, 0xa8, 0xa6, 0x3d, 0x3f, 0xaa, 0x69, 0xff, 0x1c, 0xd5, 0xb4, 0xa7, - 0xc7, 0xb5, 0xb1, 0xe7, 0xc7, 0xb5, 0xb1, 0xbf, 0x8f, 0x6b, 0x63, 0x5f, 0xad, 0xf9, 0x81, 0x78, - 0xd4, 0xde, 0xb5, 0xf6, 0xd8, 0x7e, 0x42, 0xb9, 0xf6, 0xa8, 0xbd, 0x9b, 0xd2, 0x7f, 0x2d, 0x1d, - 0xc4, 0x05, 0xc1, 0xe3, 0xdf, 0xb4, 0x29, 0xf9, 0x13, 0x75, 0xf3, 0xff, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x3d, 0x6b, 0xab, 0x63, 0xf1, 0x0d, 0x00, 0x00, + // 1030 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x5d, 0x6f, 0xdc, 0x44, + 0x14, 0x8d, 0x37, 0x1f, 0xcd, 0xde, 0xa4, 0x01, 0x2e, 0xa1, 0x75, 0xdc, 0xb0, 0xb4, 0x26, 0x24, + 0x69, 0x45, 0x6c, 0x36, 0x25, 0x2d, 0x42, 0x14, 0x44, 0x28, 0x0d, 0x7d, 0x40, 0x0a, 0x6e, 0xc5, + 0x03, 0x2f, 0x91, 0x93, 0xb5, 0x5c, 0x4b, 0x1b, 0x8f, 0xbb, 0x33, 0xbb, 0x22, 0x0a, 0xab, 0x4a, + 0x48, 0x48, 0x94, 0xa7, 0x22, 0x84, 0x10, 0xfd, 0x1d, 0xfc, 0x08, 0x1e, 0x2b, 0x78, 0xe1, 0x11, + 0x25, 0xfc, 0x0e, 0x84, 0x3c, 0x73, 0xed, 0xb5, 0x1d, 0xef, 0x57, 0x55, 0xf1, 0xb8, 0x33, 0xe7, + 0x9e, 0x73, 0xe6, 0xce, 0x9d, 0x7b, 0xbd, 0x60, 0xb8, 0x82, 0x1d, 0xb2, 0xd0, 0xb3, 0x7d, 0xd6, + 0xb1, 0x3b, 0x75, 0xfb, 0x61, 0xdb, 0x6b, 0x1d, 0x59, 0x51, 0x8b, 0x09, 0x86, 0x0b, 0xb4, 0x67, + 0xf9, 0xac, 0x63, 0x75, 0xea, 0xc6, 0xb5, 0x03, 0xc6, 0x0f, 0x19, 0xb7, 0xf7, 0x5d, 0xee, 0x29, + 0xa0, 0xdd, 0xa9, 0xef, 0x7b, 0xc2, 0xad, 0xdb, 0x91, 0xeb, 0x07, 0xa1, 0x2b, 0x02, 0x16, 0xaa, + 0x58, 0x63, 0xd9, 0x67, 0xcc, 0x6f, 0x7a, 0xb6, 0x1b, 0x05, 0xb6, 0x1b, 0x86, 0x4c, 0xc8, 0x4d, + 0x4e, 0xbb, 0x7a, 0x41, 0x35, 0x16, 0x50, 0x3b, 0x4b, 0x4a, 0x63, 0x4f, 0xfe, 0xb2, 0xd5, 0x0f, + 0xb5, 0x65, 0x1a, 0xa0, 0x7f, 0x11, 0x8b, 0x7e, 0xc2, 0x42, 0x2e, 0x02, 0xd1, 0x8e, 0x09, 0x1d, + 0xef, 0x61, 0xdb, 0xe3, 0xc2, 0xfc, 0x08, 0x96, 0x4a, 0xf6, 0x78, 0xc4, 0x42, 0xee, 0xa1, 0x09, + 0xf3, 0x07, 0x99, 0x75, 0x5d, 0xbb, 0xac, 0xad, 0x57, 0x9d, 0xdc, 0x9a, 0x79, 0x13, 0x16, 0x25, + 0xc1, 0x6e, 0x8b, 0x45, 0x8c, 0xbb, 0x4d, 0x22, 0xc6, 0x37, 0x60, 0x2e, 0xa2, 0xa5, 0xbd, 0xa0, + 0x21, 0x43, 0xa7, 0x1c, 0x48, 0x96, 0xee, 0x36, 0xcc, 0xcf, 0xe1, 0xb5, 0x42, 0x20, 0xa9, 0xbe, + 0x0b, 0xb3, 0x09, 0x4c, 0x86, 0xcd, 0x6d, 0xea, 0x56, 0x3e, 0xa1, 0x56, 0x1a, 0x93, 0x22, 0xcd, + 0x27, 0x95, 0x02, 0x1f, 0x4f, 0x9c, 0xec, 0xc0, 0x4b, 0xa9, 0x13, 0x2e, 0x5c, 0xd1, 0xe6, 0x92, + 0x76, 0x61, 0xb3, 0xd6, 0x8f, 0xf6, 0x9e, 0x44, 0x39, 0x0b, 0x51, 0xee, 0x37, 0x5a, 0x30, 0xdd, + 0x61, 0xc2, 0x6b, 0xe9, 0x95, 0x38, 0x0f, 0xdb, 0xfa, 0x1f, 0xbf, 0x6d, 0x2c, 0x52, 0xa2, 0x3f, + 0x6e, 0x34, 0x5a, 0x1e, 0xe7, 0xf7, 0x44, 0x2b, 0x08, 0x7d, 0x47, 0xc1, 0xf0, 0x06, 0x54, 0x1b, + 0x5e, 0xc4, 0x78, 0x20, 0x58, 0x4b, 0x9f, 0x1c, 0x12, 0xd3, 0x83, 0xe2, 0x1d, 0x80, 0x5e, 0x59, + 0xe8, 0x53, 0x32, 0x05, 0xab, 0x16, 0x45, 0xc5, 0x35, 0x64, 0xa9, 0x62, 0xa3, 0x1a, 0xb2, 0x76, + 0x5d, 0xdf, 0xa3, 0xc3, 0x3a, 0x99, 0x48, 0xf3, 0x57, 0x0d, 0x2e, 0x14, 0x53, 0x42, 0x39, 0xbe, + 0x01, 0xd5, 0xe4, 0x70, 0x71, 0x36, 0x26, 0x07, 0x26, 0xb9, 0x07, 0xc5, 0x9d, 0x9c, 0xb5, 0x8a, + 0xb4, 0xb6, 0x36, 0xd4, 0x9a, 0x12, 0xcd, 0x79, 0x3b, 0x80, 0x97, 0xa5, 0xb5, 0x2f, 0x99, 0xf0, + 0x46, 0x2d, 0x99, 0x71, 0x2f, 0xc0, 0xbc, 0x05, 0xaf, 0x64, 0x44, 0xe8, 0xe8, 0xeb, 0x30, 0x15, + 0xef, 0x52, 0x69, 0x2d, 0x16, 0x4f, 0x2d, 0xb1, 0x12, 0x61, 0x7e, 0x93, 0x09, 0xe7, 0x23, 0x9b, + 0xbc, 0x53, 0x92, 0xa2, 0xe7, 0xb9, 0xbd, 0xc7, 0x1a, 0x60, 0x56, 0x9e, 0xec, 0x5f, 0x53, 0x39, + 0x48, 0x6e, 0xad, 0xdc, 0xbf, 0x82, 0xbc, 0xb8, 0xdb, 0xda, 0x22, 0x2b, 0xbb, 0x6e, 0xcb, 0x3d, + 0xcc, 0xa5, 0x42, 0x2e, 0xec, 0x89, 0xa3, 0xc8, 0xa3, 0xee, 0x00, 0x6a, 0xe9, 0xfe, 0x51, 0xe4, + 0x99, 0x4f, 0x2b, 0xf0, 0x6a, 0x2e, 0x8e, 0xce, 0xf0, 0x29, 0x9c, 0xef, 0x30, 0x11, 0x84, 0xfe, + 0x9e, 0x02, 0xd3, 0x5d, 0x2c, 0x97, 0x9c, 0x25, 0x08, 0x7d, 0x15, 0xbc, 0x5d, 0xd1, 0x35, 0x67, + 0xbe, 0x93, 0x59, 0xc1, 0xcf, 0x60, 0x81, 0x1e, 0x4d, 0xc2, 0xa3, 0x8e, 0xf8, 0x7a, 0x91, 0xe7, + 0xb6, 0x42, 0x65, 0x88, 0xce, 0x37, 0xb2, 0x4b, 0xb8, 0x0d, 0xf3, 0xc2, 0x6d, 0x36, 0x8f, 0x12, + 0x9e, 0x49, 0xc9, 0x73, 0xa9, 0xc8, 0x73, 0x3f, 0xc6, 0x64, 0x58, 0xe6, 0x44, 0x6f, 0x01, 0x2d, + 0x98, 0xa1, 0x68, 0xf5, 0x62, 0x2f, 0x9c, 0x79, 0x4f, 0x2a, 0x09, 0x84, 0x32, 0x43, 0xca, 0x0d, + 0x99, 0x1b, 0xb9, 0xbe, 0x72, 0x5d, 0xa5, 0x32, 0x72, 0x57, 0x31, 0xef, 0x52, 0xa3, 0x4e, 0xf5, + 0xe8, 0x32, 0xea, 0x70, 0x8e, 0x40, 0x74, 0x0d, 0x17, 0xfb, 0xa4, 0xcf, 0x49, 0x70, 0xe6, 0xa3, + 0x3c, 0xd5, 0xff, 0xff, 0x36, 0x7e, 0xd6, 0xa8, 0xd9, 0xf7, 0x1c, 0xd0, 0x69, 0xae, 0xc3, 0x2c, + 0xb9, 0x4c, 0x5e, 0x48, 0xdf, 0xe3, 0xa4, 0xc0, 0x17, 0xf7, 0x4e, 0xde, 0x87, 0x8b, 0xd2, 0x96, + 0x2c, 0x14, 0xc7, 0xe3, 0xed, 0xa6, 0x18, 0x63, 0x1e, 0xea, 0x67, 0x63, 0xd3, 0x3b, 0x9a, 0x96, + 0xa5, 0x46, 0x37, 0x54, 0x5e, 0x98, 0x14, 0xa3, 0x90, 0x9b, 0xff, 0x56, 0x61, 0x5a, 0xf2, 0xe1, + 0x63, 0x0d, 0xe6, 0xb3, 0xe3, 0x1d, 0xd7, 0x8b, 0xe1, 0xfd, 0xbe, 0x0e, 0x8c, 0xab, 0x23, 0x20, + 0x95, 0x45, 0x73, 0xe5, 0xdb, 0x3f, 0xff, 0xf9, 0xa9, 0x52, 0xc3, 0x65, 0xbb, 0xf0, 0x89, 0x92, + 0xfd, 0x5a, 0xc0, 0xef, 0x35, 0x98, 0x4d, 0xe6, 0x0a, 0xae, 0x94, 0xb2, 0x17, 0x3e, 0x24, 0x8c, + 0xb7, 0x86, 0xa0, 0x48, 0xdf, 0x96, 0xfa, 0x57, 0x71, 0xad, 0xa8, 0x9f, 0x0e, 0x2f, 0xfb, 0x38, + 0x73, 0x01, 0x5d, 0xec, 0x42, 0x35, 0x9d, 0x8b, 0x38, 0x58, 0x24, 0x29, 0x70, 0x63, 0x75, 0x18, + 0x8c, 0xcc, 0x5c, 0x91, 0x66, 0x2e, 0xe1, 0x52, 0x5f, 0x33, 0xf8, 0x83, 0x06, 0x53, 0x71, 0xaf, + 0xc6, 0xcb, 0xa5, 0x9c, 0x99, 0xb9, 0x68, 0x5c, 0x19, 0x80, 0x20, 0xc1, 0x5b, 0x52, 0xf0, 0x26, + 0x6e, 0x8d, 0x78, 0x7a, 0x5b, 0x0e, 0x08, 0xfb, 0x58, 0xce, 0xc9, 0x2e, 0x7e, 0xa7, 0xc1, 0xb4, + 0x1c, 0x33, 0xd8, 0x5f, 0x2b, 0x4d, 0x82, 0x39, 0x08, 0x42, 0x7e, 0xb6, 0xa4, 0x1f, 0x1b, 0x37, + 0xc6, 0xf2, 0x83, 0x8f, 0x60, 0x86, 0xba, 0x69, 0xb9, 0x48, 0x6e, 0xfe, 0x18, 0x6f, 0x0e, 0xc4, + 0x90, 0x93, 0xb7, 0xa5, 0x93, 0x55, 0x5c, 0x39, 0xe3, 0x44, 0xe2, 0xec, 0xe3, 0xcc, 0x08, 0xeb, + 0xe2, 0x53, 0x0d, 0xce, 0x51, 0x7f, 0xc0, 0x72, 0xfa, 0x7c, 0xbb, 0x36, 0x56, 0x06, 0x83, 0xc8, + 0xc4, 0x6d, 0x69, 0xe2, 0x43, 0xfc, 0x60, 0xd4, 0x74, 0x24, 0xad, 0xc9, 0x3e, 0x4e, 0x1b, 0x78, + 0x17, 0x7f, 0xd4, 0x60, 0x36, 0x69, 0x78, 0x38, 0x50, 0x98, 0x0f, 0x7e, 0x3c, 0xc5, 0xae, 0x69, + 0xbe, 0x27, 0xfd, 0x6d, 0xe2, 0x3b, 0xe3, 0xfa, 0xc3, 0x5f, 0x34, 0x98, 0xcb, 0x74, 0x1f, 0x5c, + 0x2b, 0x15, 0x3c, 0xdb, 0x0f, 0x8d, 0xf5, 0xe1, 0xc0, 0xe7, 0xad, 0x25, 0xd9, 0x00, 0xb7, 0x77, + 0x7e, 0x3f, 0xa9, 0x69, 0xcf, 0x4e, 0x6a, 0xda, 0xdf, 0x27, 0x35, 0xed, 0xc9, 0x69, 0x6d, 0xe2, + 0xd9, 0x69, 0x6d, 0xe2, 0xaf, 0xd3, 0xda, 0xc4, 0x57, 0x1b, 0x7e, 0x20, 0x1e, 0xb4, 0xf7, 0xad, + 0x03, 0x76, 0x98, 0x50, 0x6e, 0x3c, 0x68, 0xef, 0xa7, 0xf4, 0x5f, 0x4b, 0x81, 0xb8, 0x20, 0x78, + 0xfc, 0x3f, 0x6d, 0x46, 0xfe, 0x8b, 0xba, 0xfe, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x17, 0xab, + 0xa6, 0x19, 0xf2, 0x0d, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/gov/types/v1/query.pb.gw.go b/x/gov/types/v1/query.pb.gw.go index 58b486404..c0047cfbf 100644 --- a/x/gov/types/v1/query.pb.gw.go +++ b/x/gov/types/v1/query.pb.gw.go @@ -983,7 +983,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Constitution_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "gov", "v1", "constitution"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_Constitution_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"atomone", "gov", "v1", "constitution"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_Proposal_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"atomone", "gov", "v1", "proposals", "proposal_id"}, "", runtime.AssumeColonVerbOpt(false))) diff --git a/x/gov/types/v1/tx.pb.go b/x/gov/types/v1/tx.pb.go index b0aaf6744..7dd0c1abc 100644 --- a/x/gov/types/v1/tx.pb.go +++ b/x/gov/types/v1/tx.pb.go @@ -780,6 +780,8 @@ type MsgProposeConstitutionAmendment struct { // authority is the address that controls the module (defaults to x/gov unless // overwritten). Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // amendment is the amendment to the constitution. It must be in valid GNU patch format. + Amendment string `protobuf:"bytes,2,opt,name=amendment,proto3" json:"amendment,omitempty"` } func (m *MsgProposeConstitutionAmendment) Reset() { *m = MsgProposeConstitutionAmendment{} } @@ -822,6 +824,13 @@ func (m *MsgProposeConstitutionAmendment) GetAuthority() string { return "" } +func (m *MsgProposeConstitutionAmendment) GetAmendment() string { + if m != nil { + return m.Amendment + } + return "" +} + // MsgProposeConstitutionAmendmentResponse defines the response structure for executing a // MsgProposeConstitutionAmendment message. type MsgProposeConstitutionAmendmentResponse struct { @@ -884,71 +893,72 @@ func init() { func init() { proto.RegisterFile("atomone/gov/v1/tx.proto", fileDescriptor_f6c84786701fca8d) } var fileDescriptor_f6c84786701fca8d = []byte{ - // 1020 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0xcf, 0x6f, 0x1b, 0x45, - 0x14, 0xce, 0x26, 0xb1, 0xdd, 0xbc, 0x40, 0xaa, 0xac, 0x5c, 0xbc, 0x59, 0x82, 0x9d, 0xae, 0x8a, - 0x9a, 0x44, 0x64, 0x17, 0xbb, 0x40, 0x85, 0x95, 0x03, 0x71, 0x40, 0xa8, 0x52, 0xad, 0x56, 0xae, - 0xf8, 0x21, 0x0e, 0x44, 0x63, 0x7b, 0x98, 0xac, 0x94, 0xdd, 0x59, 0x79, 0xc6, 0x26, 0xe6, 0x84, - 0x38, 0x21, 0x4e, 0x88, 0xbf, 0x82, 0x63, 0x0e, 0xbd, 0xf4, 0x1f, 0x40, 0x15, 0xa7, 0x8a, 0x13, - 0xa7, 0x0a, 0x25, 0x87, 0x48, 0xdc, 0x39, 0x22, 0xa1, 0xd9, 0x99, 0x5d, 0x7b, 0xbd, 0x6b, 0x3b, - 0xe4, 0xd0, 0x8b, 0xb5, 0xf3, 0xde, 0xfb, 0xde, 0x7c, 0xef, 0x9b, 0xf7, 0x66, 0x0c, 0x25, 0xc4, - 0xa9, 0x47, 0x7d, 0xec, 0x10, 0x3a, 0x70, 0x06, 0x55, 0x87, 0x9f, 0xda, 0x41, 0x8f, 0x72, 0xaa, - 0xaf, 0x29, 0x87, 0x4d, 0xe8, 0xc0, 0x1e, 0x54, 0xcd, 0x72, 0x87, 0x32, 0x8f, 0x32, 0xa7, 0x8d, - 0x18, 0x76, 0x06, 0xd5, 0x36, 0xe6, 0xa8, 0xea, 0x74, 0xa8, 0xeb, 0xcb, 0x78, 0xd3, 0x98, 0x48, - 0x24, 0x60, 0xd2, 0x53, 0x24, 0x94, 0xd0, 0xf0, 0xd3, 0x11, 0x5f, 0xca, 0xba, 0x21, 0xf3, 0x1d, - 0x49, 0x87, 0x5c, 0x44, 0x2e, 0x42, 0x29, 0x39, 0xc1, 0x4e, 0xb8, 0x6a, 0xf7, 0xbf, 0x71, 0x90, - 0x3f, 0x54, 0xae, 0x92, 0x62, 0xe1, 0x31, 0x22, 0x36, 0xf1, 0x18, 0x51, 0x8e, 0x75, 0xe4, 0xb9, - 0x3e, 0x75, 0xc2, 0x5f, 0x69, 0xb2, 0x7e, 0x5b, 0x84, 0xf5, 0x26, 0x23, 0x4f, 0xfa, 0x6d, 0xcf, - 0xe5, 0x8f, 0x7b, 0x34, 0xa0, 0x0c, 0x9d, 0xe8, 0xef, 0xc2, 0x0d, 0x0f, 0x33, 0x86, 0x08, 0x66, - 0x86, 0xb6, 0xb5, 0xb4, 0xbd, 0x5a, 0x2b, 0xda, 0x72, 0x3f, 0x3b, 0xda, 0xcf, 0x3e, 0xf0, 0x87, - 0xad, 0x38, 0x4a, 0x6f, 0xc2, 0x4d, 0xd7, 0x77, 0xb9, 0x8b, 0x4e, 0x8e, 0xba, 0x38, 0xa0, 0xcc, - 0xe5, 0xc6, 0x62, 0x08, 0xdc, 0xb0, 0x15, 0x6d, 0xa1, 0x89, 0xad, 0x34, 0xb1, 0x0f, 0xa9, 0xeb, - 0x37, 0x56, 0x9e, 0xbf, 0xac, 0x2c, 0xfc, 0x7a, 0x79, 0xb6, 0xab, 0xb5, 0xd6, 0x14, 0xf8, 0x63, - 0x89, 0xd5, 0xdf, 0x83, 0x1b, 0x41, 0x48, 0x06, 0xf7, 0x8c, 0xa5, 0x2d, 0x6d, 0x7b, 0xa5, 0x61, - 0xfc, 0xf1, 0x74, 0xaf, 0xa8, 0x52, 0x1d, 0x74, 0xbb, 0x3d, 0xcc, 0xd8, 0x13, 0xde, 0x73, 0x7d, - 0xd2, 0x8a, 0x23, 0x75, 0x53, 0xd0, 0xe6, 0xa8, 0x8b, 0x38, 0x32, 0x96, 0x05, 0xaa, 0x15, 0xaf, - 0xf5, 0x22, 0xe4, 0xb8, 0xcb, 0x4f, 0xb0, 0x91, 0x0b, 0x1d, 0x72, 0xa1, 0x1b, 0x50, 0x60, 0x7d, - 0xcf, 0x43, 0xbd, 0xa1, 0x91, 0x0f, 0xed, 0xd1, 0xb2, 0x6e, 0xff, 0x70, 0x79, 0xb6, 0x1b, 0xa7, - 0xfe, 0xe9, 0xf2, 0x6c, 0x77, 0x33, 0x3a, 0xbc, 0x41, 0xd5, 0x49, 0x49, 0x66, 0xed, 0xc3, 0x46, - 0xca, 0xd8, 0xc2, 0x2c, 0xa0, 0x3e, 0xc3, 0x7a, 0x05, 0x56, 0x03, 0x65, 0x3b, 0x72, 0xbb, 0x86, - 0xb6, 0xa5, 0x6d, 0x2f, 0xb7, 0x20, 0x32, 0x3d, 0xe8, 0x5a, 0xcf, 0x34, 0x28, 0x36, 0x19, 0xf9, - 0xe4, 0x14, 0x77, 0x1e, 0x62, 0x82, 0x3a, 0xc3, 0x43, 0xea, 0x73, 0xec, 0x73, 0xfd, 0x11, 0x14, - 0x3a, 0xf2, 0x33, 0x44, 0x4d, 0x39, 0x88, 0x46, 0xe5, 0xf7, 0xa7, 0x7b, 0x6f, 0x26, 0x9b, 0x31, - 0x12, 0x3a, 0x04, 0xb7, 0xa2, 0x2c, 0xfa, 0x26, 0xac, 0xa0, 0x3e, 0x3f, 0xa6, 0x3d, 0x97, 0x0f, - 0x8d, 0xc5, 0xb0, 0xe6, 0x91, 0xa1, 0x5e, 0x13, 0x55, 0x8f, 0xd6, 0xa2, 0xec, 0x4a, 0xb2, 0xec, - 0x14, 0x45, 0xab, 0x0c, 0x9b, 0x59, 0xf6, 0xa8, 0x78, 0xeb, 0x42, 0x83, 0x42, 0x93, 0x91, 0xcf, - 0x29, 0xc7, 0xfa, 0xfb, 0x19, 0x42, 0x34, 0x8a, 0x7f, 0xbf, 0xac, 0x8c, 0x9b, 0x65, 0x4b, 0x8c, - 0xc9, 0xa3, 0xdb, 0x90, 0x1b, 0x50, 0x8e, 0x7b, 0x92, 0xf0, 0x8c, 0x5e, 0x90, 0x61, 0x7a, 0x0d, - 0xf2, 0x34, 0xe0, 0x2e, 0xf5, 0xc3, 0xe6, 0x59, 0xab, 0x99, 0x76, 0x52, 0x1b, 0x5b, 0x90, 0x79, - 0x14, 0x46, 0xb4, 0x54, 0xe4, 0xac, 0xe6, 0xa9, 0xdf, 0x16, 0xb2, 0xc8, 0xdc, 0x42, 0x12, 0x3d, - 0x29, 0x89, 0x48, 0x66, 0xad, 0xc3, 0x4d, 0xf5, 0x19, 0x17, 0xfe, 0xaf, 0x16, 0xdb, 0xbe, 0xc0, - 0x2e, 0x39, 0xe6, 0xb8, 0xfb, 0xaa, 0x04, 0xd8, 0x87, 0x82, 0x2c, 0x8b, 0x19, 0x4b, 0xe1, 0x18, - 0x5a, 0x93, 0x0a, 0x44, 0x8c, 0xc6, 0x94, 0x88, 0x20, 0x33, 0xa5, 0xd8, 0x49, 0x4a, 0x61, 0xa6, - 0xa5, 0x88, 0x32, 0x5b, 0x1b, 0x50, 0x9a, 0x30, 0x8d, 0xf7, 0x04, 0x34, 0x19, 0x89, 0xc6, 0xfd, - 0x9a, 0xaa, 0x7c, 0x00, 0x2b, 0xea, 0xb2, 0xa1, 0xf3, 0x95, 0x19, 0x85, 0xea, 0xfb, 0x90, 0x47, - 0x1e, 0xed, 0xfb, 0x5c, 0x89, 0x73, 0xb5, 0x3b, 0x4a, 0x61, 0xea, 0xdb, 0xe1, 0x8c, 0xc4, 0xd9, - 0x84, 0x0a, 0xb7, 0x92, 0x2a, 0xa8, 0xb2, 0xac, 0x22, 0xe8, 0xa3, 0x55, 0x5c, 0xfb, 0x33, 0xd9, - 0x16, 0x9f, 0x05, 0x5d, 0xc4, 0xf1, 0x63, 0xd4, 0x43, 0x1e, 0x13, 0x95, 0x8c, 0xa6, 0x52, 0x9b, - 0x57, 0x49, 0x1c, 0xaa, 0x7f, 0x08, 0xf9, 0x20, 0xcc, 0x10, 0x96, 0xbf, 0x5a, 0x7b, 0x63, 0xf2, - 0x98, 0x65, 0xfe, 0x44, 0x19, 0x12, 0x50, 0xbf, 0x97, 0x1e, 0xf5, 0xad, 0xa8, 0x8c, 0xd3, 0xe8, - 0x81, 0x9a, 0xe0, 0xa9, 0x8e, 0x74, 0xdc, 0x14, 0x97, 0xf5, 0x1d, 0xbc, 0xde, 0x64, 0x44, 0x5e, - 0x7d, 0xf8, 0x21, 0xfa, 0xf6, 0xba, 0x35, 0xd5, 0xab, 0x69, 0x62, 0xe5, 0x2c, 0x62, 0xa3, 0xad, - 0xac, 0x12, 0xdc, 0x4a, 0x18, 0x62, 0x52, 0xbf, 0x68, 0x50, 0x19, 0x79, 0x0e, 0xa9, 0xcf, 0xb8, - 0xcb, 0xfb, 0xa2, 0xcb, 0x0f, 0x3c, 0xec, 0x77, 0x3d, 0x71, 0x23, 0x5e, 0x97, 0xe7, 0xfd, 0x34, - 0xcf, 0x3b, 0x33, 0x78, 0xc6, 0x1b, 0x5a, 0x3b, 0x70, 0x77, 0x0e, 0xa7, 0x88, 0x7f, 0xed, 0x9f, - 0x1c, 0x2c, 0x35, 0x19, 0xd1, 0xbf, 0x86, 0xb5, 0x89, 0x27, 0xfa, 0xf6, 0xe4, 0x49, 0xa7, 0x5e, - 0x1f, 0x73, 0x67, 0x6e, 0x48, 0xfc, 0x40, 0x11, 0x58, 0x4f, 0xbf, 0x3d, 0x77, 0x32, 0xf0, 0xa9, - 0x28, 0xf3, 0x9d, 0xab, 0x44, 0xc5, 0x1b, 0x7d, 0x04, 0xcb, 0xe1, 0x43, 0x50, 0xca, 0x40, 0x09, - 0x87, 0x59, 0x99, 0xe2, 0x88, 0x33, 0x7c, 0x09, 0xaf, 0x25, 0x6e, 0xd4, 0x69, 0x80, 0x28, 0xc0, - 0xbc, 0x3b, 0x27, 0x20, 0xce, 0xfc, 0x00, 0x0a, 0xd1, 0x85, 0x64, 0x66, 0x60, 0x94, 0xcf, 0xb4, - 0xa6, 0xfb, 0xc6, 0x49, 0x26, 0xe6, 0x3b, 0x8b, 0xe4, 0x78, 0x40, 0x26, 0xc9, 0xac, 0x31, 0xd3, - 0x5b, 0x00, 0x63, 0x33, 0xf6, 0x56, 0x06, 0x6c, 0xe4, 0x36, 0xdf, 0x9e, 0xe9, 0x8e, 0x73, 0xfe, - 0xa8, 0xc1, 0xe6, 0xcc, 0x11, 0x71, 0xa6, 0xe7, 0xc9, 0x04, 0x98, 0xf7, 0xff, 0x27, 0x20, 0xa2, - 0x62, 0xe6, 0xbe, 0x17, 0x97, 0x54, 0xe3, 0xd3, 0xe7, 0xe7, 0x65, 0xed, 0xc5, 0x79, 0x59, 0xfb, - 0xeb, 0xbc, 0xac, 0xfd, 0x7c, 0x51, 0x5e, 0x78, 0x71, 0x51, 0x5e, 0xf8, 0xf3, 0xa2, 0xbc, 0xf0, - 0xd5, 0x1e, 0x71, 0xf9, 0x71, 0xbf, 0x6d, 0x77, 0xa8, 0xe7, 0xa8, 0x3d, 0xf6, 0x8e, 0xfb, 0x6d, - 0x27, 0x39, 0x79, 0x7c, 0x18, 0x60, 0x26, 0xfe, 0x81, 0xe7, 0xc3, 0xbf, 0x49, 0xf7, 0xfe, 0x0b, - 0x00, 0x00, 0xff, 0xff, 0x9d, 0xc2, 0x7b, 0xc3, 0xc3, 0x0b, 0x00, 0x00, + // 1026 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4d, 0x6f, 0x1b, 0x45, + 0x18, 0xce, 0xe6, 0xb3, 0x79, 0x03, 0xa9, 0xb2, 0x72, 0xf1, 0x66, 0x09, 0x76, 0xba, 0x2a, 0x6a, + 0x12, 0x91, 0x5d, 0xec, 0x02, 0x15, 0x56, 0x0e, 0xc4, 0x01, 0xa1, 0x4a, 0xb5, 0x5a, 0xb9, 0xe2, + 0x43, 0x1c, 0x88, 0xc6, 0xf6, 0x30, 0x59, 0x29, 0xbb, 0xb3, 0xf2, 0x8c, 0x4d, 0xcc, 0x09, 0x71, + 0x42, 0x9c, 0xf8, 0x19, 0x1c, 0x73, 0xe8, 0xa5, 0x7f, 0x00, 0x55, 0x9c, 0x2a, 0x4e, 0x9c, 0x2a, + 0x94, 0x1c, 0x22, 0x71, 0xe7, 0x88, 0x84, 0x66, 0x67, 0x66, 0xed, 0xf5, 0xae, 0xed, 0x92, 0x03, + 0x17, 0x6b, 0xe7, 0xfd, 0x9a, 0xe7, 0x79, 0x66, 0xde, 0x77, 0x0c, 0x45, 0xc4, 0x69, 0x40, 0x43, + 0xec, 0x11, 0xda, 0xf7, 0xfa, 0x15, 0x8f, 0x9f, 0xb9, 0x51, 0x97, 0x72, 0x6a, 0xae, 0x2b, 0x87, + 0x4b, 0x68, 0xdf, 0xed, 0x57, 0xec, 0x52, 0x9b, 0xb2, 0x80, 0x32, 0xaf, 0x85, 0x18, 0xf6, 0xfa, + 0x95, 0x16, 0xe6, 0xa8, 0xe2, 0xb5, 0xa9, 0x1f, 0xca, 0x78, 0xdb, 0x1a, 0x2b, 0x24, 0xd2, 0xa4, + 0xa7, 0x40, 0x28, 0xa1, 0xf1, 0xa7, 0x27, 0xbe, 0x94, 0x75, 0x53, 0xd6, 0x3b, 0x96, 0x0e, 0xb9, + 0xd0, 0x2e, 0x42, 0x29, 0x39, 0xc5, 0x5e, 0xbc, 0x6a, 0xf5, 0xbe, 0xf1, 0x50, 0x38, 0x50, 0xae, + 0xa2, 0x42, 0x11, 0x30, 0x22, 0x36, 0x09, 0x18, 0x51, 0x8e, 0x0d, 0x14, 0xf8, 0x21, 0xf5, 0xe2, + 0x5f, 0x69, 0x72, 0x7e, 0x9d, 0x87, 0x8d, 0x06, 0x23, 0x4f, 0x7a, 0xad, 0xc0, 0xe7, 0x8f, 0xbb, + 0x34, 0xa2, 0x0c, 0x9d, 0x9a, 0xef, 0xc2, 0x8d, 0x00, 0x33, 0x86, 0x08, 0x66, 0x96, 0xb1, 0xbd, + 0xb0, 0xb3, 0x56, 0x2d, 0xb8, 0x72, 0x3f, 0x57, 0xef, 0xe7, 0x1e, 0x86, 0x83, 0x66, 0x12, 0x65, + 0x36, 0xe0, 0xa6, 0x1f, 0xfa, 0xdc, 0x47, 0xa7, 0xc7, 0x1d, 0x1c, 0x51, 0xe6, 0x73, 0x6b, 0x3e, + 0x4e, 0xdc, 0x74, 0x15, 0x6c, 0xa1, 0x89, 0xab, 0x34, 0x71, 0x8f, 0xa8, 0x1f, 0xd6, 0x57, 0x9f, + 0xbf, 0x2c, 0xcf, 0xfd, 0x72, 0x75, 0xbe, 0x67, 0x34, 0xd7, 0x55, 0xf2, 0xc7, 0x32, 0xd7, 0x7c, + 0x0f, 0x6e, 0x44, 0x31, 0x18, 0xdc, 0xb5, 0x16, 0xb6, 0x8d, 0x9d, 0xd5, 0xba, 0xf5, 0xfb, 0xd3, + 0xfd, 0x82, 0x2a, 0x75, 0xd8, 0xe9, 0x74, 0x31, 0x63, 0x4f, 0x78, 0xd7, 0x0f, 0x49, 0x33, 0x89, + 0x34, 0x6d, 0x01, 0x9b, 0xa3, 0x0e, 0xe2, 0xc8, 0x5a, 0x14, 0x59, 0xcd, 0x64, 0x6d, 0x16, 0x60, + 0x89, 0xfb, 0xfc, 0x14, 0x5b, 0x4b, 0xb1, 0x43, 0x2e, 0x4c, 0x0b, 0x56, 0x58, 0x2f, 0x08, 0x50, + 0x77, 0x60, 0x2d, 0xc7, 0x76, 0xbd, 0xac, 0xb9, 0x3f, 0x5c, 0x9d, 0xef, 0x25, 0xa5, 0x7f, 0xba, + 0x3a, 0xdf, 0xdb, 0xd2, 0x87, 0xd7, 0xaf, 0x78, 0x19, 0xc9, 0x9c, 0x03, 0xd8, 0xcc, 0x18, 0x9b, + 0x98, 0x45, 0x34, 0x64, 0xd8, 0x2c, 0xc3, 0x5a, 0xa4, 0x6c, 0xc7, 0x7e, 0xc7, 0x32, 0xb6, 0x8d, + 0x9d, 0xc5, 0x26, 0x68, 0xd3, 0x83, 0x8e, 0xf3, 0xcc, 0x80, 0x42, 0x83, 0x91, 0x4f, 0xce, 0x70, + 0xfb, 0x21, 0x26, 0xa8, 0x3d, 0x38, 0xa2, 0x21, 0xc7, 0x21, 0x37, 0x1f, 0xc1, 0x4a, 0x5b, 0x7e, + 0xc6, 0x59, 0x13, 0x0e, 0xa2, 0x5e, 0xfe, 0xed, 0xe9, 0xfe, 0x9b, 0xe9, 0xcb, 0xa8, 0x85, 0x8e, + 0x93, 0x9b, 0xba, 0x8a, 0xb9, 0x05, 0xab, 0xa8, 0xc7, 0x4f, 0x68, 0xd7, 0xe7, 0x03, 0x6b, 0x3e, + 0xe6, 0x3c, 0x34, 0xd4, 0xaa, 0x82, 0xf5, 0x70, 0x2d, 0x68, 0x97, 0xd3, 0xb4, 0x33, 0x10, 0x9d, + 0x12, 0x6c, 0xe5, 0xd9, 0x35, 0x79, 0xe7, 0xd2, 0x80, 0x95, 0x06, 0x23, 0x9f, 0x53, 0x8e, 0xcd, + 0xf7, 0x73, 0x84, 0xa8, 0x17, 0xfe, 0x7a, 0x59, 0x1e, 0x35, 0xcb, 0x2b, 0x31, 0x22, 0x8f, 0xe9, + 0xc2, 0x52, 0x9f, 0x72, 0xdc, 0x95, 0x80, 0xa7, 0xdc, 0x05, 0x19, 0x66, 0x56, 0x61, 0x99, 0x46, + 0xdc, 0xa7, 0x61, 0x7c, 0x79, 0xd6, 0xab, 0xb6, 0x9b, 0xd6, 0xc6, 0x15, 0x60, 0x1e, 0xc5, 0x11, + 0x4d, 0x15, 0x39, 0xed, 0xf2, 0xd4, 0x6e, 0x0b, 0x59, 0x64, 0x6d, 0x21, 0x89, 0x99, 0x96, 0x44, + 0x14, 0x73, 0x36, 0xe0, 0xa6, 0xfa, 0x4c, 0x88, 0xff, 0x63, 0x24, 0xb6, 0x2f, 0xb0, 0x4f, 0x4e, + 0x38, 0xee, 0xfc, 0x5f, 0x02, 0x1c, 0xc0, 0x8a, 0xa4, 0xc5, 0xac, 0x85, 0xb8, 0x0d, 0x9d, 0x71, + 0x05, 0x34, 0xa2, 0x11, 0x25, 0x74, 0xca, 0x54, 0x29, 0x76, 0xd3, 0x52, 0xd8, 0x59, 0x29, 0x74, + 0x65, 0x67, 0x13, 0x8a, 0x63, 0xa6, 0xd1, 0x3b, 0x01, 0x0d, 0x46, 0x74, 0xbb, 0x5f, 0x53, 0x95, + 0x0f, 0x60, 0x55, 0x0d, 0x1b, 0x3a, 0x5b, 0x99, 0x61, 0xa8, 0x79, 0x00, 0xcb, 0x28, 0xa0, 0xbd, + 0x90, 0x2b, 0x71, 0x5e, 0x6d, 0x46, 0xa9, 0x9c, 0xda, 0x4e, 0xdc, 0x23, 0x49, 0x35, 0xa1, 0xc2, + 0xad, 0xb4, 0x0a, 0x8a, 0x96, 0x53, 0x00, 0x73, 0xb8, 0x4a, 0xb8, 0x3f, 0x93, 0xd7, 0xe2, 0xb3, + 0xa8, 0x83, 0x38, 0x7e, 0x8c, 0xba, 0x28, 0x60, 0x82, 0xc9, 0xb0, 0x2b, 0x8d, 0x59, 0x4c, 0x92, + 0x50, 0xf3, 0x43, 0x58, 0x8e, 0xe2, 0x0a, 0x31, 0xfd, 0xb5, 0xea, 0x1b, 0xe3, 0xc7, 0x2c, 0xeb, + 0xa7, 0x68, 0xc8, 0x84, 0xda, 0xbd, 0x6c, 0xab, 0x6f, 0x6b, 0x1a, 0x67, 0xfa, 0x81, 0x1a, 0xc3, + 0xa9, 0x8e, 0x74, 0xd4, 0x94, 0xd0, 0xfa, 0x0e, 0x5e, 0x6f, 0x30, 0x22, 0x47, 0x1f, 0x7e, 0x88, + 0xbe, 0xbd, 0x2e, 0xa7, 0x5a, 0x25, 0x0b, 0xac, 0x94, 0x07, 0x6c, 0xb8, 0x95, 0x53, 0x84, 0x5b, + 0x29, 0x43, 0x02, 0xea, 0xdc, 0x80, 0xf2, 0xd0, 0x73, 0x44, 0x43, 0xc6, 0x7d, 0xde, 0x13, 0xb7, + 0xfc, 0x30, 0xc0, 0x61, 0x27, 0x10, 0x13, 0xf1, 0xba, 0xda, 0x8b, 0x49, 0xaa, 0x8b, 0x24, 0x93, + 0x54, 0x1b, 0x6a, 0xf7, 0xb3, 0x2c, 0xee, 0x4c, 0x61, 0x91, 0xc0, 0x71, 0x76, 0xe1, 0xee, 0x0c, + 0xc4, 0x9a, 0x5d, 0xf5, 0xef, 0x25, 0x58, 0x68, 0x30, 0x62, 0x7e, 0x0d, 0xeb, 0x63, 0x0f, 0xf8, + 0xed, 0xf1, 0x7b, 0x90, 0x79, 0x9b, 0xec, 0xdd, 0x99, 0x21, 0xc9, 0xf3, 0x45, 0x60, 0x23, 0xfb, + 0x32, 0xdd, 0xc9, 0xc9, 0xcf, 0x44, 0xd9, 0xef, 0xbc, 0x4a, 0x54, 0xb2, 0xd1, 0x47, 0xb0, 0x18, + 0x3f, 0x13, 0xc5, 0x9c, 0x2c, 0xe1, 0xb0, 0xcb, 0x13, 0x1c, 0x49, 0x85, 0x2f, 0xe1, 0xb5, 0xd4, + 0xbc, 0x9d, 0x94, 0xa0, 0x03, 0xec, 0xbb, 0x33, 0x02, 0x92, 0xca, 0x0f, 0x60, 0x45, 0x8f, 0x2b, + 0x3b, 0x27, 0x47, 0xf9, 0x6c, 0x67, 0xb2, 0x6f, 0x14, 0x64, 0xaa, 0xfb, 0xf3, 0x40, 0x8e, 0x06, + 0xe4, 0x82, 0xcc, 0x6b, 0x42, 0xb3, 0x09, 0x30, 0xd2, 0x81, 0x6f, 0xe5, 0xa4, 0x0d, 0xdd, 0xf6, + 0xdb, 0x53, 0xdd, 0x49, 0xcd, 0x1f, 0x0d, 0xd8, 0x9a, 0xda, 0x40, 0xde, 0xe4, 0x3a, 0xb9, 0x09, + 0xf6, 0xfd, 0xff, 0x98, 0xa0, 0xa1, 0xd8, 0x4b, 0xdf, 0x8b, 0x11, 0x56, 0xff, 0xf4, 0xf9, 0x45, + 0xc9, 0x78, 0x71, 0x51, 0x32, 0xfe, 0xbc, 0x28, 0x19, 0x3f, 0x5f, 0x96, 0xe6, 0x5e, 0x5c, 0x96, + 0xe6, 0xfe, 0xb8, 0x2c, 0xcd, 0x7d, 0xb5, 0x4f, 0x7c, 0x7e, 0xd2, 0x6b, 0xb9, 0x6d, 0x1a, 0x78, + 0x6a, 0x8f, 0xfd, 0x93, 0x5e, 0xcb, 0x4b, 0x77, 0x1e, 0x1f, 0x44, 0x98, 0x89, 0xff, 0xe7, 0xcb, + 0xf1, 0x9f, 0xa8, 0x7b, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xf0, 0xec, 0xe9, 0xac, 0xe1, 0x0b, + 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1842,6 +1852,13 @@ func (m *MsgProposeConstitutionAmendment) MarshalToSizedBuffer(dAtA []byte) (int _ = i var l int _ = l + if len(m.Amendment) > 0 { + i -= len(m.Amendment) + copy(dAtA[i:], m.Amendment) + i = encodeVarintTx(dAtA, i, uint64(len(m.Amendment))) + i-- + dAtA[i] = 0x12 + } if len(m.Authority) > 0 { i -= len(m.Authority) copy(dAtA[i:], m.Authority) @@ -2115,6 +2132,10 @@ func (m *MsgProposeConstitutionAmendment) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + l = len(m.Amendment) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } return n } @@ -3578,6 +3599,38 @@ func (m *MsgProposeConstitutionAmendment) Unmarshal(dAtA []byte) error { } m.Authority = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amendment", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amendment = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:])