diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a9d3ac21d..71797f5e9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,6 +71,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * Switch to InputOutputCoinsProv for exchange transfers [#1930](https://github.com/provenance-io/provenance/pull/1930). * Use fields of the SimulationState for the encoders needed for simulations [#1931](https://github.com/provenance-io/provenance/pull/1931). * Removes sync-info code for sdk v0.50 [#1760](https://github.com/provenance-io/provenance/issues/1760). +* Remove `name` legacy gov proposals [#1963](https://github.com/provenance-io/provenance/pull/1963). * Fix most of the failing unit tests [#1943](https://github.com/provenance-io/provenance/pull/1943). * Clean up ReadFromClient [#1760](https://github.com/provenance-io/provenance/issues/1760). * Enhance the config get and changed commands to make it easier to find fields [#1968](https://github.com/provenance-io/provenance/pull/1968). diff --git a/app/app.go b/app/app.go index 62bde3ce3e..4821eacab1 100644 --- a/app/app.go +++ b/app/app.go @@ -116,7 +116,6 @@ import ( ibctransferkeeper "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" ibc "github.com/cosmos/ibc-go/v8/modules/core" - ibcclient "github.com/cosmos/ibc-go/v8/modules/core/02-client" ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" @@ -159,7 +158,6 @@ import ( msgfeestypes "github.com/provenance-io/provenance/x/msgfees/types" msgfeeswasm "github.com/provenance-io/provenance/x/msgfees/wasm" "github.com/provenance-io/provenance/x/name" - nameclient "github.com/provenance-io/provenance/x/name/client" namekeeper "github.com/provenance-io/provenance/x/name/keeper" nametypes "github.com/provenance-io/provenance/x/name/types" namewasm "github.com/provenance-io/provenance/x/name/wasm" @@ -691,9 +689,6 @@ func New( govRouter := govtypesv1beta1.NewRouter() govRouter.AddRoute(govtypes.RouterKey, govtypesv1beta1.ProposalHandler). AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). - AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)). - AddRoute(wasm.RouterKey, wasmkeeper.NewLegacyWasmProposalHandler(app.WasmKeeper, wasmtypes.EnableAllProposals)). // TODO[1760]: gov: Can probably remove with gov v1 - AddRoute(nametypes.ModuleName, name.NewProposalHandler(app.NameKeeper)). AddRoute(markertypes.ModuleName, marker.NewProposalHandler(app.MarkerKeeper)). AddRoute(msgfeestypes.ModuleName, msgfees.NewProposalHandler(app.MsgFeesKeeper, app.InterfaceRegistry())) govKeeper := govkeeper.NewKeeper( @@ -793,7 +788,6 @@ func New( append( []govclient.ProposalHandler{}, paramsclient.ProposalHandler, - nameclient.RootNameProposalHandler, ), ), }) diff --git a/proto/provenance/name/v1/name.proto b/proto/provenance/name/v1/name.proto index 523cb4f618..cb69285868 100644 --- a/proto/provenance/name/v1/name.proto +++ b/proto/provenance/name/v1/name.proto @@ -39,7 +39,10 @@ message NameRecord { // CreateRootNameProposal details a proposal to create a new root name // that is controlled by a given owner and optionally restricted to the owner // for the sole creation of sub names. +// Deprecated: This legacy proposal is deprecated in favor of Msg-based gov +// proposals, see MsgCreateRootNameRequest. message CreateRootNameProposal { + option deprecated = true; option (gogoproto.equal) = false; option (gogoproto.goproto_getters) = false; option (gogoproto.goproto_stringer) = false; diff --git a/third_party/proto/cosmos_proto/cosmos.proto b/third_party/proto/cosmos_proto/cosmos.proto index 5c63b86f06..4fb58159fd 100644 --- a/third_party/proto/cosmos_proto/cosmos.proto +++ b/third_party/proto/cosmos_proto/cosmos.proto @@ -5,6 +5,12 @@ import "google/protobuf/descriptor.proto"; option go_package = "github.com/cosmos/cosmos-proto;cosmos_proto"; +extend google.protobuf.MethodOptions { + + // method_added_in is used to indicate from which version the method was added. + string method_added_in = 93001; +} + extend google.protobuf.MessageOptions { // implements_interface is used to indicate the type name of the interface @@ -13,6 +19,9 @@ extend google.protobuf.MessageOptions { // interfaces. Interfaces should be declared using a declare_interface // file option. repeated string implements_interface = 93001; + + // message_added_in is used to indicate from which version the message was added. + string message_added_in = 93002; } extend google.protobuf.FieldOptions { @@ -27,6 +36,9 @@ extend google.protobuf.FieldOptions { // generators may choose to use this information to map this field to a // language-specific type representing the scalar. string scalar = 93002; + + // field_added_in is used to indicate from which version the field was added. + string field_added_in = 93003; } extend google.protobuf.FileOptions { @@ -46,6 +58,9 @@ extend google.protobuf.FileOptions { // expected that the declaration will be found in a protobuf file named // a/b/scalars.proto in the file descriptor set. repeated ScalarDescriptor declare_scalar = 793022; + + // file_added_in is used to indicate from which the version the file was added. + string file_added_in = 793023; } // InterfaceDescriptor describes an interface type to be used with @@ -94,4 +109,4 @@ enum ScalarType { SCALAR_TYPE_UNSPECIFIED = 0; SCALAR_TYPE_STRING = 1; SCALAR_TYPE_BYTES = 2; -} +} \ No newline at end of file diff --git a/x/name/client/cli/cli_test.go b/x/name/client/cli/cli_test.go index 220fa2ef28..64114e2101 100644 --- a/x/name/client/cli/cli_test.go +++ b/x/name/client/cli/cli_test.go @@ -573,7 +573,7 @@ func (s *IntegrationTestSuite) TestPaginationWithPageKey() { }) } -func (s *IntegrationTestSuite) TestCreateRootNameCmd() { +func (s *IntegrationTestSuite) TestGovRootNameCmd() { testCases := []struct { name string cmd *cobra.Command @@ -581,83 +581,112 @@ func (s *IntegrationTestSuite) TestCreateRootNameCmd() { expectErr bool respType proto.Message expectedCode uint32 + errorMessage string }{ { - "should create a root name proposal", - namecli.GetRootNameProposalCmd(), - []string{"rootprop", - fmt.Sprintf("--%s=%s", namecli.FlagTitle, "title"), - fmt.Sprintf("--%s=%s", namecli.FlagDescription, "description"), - fmt.Sprintf("--%s=%s%s", namecli.FlagDeposit, "10", s.cfg.BondDenom), + name: "should create a root name proposal", + cmd: namecli.GetGovRootNameCmd(), + args: []string{"rootprop", + fmt.Sprintf("--%s=%s", govcli.FlagTitle, "title"), + fmt.Sprintf("--%s=%s", govcli.FlagSummary, "description"), + fmt.Sprintf("--%s=%s%s", govcli.FlagDeposit, "10", s.cfg.BondDenom), fmt.Sprintf("--%s=%s", "owner", s.testnet.Validators[0].Address.String()), fmt.Sprintf("--%s=%s", flags.FlagFrom, s.testnet.Validators[0].Address.String()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewInt64Coin(s.cfg.BondDenom, 10)).String()), }, - false, &sdk.TxResponse{}, 0, + expectErr: false, + respType: &sdk.TxResponse{}, + expectedCode: 0, }, { - "should succeed with missing deposit", - namecli.GetRootNameProposalCmd(), - []string{"rootprop", - fmt.Sprintf("--%s=%s", namecli.FlagTitle, "title"), - fmt.Sprintf("--%s=%s", namecli.FlagDescription, "description"), + name: "should fail for missing arg", + cmd: namecli.GetGovRootNameCmd(), + args: []string{ + fmt.Sprintf("--%s=%s", govcli.FlagTitle, "title"), + fmt.Sprintf("--%s=%s", govcli.FlagSummary, "description"), + fmt.Sprintf("--%s=%s%s", govcli.FlagDeposit, "10", s.cfg.BondDenom), fmt.Sprintf("--%s=%s", "owner", s.testnet.Validators[0].Address.String()), fmt.Sprintf("--%s=%s", flags.FlagFrom, s.testnet.Validators[0].Address.String()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewInt64Coin(s.cfg.BondDenom, 10)).String()), }, - false, &sdk.TxResponse{}, 0, + expectErr: false, + respType: &sdk.TxResponse{}, + expectedCode: 0, + errorMessage: "accepts 1 arg(s), received 0", }, { - "should fail for bad deposit", - namecli.GetRootNameProposalCmd(), - []string{"rootprop", - fmt.Sprintf("--%s=%s", namecli.FlagTitle, "title"), - fmt.Sprintf("--%s=%s", namecli.FlagDescription, "description"), - fmt.Sprintf("--%s=%s", namecli.FlagDeposit, "10"), + name: "should succeed with missing deposit", + cmd: namecli.GetGovRootNameCmd(), + args: []string{"rootprop", + fmt.Sprintf("--%s=%s", govcli.FlagTitle, "title"), + fmt.Sprintf("--%s=%s", govcli.FlagSummary, "description"), fmt.Sprintf("--%s=%s", "owner", s.testnet.Validators[0].Address.String()), fmt.Sprintf("--%s=%s", flags.FlagFrom, s.testnet.Validators[0].Address.String()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewInt64Coin(s.cfg.BondDenom, 10)).String()), }, - true, &sdk.TxResponse{}, 1, + expectErr: false, + respType: &sdk.TxResponse{}, + expectedCode: 0, }, { - "should fail for empty title", - namecli.GetRootNameProposalCmd(), - []string{"rootprop", - fmt.Sprintf("--%s=%s", namecli.FlagDescription, "description"), - fmt.Sprintf("--%s=%s%s", namecli.FlagDeposit, "10", s.cfg.BondDenom), + name: "should fail for bad deposit", + cmd: namecli.GetGovRootNameCmd(), + args: []string{"rootprop", + fmt.Sprintf("--%s=%s", govcli.FlagTitle, "title"), + fmt.Sprintf("--%s=%s", govcli.FlagSummary, "description"), + fmt.Sprintf("--%s=%s", govcli.FlagDeposit, "10"), + fmt.Sprintf("--%s=%s", "owner", s.testnet.Validators[0].Address.String()), fmt.Sprintf("--%s=%s", flags.FlagFrom, s.testnet.Validators[0].Address.String()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewInt64Coin(s.cfg.BondDenom, 10)).String()), }, - true, &sdk.TxResponse{}, 1, + expectErr: true, + respType: &sdk.TxResponse{}, + expectedCode: 1, }, { - "should fail for empty description", - namecli.GetRootNameProposalCmd(), - []string{"rootprop", - fmt.Sprintf("--%s=%s", namecli.FlagTitle, "title"), - fmt.Sprintf("--%s=%s%s", namecli.FlagDeposit, "10", s.cfg.BondDenom), + name: "should fail for empty title", + cmd: namecli.GetGovRootNameCmd(), + args: []string{"rootprop", + fmt.Sprintf("--%s=%s", govcli.FlagSummary, "description"), + fmt.Sprintf("--%s=%s%s", govcli.FlagDeposit, "10", s.cfg.BondDenom), fmt.Sprintf("--%s=%s", flags.FlagFrom, s.testnet.Validators[0].Address.String()), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewInt64Coin(s.cfg.BondDenom, 10)).String()), }, - true, &sdk.TxResponse{}, 1, + expectErr: false, + respType: &sdk.TxResponse{}, + expectedCode: 18, + }, + { + name: "should fail for empty summary", + cmd: namecli.GetGovRootNameCmd(), + args: []string{"rootprop", + fmt.Sprintf("--%s=%s", govcli.FlagTitle, "title"), + fmt.Sprintf("--%s=%s%s", govcli.FlagDeposit, "10", s.cfg.BondDenom), + fmt.Sprintf("--%s=%s", flags.FlagFrom, s.testnet.Validators[0].Address.String()), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewInt64Coin(s.cfg.BondDenom, 10)).String()), + }, + expectErr: false, + respType: &sdk.TxResponse{}, + expectedCode: 18, }, { - "should fail for bad owner", - namecli.GetRootNameProposalCmd(), - []string{"rootprop", - fmt.Sprintf("--%s=%s", namecli.FlagTitle, "title"), - fmt.Sprintf("--%s=%s%s", namecli.FlagDeposit, "10", s.cfg.BondDenom), + name: "should fail for bad owner", + cmd: namecli.GetGovRootNameCmd(), + args: []string{"rootprop", + fmt.Sprintf("--%s=%s", govcli.FlagTitle, "title"), + fmt.Sprintf("--%s=%s%s", govcli.FlagDeposit, "10", s.cfg.BondDenom), fmt.Sprintf("--%s=%s", "owner", "asdf"), @@ -666,7 +695,9 @@ func (s *IntegrationTestSuite) TestCreateRootNameCmd() { fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewInt64Coin(s.cfg.BondDenom, 10)).String()), }, - true, &sdk.TxResponse{}, 1, + expectErr: true, + respType: &sdk.TxResponse{}, + expectedCode: 1, }, } @@ -677,6 +708,7 @@ func (s *IntegrationTestSuite) TestCreateRootNameCmd() { testcli.NewCLITxExecutor(tc.cmd, tc.args). WithExpErr(tc.expectErr). WithExpCode(tc.expectedCode). + WithExpErrMsg(tc.errorMessage). Execute(s.T(), s.testnet) }) } diff --git a/x/name/client/cli/gov.go b/x/name/client/cli/gov.go deleted file mode 100644 index df576c155b..0000000000 --- a/x/name/client/cli/gov.go +++ /dev/null @@ -1,119 +0,0 @@ -package cli - -import ( - "fmt" - "strings" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/tx" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/version" - govtypesv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - - "github.com/provenance-io/provenance/x/name/types" -) - -const ( - // FlagOwner is the flag for the owner address of a name record. - FlagOwner = "owner" - // FlagDescription is the flag for a description. - FlagDescription = "description" - // FlagTitle is the flag for a title. - FlagTitle = "title" - // FlagDeposit is the flag for a deposit. - FlagDeposit string = "deposit" - // FlagMetadata is the flag for a deposit. - FlagMetadata string = "metadata" -) - -// GetRootNameProposalCmd returns a command for registration with the gov module -func GetRootNameProposalCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "root-name-proposal [name] (--owner [address]) (--unrestrict) [flags]", - Short: "Submit a root name creation governance proposal", - Long: strings.TrimSpace( - fmt.Sprintf(`Submit a root name creation governance proposal along with an initial deposit. -The proposal title and description must be provided through their respective flags. - -IMPORTANT: The created root name will restrict the creation of sub-names by default unless the -unrestrict flag is included. The proposer will be the default owner that must approve -all child name creation unless an alterate owner is provided. - -Example: -$ %s tx gov submit-legacy-proposal \ - root-name-proposal \ - \ - --unrestrict \ - --owner \ - --title "Proposal title" \ - --description "Description of proposal" - --from - `, - version.AppName)), - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - proposalTitle, err := cmd.Flags().GetString(FlagTitle) - if err != nil { - return fmt.Errorf("proposal title: %w", err) - } - proposalDescr, err := cmd.Flags().GetString(FlagDescription) - if err != nil { - return fmt.Errorf("proposal description: %w", err) - } - proposalOwner, err := cmd.Flags().GetString(FlagOwner) - if err != nil { - return fmt.Errorf("proposal root name owner: %w", err) - } - if len(proposalOwner) < 1 { - proposalOwner = clientCtx.GetFromAddress().String() - } - _, err = sdk.AccAddressFromBech32(proposalOwner) - if err != nil { - return err - } - depositArg, err := cmd.Flags().GetString(FlagDeposit) - if err != nil { - return err - } - deposit, err := sdk.ParseCoinsNormalized(depositArg) - if err != nil { - return err - } - - content := types.CreateRootNameProposal{ - Title: proposalTitle, - Description: proposalDescr, - Name: strings.ToLower(args[0]), - Owner: proposalOwner, - Restricted: !viper.GetBool(FlagUnrestricted), - } - err = content.ValidateBasic() - if err != nil { - return err - } - - msg, err := govtypesv1beta1.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) - if err != nil { - return err - } - - return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) - }, - } - - cmd.Flags().String(FlagOwner, "", "The owner of the new name, optional (defaults to from address)") - cmd.Flags().BoolP(FlagUnrestricted, "u", false, "Allow child name creation by everyone") - // proposal flags - cmd.Flags().String(FlagTitle, "", "Title of proposal") - cmd.Flags().String(FlagDescription, "", "Description of proposal") - cmd.Flags().String(FlagDeposit, "", "Deposit of proposal") - return cmd -} diff --git a/x/name/client/cli/tx.go b/x/name/client/cli/tx.go index f9aa92ab79..1377490073 100644 --- a/x/name/client/cli/tx.go +++ b/x/name/client/cli/tx.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/spf13/cobra" + "github.com/spf13/pflag" "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client" @@ -18,11 +19,16 @@ import ( "github.com/provenance-io/provenance/x/name/types" ) -// FlagUnrestricted is the flag for creating unrestricted names -const FlagUnrestricted = "unrestrict" +const ( + // FlagOwner is the flag for the owner address of a name record. + FlagOwner = "owner" -// FlagGovProposal is the flag to specify that the command should be run as a gov proposal -const FlagGovProposal = "gov-proposal" + // FlagGovProposal is the flag to specify that the command should be run as a gov proposal + FlagGovProposal = "gov-proposal" + + // FlagUnrestricted is the flag for creating unrestricted names + FlagUnrestricted = "unrestrict" +) // NewTxCmd is the top-level command for name CLI transactions. func NewTxCmd() *cobra.Command { @@ -37,6 +43,7 @@ func NewTxCmd() *cobra.Command { GetBindNameCmd(), GetDeleteNameCmd(), GetModifyNameCmd(), + GetGovRootNameCmd(), ) return txCmd } @@ -159,3 +166,68 @@ $ %s tx name modify-name \ flags.AddTxFlagsToCmd(cmd) return cmd } + +// GetRootNameProposalCmd returns a command for registration with the gov module +func GetGovRootNameCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "gov-root-name [name] (--owner [address]) (--unrestrict) [flags]", + Short: "Submit a root name creation governance proposal", + Long: strings.TrimSpace( + fmt.Sprintf(`Submit a root name creation governance proposal. + +IMPORTANT: The created root name will restrict the creation of sub-names by default unless the +unrestrict flag is included. The proposer will be the default owner that must approve +all child name creation unless an alterate owner is provided. + +Example: +$ %s tx name gov-root-name \ + \ + --unrestrict \ + --owner \ + --from + `, + version.AppName)), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + flagSet := cmd.Flags() + owner, err := owner(clientCtx, flagSet) + if err != nil { + return err + } + authority := provcli.GetAuthority(flagSet) + name := strings.ToLower(args[0]) + restricted := !viper.GetBool(FlagUnrestricted) + msg := types.NewMsgCreateRootNameRequest(authority, name, owner, restricted) + + return provcli.GenerateOrBroadcastTxCLIAsGovProp(clientCtx, flagSet, msg) + }, + } + + cmd.Flags().String(FlagOwner, "", "The owner of the new name, optional (defaults to from address)") + cmd.Flags().BoolP(FlagUnrestricted, "u", false, "Allow child name creation by everyone") + govcli.AddGovPropFlagsToCmd(cmd) + provcli.AddAuthorityFlagToCmd(cmd) + return cmd +} + +// owner returns the proposal owner +func owner(ctx client.Context, flags *pflag.FlagSet) (string, error) { + proposalOwner, err := flags.GetString(FlagOwner) + if err != nil { + return "", fmt.Errorf("proposal root name owner: %w", err) + } + if len(proposalOwner) < 1 { + proposalOwner = ctx.GetFromAddress().String() + } + _, err = sdk.AccAddressFromBech32(proposalOwner) + if err != nil { + return "", err + } + + return proposalOwner, nil +} diff --git a/x/name/client/proposal_handler.go b/x/name/client/proposal_handler.go deleted file mode 100644 index d486923bf6..0000000000 --- a/x/name/client/proposal_handler.go +++ /dev/null @@ -1,12 +0,0 @@ -package client - -import ( - govclient "github.com/cosmos/cosmos-sdk/x/gov/client" - - "github.com/provenance-io/provenance/x/name/client/cli" -) - -// ProposalHandler is the create root name proposal handler. -var ( - RootNameProposalHandler = govclient.NewProposalHandler(cli.GetRootNameProposalCmd) -) diff --git a/x/name/handler.go b/x/name/handler.go deleted file mode 100644 index 68b53d009a..0000000000 --- a/x/name/handler.go +++ /dev/null @@ -1,22 +0,0 @@ -package name - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - govtypesv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - - "github.com/provenance-io/provenance/x/name/keeper" - "github.com/provenance-io/provenance/x/name/types" -) - -// TODO[1760]: marker: Migrate the legacy gov proposals. -func NewProposalHandler(k keeper.Keeper) govtypesv1beta1.Handler { - return func(ctx sdk.Context, content govtypesv1beta1.Content) error { - switch c := content.(type) { - case *types.CreateRootNameProposal: - return keeper.HandleCreateRootNameProposal(ctx, k, c) - default: - return sdkerrors.ErrUnknownRequest.Wrapf("unrecognized name proposal content type: %T", c) - } - } -} diff --git a/x/name/keeper/keeper.go b/x/name/keeper/keeper.go index f2be1ece7e..fd9c11fe89 100644 --- a/x/name/keeper/keeper.go +++ b/x/name/keeper/keeper.go @@ -357,3 +357,37 @@ func (k Keeper) DeleteInvalidAddressIndexEntries(ctx sdk.Context) { logger.Info(fmt.Sprintf("Done checking address -> name index entries. Deleted %d invalid entries and kept %d valid entries.", len(toDelete), keepCount)) } + +func (k Keeper) CreateRootName(ctx sdk.Context, name, owner string, restricted bool) error { + // err is suppressed because it returns an error on not found. TODO - Remove use of error for not found + existing, _ := k.GetRecordByName(ctx, name) + if existing != nil { + return types.ErrNameAlreadyBound + } + addr, err := sdk.AccAddressFromBech32(owner) + if err != nil { + return err + } + logger := k.Logger(ctx) + + // Because the proposal can contain a full domain we need to ensure all intermediate pieces are created correctly + n := "" + segments := strings.Split(name, ".") + for i := len(segments) - 1; i >= 0; i-- { + n = strings.Join([]string{segments[i], n}, ".") + n = strings.TrimRight(n, ".") + + // Ensure there is not an existing record with this name that we might be over writing + existing, _ = k.GetRecordByName(ctx, n) + if existing == nil { + if err = k.SetNameRecord(ctx, n, addr, restricted); err != nil { + return err + } + logger.Info(fmt.Sprintf("create root name proposal: created %s and set the owner as %s", n, owner)) + } else { + logger.Info(fmt.Sprintf("create root name proposal: intermediate domain %s exists, skipping", n)) + } + } + + return nil +} diff --git a/x/name/keeper/keeper_test.go b/x/name/keeper/keeper_test.go index d91d9e4e40..4a44ed4114 100644 --- a/x/name/keeper/keeper_test.go +++ b/x/name/keeper/keeper_test.go @@ -63,6 +63,7 @@ func (s *KeeperTestSuite) SetupTest() { var nameData nametypes.GenesisState nameData.Bindings = append(nameData.Bindings, nametypes.NewNameRecord("name", s.user1Addr, false)) nameData.Bindings = append(nameData.Bindings, nametypes.NewNameRecord("example.name", s.user1Addr, false)) + nameData.Bindings = append(nameData.Bindings, nametypes.NewNameRecord("test.root", s.user1Addr, false)) nameData.Params.AllowUnrestrictedNames = false nameData.Params.MaxNameLevels = 16 nameData.Params.MinSegmentLength = 2 @@ -91,6 +92,9 @@ func (s *KeeperTestSuite) TestSetup() { }) expOut := fmt.Sprintf(`bindings: +- address: %[1]s + name: test.root + restricted: false - address: %[1]s name: name restricted: false @@ -307,6 +311,7 @@ func (s *KeeperTestSuite) TestModifyRecord() { expUser1Recs := nametypes.NameRecords{ {Name: jackthecat, Address: s.user1Addr.String(), Restricted: true}, + {Name: "test.root", Address: s.user1Addr.String(), Restricted: false}, {Name: "name", Address: s.user1Addr.String(), Restricted: false}, {Name: "example.name", Address: s.user1Addr.String(), Restricted: false}, } @@ -354,6 +359,7 @@ func (s *KeeperTestSuite) TestGetAuthority() { func (s *KeeperTestSuite) TestIterateRecord() { s.Run("iterate name's", func() { expRecords := nametypes.NameRecords{ + nametypes.NewNameRecord("test.root", s.user1Addr, false), nametypes.NewNameRecord("name", s.user1Addr, false), nametypes.NewNameRecord("example.name", s.user1Addr, false), nametypes.NewNameRecord(attrtypes.AccountDataName, authtypes.NewModuleAddress(attrtypes.ModuleName), true), @@ -565,3 +571,89 @@ func TestDeleteInvalidAddressIndexEntries(t *testing.T) { }) } } + +func (s *KeeperTestSuite) TestCreateRootNameProposals() { + + testCases := []struct { + testName string + name string + owner sdk.AccAddress + restricted bool + err error + }{ + { + testName: "add root name - valid", + name: "root", + owner: s.user1Addr, + restricted: false, + }, + { + testName: "add root name - valid full domain", + name: "example.provenance.io", + owner: s.user1Addr, + restricted: false, + }, + { + testName: "add root name - valid new sub domain", + name: "another.provenance.io", + owner: s.user1Addr, + restricted: false, + }, + { + testName: "add root name - invalid address", + name: "badroot", + owner: sdk.AccAddress("bad1address"), + restricted: false, + }, + { + testName: "add root name - fails duplicate", + name: "root", + owner: s.user1Addr, + restricted: false, + err: fmt.Errorf("name is already bound to an address"), + }, + { + testName: "add root name - fails duplicate sub domain", + name: "provenance.io", + owner: s.user1Addr, + restricted: false, + err: fmt.Errorf("name is already bound to an address"), + }, + { + testName: "add root name - fails duplicate third level domain", + name: "example.provenance.io", + owner: s.user1Addr, + restricted: false, + err: fmt.Errorf("name is already bound to an address"), + }, + { + testName: "add root name - fails another duplicate third level domain", + name: "another.provenance.io", + owner: s.user1Addr, + restricted: false, + err: fmt.Errorf("name is already bound to an address"), + }, + { + testName: "add root name - fails invalid name", + name: "..badroot", + owner: s.user1Addr, + restricted: false, + err: fmt.Errorf("segment of name is too short"), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.testName, func() { + err := s.app.NameKeeper.CreateRootName(s.ctx, tc.name, tc.owner.String(), tc.restricted) + + if err != nil { + s.Require().Error(err) + s.Require().Equal(tc.err.Error(), err.Error()) + } else { + s.Require().NoError(err) + } + }) + } +} diff --git a/x/name/keeper/msg_server.go b/x/name/keeper/msg_server.go index d56f131692..82ff4dd194 100644 --- a/x/name/keeper/msg_server.go +++ b/x/name/keeper/msg_server.go @@ -191,9 +191,7 @@ func (s msgServer) CreateRootName(goCtx context.Context, msg *types.MsgCreateRoo return nil, errors.Wrapf(govtypes.ErrInvalidSigner, "expected %s got %s", s.Keeper.GetAuthority(), msg.Authority) } - // Routes to legacy proposal handler to avoid code duplication - // Setting title and description to empty strings. These two fields are deprecated in the v1. - err := HandleCreateRootNameProposal(ctx, s.Keeper, types.NewCreateRootNameProposal("", "", msg.Record.Name, sdk.AccAddress(msg.Record.Address), msg.Record.Restricted)) + err := s.Keeper.CreateRootName(ctx, msg.Record.Name, msg.Record.Address, msg.Record.Restricted) if err != nil { return nil, err } diff --git a/x/name/keeper/msg_server_test.go b/x/name/keeper/msg_server_test.go index bcb098bff8..339f79c18b 100644 --- a/x/name/keeper/msg_server_test.go +++ b/x/name/keeper/msg_server_test.go @@ -5,6 +5,7 @@ import ( "fmt" "testing" + "cosmossdk.io/errors" abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/gogoproto/proto" "github.com/stretchr/testify/assert" @@ -16,11 +17,13 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" simapp "github.com/provenance-io/provenance/app" attrtypes "github.com/provenance-io/provenance/x/attribute/types" "github.com/provenance-io/provenance/x/name/keeper" "github.com/provenance-io/provenance/x/name/types" + nametypes "github.com/provenance-io/provenance/x/name/types" ) type MsgServerTestSuite struct { @@ -332,3 +335,44 @@ func (s *MsgServerTestSuite) TestModifyName() { }) } } + +func (s *MsgServerTestSuite) TestCreateRootName() { + tests := []struct { + name string + expectedError error + msg *types.MsgCreateRootNameRequest + expectedEvent proto.Message + }{ + { + name: "invalid authority", + msg: types.NewMsgCreateRootNameRequest("invalid-authority", "example", s.owner1, false), + expectedError: errors.Wrapf(govtypes.ErrInvalidSigner, "expected %s got %s", s.app.NameKeeper.GetAuthority(), "invalid-authority"), + }, + { + name: "valid authority with invalid root name", + msg: types.NewMsgCreateRootNameRequest(s.app.NameKeeper.GetAuthority(), "name", s.owner1, false), + expectedError: nametypes.ErrNameAlreadyBound, + }, + { + name: "valid authority with valid root name", + msg: types.NewMsgCreateRootNameRequest(s.app.NameKeeper.GetAuthority(), "example", s.owner1, false), + expectedEvent: types.NewEventNameBound(s.owner1, "example", false), + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdk.NewEventManager()) + _, err := s.msgServer.CreateRootName(s.ctx, tc.msg) + if tc.expectedError != nil { + s.Require().EqualError(err, tc.expectedError.Error()) + } else { + s.Require().NoError(err) + } + if tc.expectedEvent != nil { + result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent) + s.Require().True(result, fmt.Sprintf("Expected typed event was not found: %v", tc.expectedEvent)) + } + }) + } +} diff --git a/x/name/keeper/proposal_handler.go b/x/name/keeper/proposal_handler.go deleted file mode 100644 index 6052ca73f1..0000000000 --- a/x/name/keeper/proposal_handler.go +++ /dev/null @@ -1,45 +0,0 @@ -package keeper - -import ( - "fmt" - "strings" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/provenance-io/provenance/x/name/types" -) - -// HandleCreateRootNameProposal is a handler for executing a passed create root name proposal -func HandleCreateRootNameProposal(ctx sdk.Context, k Keeper, p *types.CreateRootNameProposal) error { - // err is suppressed because it returns an error on not found. TODO - Remove use of error for not found - existing, _ := k.GetRecordByName(ctx, p.Name) - if existing != nil { - return types.ErrNameAlreadyBound - } - addr, err := sdk.AccAddressFromBech32(p.Owner) - if err != nil { - return err - } - logger := k.Logger(ctx) - - // Because the proposal can contain a full domain we need to ensure all intermediate pieces are create correctly - name := "" - segments := strings.Split(p.Name, ".") - for i := len(segments) - 1; i >= 0; i-- { - name = strings.Join([]string{segments[i], name}, ".") - name = strings.TrimRight(name, ".") - - // Ensure there is not an existing record with this name that we might be over writing - existing, _ = k.GetRecordByName(ctx, name) - if existing == nil { - if err = k.SetNameRecord(ctx, name, addr, p.Restricted); err != nil { - return err - } - logger.Info(fmt.Sprintf("create root name proposal: created %s and set the owner as %s", name, p.Owner)) - } else { - logger.Info(fmt.Sprintf("create root name proposal: intermediate domain %s exists, skipping", name)) - } - } - - return nil -} diff --git a/x/name/keeper/proposal_handler_test.go b/x/name/keeper/proposal_handler_test.go deleted file mode 100644 index 6be03a6a4d..0000000000 --- a/x/name/keeper/proposal_handler_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package keeper_test - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/suite" - - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - sdk "github.com/cosmos/cosmos-sdk/types" - govtypesv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - - provenance "github.com/provenance-io/provenance/app" - namekeeper "github.com/provenance-io/provenance/x/name/keeper" - nametypes "github.com/provenance-io/provenance/x/name/types" -) - -type IntegrationTestSuite struct { - suite.Suite - - app *provenance.App - ctx sdk.Context - k namekeeper.Keeper - - accountAddr sdk.AccAddress -} - -func (s *IntegrationTestSuite) SetupSuite() { - s.app = provenance.Setup(s.T()) - s.ctx = s.app.BaseApp.NewContext(false) - s.k = namekeeper.NewKeeper(s.app.AppCodec(), s.app.GetKey(nametypes.ModuleName)) - s.accountAddr = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - s.k.SetNameRecord(s.ctx, "test.root", s.accountAddr, false) -} - -func (s *IntegrationTestSuite) TearDownSuite() { - s.T().Log("tearing down integration test suite") -} - -func (s *IntegrationTestSuite) TestCreateRootNameProposals() { - - testCases := []struct { - name string - prop govtypesv1beta1.Content - wantErr bool - err error - }{ - // ADD ROOT NAME PROPOSALS - { - "add root name - valid", - nametypes.NewCreateRootNameProposal("title", "description", "root", s.accountAddr, false), - false, - nil, - }, - { - "add root name - valid full domain", - nametypes.NewCreateRootNameProposal("title", "description", "example.provenance.io", s.accountAddr, false), - false, - nil, - }, - { - "add root name - valid new sub domain", - nametypes.NewCreateRootNameProposal("title", "description", "another.provenance.io", s.accountAddr, false), - false, - nil, - }, - { - "add root name - invalid address", - &nametypes.CreateRootNameProposal{Title: "title", Description: "description", Name: "badroot", Owner: "bad1address", Restricted: false}, - true, - fmt.Errorf("decoding bech32 failed: invalid checksum (expected dpg8tu got ddress)"), - }, - { - "add root name - fails duplicate", - nametypes.NewCreateRootNameProposal("title", "description", "root", s.accountAddr, false), - true, - fmt.Errorf("name is already bound to an address"), - }, - { - "add root name - fails duplicate sub domain", - nametypes.NewCreateRootNameProposal("title", "description", "provenance.io", s.accountAddr, false), - true, - fmt.Errorf("name is already bound to an address"), - }, - { - "add root name - fails duplicate third level domain", - nametypes.NewCreateRootNameProposal("title", "description", "example.provenance.io", s.accountAddr, false), - true, - fmt.Errorf("name is already bound to an address"), - }, - { - "add root name - fails another duplicate third level domain", - nametypes.NewCreateRootNameProposal("title", "description", "another.provenance.io", s.accountAddr, false), - true, - fmt.Errorf("name is already bound to an address"), - }, - { - "add root name - fails invalid name", - nametypes.NewCreateRootNameProposal("title", "description", "..badroot", s.accountAddr, false), - true, - fmt.Errorf("segment of name is too short"), - }, - } - - for _, tc := range testCases { - tc := tc - - s.Run(tc.name, func() { - - var err error - switch c := tc.prop.(type) { - case *nametypes.CreateRootNameProposal: - err = namekeeper.HandleCreateRootNameProposal(s.ctx, s.k, c) - default: - panic("invalid proposal type") - } - - if tc.wantErr { - s.Require().Error(err) - s.Require().Equal(tc.err.Error(), err.Error()) - } else { - s.Require().NoError(err) - } - }) - } -} - -func TestIntegrationTestSuite(t *testing.T) { - suite.Run(t, new(IntegrationTestSuite)) -} diff --git a/x/name/module.go b/x/name/module.go index 4b1b5b6fa5..29c6ce46c3 100644 --- a/x/name/module.go +++ b/x/name/module.go @@ -152,12 +152,6 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } -// ProposalContents returns all the name content functions used to -// simulate governance proposals. -func (am AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent { - return simulation.ProposalContents(am.keeper) -} - // RandomizedParams creates randomized name param changes for the simulator. func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.LegacyParamChange { return simulation.ParamChanges(r) diff --git a/x/name/simulation/proposals.go b/x/name/simulation/proposals.go deleted file mode 100644 index 8d1f0562e8..0000000000 --- a/x/name/simulation/proposals.go +++ /dev/null @@ -1,44 +0,0 @@ -package simulation - -import ( - "math/rand" - - sdk "github.com/cosmos/cosmos-sdk/types" - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/simulation" - - simappparams "github.com/provenance-io/provenance/app/params" - "github.com/provenance-io/provenance/x/name/keeper" - "github.com/provenance-io/provenance/x/name/types" -) - -// OpWeightSubmitCreateRootNameProposal app params key for create root name proposal -const OpWeightSubmitCreateRootNameProposal = "op_weight_submit_create_root_name_proposal" - -// ProposalContents defines the module weighted proposals' contents -func ProposalContents(k keeper.Keeper) []simtypes.WeightedProposalContent { - return []simtypes.WeightedProposalContent{ - simulation.NewWeightedProposalContent( - OpWeightSubmitCreateRootNameProposal, - simappparams.DefaultWeightCreateRootNameProposal, - SimulateCreateRootNameProposalContent(k), - ), - } -} - -// SimulateCreateRootNameProposalContent generates random create-root-name proposal content -func SimulateCreateRootNameProposalContent(_ keeper.Keeper) simtypes.ContentSimulatorFn { - return func(r *rand.Rand, _ sdk.Context, accs []simtypes.Account) simtypes.Content { - simAccount, _ := simtypes.RandomAcc(r, accs) - - restricted := r.Intn(2) == 0 - - return types.NewCreateRootNameProposal( - simtypes.RandStringOfLength(r, 10), - simtypes.RandStringOfLength(r, 100), - simtypes.RandStringOfLength(r, 10), - simAccount.Address, - restricted, - ) - } -} diff --git a/x/name/simulation/proposals_test.go b/x/name/simulation/proposals_test.go deleted file mode 100644 index 179b96f204..0000000000 --- a/x/name/simulation/proposals_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package simulation_test - -import ( - "math/rand" - "testing" - - "github.com/stretchr/testify/require" - - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - - simapp "github.com/provenance-io/provenance/app" - simappparams "github.com/provenance-io/provenance/app/params" - "github.com/provenance-io/provenance/x/name/keeper" - "github.com/provenance-io/provenance/x/name/simulation" - "github.com/provenance-io/provenance/x/name/types" -) - -func TestCreateRootNameProposalContents(t *testing.T) { - app := simapp.Setup(t) - ctx := app.BaseApp.NewContext(false) - - // initialize parameters - s := rand.NewSource(1) - r := rand.New(s) - - accounts := simtypes.RandomAccounts(r, 3) - - // execute ProposalContents function - weightedProposalContent := simulation.ProposalContents(keeper.NewKeeper(app.AppCodec(), app.GetKey(types.ModuleName))) - require.Len(t, weightedProposalContent, 1) - - w0 := weightedProposalContent[0] - - // tests w0 interface: - require.Equal(t, simulation.OpWeightSubmitCreateRootNameProposal, w0.AppParamsKey()) - require.Equal(t, simappparams.DefaultWeightCreateRootNameProposal, w0.DefaultWeight()) - - content := w0.ContentSimulatorFn()(r, ctx, accounts) - - require.Equal(t, "hPjMaxKlMIJMOXcnQfyzeOcbWwNbeHVIkPZBSpYuLyYggwexjxusrBqDOTtGTOWeLrQKjLxzIivHSlcxgdXhhuTSkuxKGLwQvuyN", content.GetDescription()) - require.Equal(t, "eAerqyNEUz", content.GetTitle()) - require.Equal(t, "name", content.ProposalRoute()) - require.Equal(t, "CreateRootName", content.ProposalType()) -} diff --git a/x/name/spec/03_messages.md b/x/name/spec/03_messages.md index b865faecab..9db8b4ba40 100644 --- a/x/name/spec/03_messages.md +++ b/x/name/spec/03_messages.md @@ -6,7 +6,6 @@ In this section we describe the processing of the staking messages and the corre - [MsgBindNameRequest](#msgbindnamerequest) - [MsgDeleteNameRequest](#msgdeletenamerequest) - [MsgModifyNameRequest](#msgmodifynamerequest) - - [CreateRootNameProposal](#createrootnameproposal) - [MsgCreateRootNameRequest](#msgcreaterootnamerequest) ## MsgBindNameRequest @@ -83,29 +82,6 @@ This message is expected to fail if: If successful a name record will be updated with the new address and restriction. -## CreateRootNameProposal - -The create root name proposal is a governance proposal that allows new root level names to be established after the genesis of the blockchain. - -```proto -message CreateRootNameProposal { - option (gogoproto.equal) = false; - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - - string title = 1; - string description = 2; - string name = 3; - string owner = 4; - bool restricted = 5; -} -``` - -This message is expected to fail if: -- The name already exists -- Insuffient length of name -- Excessive length of name - ## MsgCreateRootNameRequest The `MsgCreateRootNameRequest` is a governance proposal that allows new root level names to be established after the genesis of the blockchain. diff --git a/x/name/types/name.pb.go b/x/name/types/name.pb.go index 9aac9e5670..bf2beb62b8 100644 --- a/x/name/types/name.pb.go +++ b/x/name/types/name.pb.go @@ -164,6 +164,10 @@ func (m *NameRecord) GetRestricted() bool { // CreateRootNameProposal details a proposal to create a new root name // that is controlled by a given owner and optionally restricted to the owner // for the sole creation of sub names. +// Deprecated: This legacy proposal is deprecated in favor of Msg-based gov +// proposals, see MsgCreateRootNameRequest. +// +// Deprecated: Do not use. type CreateRootNameProposal struct { // proposal title Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` @@ -404,40 +408,40 @@ func init() { func init() { proto.RegisterFile("provenance/name/v1/name.proto", fileDescriptor_a314256905bb00ec) } var fileDescriptor_a314256905bb00ec = []byte{ - // 518 bytes of a gzipped FileDescriptorProto + // 519 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0xbf, 0x6f, 0x13, 0x3f, - 0x18, 0xc6, 0xcf, 0x6d, 0xd3, 0x6f, 0xe3, 0x2f, 0xa5, 0x91, 0x15, 0xca, 0x51, 0x89, 0x4b, 0x94, - 0x01, 0x55, 0x88, 0xe6, 0x28, 0x2c, 0x88, 0x8d, 0x20, 0xb6, 0x0a, 0x45, 0x57, 0x75, 0x61, 0xe0, - 0x70, 0xee, 0x5e, 0x5d, 0x2d, 0x9d, 0xed, 0x93, 0xed, 0xa4, 0x61, 0x65, 0x40, 0x8c, 0x8c, 0x8c, - 0x19, 0x19, 0x19, 0xf8, 0x1b, 0x10, 0x63, 0xc5, 0xc4, 0x88, 0x92, 0x01, 0xfe, 0x0c, 0x74, 0x76, - 0x7e, 0x1c, 0x61, 0x60, 0x81, 0xe9, 0xfc, 0x3e, 0xcf, 0xe3, 0x7b, 0x3f, 0x7e, 0xa5, 0x17, 0xdf, - 0x2c, 0x94, 0x1c, 0x81, 0xa0, 0x22, 0x81, 0x50, 0x50, 0x0e, 0xe1, 0xe8, 0xd8, 0x7e, 0xbb, 0x85, - 0x92, 0x46, 0x12, 0xb2, 0xb2, 0xbb, 0x56, 0x1e, 0x1d, 0x1f, 0x5c, 0x4f, 0xa4, 0xe6, 0x52, 0x87, - 0x5c, 0x67, 0x65, 0x9a, 0xeb, 0xcc, 0x85, 0x0f, 0x6e, 0x38, 0x23, 0xb6, 0x55, 0xe8, 0x8a, 0xb9, - 0xd5, 0xcc, 0x64, 0x26, 0x9d, 0x5e, 0x9e, 0x9c, 0xda, 0xf9, 0x84, 0xf0, 0x76, 0x9f, 0x2a, 0xca, - 0x35, 0xb9, 0x83, 0x09, 0xa7, 0xe3, 0x58, 0x43, 0xc6, 0x41, 0x98, 0x38, 0x07, 0x91, 0x99, 0x73, - 0x1f, 0xb5, 0xd1, 0xe1, 0x6e, 0xd4, 0xe0, 0x74, 0x7c, 0xea, 0x8c, 0x13, 0xab, 0xdb, 0x34, 0x13, - 0xeb, 0xe9, 0x8d, 0x79, 0x9a, 0x89, 0x5f, 0xd3, 0xb7, 0xf0, 0x5e, 0xf9, 0xef, 0x92, 0x3f, 0xce, - 0x61, 0x04, 0xb9, 0xf6, 0x37, 0x6d, 0x74, 0x97, 0xd3, 0xf1, 0x53, 0xca, 0xe1, 0xc4, 0x8a, 0xe4, - 0x01, 0xf6, 0x69, 0x9e, 0xcb, 0x8b, 0x78, 0x28, 0x14, 0x68, 0xa3, 0x58, 0x62, 0x20, 0xb5, 0xd7, - 0xb4, 0xbf, 0xd5, 0x46, 0x87, 0x3b, 0xd1, 0xbe, 0xf5, 0xcf, 0x2a, 0x76, 0x79, 0x5d, 0x77, 0x5e, - 0x23, 0x8c, 0xcb, 0x53, 0x04, 0x89, 0x54, 0x29, 0x21, 0x78, 0xab, 0xbc, 0x65, 0xf1, 0xeb, 0x91, - 0x3d, 0x93, 0x7b, 0xf8, 0x3f, 0x9a, 0xa6, 0x0a, 0xb4, 0xb6, 0x9c, 0xf5, 0x9e, 0xff, 0xe5, 0xe3, - 0x51, 0x73, 0x3e, 0xa4, 0x47, 0xce, 0x39, 0x35, 0x8a, 0x89, 0x2c, 0x5a, 0x04, 0x49, 0x80, 0xf1, - 0xaa, 0x93, 0x65, 0xde, 0x89, 0x2a, 0xca, 0xc3, 0xc6, 0xbb, 0x49, 0xcb, 0x7b, 0xf5, 0xfd, 0xc3, - 0xed, 0xc5, 0x8d, 0xce, 0x7b, 0x84, 0xf7, 0x1f, 0x2b, 0xa0, 0x06, 0x22, 0x29, 0x4d, 0x89, 0xd4, - 0x57, 0xb2, 0x90, 0x9a, 0xe6, 0xa4, 0x89, 0x6b, 0x86, 0x99, 0x7c, 0x41, 0xe5, 0x0a, 0xd2, 0xc6, - 0xff, 0xa7, 0xa0, 0x13, 0xc5, 0x0a, 0xc3, 0xa4, 0x70, 0x68, 0x51, 0x55, 0x5a, 0x3e, 0x66, 0xb3, - 0xf2, 0x98, 0x26, 0xae, 0xc9, 0x0b, 0x01, 0xca, 0x8e, 0xa5, 0x1e, 0xb9, 0x62, 0x0d, 0xb7, 0xf6, - 0x1b, 0xee, 0x95, 0x37, 0x93, 0x96, 0x57, 0x22, 0xff, 0x98, 0xb4, 0xbc, 0xce, 0x73, 0x7c, 0xf5, - 0xc9, 0x08, 0x84, 0x85, 0xec, 0xc9, 0xa1, 0x48, 0x89, 0xbf, 0x1a, 0x91, 0x63, 0x5c, 0x0e, 0x62, - 0xc1, 0xb0, 0x51, 0x61, 0xf8, 0xc3, 0x70, 0x3a, 0x2f, 0x70, 0x63, 0xf9, 0xff, 0x33, 0x31, 0xf8, - 0x07, 0x1d, 0x62, 0xbc, 0xb7, 0xea, 0x50, 0xa4, 0xd4, 0xc0, 0xdf, 0x6d, 0xd0, 0x4b, 0x3e, 0x4f, - 0x03, 0x74, 0x39, 0x0d, 0xd0, 0xb7, 0x69, 0x80, 0xde, 0xce, 0x02, 0xef, 0x72, 0x16, 0x78, 0x5f, - 0x67, 0x81, 0x87, 0xaf, 0x31, 0xbb, 0x43, 0x6b, 0xab, 0xd9, 0x47, 0xcf, 0xee, 0x66, 0xcc, 0x9c, - 0x0f, 0x07, 0xdd, 0x44, 0xf2, 0x70, 0x15, 0x38, 0x62, 0xb2, 0x52, 0x85, 0x63, 0xb7, 0xea, 0xe6, - 0x65, 0x01, 0x7a, 0xb0, 0x6d, 0x77, 0xf1, 0xfe, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf0, 0xbe, - 0x0f, 0x18, 0x0a, 0x04, 0x00, 0x00, + 0x18, 0xc6, 0xcf, 0x6d, 0xd3, 0x6f, 0xe3, 0xaf, 0xda, 0x46, 0x56, 0x28, 0x47, 0x25, 0x2e, 0x51, + 0x06, 0x54, 0x21, 0x9a, 0xa3, 0xb0, 0x20, 0x36, 0x82, 0xd8, 0x2a, 0x14, 0x5d, 0xd5, 0x85, 0x81, + 0xc3, 0xb9, 0x7b, 0x75, 0xb5, 0x74, 0xb6, 0x4f, 0xb6, 0x93, 0x86, 0x95, 0x01, 0x31, 0x32, 0x32, + 0x66, 0x66, 0x62, 0xe0, 0x6f, 0x40, 0x8c, 0x15, 0x13, 0x23, 0x4a, 0x06, 0xf8, 0x33, 0xd0, 0xd9, + 0xf9, 0x71, 0x84, 0x81, 0x05, 0xa6, 0xf3, 0xfb, 0x3c, 0x8f, 0xef, 0xfd, 0xf8, 0x95, 0x5e, 0x7c, + 0xb3, 0x50, 0x72, 0x04, 0x82, 0x8a, 0x04, 0x42, 0x41, 0x39, 0x84, 0xa3, 0x13, 0xfb, 0xed, 0x16, + 0x4a, 0x1a, 0x49, 0xc8, 0xca, 0xee, 0x5a, 0x79, 0x74, 0x72, 0x78, 0x3d, 0x91, 0x9a, 0x4b, 0x1d, + 0x72, 0x9d, 0x95, 0x69, 0xae, 0x33, 0x17, 0x3e, 0xbc, 0xe1, 0x8c, 0xd8, 0x56, 0xa1, 0x2b, 0xe6, + 0x56, 0x33, 0x93, 0x99, 0x74, 0x7a, 0x79, 0x72, 0x6a, 0xe7, 0x13, 0xc2, 0xdb, 0x7d, 0xaa, 0x28, + 0xd7, 0xe4, 0x0e, 0x26, 0x9c, 0x8e, 0x63, 0x0d, 0x19, 0x07, 0x61, 0xe2, 0x1c, 0x44, 0x66, 0x2e, + 0x7c, 0xd4, 0x46, 0x47, 0xbb, 0x51, 0x83, 0xd3, 0xf1, 0x99, 0x33, 0x4e, 0xad, 0x6e, 0xd3, 0x4c, + 0xac, 0xa7, 0x37, 0xe6, 0x69, 0x26, 0x7e, 0x4d, 0xdf, 0xc2, 0xfb, 0xe5, 0xbf, 0x4b, 0xfe, 0x38, + 0x87, 0x11, 0xe4, 0xda, 0xdf, 0xb4, 0xd1, 0x5d, 0x4e, 0xc7, 0x4f, 0x29, 0x87, 0x53, 0x2b, 0x92, + 0x07, 0xd8, 0xa7, 0x79, 0x2e, 0x2f, 0xe3, 0xa1, 0x50, 0xa0, 0x8d, 0x62, 0x89, 0x81, 0xd4, 0x5e, + 0xd3, 0xfe, 0x56, 0x1b, 0x1d, 0xed, 0x44, 0x07, 0xd6, 0x3f, 0xaf, 0xd8, 0xe5, 0x75, 0xdd, 0x79, + 0x8d, 0x30, 0x2e, 0x4f, 0x11, 0x24, 0x52, 0xa5, 0x84, 0xe0, 0xad, 0xf2, 0x96, 0xc5, 0xaf, 0x47, + 0xf6, 0x4c, 0xee, 0xe1, 0xff, 0x68, 0x9a, 0x2a, 0xd0, 0xda, 0x72, 0xd6, 0x7b, 0xfe, 0x97, 0x8f, + 0xc7, 0xcd, 0xf9, 0x90, 0x1e, 0x39, 0xe7, 0xcc, 0x28, 0x26, 0xb2, 0x68, 0x11, 0x24, 0x01, 0xc6, + 0xab, 0x4e, 0x96, 0x79, 0x27, 0xaa, 0x28, 0x0f, 0x1b, 0xef, 0x26, 0x2d, 0xef, 0xd5, 0xf7, 0x0f, + 0xb7, 0x17, 0x37, 0x3a, 0xef, 0x11, 0x3e, 0x78, 0xac, 0x80, 0x1a, 0x88, 0xa4, 0x34, 0x25, 0x52, + 0x5f, 0xc9, 0x42, 0x6a, 0x9a, 0x93, 0x26, 0xae, 0x19, 0x66, 0xf2, 0x05, 0x95, 0x2b, 0x48, 0x1b, + 0xff, 0x9f, 0x82, 0x4e, 0x14, 0x2b, 0x0c, 0x93, 0xc2, 0xa1, 0x45, 0x55, 0x69, 0xf9, 0x98, 0xcd, + 0xca, 0x63, 0x9a, 0xb8, 0x26, 0x2f, 0x05, 0x28, 0x3b, 0x96, 0x7a, 0xe4, 0x8a, 0x35, 0xdc, 0xda, + 0x6f, 0xb8, 0x7b, 0x6f, 0x26, 0x2d, 0xaf, 0x44, 0xfe, 0x31, 0x69, 0x79, 0x3e, 0xea, 0x3c, 0xc7, + 0x7b, 0x4f, 0x46, 0x20, 0x2c, 0x66, 0x4f, 0x0e, 0x45, 0x4a, 0xfc, 0xd5, 0x90, 0x1c, 0xe5, 0x72, + 0x14, 0x0b, 0x8a, 0x8d, 0x0a, 0xc5, 0x1f, 0xc6, 0xd3, 0x79, 0x81, 0x1b, 0xcb, 0xff, 0x9f, 0x8b, + 0xc1, 0x3f, 0xe8, 0x10, 0xe3, 0xfd, 0x55, 0x87, 0x22, 0xa5, 0x06, 0xfe, 0x6e, 0x83, 0x5e, 0xf2, + 0x79, 0x1a, 0xa0, 0xab, 0x69, 0x80, 0xbe, 0x4d, 0x03, 0xf4, 0x76, 0x16, 0x78, 0x57, 0xb3, 0xc0, + 0xfb, 0x3a, 0x0b, 0x3c, 0x7c, 0x8d, 0xd9, 0x2d, 0x5a, 0x5b, 0xce, 0x3e, 0x7a, 0x76, 0x37, 0x63, + 0xe6, 0x62, 0x38, 0xe8, 0x26, 0x92, 0x87, 0xab, 0xc0, 0x31, 0x93, 0x95, 0x2a, 0x1c, 0xbb, 0x65, + 0x37, 0x2f, 0x0b, 0xd0, 0x83, 0x6d, 0xbb, 0x8d, 0xf7, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0xe8, + 0xe0, 0x0a, 0x44, 0x0c, 0x04, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) {