Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Testing] Fix non-idempotency in (and speed up) supplier staking tests #815

Merged
merged 18 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -268,3 +268,6 @@ genesis:
claim_window_close_offset_blocks: 4
proof_window_open_offset_blocks: 0
proof_window_close_offset_blocks: 4
supplier_unbonding_period_sessions: 1
application_unbonding_period_sessions: 1
compute_units_to_tokens_multiplier: 42
6 changes: 3 additions & 3 deletions e2e/tests/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import (
prooftypes "github.com/pokt-network/poktroll/x/proof/types"
servicetypes "github.com/pokt-network/poktroll/x/service/types"
sessiontypes "github.com/pokt-network/poktroll/x/session/types"
shared "github.com/pokt-network/poktroll/x/shared"
"github.com/pokt-network/poktroll/x/shared"
sharedtypes "github.com/pokt-network/poktroll/x/shared/types"
suppliertypes "github.com/pokt-network/poktroll/x/supplier/types"
)
Expand Down Expand Up @@ -740,8 +740,8 @@ func (s *suite) getSupplierUnbondingHeight(accName string) int64 {
var resp sharedtypes.QueryParamsResponse
responseBz := []byte(strings.TrimSpace(res.Stdout))
s.cdc.MustUnmarshalJSON(responseBz, &resp)
unbondingHeight := shared.GetSupplierUnbondingHeight(&resp.Params, supplier)
return unbondingHeight

return shared.GetSupplierUnbondingHeight(&resp.Params, supplier)
}

// getApplicationInfo returns the application information for a given application address.
Expand Down
4 changes: 2 additions & 2 deletions e2e/tests/params_tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (s *suite) sendAuthzExecTx(signingKeyName, txJSONFilePath string) {
}

// newTempUpdateParamsTxJSONFile creates & returns a new temp file with the JSON representation of a tx
// which contains a MsgUpdateParams to update **all module params** for each module & paramsMap
// which contains a MsgUpdateParams to update **all module params** for each module & paramsAnyMap
// in the given moduleParamsMap. The returned file is intended for use with the `authz exec` CLI
// subcommand: `poktrolld tx authz exec <tx_json_file>`.
func (s *suite) newTempUpdateParamsTxJSONFile(moduleParams moduleParamsMap) *os.File {
Expand All @@ -76,7 +76,7 @@ func (s *suite) newTempUpdateParamsTxJSONFile(moduleParams moduleParamsMap) *os.
}

