diff --git a/.github/workflows-helpers/run-e2e-test-job-template.yaml b/.github/workflows-helpers/run-e2e-test-job-template.yaml index bd3a94feb..80378bd32 100644 --- a/.github/workflows-helpers/run-e2e-test-job-template.yaml +++ b/.github/workflows-helpers/run-e2e-test-job-template.yaml @@ -20,7 +20,7 @@ spec: poktrolld q gateway list-gateway --node=$POCKET_NODE && \ poktrolld q application list-application --node=$POCKET_NODE && \ poktrolld q supplier list-supplier --node=$POCKET_NODE && \ - poktrolld tx supplier stake-supplier 1000upokt --config=/poktroll/localnet/poktrolld/config/supplier1_stake_config.yaml --keyring-backend=test --from=supplier1 --node=$POCKET_NODE --yes && \ + poktrolld tx supplier stake-supplier --config=/poktroll/localnet/poktrolld/config/supplier1_stake_config.yaml --keyring-backend=test --from=supplier1 --node=$POCKET_NODE --yes && \ poktrolld tx application stake-application --config=/poktroll/localnet/poktrolld/config/application1_stake_config.yaml --keyring-backend=test --from=app1 --node=$POCKET_NODE --yes && \ go test -v ./e2e/tests/... -tags=e2e env: diff --git a/Makefile b/Makefile index 207a3141e..8accba245 100644 --- a/Makefile +++ b/Makefile @@ -393,7 +393,7 @@ supplier_list: ## List all the staked supplier .PHONY: supplier_stake supplier_stake: ## Stake tokens for the supplier specified (must specify the SUPPLIER and SUPPLIER_CONFIG env vars) - poktrolld --home=$(POKTROLLD_HOME) tx supplier stake-supplier 1000upokt --config $(POKTROLLD_HOME)/config/$(SERVICES) --keyring-backend test --from $(SUPPLIER) --node $(POCKET_NODE) + poktrolld --home=$(POKTROLLD_HOME) tx supplier stake-supplier --config $(POKTROLLD_HOME)/config/$(SERVICES) --keyring-backend test --from $(SUPPLIER) --node $(POCKET_NODE) .PHONY: supplier1_stake supplier1_stake: ## Stake supplier1 (also staked in genesis) diff --git a/localnet/poktrolld/config/supplier1_stake_config.yaml b/localnet/poktrolld/config/supplier1_stake_config.yaml index 28307ab37..08e45fe31 100644 --- a/localnet/poktrolld/config/supplier1_stake_config.yaml +++ b/localnet/poktrolld/config/supplier1_stake_config.yaml @@ -1,11 +1,13 @@ # TODO(@Olshansk, @okdas): Add more services (in addition to anvil) for apps and suppliers to stake for. -# TODO_TECHDEBT: svc1, svc2 and svc3 below are only in place to make GetSession testable +# TODO_TECHDEBT: svc1 below are only in place to make GetSession testable # TODO_IMPROVE(#180): Make sure genesis-staked actors are available via AccountKeeper -- service_id: anvil - endpoints: - - url: http://anvil.supplier1:8545 - rpc_type: json_rpc -- service_id: svc1 - endpoints: - - url: http://localhost:8081 - rpc_type: json_rpc +stake_amount: 1000upokt +services: + - service_id: anvil + endpoints: + - url: http://anvil.supplier1:8545 + rpc_type: json_rpc + - service_id: svc1 + endpoints: + - url: http://localhost:8081 + rpc_type: json_rpc diff --git a/localnet/poktrolld/config/supplier2_stake_config.yaml b/localnet/poktrolld/config/supplier2_stake_config.yaml index eb131ace0..3983bbf2f 100644 --- a/localnet/poktrolld/config/supplier2_stake_config.yaml +++ b/localnet/poktrolld/config/supplier2_stake_config.yaml @@ -1,8 +1,10 @@ -- service_id: anvil - endpoints: - - url: http://anvil.supplier2:8545 - rpc_type: json_rpc -- service_id: svc1 - endpoints: - - url: http://localhost:8082 - rpc_type: json_rpc +stake_amount: 1000upokt +services: + - service_id: anvil + endpoints: + - url: http://anvil.supplier2:8545 + rpc_type: json_rpc + - service_id: svc1 + endpoints: + - url: http://localhost:8082 + rpc_type: json_rpc diff --git a/localnet/poktrolld/config/supplier3_stake_config.yaml b/localnet/poktrolld/config/supplier3_stake_config.yaml index 3d6a31525..c8ee429c5 100644 --- a/localnet/poktrolld/config/supplier3_stake_config.yaml +++ b/localnet/poktrolld/config/supplier3_stake_config.yaml @@ -1,8 +1,10 @@ -- service_id: anvil - endpoints: - - url: http://anvil.supplier3:8545 - rpc_type: json_rpc -- service_id: svc1 - endpoints: - - url: http://localhost:8083 - rpc_type: json_rpc +stake_amount: 1000upokt +services: + - service_id: anvil + endpoints: + - url: http://anvil.supplier3:8545 + rpc_type: json_rpc + - service_id: svc1 + endpoints: + - url: http://localhost:8083 + rpc_type: json_rpc diff --git a/x/supplier/client/cli/tx_stake_supplier.go b/x/supplier/client/cli/tx_stake_supplier.go index 1919e1c7f..2c611f817 100644 --- a/x/supplier/client/cli/tx_stake_supplier.go +++ b/x/supplier/client/cli/tx_stake_supplier.go @@ -7,7 +7,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/spf13/cobra" "github.com/pokt-network/poktroll/x/supplier/client/config" @@ -22,27 +21,21 @@ var ( func CmdStakeSupplier() *cobra.Command { // fromAddress & signature is retrieved via `flags.FlagFrom` in the `clientCtx` cmd := &cobra.Command{ - Use: "stake-supplier --config ", + Use: "stake-supplier --config ", Short: "Stake a supplier", Long: `Stake an supplier with the provided parameters. This is a broadcast operation that will stake the tokens and associate them with the supplier specified by the 'from' address. Example: -$ poktrolld --home=$(POKTROLLD_HOME) tx supplier stake-supplier 1000upokt --config stake_config.yaml --keyring-backend test --from $(APP) --node $(POCKET_NODE)`, +$ poktrolld --home=$(POKTROLLD_HOME) tx supplier stake-supplier --config stake_config.yaml --keyring-backend test --from $(APP) --node $(POCKET_NODE)`, - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - stakeString := args[0] + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, _ []string) (err error) { configContent, err := os.ReadFile(flagStakeConfig) if err != nil { return err } - stake, err := sdk.ParseCoinNormalized(stakeString) - if err != nil { - return err - } - supplierStakeConfigs, err := config.ParseSupplierConfigs(configContent) if err != nil { return err @@ -55,8 +48,8 @@ $ poktrolld --home=$(POKTROLLD_HOME) tx supplier stake-supplier 1000upokt --conf msg := types.NewMsgStakeSupplier( clientCtx.GetFromAddress().String(), - stake, - supplierStakeConfigs, + supplierStakeConfigs.StakeAmount, + supplierStakeConfigs.Services, ) if err := msg.ValidateBasic(); err != nil { diff --git a/x/supplier/client/cli/tx_stake_supplier_test.go b/x/supplier/client/cli/tx_stake_supplier_test.go index 1549c44ec..7400e404c 100644 --- a/x/supplier/client/cli/tx_stake_supplier_test.go +++ b/x/supplier/client/cli/tx_stake_supplier_test.go @@ -40,41 +40,39 @@ func TestCLI_StakeSupplier(t *testing.T) { } defaultConfig := ` - - service_id: svc1 - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc + stake_amount: 1000upokt + services: + - service_id: svc1 + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc ` tests := []struct { - desc string - address string - stakeString string - config string - err *sdkerrors.Error + desc string + address string + config string + err *sdkerrors.Error }{ // Happy Paths { - desc: "stake supplier: valid", - address: supplierAccount.Address.String(), - stakeString: "1000upokt", - config: defaultConfig, + desc: "stake supplier: valid", + address: supplierAccount.Address.String(), + config: defaultConfig, }, // Error Paths - Address Related { desc: "stake supplier: missing address", // address: "explicitly missing", - err: types.ErrSupplierInvalidAddress, - stakeString: "1000upokt", - config: defaultConfig, + err: types.ErrSupplierInvalidAddress, + config: defaultConfig, }, { - desc: "stake supplier: invalid address", - address: "invalid", - stakeString: "1000upokt", - err: types.ErrSupplierInvalidAddress, - config: defaultConfig, + desc: "stake supplier: invalid address", + address: "invalid", + err: types.ErrSupplierInvalidAddress, + config: defaultConfig, }, // Error Paths - Stake Related @@ -82,98 +80,106 @@ func TestCLI_StakeSupplier(t *testing.T) { desc: "stake supplier: missing stake", address: supplierAccount.Address.String(), err: types.ErrSupplierInvalidStake, - // stakeString: "explicitly missing", config: ` - - service_id: svc1 - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc + # explicitly omitted stake + services: + - service_id: svc1 + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc `, }, { - desc: "stake supplier: invalid stake denom", - address: supplierAccount.Address.String(), - err: types.ErrSupplierInvalidStake, - stakeString: "1000invalid", + desc: "stake supplier: invalid stake denom", + address: supplierAccount.Address.String(), + err: types.ErrSupplierInvalidStake, config: ` - - service_id: svc1 - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc + stake_amount: 1000invalid + services: + - service_id: svc1 + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc `, }, { - desc: "stake supplier: invalid stake amount (zero)", - address: supplierAccount.Address.String(), - err: types.ErrSupplierInvalidStake, - stakeString: "0upokt", + desc: "stake supplier: invalid stake amount (zero)", + address: supplierAccount.Address.String(), + err: types.ErrSupplierInvalidStake, config: ` - - service_id: svc1 - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc + stake_amount: 0upokt + services: + - service_id: svc1 + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc `, }, { - desc: "stake supplier: invalid stake amount (negative)", - address: supplierAccount.Address.String(), - err: types.ErrSupplierInvalidStake, - stakeString: "-1000upokt", + desc: "stake supplier: invalid stake amount (negative)", + address: supplierAccount.Address.String(), + err: types.ErrSupplierInvalidStake, config: ` - - service_id: svc1 - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc + stake_amount: -1000upokt + services: + - service_id: svc1 + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc `, }, // Happy Paths - Service Related { - desc: "services_test: valid multiple services", - address: supplierAccount.Address.String(), - stakeString: "1000upokt", + desc: "services_test: valid multiple services", + address: supplierAccount.Address.String(), config: ` - - service_id: svc1 - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc - - service_id: svc2 - endpoints: - - url: http://pokt.network:8082 - rpc_type: json_rpc + stake_amount: 1000upokt + services: + - service_id: svc1 + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + - service_id: svc2 + endpoints: + - url: http://pokt.network:8082 + rpc_type: json_rpc `, }, { - desc: "services_test: valid localhost", - address: supplierAccount.Address.String(), - stakeString: "1000upokt", + desc: "services_test: valid localhost", + address: supplierAccount.Address.String(), config: ` - - service_id: svc1 - endpoints: - - url: http://127.0.0.1:8082 - rpc_type: json_rpc + stake_amount: 1000upokt + services: + - service_id: svc1 + endpoints: + - url: http://127.0.0.1:8082 + rpc_type: json_rpc `, }, { - desc: "services_test: valid loopback", - address: supplierAccount.Address.String(), - stakeString: "1000upokt", + desc: "services_test: valid loopback", + address: supplierAccount.Address.String(), config: ` - - service_id: svc1 - endpoints: - - url: http://localhost:8082 - rpc_type: json_rpc + stake_amount: 1000upokt + services: + - service_id: svc1 + endpoints: + - url: http://localhost:8082 + rpc_type: json_rpc `, }, { - desc: "services_test: valid without a pork", - address: supplierAccount.Address.String(), - stakeString: "1000upokt", + desc: "services_test: valid without a pork", + address: supplierAccount.Address.String(), config: ` - - service_id: svc1 - endpoints: - - url: http://pokt.network - rpc_type: json_rpc + stake_amount: 1000upokt + services: + - service_id: svc1 + endpoints: + - url: http://pokt.network + rpc_type: json_rpc `, }, @@ -183,60 +189,68 @@ func TestCLI_StakeSupplier(t *testing.T) { address: supplierAccount.Address.String(), err: types.ErrSupplierInvalidServiceConfig, // servicesString: "explicitly omitted", - stakeString: "1000upokt", + config: ` + stake_amount: 1000upokt + `, }, { - desc: "services_test: invalid services (empty string)", - address: supplierAccount.Address.String(), - err: types.ErrSupplierInvalidServiceConfig, - stakeString: "1000upokt", - config: ``, + desc: "services_test: invalid services (empty string)", + address: supplierAccount.Address.String(), + err: types.ErrSupplierInvalidServiceConfig, + config: ` + stake_amount: 1000upokt + services: + `, }, { - desc: "services_test: invalid URL", - address: supplierAccount.Address.String(), - err: types.ErrSupplierInvalidServiceConfig, - stakeString: "1000upokt", + desc: "services_test: invalid URL", + address: supplierAccount.Address.String(), + err: types.ErrSupplierInvalidServiceConfig, config: ` - - service_id: svc1 - endpoints: - - url: bad_url - rpc_type: json_rpc + stake_amount: 1000upokt + services: + - service_id: svc1 + endpoints: + - url: bad_url + rpc_type: json_rpc `, }, { - desc: "services_test: missing URLs", - address: supplierAccount.Address.String(), - err: types.ErrSupplierInvalidServiceConfig, - stakeString: "1000upokt", + desc: "services_test: missing URLs", + address: supplierAccount.Address.String(), + err: types.ErrSupplierInvalidServiceConfig, config: ` - - service_id: svc1 - - service_id: svc2 + stake_amount: 1000upokt + services: + - service_id: svc1 + - service_id: svc2 `, }, { - desc: "services_test: missing service IDs", - address: supplierAccount.Address.String(), - err: types.ErrSupplierInvalidServiceConfig, - stakeString: "1000upokt", + desc: "services_test: missing service IDs", + address: supplierAccount.Address.String(), + err: types.ErrSupplierInvalidServiceConfig, config: ` - - endpoints: - - url: localhost:8081 - rpc_type: json_rpc - - endpoints: - - url: localhost:8082 - rpc_type: json_rpc + stake_amount: 1000upokt + services: + - endpoints: + - url: localhost:8081 + rpc_type: json_rpc + - endpoints: + - url: localhost:8082 + rpc_type: json_rpc `, }, { - desc: "services_test: missing rpc type", - address: supplierAccount.Address.String(), - err: types.ErrSupplierInvalidServiceConfig, - stakeString: "1000upokt", + desc: "services_test: missing rpc type", + address: supplierAccount.Address.String(), + err: types.ErrSupplierInvalidServiceConfig, config: ` - - service_id: svc1 - endpoints: - - url: localhost:8082 + stake_amount: 1000upokt + services: + - service_id: svc1 + endpoints: + - url: localhost:8082 `, }, } @@ -255,7 +269,6 @@ func TestCLI_StakeSupplier(t *testing.T) { // Prepare the arguments for the CLI command args := []string{ - tt.stakeString, fmt.Sprintf("--config=%s", configPath), fmt.Sprintf("--%s=%s", flags.FlagFrom, tt.address), } diff --git a/x/supplier/client/config/errors.go b/x/supplier/client/config/errors.go index 0739daf93..6a0194a75 100644 --- a/x/supplier/client/config/errors.go +++ b/x/supplier/client/config/errors.go @@ -11,4 +11,5 @@ var ( ErrSupplierConfigInvalidRPCType = sdkerrors.Register(codespace, 5, "invalid rpc type in supplier config") ErrSupplierConfigInvalidURL = sdkerrors.Register(codespace, 6, "invalid endpoint url in supplier config") ErrSupplierConfigEmptyContent = sdkerrors.Register(codespace, 7, "empty supplier config content") + ErrSupplierConfigInvalidStake = sdkerrors.Register(codespace, 8, "invalid stake amount in supplier config") ) diff --git a/x/supplier/client/config/supplier_configs_reader.go b/x/supplier/client/config/supplier_configs_reader.go index 7794dcb3d..c5f1aeffc 100644 --- a/x/supplier/client/config/supplier_configs_reader.go +++ b/x/supplier/client/config/supplier_configs_reader.go @@ -5,10 +5,18 @@ import ( "gopkg.in/yaml.v2" + sdk "github.com/cosmos/cosmos-sdk/types" + sharedhelpers "github.com/pokt-network/poktroll/x/shared/helpers" sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) +// YAMLStakeConfig is the structure describing the supplier stake config file +type YAMLStakeConfig struct { + StakeAmount string `yaml:"stake_amount"` + Services []*YAMLStakeService `yaml:"services"` +} + // YAMLStakeService is the structure describing a single service stake entry in the stake config file type YAMLStakeService struct { ServiceId string `yaml:"service_id"` @@ -19,27 +27,63 @@ type YAMLStakeService struct { type YAMLServiceEndpoint struct { Url string `yaml:"url"` RPCType string `yaml:"rpc_type"` - Config map[string]string `yaml:"config"` + Config map[string]string `yaml:"config,omitempty"` +} + +// SupplierStakeConfig is the structure describing the parsed supplier stake config +type SupplierStakeConfig struct { + StakeAmount sdk.Coin + Services []*sharedtypes.SupplierServiceConfig } // ParseSupplierServiceConfig parses the stake config file into a SupplierServiceConfig -func ParseSupplierConfigs(configContent []byte) ([]*sharedtypes.SupplierServiceConfig, error) { - var stakeConfig []*YAMLStakeService +func ParseSupplierConfigs(configContent []byte) (*SupplierStakeConfig, error) { + var stakeConfig *YAMLStakeConfig + + if len(configContent) == 0 { + return nil, ErrSupplierConfigEmptyContent + } // Unmarshal the stake config file into a stakeConfig if err := yaml.Unmarshal(configContent, &stakeConfig); err != nil { return nil, ErrSupplierConfigUnmarshalYAML.Wrapf("%s", err) } - if len(stakeConfig) == 0 { - return nil, ErrSupplierConfigEmptyContent + // Validate the stake amount + if len(stakeConfig.StakeAmount) == 0 { + return nil, ErrSupplierConfigInvalidStake.Wrap("stake amount cannot be empty") + } + + stakeAmount, err := sdk.ParseCoinNormalized(stakeConfig.StakeAmount) + if err != nil { + return nil, ErrSupplierConfigInvalidStake.Wrap(err.Error()) + } + + if err := stakeAmount.Validate(); err != nil { + return nil, ErrSupplierConfigInvalidStake.Wrap(err.Error()) + } + + if stakeAmount.IsZero() { + return nil, ErrSupplierConfigInvalidStake.Wrap("stake amount cannot be zero") + } + + if stakeAmount.Denom != "upokt" { + return nil, ErrSupplierConfigInvalidStake.Wrapf( + "invalid stake denom, expecting: upokt, got: %s", + stakeAmount.Denom, + ) + } + + // Validate the services + if stakeConfig.Services == nil || len(stakeConfig.Services) == 0 { + return nil, ErrSupplierConfigInvalidServiceId.Wrap("serviceIds cannot be empty") } // Prepare the supplierServiceConfig - supplierServiceConfig := make([]*sharedtypes.SupplierServiceConfig, 0, len(stakeConfig)) + supplierServiceConfig := make([]*sharedtypes.SupplierServiceConfig, 0, len(stakeConfig.Services)) // Populate the services slice - for _, svc := range stakeConfig { + for _, svc := range stakeConfig.Services { // Validate the serviceId if !sharedhelpers.IsValidServiceId(svc.ServiceId) { return nil, ErrSupplierConfigInvalidServiceId.Wrapf("%s", svc.ServiceId) @@ -66,7 +110,10 @@ func ParseSupplierConfigs(configContent []byte) ([]*sharedtypes.SupplierServiceC supplierServiceConfig = append(supplierServiceConfig, service) } - return supplierServiceConfig, nil + return &SupplierStakeConfig{ + StakeAmount: stakeAmount, + Services: supplierServiceConfig, + }, nil } func parseEndpointEntry(endpoint YAMLServiceEndpoint) (*sharedtypes.SupplierEndpoint, error) { diff --git a/x/supplier/client/config/supplier_configs_reader_test.go b/x/supplier/client/config/supplier_configs_reader_test.go index 7be516b19..546a735c3 100644 --- a/x/supplier/client/config/supplier_configs_reader_test.go +++ b/x/supplier/client/config/supplier_configs_reader_test.go @@ -4,6 +4,7 @@ import ( "testing" sdkerrors "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/gogo/status" "github.com/stretchr/testify/require" @@ -14,293 +15,390 @@ import ( func Test_ParseSupplierConfigs(t *testing.T) { tests := []struct { - desc string - err *sdkerrors.Error - expected []*types.SupplierServiceConfig - config string + desc string + expectedError *sdkerrors.Error + expectedConfig *config.SupplierStakeConfig + inputConfig string }{ // Valid Configs { desc: "services_test: valid full service config", - err: nil, - expected: []*types.SupplierServiceConfig{ - { - Service: &types.Service{Id: "svc"}, - Endpoints: []*types.SupplierEndpoint{ - { - Url: "http://pokt.network:8081", - RpcType: types.RPCType_JSON_RPC, - Configs: []*types.ConfigOption{ - { - Key: types.ConfigOptions_TIMEOUT, - Value: "10", + inputConfig: ` + stake_amount: 1000upokt + services: + - service_id: svc + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + config: + timeout: 10 + `, + expectedError: nil, + expectedConfig: &config.SupplierStakeConfig{ + StakeAmount: sdk.NewCoin("upokt", sdk.NewInt(1000)), + Services: []*types.SupplierServiceConfig{ + { + Service: &types.Service{Id: "svc"}, + Endpoints: []*types.SupplierEndpoint{ + { + Url: "http://pokt.network:8081", + RpcType: types.RPCType_JSON_RPC, + Configs: []*types.ConfigOption{ + { + Key: types.ConfigOptions_TIMEOUT, + Value: "10", + }, }, }, }, }, }, }, - config: ` - - service_id: svc - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc - config: - timeout: 10 - `, }, { desc: "services_test: valid service config without endpoint config", - err: nil, - expected: []*types.SupplierServiceConfig{ - { - Service: &types.Service{Id: "svc"}, - Endpoints: []*types.SupplierEndpoint{ - { - Url: "http://pokt.network:8081", - RpcType: types.RPCType_JSON_RPC, + inputConfig: ` + stake_amount: 1000upokt + services: + - service_id: svc + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + `, + expectedError: nil, + expectedConfig: &config.SupplierStakeConfig{ + StakeAmount: sdk.NewCoin("upokt", sdk.NewInt(1000)), + Services: []*types.SupplierServiceConfig{ + { + Service: &types.Service{Id: "svc"}, + Endpoints: []*types.SupplierEndpoint{ + { + Url: "http://pokt.network:8081", + RpcType: types.RPCType_JSON_RPC, + }, }, }, }, }, - config: ` - - service_id: svc - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc - `, }, { desc: "services_test: valid service config with empty endpoint config", - err: nil, - expected: []*types.SupplierServiceConfig{ - { - Service: &types.Service{Id: "svc"}, - Endpoints: []*types.SupplierEndpoint{ - { - Url: "http://pokt.network:8081", - RpcType: types.RPCType_JSON_RPC, - Configs: []*types.ConfigOption{}, + inputConfig: ` + stake_amount: 1000upokt + services: + - service_id: svc + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + config: + `, + expectedError: nil, + expectedConfig: &config.SupplierStakeConfig{ + StakeAmount: sdk.NewCoin("upokt", sdk.NewInt(1000)), + Services: []*types.SupplierServiceConfig{ + { + Service: &types.Service{Id: "svc"}, + Endpoints: []*types.SupplierEndpoint{ + { + Url: "http://pokt.network:8081", + RpcType: types.RPCType_JSON_RPC, + Configs: []*types.ConfigOption{}, + }, }, }, }, }, - config: ` - - service_id: svc - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc - config: - `, }, { desc: "services_test: valid service config with multiple endpoints", - err: nil, - expected: []*types.SupplierServiceConfig{ - { - Service: &types.Service{Id: "svc"}, - Endpoints: []*types.SupplierEndpoint{ - { - Url: "http://pokt.network:8081", - RpcType: types.RPCType_JSON_RPC, - Configs: []*types.ConfigOption{ - { - Key: types.ConfigOptions_TIMEOUT, - Value: "10", + inputConfig: ` + stake_amount: 1000upokt + services: + - service_id: svc + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + config: + timeout: 10 + - url: http://pokt.network:8082 + rpc_type: json_rpc + config: + timeout: 11 + `, + expectedError: nil, + expectedConfig: &config.SupplierStakeConfig{ + StakeAmount: sdk.NewCoin("upokt", sdk.NewInt(1000)), + Services: []*types.SupplierServiceConfig{ + { + Service: &types.Service{Id: "svc"}, + Endpoints: []*types.SupplierEndpoint{ + { + Url: "http://pokt.network:8081", + RpcType: types.RPCType_JSON_RPC, + Configs: []*types.ConfigOption{ + { + Key: types.ConfigOptions_TIMEOUT, + Value: "10", + }, }, }, - }, - { - Url: "http://pokt.network:8082", - RpcType: types.RPCType_JSON_RPC, - Configs: []*types.ConfigOption{ - { - Key: types.ConfigOptions_TIMEOUT, - Value: "11", + { + Url: "http://pokt.network:8082", + RpcType: types.RPCType_JSON_RPC, + Configs: []*types.ConfigOption{ + { + Key: types.ConfigOptions_TIMEOUT, + Value: "11", + }, }, }, }, }, }, }, - config: ` - - service_id: svc - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc - config: - timeout: 10 - - url: http://pokt.network:8082 - rpc_type: json_rpc - config: - timeout: 11 - `, }, { - desc: "services_test: valid service config with multiple services", - err: nil, - expected: []*types.SupplierServiceConfig{ - { - Service: &types.Service{Id: "svc1"}, - Endpoints: []*types.SupplierEndpoint{ - { - Url: "http://pokt.network:8081", - RpcType: types.RPCType_JSON_RPC, - Configs: []*types.ConfigOption{ - { - Key: types.ConfigOptions_TIMEOUT, - Value: "10", + desc: "services_test: valid service config with multiple services", + expectedError: nil, + inputConfig: ` + stake_amount: 1000upokt + services: + - service_id: svc1 + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + config: + timeout: 10 + - service_id: svc2 + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + config: + timeout: 10 + `, + expectedConfig: &config.SupplierStakeConfig{ + StakeAmount: sdk.NewCoin("upokt", sdk.NewInt(1000)), + Services: []*types.SupplierServiceConfig{ + { + Service: &types.Service{Id: "svc1"}, + Endpoints: []*types.SupplierEndpoint{ + { + Url: "http://pokt.network:8081", + RpcType: types.RPCType_JSON_RPC, + Configs: []*types.ConfigOption{ + { + Key: types.ConfigOptions_TIMEOUT, + Value: "10", + }, }, }, }, }, - }, - { - Service: &types.Service{Id: "svc2"}, - Endpoints: []*types.SupplierEndpoint{ - { - Url: "http://pokt.network:8081", - RpcType: types.RPCType_JSON_RPC, - Configs: []*types.ConfigOption{ - { - Key: types.ConfigOptions_TIMEOUT, - Value: "10", + { + Service: &types.Service{Id: "svc2"}, + Endpoints: []*types.SupplierEndpoint{ + { + Url: "http://pokt.network:8081", + RpcType: types.RPCType_JSON_RPC, + Configs: []*types.ConfigOption{ + { + Key: types.ConfigOptions_TIMEOUT, + Value: "10", + }, }, }, }, }, }, }, - config: ` - - service_id: svc1 - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc - config: - timeout: 10 - - service_id: svc2 - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc - config: - timeout: 10 - `, }, // Invalid Configs { desc: "services_test: invalid service config without service ID", - err: config.ErrSupplierConfigUnmarshalYAML, - config: ` - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc - config: - timeout: 10 + inputConfig: ` + stake_amount: 1000upokt + services: + - endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + config: + timeout: 10 `, + expectedError: config.ErrSupplierConfigInvalidServiceId, }, { desc: "services_test: invalid service config with empty service ID", - err: config.ErrSupplierConfigInvalidServiceId, - config: ` - - service_id: - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc - config: - timeout: 10 + inputConfig: ` + stake_amount: 1000upokt + services: + - service_id: + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + config: + timeout: 10 `, + expectedError: config.ErrSupplierConfigInvalidServiceId, }, { desc: "services_test: invalid service config without endpoints", - err: config.ErrSupplierConfigNoEndpoints, - config: ` - - service_id: svc + inputConfig: ` + stake_amount: 1000upokt + services: + - service_id: svc `, + expectedError: config.ErrSupplierConfigNoEndpoints, }, { desc: "services_test: invalid service config with empty endpoints", - err: config.ErrSupplierConfigNoEndpoints, - config: ` - - service_id: svc - endpoints: + inputConfig: ` + stake_amount: 1000upokt + services: + - service_id: svc + endpoints: `, + expectedError: config.ErrSupplierConfigNoEndpoints, }, { desc: "services_test: invalid service config with unknown endpoint config key", - err: config.ErrSupplierConfigInvalidEndpointConfig, - config: ` - - service_id: svc - endpoints: - - url: http://pokt.network:8081 - rpc_type: json_rpc - config: - somekey: 10 + inputConfig: ` + stake_amount: 1000upokt + services: + - service_id: svc + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + config: + somekey: 10 `, + expectedError: config.ErrSupplierConfigInvalidEndpointConfig, }, { desc: "services_test: invalid service config with unknown endpoint rpc type", - err: config.ErrSupplierConfigInvalidRPCType, - config: ` - - service_id: svc - endpoints: - - url: http://pokt.network:8081 - rpc_type: somerpc - config: - timeout: 10 + inputConfig: ` + stake_amount: 1000upokt + services: + - service_id: svc + endpoints: + - url: http://pokt.network:8081 + rpc_type: somerpc + config: + timeout: 10 `, + expectedError: config.ErrSupplierConfigInvalidRPCType, }, { desc: "services_test: invalid service config with invalid endpoint url", - err: config.ErrSupplierConfigInvalidURL, - config: ` - - service_id: svc - endpoints: - - url: ::invalid_url - rpc_type: json_rpc - config: - timeout: 10 + inputConfig: ` + stake_amount: 1000upokt + services: + - service_id: svc + endpoints: + - url: ::invalid_url + rpc_type: json_rpc + config: + timeout: 10 `, + expectedError: config.ErrSupplierConfigInvalidURL, }, { - desc: "services_test: invalid service config with empty content", - err: config.ErrSupplierConfigInvalidURL, - config: ``, + desc: "services_test: invalid service config with empty content", + expectedError: config.ErrSupplierConfigEmptyContent, + inputConfig: ``, + }, + { + desc: "services_test: missing stake amount", + inputConfig: ` + services: + - service_id: svc + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + config: + timeout: 10 + `, + expectedError: config.ErrSupplierConfigInvalidStake, + }, + { + desc: "services_test: invalid stake denom", + inputConfig: ` + stake_amount: 1000invalid + services: + - service_id: svc + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + config: + timeout: 10 + `, + expectedError: config.ErrSupplierConfigInvalidStake, + }, + { + desc: "services_test: negative stake amount", + inputConfig: ` + stake_amount: -1000upokt + services: + - service_id: svc + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + config: + timeout: 10 + `, + expectedError: config.ErrSupplierConfigInvalidStake, + }, + { + desc: "services_test: zero stake amount", + inputConfig: ` + stake_amount: 0upokt + services: + - service_id: svc + endpoints: + - url: http://pokt.network:8081 + rpc_type: json_rpc + config: + timeout: 10 + `, + expectedError: config.ErrSupplierConfigInvalidStake, }, } for _, tt := range tests { t.Run(tt.desc, func(t *testing.T) { - normalizedConfig := yaml.NormalizeYAMLIndentation(tt.config) + normalizedConfig := yaml.NormalizeYAMLIndentation(tt.inputConfig) supplierServiceConfig, err := config.ParseSupplierConfigs([]byte(normalizedConfig)) - if tt.err != nil { + if tt.expectedError != nil { require.Error(t, err) - require.Nil(t, supplierServiceConfig) - stat, ok := status.FromError(tt.err) + require.ErrorIs(t, err, tt.expectedError) + stat, ok := status.FromError(tt.expectedError) require.True(t, ok) - require.Contains(t, stat.Message(), tt.err.Error()) + require.Contains(t, stat.Message(), tt.expectedError.Error()) require.Nil(t, supplierServiceConfig) return } require.NoError(t, err) - require.Equal(t, len(tt.expected), len(supplierServiceConfig)) - for i, expected := range tt.expected { + require.Equal(t, tt.expectedConfig.StakeAmount, supplierServiceConfig.StakeAmount) + require.Equal(t, tt.expectedConfig.StakeAmount.Denom, supplierServiceConfig.StakeAmount.Denom) + + require.Equal(t, len(tt.expectedConfig.Services), len(supplierServiceConfig.Services)) + for i, expected := range tt.expectedConfig.Services { - require.Equal(t, expected.Service.Id, supplierServiceConfig[i].Service.Id) + require.Equal(t, expected.Service.Id, supplierServiceConfig.Services[i].Service.Id) - require.Equal(t, len(expected.Endpoints), len(supplierServiceConfig[i].Endpoints)) + require.Equal(t, len(expected.Endpoints), len(supplierServiceConfig.Services[i].Endpoints)) for j, expectedEndpoint := range expected.Endpoints { - require.Equal(t, expectedEndpoint.Url, supplierServiceConfig[i].Endpoints[j].Url) - require.Equal(t, expectedEndpoint.RpcType, supplierServiceConfig[i].Endpoints[j].RpcType) + require.Equal(t, expectedEndpoint.Url, supplierServiceConfig.Services[i].Endpoints[j].Url) + require.Equal(t, expectedEndpoint.RpcType, supplierServiceConfig.Services[i].Endpoints[j].RpcType) - require.Equal(t, len(expectedEndpoint.Configs), len(supplierServiceConfig[i].Endpoints[j].Configs)) + require.Equal(t, len(expectedEndpoint.Configs), len(supplierServiceConfig.Services[i].Endpoints[j].Configs)) for k, expectedConfig := range expectedEndpoint.Configs { - require.Equal(t, expectedConfig.Key, supplierServiceConfig[i].Endpoints[j].Configs[k].Key) - require.Equal(t, expectedConfig.Value, supplierServiceConfig[i].Endpoints[j].Configs[k].Value) + require.Equal(t, expectedConfig.Key, supplierServiceConfig.Services[i].Endpoints[j].Configs[k].Key) + require.Equal(t, expectedConfig.Value, supplierServiceConfig.Services[i].Endpoints[j].Configs[k].Value) } } }