Skip to content

Commit

Permalink
Add update params to name module (#2004)
Browse files Browse the repository at this point in the history
* add proto defs

* add msg server endpoint

* add msg interface impls

* add event for param updated

* add spec

* add msg tests

* add msg server tests

* add command

* add cli tests

* add change log entry

* fix lint
  • Loading branch information
nullpointer0x00 authored May 28, 2024
1 parent 7cdb94f commit 1d7d9dc
Show file tree
Hide file tree
Showing 18 changed files with 1,142 additions and 72 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* `ibcratelimit` add `UpdateParams` endpoint and deprecate `GovUpdateParams` [#1984](https://github.com/provenance-io/provenance/pull/1984).
* `attribute` add `UpdateParams` endpoint and cli [#1987](https://github.com/provenance-io/provenance/pull/1987).
* `marker` add `UpdateParams` endpoint and cli [#1991](https://github.com/provenance-io/provenance/pull/1991).
* `name` add `UpdateParams` endpoint and cli [#2004](https://github.com/provenance-io/provenance/pull/2004).
* Update the exchange `commitment-settlement-fee-calc` cli query to utilize the keyring [#2001](https://github.com/provenance-io/provenance/pull/2001).

### Client Breaking
Expand Down
2 changes: 1 addition & 1 deletion client/docs/statik/statik.go

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions client/docs/swagger-ui/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117041,6 +117041,11 @@ definitions:
provenance.name.v1.MsgModifyNameResponse:
type: object
description: MsgModifyNameResponse defines the Msg/ModifyName response type.
provenance.name.v1.MsgUpdateParamsResponse:
type: object
description: >-
MsgUpdateParamsResponse is a response message for the UpdateParams
endpoint.
provenance.name.v1.NameRecord:
type: object
properties:
Expand Down
8 changes: 8 additions & 0 deletions proto/provenance/name/v1/name.proto
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,11 @@ message EventNameUpdate {
string name = 2;
bool restricted = 3;
}

// EventNameParamsUpdated event emitted when name params are updated.
message EventNameParamsUpdated {
string allow_unrestricted_names = 1;
string max_name_levels = 2;
string min_segment_length = 3;
string max_segment_length = 4;
}
17 changes: 17 additions & 0 deletions proto/provenance/name/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ service Msg {

// CreateRootName defines a governance method for creating a root name.
rpc CreateRootName(MsgCreateRootNameRequest) returns (MsgCreateRootNameResponse);

// UpdateParams is a governance proposal endpoint for updating the name module's params.
rpc UpdateParams(MsgUpdateParamsRequest) returns (MsgUpdateParamsResponse);
}

// MsgBindNameRequest defines an sdk.Msg type that is used to add an address/name binding under an optional parent name.
Expand Down Expand Up @@ -87,3 +90,17 @@ message MsgModifyNameRequest {

// MsgModifyNameResponse defines the Msg/ModifyName response type.
message MsgModifyNameResponse {}

// MsgUpdateParamsRequest is a request message for the UpdateParams endpoint.
message MsgUpdateParamsRequest {
option (cosmos.msg.v1.signer) = "authority";

// authority should be the governance module account address.
string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];

// params are the new param values to set.
Params params = 2 [(gogoproto.nullable) = false];
}

// MsgUpdateParamsResponse is a response message for the UpdateParams endpoint.
message MsgUpdateParamsResponse {}
84 changes: 84 additions & 0 deletions x/name/client/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -713,3 +713,87 @@ func (s *IntegrationTestSuite) TestGovRootNameCmd() {
})
}
}

func (s *IntegrationTestSuite) TestUpdateNameParamsCmd() {
testCases := []struct {
name string
cmd *cobra.Command
args []string
expectErr string
expectedCode uint32
}{
{
name: "update name params, should succeed",
cmd: namecli.GetUpdateNameParamsCmd(),
args: []string{
"16",
"2",
"5",
"true",
},
expectedCode: 0,
},
{
name: "update name params, should fail incorrect max segment length",
cmd: namecli.GetUpdateNameParamsCmd(),
args: []string{
"invalid",
"2",
"5",
"true",
},
expectErr: `invalid max segment length: strconv.ParseUint: parsing "invalid": invalid syntax`,
},
{
name: "update name params, should fail incorrect min segment length",
cmd: namecli.GetUpdateNameParamsCmd(),
args: []string{
"16",
"invalid",
"5",
"true",
},
expectErr: `invalid min segment length: strconv.ParseUint: parsing "invalid": invalid syntax`,
},
{
name: "update name params, should fail incorrect max name levels",
cmd: namecli.GetUpdateNameParamsCmd(),
args: []string{
"16",
"2",
"invalid",
"true",
},
expectErr: `invalid max name levels: strconv.ParseUint: parsing "invalid": invalid syntax`,
},
{
name: "update name params, should fail incorrect unrestricted names flag",
cmd: namecli.GetUpdateNameParamsCmd(),
args: []string{
"16",
"2",
"5",
"invalid",
},
expectErr: `invalid allow unrestricted names flag: strconv.ParseBool: parsing "invalid": invalid syntax`,
},
}

for _, tc := range testCases {
s.Run(tc.name, func() {
tc.args = append(tc.args,
"--title", fmt.Sprintf("title: %v", tc.name),
"--summary", fmt.Sprintf("summary: %v", tc.name),
"--deposit=1000000stake",
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()),
)
testcli.NewTxExecutor(tc.cmd, tc.args).
WithExpErrMsg(tc.expectErr).
WithExpCode(tc.expectedCode).
Execute(s.T(), s.testnet)
})
}
}
56 changes: 56 additions & 0 deletions x/name/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cli

import (
"fmt"
"strconv"
"strings"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -231,3 +232,58 @@ func owner(ctx client.Context, flags *pflag.FlagSet) (string, error) {

return proposalOwner, nil
}

// GetUpdateNameParamsCmd creates a command to update the name module's params via governance proposal.
func GetUpdateNameParamsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-name-params <max-segment-length> <min-segment-length> <max-name-levels> <allow-unrestricted-names>",
Short: "Update the name module's params via governance proposal",
Long: "Submit an update name params via governance proposal along with an initial deposit.",
Args: cobra.ExactArgs(4),
Example: fmt.Sprintf(`%[1]s tx name update-name-params 16 2 5 true --deposit 50000nhash`, version.AppName),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

flagSet := cmd.Flags()
authority := provcli.GetAuthority(flagSet)

maxSegmentLength, err := strconv.ParseUint(args[0], 10, 32)
if err != nil {
return fmt.Errorf("invalid max segment length: %w", err)
}

minSegmentLength, err := strconv.ParseUint(args[1], 10, 32)
if err != nil {
return fmt.Errorf("invalid min segment length: %w", err)
}

maxNameLevels, err := strconv.ParseUint(args[2], 10, 32)
if err != nil {
return fmt.Errorf("invalid max name levels: %w", err)
}

allowUnrestrictedNames, err := strconv.ParseBool(args[3])
if err != nil {
return fmt.Errorf("invalid allow unrestricted names flag: %w", err)
}

msg := types.NewMsgUpdateParamsRequest(
uint32(maxSegmentLength),
uint32(minSegmentLength),
uint32(maxNameLevels),
allowUnrestrictedNames,
authority,
)
return provcli.GenerateOrBroadcastTxCLIAsGovProp(clientCtx, flagSet, msg)
},
}

govcli.AddGovPropFlagsToCmd(cmd)
provcli.AddAuthorityFlagToCmd(cmd)
flags.AddTxFlagsToCmd(cmd)

return cmd
}
22 changes: 18 additions & 4 deletions x/name/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,24 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", "x/"+types.ModuleName)
}