// newTempUpdateParamTxJSONFile creates & returns a new temp file with the JSON representation of a tx
// which contains a MsgUpdateParam to update params **individually** for each module & paramsMap in the
// which contains a MsgUpdateParam to update params **individually** for each module & paramsAnyMap in the
// given moduleParamsMap. The returned file is intended for use with the `authz exec` CLI subcommand:
// `poktrolld tx authz exec <tx_json_file>`.
func (s *suite) newTempUpdateParamTxJSONFile(moduleParams moduleParamsMap) *os.File {
Expand Down
6 changes: 3 additions & 3 deletions e2e/tests/params_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ type (
paramNameKey = string
)

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

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

// paramAny is a struct that holds a param type and a param value.
type paramAny struct {
Expand Down
20 changes: 10 additions & 10 deletions e2e/tests/parse_params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ const (
paramTypeColIdx
)

// parseParamsTable parses a gocuke.DataTable into a paramsMap.
func (s *suite) parseParamsTable(table gocuke.DataTable) paramsMap {
// parseParamsTable parses a gocuke.DataTable into a paramsAnyMap.
func (s *suite) parseParamsTable(table gocuke.DataTable) paramsAnyMap {
s.Helper()

paramsMap := make(paramsMap)
paramsMap := make(paramsAnyMap)

// NB: skip the header row.
for rowIdx := 1; rowIdx < table.NumRows(); rowIdx++ {
Expand Down Expand Up @@ -78,9 +78,9 @@ func (s *suite) parseParam(table gocuke.DataTable, rowIdx int) paramAny {
}
}

// paramsMapToMsgUpdateParams converts a paramsMap into a MsgUpdateParams, which
// paramsMapToMsgUpdateParams converts a paramsAnyMap into a MsgUpdateParams, which
// it returns as a proto.Message/cosmostypes.Msg interface type.
func (s *suite) paramsMapToMsgUpdateParams(moduleName string, paramsMap paramsMap) (msgUpdateParams cosmostypes.Msg) {
func (s *suite) paramsMapToMsgUpdateParams(moduleName string, paramsMap paramsAnyMap) (msgUpdateParams cosmostypes.Msg) {
s.Helper()

switch moduleName {
Expand All @@ -104,7 +104,7 @@ func (s *suite) paramsMapToMsgUpdateParams(moduleName string, paramsMap paramsMa
return msgUpdateParams
}

func (s *suite) newTokenomicsMsgUpdateParams(params paramsMap) cosmostypes.Msg {
func (s *suite) newTokenomicsMsgUpdateParams(params paramsAnyMap) cosmostypes.Msg {
authority := authtypes.NewModuleAddress(s.granterName).String()

msgUpdateParams := &tokenomicstypes.MsgUpdateParams{
Expand All @@ -121,7 +121,7 @@ func (s *suite) newTokenomicsMsgUpdateParams(params paramsMap) cosmostypes.Msg {
return proto.Message(msgUpdateParams)
}

func (s *suite) newProofMsgUpdateParams(params paramsMap) cosmostypes.Msg {
func (s *suite) newProofMsgUpdateParams(params paramsAnyMap) cosmostypes.Msg {
authority := authtypes.NewModuleAddress(s.granterName).String()

msgUpdateParams := &prooftypes.MsgUpdateParams{
Expand All @@ -148,7 +148,7 @@ func (s *suite) newProofMsgUpdateParams(params paramsMap) cosmostypes.Msg {
return proto.Message(msgUpdateParams)
}

func (s *suite) newSharedMsgUpdateParams(params paramsMap) cosmostypes.Msg {
func (s *suite) newSharedMsgUpdateParams(params paramsAnyMap) cosmostypes.Msg {
authority := authtypes.NewModuleAddress(s.granterName).String()

msgUpdateParams := &sharedtypes.MsgUpdateParams{
Expand Down Expand Up @@ -183,7 +183,7 @@ func (s *suite) newSharedMsgUpdateParams(params paramsMap) cosmostypes.Msg {
return proto.Message(msgUpdateParams)
}

func (s *suite) newAppMsgUpdateParams(params paramsMap) cosmostypes.Msg {
func (s *suite) newAppMsgUpdateParams(params paramsAnyMap) cosmostypes.Msg {
authority := authtypes.NewModuleAddress(s.granterName).String()

msgUpdateParams := &apptypes.MsgUpdateParams{
Expand All @@ -203,7 +203,7 @@ func (s *suite) newAppMsgUpdateParams(params paramsMap) cosmostypes.Msg {
return proto.Message(msgUpdateParams)
}

func (s *suite) newServiceMsgUpdateParams(params paramsMap) cosmostypes.Msg {
func (s *suite) newServiceMsgUpdateParams(params paramsAnyMap) cosmostypes.Msg {
authority := authtypes.NewModuleAddress(s.granterName).String()

msgUpdateParams := &servicetypes.MsgUpdateParams{
Expand Down
9 changes: 8 additions & 1 deletion e2e/tests/stake_supplier.feature
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Feature: Stake Supplier Namespace

Scenario: User can stake and unstake a Supplier waiting for it to unbound
Scenario: User can stake a Supplier
Given the user has the pocketd binary installed
And the user verifies the "supplier" for account "supplier2" is not staked
And the account "supplier2" has a balance greater than "1000070" uPOKT
Expand All @@ -14,6 +14,8 @@ Feature: Stake Supplier Namespace

Scenario: User can unstake a Supplier
Given the user has the pocketd binary installed
# Reduce the application unbonding period to avoid timeouts and speed up scenarios.
And the "supplier" unbonding period param is successfully set to "1" sessions of "2" blocks
bryanchriswhite marked this conversation as resolved.
Show resolved Hide resolved
And the "supplier" for account "supplier2" is staked with "1000070" uPOKT
And an account exists for "supplier2"
When the user unstakes a "supplier" from the account "supplier2"
Expand All @@ -27,10 +29,15 @@ Feature: Stake Supplier Namespace

Scenario: User can restake a Supplier waiting for it to become active again
Given the user has the pocketd binary installed
# Reduce the application unbonding period to avoid timeouts and speed up scenarios.
And the "supplier" unbonding period param is successfully set to "1" sessions of "2" blocks
And the user verifies the "supplier" for account "supplier2" is not staked
Then the user stakes a "supplier" with "1000070" uPOKT for "anvil" service from the account "supplier2"
And the user should wait for the "supplier" module "StakeSupplier" message to be submitted
Then the user should see that the supplier for account "supplier2" is staked
But the session for application "app1" and service "anvil" does not contain "supplier2"
When the user waits for supplier "supplier2" to become active for service "anvil"
Then the session for application "app1" and service "anvil" contains the supplier "supplier2"
# Cleanup to make this feature idempotent.
And the user unstakes a "supplier" from the account "supplier2"
And the user waits for the supplier for account "supplier2" unbonding period to finish
100 changes: 100 additions & 0 deletions e2e/tests/stake_supplier_steps_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//go:build e2e

package e2e

import (
"reflect"
"strings"
"unicode"

"github.com/stretchr/testify/require"

sharedtypes "github.com/pokt-network/poktroll/x/shared/types"
)

func (s *suite) TheUnbondingPeriodParamIsSuccessfullySetToSessionsOfBlocks(
_ string,
unbondingPeriodSessions,
numBlocksPerSession int64,
) {
require.GreaterOrEqualf(s, numBlocksPerSession, int64(2),
"num_blocks_per_session MUST be at least 2 to satisfy parameter validation requirements")

paramModuleName := "shared"
granter := "gov"
grantee := "pnf"

// Ensure an authz grant is present such that this step may update parameters.
s.AnAuthzGrantFromTheAccountToTheAccountForEachModuleMsgupdateparamMessageExists(
granter, "module",
grantee, "user",
)

// NB: If new parameters are added to the shared module, they
// MUST be included here; otherwise, this step will fail.
sharedParams := sharedtypes.Params{
NumBlocksPerSession: uint64(numBlocksPerSession),
GracePeriodEndOffsetBlocks: 0,
ClaimWindowOpenOffsetBlocks: 0,
ClaimWindowCloseOffsetBlocks: 1,
ProofWindowOpenOffsetBlocks: 0,
ProofWindowCloseOffsetBlocks: 1,
SupplierUnbondingPeriodSessions: uint64(unbondingPeriodSessions),
ApplicationUnbondingPeriodSessions: uint64(unbondingPeriodSessions),
ComputeUnitsToTokensMultiplier: sharedtypes.DefaultComputeUnitsToTokensMultiplier,
}

// Convert params struct to the map type expected by
// s.sendAuthzExecToUpdateAllModuleParams().
paramsMap := paramsAnyMapFromParamsStruct(sharedParams)
s.sendAuthzExecToUpdateAllModuleParams(grantee, paramModuleName, paramsMap)

// Assert that the parameter values were updated.
s.AllModuleParamsShouldBeUpdated(paramModuleName)
}

// paramsAnyMapFromParamStruct construct a paramsAnyMap from any
// protobuf Param message type (tx.proto) using reflection.
func paramsAnyMapFromParamsStruct(paramStruct any) paramsAnyMap {
paramsMap := make(paramsAnyMap)
paramsReflectValue := reflect.ValueOf(paramStruct)
for i := 0; i < paramsReflectValue.NumField(); i++ {
fieldValue := paramsReflectValue.Field(i)
fieldStruct := paramsReflectValue.Type().Field(i)
paramName := toSnakeCase(fieldStruct.Name)

fieldTypeName := fieldStruct.Type.Name()
// TODO_IMPROVE: MsgUpdateParam currently only supports int64 and not uint64 value types.
if fieldTypeName == "uint64" {
bryanchriswhite marked this conversation as resolved.
Show resolved Hide resolved
fieldTypeName = "int64"
fieldValue = reflect.ValueOf(int64(fieldValue.Interface().(uint64)))
}

paramsMap[paramName] = paramAny{
name: paramName,
typeStr: fieldTypeName,
value: fieldValue.Interface(),
}
}
return paramsMap
}

func toSnakeCase(str string) string {
var result strings.Builder

for i, runeValue := range str {
if unicode.IsUpper(runeValue) {
// If it's not the first letter, add an underscore
if i > 0 {
result.WriteRune('_')
}
// Convert to lowercase
result.WriteRune(unicode.ToLower(runeValue))
} else {
// Otherwise, just append the rune as-is
result.WriteRune(runeValue)
}
}

return result.String()
}
32 changes: 16 additions & 16 deletions e2e/tests/update_params.feature
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,22 @@ Feature: Params Namespace
Then the "<module>" module param "<param_name>" should be updated

Examples:
| module | message_type | param_name | param_value | param_type |
| proof | /poktroll.proof.MsgUpdateParam | min_relay_difficulty_bits | 12 | int64 |
| proof | /poktroll.proof.MsgUpdateParam | proof_request_probability | 0.1 | float |
| proof | /poktroll.proof.MsgUpdateParam | proof_requirement_threshold | 100 | coin |
| proof | /poktroll.proof.MsgUpdateParam | proof_missing_penalty | 500 | coin |
| proof | /poktroll.proof.MsgUpdateParam | proof_submission_fee | 5000000 | coin |
| shared | /poktroll.shared.MsgUpdateParam | num_blocks_per_session | 5 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | grace_period_end_offset_blocks | 2 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | claim_window_open_offset_blocks | 2 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | claim_window_close_offset_blocks | 3 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | proof_window_open_offset_blocks | 1 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | proof_window_close_offset_blocks | 5 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | supplier_unbonding_period_sessions | 5 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | application_unbonding_period_sessions | 5 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | compute_units_to_tokens_multiplier | 68 | int64 |
| service | /poktroll.service.MsgUpdateParam | add_service_fee | 1000000001 | coin |
| module | message_type | param_name | param_value | param_type |
| proof | /poktroll.proof.MsgUpdateParam | min_relay_difficulty_bits | 12 | int64 |
| proof | /poktroll.proof.MsgUpdateParam | proof_request_probability | 0.1 | float |
| proof | /poktroll.proof.MsgUpdateParam | proof_requirement_threshold | 100 | coin |
| proof | /poktroll.proof.MsgUpdateParam | proof_missing_penalty | 500 | coin |
| proof | /poktroll.proof.MsgUpdateParam | proof_submission_fee | 5000000 | coin |
| shared | /poktroll.shared.MsgUpdateParam | num_blocks_per_session | 9 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | grace_period_end_offset_blocks | 0 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | claim_window_open_offset_blocks | 2 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | claim_window_close_offset_blocks | 3 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | proof_window_open_offset_blocks | 1 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | proof_window_close_offset_blocks | 5 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | supplier_unbonding_period_sessions | 5 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | application_unbonding_period_sessions | 5 | int64 |
| shared | /poktroll.shared.MsgUpdateParam | compute_units_to_tokens_multiplier | 68 | int64 |
| service | /poktroll.service.MsgUpdateParam | add_service_fee | 1000000001 | coin |

Scenario: An unauthorized user cannot update individual module params
Given the user has the pocketd binary installed
Expand Down
26 changes: 17 additions & 9 deletions e2e/tests/update_params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,16 +217,9 @@ func (s *suite) AllModuleParamsShouldBeSetToTheirDefaultValues(moduleName string
// TheAccountSendsAnAuthzExecMessageToUpdateAllModuleParams sends an authz exec
// message to update all module params for the given module.
func (s *suite) TheAccountSendsAnAuthzExecMessageToUpdateAllModuleParams(accountName, moduleName string, table gocuke.DataTable) {
// NB: set s#moduleParamsMap for later assertion.
s.expectedModuleParams = moduleParamsMap{
moduleName: s.parseParamsTable(table),
}

// Use the map of params to populate a tx JSON template & write it to a file.
txJSONFile := s.newTempUpdateParamsTxJSONFile(s.expectedModuleParams)
paramsTableMap := s.parseParamsTable(table)

// Send the authz exec tx to update all module params.
s.sendAuthzExecTx(accountName, txJSONFile.Name())
s.sendAuthzExecToUpdateAllModuleParams(accountName, moduleName, paramsTableMap)
}

// AllModuleParamsShouldBeUpdated asserts that all module params have been updated as expected.
Expand Down Expand Up @@ -481,6 +474,21 @@ func (s *suite) assertExpectedModuleParamsUpdated(moduleName string) {
}
}

// sendAuthzExecToUpdateAllModuleParams constructs and sends an authz exec
// tx to update all params for moduleName the given params.
func (s *suite) sendAuthzExecToUpdateAllModuleParams(accountName, moduleName string, params paramsAnyMap) {
// NB: set s#moduleParamsMap for later assertion.
s.expectedModuleParams = moduleParamsMap{
moduleName: params,
}

// Use the map of params to populate a tx JSON template & write it to a file.
txJSONFile := s.newTempUpdateParamsTxJSONFile(s.expectedModuleParams)

// Send the authz exec tx to update all module params.
s.sendAuthzExecTx(accountName, txJSONFile.Name())
}

// assertUpdatedParams deserializes the param query response JSON into a
// MsgUpdateParams of type P & asserts that it matches the expected params.
func assertUpdatedParams[P cosmostypes.Msg](
Expand Down
Loading
Loading