Skip to content

Commit

Permalink
Add UpdateParams to attribute module (#1987)
Browse files Browse the repository at this point in the history
* add update params rpc proto def

* add msg server endpoint, add gov authority address to keeper, add authority checking

* add msg server endpoint impl, add typed event, add test

* add msg validate basic, register msg

* add cli command

* register commands, add test

* add change log

* fix change log link

* fix changelog spacing

* add error handling
  • Loading branch information
nullpointer0x00 authored May 22, 2024
1 parent 1519183 commit 0210fda
Show file tree
Hide file tree
Showing 15 changed files with 919 additions and 103 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* Replace deprecated wasm features [#1988](https://github.com/provenance-io/provenance/pull/1988).
* Add `UpdateParams` and `Params` query rpc endpoints to modules.
* `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).

### 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 @@ -100875,6 +100875,11 @@ definitions:
provenance.attribute.v1.MsgUpdateAttributeResponse:
type: object
description: MsgUpdateAttributeResponse defines the Msg/UpdateAttribute response type.
provenance.attribute.v1.MsgUpdateParamsResponse:
type: object
description: >-
MsgUpdateParamsResponse is a response message for the UpdateParams
endpoint.
provenance.exchange.v1.AccessGrant:
type: object
properties:
Expand Down
5 changes: 5 additions & 0 deletions proto/provenance/attribute/v1/attribute.proto
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,8 @@ message EventAttributeExpired {
message EventAccountDataUpdated {
string account = 1;
}

// EventAttributeParamsUpdated event emitted when attribute params are updated.
message EventAttributeParamsUpdated {
string max_value_length = 1;
}
18 changes: 17 additions & 1 deletion proto/provenance/attribute/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ option java_package = "io.provenance.attribute.v1";
option java_multiple_files = true;

import "cosmos/msg/v1/msg.proto";
import "cosmos_proto/cosmos.proto";
import "gogoproto/gogo.proto";
import "google/protobuf/timestamp.proto";
import "provenance/attribute/v1/attribute.proto";
Expand All @@ -31,7 +32,8 @@ service Msg {
// SetAccountData defines a method for setting/updating an account's accountdata attribute.
rpc SetAccountData(MsgSetAccountDataRequest) returns (MsgSetAccountDataResponse);

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

// MsgAddAttributeRequest defines an sdk.Msg type that is used to add a new attribute to an account.
Expand Down Expand Up @@ -144,3 +146,17 @@ message MsgSetAccountDataRequest {

// MsgSetAccountDataResponse defines the Msg/SetAccountData response type.
message MsgSetAccountDataResponse {}

// 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 {}
36 changes: 36 additions & 0 deletions x/attribute/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cli
import (
"encoding/base64"
"fmt"
"strconv"
"strings"
"time"

Expand All @@ -12,7 +13,9 @@ import (
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/version"
govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli"

"github.com/provenance-io/provenance/internal/provcli"
"github.com/provenance-io/provenance/x/attribute/types"
)

Expand All @@ -33,6 +36,7 @@ func NewTxCmd() *cobra.Command {
NewDeleteAccountAttributeCmd(),
NewSetAccountDataCmd(),
NewUpdateAccountAttributeExpirationCmd(),
NewUpdateParamsCmd(),
)
return txCmd
}
Expand Down Expand Up @@ -314,3 +318,35 @@ $ %[1]s tx attribute account-data --%s

return cmd
}

// NewUpdateParamsCmd creates a command to update the attribute module's params via governance proposal.
func NewUpdateParamsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-params <max-value-length>",
Short: "Update the attribute module's params via governance proposal",
Long: "Submit an update params via governance proposal along with an initial deposit.",
Args: cobra.ExactArgs(1),
Example: fmt.Sprintf(`%[1]s tx attribute update-params 100 --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)
maxValueLength, err := strconv.ParseUint(args[0], 10, 32)
if err != nil {
return fmt.Errorf("invalid max value length: %w", err)
}
msg := types.NewMsgUpdateParamsRequest(authority, uint32(maxValueLength))
return provcli.GenerateOrBroadcastTxCLIAsGovProp(clientCtx, flagSet, msg)
},
}

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

return cmd
}
22 changes: 22 additions & 0 deletions x/attribute/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"

"github.com/provenance-io/provenance/x/attribute/types"
)
Expand All @@ -35,6 +36,8 @@ type Keeper struct {
cdc codec.BinaryCodec

modAddr sdk.AccAddress

authority string
}

// NewKeeper returns an attribute keeper. It handles:
Expand All @@ -53,11 +56,30 @@ func NewKeeper(
nameKeeper: nameKeeper,
cdc: cdc,
modAddr: authtypes.NewModuleAddress(types.ModuleName),
authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
}
nameKeeper.SetAttributeKeeper(keeper)
return keeper
}

// 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
}

// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
Expand Down
16 changes: 16 additions & 0 deletions x/attribute/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,19 @@ func (k msgServer) SetAccountData(goCtx context.Context, msg *types.MsgSetAccoun

return &types.MsgSetAccountDataResponse{}, nil
}

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

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

k.SetParams(ctx, msg.Params)
if err := ctx.EventManager().EmitTypedEvent(types.NewEventAttributeParamsUpdated(msg.Params)); err != nil {
return nil, err
}

return &types.MsgUpdateParamsResponse{}, nil
}
45 changes: 45 additions & 0 deletions x/attribute/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,48 @@ func (s *MsgServerTestSuite) TestMsgDeleteAttributeRequest() {
})
}
}

func (s *MsgServerTestSuite) TestUpdateParams() {
newParams := types.Params{
MaxValueLength: 200,
}

tests := []struct {
name string
msg types.MsgUpdateParamsRequest
errorMsg string
}{
{
name: "Should fail due to invalid authority",
msg: types.MsgUpdateParamsRequest{
Authority: "invalid-authority",
Params: newParams,
},
errorMsg: `expected "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn" got "invalid-authority": expected gov account as only signer for proposal message`,
},
{
name: "Should succeed",
msg: types.MsgUpdateParamsRequest{
Authority: authtypes.NewModuleAddress("gov").String(),
Params: newParams,
},
},
}

for _, tt := range tests {
s.Run(tt.name, func() {
s.ctx = s.ctx.WithEventManager(sdk.NewEventManager())
response, err := s.msgServer.UpdateParams(s.ctx, &tt.msg)
if len(tt.errorMsg) > 0 {
s.Assert().Error(err)
s.Assert().Equal(tt.errorMsg, err.Error())
s.Assert().Nil(response)
} else {
s.Assert().NoError(err)
s.Assert().NotNil(response)
result := s.containsMessage(s.ctx.EventManager().ABCIEvents(), types.NewEventAttributeParamsUpdated(newParams))
s.True(result, fmt.Sprintf("Expected typed event was not found: %v", types.NewEventAttributeParamsUpdated(newParams)))
}
})
}
}
Loading

0 comments on commit 0210fda

Please sign in to comment.