diff --git a/.changelog/2632.bugfix.md b/.changelog/2632.bugfix.md new file mode 100644 index 00000000000..b077d2bb2aa --- /dev/null +++ b/.changelog/2632.bugfix.md @@ -0,0 +1,3 @@ +oasis-node/cmd/stake: Make info subcommand tolerate invalid thresholds. + +Change the subcommand to print valid staking threshold kinds and warn about invalid ones. diff --git a/go/consensus/tendermint/apps/staking/query.go b/go/consensus/tendermint/apps/staking/query.go index 919ec1b6255..b4bb6379bdc 100644 --- a/go/consensus/tendermint/apps/staking/query.go +++ b/go/consensus/tendermint/apps/staking/query.go @@ -2,7 +2,6 @@ package staking import ( "context" - "errors" "github.com/oasislabs/oasis-core/go/common/crypto/signature" "github.com/oasislabs/oasis-core/go/common/quantity" @@ -12,10 +11,6 @@ import ( staking "github.com/oasislabs/oasis-core/go/staking/api" ) -// ErrInvalidThreshold is the error returned when an invalid threshold kind -// is specified in a query. -var ErrInvalidThreshold = errors.New("staking: invalid threshold") - // Query is the staking query interface. type Query interface { TotalSupply(context.Context) (*quantity.Quantity, error) @@ -79,7 +74,7 @@ func (sq *stakingQuerier) Threshold(ctx context.Context, kind staking.ThresholdK threshold, ok := thresholds[kind] if !ok { - return nil, ErrInvalidThreshold + return nil, staking.ErrInvalidThreshold } return &threshold, nil } diff --git a/go/oasis-node/cmd/stake/stake.go b/go/oasis-node/cmd/stake/stake.go index 528232b8c29..5f0b12fbb98 100644 --- a/go/oasis-node/cmd/stake/stake.go +++ b/go/oasis-node/cmd/stake/stake.go @@ -12,6 +12,7 @@ import ( "google.golang.org/grpc" "github.com/oasislabs/oasis-core/go/common/crypto/signature" + "github.com/oasislabs/oasis-core/go/common/errors" "github.com/oasislabs/oasis-core/go/common/logging" "github.com/oasislabs/oasis-core/go/common/quantity" consensus "github.com/oasislabs/oasis-core/go/consensus/api" @@ -113,7 +114,11 @@ func doInfo(cmd *cobra.Command, args []string) { api.KindCompute, api.KindStorage, } - thresholds := make(map[api.ThresholdKind]*quantity.Quantity) + type threshold struct { + value *quantity.Quantity + valid bool + } + thresholds := make(map[api.ThresholdKind]*threshold) doWithRetries(cmd, "query staking threshold(s)", func() error { for _, k := range thresholdsToQuery { if thresholds[k] != nil { @@ -122,14 +127,25 @@ func doInfo(cmd *cobra.Command, args []string) { q, err := client.Threshold(ctx, &api.ThresholdQuery{Kind: k, Height: consensus.HeightLatest}) if err != nil { + if errors.Is(err, api.ErrInvalidThreshold) { + logger.Warn(fmt.Sprintf("invalid staking threshold kind: %s", k)) + thresholds[k] = &threshold{} + continue + } return err } - thresholds[k] = q + thresholds[k] = &threshold{ + value: q, + valid: true, + } } return nil }) for _, k := range thresholdsToQuery { - fmt.Printf("Staking threshold (%s): %v\n", k, thresholds[k]) + thres := thresholds[k] + if thres.valid { + fmt.Printf("Staking threshold (%s): %v\n", k, thres.value) + } } } diff --git a/go/oasis-test-runner/scenario/e2e/stake_cli.go b/go/oasis-test-runner/scenario/e2e/stake_cli.go index 71419d0d74b..0f802e0a089 100644 --- a/go/oasis-test-runner/scenario/e2e/stake_cli.go +++ b/go/oasis-test-runner/scenario/e2e/stake_cli.go @@ -93,6 +93,11 @@ func (s *stakeCLIImpl) Run(childEnv *env.Env) error { cli := cli.New(childEnv, s.net, s.logger) + // General token info. + if err := s.getInfo(childEnv); err != nil { + return err + } + // Account list. accounts, err := s.listAccounts(childEnv) if err != nil { @@ -333,6 +338,28 @@ func (s *stakeCLIImpl) testAmendCommissionSchedule(childEnv *env.Env, cli *cli.H return nil } +func (s *stakeCLIImpl) getInfo(childEnv *env.Env) error { + s.logger.Info("querying common token info") + args := []string{ + "stake", "info", + "--" + grpc.CfgAddress, "unix:" + s.basicImpl.net.Validators()[0].SocketPath(), + } + + b, err := cli.RunSubCommandWithOutput(childEnv, s.logger, "info", s.basicImpl.net.Config().NodeBinary, args) + if err != nil { + return fmt.Errorf("scenario/e2e/stake: failed to query common token info: %s error: %w", b.String(), err) + } + // Check that subcommand reported warnings for invalid staking threshold kinds. + subCmdOutput := b.String() + thresholdKinds := []string{"compute", "storage"} + for _, kind := range thresholdKinds { + if !strings.Contains(subCmdOutput, fmt.Sprintf("invalid staking threshold kind: %s", kind)) { + return fmt.Errorf("scenario/e2e/stake: querying common token info should warn about invalid staking threshold for kind: %s", kind) + } + } + return nil +} + func (s *stakeCLIImpl) listAccounts(childEnv *env.Env) ([]signature.PublicKey, error) { s.logger.Info("listing all accounts") args := []string{ diff --git a/go/staking/api/api.go b/go/staking/api/api.go index e8bdb3ad3c4..46433cf9ce1 100644 --- a/go/staking/api/api.go +++ b/go/staking/api/api.go @@ -44,6 +44,10 @@ var ( // policy. ErrForbidden = errors.New(ModuleName, 5, "staking: forbidden by policy") + // ErrInvalidThreshold is the error returned when an invalid threshold kind + // is specified in a query. + ErrInvalidThreshold = errors.New(ModuleName, 6, "staking: invalid threshold") + // MethodTransfer is the method name for transfers. MethodTransfer = transaction.NewMethodName(ModuleName, "Transfer", Transfer{}) // MethodBurn is the method name for burns. diff --git a/tests/fixture-data/stake-cli/staking-genesis.json b/tests/fixture-data/stake-cli/staking-genesis.json index 6370b44b131..7bd53497a4b 100644 --- a/tests/fixture-data/stake-cli/staking-genesis.json +++ b/tests/fixture-data/stake-cli/staking-genesis.json @@ -5,6 +5,10 @@ "rate_bound_lead": 30, "max_rate_steps": 4, "max_bound_steps": 12 + }, + "thresholds": { + "0": "0", + "1": "0" } } }