From 961b006f8f2157a7ed772414b250decd46035800 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 26 Sep 2024 10:12:23 +0200 Subject: [PATCH 01/21] docs: update "adding params" --- .../develop/developer_guide/adding_params.md | 141 +++++++++++++++++- 1 file changed, 133 insertions(+), 8 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index 37ff71d1f..99bf3b1ac 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -43,6 +43,83 @@ https://github.com/ignite/cli/issues/3684#issuecomment-2299796210 ## Step-by-Step Instructions +### 0. If the Module Doesn't Already Support a `MsgUpdateParam` Message + +In order to support **individual parameter updates**, the module MUST have a `MsgUpdateParam` message. +If the module doesn't already support this message, it will need to be added. + +### 0.1 Scaffold the `MsgUpdateParam` Message + +```bash +ignite scaffold message update-param --module --signer authority name as_type --response params +``` + +### 0.2 Update the `MsgUpdateParam` Message Fields + +Update the `MsgUpdateParam` message fields in the module's `tx.proto` file to include the following comments and protobuf options: + +```diff ++// MsgUpdateParam is the Msg/UpdateParam request type to update a single param. + message MsgUpdateParam { + option (cosmos.msg.v1.signer) = "authority"; +- string authority = 1; ++ ++ // authority is the address that controls the module (defaults to x/gov unless overwritten). ++ string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; ++ + string name = 2; +- string asType = 3; ++ oneof as_type { ++ // Add `as_` fields for each type in this module's Params type; e.g.: ++ // int64 as_int64 = 3 [(gogoproto.jsontag) = "as_int64"]; ++ // bytes as_bytes = 4 [(gogoproto.jsontag) = "as_bytes"]; ++ // cosmos.base.v1beta1.Coin as_coin = 5 [(gogoproto.jsontag) = "as_coin"]; ++ } + } + + message MsgUpdateParamResponse { +``` + +### 0.3 Comment Out AutoCLI + +When scaffolding the `MsgUpdateParam` message, lines are added to `x//module/autocli.go`. +Since governance parameters aren't updated via `poktrolld` CLI, comment out these new lines: + +```diff +... +Tx: &autocliv1.ServiceCommandDescriptor{ + Service: modulev1.Msg_ServiceDesc.ServiceName, + EnhanceCustomCommand: true, // only required if you want to use the custom command + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + ... ++ // { ++ // RpcMethod: "UpdateParam", ++ // Use: "update-param [name] [as-type]", ++ // Short: "Send a update-param tx", ++ // PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "name"}, {ProtoField: "asType"}}, ++ // }, + // this line is used by ignite scaffolding # autocli/tx + }, +}, +... +``` + +### 0.4. Update the DAO Genesis Authorizations JSON File + +Add a grant (array element) to `tools/scripts/authz/dao_genesis_authorizations.json` with the `authorization.msg` typeURL for this module's `MsgUpdateType`: + +```json + { + "granter": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", + "grantee": "pokt1eeeksh2tvkh7wzmfrljnhw4wrhs55lcuvmekkw", + "authorization": { + "@type": "\/cosmos.authz.v1beta1.GenericAuthorization", + "msg": "\/poktroll..MsgUpdateParam" + }, + "expiration": "2500-01-01T00:00:00Z" + }, +``` + ### 1. Define the Parameter in the Protocol Buffers File Open the appropriate `.proto` file for your module (e.g., `params.proto`) and define the new parameter. @@ -56,9 +133,57 @@ message Params { } ``` -### 2 Update the Parameter Integration Tests +### 2 Update the Parameter Integration Tests -// TODO_DOCUMENT(@bryanchriswhite, #826) +Integration tests which cover parameter updates utilize the `ModuleParamConfig`s defined in [`testutil/integration/params/param_configs.go`](https://github.com/pokt-network/poktroll/blob/main/testutil/integration/suites/param_configs.go) to dynamically (i.e. using reflection) construct and send parameter update messages in a test environment. +When adding parameters to a module, it is necessary to update that module's `ModuleParamConfig` to include the new parameter, othwerwise it will not be covered by the integration test suite. + +### 2.1 If the Module Didn't Previously Support a `MsgUpdateParam` Message + + Add `MsgUpdateParam` & `MsgUpdateParamResponse` to the module's `ModuleParamConfig#ParamsMsg`: + +```diff +SomeModuleParamConfig = ModuleParamConfig{ + ParamsMsgs: ModuleParamsMessages{ + MsgUpdateParams: gatewaytypes.MsgUpdateParams{}, + MsgUpdateParamsResponse: gatewaytypes.MsgUpdateParamsResponse{}, ++ MsgUpdateParam: gatewaytypes.MsgUpdateParam{}, ++ MsgUpdateParamResponse: gatewaytypes.MsgUpdateParamResponse{}, + QueryParamsRequest: gatewaytypes.QueryParamsRequest{}, + QueryParamsResponse: gatewaytypes.QueryParamsResponse{}, + }, + ... +} +``` + +### 2.2 Add a valid param + +Update `ModuleParamConfig#ValidParams` to include a valid and non-default value for the new parameter. + +```diff +SomeModuleParamConfig = ModuleParamConfig{ + ... + ValidParams: gatewaytypes.Params{ ++ MinStake: &ValidActorMinStake, + }, + ... +} +``` + +### 2.3 Check for `as_` on `MsgUpdateParam` + +Ensure an `as_` field exists on `MsgUpdateParam` corresponding to the type of the new parameter. +Below is an example of adding an `int64` type parameter to a new `MsgUpdateParam` message: + +```diff + message MsgUpdateParam { + ... + oneof as_type { +- // Add `as_` fields for each type in this module's Params type; e.g.: ++ int64 as_int64 = 3 [(gogoproto.jsontag) = "as_int64"]; + } + } +``` ### 3. Update the Default Parameter Values @@ -110,9 +235,9 @@ genesis: Add a new target in the `Makefile` to update the new parameter. ```makefile -.PHONY: params_update_proof_new_parameter_name -params_update_proof_new_parameter_name: ## Update the proof module new_parameter_name param - poktrolld tx authz exec ./tools/scripts/params/proof_new_parameter_name.json $(PARAM_FLAGS) +.PHONY: params_update__ +params_update__: ## Update the module param + poktrolld tx authz exec ./tools/scripts/params/_.json $(PARAM_FLAGS) ``` ### 6. Create a new JSON File for the Individual Parameter Update @@ -127,8 +252,8 @@ directory to specify how to update the new parameter. { "@type": "/poktroll.proof.MsgUpdateParam", "authority": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", - "name": "new_parameter_name", - "as_int64": "100" + "name": "", + "as_int64": "" } ] } @@ -151,7 +276,7 @@ with the default value for the new parameter. "min_relay_difficulty_bits": "0", "proof_request_probability": "0.25", "proof_requirement_threshold": "20", - "new_parameter_name": "100" // Add this line + "": "" // Add this line } } ] From 4463ecbc583a0120fa94e3faa876c7e43e438d7c Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 26 Sep 2024 12:41:54 +0200 Subject: [PATCH 02/21] docs: re-org and add detail --- .../develop/developer_guide/adding_params.md | 470 ++++++++++-------- 1 file changed, 273 insertions(+), 197 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index 99bf3b1ac..cf20d2e49 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -43,81 +43,93 @@ https://github.com/ignite/cli/issues/3684#issuecomment-2299796210 ## Step-by-Step Instructions +:::warning +The steps outlined below follow **the same example** where: +- **Module name**: `examplemod` +- **New parameter name**: `new_param` +- **Default value**: `42` + +When following these steps, be sure to substitute these example values with your own! +::: + ### 0. If the Module Doesn't Already Support a `MsgUpdateParam` Message In order to support **individual parameter updates**, the module MUST have a `MsgUpdateParam` message. If the module doesn't already support this message, it will need to be added. -### 0.1 Scaffold the `MsgUpdateParam` Message +#### 0.1 Scaffold the `MsgUpdateParam` Message + +Use `ignite` to scaffold a new `MsgUpdateParam` message for the module. +Additional flags are used for convenience: ```bash -ignite scaffold message update-param --module --signer authority name as_type --response params +ignite scaffold message update-param --module examplemod --signer authority name as_type --response params ``` -### 0.2 Update the `MsgUpdateParam` Message Fields +#### 0.2 Update the `MsgUpdateParam` Message Fields Update the `MsgUpdateParam` message fields in the module's `tx.proto` file to include the following comments and protobuf options: -```diff -+// MsgUpdateParam is the Msg/UpdateParam request type to update a single param. - message MsgUpdateParam { - option (cosmos.msg.v1.signer) = "authority"; -- string authority = 1; -+ -+ // authority is the address that controls the module (defaults to x/gov unless overwritten). -+ string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; -+ - string name = 2; -- string asType = 3; -+ oneof as_type { -+ // Add `as_` fields for each type in this module's Params type; e.g.: -+ // int64 as_int64 = 3 [(gogoproto.jsontag) = "as_int64"]; -+ // bytes as_bytes = 4 [(gogoproto.jsontag) = "as_bytes"]; -+ // cosmos.base.v1beta1.Coin as_coin = 5 [(gogoproto.jsontag) = "as_coin"]; -+ } - } - - message MsgUpdateParamResponse { +```protobuf ++ // MsgUpdateParam is the Msg/UpdateParam request type to update a single param. + message MsgUpdateParam { + option (cosmos.msg.v1.signer) = "authority"; +- string authority = 1; ++ ++ // authority is the address that controls the module (defaults to x/gov unless overwritten). ++ string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; ++ + string name = 2; +- string asType = 3; ++ oneof as_type { ++ // Add `as_` fields for each type in this module's Params type; e.g.: ++ // int64 as_int64 = 3 [(gogoproto.jsontag) = "as_int64"]; ++ // bytes as_bytes = 4 [(gogoproto.jsontag) = "as_bytes"]; ++ // cosmos.base.v1beta1.Coin as_coin = 5 [(gogoproto.jsontag) = "as_coin"]; ++ } + } + + message MsgUpdateParamResponse { ``` -### 0.3 Comment Out AutoCLI +#### 0.3 Comment Out AutoCLI -When scaffolding the `MsgUpdateParam` message, lines are added to `x//module/autocli.go`. +When scaffolding the `MsgUpdateParam` message, lines are added to `x/examplemod/module/autocli.go`. Since governance parameters aren't updated via `poktrolld` CLI, comment out these new lines: -```diff -... -Tx: &autocliv1.ServiceCommandDescriptor{ - Service: modulev1.Msg_ServiceDesc.ServiceName, - EnhanceCustomCommand: true, // only required if you want to use the custom command - RpcCommandOptions: []*autocliv1.RpcCommandOptions{ - ... -+ // { -+ // RpcMethod: "UpdateParam", -+ // Use: "update-param [name] [as-type]", -+ // Short: "Send a update-param tx", -+ // PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "name"}, {ProtoField: "asType"}}, -+ // }, - // this line is used by ignite scaffolding # autocli/tx - }, -}, -... +```go + // ... + Tx: &autocliv1.ServiceCommandDescriptor{ + Service: modulev1.Msg_ServiceDesc.ServiceName, + EnhanceCustomCommand: true, // only required if you want to use the custom command + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + // ... ++ // { ++ // RpcMethod: "UpdateParam", ++ // Use: "update-param [name] [as-type]", ++ // Short: "Send a update-param tx", ++ // PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "name"}, {ProtoField: "asType"}}, ++ // }, + // this line is used by ignite scaffolding # autocli/tx + }, + }, + // ... ``` -### 0.4. Update the DAO Genesis Authorizations JSON File +#### 0.4. Update the DAO Genesis Authorizations JSON File Add a grant (array element) to `tools/scripts/authz/dao_genesis_authorizations.json` with the `authorization.msg` typeURL for this module's `MsgUpdateType`: ```json - { - "granter": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", - "grantee": "pokt1eeeksh2tvkh7wzmfrljnhw4wrhs55lcuvmekkw", - "authorization": { - "@type": "\/cosmos.authz.v1beta1.GenericAuthorization", - "msg": "\/poktroll..MsgUpdateParam" - }, - "expiration": "2500-01-01T00:00:00Z" - }, ++ { ++ "granter": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", ++ "grantee": "pokt1eeeksh2tvkh7wzmfrljnhw4wrhs55lcuvmekkw", ++ "authorization": { ++ "@type": "\/cosmos.authz.v1beta1.GenericAuthorization", ++ "msg": "\/poktroll.examplemod.MsgUpdateParam" // Replace examplemod with the module name ++ }, ++ "expiration": "2500-01-01T00:00:00Z" ++ }, ``` ### 1. Define the Parameter in the Protocol Buffers File @@ -125,12 +137,12 @@ Add a grant (array element) to `tools/scripts/authz/dao_genesis_authorizations.j Open the appropriate `.proto` file for your module (e.g., `params.proto`) and define the new parameter. ```protobuf -message Params { - // Other existing parameters... - - // Description of the new parameter. - uint64 new_parameter_name = 3 [(gogoproto.jsontag) = "new_parameter_name"]; -} + message Params { + // Other existing parameters... + + // Description of the new parameter. ++ uint64 new_parameter = 3 [(gogoproto.jsontag) = "new_parameter"]; + } ``` ### 2 Update the Parameter Integration Tests @@ -138,44 +150,43 @@ message Params { Integration tests which cover parameter updates utilize the `ModuleParamConfig`s defined in [`testutil/integration/params/param_configs.go`](https://github.com/pokt-network/poktroll/blob/main/testutil/integration/suites/param_configs.go) to dynamically (i.e. using reflection) construct and send parameter update messages in a test environment. When adding parameters to a module, it is necessary to update that module's `ModuleParamConfig` to include the new parameter, othwerwise it will not be covered by the integration test suite. -### 2.1 If the Module Didn't Previously Support a `MsgUpdateParam` Message +#### 2.0 If the Module Didn't Previously Support a `MsgUpdateParam` Message - Add `MsgUpdateParam` & `MsgUpdateParamResponse` to the module's `ModuleParamConfig#ParamsMsg`: +Add `MsgUpdateParam` & `MsgUpdateParamResponse` to the module's `ModuleParamConfig#ParamsMsg`: -```diff -SomeModuleParamConfig = ModuleParamConfig{ - ParamsMsgs: ModuleParamsMessages{ - MsgUpdateParams: gatewaytypes.MsgUpdateParams{}, - MsgUpdateParamsResponse: gatewaytypes.MsgUpdateParamsResponse{}, -+ MsgUpdateParam: gatewaytypes.MsgUpdateParam{}, -+ MsgUpdateParamResponse: gatewaytypes.MsgUpdateParamResponse{}, - QueryParamsRequest: gatewaytypes.QueryParamsRequest{}, - QueryParamsResponse: gatewaytypes.QueryParamsResponse{}, - }, - ... -} +```go + SomeModuleParamConfig = ModuleParamConfig{ + ParamsMsgs: ModuleParamsMessages{ + MsgUpdateParams: gatewaytypes.MsgUpdateParams{}, + MsgUpdateParamsResponse: gatewaytypes.MsgUpdateParamsResponse{}, ++ MsgUpdateParam: gatewaytypes.MsgUpdateParam{}, ++ MsgUpdateParamResponse: gatewaytypes.MsgUpdateParamResponse{}, + QueryParamsRequest: gatewaytypes.QueryParamsRequest{}, + QueryParamsResponse: gatewaytypes.QueryParamsResponse{}, + }, + // ... + } ``` -### 2.2 Add a valid param +#### 2.1 Add a valid param -Update `ModuleParamConfig#ValidParams` to include a valid and non-default value for the new parameter. +Update `ModuleParamConfig#ValidParams` to include a valid and non-default value for the new parameter: -```diff -SomeModuleParamConfig = ModuleParamConfig{ - ... - ValidParams: gatewaytypes.Params{ -+ MinStake: &ValidActorMinStake, - }, - ... -} +```go + ExamplemodModuleParamConfig = ModuleParamConfig{ + // ... + ValidParams: gatewaytypes.Params{ ++ NewParameter: 420, + }, + // ... + } ``` -### 2.3 Check for `as_` on `MsgUpdateParam` +#### 2.2 Check for `as_` on `MsgUpdateParam` -Ensure an `as_` field exists on `MsgUpdateParam` corresponding to the type of the new parameter. -Below is an example of adding an `int64` type parameter to a new `MsgUpdateParam` message: +Ensure an `as_` field exists on `MsgUpdateParam` corresponding to the type of the new parameter: -```diff +```proto message MsgUpdateParam { ... oneof as_type { @@ -187,181 +198,187 @@ Below is an example of adding an `int64` type parameter to a new `MsgUpdateParam ### 3. Update the Default Parameter Values -In the corresponding Go file (e.g., `x//types/params.go`), define the default value, key, and parameter name for the -new parameter and include the default in the `NewParams` and `DefaultParams` functions. +#### 3.1 Go Source Defaults + +In the corresponding Go file (e.g., `x/examplemod/types/params.go`), define the default +value, key, and parameter name for the new parameter and include the default in the +`NewParams` and `DefaultParams` functions: ```go -var ( - // Other existing parameters... - - KeyNewParameterName = []byte("NewParameterName") - ParamNewParameterName = "new_parameter_name" - DefaultNewParameterName uint64 = 100 // Example default value -) - -func NewParams( - // Other existing parameters... - newParameterName uint64, -) Params { - return Params{ + var ( + // Other existing parameter keys, names, and defaults... + ++ KeyNewParameter = []byte("NewParameter") ++ ParamNewParameter = "new_parameter" ++ DefaultNewParameter int64 = 42 + ) + + func NewParams( // Other existing parameters... - NewParameterName: newParameterName, ++ newParameter int64, + ) Params { + return Params{ + // Other existing parameters... ++ NewParameter: newParameter, + } + } + + func DefaultParams() Params { + return NewParams( + // Other existing default parameters... ++ DefaultNewParameter, + ) } -} - -func DefaultParams() Params { - return NewParams( - // Other existing default parameters... - DefaultNewParameterName, - ) -} ``` -### 4. Add Parameter Default to Genesis Configuration +### 3.2 Genesis Configuration Parameter Defaults -Add the new parameter to the genesis configuration file (e.g., `config.yml`). +Add the new parameter to the genesis configuration file (e.g., `config.yml`): ```yaml -genesis: - proof: - params: - # Other existing parameters... - - new_parameter_name: 100 + genesis: + examplemod: + params: + # Other existing parameters... + ++ new_parameter: 42 ``` -### 5. Modify the Makefile +### 4. Update the Makefile and Supporting JSON Files + +#### 4.1 Update the Makefile Add a new target in the `Makefile` to update the new parameter. +Below is an example of adding the make target corresponding to the `shared` module's `num_blocks_per_session` param: ```makefile -.PHONY: params_update__ -params_update__: ## Update the module param - poktrolld tx authz exec ./tools/scripts/params/_.json $(PARAM_FLAGS) +.PHONY: params_update_examplemod_new_parameter +params_update_examplemod_new_parameter: ## Update the examplemod module new_parameter param + poktrolld tx authz exec ./tools/scripts/params/examplemod_new_parameter.json $(PARAM_FLAGS) ``` -### 6. Create a new JSON File for the Individual Parameter Update +:::warning +Reminder to substitute `examplemod` and `new_parameter` with your module and param names! +::: -Create a new JSON file (e.g., `proof_new_parameter_name.json`) in the tools/scripts/params -directory to specify how to update the new parameter. +#### 4.2 Create a new JSON File for the Individual Parameter Update + +Create a new JSON file (e.g., `proof_new_parameter_name.json`) in the tools/scripts/params directory to specify how to update the new parameter: ```json { "body": { "messages": [ { - "@type": "/poktroll.proof.MsgUpdateParam", + "@type": "/poktroll.examplemod.MsgUpdateParam", // Replace module name "authority": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", - "name": "", - "as_int64": "" + "name": "new_parameter", // Replace new parameter name + "as_int64": "42" // Replace default value } ] } } ``` -### 7. Update the JSON File for Updating All Parameters for the Module +#### 4.3 Update the JSON File for Updating All Parameters for the Module Add a line to the existing module's `MsgUpdateParam` JSON file (e.g., `proof_all.json`) with the default value for the new parameter. ```json -{ - "body": { - "messages": [ - { - "@type": "/poktroll.proof.MsgUpdateParams", - "authority": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", - "params": { - "min_relay_difficulty_bits": "0", - "proof_request_probability": "0.25", - "proof_requirement_threshold": "20", - "": "" // Add this line + { + "body": { + "messages": [ + { + "@type": "/poktroll.examplemod.MsgUpdateParams", // Replace module name + "authority": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", + "params": { + // Other existing parameters... ++ "new_parameter": "42" // Replace name and default value + } } - } - ] + ] + } } -} ``` -### 8. Parameter Validation +### 5. Parameter Validation -#### 8.1 New Parameter Validation +#### 5.1 New Parameter Validation -Implement a validation function for the new parameter in the corresponding `params.go` -file you've been working on. +Implement a validation function for the new parameter in `x/examplemod/types/params.go`: ```go -func ValidateNewParameterName(v interface{}) error { - _, ok := v.(uint64) - if !ok { - return fmt.Errorf("invalid parameter type: %T", v) - } - return nil -} ++ func ValidateNewParameter(v interface{}) error { ++ _, ok := v.(int64) ++ if !ok { ++ return fmt.Errorf("invalid parameter type: %T", v) ++ } ++ return nil ++ } ``` -#### 8.2 Parameter Validation in Workflow +#### 5.2 Parameter Validation in Workflow -Integrate the usage of the new `ValidateNewParameterName` function in the corresponding -`Params#ValidateBasic()` function where this is used. +Integrate the usage of the new `ValidateNewParameter` function in the corresponding +`Params#ValidateBasic()` function where this is used: ```go -func (params *Params) ValidateBasic() error { - // ... - if err := ValidateNewParameterName(params.NewParameterName); err != nil { - return err + func (params *Params) ValidateBasic() error { + // ... ++ if err := ValidateNewParameter(params.NewParameter); err != nil { ++ return err ++ } + // ... } - // ... -} ``` -### 9. Add the Parameter to `ParamSetPairs()` +### 6. Add the Parameter to `ParamSetPairs()` -Include the new parameter in the `ParamSetPairs` function. +Include the new parameter in the `ParamSetPairs` function: ```go -func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { - return paramtypes.ParamSetPairs{ - // Other existing parameters... - - paramtypes.NewParamSetPair( - KeyNewParameterName, - &p.NewParameterName, - ValidateNewParameterName, - ), + func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + // Other existing parameters... + ++ paramtypes.NewParamSetPair( ++ KeyNewParameter, ++ &p.NewParameter, ++ ValidateNewParameter, ++ ), + } } -} ``` -### 10. Update Unit Tests +### 7. Update Unit Tests Add tests which exercise validation of the new parameter in your test files -(e.g., `/types/params_test.go` and `msg_server_update_param_test.go`). +(e.g., `x/examplemod/types/params_test.go` and `x/examplemod/keeper/msg_server_update_param_test.go`). -#### 10.1 Parameter Validation Tests +#### 7.1 Parameter Validation Tests ```go -func TestParams_ValidateNewParameterName(t *testing.T) { +func TestParams_ValidateNewParameter(t *testing.T) { tests := []struct { desc string - newParameterName interface{} + newParameter interface{} expectedErr error }{ { desc: "invalid type", - newParameterName: int64(-1), + newParameter: uint64(1), expectedErr: fmt.Errorf("invalid parameter type: int64"), }, { - desc: "valid newParameterName", - newParameterName: uint64(100), + desc: "valid newParameter", + newParameterName: int64(42), }, } for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { - err := ValidateNewParameterName(tt.newParameterName) + err := ValidateNewParameter(tt.newParameter) if tt.expectedErr != nil { require.Error(t, err) require.Contains(t, err.Error(), tt.expectedErr.Error()) @@ -373,13 +390,11 @@ func TestParams_ValidateNewParameterName(t *testing.T) { } ``` -#### 10.2 Parameter Update Tests - -The example presented below corresponds to `/keeper/msg_server_update_param_test.go`. +#### 7.2 Parameter Update Tests ```go -func TestMsgUpdateParam_UpdateNewParameterNameOnly(t *testing.T) { - var expectedNewParameterName uint64 = 100 +func TestMsgUpdateParam_UpdateNewParameterOnly(t *testing.T) { + var expectedNewParameter uint64 = 420 // Set the parameters to their default values k, msgSrv, ctx := setupMsgServer(t) @@ -390,23 +405,82 @@ func TestMsgUpdateParam_UpdateNewParameterNameOnly(t *testing.T) { require.NotEqual(t, expectedNewParameterName, defaultParams.NewParameterName) // Update the new parameter - updateParamMsg := &prooftypes.MsgUpdateParam{ + updateParamMsg := &examplemodtypes.MsgUpdateParam{ Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), - Name: prooftypes.ParamNewParameterName, - AsType: &prooftypes.MsgUpdateParam_AsInt64{AsInt64: int64(expectedNewParameterName)}, + Name: examplemodtypes.ParamNewParameter, + AsType: &examplemodtypes.MsgUpdateParam_AsInt64{AsInt64: int64(expectedNewParameter)}, } res, err := msgSrv.UpdateParam(ctx, updateParamMsg) require.NoError(t, err) - require.Equal(t, expectedNewParameterName, res.Params.NewParameterName) + require.Equal(t, expectedNewParameter, res.Params.NewParameter) - // READ ME: THIS TEST SHOULD ALSO ASSERT THAT ALL OTHER PARAMS OF THE SAME MODULE REMAIN UNCHANGED + // IMPORTANT!: THIS TEST SHOULD ALSO ASSERT THAT ALL OTHER PARAMS OF THE SAME MODULE REMAIN UNCHANGED } ``` -### 11. Implement individual parameter updates +### 8. Add Parameter Case to Switch Statements + +#### 8.0 If the Module Doesn't Already Support a `MsgUpdateParam` Message -#### 11.1 Add `ParamNameNewParameterName` to `MsgUpdateParam#ValidateBasic()` in `x/types/message_update_param.go` +Prepare `x/examplemod/types/message_update_param.go` to handle parameter updates by type: + +```go +- func NewMsgUpdateParam(authority string, name string, asType string) *MsgUpdateParam { ++ func NewMsgUpdateParam(authority string, name string, value any) *MsgUpdateParam { ++ var valueAsType isMsgUpdateParam_AsType ++ ++ switch v := value.(type) { ++ case int64: ++ valueAsType = &MsgUpdateParam_AsCoin{AsInt64: v} ++ default: ++ panic(fmt.Sprintf("unexpected param value type: %T", value)) ++ } ++ + return &MsgUpdateParam{ + Authority: authority, + Name: name, +- AsType: asType, ++ AsType: valueAsType, + } + } + + func (msg *MsgUpdateParam) ValidateBasic() error { + _, err := cosmostypes.AccAddressFromBech32(msg.Authority) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) + } ++ ++ // Parameter value cannot be nil. ++ if msg.AsType == nil { ++ return ErrGatewayParamInvalid.Wrap("missing param AsType") ++ } ++ ++ // Parameter name must be supported by this module. ++ switch msg.Name { ++ case ParamNewParameter: ++ return msg.paramTypeIsInt64() ++ default: ++ return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) ++ } ++ } ++ ++ func (msg *MsgUpdateParam) paramTypeIsInt64() error { ++ _, ok := msg.AsType.(*MsgUpdateParam_AsInt64) ++ if !ok { ++ return ErrGatewayParamInvalid.Wrapf( ++ "invalid type for param %q expected %T type: %T", ++ msg.Name, &MsgUpdateParam_AsInt64{}, msg.AsType, ++ ) ++ } ++ + return nil + } +``` + +#### 8.1 `MsgUpdateParam#ValidateBasic()` + +Add `ParamNameNewParameterName` to `MsgUpdateParam#ValidateBasic()` in `x/types/message_update_param.go`: ```go // Parameter name must be supported by this module. @@ -416,7 +490,9 @@ func TestMsgUpdateParam_UpdateNewParameterNameOnly(t *testing.T) { return msg.paramTypeIsInt64() ``` -#### 11.2 Add `ParamNameNewParameterName` to `msgServer#UpdateParam()` in `x/keeper/msg_server_update_param.go` +#### 8.2 `msgServer#UpdateParam()` + +Add `ParamNameNewParameterName` to `msgServer#UpdateParam()` in `x/keeper/msg_server_update_param.go`: ```go case types.ParamNewParameterName: From 2c16bd10695218f9b9ad50c706e6e3d44c0d4192 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 26 Sep 2024 12:45:17 +0200 Subject: [PATCH 03/21] docs: update ToC --- .../develop/developer_guide/adding_params.md | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index cf20d2e49..ecd0b802f 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -6,27 +6,34 @@ title: Adding On-Chain Module Parameters # Adding On-Chain Module Parameters - [Step-by-Step Instructions](#step-by-step-instructions) - - [1. Define the Parameter in the Protocol Buffers File](#1-define-the-parameter-in-the-protocol-buffers-file) - - [2 Update the Parameter E2E Tests](#2-update-the-parameter-e2e-tests) - - [2.1 Scenario Example](#21-scenario-example) - - [2.2 Scenario Outline Example](#22-scenario-outline-example) - - [2.3 Step Definition Helpers Example](#23-step-definition-helpers-example) - - [2.4 Update switch statement to support new param](#24-update-switch-statement-to-support-new-param) - - [3. Update the Default Parameter Values](#3-update-the-default-parameter-values) - - [4. Add Parameter Default to Genesis Configuration](#4-add-parameter-default-to-genesis-configuration) - - [5. Modify the Makefile](#5-modify-the-makefile) - - [6. Create a new JSON File for the Individual Parameter Update](#6-create-a-new-json-file-for-the-individual-parameter-update) - - [7. Update the JSON File for Updating All Parameters for the Module](#7-update-the-json-file-for-updating-all-parameters-for-the-module) - - [8. Parameter Validation](#8-parameter-validation) - - [8.1 New Parameter Validation](#81-new-parameter-validation) - - [8.2 Parameter Validation in Workflow](#82-parameter-validation-in-workflow) - - [9. Add the Parameter to `ParamSetPairs()`](#9-add-the-parameter-to-paramsetpairs) - - [10. Update Unit Tests](#10-update-unit-tests) - - [10.1 Parameter Validation Tests](#101-parameter-validation-tests) - - [10.2 Parameter Update Tests](#102-parameter-update-tests) - - [11. Implement individual parameter updates](#11-implement-individual-parameter-updates) - - [11.1 Add `ParamNameNewParameterName` to `MsgUpdateParam#ValidateBasic()` in `x/types/message_update_param.go`](#111-add-paramnamenewparametername-to-msgupdateparamvalidatebasic-in-xtypesmessage_update_paramgo) - - [11.2 Add `ParamNameNewParameterName` to `msgServer#UpdateParam()` in `x/keeper/msg_server_update_param.go`](#112-add-paramnamenewparametername-to-msgserverupdateparam-in-xkeepermsg_server_update_paramgo) + - [0. If the Module Doesn't Already Support a `MsgUpdateParam` Message](#0-if-the-module-doesnt-already-support-a-msgupdateparam-message) + - [0.1 Scaffold the `MsgUpdateParam` Message](#01-scaffold-the-msgupdateparam-message) + - [0.2 Update the `MsgUpdateParam` Message Fields](#02-update-the-msgupdateparam-message-fields) + - [0.3 Comment Out AutoCLI](#03-comment-out-autocli) + - [0.4. Update the DAO Genesis Authorizations JSON File](#04-update-the-dao-genesis-authorizations-json-file) + - [1. Define the Parameter in the Protocol Buffers File](#1-define-the-parameter-in-the-protocol-buffers-file) + - [2 Update the Parameter Integration Tests](#2-update-the-parameter-integration-tests) + - [2.0 If the Module Didn't Previously Support a `MsgUpdateParam` Message](#20-if-the-module-didnt-previously-support-a-msgupdateparam-message) + - [2.1 Add a valid param](#21-add-a-valid-param) + - [2.2 Check for `as_` on `MsgUpdateParam`](#22-check-for-as_type-on-msgupdateparam) + - [3. Update the Default Parameter Values](#3-update-the-default-parameter-values) + - [3.1 Go Source Defaults](#31-go-source-defaults) + - [3.2 Genesis Configuration Parameter Defaults](#32-genesis-configuration-parameter-defaults) + - [4. Update the Makefile and Supporting JSON Files](#4-update-the-makefile-and-supporting-json-files) + - [4.1 Update the Makefile](#41-update-the-makefile) + - [4.2 Create a new JSON File for the Individual Parameter Update](#42-create-a-new-json-file-for-the-individual-parameter-update) + - [4.3 Update the JSON File for Updating All Parameters for the Module](#43-update-the-json-file-for-updating-all-parameters-for-the-module) + - [5. Parameter Validation](#5-parameter-validation) + - [5.1 New Parameter Validation](#51-new-parameter-validation) + - [5.2 Parameter Validation in Workflow](#52-parameter-validation-in-workflow) + - [6. Add the Parameter to `ParamSetPairs()`](#6-add-the-parameter-to-paramsetpairs) + - [7. Update Unit Tests](#7-update-unit-tests) + - [7.1 Parameter Validation Tests](#71-parameter-validation-tests) + - [7.2 Parameter Update Tests](#72-parameter-update-tests) + - [8. Add Parameter Case to Switch Statements](#8-add-parameter-case-to-switch-statements) + - [8.0 If the Module Doesn't Already Support a `MsgUpdateParam` Message](#80-if-the-module-doesnt-already-support-a-msgupdateparam-message) + - [8.1 `MsgUpdateParam#ValidateBasic()`](#81-msgupdateparamvalidatebasic) + - [8.2 `msgServer#UpdateParam()`](#82-msgserverupdateparam) Adding a new on-chain module parameter involves multiple steps to ensure that the parameter is properly integrated into the system. This guide will walk you through From 82c8598bbb6c25be409f079aecd24c648b49aa23 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 26 Sep 2024 09:03:22 +0200 Subject: [PATCH 04/21] docs: revert unintended params docs changes --- docusaurus/docs/protocol/governance/params.md | 8 -------- tools/scripts/docusaurus/params_template.md | 8 -------- 2 files changed, 16 deletions(-) diff --git a/docusaurus/docs/protocol/governance/params.md b/docusaurus/docs/protocol/governance/params.md index 37400c7e4..69f188940 100644 --- a/docusaurus/docs/protocol/governance/params.md +++ b/docusaurus/docs/protocol/governance/params.md @@ -13,14 +13,6 @@ DO NOT EDIT: this file was generated by make docs_update_gov_params_page - [Adding a new parameter](#adding-a-new-parameter) - [Parameters](#parameters) -## Access Control - -// TODO_DOCUMENT(@bryanchriswhite) tl;dr, authz. - -## Updating governance parameter values - -// TODO_DOCUMENT(@bryanchriswhite) - ## Updating this page ``` diff --git a/tools/scripts/docusaurus/params_template.md b/tools/scripts/docusaurus/params_template.md index 11a0294a8..2e2c43f7f 100644 --- a/tools/scripts/docusaurus/params_template.md +++ b/tools/scripts/docusaurus/params_template.md @@ -13,14 +13,6 @@ DO NOT EDIT: this file was generated by make docs_update_gov_params_page - [Adding a new parameter](#adding-a-new-parameter) - [Parameters](#parameters) -## Access Control - -// TODO_DOCUMENT(@bryanchriswhite) tl;dr, authz. - -## Updating governance parameter values - -// TODO_DOCUMENT(@bryanchriswhite) - ## Updating this page %s From a22ef77d30c37df4ba255abe58a54e61b6d1fd33 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 26 Sep 2024 14:35:29 +0200 Subject: [PATCH 05/21] docs: update section 7 --- .../develop/developer_guide/adding_params.md | 138 ++++++++++-------- 1 file changed, 81 insertions(+), 57 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index ecd0b802f..b8c1bb18b 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -328,10 +328,10 @@ Implement a validation function for the new parameter in `x/examplemod/types/par #### 5.2 Parameter Validation in Workflow Integrate the usage of the new `ValidateNewParameter` function in the corresponding -`Params#ValidateBasic()` function where this is used: +`Params#Validate()` function where this is used: ```go - func (params *Params) ValidateBasic() error { + func (params *Params) Validate() error { // ... + if err := ValidateNewParameter(params.NewParameter); err != nil { + return err @@ -342,12 +342,12 @@ Integrate the usage of the new `ValidateNewParameter` function in the correspond ### 6. Add the Parameter to `ParamSetPairs()` -Include the new parameter in the `ParamSetPairs` function: +Include the new parameter in the `ParamSetPairs` function return: ```go func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { return paramtypes.ParamSetPairs{ - // Other existing parameters... + // Other existing param set pairs... + paramtypes.NewParamSetPair( + KeyNewParameter, @@ -360,70 +360,94 @@ Include the new parameter in the `ParamSetPairs` function: ### 7. Update Unit Tests -Add tests which exercise validation of the new parameter in your test files -(e.g., `x/examplemod/types/params_test.go` and `x/examplemod/keeper/msg_server_update_param_test.go`). - #### 7.1 Parameter Validation Tests -```go -func TestParams_ValidateNewParameter(t *testing.T) { - tests := []struct { - desc string - newParameter interface{} - expectedErr error - }{ - { - desc: "invalid type", - newParameter: uint64(1), - expectedErr: fmt.Errorf("invalid parameter type: int64"), - }, - { - desc: "valid newParameter", - newParameterName: int64(42), - }, - } +Add unit tests which exercise validation of the new parameter(s) in `x/examplemod/keeper/params_test.go`: +Ensure there is a test function for each parameter which covers all cases of invalid input - for _, tt := range tests { - t.Run(tt.desc, func(t *testing.T) { - err := ValidateNewParameter(tt.newParameter) - if tt.expectedErr != nil { - require.Error(t, err) - require.Contains(t, err.Error(), tt.expectedErr.Error()) - } else { - require.NoError(t, err) - } - }) +```go + func TestGetParams(t *testing.T) { + // ... } -} + ++ func TestParams_ValidateNewParameter(t *testing.T) { ++ tests := []struct { ++ desc string ++ newParameter interface{} ++ expectedErr error ++ }{ ++ { ++ desc: "invalid type", ++ newParameter: "420", ++ expectedErr: fmt.Errorf("invalid parameter type: string"), ++ }, ++ { ++ desc: "valid newParameterName", ++ newParameter: int64(420), ++ }, ++ } ++ ++ for _, tt := range tests { ++ t.Run(tt.desc, func(t *testing.T) { ++ err := ValidateNewParameter(tt.newParameter) ++ if tt.expectedErr != nil { ++ require.Error(t, err) ++ require.Contains(t, err.Error(), tt.expectedErr.Error()) ++ } else { ++ require.NoError(t, err) ++ } ++ }) ++ } ++ } ``` #### 7.2 Parameter Update Tests +Add test cases to `x/examplemod/keeper/msg_update_params_test.go` to ensure coverage over any invalid parameter configurations. +Add a case for the "minimal params" if some subset of the params are "required". +If one already exist, update it if applicable; e.g.: + ```go -func TestMsgUpdateParam_UpdateNewParameterOnly(t *testing.T) { - var expectedNewParameter uint64 = 420 - - // Set the parameters to their default values - k, msgSrv, ctx := setupMsgServer(t) - defaultParams := prooftypes.DefaultParams() - require.NoError(t, k.SetParams(ctx, defaultParams)) - - // Ensure the default values are different from the new values we want to set - require.NotEqual(t, expectedNewParameterName, defaultParams.NewParameterName) - - // Update the new parameter - updateParamMsg := &examplemodtypes.MsgUpdateParam{ - Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), - Name: examplemodtypes.ParamNewParameter, - AsType: &examplemodtypes.MsgUpdateParam_AsInt64{AsInt64: int64(expectedNewParameter)}, - } - res, err := msgSrv.UpdateParam(ctx, updateParamMsg) - require.NoError(t, err) ++ { ++ desc: "valid: send minimal params", // For parameters which MUST NEVER be their zero value or nil. ++ input: &examplemodtypes.MsgUpdateParams{ ++ Authority: k.GetAuthority(), ++ Params: examplemodtypes.Params{ ++ NewParameter: 42, ++ }, ++ }, ++ shouldError: false, ++ }, +``` - require.Equal(t, expectedNewParameter, res.Params.NewParameter) +Add unit tests which exercise individual parameter updates in `x/examplemod/keeper/msg_server_update_param_test.go`. +These tests assert that the value of a given parameter is: - // IMPORTANT!: THIS TEST SHOULD ALSO ASSERT THAT ALL OTHER PARAMS OF THE SAME MODULE REMAIN UNCHANGED -} +```go ++ func TestMsgUpdateParam_UpdateNewParameterOnly(t *testing.T) { ++ var expectedNewParameter uint64 = 420 ++ ++ // Set the parameters to their default values ++ k, msgSrv, ctx := setupMsgServer(t) ++ defaultParams := prooftypes.DefaultParams() ++ require.NoError(t, k.SetParams(ctx, defaultParams)) ++ ++ // Ensure the default values are different from the new values we want to set ++ require.NotEqual(t, expectedNewParameter, defaultParams.NewParameter) ++ ++ // Update the new parameter ++ updateParamMsg := &examplemodtypes.MsgUpdateParam{ ++ Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), ++ Name: examplemodtypes.ParamNewParameter, ++ AsType: &examplemodtypes.MsgUpdateParam_AsInt64{AsInt64: int64(expectedNewParameter)}, ++ } ++ res, err := msgSrv.UpdateParam(ctx, updateParamMsg) ++ require.NoError(t, err) ++ ++ require.Equal(t, expectedNewParameter, res.Params.NewParameter) ++ ++ // IMPORTANT!: THIS TEST SHOULD ALSO ASSERT THAT ALL OTHER PARAMS OF THE SAME MODULE REMAIN UNCHANGED ++ } ``` ### 8. Add Parameter Case to Switch Statements From f6e5bc558b937b1a94b91bb834b6e7e5213d845d Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 26 Sep 2024 14:56:40 +0200 Subject: [PATCH 06/21] docs: update section 8 --- .../develop/developer_guide/adding_params.md | 178 ++++++++++++------ 1 file changed, 122 insertions(+), 56 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index b8c1bb18b..fe81b1b55 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -454,88 +454,154 @@ These tests assert that the value of a given parameter is: #### 8.0 If the Module Doesn't Already Support a `MsgUpdateParam` Message -Prepare `x/examplemod/types/message_update_param.go` to handle parameter updates by type: +Prepare `x/examplemod/types/message_update_param.go` to handle parameter validations by type: ```go - func NewMsgUpdateParam(authority string, name string, asType string) *MsgUpdateParam { + func NewMsgUpdateParam(authority string, name string, value any) *MsgUpdateParam { + var valueAsType isMsgUpdateParam_AsType -+ ++ + switch v := value.(type) { -+ case int64: -+ valueAsType = &MsgUpdateParam_AsCoin{AsInt64: v} + default: + panic(fmt.Sprintf("unexpected param value type: %T", value)) + } -+ - return &MsgUpdateParam{ - Authority: authority, - Name: name, ++ + return &MsgUpdateParam{ + Authority: authority, + Name: name, - AsType: asType, + AsType: valueAsType, } } - + func (msg *MsgUpdateParam) ValidateBasic() error { - _, err := cosmostypes.AccAddressFromBech32(msg.Authority) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) - } -+ -+ // Parameter value cannot be nil. -+ if msg.AsType == nil { -+ return ErrGatewayParamInvalid.Wrap("missing param AsType") -+ } -+ -+ // Parameter name must be supported by this module. -+ switch msg.Name { -+ case ParamNewParameter: -+ return msg.paramTypeIsInt64() -+ default: -+ return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) -+ } -+ } -+ -+ func (msg *MsgUpdateParam) paramTypeIsInt64() error { -+ _, ok := msg.AsType.(*MsgUpdateParam_AsInt64) -+ if !ok { -+ return ErrGatewayParamInvalid.Wrapf( -+ "invalid type for param %q expected %T type: %T", -+ msg.Name, &MsgUpdateParam_AsInt64{}, msg.AsType, -+ ) -+ } -+ - return nil + _, err := cosmostypes.AccAddressFromBech32(msg.Authority) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) + } ++ ++ // Parameter value cannot be nil. ++ if msg.AsType == nil { ++ return ErrGatewayParamInvalid.Wrap("missing param AsType") ++ } ++ ++ // Parameter name must be supported by this module. ++ switch msg.Name { ++ default: ++ return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) ++ } + + return nil } ``` -#### 8.1 `MsgUpdateParam#ValidateBasic()` - -Add `ParamNameNewParameterName` to `MsgUpdateParam#ValidateBasic()` in `x/types/message_update_param.go`: +Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter updates by type: ```go - // Parameter name must be supported by this module. - switch msg.Name { - case ParamNumBlocksPerSession, - ParamNewParameterName: - return msg.paramTypeIsInt64() ++ // UpdateParam updates a single parameter in the proof module and returns ++ // all active parameters. + func (k msgServer) UpdateParam( + ctx context.Context, + msg *types.MsgUpdateParam, + ) (*types.MsgUpdateParamResponse, error) { +- ctx := sdk.UnwrapSDKContext(goCtx) +- +- // TODO: Handling the message +- _ = ctx +- ++ if err := msg.ValidateBasic(); err != nil { ++ return nil, err ++ } ++ ++ if k.GetAuthority() != msg.Authority { ++ return nil, types.ErrProofInvalidSigner.Wrapf("invalid authority; expected %s, got %s", k.GetAuthority(), msg.Authority) ++ } ++ ++ params := k.GetParams(ctx) ++ ++ switch msg.Name { ++ default: ++ return nil, types.ErrProofParamInvalid.Wrapf("unsupported param %q", msg.Name) ++ } ++ ++ if err := k.SetParams(ctx, params); err != nil { ++ return nil, err ++ } ++ ++ updatedParams := k.GetParams(ctx) ++ return &types.MsgUpdateParamResponse{ ++ Params: &updatedParams, ++ }, nil + } ``` -#### 8.2 `msgServer#UpdateParam()` +#### 8.1 `MsgUpdateParam#ValidateBasic()` -Add `ParamNameNewParameterName` to `msgServer#UpdateParam()` in `x/keeper/msg_server_update_param.go`: +Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switch in `MsgUpdateParam#ValidateBasic()` in `x/types/message_update_param.go`: ```go -case types.ParamNewParameterName: - value, ok := msg.AsType.(*types.MsgUpdateParam_AsInt64) - if !ok { - return nil, types.ErrProofParamInvalid.Wrapf("unsupported value type for %s param: %T", msg.Name, msg.AsType) + func NewMsgUpdateParam(authority string, name string, value any) *MsgUpdateParam { + // ... + switch v := value.(type) { ++ case int64: ++ valueAsType = &MsgUpdateParam_AsCoin{AsInt64: v} + default: + panic(fmt.Sprintf("unexpected param value type: %T", value)) + } + // ... } - newParameter := uint64(value.AsInt64) - if err := types.ValidateNewParameter(newParameter); err != nil { - return nil, err + func (msg *MsgUpdateParam) ValidateBasic() error { + // ... + switch msg.Name { ++ case ParamNewParameter: ++ return msg.paramTypeIsInt64() + default: + return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) + } } ++ ++ func (msg *MsgUpdateParam) paramTypeIsInt64() error { ++ _, ok := msg.AsType.(*MsgUpdateParam_AsInt64) ++ if !ok { ++ return ErrGatewayParamInvalid.Wrapf( ++ "invalid type for param %q expected %T type: %T", ++ msg.Name, &MsgUpdateParam_AsInt64{}, msg.AsType, ++ ) ++ } ++ ++ return nil ++ } +``` + +#### 8.2 `msgServer#UpdateParam()` + +Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switch statement in `msgServer#UpdateParam()` in `x/keeper/msg_server_update_param.go`: - params.NewParameter = newParameter +```go + // UpdateParam updates a single parameter in the proof module and returns + // all active parameters. + func (k msgServer) UpdateParam( + ctx context.Context, + msg *types.MsgUpdateParam, + ) (*types.MsgUpdateParamResponse, error) { + // ... + switch msg.Name { ++ case types.ParamRelayDifficultyTargetHash: ++ value, ok := msg.AsType.(*types.MsgUpdateParam_AsBytes) ++ if !ok { ++ return nil, types.ErrProofParamInvalid.Wrapf("unsupported value type for %s param: %T", msg.Name, msg.AsType) ++ } ++ relayDifficultyTargetHash := value.AsBytes ++ ++ if err := types.ValidateRelayDifficultyTargetHash(relayDifficultyTargetHash); err != nil { ++ return nil, err ++ } ++ ++ params.RelayDifficultyTargetHash = relayDifficultyTargetHash + default: + return nil, types.ErrProofParamInvalid.Wrapf("unsupported param %q", msg.Name) + } + // ... + } ``` From df3e003b08cfba02fcfa3f40a97ea22e0239f032 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 26 Sep 2024 15:01:45 +0200 Subject: [PATCH 07/21] fixup! docs: update section 8 --- docusaurus/docs/develop/developer_guide/adding_params.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index fe81b1b55..6637b1c07 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -537,7 +537,7 @@ Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter upd #### 8.1 `MsgUpdateParam#ValidateBasic()` -Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switch in `MsgUpdateParam#ValidateBasic()` in `x/types/message_update_param.go`: +Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switch in `MsgUpdateParam#ValidateBasic()` in `x/examplemod/types/message_update_param.go`: ```go func NewMsgUpdateParam(authority string, name string, value any) *MsgUpdateParam { @@ -576,7 +576,7 @@ Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switc #### 8.2 `msgServer#UpdateParam()` -Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switch statement in `msgServer#UpdateParam()` in `x/keeper/msg_server_update_param.go`: +Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switch statement in `msgServer#UpdateParam()` in `x/examplemod/keeper/msg_server_update_param.go`: ```go // UpdateParam updates a single parameter in the proof module and returns From 4eeebb5f821abaf1d9590dedf59f431946d0c0ac Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 27 Sep 2024 12:16:32 +0200 Subject: [PATCH 08/21] docs: improvements --- .../develop/developer_guide/adding_params.md | 239 ++++++++++-------- 1 file changed, 132 insertions(+), 107 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index 6637b1c07..4f1621076 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -64,6 +64,10 @@ When following these steps, be sure to substitute these example values with your In order to support **individual parameter updates**, the module MUST have a `MsgUpdateParam` message. If the module doesn't already support this message, it will need to be added. +:::tip +At any point, you can always run `go test ./x/examplemod/...` to check whether everything is working or locate outstanding necessary changes. +::: + #### 0.1 Scaffold the `MsgUpdateParam` Message Use `ignite` to scaffold a new `MsgUpdateParam` message for the module. @@ -73,6 +77,21 @@ Additional flags are used for convenience: ignite scaffold message update-param --module examplemod --signer authority name as_type --response params ``` +:::info +If you experience errors like these: +``` +✘ Error while running command /home/bwhite/go/bin/buf generate /tmp/proto-sdk2893110128/cosmos/upgrade/v1beta1/tx.proto ...: {..."message":"import \"gogoproto/gogo.proto\": file does not exist"} +: exit status 100 +``` +``` +✘ Error while running command go mod tidy: go: +... +go: github.com/pokt-network/poktroll/api/poktroll/examplemod imports + cosmossdk.io/api/poktroll/shared: module cosmossdk.io/api@latest found (v0.7.6), but does not contain package cosmossdk.io/api/poktroll/shared +``` +Then try running `make proto_clean_pulsar`. +::: + #### 0.2 Update the `MsgUpdateParam` Message Fields Update the `MsgUpdateParam` message fields in the module's `tx.proto` file to include the following comments and protobuf options: @@ -139,30 +158,96 @@ Add a grant (array element) to `tools/scripts/authz/dao_genesis_authorizations.j + }, ``` -### 1. Define the Parameter in the Protocol Buffers File +#### 0.5 Update the `NewMsgUpdateParam` Constructor and `MsgUpdateParam#ValidateBasic()` -Open the appropriate `.proto` file for your module (e.g., `params.proto`) and define the new parameter. +Prepare `x/examplemod/types/message_update_param.go` to handle message construction and parameter validations by type: -```protobuf - message Params { - // Other existing parameters... - - // Description of the new parameter. -+ uint64 new_parameter = 3 [(gogoproto.jsontag) = "new_parameter"]; +```go +- func NewMsgUpdateParam(authority string, name string, asType string) *MsgUpdateParam { ++ func NewMsgUpdateParam(authority string, name string, asType any) *MsgUpdateParam { ++ var asTypeIface isMsgUpdateParam_AsType ++ ++ switch t := asType.(type) { ++ default: ++ panic(fmt.Sprintf("unexpected param value type: %T", asType)) ++ } ++ + return &MsgUpdateParam{ + Authority: authority, + Name: name, +- AsType: asType, ++ AsType: asTypeIface, + } } + + func (msg *MsgUpdateParam) ValidateBasic() error { + _, err := cosmostypes.AccAddressFromBech32(msg.Authority) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) + } ++ ++ // Parameter value cannot be nil. ++ if msg.AsType == nil { ++ return ErrGatewayParamInvalid.Wrap("missing param AsType") ++ } ++ ++ // Parameter name must be supported by this module. ++ switch msg.Name { ++ default: ++ return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) ++ } + +return nil +} ``` +#### 0.6 Update the Module's `msgServer#UpdateParam()` Handler -### 2 Update the Parameter Integration Tests +Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter updates by type: -Integration tests which cover parameter updates utilize the `ModuleParamConfig`s defined in [`testutil/integration/params/param_configs.go`](https://github.com/pokt-network/poktroll/blob/main/testutil/integration/suites/param_configs.go) to dynamically (i.e. using reflection) construct and send parameter update messages in a test environment. -When adding parameters to a module, it is necessary to update that module's `ModuleParamConfig` to include the new parameter, othwerwise it will not be covered by the integration test suite. +```go ++ // UpdateParam updates a single parameter in the proof module and returns ++ // all active parameters. + func (k msgServer) UpdateParam( + ctx context.Context, + msg *types.MsgUpdateParam, + ) (*types.MsgUpdateParamResponse, error) { +- ctx := sdk.UnwrapSDKContext(goCtx) +- +- // TODO: Handling the message +- _ = ctx +- ++ if err := msg.ValidateBasic(); err != nil { ++ return nil, err ++ } ++ ++ if k.GetAuthority() != msg.Authority { ++ return nil, types.ErrProofInvalidSigner.Wrapf("invalid authority; expected %s, got %s", k.GetAuthority(), msg.Authority) ++ } ++ ++ params := k.GetParams(ctx) ++ ++ switch msg.Name { ++ default: ++ return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) ++ } ++ ++ if err := k.SetParams(ctx, params); err != nil { ++ return nil, err ++ } ++ ++ updatedParams := k.GetParams(ctx) ++ return &types.MsgUpdateParamResponse{ ++ Params: &updatedParams, ++ }, nil + } +``` -#### 2.0 If the Module Didn't Previously Support a `MsgUpdateParam` Message +#### 0.7 Update Module's Params Test Suite `ModuleParamConfig` Add `MsgUpdateParam` & `MsgUpdateParamResponse` to the module's `ModuleParamConfig#ParamsMsg`: ```go - SomeModuleParamConfig = ModuleParamConfig{ + ExamplemodModuleParamConfig = ModuleParamConfig{ ParamsMsgs: ModuleParamsMessages{ MsgUpdateParams: gatewaytypes.MsgUpdateParams{}, MsgUpdateParamsResponse: gatewaytypes.MsgUpdateParamsResponse{}, @@ -175,6 +260,29 @@ Add `MsgUpdateParam` & `MsgUpdateParamResponse` to the module's `ModuleParamConf } ``` + +### 1. Define the Parameter in the Protocol Buffers File + +Open the appropriate `.proto` file for your module (e.g., `params.proto`) and define the new parameter. + +```protobuf + message Params { + // Other existing parameters... + ++ // Description of the new parameter. ++ uint64 new_parameter = 3 [(gogoproto.jsontag) = "new_parameter", (gogoproto.moretags) = "yaml:\"new_parameter\""]; + } +``` + +:::tip +Don't forget to run `make proto_regen` to update generated protobuf go code. +::: + +### 2 Update the Parameter Integration Tests + +Integration tests which cover parameter updates utilize the `ModuleParamConfig`s defined in [`testutil/integration/params/param_configs.go`](https://github.com/pokt-network/poktroll/blob/main/testutil/integration/suites/param_configs.go) to dynamically (i.e. using reflection) construct and send parameter update messages in a test environment. +When adding parameters to a module, it is necessary to update that module's `ModuleParamConfig` to include the new parameter, othwerwise it will not be covered by the integration test suite. + #### 2.1 Add a valid param Update `ModuleParamConfig#ValidParams` to include a valid and non-default value for the new parameter: @@ -452,101 +560,18 @@ These tests assert that the value of a given parameter is: ### 8. Add Parameter Case to Switch Statements -#### 8.0 If the Module Doesn't Already Support a `MsgUpdateParam` Message - -Prepare `x/examplemod/types/message_update_param.go` to handle parameter validations by type: - -```go -- func NewMsgUpdateParam(authority string, name string, asType string) *MsgUpdateParam { -+ func NewMsgUpdateParam(authority string, name string, value any) *MsgUpdateParam { -+ var valueAsType isMsgUpdateParam_AsType -+ -+ switch v := value.(type) { -+ default: -+ panic(fmt.Sprintf("unexpected param value type: %T", value)) -+ } -+ - return &MsgUpdateParam{ - Authority: authority, - Name: name, -- AsType: asType, -+ AsType: valueAsType, - } - } - - func (msg *MsgUpdateParam) ValidateBasic() error { - _, err := cosmostypes.AccAddressFromBech32(msg.Authority) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) - } -+ -+ // Parameter value cannot be nil. -+ if msg.AsType == nil { -+ return ErrGatewayParamInvalid.Wrap("missing param AsType") -+ } -+ -+ // Parameter name must be supported by this module. -+ switch msg.Name { -+ default: -+ return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) -+ } - - return nil - } -``` - -Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter updates by type: - -```go -+ // UpdateParam updates a single parameter in the proof module and returns -+ // all active parameters. - func (k msgServer) UpdateParam( - ctx context.Context, - msg *types.MsgUpdateParam, - ) (*types.MsgUpdateParamResponse, error) { -- ctx := sdk.UnwrapSDKContext(goCtx) -- -- // TODO: Handling the message -- _ = ctx -- -+ if err := msg.ValidateBasic(); err != nil { -+ return nil, err -+ } -+ -+ if k.GetAuthority() != msg.Authority { -+ return nil, types.ErrProofInvalidSigner.Wrapf("invalid authority; expected %s, got %s", k.GetAuthority(), msg.Authority) -+ } -+ -+ params := k.GetParams(ctx) -+ -+ switch msg.Name { -+ default: -+ return nil, types.ErrProofParamInvalid.Wrapf("unsupported param %q", msg.Name) -+ } -+ -+ if err := k.SetParams(ctx, params); err != nil { -+ return nil, err -+ } -+ -+ updatedParams := k.GetParams(ctx) -+ return &types.MsgUpdateParamResponse{ -+ Params: &updatedParams, -+ }, nil - } -``` - #### 8.1 `MsgUpdateParam#ValidateBasic()` Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switch in `MsgUpdateParam#ValidateBasic()` in `x/examplemod/types/message_update_param.go`: ```go - func NewMsgUpdateParam(authority string, name string, value any) *MsgUpdateParam { + func NewMsgUpdateParam(authority string, name string, asType any) *MsgUpdateParam { // ... - switch v := value.(type) { + switch t := asType.(type) { + case int64: -+ valueAsType = &MsgUpdateParam_AsCoin{AsInt64: v} ++ asTypeIface = &MsgUpdateParam_AsCoin{AsInt64: t} default: - panic(fmt.Sprintf("unexpected param value type: %T", value)) + panic(fmt.Sprintf("unexpected param value type: %T", asType)) } // ... } @@ -564,7 +589,7 @@ Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switc + func (msg *MsgUpdateParam) paramTypeIsInt64() error { + _, ok := msg.AsType.(*MsgUpdateParam_AsInt64) + if !ok { -+ return ErrGatewayParamInvalid.Wrapf( ++ return ErrExamplemodParamInvalid.Wrapf( + "invalid type for param %q expected %T type: %T", + msg.Name, &MsgUpdateParam_AsInt64{}, msg.AsType, + ) @@ -587,20 +612,20 @@ Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switc ) (*types.MsgUpdateParamResponse, error) { // ... switch msg.Name { -+ case types.ParamRelayDifficultyTargetHash: -+ value, ok := msg.AsType.(*types.MsgUpdateParam_AsBytes) ++ case types.ParamNewParameter: ++ asType, ok := msg.AsType.(*types.MsgUpdateParam_AsInt64) + if !ok { + return nil, types.ErrProofParamInvalid.Wrapf("unsupported value type for %s param: %T", msg.Name, msg.AsType) + } -+ relayDifficultyTargetHash := value.AsBytes ++ newParameter := value.AsInt64 + -+ if err := types.ValidateRelayDifficultyTargetHash(relayDifficultyTargetHash); err != nil { ++ if err := types.ValidateNewParameter(newParameter); err != nil { + return nil, err + } + -+ params.RelayDifficultyTargetHash = relayDifficultyTargetHash ++ params.NewParameter = newParameter default: - return nil, types.ErrProofParamInvalid.Wrapf("unsupported param %q", msg.Name) + return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) } // ... } From 5604ecc2bd5e4141a182c88bb1212e305dbd9689 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 27 Sep 2024 12:17:42 +0200 Subject: [PATCH 09/21] docs: update ToC --- docusaurus/docs/develop/developer_guide/adding_params.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index 4f1621076..18fe79ac9 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -11,9 +11,11 @@ title: Adding On-Chain Module Parameters - [0.2 Update the `MsgUpdateParam` Message Fields](#02-update-the-msgupdateparam-message-fields) - [0.3 Comment Out AutoCLI](#03-comment-out-autocli) - [0.4. Update the DAO Genesis Authorizations JSON File](#04-update-the-dao-genesis-authorizations-json-file) + - [0.5 Update the `NewMsgUpdateParam` Constructor and `MsgUpdateParam#ValidateBasic()`](#05-update-the-newmsgupdateparam-constructor-and-msgupdateparamvalidatebasic) + - [0.6 Update the Module's `msgServer#UpdateParam()` Handler](#06-update-the-modules-msgserverupdateparam-handler) + - [0.7 Update Module's Params Test Suite `ModuleParamConfig`](#07-update-modules-params-test-suite-moduleparamconfig) - [1. Define the Parameter in the Protocol Buffers File](#1-define-the-parameter-in-the-protocol-buffers-file) - [2 Update the Parameter Integration Tests](#2-update-the-parameter-integration-tests) - - [2.0 If the Module Didn't Previously Support a `MsgUpdateParam` Message](#20-if-the-module-didnt-previously-support-a-msgupdateparam-message) - [2.1 Add a valid param](#21-add-a-valid-param) - [2.2 Check for `as_` on `MsgUpdateParam`](#22-check-for-as_type-on-msgupdateparam) - [3. Update the Default Parameter Values](#3-update-the-default-parameter-values) @@ -31,7 +33,6 @@ title: Adding On-Chain Module Parameters - [7.1 Parameter Validation Tests](#71-parameter-validation-tests) - [7.2 Parameter Update Tests](#72-parameter-update-tests) - [8. Add Parameter Case to Switch Statements](#8-add-parameter-case-to-switch-statements) - - [8.0 If the Module Doesn't Already Support a `MsgUpdateParam` Message](#80-if-the-module-doesnt-already-support-a-msgupdateparam-message) - [8.1 `MsgUpdateParam#ValidateBasic()`](#81-msgupdateparamvalidatebasic) - [8.2 `msgServer#UpdateParam()`](#82-msgserverupdateparam) @@ -260,7 +261,6 @@ Add `MsgUpdateParam` & `MsgUpdateParamResponse` to the module's `ModuleParamConf } ``` - ### 1. Define the Parameter in the Protocol Buffers File Open the appropriate `.proto` file for your module (e.g., `params.proto`) and define the new parameter. From bcefdd833759190434fc3e50a50c2b6db72b0764 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Tue, 1 Oct 2024 10:41:27 +0200 Subject: [PATCH 10/21] chore: self-review improvements --- .../develop/developer_guide/adding_params.md | 324 ++++++++++-------- 1 file changed, 188 insertions(+), 136 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index 18fe79ac9..a1175e1dc 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -8,7 +8,7 @@ title: Adding On-Chain Module Parameters - [Step-by-Step Instructions](#step-by-step-instructions) - [0. If the Module Doesn't Already Support a `MsgUpdateParam` Message](#0-if-the-module-doesnt-already-support-a-msgupdateparam-message) - [0.1 Scaffold the `MsgUpdateParam` Message](#01-scaffold-the-msgupdateparam-message) - - [0.2 Update the `MsgUpdateParam` Message Fields](#02-update-the-msgupdateparam-message-fields) + - [0.2 Update `MsgUpdateParam` and `MsgUpdateParamResponse` Fields](#02-update-msgupdateparam-and-msgupdateparamresponse-fields) - [0.3 Comment Out AutoCLI](#03-comment-out-autocli) - [0.4. Update the DAO Genesis Authorizations JSON File](#04-update-the-dao-genesis-authorizations-json-file) - [0.5 Update the `NewMsgUpdateParam` Constructor and `MsgUpdateParam#ValidateBasic()`](#05-update-the-newmsgupdateparam-constructor-and-msgupdateparamvalidatebasic) @@ -60,16 +60,16 @@ The steps outlined below follow **the same example** where: When following these steps, be sure to substitute these example values with your own! ::: +:::tip +At any point, you can always run `go test ./x/examplemod/...` to check whether everything is working or locate outstanding necessary changes. +::: + ### 0. If the Module Doesn't Already Support a `MsgUpdateParam` Message In order to support **individual parameter updates**, the module MUST have a `MsgUpdateParam` message. If the module doesn't already support this message, it will need to be added. -:::tip -At any point, you can always run `go test ./x/examplemod/...` to check whether everything is working or locate outstanding necessary changes. -::: - -#### 0.1 Scaffold the `MsgUpdateParam` Message +#### 0.1. Scaffold the `MsgUpdateParam` Message Use `ignite` to scaffold a new `MsgUpdateParam` message for the module. Additional flags are used for convenience: @@ -93,9 +93,9 @@ go: github.com/pokt-network/poktroll/api/poktroll/examplemod imports Then try running `make proto_clean_pulsar`. ::: -#### 0.2 Update the `MsgUpdateParam` Message Fields +#### 0.2. Update `MsgUpdateParam` and `MsgUpdateParamResponse` Fields -Update the `MsgUpdateParam` message fields in the module's `tx.proto` file to include the following comments and protobuf options: +Update the `MsgUpdateParam` message fields in the module's `tx.proto` file (e.g. `proto/poktroll/examplemod/tx.proto`) to include the following comments and protobuf options: ```protobuf + // MsgUpdateParam is the Msg/UpdateParam request type to update a single param. @@ -119,6 +119,14 @@ Update the `MsgUpdateParam` message fields in the module's `tx.proto` file to in message MsgUpdateParamResponse { ``` +Update the `MsgUpdateParamResponse` message field (`params`) in the same `tx.proto` file: +```protobuf + message MsgUpdateParamResponse { +- string params = 1; ++ Params params = 1; + } +``` + #### 0.3 Comment Out AutoCLI When scaffolding the `MsgUpdateParam` message, lines are added to `x/examplemod/module/autocli.go`. @@ -187,18 +195,18 @@ Prepare `x/examplemod/types/message_update_param.go` to handle message construct return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) } + -+ // Parameter value cannot be nil. ++ // Parameter value MUST NOT be nil. + if msg.AsType == nil { -+ return ErrGatewayParamInvalid.Wrap("missing param AsType") ++ return ErrExamplemodParamInvalid.Wrap("missing param AsType") + } + -+ // Parameter name must be supported by this module. ++ // Parameter name MUST be supported by this module. + switch msg.Name { + default: + return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) + } -return nil + return nil } ``` #### 0.6 Update the Module's `msgServer#UpdateParam()` Handler @@ -206,23 +214,21 @@ return nil Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter updates by type: ```go -+ // UpdateParam updates a single parameter in the proof module and returns -+ // all active parameters. - func (k msgServer) UpdateParam( - ctx context.Context, - msg *types.MsgUpdateParam, - ) (*types.MsgUpdateParamResponse, error) { +- func (k msgServer) UpdateParam(goCtx context.Context, msg *types.MsgUpdateParam) (*types.MsgUpdateParamResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - // TODO: Handling the message - _ = ctx - ++ // UpdateParam updates a single parameter in the proof module and returns ++ // all active parameters. ++ func (k msgServer) UpdateParam(ctx context.Context, msg *types.MsgUpdateParam) (*types.MsgUpdateParamResponse, error) { + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + + if k.GetAuthority() != msg.Authority { -+ return nil, types.ErrProofInvalidSigner.Wrapf("invalid authority; expected %s, got %s", k.GetAuthority(), msg.Authority) ++ return nil, types.ErrExamplemodInvalidSigner.Wrapf("invalid authority; expected %s, got %s", k.GetAuthority(), msg.Authority) + } + + params := k.GetParams(ctx) @@ -263,7 +269,7 @@ Add `MsgUpdateParam` & `MsgUpdateParamResponse` to the module's `ModuleParamConf ### 1. Define the Parameter in the Protocol Buffers File -Open the appropriate `.proto` file for your module (e.g., `params.proto`) and define the new parameter. +Define the new parameter in the module's `params.proto` file (e.g., `proto/poktroll/examplemod/params.proto`): ```protobuf message Params { @@ -278,14 +284,14 @@ Open the appropriate `.proto` file for your module (e.g., `params.proto`) and de Don't forget to run `make proto_regen` to update generated protobuf go code. ::: -### 2 Update the Parameter Integration Tests +### 2. Update the Parameter Integration Tests Integration tests which cover parameter updates utilize the `ModuleParamConfig`s defined in [`testutil/integration/params/param_configs.go`](https://github.com/pokt-network/poktroll/blob/main/testutil/integration/suites/param_configs.go) to dynamically (i.e. using reflection) construct and send parameter update messages in a test environment. When adding parameters to a module, it is necessary to update that module's `ModuleParamConfig` to include the new parameter, othwerwise it will not be covered by the integration test suite. #### 2.1 Add a valid param -Update `ModuleParamConfig#ValidParams` to include a valid and non-default value for the new parameter: +Update `ModuleParamConfig#ValidParams` to include a valid and non-default value for the new parameter in the module's `tx.proto` file (e.g. `proto/poktroll/examplemod/tx.proto`): ```go ExamplemodModuleParamConfig = ModuleParamConfig{ @@ -299,7 +305,7 @@ Update `ModuleParamConfig#ValidParams` to include a valid and non-default value #### 2.2 Check for `as_` on `MsgUpdateParam` -Ensure an `as_` field exists on `MsgUpdateParam` corresponding to the type of the new parameter: +Ensure an `as_` field exists on `MsgUpdateParam` corresponding to the type of the new parameter (`proto/poktroll/examplemod/tx.proto`): ```proto message MsgUpdateParam { @@ -346,7 +352,7 @@ value, key, and parameter name for the new parameter and include the default in } ``` -### 3.2 Genesis Configuration Parameter Defaults +#### 3.2 Genesis Configuration Parameter Defaults Add the new parameter to the genesis configuration file (e.g., `config.yml`): @@ -359,81 +365,24 @@ Add the new parameter to the genesis configuration file (e.g., `config.yml`): + new_parameter: 42 ``` -### 4. Update the Makefile and Supporting JSON Files +### 4. Parameter Validation -#### 4.1 Update the Makefile - -Add a new target in the `Makefile` to update the new parameter. -Below is an example of adding the make target corresponding to the `shared` module's `num_blocks_per_session` param: - -```makefile -.PHONY: params_update_examplemod_new_parameter -params_update_examplemod_new_parameter: ## Update the examplemod module new_parameter param - poktrolld tx authz exec ./tools/scripts/params/examplemod_new_parameter.json $(PARAM_FLAGS) -``` - -:::warning -Reminder to substitute `examplemod` and `new_parameter` with your module and param names! -::: - -#### 4.2 Create a new JSON File for the Individual Parameter Update - -Create a new JSON file (e.g., `proof_new_parameter_name.json`) in the tools/scripts/params directory to specify how to update the new parameter: - -```json -{ - "body": { - "messages": [ - { - "@type": "/poktroll.examplemod.MsgUpdateParam", // Replace module name - "authority": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", - "name": "new_parameter", // Replace new parameter name - "as_int64": "42" // Replace default value - } - ] - } -} -``` - -#### 4.3 Update the JSON File for Updating All Parameters for the Module - -Add a line to the existing module's `MsgUpdateParam` JSON file (e.g., `proof_all.json`) -with the default value for the new parameter. - -```json - { - "body": { - "messages": [ - { - "@type": "/poktroll.examplemod.MsgUpdateParams", // Replace module name - "authority": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", - "params": { - // Other existing parameters... -+ "new_parameter": "42" // Replace name and default value - } - } - ] - } - } -``` - -### 5. Parameter Validation - -#### 5.1 New Parameter Validation +#### 4.1 Define a Validation Function Implement a validation function for the new parameter in `x/examplemod/types/params.go`: ```go ++ // ValidateNewParameter validates the NewParameter param. + func ValidateNewParameter(v interface{}) error { + _, ok := v.(int64) + if !ok { -+ return fmt.Errorf("invalid parameter type: %T", v) ++ return ErrExamplemodParamInvalid.Wrapf("invalid parameter type: %T", v) + } + return nil + } ``` -#### 5.2 Parameter Validation in Workflow +#### 4.2 Call it in the `Params#Validate()` Integrate the usage of the new `ValidateNewParameter` function in the corresponding `Params#Validate()` function where this is used: @@ -448,9 +397,9 @@ Integrate the usage of the new `ValidateNewParameter` function in the correspond } ``` -### 6. Add the Parameter to `ParamSetPairs()` +#### 4.3 Add a `ParamSetPair` to `ParamSetPairs()` -Include the new parameter in the `ParamSetPairs` function return: +Include a call to `NewParamSetPair()`, passing the parameter's key, value pointer, and validation function in the `ParamSetPairs` function return: ```go func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { @@ -466,12 +415,12 @@ Include the new parameter in the `ParamSetPairs` function return: } ``` -### 7. Update Unit Tests +### 5. Update Unit Tests -#### 7.1 Parameter Validation Tests +#### 5.1 Parameter Validation Tests -Add unit tests which exercise validation of the new parameter(s) in `x/examplemod/keeper/params_test.go`: -Ensure there is a test function for each parameter which covers all cases of invalid input +Add unit tests which exercise validation of the new parameter(s) in `x/examplemod/keeper/params_test.go`. +Ensure there is a test function for each parameter which covers all cases of invalid input: ```go func TestGetParams(t *testing.T) { @@ -487,7 +436,7 @@ Ensure there is a test function for each parameter which covers all cases of inv + { + desc: "invalid type", + newParameter: "420", -+ expectedErr: fmt.Errorf("invalid parameter type: string"), ++ expectedErr: ErrExamplemodParamInvalid.Wrapf("invalid parameter type: string"), + }, + { + desc: "valid newParameterName", @@ -495,12 +444,12 @@ Ensure there is a test function for each parameter which covers all cases of inv + }, + } + -+ for _, tt := range tests { -+ t.Run(tt.desc, func(t *testing.T) { -+ err := ValidateNewParameter(tt.newParameter) -+ if tt.expectedErr != nil { ++ for _, test := range tests { ++ t.Run(test.desc, func(t *testing.T) { ++ err := ValidateNewParameter(test.newParameter) ++ if test.expectedErr != nil { + require.Error(t, err) -+ require.Contains(t, err.Error(), tt.expectedErr.Error()) ++ require.Contains(t, err.Error(), test.expectedErr.Error()) + } else { + require.NoError(t, err) + } @@ -509,9 +458,9 @@ Ensure there is a test function for each parameter which covers all cases of inv + } ``` -#### 7.2 Parameter Update Tests +#### 5.2 Parameter Update Tests -Add test cases to `x/examplemod/keeper/msg_update_params_test.go` to ensure coverage over any invalid parameter configurations. +Add test cases to `x/examplemod/keeper/msg_update_params_test.go` to ensure coverage over any invalid parameter combinations. Add a case for the "minimal params" if some subset of the params are "required". If one already exist, update it if applicable; e.g.: @@ -528,8 +477,8 @@ If one already exist, update it if applicable; e.g.: + }, ``` -Add unit tests which exercise individual parameter updates in `x/examplemod/keeper/msg_server_update_param_test.go`. -These tests assert that the value of a given parameter is: +Add a unit test which exercise individually updating the new parameter in `x/examplemod/keeper/msg_server_update_param_test.go`. +This test asserts that updating was successful and that no other parameter was effected: ```go + func TestMsgUpdateParam_UpdateNewParameterOnly(t *testing.T) { @@ -551,55 +500,102 @@ These tests assert that the value of a given parameter is: + } + res, err := msgSrv.UpdateParam(ctx, updateParamMsg) + require.NoError(t, err) -+ + require.Equal(t, expectedNewParameter, res.Params.NewParameter) -+ -+ // IMPORTANT!: THIS TEST SHOULD ALSO ASSERT THAT ALL OTHER PARAMS OF THE SAME MODULE REMAIN UNCHANGED ++ ++ // Ensure the other parameters are unchanged ++ testkeeper.AssertDefaultParamsEqualExceptFields(t, &defaultParams, res.Params, "MinStake") + } ``` -### 8. Add Parameter Case to Switch Statements +:::warning +If creating `msg_server_update_param_test.go`, be sure to: +1. use the `keeper_test` package (i.e. `package keeper_test`). +2. add the testutil keeper import: `testkeeper "github.com/pokt-network/poktroll/testutil/keeper"` +::: + +Update `x/examplemod/types/message_update_param_test.go` to use the new `MsgUpdateParam#AsType` fields. +Start with the following cases and add those which cover all invalid values for the new param (and its `AsType`; e.g. `AsCoin` cannot be nil): -#### 8.1 `MsgUpdateParam#ValidateBasic()` +```go + func TestMsgUpdateParam_ValidateBasic(t *testing.T) { + tests := []struct { +- name string ++ desc string + msg MsgUpdateParam + err error + }{ + { +- name: "invalid address", ++ desc: "invalid: authority address invalid", + msg: MsgUpdateParam{ + Authority: "invalid_address", ++ Name: "", // Doesn't matter for this test ++ AsType: &MsgUpdateParam_AsInt64{AsInt64: 0}, + }, + err: sdkerrors.ErrInvalidAddress, ++ }, { ++ desc: "invalid: param name incorrect (non-existent)", ++ msg: MsgUpdateParam{ ++ Authority: sample.AccAddress(), ++ Name: "non_existent", ++ AsType: &MsgUpdateParam_AsInt64{AsInt64: DefaultNewParameter}, ++ }, ++ err: ErrExamplemodParamInvalid, + }, { +- name: "valid address", ++ desc: "valid: correct address, param name, and type", + msg: MsgUpdateParam{ + Authority: sample.AccAddress(), ++ Name: ParamNewParameter, ++ AsType: &MsgUpdateParam_AsInt64{AsInt64: DefaultNewParameter}, + }, + }, + } + // ... + } +``` -Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switch in `MsgUpdateParam#ValidateBasic()` in `x/examplemod/types/message_update_param.go`: +### 6. Add Parameter Case to Switch Statements + +#### 6.1 `MsgUpdateParam#ValidateBasic()` + +Add the parameter type and name (e.g. `ParamNameNewParameter`) to new cases in the switch statements in `NewMsgUpdateParam()` and `MsgUpdateParam#ValidateBasic()` in `x/examplemod/types/message_update_param.go`: ```go func NewMsgUpdateParam(authority string, name string, asType any) *MsgUpdateParam { - // ... - switch t := asType.(type) { -+ case int64: -+ asTypeIface = &MsgUpdateParam_AsCoin{AsInt64: t} - default: - panic(fmt.Sprintf("unexpected param value type: %T", asType)) - } - // ... + // ... + switch t := asType.(type) { ++ case int64: ++ asTypeIface = &MsgUpdateParam_AsCoin{AsInt64: t} + default: + panic(fmt.Sprintf("unexpected param value type: %T", asType)) + } + // ... } func (msg *MsgUpdateParam) ValidateBasic() error { - // ... - switch msg.Name { -+ case ParamNewParameter: -+ return msg.paramTypeIsInt64() - default: - return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) - } + // ... + switch msg.Name { ++ case ParamNewParameter: ++ return msg.paramTypeIsInt64() + default: + return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) + } } + + func (msg *MsgUpdateParam) paramTypeIsInt64() error { -+ _, ok := msg.AsType.(*MsgUpdateParam_AsInt64) -+ if !ok { -+ return ErrExamplemodParamInvalid.Wrapf( -+ "invalid type for param %q expected %T type: %T", -+ msg.Name, &MsgUpdateParam_AsInt64{}, msg.AsType, -+ ) -+ } ++ if _, ok := msg.AsType.(*MsgUpdateParam_AsInt64); !ok { ++ return ErrExamplemodParamInvalid.Wrapf( ++ "invalid type for param %q expected %T, got: %T", ++ msg.Name, &MsgUpdateParam_AsInt64{}, msg.AsType, ++ ) ++ } + -+ return nil ++ return nil + } ``` -#### 8.2 `msgServer#UpdateParam()` +#### 6.2 `msgServer#UpdateParam()` Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switch statement in `msgServer#UpdateParam()` in `x/examplemod/keeper/msg_server_update_param.go`: @@ -613,11 +609,10 @@ Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switc // ... switch msg.Name { + case types.ParamNewParameter: -+ asType, ok := msg.AsType.(*types.MsgUpdateParam_AsInt64) -+ if !ok { -+ return nil, types.ErrProofParamInvalid.Wrapf("unsupported value type for %s param: %T", msg.Name, msg.AsType) ++ if _, ok := msg.AsType.(*types.MsgUpdateParam_AsInt64); !ok { ++ return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported value type for %s param: %T", msg.Name, msg.AsType) + } -+ newParameter := value.AsInt64 ++ newParameter := msg.GetAsInt64() + + if err := types.ValidateNewParameter(newParameter); err != nil { + return nil, err @@ -630,3 +625,60 @@ Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switc // ... } ``` + +### 7. Update the Makefile and Supporting JSON Files + +#### 7.1 Update the Makefile + +Add a new target in `makefiles/params.mk` to update the new parameter: + +```makefile +.PHONY: params_update_examplemod_new_parameter +params_update_examplemod_new_parameter: ## Update the examplemod module new_parameter param + poktrolld tx authz exec ./tools/scripts/params/examplemod_new_parameter.json $(PARAM_FLAGS) +``` + +:::warning +Reminder to substitute `examplemod` and `new_parameter` with your module and param names! +::: + +#### 7.2 Create a new JSON File for the Individual Parameter Update + +Create a new JSON file (e.g., `proof_new_parameter_name.json`) in the tools/scripts/params directory to specify how to update the new parameter: + +```json +{ + "body": { + "messages": [ + { + "@type": "/poktroll.examplemod.MsgUpdateParam", // Replace module name + "authority": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", + "name": "new_parameter", // Replace new parameter name + "as_int64": "42" // Replace default value + } + ] + } +} +``` + +#### 7.3 Update the JSON File for Updating All Parameters for the Module + +Add a line to the existing module's `MsgUpdateParam` JSON file (e.g., `proof_all.json`) +with the default value for the new parameter. + +```json + { + "body": { + "messages": [ + { + "@type": "/poktroll.examplemod.MsgUpdateParams", // Replace module name + "authority": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", + "params": { + // Other existing parameters... ++ "new_parameter": "42" // Replace name and default value + } + } + ] + } + } +``` From b43c648fcbcfc687abf3093c2f95298ff8360125 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 2 Oct 2024 14:55:16 +0200 Subject: [PATCH 11/21] docs: improvements --- .../develop/developer_guide/adding_params.md | 254 ++++++++++-------- 1 file changed, 136 insertions(+), 118 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index a1175e1dc..ce1d10ef6 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -15,26 +15,27 @@ title: Adding On-Chain Module Parameters - [0.6 Update the Module's `msgServer#UpdateParam()` Handler](#06-update-the-modules-msgserverupdateparam-handler) - [0.7 Update Module's Params Test Suite `ModuleParamConfig`](#07-update-modules-params-test-suite-moduleparamconfig) - [1. Define the Parameter in the Protocol Buffers File](#1-define-the-parameter-in-the-protocol-buffers-file) - - [2 Update the Parameter Integration Tests](#2-update-the-parameter-integration-tests) - - [2.1 Add a valid param](#21-add-a-valid-param) - - [2.2 Check for `as_` on `MsgUpdateParam`](#22-check-for-as_type-on-msgupdateparam) - - [3. Update the Default Parameter Values](#3-update-the-default-parameter-values) - - [3.1 Go Source Defaults](#31-go-source-defaults) - - [3.2 Genesis Configuration Parameter Defaults](#32-genesis-configuration-parameter-defaults) - - [4. Update the Makefile and Supporting JSON Files](#4-update-the-makefile-and-supporting-json-files) - - [4.1 Update the Makefile](#41-update-the-makefile) - - [4.2 Create a new JSON File for the Individual Parameter Update](#42-create-a-new-json-file-for-the-individual-parameter-update) - - [4.3 Update the JSON File for Updating All Parameters for the Module](#43-update-the-json-file-for-updating-all-parameters-for-the-module) - - [5. Parameter Validation](#5-parameter-validation) - - [5.1 New Parameter Validation](#51-new-parameter-validation) - - [5.2 Parameter Validation in Workflow](#52-parameter-validation-in-workflow) - - [6. Add the Parameter to `ParamSetPairs()`](#6-add-the-parameter-to-paramsetpairs) - - [7. Update Unit Tests](#7-update-unit-tests) - - [7.1 Parameter Validation Tests](#71-parameter-validation-tests) - - [7.2 Parameter Update Tests](#72-parameter-update-tests) - - [8. Add Parameter Case to Switch Statements](#8-add-parameter-case-to-switch-statements) - - [8.1 `MsgUpdateParam#ValidateBasic()`](#81-msgupdateparamvalidatebasic) - - [8.2 `msgServer#UpdateParam()`](#82-msgserverupdateparam) + - [2. Update the Default Parameter Values](#2-update-the-default-parameter-values) + - [2.1 Go Source Defaults](#21-go-source-defaults) + - [2.2 Genesis Configuration Parameter Defaults](#22-genesis-configuration-parameter-defaults) + - [3. Parameter Validation](#3-parameter-validation) + - [3.1 Define a Validation Function](#31-define-a-validation-function) + - [3.2 Call it in the `Params#Validate()`](#32-call-it-in-the-paramsvalidate) + - [3.3 Add a `ParamSetPair` to `ParamSetPairs()`](#33-add-a-paramsetpair-to-paramsetpairs) + - [4. Add Parameter Case to Switch Statements](#4-add-parameter-case-to-switch-statements) + - [4.1 `MsgUpdateParam#ValidateBasic()`](#41-msgupdateparamvalidatebasic) + - [4.2 `msgServer#UpdateParam()`](#42-msgserverupdateparam) + - [5. Update Unit Tests](#5-update-unit-tests) + - [5.1 Parameter Validation Tests](#51-parameter-validation-tests) + - [5.2 Parameter Update Tests](#52-parameter-update-tests) + - [6. Update the Parameter Integration Tests](#6-update-the-parameter-integration-tests) + - [6.1 Add a valid param](#61-add-a-valid-param) + - [6.2 Check for `as_` on `MsgUpdateParam`](#62-check-for-as_type-on-msgupdateparam) + - [6.3 Update the module's `ModuleParamConfig`](#63-update-the-modules-moduleparamconfig) + - [7. Update the Makefile and Supporting JSON Files](#7-update-the-makefile-and-supporting-json-files) + - [7.1 Update the Makefile](#71-update-the-makefile) + - [7.2 Create a new JSON File for the Individual Parameter Update](#72-create-a-new-json-file-for-the-individual-parameter-update) + - [7.3 Update the JSON File for Updating All Parameters for the Module](#73-update-the-json-file-for-updating-all-parameters-for-the-module) Adding a new on-chain module parameter involves multiple steps to ensure that the parameter is properly integrated into the system. This guide will walk you through @@ -194,6 +195,8 @@ Prepare `x/examplemod/types/message_update_param.go` to handle message construct if err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) } +- +- return nil + + // Parameter value MUST NOT be nil. + if msg.AsType == nil { @@ -205,9 +208,7 @@ Prepare `x/examplemod/types/message_update_param.go` to handle message construct + default: + return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) + } - - return nil -} + } ``` #### 0.6 Update the Module's `msgServer#UpdateParam()` Handler @@ -284,42 +285,9 @@ Define the new parameter in the module's `params.proto` file (e.g., `proto/poktr Don't forget to run `make proto_regen` to update generated protobuf go code. ::: -### 2. Update the Parameter Integration Tests - -Integration tests which cover parameter updates utilize the `ModuleParamConfig`s defined in [`testutil/integration/params/param_configs.go`](https://github.com/pokt-network/poktroll/blob/main/testutil/integration/suites/param_configs.go) to dynamically (i.e. using reflection) construct and send parameter update messages in a test environment. -When adding parameters to a module, it is necessary to update that module's `ModuleParamConfig` to include the new parameter, othwerwise it will not be covered by the integration test suite. - -#### 2.1 Add a valid param +### 2. Update the Default Parameter Values -Update `ModuleParamConfig#ValidParams` to include a valid and non-default value for the new parameter in the module's `tx.proto` file (e.g. `proto/poktroll/examplemod/tx.proto`): - -```go - ExamplemodModuleParamConfig = ModuleParamConfig{ - // ... - ValidParams: gatewaytypes.Params{ -+ NewParameter: 420, - }, - // ... - } -``` - -#### 2.2 Check for `as_` on `MsgUpdateParam` - -Ensure an `as_` field exists on `MsgUpdateParam` corresponding to the type of the new parameter (`proto/poktroll/examplemod/tx.proto`): - -```proto - message MsgUpdateParam { - ... - oneof as_type { -- // Add `as_` fields for each type in this module's Params type; e.g.: -+ int64 as_int64 = 3 [(gogoproto.jsontag) = "as_int64"]; - } - } -``` - -### 3. Update the Default Parameter Values - -#### 3.1 Go Source Defaults +#### 2.1 Go Source Defaults In the corresponding Go file (e.g., `x/examplemod/types/params.go`), define the default value, key, and parameter name for the new parameter and include the default in the @@ -352,7 +320,7 @@ value, key, and parameter name for the new parameter and include the default in } ``` -#### 3.2 Genesis Configuration Parameter Defaults +#### 2.2 Genesis Configuration Parameter Defaults Add the new parameter to the genesis configuration file (e.g., `config.yml`): @@ -365,9 +333,9 @@ Add the new parameter to the genesis configuration file (e.g., `config.yml`): + new_parameter: 42 ``` -### 4. Parameter Validation +### 3. Parameter Validation -#### 4.1 Define a Validation Function +#### 3.1 Define a Validation Function Implement a validation function for the new parameter in `x/examplemod/types/params.go`: @@ -382,7 +350,7 @@ Implement a validation function for the new parameter in `x/examplemod/types/par + } ``` -#### 4.2 Call it in the `Params#Validate()` +#### 3.2 Call it in the `Params#Validate()` Integrate the usage of the new `ValidateNewParameter` function in the corresponding `Params#Validate()` function where this is used: @@ -397,7 +365,7 @@ Integrate the usage of the new `ValidateNewParameter` function in the correspond } ``` -#### 4.3 Add a `ParamSetPair` to `ParamSetPairs()` +#### 3.3 Add a `ParamSetPair` to `ParamSetPairs()` Include a call to `NewParamSetPair()`, passing the parameter's key, value pointer, and validation function in the `ParamSetPairs` function return: @@ -415,6 +383,77 @@ Include a call to `NewParamSetPair()`, passing the parameter's key, value pointe } ``` +### 4. Add Parameter Case to Switch Statements + +#### 4.1 `MsgUpdateParam#ValidateBasic()` + +Add the parameter type and name (e.g. `ParamNameNewParameter`) to new cases in the switch statements in `NewMsgUpdateParam()` and `MsgUpdateParam#ValidateBasic()` in `x/examplemod/types/message_update_param.go`: + +```go + func NewMsgUpdateParam(authority string, name string, asType any) *MsgUpdateParam { + // ... + switch t := asType.(type) { ++ case int64: ++ asTypeIface = &MsgUpdateParam_AsCoin{AsInt64: t} + default: + panic(fmt.Sprintf("unexpected param value type: %T", asType)) + } + // ... + } + + func (msg *MsgUpdateParam) ValidateBasic() error { + // ... + switch msg.Name { ++ case ParamNewParameter: ++ return msg.paramTypeIsInt64() + default: + return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) + } + } ++ ++ func (msg *MsgUpdateParam) paramTypeIsInt64() error { ++ if _, ok := msg.AsType.(*MsgUpdateParam_AsInt64); !ok { ++ return ErrExamplemodParamInvalid.Wrapf( ++ "invalid type for param %q expected %T, got: %T", ++ msg.Name, &MsgUpdateParam_AsInt64{}, msg.AsType, ++ ) ++ } ++ ++ return nil ++ } +``` + +#### 4.2 `msgServer#UpdateParam()` + +Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switch statement in `msgServer#UpdateParam()` in `x/examplemod/keeper/msg_server_update_param.go`: + +```go + // UpdateParam updates a single parameter in the proof module and returns + // all active parameters. + func (k msgServer) UpdateParam( + ctx context.Context, + msg *types.MsgUpdateParam, + ) (*types.MsgUpdateParamResponse, error) { + // ... + switch msg.Name { ++ case types.ParamNewParameter: ++ if _, ok := msg.AsType.(*types.MsgUpdateParam_AsInt64); !ok { ++ return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported value type for %s param: %T", msg.Name, msg.AsType) ++ } ++ newParameter := msg.GetAsInt64() ++ ++ if err := types.ValidateNewParameter(newParameter); err != nil { ++ return nil, err ++ } ++ ++ params.NewParameter = newParameter + default: + return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) + } + // ... + } +``` + ### 5. Update Unit Tests #### 5.1 Parameter Validation Tests @@ -555,75 +594,54 @@ Start with the following cases and add those which cover all invalid values for } ``` -### 6. Add Parameter Case to Switch Statements +### 6. Update the Parameter Integration Tests -#### 6.1 `MsgUpdateParam#ValidateBasic()` +Integration tests which cover parameter updates utilize the `ModuleParamConfig`s defined in [`testutil/integration/params/param_configs.go`](https://github.com/pokt-network/poktroll/blob/main/testutil/integration/suites/param_configs.go) to dynamically (i.e. using reflection) construct and send parameter update messages in a test environment. +When adding parameters to a module, it is necessary to update that module's `ModuleParamConfig` to include the new parameter, othwerwise it will not be covered by the integration test suite. -Add the parameter type and name (e.g. `ParamNameNewParameter`) to new cases in the switch statements in `NewMsgUpdateParam()` and `MsgUpdateParam#ValidateBasic()` in `x/examplemod/types/message_update_param.go`: +#### 6.1 Add a valid param + +Update `ModuleParamConfig#ValidParams` to include a valid and non-default value for the new parameter in the module's `tx.proto` file (e.g. `proto/poktroll/examplemod/tx.proto`): ```go - func NewMsgUpdateParam(authority string, name string, asType any) *MsgUpdateParam { - // ... - switch t := asType.(type) { -+ case int64: -+ asTypeIface = &MsgUpdateParam_AsCoin{AsInt64: t} - default: - panic(fmt.Sprintf("unexpected param value type: %T", asType)) - } - // ... + ExamplemodModuleParamConfig = ModuleParamConfig{ + // ... + ValidParams: gatewaytypes.Params{ ++ NewParameter: 420, + }, + // ... } +``` - func (msg *MsgUpdateParam) ValidateBasic() error { - // ... - switch msg.Name { -+ case ParamNewParameter: -+ return msg.paramTypeIsInt64() - default: - return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) - } - } -+ -+ func (msg *MsgUpdateParam) paramTypeIsInt64() error { -+ if _, ok := msg.AsType.(*MsgUpdateParam_AsInt64); !ok { -+ return ErrExamplemodParamInvalid.Wrapf( -+ "invalid type for param %q expected %T, got: %T", -+ msg.Name, &MsgUpdateParam_AsInt64{}, msg.AsType, -+ ) -+ } -+ -+ return nil -+ } +#### 6.2 Check for `as_` on `MsgUpdateParam` + +Ensure an `as_` field exists on `MsgUpdateParam` corresponding to the type of the new parameter (`proto/poktroll/examplemod/tx.proto`): + +```proto + message MsgUpdateParam { + ... + oneof as_type { +- // Add `as_` fields for each type in this module's Params type; e.g.: ++ int64 as_int64 = 3 [(gogoproto.jsontag) = "as_int64"]; + } + } ``` -#### 6.2 `msgServer#UpdateParam()` +#### 6.3 Update the module's `ModuleParamConfig` -Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switch statement in `msgServer#UpdateParam()` in `x/examplemod/keeper/msg_server_update_param.go`: +Ensure that all available `as_` types for the module are present on the module's `ModuleParamConfig#ParamTypes` field: ```go - // UpdateParam updates a single parameter in the proof module and returns - // all active parameters. - func (k msgServer) UpdateParam( - ctx context.Context, - msg *types.MsgUpdateParam, - ) (*types.MsgUpdateParamResponse, error) { + ExamplemodModuleParamConfig = ModuleParamConfig{ // ... - switch msg.Name { -+ case types.ParamNewParameter: -+ if _, ok := msg.AsType.(*types.MsgUpdateParam_AsInt64); !ok { -+ return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported value type for %s param: %T", msg.Name, msg.AsType) -+ } -+ newParameter := msg.GetAsInt64() -+ -+ if err := types.ValidateNewParameter(newParameter); err != nil { -+ return nil, err -+ } -+ -+ params.NewParameter = newParameter - default: - return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) - } + ValidParams: suppliertypes.Params{}, ++ ParamTypes: map[ParamType]any{ ++ ParamTypeInt64: suppliertypes.MsgUpdateParam_AsInt64{}, ++ }, + DefaultParams: suppliertypes.DefaultParams(), // ... } + ``` ### 7. Update the Makefile and Supporting JSON Files From 54cf68124a1d55fcd357a53c25fd3324b32b69f6 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 2 Oct 2024 16:44:13 +0200 Subject: [PATCH 12/21] chore: improvements --- .../develop/developer_guide/adding_params.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index ce1d10ef6..260d2e90a 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -341,11 +341,14 @@ Implement a validation function for the new parameter in `x/examplemod/types/par ```go + // ValidateNewParameter validates the NewParameter param. -+ func ValidateNewParameter(v interface{}) error { -+ _, ok := v.(int64) ++ func ValidateNewParameter(newParamAny any) error { ++ newParam, ok := newParamAny.(int64) + if !ok { -+ return ErrExamplemodParamInvalid.Wrapf("invalid parameter type: %T", v) ++ return ErrExamplemodParamInvalid.Wrapf("invalid parameter type: %T", newParamAny) + } ++ ++ // Any additional validation... ++ + return nil + } ``` @@ -401,11 +404,18 @@ Add the parameter type and name (e.g. `ParamNameNewParameter`) to new cases in t // ... } ++ // ValidateBasic performs a basic validation of the MsgUpdateParam fields. It ensures: ++ // 1. The parameter name is supported. ++ // 2. The parameter type matches the expected type for a given parameter name. ++ // 3. The parameter value is valid (according to its respective validation function). func (msg *MsgUpdateParam) ValidateBasic() error { // ... switch msg.Name { + case ParamNewParameter: -+ return msg.paramTypeIsInt64() ++ if err := msg.paramTypeIsInt64(); err != nil { ++ return err ++ } ++ return ValidateNewParameter(msg.GetAsInt64()) default: return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) } From 509cf16b41ba9ddd4938dae2241a89379e705a9d Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 2 Oct 2024 17:32:52 +0200 Subject: [PATCH 13/21] chore: improve indentation & validation --- .../develop/developer_guide/adding_params.md | 125 ++++++++---------- 1 file changed, 58 insertions(+), 67 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index 260d2e90a..afe168646 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -175,39 +175,39 @@ Prepare `x/examplemod/types/message_update_param.go` to handle message construct ```go - func NewMsgUpdateParam(authority string, name string, asType string) *MsgUpdateParam { + func NewMsgUpdateParam(authority string, name string, asType any) *MsgUpdateParam { -+ var asTypeIface isMsgUpdateParam_AsType ++ var asTypeIface isMsgUpdateParam_AsType + -+ switch t := asType.(type) { -+ default: -+ panic(fmt.Sprintf("unexpected param value type: %T", asType)) -+ } ++ switch t := asType.(type) { ++ default: ++ panic(fmt.Sprintf("unexpected param value type: %T", asType)) ++ } + return &MsgUpdateParam{ - Authority: authority, - Name: name, -- AsType: asType, -+ AsType: asTypeIface, + Authority: authority, + Name: name, +- AsType: asType, ++ AsType: asTypeIface, } } func (msg *MsgUpdateParam) ValidateBasic() error { - _, err := cosmostypes.AccAddressFromBech32(msg.Authority) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) - } + _, err := cosmostypes.AccAddressFromBech32(msg.Authority) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) + } - -- return nil +- return nil + -+ // Parameter value MUST NOT be nil. -+ if msg.AsType == nil { -+ return ErrExamplemodParamInvalid.Wrap("missing param AsType") -+ } ++ // Parameter value MUST NOT be nil. ++ if msg.AsType == nil { ++ return ErrExamplemodParamInvalid.Wrap("missing param AsType") ++ } + -+ // Parameter name MUST be supported by this module. -+ switch msg.Name { -+ default: -+ return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) -+ } ++ // Parameter name MUST be supported by this module. ++ switch msg.Name { ++ default: ++ return ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) ++ } } ``` #### 0.6 Update the Module's `msgServer#UpdateParam()` Handler @@ -228,25 +228,25 @@ Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter upd + return nil, err + } + -+ if k.GetAuthority() != msg.Authority { -+ return nil, types.ErrExamplemodInvalidSigner.Wrapf("invalid authority; expected %s, got %s", k.GetAuthority(), msg.Authority) -+ } ++ if k.GetAuthority() != msg.Authority { ++ return nil, types.ErrExamplemodInvalidSigner.Wrapf("invalid authority; expected %s, got %s", k.GetAuthority(), msg.Authority) ++ } + -+ params := k.GetParams(ctx) ++ params := k.GetParams(ctx) + -+ switch msg.Name { -+ default: -+ return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) -+ } ++ switch msg.Name { ++ default: ++ return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) ++ } + -+ if err := k.SetParams(ctx, params); err != nil { -+ return nil, err -+ } ++ if err := k.SetParams(ctx, params); err != nil { ++ return nil, err ++ } + -+ updatedParams := k.GetParams(ctx) -+ return &types.MsgUpdateParamResponse{ -+ Params: &updatedParams, -+ }, nil ++ updatedParams := k.GetParams(ctx) ++ return &types.MsgUpdateParamResponse{ ++ Params: &updatedParams, ++ }, nil } ``` @@ -441,25 +441,16 @@ Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switc // UpdateParam updates a single parameter in the proof module and returns // all active parameters. func (k msgServer) UpdateParam( - ctx context.Context, - msg *types.MsgUpdateParam, + ctx context.Context, + msg *types.MsgUpdateParam, ) (*types.MsgUpdateParamResponse, error) { // ... - switch msg.Name { -+ case types.ParamNewParameter: -+ if _, ok := msg.AsType.(*types.MsgUpdateParam_AsInt64); !ok { -+ return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported value type for %s param: %T", msg.Name, msg.AsType) -+ } -+ newParameter := msg.GetAsInt64() -+ -+ if err := types.ValidateNewParameter(newParameter); err != nil { -+ return nil, err -+ } -+ -+ params.NewParameter = newParameter - default: - return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) - } + switch msg.Name { ++ case types.ParamNewParameter: ++ params.NewParameter = msg.GetAsInt64() + default: + return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) + } // ... } ``` @@ -478,9 +469,9 @@ Ensure there is a test function for each parameter which covers all cases of inv + func TestParams_ValidateNewParameter(t *testing.T) { + tests := []struct { -+ desc string -+ newParameter interface{} -+ expectedErr error ++ desc string ++ newParameter any ++ expectedErr error + }{ + { + desc: "invalid type", @@ -488,7 +479,7 @@ Ensure there is a test function for each parameter which covers all cases of inv + expectedErr: ErrExamplemodParamInvalid.Wrapf("invalid parameter type: string"), + }, + { -+ desc: "valid newParameterName", ++ desc: "valid NewParameterName", + newParameter: int64(420), + }, + } @@ -515,14 +506,14 @@ If one already exist, update it if applicable; e.g.: ```go + { -+ desc: "valid: send minimal params", // For parameters which MUST NEVER be their zero value or nil. -+ input: &examplemodtypes.MsgUpdateParams{ -+ Authority: k.GetAuthority(), -+ Params: examplemodtypes.Params{ -+ NewParameter: 42, -+ }, ++ desc: "valid: send minimal params", // For parameters which MUST NEVER be their zero value or nil. ++ input: &examplemodtypes.MsgUpdateParams{ ++ Authority: k.GetAuthority(), ++ Params: examplemodtypes.Params{ ++ NewParameter: 42, + }, -+ shouldError: false, ++ }, ++ shouldError: false, + }, ``` @@ -552,7 +543,7 @@ This test asserts that updating was successful and that no other parameter was e + require.Equal(t, expectedNewParameter, res.Params.NewParameter) + + // Ensure the other parameters are unchanged -+ testkeeper.AssertDefaultParamsEqualExceptFields(t, &defaultParams, res.Params, "MinStake") ++ testkeeper.AssertDefaultParamsEqualExceptFields(t, &defaultParams, res.Params, examplemodtypes.ParamNewParameter) + } ``` From 4c1e1a6fe024f69e6a7981be3710e76f5522c156 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Fri, 4 Oct 2024 10:43:50 +0200 Subject: [PATCH 14/21] chore: msg_server_update_param improvements: - Add logger values - Add error logs - Ensure gRPC status error returns - Fix test param field argument --- .../develop/developer_guide/adding_params.md | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index afe168646..5886d2b9f 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -224,26 +224,49 @@ Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter upd + // UpdateParam updates a single parameter in the proof module and returns + // all active parameters. + func (k msgServer) UpdateParam(ctx context.Context, msg *types.MsgUpdateParam) (*types.MsgUpdateParamResponse, error) { ++ logger := k.logger.With( ++ "method", "UpdateParam", ++ "param_name", msg.Name, ++ ) ++ + if err := msg.ValidateBasic(); err != nil { -+ return nil, err ++ return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + if k.GetAuthority() != msg.Authority { -+ return nil, types.ErrExamplemodInvalidSigner.Wrapf("invalid authority; expected %s, got %s", k.GetAuthority(), msg.Authority) ++ return nil, status.Error( ++ codes.InvalidArgument, ++ suppliertypes.ErrSupplierInvalidSigner.Wrapf( ++ "invalid authority; expected %s, got %s", ++ k.GetAuthority(), msg.Authority, ++ ).Error(), ++ ) + } + + params := k.GetParams(ctx) + + switch msg.Name { + default: -+ return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) ++ return nil, status.Error( ++ codes.InvalidArgument, ++ suppliertypes.ErrSupplierParamInvalid.Wrapf("unsupported param %q", msg.Name).Error(), ++ ) ++ } ++ ++ // Perform a global validation on all params, which includes the updated param. ++ // This is needed to ensure that the updated param is valid in the context of all other params. ++ if err := params.Validate(); err != nil { ++ return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + if err := k.SetParams(ctx, params); err != nil { -+ return nil, err ++ err = fmt.Errorf("unable to set params: %w", err) ++ logger.Error(err.Error()) ++ return nil, status.Error(codes.Internal, err.Error()) + } + + updatedParams := k.GetParams(ctx) ++ + return &types.MsgUpdateParamResponse{ + Params: &updatedParams, + }, nil @@ -437,6 +460,10 @@ Add the parameter type and name (e.g. `ParamNameNewParameter`) to new cases in t Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switch statement in `msgServer#UpdateParam()` in `x/examplemod/keeper/msg_server_update_param.go`: +:::warning +Every error return from `msgServer` methods (e.g. `#UpdateParams()`) **SHOULD** be encapsulated in a gRPC status error! +::: + ```go // UpdateParam updates a single parameter in the proof module and returns // all active parameters. @@ -447,9 +474,13 @@ Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switc // ... switch msg.Name { + case types.ParamNewParameter: ++ logger = logger.with("param_value", msg.GetAsInt64()) + params.NewParameter = msg.GetAsInt64() default: - return nil, types.ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name) + return nil, status.Error( + codes.InvalidArgument, + suppliertypes.ErrSupplierParamInvalid.Wrapf("unsupported param %q", msg.Name).Error(), + ) } // ... } @@ -543,7 +574,7 @@ This test asserts that updating was successful and that no other parameter was e + require.Equal(t, expectedNewParameter, res.Params.NewParameter) + + // Ensure the other parameters are unchanged -+ testkeeper.AssertDefaultParamsEqualExceptFields(t, &defaultParams, res.Params, examplemodtypes.ParamNewParameter) ++ testkeeper.AssertDefaultParamsEqualExceptFields(t, &defaultParams, res.Params, string(examplemodtypes.KeyNewParameter)) + } ``` From 5c995f12ea6957d57c7350f9186ff15bddcc971c Mon Sep 17 00:00:00 2001 From: Bryan White Date: Mon, 7 Oct 2024 12:21:58 +0200 Subject: [PATCH 15/21] chore: improvements --- .../develop/developer_guide/adding_params.md | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index 5886d2b9f..9aa55db6d 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -174,27 +174,28 @@ Prepare `x/examplemod/types/message_update_param.go` to handle message construct ```go - func NewMsgUpdateParam(authority string, name string, asType string) *MsgUpdateParam { -+ func NewMsgUpdateParam(authority string, name string, asType any) *MsgUpdateParam { ++ func NewMsgUpdateParam(authority string, name string, asType any) (*MsgUpdateParam, error) { + var asTypeIface isMsgUpdateParam_AsType + + switch t := asType.(type) { + default: -+ panic(fmt.Sprintf("unexpected param value type: %T", asType)) ++ return nil, ExamplemodParamInvalid.Wrapf("unexpected param value type: %T", asType) + } + return &MsgUpdateParam{ Authority: authority, Name: name, - AsType: asType, +- } + AsType: asTypeIface, - } ++ }, nil } func (msg *MsgUpdateParam) ValidateBasic() error { _, err := cosmostypes.AccAddressFromBech32(msg.Authority) if err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid authority address (%s)", err) - } + } - - return nil + @@ -275,7 +276,7 @@ Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter upd #### 0.7 Update Module's Params Test Suite `ModuleParamConfig` -Add `MsgUpdateParam` & `MsgUpdateParamResponse` to the module's `ModuleParamConfig#ParamsMsg`: +Add `MsgUpdateParam` & `MsgUpdateParamResponse` to the module's `ModuleParamConfig#ParamsMsg` in `testutil/integration/suites/param_config.go`: ```go ExamplemodModuleParamConfig = ModuleParamConfig{ @@ -416,13 +417,13 @@ Include a call to `NewParamSetPair()`, passing the parameter's key, value pointe Add the parameter type and name (e.g. `ParamNameNewParameter`) to new cases in the switch statements in `NewMsgUpdateParam()` and `MsgUpdateParam#ValidateBasic()` in `x/examplemod/types/message_update_param.go`: ```go - func NewMsgUpdateParam(authority string, name string, asType any) *MsgUpdateParam { + func NewMsgUpdateParam(authority string, name string, asType any) (*MsgUpdateParam, error) { // ... switch t := asType.(type) { + case int64: + asTypeIface = &MsgUpdateParam_AsCoin{AsInt64: t} default: - panic(fmt.Sprintf("unexpected param value type: %T", asType)) + return nil, ErrExamplemodParamInvalid.Wrapf("unexpected param value type: %T", asType)) } // ... } @@ -471,6 +472,9 @@ Every error return from `msgServer` methods (e.g. `#UpdateParams()`) **SHOULD** ctx context.Context, msg *types.MsgUpdateParam, ) (*types.MsgUpdateParamResponse, error) { + if err := msg.ValidateBasic(); err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } // ... switch msg.Name { + case types.ParamNewParameter: @@ -483,6 +487,10 @@ Every error return from `msgServer` methods (e.g. `#UpdateParams()`) **SHOULD** ) } // ... + if err := params.Validate(); err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + // ... } ``` @@ -593,7 +601,8 @@ Start with the following cases and add those which cover all invalid values for - name string + desc string msg MsgUpdateParam - err error +- err error ++ expectedErr error }{ { - name: "invalid address", @@ -603,7 +612,8 @@ Start with the following cases and add those which cover all invalid values for + Name: "", // Doesn't matter for this test + AsType: &MsgUpdateParam_AsInt64{AsInt64: 0}, }, - err: sdkerrors.ErrInvalidAddress, +- err: sdkerrors.ErrInvalidAddress, ++ expectedErr: sdkerrors.ErrInvalidAddress, + }, { + desc: "invalid: param name incorrect (non-existent)", + msg: MsgUpdateParam{ @@ -611,7 +621,7 @@ Start with the following cases and add those which cover all invalid values for + Name: "non_existent", + AsType: &MsgUpdateParam_AsInt64{AsInt64: DefaultNewParameter}, + }, -+ err: ErrExamplemodParamInvalid, ++ expectedErr: ErrExamplemodParamInvalid, }, { - name: "valid address", + desc: "valid: correct address, param name, and type", From b637856e987b6385ef025b3d5d3ea939d3afac0a Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 7 Nov 2024 14:04:38 +0100 Subject: [PATCH 16/21] fix: ToC indentation --- .../develop/developer_guide/adding_params.md | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index 9aa55db6d..4e125d9ad 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -14,28 +14,28 @@ title: Adding On-Chain Module Parameters - [0.5 Update the `NewMsgUpdateParam` Constructor and `MsgUpdateParam#ValidateBasic()`](#05-update-the-newmsgupdateparam-constructor-and-msgupdateparamvalidatebasic) - [0.6 Update the Module's `msgServer#UpdateParam()` Handler](#06-update-the-modules-msgserverupdateparam-handler) - [0.7 Update Module's Params Test Suite `ModuleParamConfig`](#07-update-modules-params-test-suite-moduleparamconfig) - - [1. Define the Parameter in the Protocol Buffers File](#1-define-the-parameter-in-the-protocol-buffers-file) - - [2. Update the Default Parameter Values](#2-update-the-default-parameter-values) - - [2.1 Go Source Defaults](#21-go-source-defaults) - - [2.2 Genesis Configuration Parameter Defaults](#22-genesis-configuration-parameter-defaults) - - [3. Parameter Validation](#3-parameter-validation) - - [3.1 Define a Validation Function](#31-define-a-validation-function) - - [3.2 Call it in the `Params#Validate()`](#32-call-it-in-the-paramsvalidate) - - [3.3 Add a `ParamSetPair` to `ParamSetPairs()`](#33-add-a-paramsetpair-to-paramsetpairs) - - [4. Add Parameter Case to Switch Statements](#4-add-parameter-case-to-switch-statements) - - [4.1 `MsgUpdateParam#ValidateBasic()`](#41-msgupdateparamvalidatebasic) - - [4.2 `msgServer#UpdateParam()`](#42-msgserverupdateparam) - - [5. Update Unit Tests](#5-update-unit-tests) - - [5.1 Parameter Validation Tests](#51-parameter-validation-tests) - - [5.2 Parameter Update Tests](#52-parameter-update-tests) - - [6. Update the Parameter Integration Tests](#6-update-the-parameter-integration-tests) - - [6.1 Add a valid param](#61-add-a-valid-param) - - [6.2 Check for `as_` on `MsgUpdateParam`](#62-check-for-as_type-on-msgupdateparam) - - [6.3 Update the module's `ModuleParamConfig`](#63-update-the-modules-moduleparamconfig) - - [7. Update the Makefile and Supporting JSON Files](#7-update-the-makefile-and-supporting-json-files) - - [7.1 Update the Makefile](#71-update-the-makefile) - - [7.2 Create a new JSON File for the Individual Parameter Update](#72-create-a-new-json-file-for-the-individual-parameter-update) - - [7.3 Update the JSON File for Updating All Parameters for the Module](#73-update-the-json-file-for-updating-all-parameters-for-the-module) + - [1. Define the Parameter in the Protocol Buffers File](#1-define-the-parameter-in-the-protocol-buffers-file) + - [2. Update the Default Parameter Values](#2-update-the-default-parameter-values) + - [2.1 Go Source Defaults](#21-go-source-defaults) + - [2.2 Genesis Configuration Parameter Defaults](#22-genesis-configuration-parameter-defaults) + - [3. Parameter Validation](#3-parameter-validation) + - [3.1 Define a Validation Function](#31-define-a-validation-function) + - [3.2 Call it in the `Params#Validate()`](#32-call-it-in-the-paramsvalidate) + - [3.3 Add a `ParamSetPair` to `ParamSetPairs()`](#33-add-a-paramsetpair-to-paramsetpairs) + - [4. Add Parameter Case to Switch Statements](#4-add-parameter-case-to-switch-statements) + - [4.1 `MsgUpdateParam#ValidateBasic()`](#41-msgupdateparamvalidatebasic) + - [4.2 `msgServer#UpdateParam()`](#42-msgserverupdateparam) + - [5. Update Unit Tests](#5-update-unit-tests) + - [5.1 Parameter Validation Tests](#51-parameter-validation-tests) + - [5.2 Parameter Update Tests](#52-parameter-update-tests) + - [6. Update the Parameter Integration Tests](#6-update-the-parameter-integration-tests) + - [6.1 Add a valid param](#61-add-a-valid-param) + - [6.2 Check for `as_` on `MsgUpdateParam`](#62-check-for-as_type-on-msgupdateparam) + - [6.3 Update the module's `ModuleParamConfig`](#63-update-the-modules-moduleparamconfig) + - [7. Update the Makefile and Supporting JSON Files](#7-update-the-makefile-and-supporting-json-files) + - [7.1 Update the Makefile](#71-update-the-makefile) + - [7.2 Create a new JSON File for the Individual Parameter Update](#72-create-a-new-json-file-for-the-individual-parameter-update) + - [7.3 Update the JSON File for Updating All Parameters for the Module](#73-update-the-json-file-for-updating-all-parameters-for-the-module) Adding a new on-chain module parameter involves multiple steps to ensure that the parameter is properly integrated into the system. This guide will walk you through From 9bce5273307e06496e24a9d36012aecad0eefafb Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 14 Nov 2024 12:11:48 +0100 Subject: [PATCH 17/21] fix: dogfooding --- .../develop/developer_guide/adding_params.md | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index 4e125d9ad..495e7bbe6 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -91,6 +91,10 @@ If you experience errors like these: go: github.com/pokt-network/poktroll/api/poktroll/examplemod imports cosmossdk.io/api/poktroll/shared: module cosmossdk.io/api@latest found (v0.7.6), but does not contain package cosmossdk.io/api/poktroll/shared ``` +```go +✘ Error while running command /home/bwhite/go/bin/buf dep update /home/bwhite/Projects/pokt/poktroll/proto: Failure: decode proto/buf.lock: no digest specified for module buf.build/cosmos/ics23 +: exit status 1 +``` Then try running `make proto_clean_pulsar`. ::: @@ -216,7 +220,7 @@ Prepare `x/examplemod/types/message_update_param.go` to handle message construct Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter updates by type: ```go -- func (k msgServer) UpdateParam(goCtx context.Context, msg *types.MsgUpdateParam) (*types.MsgUpdateParamResponse, error) { +- func (k msgServer) UpdateParam(goCtx context.Context, msg *examplemodtypes.MsgUpdateParam) (*examplemodtypes.MsgUpdateParamResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - // TODO: Handling the message @@ -224,7 +228,7 @@ Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter upd - + // UpdateParam updates a single parameter in the proof module and returns + // all active parameters. -+ func (k msgServer) UpdateParam(ctx context.Context, msg *types.MsgUpdateParam) (*types.MsgUpdateParamResponse, error) { ++ func (k msgServer) UpdateParam(ctx context.Context, msg *examplemodtypes.MsgUpdateParam) (*examplemodtypes.MsgUpdateParamResponse, error) { + logger := k.logger.With( + "method", "UpdateParam", + "param_name", msg.Name, @@ -237,7 +241,7 @@ Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter upd + if k.GetAuthority() != msg.Authority { + return nil, status.Error( + codes.InvalidArgument, -+ suppliertypes.ErrSupplierInvalidSigner.Wrapf( ++ examplemodtypes.ErrExamplemodInvalidSigner.Wrapf( + "invalid authority; expected %s, got %s", + k.GetAuthority(), msg.Authority, + ).Error(), @@ -250,7 +254,7 @@ Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter upd + default: + return nil, status.Error( + codes.InvalidArgument, -+ suppliertypes.ErrSupplierParamInvalid.Wrapf("unsupported param %q", msg.Name).Error(), ++ examplemodtypes.ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name).Error(), + ) + } + @@ -305,6 +309,10 @@ Define the new parameter in the module's `params.proto` file (e.g., `proto/poktr } ``` +:::warning +Be sure to update the `gogoproto.jsontag` and `gogoproto.moretags` option values to match the new parameter name! +::: + :::tip Don't forget to run `make proto_regen` to update generated protobuf go code. ::: @@ -436,7 +444,7 @@ Add the parameter type and name (e.g. `ParamNameNewParameter`) to new cases in t // ... switch msg.Name { + case ParamNewParameter: -+ if err := msg.paramTypeIsInt64(); err != nil { ++ if err = msg.paramTypeIsInt64(); err != nil { + return err + } + return ValidateNewParameter(msg.GetAsInt64()) @@ -470,20 +478,20 @@ Every error return from `msgServer` methods (e.g. `#UpdateParams()`) **SHOULD** // all active parameters. func (k msgServer) UpdateParam( ctx context.Context, - msg *types.MsgUpdateParam, - ) (*types.MsgUpdateParamResponse, error) { + msg *examplemodtypes.MsgUpdateParam, + ) (*examplemodtypes.MsgUpdateParamResponse, error) { if err := msg.ValidateBasic(); err != nil { return nil, status.Error(codes.InvalidArgument, err.Error()) } // ... switch msg.Name { -+ case types.ParamNewParameter: ++ case examplemodtypes.ParamNewParameter: + logger = logger.with("param_value", msg.GetAsInt64()) + params.NewParameter = msg.GetAsInt64() default: return nil, status.Error( codes.InvalidArgument, - suppliertypes.ErrSupplierParamInvalid.Wrapf("unsupported param %q", msg.Name).Error(), + examplemodtypes.ErrExamplemodParamInvalid.Wrapf("unsupported param %q", msg.Name).Error(), ) } // ... @@ -515,7 +523,7 @@ Ensure there is a test function for each parameter which covers all cases of inv + { + desc: "invalid type", + newParameter: "420", -+ expectedErr: ErrExamplemodParamInvalid.Wrapf("invalid parameter type: string"), ++ expectedErr: examplemodtypes.ErrExamplemodParamInvalid.Wrapf("invalid parameter type: string"), + }, + { + desc: "valid NewParameterName", @@ -525,7 +533,7 @@ Ensure there is a test function for each parameter which covers all cases of inv + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { -+ err := ValidateNewParameter(test.newParameter) ++ err := examplemodtypes.ValidateNewParameter(test.newParameter) + if test.expectedErr != nil { + require.Error(t, err) + require.Contains(t, err.Error(), test.expectedErr.Error()) @@ -561,11 +569,11 @@ This test asserts that updating was successful and that no other parameter was e ```go + func TestMsgUpdateParam_UpdateNewParameterOnly(t *testing.T) { -+ var expectedNewParameter uint64 = 420 ++ var expectedNewParameter int64 = 420 + + // Set the parameters to their default values + k, msgSrv, ctx := setupMsgServer(t) -+ defaultParams := prooftypes.DefaultParams() ++ defaultParams := examplemodtypes.DefaultParams() + require.NoError(t, k.SetParams(ctx, defaultParams)) + + // Ensure the default values are different from the new values we want to set @@ -575,7 +583,7 @@ This test asserts that updating was successful and that no other parameter was e + updateParamMsg := &examplemodtypes.MsgUpdateParam{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Name: examplemodtypes.ParamNewParameter, -+ AsType: &examplemodtypes.MsgUpdateParam_AsInt64{AsInt64: int64(expectedNewParameter)}, ++ AsType: &examplemodtypes.MsgUpdateParam_AsInt64{AsInt64: expectedNewParameter}, + } + res, err := msgSrv.UpdateParam(ctx, updateParamMsg) + require.NoError(t, err) @@ -648,7 +656,7 @@ Update `ModuleParamConfig#ValidParams` to include a valid and non-default value ```go ExamplemodModuleParamConfig = ModuleParamConfig{ // ... - ValidParams: gatewaytypes.Params{ + ValidParams: examplemodtypes.Params{ + NewParameter: 420, }, // ... @@ -676,11 +684,11 @@ Ensure that all available `as_` types for the module are present on the mo ```go ExamplemodModuleParamConfig = ModuleParamConfig{ // ... - ValidParams: suppliertypes.Params{}, + ValidParams: examplemodtypes.Params{}, + ParamTypes: map[ParamType]any{ -+ ParamTypeInt64: suppliertypes.MsgUpdateParam_AsInt64{}, ++ ParamTypeInt64: examplemodtypes.MsgUpdateParam_AsInt64{}, + }, - DefaultParams: suppliertypes.DefaultParams(), + DefaultParams: examplemodtypes.DefaultParams(), // ... } From 50025e648fb39281e4e24152f5cf702bede3a2fe Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 14 Nov 2024 12:21:39 +0100 Subject: [PATCH 18/21] chore: review feedback improvements Co-authored-by: red-0ne --- docusaurus/docs/develop/developer_guide/adding_params.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index 495e7bbe6..02720f427 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -55,8 +55,8 @@ https://github.com/ignite/cli/issues/3684#issuecomment-2299796210 :::warning The steps outlined below follow **the same example** where: - **Module name**: `examplemod` -- **New parameter name**: `new_param` -- **Default value**: `42` +- **New parameter name**: `new_parameter` +- **Default value**: `int64(42)` When following these steps, be sure to substitute these example values with your own! ::: @@ -134,7 +134,7 @@ Update the `MsgUpdateParamResponse` message field (`params`) in the same `tx.pro #### 0.3 Comment Out AutoCLI -When scaffolding the `MsgUpdateParam` message, lines are added to `x/examplemod/module/autocli.go`. +When scaffolding the `MsgUpdateParam` message, generated code is added to `x/examplemod/module/autocli.go`. Since governance parameters aren't updated via `poktrolld` CLI, comment out these new lines: ```go @@ -305,7 +305,7 @@ Define the new parameter in the module's `params.proto` file (e.g., `proto/poktr // Other existing parameters... + // Description of the new parameter. -+ uint64 new_parameter = 3 [(gogoproto.jsontag) = "new_parameter", (gogoproto.moretags) = "yaml:\"new_parameter\""]; ++ int64 new_parameter = 3 [(gogoproto.jsontag) = "new_parameter", (gogoproto.moretags) = "yaml:\"new_parameter\""]; } ``` From c40aaff918416789983b0fee904d47fcec928859 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Thu, 14 Nov 2024 12:24:47 +0100 Subject: [PATCH 19/21] chore: update yarn.lock --- docusaurus/yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docusaurus/yarn.lock b/docusaurus/yarn.lock index 5c2dcf935..93cee387e 100644 --- a/docusaurus/yarn.lock +++ b/docusaurus/yarn.lock @@ -1810,10 +1810,15 @@ dependencies: "@types/mdx" "^2.0.0" -"@node-rs/jieba-darwin-arm64@1.10.0": +"@node-rs/jieba-linux-x64-gnu@1.10.0": version "1.10.0" - resolved "https://registry.npmjs.org/@node-rs/jieba-darwin-arm64/-/jieba-darwin-arm64-1.10.0.tgz" - integrity sha512-IhR5r+XxFcfhVsF93zQ3uCJy8ndotRntXzoW/JCyKqOahUo/ITQRT6vTKHKMyD9xNmjl222OZonBSo2+mlI2fQ== + resolved "https://registry.npmjs.org/@node-rs/jieba-linux-x64-gnu/-/jieba-linux-x64-gnu-1.10.0.tgz" + integrity sha512-rS5Shs8JITxJjFIjoIZ5a9O+GO21TJgKu03g2qwFE3QaN5ZOvXtz+/AqqyfT4GmmMhCujD83AGqfOGXDmItF9w== + +"@node-rs/jieba-linux-x64-musl@1.10.0": + version "1.10.0" + resolved "https://registry.npmjs.org/@node-rs/jieba-linux-x64-musl/-/jieba-linux-x64-musl-1.10.0.tgz" + integrity sha512-BvSiF2rR8Birh2oEVHcYwq0WGC1cegkEdddWsPrrSmpKmukJE2zyjcxaOOggq2apb8fIRsjyeeUh6X3R5AgjvA== "@node-rs/jieba@^1.6.0": version "1.10.0" @@ -4614,11 +4619,6 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" From c9b707e0fd3b3d7f76ffbd5300d79e53f8ee57c8 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Tue, 19 Nov 2024 15:07:20 -0800 Subject: [PATCH 20/21] Minor nits --- .../develop/developer_guide/adding_params.md | 120 +++++++++--------- docusaurus/yarn.lock | 16 +-- 2 files changed, 70 insertions(+), 66 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index 02720f427..59b57d5c9 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -7,8 +7,8 @@ title: Adding On-Chain Module Parameters - [Step-by-Step Instructions](#step-by-step-instructions) - [0. If the Module Doesn't Already Support a `MsgUpdateParam` Message](#0-if-the-module-doesnt-already-support-a-msgupdateparam-message) - - [0.1 Scaffold the `MsgUpdateParam` Message](#01-scaffold-the-msgupdateparam-message) - - [0.2 Update `MsgUpdateParam` and `MsgUpdateParamResponse` Fields](#02-update-msgupdateparam-and-msgupdateparamresponse-fields) + - [0.1. Scaffold the `MsgUpdateParam` Message](#01-scaffold-the-msgupdateparam-message) + - [0.2. Update `MsgUpdateParam` and `MsgUpdateParamResponse` Fields](#02-update-msgupdateparam-and-msgupdateparamresponse-fields) - [0.3 Comment Out AutoCLI](#03-comment-out-autocli) - [0.4. Update the DAO Genesis Authorizations JSON File](#04-update-the-dao-genesis-authorizations-json-file) - [0.5 Update the `NewMsgUpdateParam` Constructor and `MsgUpdateParam#ValidateBasic()`](#05-update-the-newmsgupdateparam-constructor-and-msgupdateparamvalidatebasic) @@ -54,6 +54,7 @@ https://github.com/ignite/cli/issues/3684#issuecomment-2299796210 :::warning The steps outlined below follow **the same example** where: + - **Module name**: `examplemod` - **New parameter name**: `new_parameter` - **Default value**: `int64(42)` @@ -79,38 +80,38 @@ Additional flags are used for convenience: ignite scaffold message update-param --module examplemod --signer authority name as_type --response params ``` -:::info -If you experience errors like these: -``` +Try running `make proto_clean_pulsar` if you experience errors like these: + +```bash ✘ Error while running command /home/bwhite/go/bin/buf generate /tmp/proto-sdk2893110128/cosmos/upgrade/v1beta1/tx.proto ...: {..."message":"import \"gogoproto/gogo.proto\": file does not exist"} : exit status 100 ``` -``` -✘ Error while running command go mod tidy: go: -... -go: github.com/pokt-network/poktroll/api/poktroll/examplemod imports + +```bash +✘ Error while running command go mod tidy: go: +... +go: github.com/pokt-network/poktroll/api/poktroll/examplemod imports cosmossdk.io/api/poktroll/shared: module cosmossdk.io/api@latest found (v0.7.6), but does not contain package cosmossdk.io/api/poktroll/shared ``` -```go + +```bash ✘ Error while running command /home/bwhite/go/bin/buf dep update /home/bwhite/Projects/pokt/poktroll/proto: Failure: decode proto/buf.lock: no digest specified for module buf.build/cosmos/ics23 : exit status 1 ``` -Then try running `make proto_clean_pulsar`. -::: #### 0.2. Update `MsgUpdateParam` and `MsgUpdateParamResponse` Fields Update the `MsgUpdateParam` message fields in the module's `tx.proto` file (e.g. `proto/poktroll/examplemod/tx.proto`) to include the following comments and protobuf options: -```protobuf +```diff + // MsgUpdateParam is the Msg/UpdateParam request type to update a single param. message MsgUpdateParam { option (cosmos.msg.v1.signer) = "authority"; - string authority = 1; -+ ++ + // authority is the address that controls the module (defaults to x/gov unless overwritten). + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; -+ ++ string name = 2; - string asType = 3; + oneof as_type { @@ -120,12 +121,13 @@ Update the `MsgUpdateParam` message fields in the module's `tx.proto` file (e.g. + // cosmos.base.v1beta1.Coin as_coin = 5 [(gogoproto.jsontag) = "as_coin"]; + } } - + message MsgUpdateParamResponse { ``` Update the `MsgUpdateParamResponse` message field (`params`) in the same `tx.proto` file: -```protobuf + +```diff message MsgUpdateParamResponse { - string params = 1; + Params params = 1; @@ -137,19 +139,19 @@ Update the `MsgUpdateParamResponse` message field (`params`) in the same `tx.pro When scaffolding the `MsgUpdateParam` message, generated code is added to `x/examplemod/module/autocli.go`. Since governance parameters aren't updated via `poktrolld` CLI, comment out these new lines: -```go +```diff // ... Tx: &autocliv1.ServiceCommandDescriptor{ Service: modulev1.Msg_ServiceDesc.ServiceName, EnhanceCustomCommand: true, // only required if you want to use the custom command RpcCommandOptions: []*autocliv1.RpcCommandOptions{ // ... -+ // { -+ // RpcMethod: "UpdateParam", -+ // Use: "update-param [name] [as-type]", -+ // Short: "Send a update-param tx", -+ // PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "name"}, {ProtoField: "asType"}}, -+ // }, ++ // { ++ // RpcMethod: "UpdateParam", ++ // Use: "update-param [name] [as-type]", ++ // Short: "Send a update-param tx", ++ / PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "name"}, {ProtoField: "asType"}}, ++ // }, // this line is used by ignite scaffolding # autocli/tx }, }, @@ -160,7 +162,7 @@ Since governance parameters aren't updated via `poktrolld` CLI, comment out thes Add a grant (array element) to `tools/scripts/authz/dao_genesis_authorizations.json` with the `authorization.msg` typeURL for this module's `MsgUpdateType`: -```json +```diff + { + "granter": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", + "grantee": "pokt1eeeksh2tvkh7wzmfrljnhw4wrhs55lcuvmekkw", @@ -176,7 +178,7 @@ Add a grant (array element) to `tools/scripts/authz/dao_genesis_authorizations.j Prepare `x/examplemod/types/message_update_param.go` to handle message construction and parameter validations by type: -```go +```diff - func NewMsgUpdateParam(authority string, name string, asType string) *MsgUpdateParam { + func NewMsgUpdateParam(authority string, name string, asType any) (*MsgUpdateParam, error) { + var asTypeIface isMsgUpdateParam_AsType @@ -215,11 +217,12 @@ Prepare `x/examplemod/types/message_update_param.go` to handle message construct + } } ``` + #### 0.6 Update the Module's `msgServer#UpdateParam()` Handler Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter updates by type: -```go +```diff - func (k msgServer) UpdateParam(goCtx context.Context, msg *examplemodtypes.MsgUpdateParam) (*examplemodtypes.MsgUpdateParamResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - @@ -282,7 +285,7 @@ Prepare `x/examplemod/keeper/msg_server_update_param.go` to handle parameter upd Add `MsgUpdateParam` & `MsgUpdateParamResponse` to the module's `ModuleParamConfig#ParamsMsg` in `testutil/integration/suites/param_config.go`: -```go +```diff ExamplemodModuleParamConfig = ModuleParamConfig{ ParamsMsgs: ModuleParamsMessages{ MsgUpdateParams: gatewaytypes.MsgUpdateParams{}, @@ -300,10 +303,10 @@ Add `MsgUpdateParam` & `MsgUpdateParamResponse` to the module's `ModuleParamConf Define the new parameter in the module's `params.proto` file (e.g., `proto/poktroll/examplemod/params.proto`): -```protobuf +```diff message Params { // Other existing parameters... - + + // Description of the new parameter. + int64 new_parameter = 3 [(gogoproto.jsontag) = "new_parameter", (gogoproto.moretags) = "yaml:\"new_parameter\""]; } @@ -325,15 +328,15 @@ In the corresponding Go file (e.g., `x/examplemod/types/params.go`), define the value, key, and parameter name for the new parameter and include the default in the `NewParams` and `DefaultParams` functions: -```go +```diff var ( // Other existing parameter keys, names, and defaults... - + + KeyNewParameter = []byte("NewParameter") + ParamNewParameter = "new_parameter" + DefaultNewParameter int64 = 42 ) - + func NewParams( // Other existing parameters... + newParameter int64, @@ -343,7 +346,7 @@ value, key, and parameter name for the new parameter and include the default in + NewParameter: newParameter, } } - + func DefaultParams() Params { return NewParams( // Other existing default parameters... @@ -356,12 +359,12 @@ value, key, and parameter name for the new parameter and include the default in Add the new parameter to the genesis configuration file (e.g., `config.yml`): -```yaml +```diff genesis: examplemod: params: # Other existing parameters... - + + new_parameter: 42 ``` @@ -371,7 +374,7 @@ Add the new parameter to the genesis configuration file (e.g., `config.yml`): Implement a validation function for the new parameter in `x/examplemod/types/params.go`: -```go +```diff + // ValidateNewParameter validates the NewParameter param. + func ValidateNewParameter(newParamAny any) error { + newParam, ok := newParamAny.(int64) @@ -390,7 +393,7 @@ Implement a validation function for the new parameter in `x/examplemod/types/par Integrate the usage of the new `ValidateNewParameter` function in the corresponding `Params#Validate()` function where this is used: -```go +```diff func (params *Params) Validate() error { // ... + if err := ValidateNewParameter(params.NewParameter); err != nil { @@ -404,11 +407,11 @@ Integrate the usage of the new `ValidateNewParameter` function in the correspond Include a call to `NewParamSetPair()`, passing the parameter's key, value pointer, and validation function in the `ParamSetPairs` function return: -```go +```diff func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { return paramtypes.ParamSetPairs{ // Other existing param set pairs... - + + paramtypes.NewParamSetPair( + KeyNewParameter, + &p.NewParameter, @@ -424,7 +427,7 @@ Include a call to `NewParamSetPair()`, passing the parameter's key, value pointe Add the parameter type and name (e.g. `ParamNameNewParameter`) to new cases in the switch statements in `NewMsgUpdateParam()` and `MsgUpdateParam#ValidateBasic()` in `x/examplemod/types/message_update_param.go`: -```go +```diff func NewMsgUpdateParam(authority string, name string, asType any) (*MsgUpdateParam, error) { // ... switch t := asType.(type) { @@ -473,7 +476,7 @@ Add the parameter name (e.g. `ParamNameNewParameter`) to a new case in the switc Every error return from `msgServer` methods (e.g. `#UpdateParams()`) **SHOULD** be encapsulated in a gRPC status error! ::: -```go +```diff // UpdateParam updates a single parameter in the proof module and returns // all active parameters. func (k msgServer) UpdateParam( @@ -481,7 +484,7 @@ Every error return from `msgServer` methods (e.g. `#UpdateParams()`) **SHOULD** msg *examplemodtypes.MsgUpdateParam, ) (*examplemodtypes.MsgUpdateParamResponse, error) { if err := msg.ValidateBasic(); err != nil { - return nil, status.Error(codes.InvalidArgument, err.Error()) + return nil, status.Error(codes.InvalidArgument, err.Error()) } // ... switch msg.Name { @@ -509,11 +512,11 @@ Every error return from `msgServer` methods (e.g. `#UpdateParams()`) **SHOULD** Add unit tests which exercise validation of the new parameter(s) in `x/examplemod/keeper/params_test.go`. Ensure there is a test function for each parameter which covers all cases of invalid input: -```go +```diff func TestGetParams(t *testing.T) { // ... } - + + func TestParams_ValidateNewParameter(t *testing.T) { + tests := []struct { + desc string @@ -530,7 +533,7 @@ Ensure there is a test function for each parameter which covers all cases of inv + newParameter: int64(420), + }, + } -+ ++ + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + err := examplemodtypes.ValidateNewParameter(test.newParameter) @@ -557,7 +560,7 @@ If one already exist, update it if applicable; e.g.: + input: &examplemodtypes.MsgUpdateParams{ + Authority: k.GetAuthority(), + Params: examplemodtypes.Params{ -+ NewParameter: 42, ++ NewParameter: 42, + }, + }, + shouldError: false, @@ -570,15 +573,15 @@ This test asserts that updating was successful and that no other parameter was e ```go + func TestMsgUpdateParam_UpdateNewParameterOnly(t *testing.T) { + var expectedNewParameter int64 = 420 -+ ++ + // Set the parameters to their default values + k, msgSrv, ctx := setupMsgServer(t) + defaultParams := examplemodtypes.DefaultParams() + require.NoError(t, k.SetParams(ctx, defaultParams)) -+ ++ + // Ensure the default values are different from the new values we want to set + require.NotEqual(t, expectedNewParameter, defaultParams.NewParameter) -+ ++ + // Update the new parameter + updateParamMsg := &examplemodtypes.MsgUpdateParam{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), @@ -596,14 +599,16 @@ This test asserts that updating was successful and that no other parameter was e :::warning If creating `msg_server_update_param_test.go`, be sure to: + 1. use the `keeper_test` package (i.e. `package keeper_test`). 2. add the testutil keeper import: `testkeeper "github.com/pokt-network/poktroll/testutil/keeper"` + ::: Update `x/examplemod/types/message_update_param_test.go` to use the new `MsgUpdateParam#AsType` fields. Start with the following cases and add those which cover all invalid values for the new param (and its `AsType`; e.g. `AsCoin` cannot be nil): -```go +```diff func TestMsgUpdateParam_ValidateBasic(t *testing.T) { tests := []struct { - name string @@ -644,7 +649,7 @@ Start with the following cases and add those which cover all invalid values for } ``` -### 6. Update the Parameter Integration Tests +### 6. Update the Parameter Integration Tests Integration tests which cover parameter updates utilize the `ModuleParamConfig`s defined in [`testutil/integration/params/param_configs.go`](https://github.com/pokt-network/poktroll/blob/main/testutil/integration/suites/param_configs.go) to dynamically (i.e. using reflection) construct and send parameter update messages in a test environment. When adding parameters to a module, it is necessary to update that module's `ModuleParamConfig` to include the new parameter, othwerwise it will not be covered by the integration test suite. @@ -653,7 +658,7 @@ When adding parameters to a module, it is necessary to update that module's `Mod Update `ModuleParamConfig#ValidParams` to include a valid and non-default value for the new parameter in the module's `tx.proto` file (e.g. `proto/poktroll/examplemod/tx.proto`): -```go +```diff ExamplemodModuleParamConfig = ModuleParamConfig{ // ... ValidParams: examplemodtypes.Params{ @@ -667,7 +672,7 @@ Update `ModuleParamConfig#ValidParams` to include a valid and non-default value Ensure an `as_` field exists on `MsgUpdateParam` corresponding to the type of the new parameter (`proto/poktroll/examplemod/tx.proto`): -```proto +```diff message MsgUpdateParam { ... oneof as_type { @@ -681,7 +686,7 @@ Ensure an `as_` field exists on `MsgUpdateParam` corresponding to the type Ensure that all available `as_` types for the module are present on the module's `ModuleParamConfig#ParamTypes` field: -```go +```diff ExamplemodModuleParamConfig = ModuleParamConfig{ // ... ValidParams: examplemodtypes.Params{}, @@ -691,7 +696,6 @@ Ensure that all available `as_` types for the module are present on the mo DefaultParams: examplemodtypes.DefaultParams(), // ... } - ``` ### 7. Update the Makefile and Supporting JSON Files @@ -722,7 +726,7 @@ Create a new JSON file (e.g., `proof_new_parameter_name.json`) in the tools/scri "@type": "/poktroll.examplemod.MsgUpdateParam", // Replace module name "authority": "pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t", "name": "new_parameter", // Replace new parameter name - "as_int64": "42" // Replace default value + "as_int64": "42" // Replace default value } ] } @@ -734,7 +738,7 @@ Create a new JSON file (e.g., `proof_new_parameter_name.json`) in the tools/scri Add a line to the existing module's `MsgUpdateParam` JSON file (e.g., `proof_all.json`) with the default value for the new parameter. -```json +```diff { "body": { "messages": [ diff --git a/docusaurus/yarn.lock b/docusaurus/yarn.lock index 93cee387e..5c2dcf935 100644 --- a/docusaurus/yarn.lock +++ b/docusaurus/yarn.lock @@ -1810,15 +1810,10 @@ dependencies: "@types/mdx" "^2.0.0" -"@node-rs/jieba-linux-x64-gnu@1.10.0": +"@node-rs/jieba-darwin-arm64@1.10.0": version "1.10.0" - resolved "https://registry.npmjs.org/@node-rs/jieba-linux-x64-gnu/-/jieba-linux-x64-gnu-1.10.0.tgz" - integrity sha512-rS5Shs8JITxJjFIjoIZ5a9O+GO21TJgKu03g2qwFE3QaN5ZOvXtz+/AqqyfT4GmmMhCujD83AGqfOGXDmItF9w== - -"@node-rs/jieba-linux-x64-musl@1.10.0": - version "1.10.0" - resolved "https://registry.npmjs.org/@node-rs/jieba-linux-x64-musl/-/jieba-linux-x64-musl-1.10.0.tgz" - integrity sha512-BvSiF2rR8Birh2oEVHcYwq0WGC1cegkEdddWsPrrSmpKmukJE2zyjcxaOOggq2apb8fIRsjyeeUh6X3R5AgjvA== + resolved "https://registry.npmjs.org/@node-rs/jieba-darwin-arm64/-/jieba-darwin-arm64-1.10.0.tgz" + integrity sha512-IhR5r+XxFcfhVsF93zQ3uCJy8ndotRntXzoW/JCyKqOahUo/ITQRT6vTKHKMyD9xNmjl222OZonBSo2+mlI2fQ== "@node-rs/jieba@^1.6.0": version "1.10.0" @@ -4619,6 +4614,11 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" From f6a6f9dd9b82ec9f845f7e91d6a730b7e357ac24 Mon Sep 17 00:00:00 2001 From: Bryan White Date: Wed, 20 Nov 2024 14:49:04 +0100 Subject: [PATCH 21/21] docs: update 4.1 --- .../docs/develop/developer_guide/adding_params.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docusaurus/docs/develop/developer_guide/adding_params.md b/docusaurus/docs/develop/developer_guide/adding_params.md index 59b57d5c9..48de66434 100644 --- a/docusaurus/docs/develop/developer_guide/adding_params.md +++ b/docusaurus/docs/develop/developer_guide/adding_params.md @@ -447,7 +447,7 @@ Add the parameter type and name (e.g. `ParamNameNewParameter`) to new cases in t // ... switch msg.Name { + case ParamNewParameter: -+ if err = msg.paramTypeIsInt64(); err != nil { ++ if err := genericParamTypeIs[*MsgUpdateParam_AsInt64](msg); err != nil { + return err + } + return ValidateNewParameter(msg.GetAsInt64()) @@ -456,16 +456,17 @@ Add the parameter type and name (e.g. `ParamNameNewParameter`) to new cases in t } } + -+ func (msg *MsgUpdateParam) paramTypeIsInt64() error { -+ if _, ok := msg.AsType.(*MsgUpdateParam_AsInt64); !ok { -+ return ErrExamplemodParamInvalid.Wrapf( -+ "invalid type for param %q expected %T, got: %T", -+ msg.Name, &MsgUpdateParam_AsInt64{}, msg.AsType, ++ func genericParamTypeIs[T any](msg *MsgUpdateParam) error { ++ if _, ok := msg.AsType.(T); !ok { ++ return ErrParamInvalid.Wrapf( ++ "invalid type for param %q; expected %T, got %T", ++ msg.Name, *new(T), msg.AsType, + ) + } + + return nil + } + ``` #### 4.2 `msgServer#UpdateParam()`