// GetAuthority is signer of the proposal
func (k Keeper) GetAuthority() string {
return k.authority
}

// IsAuthority returns true if the provided address bech32 string is the authority address.
func (k Keeper) IsAuthority(addr string) bool {
return strings.EqualFold(k.authority, addr)
}

// ValidateAuthority returns an error if the provided address is not the authority.
func (k Keeper) ValidateAuthority(addr string) error {
if !k.IsAuthority(addr) {
return govtypes.ErrInvalidSigner.Wrapf("expected %q got %q", k.GetAuthority(), addr)
}
return nil
}

// SetAttributeKeeper sets the attribute keeper
func (k *Keeper) SetAttributeKeeper(ak types.AttributeKeeper) {
if k.attrKeeper != nil && ak != nil && k.attrKeeper != ak {
Expand Down Expand Up @@ -291,10 +309,6 @@ func (k Keeper) addRecord(ctx sdk.Context, name string, addr sdk.AccAddress, res
return nil
}

func (k Keeper) GetAuthority() string {
return k.authority
}

// DeleteInvalidAddressIndexEntries is only for the rust upgrade. It goes over all the address -> name entries and
// deletes any that are no longer accurate.
func (k Keeper) DeleteInvalidAddressIndexEntries(ctx sdk.Context) {
Expand Down
20 changes: 20 additions & 0 deletions x/name/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,23 @@ func (s msgServer) CreateRootName(goCtx context.Context, msg *types.MsgCreateRoo

return &types.MsgCreateRootNameResponse{}, nil
}

// UpdateParams is a governance proposal endpoint for updating the name module's params.
func (s msgServer) UpdateParams(goCtx context.Context, msg *types.MsgUpdateParamsRequest) (*types.MsgUpdateParamsResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

if err := s.ValidateAuthority(msg.Authority); err != nil {
return nil, err
}

s.SetParams(ctx, msg.Params)
if err := ctx.EventManager().EmitTypedEvent(types.NewEventNameParamsUpdated(
msg.Params.AllowUnrestrictedNames,
msg.Params.MaxNameLevels,
msg.Params.MaxSegmentLength,
msg.Params.MinSegmentLength)); err != nil {
return nil, err
}

return &types.MsgUpdateParamsResponse{}, nil
}
55 changes: 55 additions & 0 deletions x/name/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,3 +376,58 @@ func (s *MsgServerTestSuite) TestCreateRootName() {
})
}
}

