Skip to content

Commit

Permalink
chore: review improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
bryanchriswhite committed May 10, 2024
1 parent 009e2d3 commit 65819f0
Show file tree
Hide file tree
Showing 11 changed files with 509 additions and 393 deletions.
2 changes: 1 addition & 1 deletion e2e/tests/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ type suite struct {
granteeName string

// moduleParamsMap is a map of module names to a map of parameter names to parameter values & types.
expectedModuleParamsMap map[string]map[string]anyMap
expectedModuleParams moduleParamsMap
}

func (s *suite) Before() {
Expand Down
123 changes: 123 additions & 0 deletions e2e/tests/params_tx_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package e2e

import (
"fmt"
"os"
"text/template"
"time"

"github.com/cometbft/cometbft/libs/cli"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/types/tx"
"github.com/stretchr/testify/require"
)

// updateParamsTxJSONTemplate is a text template for a tx JSON file which is
// intended to be used with the `authz exec` CLI subcommand: `poktrolld tx authz exec <tx_json_file>`.
var updateParamsTxJSONTemplate = template.Must(
template.New("txJSON").Parse(`{ "body": {{.}} }`),
)

// sendAuthzExecTx sends an authz exec tx using the `authz exec` CLI subcommand:
// `poktrolld tx authz exec <tx_json_file>`.
// It returns before the tx has been committed but after it has been broadcast.
// It ensures that all module params are reset to their default values after the
// test completes.
func (s *suite) sendAuthzExecTx(txJSONFilePath string) {
argsAndFlags := []string{
"tx", "authz", "exec",
txJSONFilePath,
"--from", s.granteeName,
keyRingFlag,
fmt.Sprintf("--%s=json", cli.OutputFlag),
"--yes",
}
_, err := s.pocketd.RunCommandOnHost("", argsAndFlags...)
require.NoError(s, err)

// TODO_IMPROVE: wait for the tx to be committed using an events query client
// instead of sleeping for a specific amount of time.
s.Logf("waiting %d seconds for the tx to be committed...", txDelaySeconds)
time.Sleep(txDelaySeconds * time.Second)

// Reset all module params to their default values after the test completes.
s.once.Do(func() {
s.Cleanup(func() { s.resetAllModuleParamsToDefaults() })
})
}

// newTempTxJSONFile creates a new temp file with the JSON representation of a tx
// which contains a MsgUpdateParams for each module and paramsMap in the given moduleParamsMap.
// It is intended for use with the `authz exec` CLI subcommand: `poktrolld tx authz exec <tx_json_file>`.
// It returns the file path.
func (s *suite) newTempUpdateParamsTxJSONFile(moduleParamsMap moduleParamsMap) *os.File {
var anyMsgs []*types.Any

for moduleName, paramsMap := range moduleParamsMap {
// Convert the params map to a MsgUpdateParams message.
msg := s.paramsMapToMsgUpdateParams(moduleName, paramsMap)

// Convert the MsgUpdateParams message to a pb.Any message.
anyMsg, err := types.NewAnyWithValue(msg)
require.NoError(s, err)

anyMsgs = append(anyMsgs, anyMsg)
}

return s.newTempTxJSONFile(anyMsgs)
}

// newTempUpdateParamTxJSONFile creates a new temp file with the JSON representation of a tx,
// intended for use with the `authz exec` CLI subcommand: `poktrolld tx authz exec <tx_json_file>`.
// It returns the file path.
func (s *suite) newTempUpdateParamTxJSONFile(moduleParams moduleParamsMap) *os.File {
var anyMsgs []*types.Any

for moduleName, paramsMap := range moduleParams {
for _, param := range paramsMap {
// Convert the params map to a MsgUpdateParams message.
msg := s.newMsgUpdateParam(moduleName, param)

// Convert the MsgUpdateParams message to a pb.Any message.
anyMsg, err := types.NewAnyWithValue(msg)
require.NoError(s, err)

anyMsgs = append(anyMsgs, anyMsg)
}
}

return s.newTempTxJSONFile(anyMsgs)
}

// newTempTxJSONFile creates & returns a new temp file with the JSON representation
// of a tx which contains the given pb.Any messages. The temp file is removed when
// the test completes.
func (s *suite) newTempTxJSONFile(anyMsgs []*types.Any) *os.File {
// Construct a TxBody with the pb.Any message for serialization.
txBody := &tx.TxBody{
Messages: anyMsgs,
}

// Serialize txBody to JSON for interpolation into the tx JSON template.
txBodyJSON, err := s.cdc.MarshalJSON(txBody)
require.NoError(s, err)

// Create a temporary file to write the interpolated tx JSON.
tempFile, err := os.CreateTemp("", "exec.json")
require.NoError(s, err)

defer func(f *os.File) {
_ = f.Close()
}(tempFile)

// Remove tempFile when the test completes.
s.Cleanup(func() {
_ = os.Remove(tempFile.Name())
})

// Interpolate txBodyJSON into the tx JSON template.
err = updateParamsTxJSONTemplate.Execute(tempFile, string(txBodyJSON))
require.NoError(s, err)

return tempFile
}
41 changes: 41 additions & 0 deletions e2e/tests/params_types_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package e2e

const (
computeUnitsToTokensMultipler = "compute_units_to_tokens_multiplier"
minRelayDifficultyBits = "min_relay_difficulty_bits"
)

type (
// moduleNameKey is the key for a module name in the module params map.
moduleNameKey = string
// paramNameKey is the key for a param name in the params map.
paramNameKey = string
)

// paramsMap is a map of param names to param values.
type paramsMap map[paramNameKey]paramAny

// moduleParamsMap is a map of module names to params maps.
type moduleParamsMap map[moduleNameKey]paramsMap

// paramAny is a struct that holds a param type and a param value.
type paramAny struct {
name string
typeStr string
value any
}

// authzCLIGrantResponse is the JSON response struct for the authz grants query
// CLI subcommand: `poktrolld query authz grants <granter_addr> <grantee_addr>`.
// NB: `authz.QueryGrantsResponse` is not used because it seems to be incompatible
// with the JSON response format of the authz CLI query subcommand.
type authzCLIGrantResponse struct {
Grants []struct {
Authorization struct {
Type string `json:"type"`
Value struct {
Msg string `json:"msg"`
} `json:"value"`
} `json:"authorization"`
} `json:"grants"`
}
177 changes: 177 additions & 0 deletions e2e/tests/parse_params_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package e2e

import (
"fmt"

cosmostypes "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/gogoproto/proto"
"github.com/regen-network/gocuke"

prooftypes "github.com/pokt-network/poktroll/x/proof/types"
tokenomicstypes "github.com/pokt-network/poktroll/x/tokenomics/types"
)

const (
paramNameColIdx = iota
paramValueColIdx
paramTypeColIdx
)

// parseParamsTable parses a gocuke.DataTable into a paramsMap.
func (s *suite) parseParamsTable(table gocuke.DataTable) paramsMap {
paramsMap := make(paramsMap)

// NB: skip the header row.
for rowIdx := 1; rowIdx < table.NumRows(); rowIdx++ {
param := s.parseParam(table, rowIdx)
paramsMap[param.name] = param
}

return paramsMap
}

// parseParam parses a row of a gocuke.DataTable into a paramName and a paramAny.
func (s *suite) parseParam(table gocuke.DataTable, rowIdx int) paramAny {
var paramValue any
paramName := table.Cell(rowIdx, paramNameColIdx).String()
paramType := table.Cell(rowIdx, paramTypeColIdx).String()

switch paramType {
case "string":
paramValue = table.Cell(rowIdx, paramValueColIdx).String()
case "int64":
paramValue = table.Cell(rowIdx, paramValueColIdx).Int64()
case "bytes":
paramValue = []byte(table.Cell(rowIdx, paramValueColIdx).String())
default:
s.Fatalf("unexpected param type %q", paramType)
}

return paramAny{
name: paramName,
typeStr: paramType,
value: paramValue,
}
}

// paramsMapToMsgUpdateParams converts a paramsMap into a MsgUpdateParams, which
// it returns as a proto.Message/cosmostypes.Msg interface type.
func (s *suite) paramsMapToMsgUpdateParams(moduleName string, paramsMap paramsMap) (msg cosmostypes.Msg) {
authority := authtypes.NewModuleAddress(s.granterName).String()

switch moduleName {
case tokenomicstypes.ModuleName:
msgUpdateParams := &tokenomicstypes.MsgUpdateParams{
Authority: authority,
Params: tokenomicstypes.Params{},
}

for paramName, paramValue := range paramsMap {
switch paramName {
case "compute_units_to_tokens_multiplier":
msgUpdateParams.Params.ComputeUnitsToTokensMultiplier = uint64(paramValue.value.(int64))
default:
s.Fatalf("unexpected %q type param name %q", paramValue.typeStr, paramName)
}
}
msg = proto.Message(msgUpdateParams)

case prooftypes.ModuleName:
msgUpdateParams := &prooftypes.MsgUpdateParams{
Authority: authority,
Params: prooftypes.Params{},
}

for paramName, paramValue := range paramsMap {
s.Logf("paramName: %s, value: %v", paramName, paramValue.value)
switch paramName {
case "min_relay_difficulty_bits":
msgUpdateParams.Params.MinRelayDifficultyBits = uint64(paramValue.value.(int64))
default:
s.Fatalf("unexpected %q type param name %q", paramValue.typeStr, paramName)
}
}
msg = proto.Message(msgUpdateParams)

default:
err := fmt.Errorf("unexpected module name %q", moduleName)
s.Fatal(err)
panic(err)
}

return msg
}

// newMsgUpdateParam returns a MsgUpdateParam for the given module name, param name,
// and param type/value.
func (s *suite) newMsgUpdateParam(
moduleName string,
param paramAny,
) (msg cosmostypes.Msg) {
authority := authtypes.NewModuleAddress(s.granterName).String()

// TODO_IMPROVE: can this be simplified?
switch moduleName {
case tokenomicstypes.ModuleName:
switch param.typeStr {
case "string":
msg = proto.Message(&tokenomicstypes.MsgUpdateParam{
Authority: authority,
Name: param.name,
AsType: &tokenomicstypes.MsgUpdateParam_AsString{
AsString: param.value.(string),
},
})
case "int64":
msg = proto.Message(&tokenomicstypes.MsgUpdateParam{
Authority: authority,
Name: param.name,
AsType: &tokenomicstypes.MsgUpdateParam_AsInt64{
AsInt64: param.value.(int64),
},
})
case "bytes":
msg = proto.Message(&tokenomicstypes.MsgUpdateParam{
Authority: authority,
Name: param.name,
AsType: &tokenomicstypes.MsgUpdateParam_AsBytes{
AsBytes: param.value.([]byte),
},
})
}
case prooftypes.ModuleName:
switch param.typeStr {
case "string":
msg = proto.Message(&prooftypes.MsgUpdateParam{
Authority: authority,
Name: param.name,
AsType: &prooftypes.MsgUpdateParam_AsString{
AsString: param.value.(string),
},
})
case "int64":
msg = proto.Message(&prooftypes.MsgUpdateParam{
Authority: authority,
Name: param.name,
AsType: &prooftypes.MsgUpdateParam_AsInt64{
AsInt64: param.value.(int64),
},
})
case "bytes":
msg = proto.Message(&prooftypes.MsgUpdateParam{
Authority: authority,
Name: param.name,
AsType: &prooftypes.MsgUpdateParam_AsBytes{
AsBytes: param.value.([]byte),
},
})
}
default:
err := fmt.Errorf("unexpected module name %q", moduleName)
s.Fatal(err)
panic(err)
}

return msg
}
Loading

0 comments on commit 65819f0

Please sign in to comment.