func (s *MsgServerTestSuite) TestUpdateParams() {
authority := s.app.NameKeeper.GetAuthority()

tests := []struct {
name string
expErr string
msg *types.MsgUpdateParamsRequest
expectedEvent proto.Message
}{
{
name: "valid authority with valid params",
msg: types.NewMsgUpdateParamsRequest(
100,
3,
10,
true,
authority,
),
expectedEvent: types.NewEventNameParamsUpdated(
true,
10,
100,
3,
),
},
{
name: "invalid authority",
msg: types.NewMsgUpdateParamsRequest(
100,
3,
10,
true,
"invalid-authority",
),
expErr: `expected "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn" got "invalid-authority": expected gov account as only signer for proposal message`,
},
}

for _, tc := range tests {
s.Run(tc.name, func() {
s.ctx = s.ctx.WithEventManager(sdk.NewEventManager())
_, err := s.msgServer.UpdateParams(s.ctx, tc.msg)
if len(tc.expErr) > 0 {
s.Require().EqualError(err, tc.expErr, "Expected error message did not match")
} else {
s.Require().NoError(err, "Expected no error but got: %v", err)
}
if tc.expectedEvent != nil {
result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), tc.expectedEvent)
s.Require().True(result, "Expected typed event was not found: %v", tc.expectedEvent)
}
})
}
}
2 changes: 1 addition & 1 deletion x/name/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
// SetParams sets the name parameters to the store.
func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(&params) // Serialize parameters to bytes
bz := k.cdc.MustMarshal(&params)
store.Set(types.NameParamStoreKey, bz)
}

Expand Down
10 changes: 10 additions & 0 deletions x/name/spec/04_events.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The name module emits the following events:
- [MsgDeleteNameRequest](#msgdeletenamerequest)
- [MsgModifyNameRequest](#msgmodifynamerequest)
- [CreateRootNameProposal](#createrootnameproposal)
- [EventNameParamsUpdated](#eventnameparamsupdated)

## Handlers

Expand Down Expand Up @@ -45,3 +46,12 @@ The name module emits the following events:
| name_bound | name | \{NameRecord|Name\} |
| name_bound | address | \{NameRecord|Address\} |
| name_bound | restricted | \{NameRecord|Restricted\} |

### EventNameParamsUpdated

| Type | Attribute Key | Attribute Value |
| ------------------------ | -------------------------- | --------------------------- |
| name_params_updated | allow_unrestricted_names | \{Boolean\} |
| name_params_updated | max_name_levels | \{String\} |
| name_params_updated | min_segment_length | \{String\} |
| name_params_updated | max_segment_length | \{String\} |
12 changes: 12 additions & 0 deletions x/name/types/events.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package types

import "strconv"

const (
// EventTypeNameBound is the type of event generated when a name is bound to an address.
EventTypeNameBound string = "name_bound"
Expand Down Expand Up @@ -35,3 +37,13 @@ func NewEventNameUpdate(address string, name string, restricted bool) *EventName
Restricted: restricted,
}
}

// NewEventNameParamsUpdated returns a new instance of EventNameParamsUpdated
func NewEventNameParamsUpdated(allowUnrestrictedNames bool, maxNameLevels, minSegmentLength, maxSegmentLength uint32) *EventNameParamsUpdated {
return &EventNameParamsUpdated{
AllowUnrestrictedNames: strconv.FormatBool(allowUnrestrictedNames),
MaxNameLevels: strconv.FormatUint(uint64(maxNameLevels), 10),
MinSegmentLength: strconv.FormatUint(uint64(minSegmentLength), 10),
MaxSegmentLength: strconv.FormatUint(uint64(maxSegmentLength), 10),
}
}
Loading

0 comments on commit 1d7d9dc

Please sign in to comment.