From 9a183ffbcc0163c8deb71c7fd5f8089a83e58f05 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 27 Dec 2019 12:57:54 -0500 Subject: [PATCH] Merge PR #5421: Refactor Error Handling --- CHANGELOG.md | 15 +- baseapp/abci.go | 176 ++++--- baseapp/baseapp.go | 161 +++--- baseapp/baseapp_test.go | 203 +++++--- baseapp/helpers.go | 6 +- baseapp/queryrouter_test.go | 2 +- baseapp/router_test.go | 4 +- client/context/broadcast.go | 7 +- client/context/broadcast_test.go | 11 +- .../adr-015-ibc-packet-receiver.md | 2 +- docs/building-modules/handler.md | 13 +- docs/building-modules/querier.md | 6 +- server/mock/app.go | 12 +- server/mock/tx.go | 7 +- simapp/app.go | 16 +- simapp/test_helpers.go | 20 +- store/errors/errors.go | 26 - store/iavl/store.go | 9 +- store/iavl/store_test.go | 21 +- store/rootmulti/store.go | 21 +- store/rootmulti/store_test.go | 20 +- types/decimal.go | 24 +- types/errors.go | 361 -------------- types/errors/abci.go | 39 ++ types/errors/abci_test.go | 26 +- types/errors/errors.go | 43 +- types/errors/stacktrace_test.go | 8 +- types/errors_test.go | 138 ------ types/handler.go | 2 +- types/queryable.go | 9 +- types/result.go | 48 +- types/result_test.go | 14 +- types/tx_msg.go | 8 +- x/auth/ante/ante_test.go | 71 ++- x/auth/client/rest/query.go | 6 +- x/auth/client/utils/tx.go | 6 +- x/auth/client/utils/tx_test.go | 7 +- x/auth/keeper/keeper.go | 9 +- x/auth/keeper/querier.go | 15 +- x/auth/types/expected_keepers.go | 2 +- x/auth/types/stdtx.go | 26 +- x/auth/types/stdtx_test.go | 13 +- x/bank/alias.go | 29 +- x/bank/bench_test.go | 10 +- x/bank/handler.go | 28 +- x/bank/handler_test.go | 13 +- x/bank/internal/keeper/keeper.go | 101 ++-- x/bank/internal/keeper/keeper_test.go | 12 +- x/bank/internal/keeper/querier.go | 13 +- x/bank/internal/types/errors.go | 34 +- x/bank/internal/types/msgs.go | 43 +- x/bank/simulation/operations.go | 13 +- x/crisis/alias.go | 34 +- x/crisis/handler.go | 17 +- x/crisis/handler_test.go | 24 +- x/crisis/internal/keeper/keeper.go | 2 +- x/crisis/internal/types/errors.go | 22 +- x/crisis/internal/types/expected_keepers.go | 2 +- x/crisis/internal/types/msgs.go | 4 +- x/distribution/alias.go | 16 +- x/distribution/handler.go | 37 +- x/distribution/keeper/allocation_test.go | 38 +- x/distribution/keeper/delegation.go | 4 +- x/distribution/keeper/delegation_test.go | 64 ++- x/distribution/keeper/fee_pool.go | 5 +- x/distribution/keeper/keeper.go | 29 +- x/distribution/keeper/proposal_handler.go | 5 +- x/distribution/keeper/querier.go | 88 ++-- x/distribution/keeper/querier_test.go | 12 +- x/distribution/keeper/test_common.go | 8 +- x/distribution/simulation/operations.go | 25 +- x/distribution/types/errors.go | 56 +-- x/distribution/types/expected_keepers.go | 6 +- x/distribution/types/msg.go | 24 +- x/distribution/types/proposal.go | 9 +- x/evidence/alias.go | 30 +- x/evidence/genesis_test.go | 3 +- x/evidence/handler.go | 15 +- x/evidence/handler_test.go | 13 +- x/evidence/internal/keeper/infraction_test.go | 15 +- x/evidence/internal/keeper/keeper.go | 13 +- x/evidence/internal/keeper/keeper_test.go | 3 +- x/evidence/internal/keeper/querier.go | 8 +- x/evidence/internal/types/errors.go | 56 +-- x/evidence/internal/types/msgs.go | 8 +- x/genutil/client/rest/query.go | 19 +- x/gov/abci.go | 2 +- x/gov/abci_test.go | 51 +- x/gov/alias.go | 87 ++-- x/gov/genesis_test.go | 2 +- x/gov/handler.go | 33 +- x/gov/handler_test.go | 7 +- x/gov/keeper/deposit.go | 11 +- x/gov/keeper/deposit_test.go | 6 +- x/gov/keeper/keeper.go | 6 +- x/gov/keeper/proposal.go | 12 +- x/gov/keeper/proposal_test.go | 25 +- x/gov/keeper/querier.go | 76 +-- x/gov/keeper/querier_test.go | 10 +- x/gov/keeper/test_common.go | 8 +- x/gov/keeper/vote.go | 9 +- x/gov/legacy/v0_36/types.go | 30 +- x/gov/simulation/operations.go | 19 +- x/gov/test_common.go | 28 +- x/gov/types/content.go | 16 +- x/gov/types/errors.go | 71 +-- x/gov/types/expected_keepers.go | 18 +- x/gov/types/msgs.go | 27 +- x/gov/types/proposal.go | 8 +- x/mint/alias.go | 7 +- x/mint/internal/keeper/keeper.go | 8 +- x/mint/internal/keeper/querier.go | 19 +- x/mint/internal/types/expected_keepers.go | 6 +- x/mock/app.go | 2 +- x/mock/app_test.go | 16 +- x/mock/test_utils.go | 33 +- x/mock/types.go | 11 +- x/params/alias.go | 18 +- x/params/commmon_test.go | 2 +- x/params/keeper.go | 20 +- x/params/proposal_handler.go | 12 +- x/params/proposal_handler_test.go | 2 +- x/params/types/errors.go | 49 +- x/params/types/proposal.go | 15 +- x/slashing/abci_test.go | 6 +- x/slashing/alias.go | 15 +- x/slashing/app_test.go | 14 +- x/slashing/handler.go | 15 +- x/slashing/handler_test.go | 91 ++-- x/slashing/internal/keeper/keeper.go | 7 +- x/slashing/internal/keeper/keeper_test.go | 30 +- x/slashing/internal/keeper/querier.go | 28 +- x/slashing/internal/keeper/test_common.go | 8 +- x/slashing/internal/keeper/unjail.go | 16 +- x/slashing/internal/types/errors.go | 57 +-- x/slashing/internal/types/msg.go | 4 +- x/slashing/simulation/operations.go | 6 +- x/staking/alias.go | 27 +- x/staking/app_test.go | 4 +- x/staking/client/cli/tx.go | 5 +- x/staking/exported/exported.go | 40 +- x/staking/handler.go | 75 +-- x/staking/handler_test.go | 467 +++++++++++------- x/staking/keeper/delegation.go | 71 +-- x/staking/keeper/keeper.go | 14 +- x/staking/keeper/pool.go | 4 +- x/staking/keeper/querier.go | 134 ++--- x/staking/keeper/query_utils.go | 8 +- x/staking/keeper/test_common.go | 5 +- x/staking/keeper/validator.go | 2 +- x/staking/simulation/operations.go | 31 +- x/staking/types/commission.go | 24 +- x/staking/types/errors.go | 270 ++-------- x/staking/types/expected_keepers.go | 8 +- x/staking/types/historical_info.go | 4 +- x/staking/types/msg.go | 58 ++- x/staking/types/validator.go | 25 +- x/supply/alias.go | 3 +- x/supply/internal/keeper/bank.go | 85 ++-- x/supply/internal/keeper/bank_test.go | 24 +- x/supply/internal/keeper/key.go | 8 - x/supply/internal/keeper/querier.go | 19 +- x/supply/internal/types/expected_keepers.go | 10 +- x/upgrade/abci_test.go | 12 +- x/upgrade/alias.go | 8 +- x/upgrade/handler.go | 12 +- x/upgrade/internal/keeper/keeper.go | 10 +- x/upgrade/internal/keeper/querier.go | 20 +- x/upgrade/internal/types/plan.go | 12 +- x/upgrade/internal/types/proposal.go | 14 +- 170 files changed, 2309 insertions(+), 2926 deletions(-) delete mode 100644 store/errors/errors.go delete mode 100644 types/errors.go delete mode 100644 types/errors_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index dac02cb50f66..be6b7cec3274 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,7 +50,20 @@ logic has been implemented for v0.38 target version. Applications can migrate vi ### API Breaking Changes -* (client) [\#5442](https://github.com/cosmos/cosmos-sdk/pull/5442) Remove client/alias.go as it's not necessary and +* (baseapp/types) [\#5421](https://github.com/cosmos/cosmos-sdk/pull/5421) The `Error` interface (`types/errors.go`) + has been removed in favor of the concrete type defined in `types/errors/` which implements the standard `error` + interface. As a result, the `Handler` and `Querier` implementations now return a standard `error`. + Within `BaseApp`, `runTx` now returns a `(GasInfo, *Result, error)` tuple and `runMsgs` returns a + `(*Result, error)` tuple. A reference to a `Result` is now used to indicate success whereas an error + signals an invalid message or failed message execution. As a result, the fields `Code`, `Codespace`, + `GasWanted`, and `GasUsed` have been removed the `Result` type. The latter two fields are now found + in the `GasInfo` type which is always returned regardless of execution outcome. + + Note to developers: Since all handlers and queriers must now return a standard `error`, the `types/errors/` + package contains all the relevant and pre-registered errors that you typically work with. A typical + error returned will look like `sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "...")`. You can retrieve + relevant ABCI information from the error via `ABCIInfo`. +* (client) [\#5442](https://github.com/cosmos/cosmos-sdk/pull/5442) Remove client/alias.go as it's not necessary and components can be imported directly from the packages. * (store) [\#4748](https://github.com/cosmos/cosmos-sdk/pull/4748) The `CommitMultiStore` interface now requires a `SetInterBlockCache` method. Applications that do not wish to support this can simply diff --git a/baseapp/abci.go b/baseapp/abci.go index e93b7c56c2c9..57bcec661eff 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // InitChain implements the ABCI interface. It runs the initialization logic @@ -153,54 +154,66 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc return } -// CheckTx implements the ABCI interface. It runs the "basic checks" to see -// whether or not a transaction can possibly be executed, first decoding and then -// the ante handler (which checks signatures/fees/ValidateBasic). -// -// NOTE:CheckTx does not run the actual Msg handler function(s). -func (app *BaseApp) CheckTx(req abci.RequestCheckTx) (res abci.ResponseCheckTx) { - var result sdk.Result - +// CheckTx implements the ABCI interface and executes a tx in CheckTx mode. In +// CheckTx mode, messages are not executed. This means messages are only validated +// and only the AnteHandler is executed. State is persisted to the BaseApp's +// internal CheckTx state if the AnteHandler passes. Otherwise, the ResponseCheckTx +// will contain releveant error information. Regardless of tx execution outcome, +// the ResponseCheckTx will contain relevant gas execution context. +func (app *BaseApp) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx { tx, err := app.txDecoder(req.Tx) + if err != nil { + return sdkerrors.ResponseCheckTx(err, 0, 0) + } + + var mode runTxMode + switch { - case err != nil: - result = err.Result() case req.Type == abci.CheckTxType_New: - result = app.runTx(runTxModeCheck, req.Tx, tx) + mode = runTxModeCheck + case req.Type == abci.CheckTxType_Recheck: - result = app.runTx(runTxModeReCheck, req.Tx, tx) + mode = runTxModeReCheck + default: - panic(fmt.Sprintf("Unknown RequestCheckTx Type: %v", req.Type)) + panic(fmt.Sprintf("unknown RequestCheckTx type: %s", req.Type)) + } + + gInfo, result, err := app.runTx(mode, req.Tx, tx) + if err != nil { + return sdkerrors.ResponseCheckTx(err, gInfo.GasWanted, gInfo.GasUsed) } return abci.ResponseCheckTx{ - Code: uint32(result.Code), - Data: result.Data, + GasWanted: int64(gInfo.GasWanted), // TODO: Should type accept unsigned ints? + GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints? Log: result.Log, - GasWanted: int64(result.GasWanted), // TODO: Should type accept unsigned ints? - GasUsed: int64(result.GasUsed), // TODO: Should type accept unsigned ints? + Data: result.Data, Events: result.Events.ToABCIEvents(), } } -// DeliverTx implements the ABCI interface. -func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliverTx) { - var result sdk.Result - +// DeliverTx implements the ABCI interface and executes a tx in DeliverTx mode. +// State only gets persisted if all messages are valid and get executed successfully. +// Otherwise, the ResponseDeliverTx will contain releveant error information. +// Regardless of tx execution outcome, the ResponseDeliverTx will contain relevant +// gas execution context. +func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx { tx, err := app.txDecoder(req.Tx) if err != nil { - result = err.Result() - } else { - result = app.runTx(runTxModeDeliver, req.Tx, tx) + return sdkerrors.ResponseDeliverTx(err, 0, 0) + } + + gInfo, result, err := app.runTx(runTxModeDeliver, req.Tx, tx) + if err != nil { + return sdkerrors.ResponseDeliverTx(err, gInfo.GasWanted, gInfo.GasUsed) } return abci.ResponseDeliverTx{ - Code: uint32(result.Code), - Codespace: string(result.Codespace), - Data: result.Data, + GasWanted: int64(gInfo.GasWanted), // TODO: Should type accept unsigned ints? + GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints? Log: result.Log, - GasWanted: int64(result.GasWanted), // TODO: Should type accept unsigned ints? - GasUsed: int64(result.GasUsed), // TODO: Should type accept unsigned ints? + Data: result.Data, Events: result.Events.ToABCIEvents(), } } @@ -278,11 +291,10 @@ func (app *BaseApp) halt() { // Query implements the ABCI interface. It delegates to CommitMultiStore if it // implements Queryable. -func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { +func (app *BaseApp) Query(req abci.RequestQuery) abci.ResponseQuery { path := splitPath(req.Path) if len(path) == 0 { - msg := "no query path provided" - return sdk.ErrUnknownRequest(msg).QueryResult() + sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no query path provided")) } switch path[0] { @@ -294,61 +306,59 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { return handleQueryStore(app, path, req) case "p2p": - return handleQueryP2P(app, path, req) + return handleQueryP2P(app, path) case "custom": return handleQueryCustom(app, path, req) } - msg := "unknown query path" - return sdk.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query path")) } -func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) { +func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery { if len(path) >= 2 { - var result sdk.Result - switch path[1] { case "simulate": txBytes := req.Data + tx, err := app.txDecoder(txBytes) if err != nil { - result = err.Result() - } else { - result = app.Simulate(txBytes, tx) + return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to decode tx")) + } + + gInfo, _, _ := app.Simulate(txBytes, tx) + + return abci.ResponseQuery{ + Codespace: sdkerrors.RootCodespace, + Height: req.Height, + Value: codec.Cdc.MustMarshalBinaryLengthPrefixed(gInfo.GasUsed), } case "version": return abci.ResponseQuery{ - Code: uint32(sdk.CodeOK), - Codespace: string(sdk.CodespaceRoot), + Codespace: sdkerrors.RootCodespace, Height: req.Height, Value: []byte(app.appVersion), } default: - result = sdk.ErrUnknownRequest(fmt.Sprintf("unknown query: %s", path)).Result() - } - - value := codec.Cdc.MustMarshalBinaryLengthPrefixed(result) - return abci.ResponseQuery{ - Code: uint32(sdk.CodeOK), - Codespace: string(sdk.CodespaceRoot), - Height: req.Height, - Value: value, + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query: %s", path)) } } - msg := "expected second parameter to be either 'simulate' or 'version', neither was present" - return sdk.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult( + sdkerrors.Wrap( + sdkerrors.ErrUnknownRequest, + "expected second parameter to be either 'simulate' or 'version', neither was present", + ), + ) } func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery { // "/store" prefix for store queries queryable, ok := app.cms.(sdk.Queryable) if !ok { - msg := "multistore doesn't support queries" - return sdk.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "multistore doesn't support queries")) } req.Path = "/" + strings.Join(path[1:], "/") @@ -359,7 +369,12 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.R } if req.Height <= 1 && req.Prove { - return sdk.ErrInternal("cannot query with proof when height <= 1; please provide a valid height").QueryResult() + return sdkerrors.QueryResult( + sdkerrors.Wrap( + sdkerrors.ErrInvalidRequest, + "cannot query with proof when height <= 1; please provide a valid height", + ), + ) } resp := queryable.Query(req) @@ -368,7 +383,7 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.R return resp } -func handleQueryP2P(app *BaseApp, path []string, _ abci.RequestQuery) (res abci.ResponseQuery) { +func handleQueryP2P(app *BaseApp, path []string) abci.ResponseQuery { // "/p2p" prefix for p2p queries if len(path) >= 4 { cmd, typ, arg := path[1], path[2], path[3] @@ -383,28 +398,30 @@ func handleQueryP2P(app *BaseApp, path []string, _ abci.RequestQuery) (res abci. } default: - msg := "expected second parameter to be 'filter'" - return sdk.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "expected second parameter to be 'filter'")) } } - msg := "Expected path is p2p filter " - return sdk.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult( + sdkerrors.Wrap( + sdkerrors.ErrUnknownRequest, "expected path is p2p filter ", + ), + ) } -func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) { +func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery { // path[0] should be "custom" because "/custom" prefix is required for keeper // queries. // // The QueryRouter routes using path[1]. For example, in the path // "custom/gov/proposal", QueryRouter routes using "gov". if len(path) < 2 || path[1] == "" { - return sdk.ErrUnknownRequest("No route for custom query specified").QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no route for custom query specified")) } querier := app.queryRouter.Route(path[1]) if querier == nil { - return sdk.ErrUnknownRequest(fmt.Sprintf("no custom querier found for route %s", path[1])).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "no custom querier found for route %s", path[1])) } // when a client did not provide a query height, manually inject the latest @@ -413,17 +430,22 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res } if req.Height <= 1 && req.Prove { - return sdk.ErrInternal("cannot query with proof when height <= 1; please provide a valid height").QueryResult() + return sdkerrors.QueryResult( + sdkerrors.Wrap( + sdkerrors.ErrInvalidRequest, + "cannot query with proof when height <= 1; please provide a valid height", + ), + ) } cacheMS, err := app.cms.CacheMultiStoreWithVersion(req.Height) if err != nil { - return sdk.ErrInternal( - fmt.Sprintf( - "failed to load state at height %d; %s (latest height: %d)", - req.Height, err, app.LastBlockHeight(), + return sdkerrors.QueryResult( + sdkerrors.Wrapf( + sdkerrors.ErrInvalidRequest, + "failed to load state at height %d; %s (latest height: %d)", req.Height, err, app.LastBlockHeight(), ), - ).QueryResult() + ) } // cache wrap the commit-multistore for safety @@ -435,18 +457,18 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res // // For example, in the path "custom/gov/proposal/test", the gov querier gets // []string{"proposal", "test"} as the path. - resBytes, queryErr := querier(ctx, path[2:], req) - if queryErr != nil { + resBytes, err := querier(ctx, path[2:], req) + if err != nil { + space, code, log := sdkerrors.ABCIInfo(err, false) return abci.ResponseQuery{ - Code: uint32(queryErr.Code()), - Codespace: string(queryErr.Codespace()), + Code: code, + Codespace: space, + Log: log, Height: req.Height, - Log: queryErr.ABCILog(), } } return abci.ResponseQuery{ - Code: uint32(sdk.CodeOK), Height: req.Height, Value: resBytes, } diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index ae1ca19db7f7..46f3e2649907 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -19,6 +19,7 @@ import ( "github.com/cosmos/cosmos-sdk/store" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) const ( @@ -446,13 +447,12 @@ func (app *BaseApp) validateHeight(req abci.RequestBeginBlock) error { } // validateBasicTxMsgs executes basic validator calls for messages. -func validateBasicTxMsgs(msgs []sdk.Msg) sdk.Error { +func validateBasicTxMsgs(msgs []sdk.Msg) error { if len(msgs) == 0 { - return sdk.ErrUnknownRequest("Tx.GetMsgs() must return at least one message in list") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "must contain at least one message") } for _, msg := range msgs { - // Validate the Msg. err := msg.ValidateBasic() if err != nil { return err @@ -508,11 +508,14 @@ func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context return ctx.WithMultiStore(msCache), msCache } -// runTx processes a transaction. The transactions is processed via an -// anteHandler. The provided txBytes may be nil in some cases, eg. in tests. For -// further details on transaction execution, reference the BaseApp SDK -// documentation. -func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk.Result) { +// runTx processes a transaction within a given execution mode, encoded transaction +// bytes, and the decoded transaction itself. All state transitions occur through +// a cached Context depending on the mode provided. State only gets persisted +// if all messages get executed successfully and the execution mode is DeliverTx. +// Note, gas execution info is always returned. A reference to a Result is +// returned if the tx does not run out of gas and if all the messages are valid +// and execute successfully. An error is returned otherwise. +func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (gInfo sdk.GasInfo, result *sdk.Result, err error) { // NOTE: GasWanted should be returned by the AnteHandler. GasUsed is // determined by the GasMeter. We need access to the context to get the gas // meter so we initialize upfront. @@ -523,7 +526,8 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk // only run the tx if there is block gas remaining if mode == runTxModeDeliver && ctx.BlockGasMeter().IsOutOfGas() { - return sdk.ErrOutOfGas("no block gas left to run tx").Result() + gInfo = sdk.GasInfo{GasUsed: ctx.BlockGasMeter().GasConsumed()} + return gInfo, nil, sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "no block gas left to run tx") } var startingGas uint64 @@ -534,20 +538,28 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk defer func() { if r := recover(); r != nil { switch rType := r.(type) { + // TODO: Use ErrOutOfGas instead of ErrorOutOfGas which would allow us + // to keep the stracktrace. case sdk.ErrorOutOfGas: - log := fmt.Sprintf( - "out of gas in location: %v; gasWanted: %d, gasUsed: %d", - rType.Descriptor, gasWanted, ctx.GasMeter().GasConsumed(), + err = sdkerrors.Wrap( + sdkerrors.ErrOutOfGas, fmt.Sprintf( + "out of gas in location: %v; gasWanted: %d, gasUsed: %d", + rType.Descriptor, gasWanted, ctx.GasMeter().GasConsumed(), + ), ) - result = sdk.ErrOutOfGas(log).Result() + default: - log := fmt.Sprintf("recovered: %v\nstack:\n%v", r, string(debug.Stack())) - result = sdk.ErrInternal(log).Result() + err = sdkerrors.Wrap( + sdkerrors.ErrPanic, fmt.Sprintf( + "recovered: %v\nstack:\n%v", r, string(debug.Stack()), + ), + ) } + + result = nil } - result.GasWanted = gasWanted - result.GasUsed = ctx.GasMeter().GasConsumed() + gInfo = sdk.GasInfo{GasWanted: gasWanted, GasUsed: ctx.GasMeter().GasConsumed()} }() // If BlockGasMeter() panics it will be caught by the above recover and will @@ -558,8 +570,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk defer func() { if mode == runTxModeDeliver { ctx.BlockGasMeter().ConsumeGas( - ctx.GasMeter().GasConsumedToLimit(), - "block gas meter", + ctx.GasMeter().GasConsumedToLimit(), "block gas meter", ) if ctx.BlockGasMeter().GasConsumed() < startingGas { @@ -568,20 +579,21 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk } }() - var msgs = tx.GetMsgs() + msgs := tx.GetMsgs() if err := validateBasicTxMsgs(msgs); err != nil { - return err.Result() + gInfo = sdk.GasInfo{GasUsed: ctx.BlockGasMeter().GasConsumed()} + return gInfo, nil, err } if app.anteHandler != nil { var anteCtx sdk.Context var msCache sdk.CacheMultiStore - // Cache wrap context before anteHandler call in case it aborts. + // Cache wrap context before AnteHandler call in case it aborts. // This is required for both CheckTx and DeliverTx. // Ref: https://github.com/cosmos/cosmos-sdk/issues/2772 // - // NOTE: Alternatively, we could require that anteHandler ensures that + // NOTE: Alternatively, we could require that AnteHandler ensures that // writes do not happen if aborted/failed. This may have some // performance benefits, but it'll be more difficult to get right. anteCtx, msCache = app.cacheTxContext(ctx, txBytes) @@ -589,11 +601,11 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk newCtx, err := app.anteHandler(anteCtx, tx, mode == runTxModeSimulate) if !newCtx.IsZero() { // At this point, newCtx.MultiStore() is cache-wrapped, or something else - // replaced by the ante handler. We want the original multistore, not one - // which was cache-wrapped for the ante handler. + // replaced by the AnteHandler. We want the original multistore, not one + // which was cache-wrapped for the AnteHandler. // // Also, in the case of the tx aborting, we need to track gas consumed via - // the instantiated gas meter in the ante handler, so we update the context + // the instantiated gas meter in the AnteHandler, so we update the context // prior to returning. ctx = newCtx.WithMultiStore(ms) } @@ -602,10 +614,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk gasWanted = ctx.GasMeter().Limit() if err != nil { - res := sdk.ResultFromError(err) - res.GasWanted = gasWanted - res.GasUsed = ctx.GasMeter().GasConsumed() - return res + return gInfo, nil, err } msCache.Write() @@ -615,83 +624,63 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk // MultiStore in case message processing fails. At this point, the MultiStore // is doubly cached-wrapped. runMsgCtx, msCache := app.cacheTxContext(ctx, txBytes) - result = app.runMsgs(runMsgCtx, msgs, mode) - result.GasWanted = gasWanted - // Safety check: don't write the cache state unless we're in DeliverTx. - if mode != runTxModeDeliver { - return result - } - - // only update state if all messages pass - if result.IsOK() { + // Attempt to execute all messages and only update state if all messages pass + // and we're in DeliverTx. Note, runMsgs will never return a reference to a + // Result if any single message fails or does not have a registered Handler. + result, err = app.runMsgs(runMsgCtx, msgs, mode) + if err == nil && mode == runTxModeDeliver { msCache.Write() } - return result + return gInfo, result, err } -// runMsgs iterates through all the messages and executes them. -func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (result sdk.Result) { +// runMsgs iterates through a list of messages and executes them with the provided +// Context and execution mode. Messages will only be executed during simulation +// and DeliverTx. An error is returned if any single message fails or if a +// Handler does not exist for a given message route. Otherwise, a reference to a +// Result is returned. The caller must not commit state if an error is returned. +func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*sdk.Result, error) { msgLogs := make(sdk.ABCIMessageLogs, 0, len(msgs)) - data := make([]byte, 0, len(msgs)) - var ( - code sdk.CodeType - codespace sdk.CodespaceType - ) - events := sdk.EmptyEvents() - // NOTE: GasWanted is determined by ante handler and GasUsed by the GasMeter. + // NOTE: GasWanted is determined by the AnteHandler and GasUsed by the GasMeter. for i, msg := range msgs { - // match message route + // skip actual execution for (Re)CheckTx mode + if mode == runTxModeCheck || mode == runTxModeReCheck { + break + } + msgRoute := msg.Route() handler := app.router.Route(msgRoute) if handler == nil { - return sdk.ErrUnknownRequest("unrecognized message type: " + msgRoute).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message route: %s; message index: %d", msgRoute, i) } - var msgResult sdk.Result - - // skip actual execution for CheckTx and ReCheckTx mode - if mode != runTxModeCheck && mode != runTxModeReCheck { - msgResult = handler(ctx, msg) + msgResult, err := handler(ctx, msg) + if err != nil { + return nil, sdkerrors.Wrapf(err, "failed to execute message; message index: %d", i) } - // Each message result's Data must be length prefixed in order to separate - // each result. - data = append(data, msgResult.Data...) - - msgEvents := msgResult.Events - - // append events from the message's execution and a message action event - msgEvents = msgEvents.AppendEvent( + msgEvents := sdk.Events{ sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyAction, msg.Type())), - ) - - events = events.AppendEvents(msgEvents) - - // stop execution and return on first failed message - if !msgResult.IsOK() { - msgLogs = append(msgLogs, sdk.NewABCIMessageLog(uint16(i), false, msgResult.Log, msgEvents)) - - code = msgResult.Code - codespace = msgResult.Codespace - break } + msgEvents = msgEvents.AppendEvents(msgResult.Events) - msgLogs = append(msgLogs, sdk.NewABCIMessageLog(uint16(i), true, msgResult.Log, msgEvents)) - } - - result = sdk.Result{ - Code: code, - Codespace: codespace, - Data: data, - Log: strings.TrimSpace(msgLogs.String()), - GasUsed: ctx.GasMeter().GasConsumed(), - Events: events, + // append message events, data and logs + // + // Note: Each message result's data must be length-prefixed in order to + // separate each result. + events = events.AppendEvents(msgEvents) + data = append(data, msgResult.Data...) + msgLogs = append(msgLogs, sdk.NewABCIMessageLog(uint16(i), msgResult.Log, msgEvents)) } - return result + return &sdk.Result{ + Data: data, + Log: strings.TrimSpace(msgLogs.String()), + Events: events, + }, nil } diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 52df9bbef0ed..01996e27ef40 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -514,8 +514,8 @@ func (tx *txTest) setFailOnHandler(fail bool) { } // Implements Tx -func (tx txTest) GetMsgs() []sdk.Msg { return tx.Msgs } -func (tx txTest) ValidateBasic() sdk.Error { return nil } +func (tx txTest) GetMsgs() []sdk.Msg { return tx.Msgs } +func (tx txTest) ValidateBasic() error { return nil } const ( routeMsgCounter = "msgCounter" @@ -534,19 +534,20 @@ func (msg msgCounter) Route() string { return routeMsgCounter } func (msg msgCounter) Type() string { return "counter1" } func (msg msgCounter) GetSignBytes() []byte { return nil } func (msg msgCounter) GetSigners() []sdk.AccAddress { return nil } -func (msg msgCounter) ValidateBasic() sdk.Error { +func (msg msgCounter) ValidateBasic() error { if msg.Counter >= 0 { return nil } - return sdk.ErrInvalidSequence("counter should be a non-negative integer.") + return sdkerrors.Wrap(sdkerrors.ErrInvalidSequence, "counter should be a non-negative integer") } -func newTxCounter(txInt int64, msgInts ...int64) *txTest { - msgs := make([]sdk.Msg, 0, len(msgInts)) - for _, msgInt := range msgInts { - msgs = append(msgs, msgCounter{msgInt, false}) +func newTxCounter(counter int64, msgCounters ...int64) *txTest { + msgs := make([]sdk.Msg, 0, len(msgCounters)) + for _, c := range msgCounters { + msgs = append(msgs, msgCounter{c, false}) } - return &txTest{msgs, txInt, false} + + return &txTest{msgs, counter, false} } // a msg we dont know how to route @@ -573,24 +574,26 @@ func (msg msgCounter2) Route() string { return routeMsgCounter2 } func (msg msgCounter2) Type() string { return "counter2" } func (msg msgCounter2) GetSignBytes() []byte { return nil } func (msg msgCounter2) GetSigners() []sdk.AccAddress { return nil } -func (msg msgCounter2) ValidateBasic() sdk.Error { +func (msg msgCounter2) ValidateBasic() error { if msg.Counter >= 0 { return nil } - return sdk.ErrInvalidSequence("counter should be a non-negative integer.") + return sdkerrors.Wrap(sdkerrors.ErrInvalidSequence, "counter should be a non-negative integer") } // amino decode func testTxDecoder(cdc *codec.Codec) sdk.TxDecoder { - return func(txBytes []byte) (sdk.Tx, sdk.Error) { + return func(txBytes []byte) (sdk.Tx, error) { var tx txTest if len(txBytes) == 0 { - return nil, sdk.ErrTxDecode("txBytes are empty") + return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty") } + err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx) if err != nil { - return nil, sdk.ErrTxDecode("").TraceSDK(err.Error()) + return nil, sdkerrors.ErrTxDecode } + return tx, nil } } @@ -604,25 +607,28 @@ func anteHandlerTxTest(t *testing.T, capKey sdk.StoreKey, storeKey []byte) sdk.A return newCtx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "ante handler failure") } - res := incrementingCounter(t, store, storeKey, txTest.Counter) - if !res.IsOK() { - err = sdkerrors.ABCIError(string(res.Codespace), uint32(res.Code), res.Log) + _, err = incrementingCounter(t, store, storeKey, txTest.Counter) + if err != nil { + return newCtx, err } - return + + return newCtx, nil } } func handlerMsgCounter(t *testing.T, capKey sdk.StoreKey, deliverKey []byte) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { store := ctx.KVStore(capKey) var msgCount int64 + switch m := msg.(type) { case *msgCounter: if m.FailOnHandler { - return sdk.ErrInternal("message handler failure").Result() + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "message handler failure") } msgCount = m.Counter + case *msgCounter2: msgCount = m.Counter } @@ -651,11 +657,11 @@ func setIntOnStore(store sdk.KVStore, key []byte, i int64) { // check counter matches what's in store. // increment and store -func incrementingCounter(t *testing.T, store sdk.KVStore, counterKey []byte, counter int64) (res sdk.Result) { +func incrementingCounter(t *testing.T, store sdk.KVStore, counterKey []byte, counter int64) (*sdk.Result, error) { storedCounter := getIntFromStore(store, counterKey) require.Equal(t, storedCounter, counter) setIntOnStore(store, counterKey, counter+1) - return + return &sdk.Result{}, nil } //--------------------------------------------------------------------- @@ -675,7 +681,9 @@ func TestCheckTx(t *testing.T) { anteOpt := func(bapp *BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, counterKey)) } routerOpt := func(bapp *BaseApp) { // TODO: can remove this once CheckTx doesnt process msgs. - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { return sdk.Result{} }) + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + return &sdk.Result{}, nil + }) } app := setupBaseApp(t, anteOpt, routerOpt) @@ -847,9 +855,9 @@ func TestSimulateTx(t *testing.T) { } routerOpt := func(bapp *BaseApp) { - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx.GasMeter().ConsumeGas(gasConsumed, "test") - return sdk.Result{GasUsed: ctx.GasMeter().GasConsumed()} + return &sdk.Result{}, nil }) } @@ -872,14 +880,16 @@ func TestSimulateTx(t *testing.T) { require.Nil(t, err) // simulate a message, check gas reported - result := app.Simulate(txBytes, tx) - require.True(t, result.IsOK(), result.Log) - require.Equal(t, gasConsumed, result.GasUsed) + gInfo, result, err := app.Simulate(txBytes, tx) + require.NoError(t, err) + require.NotNil(t, result) + require.Equal(t, gasConsumed, gInfo.GasUsed) // simulate again, same result - result = app.Simulate(txBytes, tx) - require.True(t, result.IsOK(), result.Log) - require.Equal(t, gasConsumed, result.GasUsed) + gInfo, result, err = app.Simulate(txBytes, tx) + require.NoError(t, err) + require.NotNil(t, result) + require.Equal(t, gasConsumed, gInfo.GasUsed) // simulate by calling Query with encoded tx query := abci.RequestQuery{ @@ -889,11 +899,10 @@ func TestSimulateTx(t *testing.T) { queryResult := app.Query(query) require.True(t, queryResult.IsOK(), queryResult.Log) - var res sdk.Result - codec.Cdc.MustUnmarshalBinaryLengthPrefixed(queryResult.Value, &res) - require.Nil(t, err, "Result unmarshalling failed") - require.True(t, res.IsOK(), res.Log) - require.Equal(t, gasConsumed, res.GasUsed, res.Log) + var res uint64 + err = codec.Cdc.UnmarshalBinaryLengthPrefixed(queryResult.Value, &res) + require.NoError(t, err) + require.Equal(t, gasConsumed, res) app.EndBlock(abci.RequestEndBlock{}) app.Commit() } @@ -906,7 +915,9 @@ func TestRunInvalidTransaction(t *testing.T) { }) } routerOpt := func(bapp *BaseApp) { - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return }) + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + return &sdk.Result{}, nil + }) } app := setupBaseApp(t, anteOpt, routerOpt) @@ -914,15 +925,19 @@ func TestRunInvalidTransaction(t *testing.T) { header := abci.Header{Height: 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) - // Transaction with no messages + // transaction with no messages { emptyTx := &txTest{} - err := app.Deliver(emptyTx) - require.EqualValues(t, sdk.CodeUnknownRequest, err.Code) - require.EqualValues(t, sdk.CodespaceRoot, err.Codespace) + _, result, err := app.Deliver(emptyTx) + require.Error(t, err) + require.Nil(t, result) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrInvalidRequest.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrInvalidRequest.ABCICode(), code, err) } - // Transaction where ValidateBasic fails + // transaction where ValidateBasic fails { testCases := []struct { tx *txTest @@ -940,27 +955,39 @@ func TestRunInvalidTransaction(t *testing.T) { for _, testCase := range testCases { tx := testCase.tx - res := app.Deliver(tx) + _, result, err := app.Deliver(tx) + if testCase.fail { - require.EqualValues(t, sdk.CodeInvalidSequence, res.Code) - require.EqualValues(t, sdk.CodespaceRoot, res.Codespace) + require.Error(t, err) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrInvalidSequence.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrInvalidSequence.ABCICode(), code, err) } else { - require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) + require.NotNil(t, result) } } } - // Transaction with no known route + // transaction with no known route { unknownRouteTx := txTest{[]sdk.Msg{msgNoRoute{}}, 0, false} - err := app.Deliver(unknownRouteTx) - require.EqualValues(t, sdk.CodeUnknownRequest, err.Code) - require.EqualValues(t, sdk.CodespaceRoot, err.Codespace) + _, result, err := app.Deliver(unknownRouteTx) + require.Error(t, err) + require.Nil(t, result) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), code, err) unknownRouteTx = txTest{[]sdk.Msg{msgCounter{}, msgNoRoute{}}, 0, false} - err = app.Deliver(unknownRouteTx) - require.EqualValues(t, sdk.CodeUnknownRequest, err.Code) - require.EqualValues(t, sdk.CodespaceRoot, err.Codespace) + _, result, err = app.Deliver(unknownRouteTx) + require.Error(t, err) + require.Nil(t, result) + + space, code, _ = sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), code, err) } // Transaction with an unregistered message @@ -975,9 +1002,10 @@ func TestRunInvalidTransaction(t *testing.T) { txBytes, err := newCdc.MarshalBinaryLengthPrefixed(tx) require.NoError(t, err) + res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) - require.EqualValues(t, sdk.CodeTxDecode, res.Code) - require.EqualValues(t, sdk.CodespaceRoot, res.Codespace) + require.EqualValues(t, sdkerrors.ErrTxDecode.ABCICode(), res.Code) + require.EqualValues(t, sdkerrors.ErrTxDecode.Codespace(), res.Codespace) } } @@ -996,8 +1024,7 @@ func TestTxGasLimits(t *testing.T) { if r := recover(); r != nil { switch rType := r.(type) { case sdk.ErrorOutOfGas: - log := fmt.Sprintf("out of gas in location: %v", rType.Descriptor) - err = sdkerrors.Wrap(sdkerrors.ErrOutOfGas, log) + err = sdkerrors.Wrapf(sdkerrors.ErrOutOfGas, "out of gas in location: %v", rType.Descriptor) default: panic(r) } @@ -1007,16 +1034,16 @@ func TestTxGasLimits(t *testing.T) { count := tx.(*txTest).Counter newCtx.GasMeter().ConsumeGas(uint64(count), "counter-ante") - return + return newCtx, nil }) } routerOpt := func(bapp *BaseApp) { - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { count := msg.(msgCounter).Counter ctx.GasMeter().ConsumeGas(uint64(count), "counter-handler") - return sdk.Result{} + return &sdk.Result{}, nil }) } @@ -1051,17 +1078,21 @@ func TestTxGasLimits(t *testing.T) { for i, tc := range testCases { tx := tc.tx - res := app.Deliver(tx) + gInfo, result, err := app.Deliver(tx) // check gas used and wanted - require.Equal(t, tc.gasUsed, res.GasUsed, fmt.Sprintf("%d: %v, %v", i, tc, res)) + require.Equal(t, tc.gasUsed, gInfo.GasUsed, fmt.Sprintf("tc #%d; gas: %v, result: %v, err: %s", i, gInfo, result, err)) // check for out of gas if !tc.fail { - require.True(t, res.IsOK(), fmt.Sprintf("%d: %v, %v", i, tc, res)) + require.NotNil(t, result, fmt.Sprintf("%d: %v, %v", i, tc, err)) } else { - require.Equal(t, sdk.CodeOutOfGas, res.Code, fmt.Sprintf("%d: %v, %v", i, tc, res)) - require.Equal(t, sdk.CodespaceRoot, res.Codespace) + require.Error(t, err) + require.Nil(t, result) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrOutOfGas.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrOutOfGas.ABCICode(), code, err) } } } @@ -1093,10 +1124,10 @@ func TestMaxBlockGasLimits(t *testing.T) { } routerOpt := func(bapp *BaseApp) { - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { count := msg.(msgCounter).Counter ctx.GasMeter().ConsumeGas(uint64(count), "counter-handler") - return sdk.Result{} + return &sdk.Result{}, nil }) } @@ -1137,23 +1168,29 @@ func TestMaxBlockGasLimits(t *testing.T) { // execute the transaction multiple times for j := 0; j < tc.numDelivers; j++ { - res := app.Deliver(tx) + _, result, err := app.Deliver(tx) ctx := app.getState(runTxModeDeliver).ctx - blockGasUsed := ctx.BlockGasMeter().GasConsumed() // check for failed transactions if tc.fail && (j+1) > tc.failAfterDeliver { - require.Equal(t, res.Code, sdk.CodeOutOfGas, fmt.Sprintf("%d: %v, %v", i, tc, res)) - require.Equal(t, res.Codespace, sdk.CodespaceRoot, fmt.Sprintf("%d: %v, %v", i, tc, res)) + require.Error(t, err, fmt.Sprintf("tc #%d; result: %v, err: %s", i, result, err)) + require.Nil(t, result, fmt.Sprintf("tc #%d; result: %v, err: %s", i, result, err)) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrOutOfGas.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrOutOfGas.ABCICode(), code, err) require.True(t, ctx.BlockGasMeter().IsOutOfGas()) } else { // check gas used and wanted + blockGasUsed := ctx.BlockGasMeter().GasConsumed() expBlockGasUsed := tc.gasUsedPerDeliver * uint64(j+1) - require.Equal(t, expBlockGasUsed, blockGasUsed, - fmt.Sprintf("%d,%d: %v, %v, %v, %v", i, j, tc, expBlockGasUsed, blockGasUsed, res)) + require.Equal( + t, expBlockGasUsed, blockGasUsed, + fmt.Sprintf("%d,%d: %v, %v, %v, %v", i, j, tc, expBlockGasUsed, blockGasUsed, result), + ) - require.True(t, res.IsOK(), fmt.Sprintf("%d,%d: %v, %v", i, j, tc, res)) + require.NotNil(t, result, fmt.Sprintf("tc #%d; currDeliver: %d, result: %v, err: %s", i, j, result, err)) require.False(t, ctx.BlockGasMeter().IsPastLimit()) } } @@ -1260,10 +1297,10 @@ func TestGasConsumptionBadTx(t *testing.T) { } routerOpt := func(bapp *BaseApp) { - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { count := msg.(msgCounter).Counter ctx.GasMeter().ConsumeGas(uint64(count), "counter-handler") - return sdk.Result{} + return &sdk.Result{}, nil }) } @@ -1313,10 +1350,10 @@ func TestQuery(t *testing.T) { } routerOpt := func(bapp *BaseApp) { - bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + bapp.Router().AddRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { store := ctx.KVStore(capKey1) store.Set(key, value) - return sdk.Result{} + return &sdk.Result{}, nil }) } @@ -1338,8 +1375,9 @@ func TestQuery(t *testing.T) { require.Equal(t, 0, len(res.Value)) // query is still empty after a CheckTx - resTx := app.Check(tx) - require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx)) + _, resTx, err := app.Check(tx) + require.NoError(t, err) + require.NotNil(t, resTx) res = app.Query(query) require.Equal(t, 0, len(res.Value)) @@ -1347,8 +1385,9 @@ func TestQuery(t *testing.T) { header := abci.Header{Height: app.LastBlockHeight() + 1} app.BeginBlock(abci.RequestBeginBlock{Header: header}) - resTx = app.Deliver(tx) - require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx)) + _, resTx, err = app.Deliver(tx) + require.NoError(t, err) + require.NotNil(t, resTx) res = app.Query(query) require.Equal(t, 0, len(res.Value)) diff --git a/baseapp/helpers.go b/baseapp/helpers.go index 5ea3cdcd9a77..aa9c10d328d7 100644 --- a/baseapp/helpers.go +++ b/baseapp/helpers.go @@ -10,15 +10,15 @@ import ( var isAlphaNumeric = regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString -func (app *BaseApp) Check(tx sdk.Tx) (result sdk.Result) { +func (app *BaseApp) Check(tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) { return app.runTx(runTxModeCheck, nil, tx) } -func (app *BaseApp) Simulate(txBytes []byte, tx sdk.Tx) (result sdk.Result) { +func (app *BaseApp) Simulate(txBytes []byte, tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) { return app.runTx(runTxModeSimulate, txBytes, tx) } -func (app *BaseApp) Deliver(tx sdk.Tx) (result sdk.Result) { +func (app *BaseApp) Deliver(tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) { return app.runTx(runTxModeDeliver, nil, tx) } diff --git a/baseapp/queryrouter_test.go b/baseapp/queryrouter_test.go index 7743028313cc..c7637f17000e 100644 --- a/baseapp/queryrouter_test.go +++ b/baseapp/queryrouter_test.go @@ -10,7 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -var testQuerier = func(_ sdk.Context, _ []string, _ abci.RequestQuery) (res []byte, err sdk.Error) { +var testQuerier = func(_ sdk.Context, _ []string, _ abci.RequestQuery) ([]byte, error) { return nil, nil } diff --git a/baseapp/router_test.go b/baseapp/router_test.go index 86e09cf21b79..1a6d999bcce6 100644 --- a/baseapp/router_test.go +++ b/baseapp/router_test.go @@ -8,8 +8,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -var testHandler = func(_ sdk.Context, _ sdk.Msg) sdk.Result { - return sdk.Result{} +var testHandler = func(_ sdk.Context, _ sdk.Msg) (*sdk.Result, error) { + return &sdk.Result{}, nil } func TestRouter(t *testing.T) { diff --git a/client/context/broadcast.go b/client/context/broadcast.go index 1996c47d99cb..67251b6da89d 100644 --- a/client/context/broadcast.go +++ b/client/context/broadcast.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // BroadcastTx broadcasts a transactions either synchronously or asynchronously @@ -52,19 +53,19 @@ func CheckTendermintError(err error, txBytes []byte) *sdk.TxResponse { switch { case strings.Contains(errStr, strings.ToLower(mempool.ErrTxInCache.Error())): return &sdk.TxResponse{ - Code: uint32(sdk.CodeTxInMempoolCache), + Code: sdkerrors.ErrTxInMempoolCache.ABCICode(), TxHash: txHash, } case strings.Contains(errStr, "mempool is full"): return &sdk.TxResponse{ - Code: uint32(sdk.CodeMempoolIsFull), + Code: sdkerrors.ErrMempoolIsFull.ABCICode(), TxHash: txHash, } case strings.Contains(errStr, "tx too large"): return &sdk.TxResponse{ - Code: uint32(sdk.CodeTxTooLarge), + Code: sdkerrors.ErrTxTooLarge.ABCICode(), TxHash: txHash, } diff --git a/client/context/broadcast_test.go b/client/context/broadcast_test.go index 2afddb8f3524..530645b9d187 100644 --- a/client/context/broadcast_test.go +++ b/client/context/broadcast_test.go @@ -4,16 +4,15 @@ import ( "fmt" "testing" - "github.com/tendermint/tendermint/crypto/tmhash" - "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/mempool" "github.com/tendermint/tendermint/rpc/client/mock" ctypes "github.com/tendermint/tendermint/rpc/core/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) type MockClient struct { @@ -43,9 +42,9 @@ func CreateContextWithErrorAndMode(err error, mode string) CLIContext { // Test the correct code is returned when func TestBroadcastError(t *testing.T) { errors := map[error]uint32{ - mempool.ErrTxInCache: uint32(types.CodeTxInMempoolCache), - mempool.ErrTxTooLarge{}: uint32(types.CodeTxTooLarge), - mempool.ErrMempoolIsFull{}: uint32(types.CodeMempoolIsFull), + mempool.ErrTxInCache: sdkerrors.ErrTxInMempoolCache.ABCICode(), + mempool.ErrTxTooLarge{}: sdkerrors.ErrTxTooLarge.ABCICode(), + mempool.ErrMempoolIsFull{}: sdkerrors.ErrMempoolIsFull.ABCICode(), } modes := []string{ diff --git a/docs/architecture/adr-015-ibc-packet-receiver.md b/docs/architecture/adr-015-ibc-packet-receiver.md index e772c3234c47..2ea26dcb5bae 100644 --- a/docs/architecture/adr-015-ibc-packet-receiver.md +++ b/docs/architecture/adr-015-ibc-packet-receiver.md @@ -204,7 +204,7 @@ type PacketDataI interface { GetCommitment() []byte // Commitment form that will be stored in the state. GetTimeoutHeight() uint64 - ValidateBasic() sdk.Error + ValidateBasic() error Type() string } ``` diff --git a/docs/building-modules/handler.md b/docs/building-modules/handler.md index 3b19bf9603a9..37b46511a09a 100644 --- a/docs/building-modules/handler.md +++ b/docs/building-modules/handler.md @@ -25,19 +25,24 @@ Let us break it down: ## Implementation of a module `handler`s -Module `handler`s are typically implemented in a `./handler.go` file inside the module's folder. The [module manager](./module-manager.md) is used to add the module's `handler`s to the [application's `router`](../core/baseapp.md#message-routing) via the `NewHandler()` method. Typically, the manager's `NewHandler()` method simply calls a `NewHandler()` method defined in `handler.go`, which looks like the following: +Module `handler`s are typically implemented in a `./handler.go` file inside the module's folder. The +[module manager](./module-manager.md) is used to add the module's `handler`s to the +[application's `router`](../core/baseapp.md#message-routing) via the `NewHandler()` method. Typically, +the manager's `NewHandler()` method simply calls a `NewHandler()` method defined in `handler.go`, +which looks like the following: ```go func NewHandler(keeper Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { switch msg := msg.(type) { case MsgType1: return handleMsgType1(ctx, keeper, msg) + case MsgType2: return handleMsgType2(ctx, keeper, msg) + default: - errMsg := fmt.Sprintf("Unrecognized nameservice Msg type: %v", msg.Type()) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } } } diff --git a/docs/building-modules/querier.md b/docs/building-modules/querier.md index 02c334fc3843..be4750778661 100644 --- a/docs/building-modules/querier.md +++ b/docs/building-modules/querier.md @@ -29,14 +29,16 @@ Module `querier`s are typically implemented in a `./internal/keeper/querier.go` ```go func NewQuerier(keeper Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case QueryType1: return queryType1(ctx, path[1:], req, keeper) + case QueryType2: return queryType2(ctx, path[1:], req, keeper) + default: - return nil, sdk.ErrUnknownRequest("unknown nameservice query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } } } diff --git a/server/mock/app.go b/server/mock/app.go index 9063bb7c5ea1..d1e1146d6a57 100644 --- a/server/mock/app.go +++ b/server/mock/app.go @@ -2,6 +2,7 @@ package mock import ( "encoding/json" + "errors" "fmt" "path/filepath" @@ -49,10 +50,10 @@ func NewApp(rootDir string, logger log.Logger) (abci.Application, error) { // KVStoreHandler is a simple handler that takes kvstoreTx and writes // them to the db func KVStoreHandler(storeKey sdk.StoreKey) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { dTx, ok := msg.(kvstoreTx) if !ok { - panic("KVStoreHandler should only receive kvstoreTx") + return nil, errors.New("KVStoreHandler should only receive kvstoreTx") } // tx is already unmarshalled @@ -62,10 +63,9 @@ func KVStoreHandler(storeKey sdk.StoreKey) sdk.Handler { store := ctx.KVStore(storeKey) store.Set(key, value) - return sdk.Result{ - Code: 0, - Log: fmt.Sprintf("set %s=%s", key, value), - } + return &sdk.Result{ + Log: fmt.Sprintf("set %s=%s", key, value), + }, nil } } diff --git a/server/mock/tx.go b/server/mock/tx.go index 6774fb28145a..27441051ce8a 100644 --- a/server/mock/tx.go +++ b/server/mock/tx.go @@ -6,6 +6,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // An sdk.Tx which is its own sdk.Msg. @@ -47,7 +48,7 @@ func (tx kvstoreTx) GetSignBytes() []byte { } // Should the app be calling this? Or only handlers? -func (tx kvstoreTx) ValidateBasic() sdk.Error { +func (tx kvstoreTx) ValidateBasic() error { return nil } @@ -57,7 +58,7 @@ func (tx kvstoreTx) GetSigners() []sdk.AccAddress { // takes raw transaction bytes and decodes them into an sdk.Tx. An sdk.Tx has // all the signatures and can be used to authenticate. -func decodeTx(txBytes []byte) (sdk.Tx, sdk.Error) { +func decodeTx(txBytes []byte) (sdk.Tx, error) { var tx sdk.Tx split := bytes.Split(txBytes, []byte("=")) @@ -68,7 +69,7 @@ func decodeTx(txBytes []byte) (sdk.Tx, sdk.Error) { k, v := split[0], split[1] tx = kvstoreTx{k, v, txBytes} } else { - return nil, sdk.ErrTxDecode("too many =") + return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "too many '='") } return tx, nil diff --git a/simapp/app.go b/simapp/app.go index 2bd4ed3543f5..e4e4ede4e9d2 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -158,7 +158,7 @@ func NewSimApp( } // init params keeper and subspaces - app.ParamsKeeper = params.NewKeeper(app.cdc, keys[params.StoreKey], tkeys[params.TStoreKey], params.DefaultCodespace) + app.ParamsKeeper = params.NewKeeper(app.cdc, keys[params.StoreKey], tkeys[params.TStoreKey]) app.subspaces[auth.ModuleName] = app.ParamsKeeper.Subspace(auth.DefaultParamspace) app.subspaces[bank.ModuleName] = app.ParamsKeeper.Subspace(bank.DefaultParamspace) app.subspaces[staking.ModuleName] = app.ParamsKeeper.Subspace(staking.DefaultParamspace) @@ -174,25 +174,24 @@ func NewSimApp( app.cdc, keys[auth.StoreKey], app.subspaces[auth.ModuleName], auth.ProtoBaseAccount, ) app.BankKeeper = bank.NewBaseKeeper( - app.AccountKeeper, app.subspaces[bank.ModuleName], bank.DefaultCodespace, - app.BlacklistedAccAddrs(), + app.AccountKeeper, app.subspaces[bank.ModuleName], app.BlacklistedAccAddrs(), ) app.SupplyKeeper = supply.NewKeeper( app.cdc, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms, ) stakingKeeper := staking.NewKeeper( app.cdc, keys[staking.StoreKey], app.SupplyKeeper, app.subspaces[staking.ModuleName], - staking.DefaultCodespace) + ) app.MintKeeper = mint.NewKeeper( app.cdc, keys[mint.StoreKey], app.subspaces[mint.ModuleName], &stakingKeeper, app.SupplyKeeper, auth.FeeCollectorName, ) app.DistrKeeper = distr.NewKeeper( app.cdc, keys[distr.StoreKey], app.subspaces[distr.ModuleName], &stakingKeeper, - app.SupplyKeeper, distr.DefaultCodespace, auth.FeeCollectorName, app.ModuleAccountAddrs(), + app.SupplyKeeper, auth.FeeCollectorName, app.ModuleAccountAddrs(), ) app.SlashingKeeper = slashing.NewKeeper( - app.cdc, keys[slashing.StoreKey], &stakingKeeper, app.subspaces[slashing.ModuleName], slashing.DefaultCodespace, + app.cdc, keys[slashing.StoreKey], &stakingKeeper, app.subspaces[slashing.ModuleName], ) app.CrisisKeeper = crisis.NewKeeper( app.subspaces[crisis.ModuleName], invCheckPeriod, app.SupplyKeeper, auth.FeeCollectorName, @@ -201,8 +200,7 @@ func NewSimApp( // create evidence keeper with router evidenceKeeper := evidence.NewKeeper( - app.cdc, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], evidence.DefaultCodespace, - &app.StakingKeeper, app.SlashingKeeper, + app.cdc, keys[evidence.StoreKey], app.subspaces[evidence.ModuleName], &app.StakingKeeper, app.SlashingKeeper, ) evidenceRouter := evidence.NewRouter() // TODO: Register evidence routes. @@ -217,7 +215,7 @@ func NewSimApp( AddRoute(upgrade.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)) app.GovKeeper = gov.NewKeeper( app.cdc, keys[gov.StoreKey], app.subspaces[gov.ModuleName], app.SupplyKeeper, - &stakingKeeper, gov.DefaultCodespace, govRouter, + &stakingKeeper, govRouter, ) // register the staking hooks diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index 0e6d22150255..d132394c9bc7 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -115,7 +115,7 @@ func CheckBalance(t *testing.T, app *SimApp, addr sdk.AccAddress, exp sdk.Coins) func SignCheckDeliver( t *testing.T, cdc *codec.Codec, app *bam.BaseApp, header abci.Header, msgs []sdk.Msg, accNums, seq []uint64, expSimPass, expPass bool, priv ...crypto.PrivKey, -) sdk.Result { +) (sdk.GasInfo, *sdk.Result, error) { tx := helpers.GenTx( msgs, @@ -131,28 +131,32 @@ func SignCheckDeliver( require.Nil(t, err) // Must simulate now as CheckTx doesn't run Msgs anymore - res := app.Simulate(txBytes, tx) + _, res, err := app.Simulate(txBytes, tx) if expSimPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.NoError(t, err) + require.NotNil(t, res) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.Error(t, err) + require.Nil(t, res) } // Simulate a sending a transaction and committing a block app.BeginBlock(abci.RequestBeginBlock{Header: header}) - res = app.Deliver(tx) + gInfo, res, err := app.Deliver(tx) if expPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.NoError(t, err) + require.NotNil(t, res) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.Error(t, err) + require.Nil(t, res) } app.EndBlock(abci.RequestEndBlock{}) app.Commit() - return res + return gInfo, res, err } // GenSequenceOfTxs generates a set of signed transactions of messages, such diff --git a/store/errors/errors.go b/store/errors/errors.go deleted file mode 100644 index 98e1b8aa1330..000000000000 --- a/store/errors/errors.go +++ /dev/null @@ -1,26 +0,0 @@ -package errors - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" -) - -const ( - CodeOK = sdk.CodeOK - CodeInternal = sdk.CodeInternal - CodeTxDecode = sdk.CodeTxDecode - CodeUnknownRequest = sdk.CodeUnknownRequest - - CodespaceRoot = sdk.CodespaceRoot -) - -type Error = sdk.Error - -func ErrInternal(msg string) Error { - return sdk.ErrInternal(msg) -} -func ErrTxDecode(msg string) Error { - return sdk.ErrTxDecode(msg) -} -func ErrUnknownRequest(msg string) Error { - return sdk.ErrUnknownRequest(msg) -} diff --git a/store/iavl/store.go b/store/iavl/store.go index b7b94307bbe6..2faf786cd236 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -1,14 +1,13 @@ package iavl import ( - "fmt" "io" "sync" "github.com/cosmos/cosmos-sdk/store/cachekv" - serrors "github.com/cosmos/cosmos-sdk/store/errors" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/pkg/errors" "github.com/tendermint/iavl" @@ -236,8 +235,7 @@ func getHeight(tree Tree, req abci.RequestQuery) int64 { // explicitly set the height you want to see func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { if len(req.Data) == 0 { - msg := "Query cannot be zero length" - return serrors.ErrTxDecode(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrTxDecode, "query cannot be zero length")) } tree := st.tree @@ -296,8 +294,7 @@ func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { res.Value = cdc.MustMarshalBinaryLengthPrefixed(KVs) default: - msg := fmt.Sprintf("Unexpected Query path: %v", req.Path) - return serrors.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unexpected query path: %v", req.Path)) } return res diff --git a/store/iavl/store_test.go b/store/iavl/store_test.go index b70be1dee138..d7c38aa0d548 100644 --- a/store/iavl/store_test.go +++ b/store/iavl/store_test.go @@ -11,7 +11,6 @@ import ( cmn "github.com/tendermint/tendermint/libs/common" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/store/errors" "github.com/cosmos/cosmos-sdk/store/types" ) @@ -497,7 +496,7 @@ func TestIAVLStoreQuery(t *testing.T) { // query subspace before anything set qres := iavlStore.Query(querySub) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, valExpSubEmpty, qres.Value) // set data @@ -506,24 +505,24 @@ func TestIAVLStoreQuery(t *testing.T) { // set data without commit, doesn't show up qres = iavlStore.Query(query) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Nil(t, qres.Value) // commit it, but still don't see on old version cid = iavlStore.Commit() qres = iavlStore.Query(query) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Nil(t, qres.Value) // but yes on the new version query.Height = cid.Version qres = iavlStore.Query(query) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, v1, qres.Value) // and for the subspace qres = iavlStore.Query(querySub) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, valExpSub1, qres.Value) // modify @@ -532,28 +531,28 @@ func TestIAVLStoreQuery(t *testing.T) { // query will return old values, as height is fixed qres = iavlStore.Query(query) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, v1, qres.Value) // update to latest in the query and we are happy query.Height = cid.Version qres = iavlStore.Query(query) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, v3, qres.Value) query2 := abci.RequestQuery{Path: "/key", Data: k2, Height: cid.Version} qres = iavlStore.Query(query2) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, v2, qres.Value) // and for the subspace qres = iavlStore.Query(querySub) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, valExpSub2, qres.Value) // default (height 0) will show latest -1 query0 := abci.RequestQuery{Path: "/key", Data: k1} qres = iavlStore.Query(query0) - require.Equal(t, uint32(errors.CodeOK), qres.Code) + require.Equal(t, uint32(0), qres.Code) require.Equal(t, v1, qres.Value) } diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 4f3d212e4914..0b22d5442cb0 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -12,11 +12,11 @@ import ( "github.com/cosmos/cosmos-sdk/store/cachemulti" "github.com/cosmos/cosmos-sdk/store/dbadapter" - "github.com/cosmos/cosmos-sdk/store/errors" "github.com/cosmos/cosmos-sdk/store/iavl" "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/transient" "github.com/cosmos/cosmos-sdk/store/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) const ( @@ -408,19 +408,17 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { path := req.Path storeName, subpath, err := parsePath(path) if err != nil { - return err.QueryResult() + return sdkerrors.QueryResult(err) } store := rs.getStoreByName(storeName) if store == nil { - msg := fmt.Sprintf("no such store: %s", storeName) - return errors.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "no such store: %s", storeName)) } queryable, ok := store.(types.Queryable) if !ok { - msg := fmt.Sprintf("store %s (type %T) doesn't support queries", storeName, store) - return errors.ErrUnknownRequest(msg).QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "store %s (type %T) doesn't support queries", storeName, store)) } // trim the path and make the query @@ -432,12 +430,12 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { } if res.Proof == nil || len(res.Proof.Ops) == 0 { - return errors.ErrInternal("proof is unexpectedly empty; ensure height has not been pruned").QueryResult() + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "proof is unexpectedly empty; ensure height has not been pruned")) } commitInfo, errMsg := getCommitInfo(rs.db, res.Height) if errMsg != nil { - return errors.ErrInternal(errMsg.Error()).QueryResult() + return sdkerrors.QueryResult(err) } // Restore origin path and append proof op. @@ -454,10 +452,9 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { // parsePath expects a format like /[/] // Must start with /, subpath may be empty // Returns error if it doesn't start with / -func parsePath(path string) (storeName string, subpath string, err errors.Error) { +func parsePath(path string) (storeName string, subpath string, err error) { if !strings.HasPrefix(path, "/") { - err = errors.ErrUnknownRequest(fmt.Sprintf("invalid path: %s", path)) - return + return storeName, subpath, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid path: %s", path) } paths := strings.SplitN(path[1:], "/", 2) @@ -467,7 +464,7 @@ func parsePath(path string) (storeName string, subpath string, err errors.Error) subpath = "/" + paths[1] } - return + return storeName, subpath, nil } //---------------------------------------- diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index 47b2ece360a0..16181c4080f2 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -8,9 +8,9 @@ import ( "github.com/tendermint/tendermint/crypto/merkle" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/store/errors" "github.com/cosmos/cosmos-sdk/store/iavl" "github.com/cosmos/cosmos-sdk/store/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) func TestStoreType(t *testing.T) { @@ -324,37 +324,37 @@ func TestMultiStoreQuery(t *testing.T) { // Test bad path. query := abci.RequestQuery{Path: "/key", Data: k, Height: ver} qres := multi.Query(query) - require.EqualValues(t, errors.CodeUnknownRequest, qres.Code) - require.EqualValues(t, errors.CodespaceRoot, qres.Codespace) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace) query.Path = "h897fy32890rf63296r92" qres = multi.Query(query) - require.EqualValues(t, errors.CodeUnknownRequest, qres.Code) - require.EqualValues(t, errors.CodespaceRoot, qres.Codespace) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace) // Test invalid store name. query.Path = "/garbage/key" qres = multi.Query(query) - require.EqualValues(t, errors.CodeUnknownRequest, qres.Code) - require.EqualValues(t, errors.CodespaceRoot, qres.Codespace) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), qres.Code) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), qres.Codespace) // Test valid query with data. query.Path = "/store1/key" qres = multi.Query(query) - require.EqualValues(t, errors.CodeOK, qres.Code) + require.EqualValues(t, 0, qres.Code) require.Equal(t, v, qres.Value) // Test valid but empty query. query.Path = "/store2/key" query.Prove = true qres = multi.Query(query) - require.EqualValues(t, errors.CodeOK, qres.Code) + require.EqualValues(t, 0, qres.Code) require.Nil(t, qres.Value) // Test store2 data. query.Data = k2 qres = multi.Query(query) - require.EqualValues(t, errors.CodeOK, qres.Code) + require.EqualValues(t, 0, qres.Code) require.Equal(t, v2, qres.Value) } diff --git a/types/decimal.go b/types/decimal.go index b066c3e43374..63aecf6cab18 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -2,6 +2,7 @@ package types import ( "encoding/json" + "errors" "fmt" "math/big" "strconv" @@ -33,6 +34,13 @@ var ( tenInt = big.NewInt(10) ) +// Decimal errors +var ( + ErrEmptyDecimalStr = errors.New("decimal string cannot be empty") + ErrInvalidDecimalLength = errors.New("invalid decimal length") + ErrInvalidDecimalStr = errors.New("invalid decimal string") +) + // Set precision multipliers func init() { precisionMultipliers = make([]*big.Int, Precision+1) @@ -123,9 +131,9 @@ func NewDecFromIntWithPrec(i Int, prec int64) Dec { // are provided in the string than the constant Precision. // // CONTRACT - This function does not mutate the input str. -func NewDecFromStr(str string) (d Dec, err Error) { +func NewDecFromStr(str string) (Dec, error) { if len(str) == 0 { - return d, ErrUnknownRequest("decimal string is empty") + return Dec{}, ErrEmptyDecimalStr } // first extract any negative symbol @@ -136,7 +144,7 @@ func NewDecFromStr(str string) (d Dec, err Error) { } if len(str) == 0 { - return d, ErrUnknownRequest("decimal string is empty") + return Dec{}, ErrEmptyDecimalStr } strs := strings.Split(str, ".") @@ -146,17 +154,16 @@ func NewDecFromStr(str string) (d Dec, err Error) { if len(strs) == 2 { // has a decimal place lenDecs = len(strs[1]) if lenDecs == 0 || len(combinedStr) == 0 { - return d, ErrUnknownRequest("bad decimal length") + return Dec{}, ErrInvalidDecimalLength } combinedStr += strs[1] } else if len(strs) > 2 { - return d, ErrUnknownRequest("too many periods to be a decimal string") + return Dec{}, ErrInvalidDecimalStr } if lenDecs > Precision { - return d, ErrUnknownRequest( - fmt.Sprintf("too much precision, maximum %v, len decimal %v", Precision, lenDecs)) + return Dec{}, fmt.Errorf("invalid precision; max: %d, got: %d", Precision, lenDecs) } // add some extra zero's to correct to the Precision factor @@ -166,11 +173,12 @@ func NewDecFromStr(str string) (d Dec, err Error) { combined, ok := new(big.Int).SetString(combinedStr, 10) // base 10 if !ok { - return d, ErrUnknownRequest(fmt.Sprintf("bad string to integer conversion, combinedStr: %v", combinedStr)) + return Dec{}, fmt.Errorf("failed to set decimal string: %s", combinedStr) } if neg { combined = new(big.Int).Neg(combined) } + return Dec{combined}, nil } diff --git a/types/errors.go b/types/errors.go deleted file mode 100644 index c59571bfe540..000000000000 --- a/types/errors.go +++ /dev/null @@ -1,361 +0,0 @@ -package types - -import ( - "bytes" - "encoding/json" - "fmt" - "strings" - - "github.com/pkg/errors" - - abci "github.com/tendermint/tendermint/abci/types" - cmn "github.com/tendermint/tendermint/libs/common" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -// CodeType - ABCI code identifier within codespace -type CodeType uint32 - -// CodespaceType - codespace identifier -type CodespaceType string - -// IsOK - is everything okay? -func (code CodeType) IsOK() bool { - return code == CodeOK -} - -// SDK error codes -const ( - // Base error codes - CodeOK CodeType = 0 - CodeInternal CodeType = 1 - CodeTxDecode CodeType = 2 - CodeInvalidSequence CodeType = 3 - CodeUnauthorized CodeType = 4 - CodeInsufficientFunds CodeType = 5 - CodeUnknownRequest CodeType = 6 - CodeInvalidAddress CodeType = 7 - CodeInvalidPubKey CodeType = 8 - CodeUnknownAddress CodeType = 9 - CodeInsufficientCoins CodeType = 10 - CodeInvalidCoins CodeType = 11 - CodeOutOfGas CodeType = 12 - CodeMemoTooLarge CodeType = 13 - CodeInsufficientFee CodeType = 14 - CodeTooManySignatures CodeType = 15 - CodeGasOverflow CodeType = 16 - CodeNoSignatures CodeType = 17 - CodeTxInMempoolCache CodeType = 18 - CodeMempoolIsFull CodeType = 19 - CodeTxTooLarge CodeType = 20 - - // CodespaceRoot is a codespace for error codes in this file only. - // Notice that 0 is an "unset" codespace, which can be overridden with - // Error.WithDefaultCodespace(). - CodespaceUndefined CodespaceType = "" - CodespaceRoot CodespaceType = "sdk" -) - -func unknownCodeMsg(code CodeType) string { - return fmt.Sprintf("unknown code %d", code) -} - -// NOTE: Don't stringer this, we'll put better messages in later. -func CodeToDefaultMsg(code CodeType) string { - switch code { - case CodeInternal: - return "internal error" - case CodeTxDecode: - return "tx parse error" - case CodeInvalidSequence: - return "invalid sequence" - case CodeUnauthorized: - return "unauthorized" - case CodeInsufficientFunds: - return "insufficient funds" - case CodeUnknownRequest: - return "unknown request" - case CodeInvalidAddress: - return "invalid address" - case CodeInvalidPubKey: - return "invalid pubkey" - case CodeUnknownAddress: - return "unknown address" - case CodeInsufficientCoins: - return "insufficient coins" - case CodeInvalidCoins: - return "invalid coins" - case CodeOutOfGas: - return "out of gas" - case CodeMemoTooLarge: - return "memo too large" - case CodeInsufficientFee: - return "insufficient fee" - case CodeTooManySignatures: - return "maximum numer of signatures exceeded" - case CodeNoSignatures: - return "no signatures supplied" - default: - return unknownCodeMsg(code) - } -} - -//-------------------------------------------------------------------------------- -// All errors are created via constructors so as to enable us to hijack them -// and inject stack traces if we really want to. - -// nolint -func ErrInternal(msg string) Error { - return newErrorWithRootCodespace(CodeInternal, msg) -} -func ErrTxDecode(msg string) Error { - return newErrorWithRootCodespace(CodeTxDecode, msg) -} -func ErrInvalidSequence(msg string) Error { - return newErrorWithRootCodespace(CodeInvalidSequence, msg) -} -func ErrUnauthorized(msg string) Error { - return newErrorWithRootCodespace(CodeUnauthorized, msg) -} -func ErrInsufficientFunds(msg string) Error { - return newErrorWithRootCodespace(CodeInsufficientFunds, msg) -} -func ErrUnknownRequest(msg string) Error { - return newErrorWithRootCodespace(CodeUnknownRequest, msg) -} -func ErrInvalidAddress(msg string) Error { - return newErrorWithRootCodespace(CodeInvalidAddress, msg) -} -func ErrUnknownAddress(msg string) Error { - return newErrorWithRootCodespace(CodeUnknownAddress, msg) -} -func ErrInvalidPubKey(msg string) Error { - return newErrorWithRootCodespace(CodeInvalidPubKey, msg) -} -func ErrInsufficientCoins(msg string) Error { - return newErrorWithRootCodespace(CodeInsufficientCoins, msg) -} -func ErrInvalidCoins(msg string) Error { - return newErrorWithRootCodespace(CodeInvalidCoins, msg) -} -func ErrOutOfGas(msg string) Error { - return newErrorWithRootCodespace(CodeOutOfGas, msg) -} -func ErrMemoTooLarge(msg string) Error { - return newErrorWithRootCodespace(CodeMemoTooLarge, msg) -} -func ErrInsufficientFee(msg string) Error { - return newErrorWithRootCodespace(CodeInsufficientFee, msg) -} -func ErrTooManySignatures(msg string) Error { - return newErrorWithRootCodespace(CodeTooManySignatures, msg) -} -func ErrNoSignatures(msg string) Error { - return newErrorWithRootCodespace(CodeNoSignatures, msg) -} -func ErrGasOverflow(msg string) Error { - return newErrorWithRootCodespace(CodeGasOverflow, msg) -} - -//---------------------------------------- -// Error & sdkError - -type cmnError = cmn.Error - -// sdk Error type -type Error interface { - // Implements cmn.Error - // Error() string - // Stacktrace() cmn.Error - // Trace(offset int, format string, args ...interface{}) cmn.Error - // Data() interface{} - cmnError - - // convenience - TraceSDK(format string, args ...interface{}) Error - - // set codespace - WithDefaultCodespace(CodespaceType) Error - - Code() CodeType - Codespace() CodespaceType - ABCILog() string - Result() Result - QueryResult() abci.ResponseQuery -} - -// NewError - create an error. -func NewError(codespace CodespaceType, code CodeType, format string, args ...interface{}) Error { - return newError(codespace, code, format, args...) -} - -func newErrorWithRootCodespace(code CodeType, format string, args ...interface{}) *sdkError { - return newError(CodespaceRoot, code, format, args...) -} - -func newError(codespace CodespaceType, code CodeType, format string, args ...interface{}) *sdkError { - if format == "" { - format = CodeToDefaultMsg(code) - } - return &sdkError{ - codespace: codespace, - code: code, - cmnError: cmn.NewError(format, args...), - } -} - -type sdkError struct { - codespace CodespaceType - code CodeType - cmnError -} - -// Implements Error. -func (err *sdkError) WithDefaultCodespace(cs CodespaceType) Error { - codespace := err.codespace - if codespace == CodespaceUndefined { - codespace = cs - } - return &sdkError{ - codespace: cs, - code: err.code, - cmnError: err.cmnError, - } -} - -// Implements ABCIError. -// nolint: errcheck -func (err *sdkError) TraceSDK(format string, args ...interface{}) Error { - err.Trace(1, format, args...) - return err -} - -// Implements ABCIError. -func (err *sdkError) Error() string { - return fmt.Sprintf(`ERROR: -Codespace: %s -Code: %d -Message: %#v -`, err.codespace, err.code, err.cmnError.Error()) -} - -// Implements Error. -func (err *sdkError) Codespace() CodespaceType { - return err.codespace -} - -// Implements Error. -func (err *sdkError) Code() CodeType { - return err.code -} - -// Implements ABCIError. -func (err *sdkError) ABCILog() string { - errMsg := err.cmnError.Error() - return encodeErrorLog(err.codespace, err.code, errMsg) -} - -func encodeErrorLog(codespace CodespaceType, code CodeType, msg string) string { - jsonErr := humanReadableError{ - Codespace: codespace, - Code: code, - Message: msg, - } - - var buff bytes.Buffer - enc := json.NewEncoder(&buff) - enc.SetEscapeHTML(false) - - if err := enc.Encode(jsonErr); err != nil { - panic(errors.Wrap(err, "failed to encode ABCI error log")) - } - - return strings.TrimSpace(buff.String()) -} - -func (err *sdkError) Result() Result { - return Result{ - Code: err.Code(), - Codespace: err.Codespace(), - Log: err.ABCILog(), - } -} - -// QueryResult allows us to return sdk.Error.QueryResult() in query responses -func (err *sdkError) QueryResult() abci.ResponseQuery { - return abci.ResponseQuery{ - Code: uint32(err.Code()), - Codespace: string(err.Codespace()), - Log: err.ABCILog(), - } -} - -// ResultFromError will return err.Result() if it implements sdk.Error -// Otherwise, it will use the reflecton from types/error to determine -// the code, codespace, and log. -// -// This is intended to provide a bridge to allow both error types -// to live side-by-side. -func ResultFromError(err error) Result { - if sdk, ok := err.(Error); ok { - return sdk.Result() - } - space, code, log := sdkerrors.ABCIInfo(err, false) - return Result{ - Codespace: CodespaceType(space), - Code: CodeType(code), - Log: encodeErrorLog(CodespaceType(space), CodeType(code), log), - } -} - -// ConvertError accepts a standard error and attempts to convert it to an sdk.Error. -// If the given error is already an sdk.Error, it'll simply be returned. Otherwise, -// it'll convert it to a types.Error. This is meant to provide a migration path -// away from sdk.Error in favor of types.Error. -func ConvertError(err error) Error { - if err == nil { - return nil - } - if sdkError, ok := err.(Error); ok { - return sdkError - } - - space, code, log := sdkerrors.ABCIInfo(err, false) - return NewError(CodespaceType(space), CodeType(code), log) -} - -//---------------------------------------- -// REST error utilities - -// appends a message to the head of the given error -func AppendMsgToErr(msg string, err string) string { - msgIdx := strings.Index(err, "message\":\"") - if msgIdx != -1 { - errMsg := err[msgIdx+len("message\":\"") : len(err)-2] - errMsg = fmt.Sprintf("%s; %s", msg, errMsg) - return fmt.Sprintf("%s%s%s", - err[:msgIdx+len("message\":\"")], - errMsg, - err[len(err)-2:], - ) - } - return fmt.Sprintf("%s; %s", msg, err) -} - -// returns the index of the message in the ABCI Log -// nolint:deadcode,unused -func mustGetMsgIndex(abciLog string) int { - msgIdx := strings.Index(abciLog, "message\":\"") - if msgIdx == -1 { - panic(fmt.Sprintf("invalid error format: %s", abciLog)) - } - return msgIdx + len("message\":\"") -} - -// parses the error into an object-like struct for exporting -type humanReadableError struct { - Codespace CodespaceType `json:"codespace"` - Code CodeType `json:"code"` - Message string `json:"message"` -} diff --git a/types/errors/abci.go b/types/errors/abci.go index 1f70758cdd1b..cc5633543192 100644 --- a/types/errors/abci.go +++ b/types/errors/abci.go @@ -4,6 +4,8 @@ import ( "errors" "fmt" "reflect" + + abci "github.com/tendermint/tendermint/abci/types" ) const ( @@ -40,6 +42,43 @@ func ABCIInfo(err error, debug bool) (codespace string, code uint32, log string) return abciCodespace(err), abciCode(err), encode(err) } +// ResponseCheckTx returns an ABCI ResponseCheckTx object with fields filled in +// from the given error and gas values. +func ResponseCheckTx(err error, gw, gu uint64) abci.ResponseCheckTx { + space, code, log := ABCIInfo(err, false) + return abci.ResponseCheckTx{ + Codespace: space, + Code: code, + Log: log, + GasWanted: int64(gw), + GasUsed: int64(gu), + } +} + +// ResponseDeliverTx returns an ABCI ResponseDeliverTx object with fields filled in +// from the given error and gas values. +func ResponseDeliverTx(err error, gw, gu uint64) abci.ResponseDeliverTx { + space, code, log := ABCIInfo(err, false) + return abci.ResponseDeliverTx{ + Codespace: space, + Code: code, + Log: log, + GasWanted: int64(gw), + GasUsed: int64(gu), + } +} + +// QueryResult returns a ResponseQuery from an error. It will try to parse ABCI +// info from the error. +func QueryResult(err error) abci.ResponseQuery { + space, code, log := ABCIInfo(err, false) + return abci.ResponseQuery{ + Codespace: space, + Code: code, + Log: log, + } +} + // The debugErrEncoder encodes the error with a stacktrace. func debugErrEncoder(err error) string { return fmt.Sprintf("%+v", err) diff --git a/types/errors/abci_test.go b/types/errors/abci_test.go index 20b4f74b6f8b..c098811ea474 100644 --- a/types/errors/abci_test.go +++ b/types/errors/abci_test.go @@ -15,17 +15,17 @@ func TestABCInfo(t *testing.T) { wantSpace string wantLog string }{ - "plain weave error": { + "plain SDK error": { err: ErrUnauthorized, debug: false, wantLog: "unauthorized", wantCode: ErrUnauthorized.code, wantSpace: RootCodespace, }, - "wrapped weave error": { + "wrapped SDK error": { err: Wrap(Wrap(ErrUnauthorized, "foo"), "bar"), debug: false, - wantLog: "bar: foo: unauthorized", + wantLog: "unauthorized: foo: bar", wantCode: ErrUnauthorized.code, wantSpace: RootCodespace, }, @@ -36,7 +36,7 @@ func TestABCInfo(t *testing.T) { wantCode: 0, wantSpace: "", }, - "nil weave error is not an error": { + "nil SDK error is not an error": { err: (*Error)(nil), debug: false, wantLog: "", @@ -112,23 +112,23 @@ func TestABCIInfoStacktrace(t *testing.T) { wantStacktrace bool wantErrMsg string }{ - "wrapped weave error in debug mode provides stacktrace": { + "wrapped SDK error in debug mode provides stacktrace": { err: Wrap(ErrUnauthorized, "wrapped"), debug: true, wantStacktrace: true, - wantErrMsg: "wrapped: unauthorized", + wantErrMsg: "unauthorized: wrapped", }, - "wrapped weave error in non-debug mode does not have stacktrace": { + "wrapped SDK error in non-debug mode does not have stacktrace": { err: Wrap(ErrUnauthorized, "wrapped"), debug: false, wantStacktrace: false, - wantErrMsg: "wrapped: unauthorized", + wantErrMsg: "unauthorized: wrapped", }, "wrapped stdlib error in debug mode provides stacktrace": { err: Wrap(fmt.Errorf("stdlib"), "wrapped"), debug: true, wantStacktrace: true, - wantErrMsg: "wrapped: stdlib", + wantErrMsg: "stdlib: wrapped", }, "wrapped stdlib error in non-debug mode does not have stacktrace": { err: Wrap(fmt.Errorf("stdlib"), "wrapped"), @@ -163,7 +163,7 @@ func TestABCIInfoHidesStacktrace(t *testing.T) { err := Wrap(ErrUnauthorized, "wrapped") _, _, log := ABCIInfo(err, false) - if log != "wrapped: unauthorized" { + if log != "unauthorized: wrapped" { t.Fatalf("unexpected message in non debug mode: %s", log) } } @@ -173,7 +173,7 @@ func TestRedact(t *testing.T) { t.Error("reduct must not pass through panic error") } if err := Redact(ErrUnauthorized); !ErrUnauthorized.Is(err) { - t.Error("reduct should pass through weave error") + t.Error("reduct should pass through SDK error") } var cerr customErr @@ -203,12 +203,12 @@ func TestABCIInfoSerializeErr(t *testing.T) { "single error": { src: myErrDecode, debug: false, - exp: "test: tx parse error", + exp: "tx parse error: test", }, "second error": { src: myErrAddr, debug: false, - exp: "tester: invalid address", + exp: "invalid address: tester", }, "single error with debug": { src: myErrDecode, diff --git a/types/errors/errors.go b/types/errors/errors.go index 22ed2f4c8c89..49624f784775 100644 --- a/types/errors/errors.go +++ b/types/errors/errors.go @@ -44,32 +44,43 @@ var ( // ErrUnknownAddress to doc ErrUnknownAddress = Register(RootCodespace, 9, "unknown address") - // ErrInsufficientCoins to doc (what is the difference between ErrInsufficientFunds???) - ErrInsufficientCoins = Register(RootCodespace, 10, "insufficient coins") - // ErrInvalidCoins to doc - ErrInvalidCoins = Register(RootCodespace, 11, "invalid coins") + ErrInvalidCoins = Register(RootCodespace, 10, "invalid coins") // ErrOutOfGas to doc - ErrOutOfGas = Register(RootCodespace, 12, "out of gas") + ErrOutOfGas = Register(RootCodespace, 11, "out of gas") // ErrMemoTooLarge to doc - ErrMemoTooLarge = Register(RootCodespace, 13, "memo too large") + ErrMemoTooLarge = Register(RootCodespace, 12, "memo too large") // ErrInsufficientFee to doc - ErrInsufficientFee = Register(RootCodespace, 14, "insufficient fee") + ErrInsufficientFee = Register(RootCodespace, 13, "insufficient fee") // ErrTooManySignatures to doc - ErrTooManySignatures = Register(RootCodespace, 15, "maximum numer of signatures exceeded") + ErrTooManySignatures = Register(RootCodespace, 14, "maximum number of signatures exceeded") // ErrNoSignatures to doc - ErrNoSignatures = Register(RootCodespace, 16, "no signatures supplied") + ErrNoSignatures = Register(RootCodespace, 15, "no signatures supplied") // ErrJSONMarshal defines an ABCI typed JSON marshalling error - ErrJSONMarshal = Register(RootCodespace, 17, "failed to marshal JSON bytes") + ErrJSONMarshal = Register(RootCodespace, 16, "failed to marshal JSON bytes") // ErrJSONUnmarshal defines an ABCI typed JSON unmarshalling error - ErrJSONUnmarshal = Register(RootCodespace, 18, "failed to unmarshal JSON bytes") + ErrJSONUnmarshal = Register(RootCodespace, 17, "failed to unmarshal JSON bytes") + + // ErrInvalidRequest defines an ABCI typed error where the request contains + // invalid data. + ErrInvalidRequest = Register(RootCodespace, 18, "invalid request") + + // ErrTxInMempoolCache defines an ABCI typed error where a tx already exists + // in the mempool. + ErrTxInMempoolCache = Register(RootCodespace, 19, "tx already in mempool") + + // ErrMempoolIsFull defines an ABCI typed error where the mempool is full. + ErrMempoolIsFull = Register(RootCodespace, 20, "mempool is full") + + // ErrTxTooLarge defines an ABCI typed error where tx is too large. + ErrTxTooLarge = Register(RootCodespace, 21, "tx too large") // ErrPanic is only set when we recover from a panic, so we know to // redact potentially sensitive system info @@ -89,12 +100,10 @@ func Register(codespace string, code uint32, description string) *Error { if e := getUsed(codespace, code); e != nil { panic(fmt.Sprintf("error with code %d is already registered: %q", code, e.desc)) } - err := &Error{ - code: code, - codespace: codespace, - desc: description, - } + + err := New(codespace, code, description) setUsed(err) + return err } @@ -247,7 +256,7 @@ type wrappedError struct { } func (e *wrappedError) Error() string { - return fmt.Sprintf("%s: %s", e.msg, e.parent.Error()) + return fmt.Sprintf("%s: %s", e.parent.Error(), e.msg) } func (e *wrappedError) Cause() error { diff --git a/types/errors/stacktrace_test.go b/types/errors/stacktrace_test.go index bef4bccb704e..042edc0b6919 100644 --- a/types/errors/stacktrace_test.go +++ b/types/errors/stacktrace_test.go @@ -15,19 +15,19 @@ func TestStackTrace(t *testing.T) { }{ "New gives us a stacktrace": { err: Wrap(ErrNoSignatures, "name"), - wantError: "name: no signatures supplied", + wantError: "no signatures supplied: name", }, "Wrapping stderr gives us a stacktrace": { err: Wrap(fmt.Errorf("foo"), "standard"), - wantError: "standard: foo", + wantError: "foo: standard", }, "Wrapping pkg/errors gives us clean stacktrace": { err: Wrap(errors.New("bar"), "pkg"), - wantError: "pkg: bar", + wantError: "bar: pkg", }, "Wrapping inside another function is still clean": { err: Wrap(fmt.Errorf("indirect"), "do the do"), - wantError: "do the do: indirect", + wantError: "indirect: do the do", }, } diff --git a/types/errors_test.go b/types/errors_test.go deleted file mode 100644 index 912de348a408..000000000000 --- a/types/errors_test.go +++ /dev/null @@ -1,138 +0,0 @@ -package types - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -var codeTypes = []CodeType{ - CodeInternal, - CodeTxDecode, - CodeInvalidSequence, - CodeUnauthorized, - CodeInsufficientFunds, - CodeUnknownRequest, - CodeInvalidAddress, - CodeInvalidPubKey, - CodeUnknownAddress, - CodeInsufficientCoins, - CodeInvalidCoins, - CodeOutOfGas, - CodeMemoTooLarge, -} - -type errFn func(msg string) Error - -var errFns = []errFn{ - ErrInternal, - ErrTxDecode, - ErrInvalidSequence, - ErrUnauthorized, - ErrInsufficientFunds, - ErrUnknownRequest, - ErrInvalidAddress, - ErrInvalidPubKey, - ErrUnknownAddress, - ErrInsufficientCoins, - ErrInvalidCoins, - ErrOutOfGas, - ErrMemoTooLarge, -} - -func TestCodeType(t *testing.T) { - require.True(t, CodeOK.IsOK()) - - for tcnum, c := range codeTypes { - msg := CodeToDefaultMsg(c) - require.NotEqual(t, unknownCodeMsg(c), msg, "Code expected to be known. tc #%d, code %d, msg %s", tcnum, c, msg) - } - - msg := CodeToDefaultMsg(CodeOK) - require.Equal(t, unknownCodeMsg(CodeOK), msg) -} - -func TestErrFn(t *testing.T) { - for i, errFn := range errFns { - err := errFn("") - codeType := codeTypes[i] - require.Equal(t, err.Code(), codeType, "Err function expected to return proper code. tc #%d", i) - require.Equal(t, err.Codespace(), CodespaceRoot, "Err function expected to return proper codespace. tc #%d", i) - require.Equal(t, err.QueryResult().Code, uint32(err.Code()), "Err function expected to return proper Code from QueryResult. tc #%d") - require.Equal(t, err.QueryResult().Log, err.ABCILog(), "Err function expected to return proper ABCILog from QueryResult. tc #%d") - } -} - -func TestAppendMsgToErr(t *testing.T) { - for i, errFn := range errFns { - err := errFn("") - errMsg := err.Stacktrace().Error() - abciLog := err.ABCILog() - - // plain msg error - msg := AppendMsgToErr("something unexpected happened", errMsg) - require.Equal( - t, - fmt.Sprintf("something unexpected happened; %s", errMsg), - msg, - fmt.Sprintf("Should have formatted the error message of ABCI Log. tc #%d", i), - ) - - // ABCI Log msg error - msg = AppendMsgToErr("something unexpected happened", abciLog) - msgIdx := mustGetMsgIndex(abciLog) - require.Equal( - t, - fmt.Sprintf("%s%s; %s}", - abciLog[:msgIdx], - "something unexpected happened", - abciLog[msgIdx:len(abciLog)-1], - ), - msg, - fmt.Sprintf("Should have formatted the error message of ABCI Log. tc #%d", i)) - } -} - -func TestResultFromError(t *testing.T) { - cases := map[string]struct { - err error - expect Result - }{ - "sdk.Error": { - err: ErrUnauthorized("not owner"), - expect: Result{ - Codespace: CodespaceRoot, - Code: CodeUnauthorized, - Log: `{"codespace":"sdk","code":4,"message":"not owner"}`, - }, - }, - "types/errors": { - err: sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "not owner"), - expect: Result{ - Codespace: CodespaceRoot, - Code: CodeUnauthorized, - Log: `{"codespace":"sdk","code":4,"message":"not owner: unauthorized"}`, - }, - }, - "stdlib errors": { - err: fmt.Errorf("not owner"), - expect: Result{ - Codespace: CodespaceType("undefined"), - Code: CodeInternal, - // note that we redact the internal errors in the new package to not leak eg. panics - Log: `{"codespace":"undefined","code":1,"message":"internal error"}`, - }, - }, - } - - for name, tc := range cases { - tc := tc - t.Run(name, func(t *testing.T) { - res := ResultFromError(tc.err) - require.Equal(t, tc.expect, res) - }) - } -} diff --git a/types/handler.go b/types/handler.go index d0cc41ec46dc..6815230a861f 100644 --- a/types/handler.go +++ b/types/handler.go @@ -1,7 +1,7 @@ package types // Handler defines the core of the state transition function of an application. -type Handler func(ctx Context, msg Msg) Result +type Handler func(ctx Context, msg Msg) (*Result, error) // AnteHandler authenticates transactions, before their internal messages are handled. // If newCtx.IsZero(), ctx is used instead. diff --git a/types/queryable.go b/types/queryable.go index 9223332bc833..f89965906af8 100644 --- a/types/queryable.go +++ b/types/queryable.go @@ -1,6 +1,9 @@ package types -import abci "github.com/tendermint/tendermint/abci/types" +import ( + abci "github.com/tendermint/tendermint/abci/types" +) -// Type for querier functions on keepers to implement to handle custom queries -type Querier = func(ctx Context, path []string, req abci.RequestQuery) (res []byte, err Error) +// Querier defines a function type that a module querier must implement to handle +// custom client queries. +type Querier = func(ctx Context, path []string, req abci.RequestQuery) ([]byte, error) diff --git a/types/result.go b/types/result.go index 41a31b84ba3c..8b9a28df502b 100644 --- a/types/result.go +++ b/types/result.go @@ -12,36 +12,27 @@ import ( ctypes "github.com/tendermint/tendermint/rpc/core/types" ) -// Result is the union of ResponseFormat and ResponseCheckTx. -type Result struct { - // Code is the response code, is stored back on the chain. - Code CodeType - - // Codespace is the string referring to the domain of an error - Codespace CodespaceType - - // Data is any data returned from the app. - // Data has to be length prefixed in order to separate - // results from multiple msgs executions - Data []byte - - // Log contains the txs log information. NOTE: nondeterministic. - Log string - +// GasInfo defines tx execution gas context. +type GasInfo struct { // GasWanted is the maximum units of work we allow this tx to perform. GasWanted uint64 // GasUsed is the amount of gas actually consumed. NOTE: unimplemented GasUsed uint64 - - // Events contains a slice of Event objects that were emitted during some - // execution. - Events Events } -// TODO: In the future, more codes may be OK. -func (res Result) IsOK() bool { - return res.Code.IsOK() +// Result is the union of ResponseFormat and ResponseCheckTx. +type Result struct { + // Data is any data returned from message or handler execution. It MUST be length + // prefixed in order to separate data from multiple message executions. + Data []byte + + // Log contains the log information from message or handler execution. + Log string + + // Events contains a slice of Event objects that were emitted during message or + // handler execution. + Events Events } // ABCIMessageLogs represents a slice of ABCIMessageLog. @@ -50,7 +41,6 @@ type ABCIMessageLogs []ABCIMessageLog // ABCIMessageLog defines a structure containing an indexed tx ABCI message log. type ABCIMessageLog struct { MsgIndex uint16 `json:"msg_index"` - Success bool `json:"success"` Log string `json:"log"` // Events contains a slice of Event objects that were emitted during some @@ -58,10 +48,9 @@ type ABCIMessageLog struct { Events StringEvents `json:"events"` } -func NewABCIMessageLog(i uint16, success bool, log string, events Events) ABCIMessageLog { +func NewABCIMessageLog(i uint16, log string, events Events) ABCIMessageLog { return ABCIMessageLog{ MsgIndex: i, - Success: success, Log: log, Events: StringifyEvents(events.ToABCIEvents()), } @@ -84,6 +73,7 @@ func (logs ABCIMessageLogs) String() (str string) { type TxResponse struct { Height int64 `json:"height"` TxHash string `json:"txhash"` + Codespace string `json:"codespace,omitempty"` Code uint32 `json:"code,omitempty"` Data string `json:"data,omitempty"` RawLog string `json:"raw_log,omitempty"` @@ -91,7 +81,6 @@ type TxResponse struct { Info string `json:"info,omitempty"` GasWanted int64 `json:"gas_wanted,omitempty"` GasUsed int64 `json:"gas_used,omitempty"` - Codespace string `json:"codespace,omitempty"` Tx Tx `json:"tx,omitempty"` Timestamp string `json:"timestamp,omitempty"` @@ -111,6 +100,7 @@ func NewResponseResultTx(res *ctypes.ResultTx, tx Tx, timestamp string) TxRespon return TxResponse{ TxHash: res.Hash.String(), Height: res.Height, + Codespace: res.TxResult.Codespace, Code: res.TxResult.Code, Data: strings.ToUpper(hex.EncodeToString(res.TxResult.Data)), RawLog: res.TxResult.Log, @@ -153,6 +143,7 @@ func newTxResponseCheckTx(res *ctypes.ResultBroadcastTxCommit) TxResponse { return TxResponse{ Height: res.Height, TxHash: txHash, + Codespace: res.CheckTx.Codespace, Code: res.CheckTx.Code, Data: strings.ToUpper(hex.EncodeToString(res.CheckTx.Data)), RawLog: res.CheckTx.Log, @@ -161,7 +152,6 @@ func newTxResponseCheckTx(res *ctypes.ResultBroadcastTxCommit) TxResponse { GasWanted: res.CheckTx.GasWanted, GasUsed: res.CheckTx.GasUsed, Events: StringifyEvents(res.CheckTx.Events), - Codespace: res.CheckTx.Codespace, } } @@ -180,6 +170,7 @@ func newTxResponseDeliverTx(res *ctypes.ResultBroadcastTxCommit) TxResponse { return TxResponse{ Height: res.Height, TxHash: txHash, + Codespace: res.DeliverTx.Codespace, Code: res.DeliverTx.Code, Data: strings.ToUpper(hex.EncodeToString(res.DeliverTx.Data)), RawLog: res.DeliverTx.Log, @@ -188,7 +179,6 @@ func newTxResponseDeliverTx(res *ctypes.ResultBroadcastTxCommit) TxResponse { GasWanted: res.DeliverTx.GasWanted, GasUsed: res.DeliverTx.GasUsed, Events: StringifyEvents(res.DeliverTx.Events), - Codespace: res.DeliverTx.Codespace, } } diff --git a/types/result_test.go b/types/result_test.go index c4fedc2992f3..bbdf3b75e70a 100644 --- a/types/result_test.go +++ b/types/result_test.go @@ -7,17 +7,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestResult(t *testing.T) { - var res Result - require.True(t, res.IsOK()) - - res.Data = []byte("data") - require.True(t, res.IsOK()) - - res.Code = CodeType(1) - require.False(t, res.IsOK()) -} - func TestParseABCILog(t *testing.T) { logs := `[{"log":"","msg_index":1,"success":true}]` @@ -26,12 +15,11 @@ func TestParseABCILog(t *testing.T) { require.Len(t, res, 1) require.Equal(t, res[0].Log, "") require.Equal(t, res[0].MsgIndex, uint16(1)) - require.True(t, res[0].Success) } func TestABCIMessageLog(t *testing.T) { events := Events{NewEvent("transfer", NewAttribute("sender", "foo"))} - msgLog := NewABCIMessageLog(0, true, "", events) + msgLog := NewABCIMessageLog(0, "", events) msgLogs := ABCIMessageLogs{msgLog} bz, err := codec.Cdc.MarshalJSON(msgLogs) diff --git a/types/tx_msg.go b/types/tx_msg.go index bc4c2540d911..1b0da612b736 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -17,7 +17,7 @@ type Msg interface { // ValidateBasic does a simple validation check that // doesn't require access to any other information. - ValidateBasic() Error + ValidateBasic() error // Get the canonical byte representation of the Msg. GetSignBytes() []byte @@ -37,13 +37,13 @@ type Tx interface { // ValidateBasic does a simple and lightweight validation check that doesn't // require access to any other information. - ValidateBasic() Error + ValidateBasic() error } //__________________________________________________________ // TxDecoder unmarshals transaction bytes -type TxDecoder func(txBytes []byte) (Tx, Error) +type TxDecoder func(txBytes []byte) (Tx, error) // TxEncoder marshals transaction to bytes type TxEncoder func(tx Tx) ([]byte, error) @@ -73,7 +73,7 @@ func (msg *TestMsg) GetSignBytes() []byte { } return MustSortJSON(bz) } -func (msg *TestMsg) ValidateBasic() Error { return nil } +func (msg *TestMsg) ValidateBasic() error { return nil } func (msg *TestMsg) GetSigners() []AccAddress { return msg.signers } diff --git a/x/auth/ante/ante_test.go b/x/auth/ante/ante_test.go index 5ac42a6dc855..1d55b4d320c3 100644 --- a/x/auth/ante/ante_test.go +++ b/x/auth/ante/ante_test.go @@ -2,6 +2,7 @@ package ante_test import ( "encoding/json" + "errors" "fmt" "math/rand" "strings" @@ -26,14 +27,10 @@ func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx } // run the tx through the anteHandler and ensure it fails with the given code -func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, simulate bool, code sdk.CodeType) { +func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, simulate bool, expErr error) { _, err := anteHandler(ctx, tx, simulate) require.NotNil(t, err) - - result := sdk.ResultFromError(err) - - require.Equal(t, code, result.Code, fmt.Sprintf("Expected %v, got %v", code, result)) - require.Equal(t, sdk.CodespaceRoot, result.Codespace) + require.True(t, errors.Is(expErr, err)) } // Test that simulate transaction accurately estimates gas cost @@ -117,23 +114,23 @@ func TestAnteHandlerSigErrors(t *testing.T) { require.Equal(t, expectedSigners, stdTx.GetSigners()) // Check no signatures fails - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeNoSignatures) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrNoSignatures) // test num sigs dont match GetSigners privs, accNums, seqs = []crypto.PrivKey{priv1}, []uint64{0}, []uint64{0} tx = types.NewTestTx(ctx, msgs, privs, accNums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // test an unrecognized account privs, accNums, seqs = []crypto.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0} tx = types.NewTestTx(ctx, msgs, privs, accNums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnknownAddress) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnknownAddress) // save the first account, but second is still unrecognized acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) acc1.SetCoins(fee.Amount) app.AccountKeeper.SetAccount(ctx, acc1) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnknownAddress) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnknownAddress) } // Test logic around account number checking with one signer and many signers. @@ -172,7 +169,7 @@ func TestAnteHandlerAccountNumbers(t *testing.T) { // new tx from wrong account number seqs = []uint64{1} tx = types.NewTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // from correct account number seqs = []uint64{1} @@ -185,7 +182,7 @@ func TestAnteHandlerAccountNumbers(t *testing.T) { msgs = []sdk.Msg{msg1, msg2} privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{1, 0}, []uint64{2, 0} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // correct account numbers privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{0, 1}, []uint64{2, 0} @@ -228,7 +225,7 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) { // new tx from wrong account number seqs = []uint64{1} tx = types.NewTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // from correct account number seqs = []uint64{1} @@ -241,7 +238,7 @@ func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) { msgs = []sdk.Msg{msg1, msg2} privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{1, 0}, []uint64{2, 0} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // correct account numbers privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{0, 0}, []uint64{2, 0} @@ -288,7 +285,7 @@ func TestAnteHandlerSequences(t *testing.T) { checkValidTx(t, anteHandler, ctx, tx, false) // test sending it again fails (replay protection) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // fix sequence, should pass seqs = []uint64{1} @@ -305,14 +302,14 @@ func TestAnteHandlerSequences(t *testing.T) { checkValidTx(t, anteHandler, ctx, tx, false) // replay fails - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // tx from just second signer with incorrect sequence fails msg = types.NewTestMsg(addr2) msgs = []sdk.Msg{msg} privs, accnums, seqs = []crypto.PrivKey{priv2}, []uint64{1}, []uint64{0} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeUnauthorized) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrUnauthorized) // fix the sequence and it passes tx = types.NewTestTx(ctx, msgs, []crypto.PrivKey{priv2}, []uint64{1}, []uint64{1}, fee) @@ -348,11 +345,11 @@ func TestAnteHandlerFees(t *testing.T) { // signer does not have enough funds to pay the fee tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInsufficientFunds) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInsufficientFunds) acc1.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("atom", 149))) app.AccountKeeper.SetAccount(ctx, acc1) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInsufficientFunds) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInsufficientFunds) require.True(t, app.SupplyKeeper.GetModuleAccount(ctx, types.FeeCollectorName).GetCoins().Empty()) require.True(sdk.IntEq(t, app.AccountKeeper.GetAccount(ctx, addr1).GetCoins().AmountOf("atom"), sdk.NewInt(149))) @@ -388,17 +385,17 @@ func TestAnteHandlerMemoGas(t *testing.T) { // tx does not have enough gas tx = types.NewTestTx(ctx, []sdk.Msg{msg}, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeOutOfGas) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrOutOfGas) // tx with memo doesn't have enough gas fee = types.NewStdFee(801, sdk.NewCoins(sdk.NewInt64Coin("atom", 0))) tx = types.NewTestTxWithMemo(ctx, []sdk.Msg{msg}, privs, accnums, seqs, fee, "abcininasidniandsinasindiansdiansdinaisndiasndiadninsd") - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeOutOfGas) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrOutOfGas) // memo too large fee = types.NewStdFee(50000, sdk.NewCoins(sdk.NewInt64Coin("atom", 0))) tx = types.NewTestTxWithMemo(ctx, []sdk.Msg{msg}, privs, accnums, seqs, fee, strings.Repeat("01234567890", 500)) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeMemoTooLarge) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrMemoTooLarge) // tx with memo has enough gas fee = types.NewStdFee(50000, sdk.NewCoins(sdk.NewInt64Coin("atom", 0))) @@ -492,7 +489,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { chainID := ctx.ChainID() chainID2 := chainID + "somemorestuff" - codeUnauth := sdk.CodeUnauthorized + errUnauth := sdkerrors.ErrUnauthorized cases := []struct { chainID string @@ -500,14 +497,14 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { seq uint64 fee types.StdFee msgs []sdk.Msg - code sdk.CodeType + err error }{ - {chainID2, 0, 1, fee, msgs, codeUnauth}, // test wrong chain_id - {chainID, 0, 2, fee, msgs, codeUnauth}, // test wrong seqs - {chainID, 1, 1, fee, msgs, codeUnauth}, // test wrong accnum - {chainID, 0, 1, fee, []sdk.Msg{types.NewTestMsg(addr2)}, codeUnauth}, // test wrong msg - {chainID, 0, 1, fee2, msgs, codeUnauth}, // test wrong fee - {chainID, 0, 1, fee3, msgs, codeUnauth}, // test wrong fee + {chainID2, 0, 1, fee, msgs, errUnauth}, // test wrong chain_id + {chainID, 0, 2, fee, msgs, errUnauth}, // test wrong seqs + {chainID, 1, 1, fee, msgs, errUnauth}, // test wrong accnum + {chainID, 0, 1, fee, []sdk.Msg{types.NewTestMsg(addr2)}, errUnauth}, // test wrong msg + {chainID, 0, 1, fee2, msgs, errUnauth}, // test wrong fee + {chainID, 0, 1, fee3, msgs, errUnauth}, // test wrong fee } privs, seqs = []crypto.PrivKey{priv1}, []uint64{1} @@ -517,20 +514,20 @@ func TestAnteHandlerBadSignBytes(t *testing.T) { types.StdSignBytes(cs.chainID, cs.accnum, cs.seq, cs.fee, cs.msgs, ""), "", ) - checkInvalidTx(t, anteHandler, ctx, tx, false, cs.code) + checkInvalidTx(t, anteHandler, ctx, tx, false, cs.err) } // test wrong signer if public key exist privs, accnums, seqs = []crypto.PrivKey{priv2}, []uint64{0}, []uint64{1} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInvalidPubKey) // test wrong signer if public doesn't exist msg = types.NewTestMsg(addr2) msgs = []sdk.Msg{msg} privs, accnums, seqs = []crypto.PrivKey{priv1}, []uint64{1}, []uint64{0} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInvalidPubKey) } func TestAnteHandlerSetPubKey(t *testing.T) { @@ -572,14 +569,14 @@ func TestAnteHandlerSetPubKey(t *testing.T) { tx = types.NewTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee) sigs := tx.(types.StdTx).Signatures sigs[0].PubKey = nil - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInvalidPubKey) acc2 = app.AccountKeeper.GetAccount(ctx, addr2) require.Nil(t, acc2.GetPubKey()) // test invalid signature and public key tx = types.NewTestTx(ctx, msgs, privs, []uint64{1}, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInvalidPubKey) acc2 = app.AccountKeeper.GetAccount(ctx, addr2) require.Nil(t, acc2.GetPubKey()) @@ -686,7 +683,7 @@ func TestAnteHandlerSigLimitExceeded(t *testing.T) { privs, accnums, seqs := []crypto.PrivKey{priv1, priv2, priv3, priv4, priv5, priv6, priv7, priv8}, []uint64{0, 1, 2, 3, 4, 5, 6, 7}, []uint64{0, 0, 0, 0, 0, 0, 0, 0} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeTooManySignatures) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrTooManySignatures) } // Test custom SignatureVerificationGasConsumer @@ -717,7 +714,7 @@ func TestCustomSignatureVerificationGasConsumer(t *testing.T) { fee := types.NewTestStdFee() msgs := []sdk.Msg{msg} tx = types.NewTestTx(ctx, msgs, privs, accnums, seqs, fee) - checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidPubKey) + checkInvalidTx(t, anteHandler, ctx, tx, false, sdkerrors.ErrInvalidPubKey) // verify that an ed25519 account gets accepted priv2 := ed25519.GenPrivKey() diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index be094b6c69a4..77cba3e59c1e 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -61,8 +61,10 @@ func QueryTxsRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, - sdk.AppendMsgToErr("could not parse query parameters", err.Error())) + rest.WriteErrorResponse( + w, http.StatusBadRequest, + fmt.Sprintf("failed to parse query parameters: %s", err), + ) return } diff --git a/x/auth/client/utils/tx.go b/x/auth/client/utils/tx.go index 7bdde2306518..55b7007002d9 100644 --- a/x/auth/client/utils/tx.go +++ b/x/auth/client/utils/tx.go @@ -278,12 +278,12 @@ func adjustGasEstimate(estimate uint64, adjustment float64) uint64 { } func parseQueryResponse(cdc *codec.Codec, rawRes []byte) (uint64, error) { - var simulationResult sdk.Result - if err := cdc.UnmarshalBinaryLengthPrefixed(rawRes, &simulationResult); err != nil { + var gasUsed uint64 + if err := cdc.UnmarshalBinaryLengthPrefixed(rawRes, &gasUsed); err != nil { return 0, err } - return simulationResult.GasUsed, nil + return gasUsed, nil } // PrepareTxBuilder populates a TxBuilder in preparation for the build of a Tx. diff --git a/x/auth/client/utils/tx_test.go b/x/auth/client/utils/tx_test.go index cde10cc56029..a9c33b232053 100644 --- a/x/auth/client/utils/tx_test.go +++ b/x/auth/client/utils/tx_test.go @@ -23,7 +23,7 @@ var ( func TestParseQueryResponse(t *testing.T) { cdc := makeCodec() - sdkResBytes := cdc.MustMarshalBinaryLengthPrefixed(sdk.Result{GasUsed: 10}) + sdkResBytes := cdc.MustMarshalBinaryLengthPrefixed(uint64(10)) gas, err := parseQueryResponse(cdc, sdkResBytes) assert.Equal(t, gas, uint64(10)) assert.Nil(t, err) @@ -39,14 +39,16 @@ func TestCalculateGas(t *testing.T) { if wantErr { return nil, 0, errors.New("") } - return cdc.MustMarshalBinaryLengthPrefixed(sdk.Result{GasUsed: gasUsed}), 0, nil + return cdc.MustMarshalBinaryLengthPrefixed(gasUsed), 0, nil } } + type args struct { queryFuncGasUsed uint64 queryFuncWantErr bool adjustment float64 } + tests := []struct { name string args args @@ -57,6 +59,7 @@ func TestCalculateGas(t *testing.T) { {"error", args{0, true, 1.2}, 0, 0, true}, {"adjusted gas", args{10, false, 1.2}, 10, 12, false}, } + for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { diff --git a/x/auth/keeper/keeper.go b/x/auth/keeper/keeper.go index d60a396d342b..244dec7c193b 100644 --- a/x/auth/keeper/keeper.go +++ b/x/auth/keeper/keeper.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/params/subspace" @@ -49,19 +50,19 @@ func (ak AccountKeeper) Logger(ctx sdk.Context) log.Logger { } // GetPubKey Returns the PubKey of the account at address -func (ak AccountKeeper) GetPubKey(ctx sdk.Context, addr sdk.AccAddress) (crypto.PubKey, sdk.Error) { +func (ak AccountKeeper) GetPubKey(ctx sdk.Context, addr sdk.AccAddress) (crypto.PubKey, error) { acc := ak.GetAccount(ctx, addr) if acc == nil { - return nil, sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", addr)) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) } return acc.GetPubKey(), nil } // GetSequence Returns the Sequence of the account at address -func (ak AccountKeeper) GetSequence(ctx sdk.Context, addr sdk.AccAddress) (uint64, sdk.Error) { +func (ak AccountKeeper) GetSequence(ctx sdk.Context, addr sdk.AccAddress) (uint64, error) { acc := ak.GetAccount(ctx, addr) if acc == nil { - return 0, sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", addr)) + return 0, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr) } return acc.GetSequence(), nil } diff --git a/x/auth/keeper/querier.go b/x/auth/keeper/querier.go index b40dc0135d8f..28e505970b45 100644 --- a/x/auth/keeper/querier.go +++ b/x/auth/keeper/querier.go @@ -1,41 +1,40 @@ package keeper import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/types" ) // NewQuerier creates a querier for auth REST endpoints func NewQuerier(keeper AccountKeeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryAccount: return queryAccount(ctx, req, keeper) default: - return nil, sdk.ErrUnknownRequest("unknown auth query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) } } } -func queryAccount(ctx sdk.Context, req abci.RequestQuery, keeper AccountKeeper) ([]byte, sdk.Error) { +func queryAccount(ctx sdk.Context, req abci.RequestQuery, keeper AccountKeeper) ([]byte, error) { var params types.QueryAccountParams if err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms); err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } account := keeper.GetAccount(ctx, params.Address) if account == nil { - return nil, sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", params.Address)) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", params.Address) } bz, err := codec.MarshalJSONIndent(keeper.cdc, account) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil diff --git a/x/auth/types/expected_keepers.go b/x/auth/types/expected_keepers.go index 11e03ef36cb8..499bc288c849 100644 --- a/x/auth/types/expected_keepers.go +++ b/x/auth/types/expected_keepers.go @@ -7,7 +7,7 @@ import ( // SupplyKeeper defines the expected supply Keeper (noalias) type SupplyKeeper interface { - SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error GetModuleAccount(ctx sdk.Context, moduleName string) exported.ModuleAccountI GetModuleAddress(moduleName string) sdk.AccAddress } diff --git a/x/auth/types/stdtx.go b/x/auth/types/stdtx.go index fa8b5d100d5f..bc6042abbbb2 100644 --- a/x/auth/types/stdtx.go +++ b/x/auth/types/stdtx.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/exported" ) @@ -42,20 +43,29 @@ func (tx StdTx) GetMsgs() []sdk.Msg { return tx.Msgs } // ValidateBasic does a simple and lightweight validation check that doesn't // require access to any other information. -func (tx StdTx) ValidateBasic() sdk.Error { +func (tx StdTx) ValidateBasic() error { stdSigs := tx.GetSignatures() if tx.Fee.Gas > maxGasWanted { - return sdk.ErrGasOverflow(fmt.Sprintf("invalid gas supplied; %d > %d", tx.Fee.Gas, maxGasWanted)) + return sdkerrors.Wrapf( + sdkerrors.ErrInvalidRequest, + "invalid gas supplied; %d > %d", tx.Fee.Gas, maxGasWanted, + ) } if tx.Fee.Amount.IsAnyNegative() { - return sdk.ErrInsufficientFee(fmt.Sprintf("invalid fee %s amount provided", tx.Fee.Amount)) + return sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFee, + "invalid fee provided: %s", tx.Fee.Amount, + ) } if len(stdSigs) == 0 { - return sdk.ErrNoSignatures("no signers") + return sdkerrors.ErrNoSignatures } if len(stdSigs) != len(tx.GetSigners()) { - return sdk.ErrUnauthorized("wrong number of signers") + return sdkerrors.Wrapf( + sdkerrors.ErrUnauthorized, + "wrong number of signers; expected %d, got %d", tx.GetSigners(), len(stdSigs), + ) } return nil @@ -240,18 +250,18 @@ type StdSignature struct { // DefaultTxDecoder logic for standard transaction decoding func DefaultTxDecoder(cdc *codec.Codec) sdk.TxDecoder { - return func(txBytes []byte) (sdk.Tx, sdk.Error) { + return func(txBytes []byte) (sdk.Tx, error) { var tx = StdTx{} if len(txBytes) == 0 { - return nil, sdk.ErrTxDecode("txBytes are empty") + return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty") } // StdTx.Msg is an interface. The concrete types // are registered by MakeTxCodec err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx) if err != nil { - return nil, sdk.ErrTxDecode("error decoding transaction").TraceSDK(err.Error()) + return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) } return tx, nil diff --git a/x/auth/types/stdtx_test.go b/x/auth/types/stdtx_test.go index 375a15c49cc4..8131006f59d5 100644 --- a/x/auth/types/stdtx_test.go +++ b/x/auth/types/stdtx_test.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) var ( @@ -78,7 +79,8 @@ func TestTxValidateBasic(t *testing.T) { err := tx.ValidateBasic() require.Error(t, err) - require.Equal(t, sdk.CodeInsufficientFee, err.Result().Code) + _, code, _ := sdkerrors.ABCIInfo(err, false) + require.Equal(t, sdkerrors.ErrInsufficientFee.ABCICode(), code) // require to fail validation when no signatures exist privs, accNums, seqs := []crypto.PrivKey{}, []uint64{}, []uint64{} @@ -86,7 +88,8 @@ func TestTxValidateBasic(t *testing.T) { err = tx.ValidateBasic() require.Error(t, err) - require.Equal(t, sdk.CodeNoSignatures, err.Result().Code) + _, code, _ = sdkerrors.ABCIInfo(err, false) + require.Equal(t, sdkerrors.ErrNoSignatures.ABCICode(), code) // require to fail validation when signatures do not match expected signers privs, accNums, seqs = []crypto.PrivKey{priv1}, []uint64{0, 1}, []uint64{0, 0} @@ -94,7 +97,8 @@ func TestTxValidateBasic(t *testing.T) { err = tx.ValidateBasic() require.Error(t, err) - require.Equal(t, sdk.CodeUnauthorized, err.Result().Code) + _, code, _ = sdkerrors.ABCIInfo(err, false) + require.Equal(t, sdkerrors.ErrUnauthorized.ABCICode(), code) // require to fail with invalid gas supplied badFee = NewTestStdFee() @@ -103,7 +107,8 @@ func TestTxValidateBasic(t *testing.T) { err = tx.ValidateBasic() require.Error(t, err) - require.Equal(t, sdk.CodeGasOverflow, err.Result().Code) + _, code, _ = sdkerrors.ABCIInfo(err, false) + require.Equal(t, sdkerrors.ErrInvalidRequest.ABCICode(), code) // require to pass when above criteria are matched privs, accNums, seqs = []crypto.PrivKey{priv1, priv2}, []uint64{0, 1}, []uint64{0, 0} diff --git a/x/bank/alias.go b/x/bank/alias.go index 3533e3084d9d..1ac7cecebd90 100644 --- a/x/bank/alias.go +++ b/x/bank/alias.go @@ -1,25 +1,19 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/bank/internal/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/bank/internal/types package bank +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) const ( - QueryBalance = keeper.QueryBalance - DefaultCodespace = types.DefaultCodespace - CodeSendDisabled = types.CodeSendDisabled - CodeInvalidInputsOutputs = types.CodeInvalidInputsOutputs - ModuleName = types.ModuleName - QuerierRoute = types.QuerierRoute - RouterKey = types.RouterKey - DefaultParamspace = types.DefaultParamspace - DefaultSendEnabled = types.DefaultSendEnabled + QueryBalance = keeper.QueryBalance + ModuleName = types.ModuleName + QuerierRoute = types.QuerierRoute + RouterKey = types.RouterKey + DefaultParamspace = types.DefaultParamspace + DefaultSendEnabled = types.DefaultSendEnabled EventTypeTransfer = types.EventTypeTransfer AttributeKeyRecipient = types.AttributeKeyRecipient @@ -28,7 +22,6 @@ const ( ) var ( - // functions aliases RegisterInvariants = keeper.RegisterInvariants NonnegativeBalanceInvariant = keeper.NonnegativeBalanceInvariant NewBaseKeeper = keeper.NewBaseKeeper @@ -50,10 +43,8 @@ var ( ValidateInputsOutputs = types.ValidateInputsOutputs ParamKeyTable = types.ParamKeyTable NewQueryBalanceParams = types.NewQueryBalanceParams - - // variable aliases - ModuleCdc = types.ModuleCdc - ParamStoreKeySendEnabled = types.ParamStoreKeySendEnabled + ModuleCdc = types.ModuleCdc + ParamStoreKeySendEnabled = types.ParamStoreKeySendEnabled ) type ( diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index 9e0bd735484d..9161a88c31ba 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -34,10 +34,11 @@ func BenchmarkOneBankSendTxPerBlock(b *testing.B) { // Committing, and what time comes from Check/Deliver Tx. for i := 0; i < b.N; i++ { benchmarkApp.BeginBlock(abci.RequestBeginBlock{}) - x := benchmarkApp.Check(txs[i]) - if !x.IsOK() { + _, _, err := benchmarkApp.Check(txs[i]) + if err != nil { panic("something is broken in checking transaction") } + benchmarkApp.Deliver(txs[i]) benchmarkApp.EndBlock(abci.RequestEndBlock{}) benchmarkApp.Commit() @@ -63,10 +64,11 @@ func BenchmarkOneBankMultiSendTxPerBlock(b *testing.B) { // Committing, and what time comes from Check/Deliver Tx. for i := 0; i < b.N; i++ { benchmarkApp.BeginBlock(abci.RequestBeginBlock{}) - x := benchmarkApp.Check(txs[i]) - if !x.IsOK() { + _, _, err := benchmarkApp.Check(txs[i]) + if err != nil { panic("something is broken in checking transaction") } + benchmarkApp.Deliver(txs[i]) benchmarkApp.EndBlock(abci.RequestEndBlock{}) benchmarkApp.Commit() diff --git a/x/bank/handler.go b/x/bank/handler.go index 8e6133347715..3c83ec4c2af4 100644 --- a/x/bank/handler.go +++ b/x/bank/handler.go @@ -1,16 +1,15 @@ package bank import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) // NewHandler returns a handler for "bank" type messages. func NewHandler(k keeper.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -21,25 +20,24 @@ func NewHandler(k keeper.Keeper) sdk.Handler { return handleMsgMultiSend(ctx, k, msg) default: - errMsg := fmt.Sprintf("unrecognized bank message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized bank message type: %T", msg) } } } // Handle MsgSend. -func handleMsgSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgSend) sdk.Result { +func handleMsgSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgSend) (*sdk.Result, error) { if !k.GetSendEnabled(ctx) { - return types.ErrSendDisabled(k.Codespace()).Result() + return nil, types.ErrSendDisabled } if k.BlacklistedAddr(msg.ToAddress) { - return sdk.ErrUnauthorized(fmt.Sprintf("%s is not allowed to receive transactions", msg.ToAddress)).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive transactions", msg.ToAddress) } err := k.SendCoins(ctx, msg.FromAddress, msg.ToAddress, msg.Amount) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -49,25 +47,25 @@ func handleMsgSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgSend) sdk.Resu ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } // Handle MsgMultiSend. -func handleMsgMultiSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgMultiSend) sdk.Result { +func handleMsgMultiSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgMultiSend) (*sdk.Result, error) { // NOTE: totalIn == totalOut should already have been checked if !k.GetSendEnabled(ctx) { - return types.ErrSendDisabled(k.Codespace()).Result() + return nil, types.ErrSendDisabled } for _, out := range msg.Outputs { if k.BlacklistedAddr(out.Address) { - return sdk.ErrUnauthorized(fmt.Sprintf("%s is not allowed to receive transactions", out.Address)).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive transactions", out.Address) } } err := k.InputOutputCoins(ctx, msg.Inputs, msg.Outputs) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -77,5 +75,5 @@ func handleMsgMultiSend(ctx sdk.Context, k keeper.Keeper, msg types.MsgMultiSend ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } diff --git a/x/bank/handler_test.go b/x/bank/handler_test.go index 457afc8e69d9..f9d313385f0a 100644 --- a/x/bank/handler_test.go +++ b/x/bank/handler_test.go @@ -4,17 +4,20 @@ import ( "strings" "testing" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/stretchr/testify/require" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) func TestInvalidMsg(t *testing.T) { h := NewHandler(nil) - res := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) - require.False(t, res.IsOK()) - require.True(t, strings.Contains(res.Log, "unrecognized bank message type")) + res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) + require.Error(t, err) + require.Nil(t, res) + + _, _, log := sdkerrors.ABCIInfo(err, false) + require.True(t, strings.Contains(log, "unrecognized bank message type")) } diff --git a/x/bank/internal/keeper/keeper.go b/x/bank/internal/keeper/keeper.go index cd0242e23f17..f36477f3c3b1 100644 --- a/x/bank/internal/keeper/keeper.go +++ b/x/bank/internal/keeper/keeper.go @@ -7,6 +7,7 @@ import ( "github.com/tendermint/tendermint/libs/log" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" @@ -20,8 +21,8 @@ var _ Keeper = (*BaseKeeper)(nil) type Keeper interface { SendKeeper - DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) sdk.Error + DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error + UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error } // BaseKeeper manages transfers between accounts. It implements the Keeper interface. @@ -33,13 +34,13 @@ type BaseKeeper struct { } // NewBaseKeeper returns a new BaseKeeper -func NewBaseKeeper(ak types.AccountKeeper, - paramSpace params.Subspace, - codespace sdk.CodespaceType, blacklistedAddrs map[string]bool) BaseKeeper { +func NewBaseKeeper( + ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, +) BaseKeeper { ps := paramSpace.WithKeyTable(types.ParamKeyTable()) return BaseKeeper{ - BaseSendKeeper: NewBaseSendKeeper(ak, ps, codespace, blacklistedAddrs), + BaseSendKeeper: NewBaseSendKeeper(ak, ps, blacklistedAddrs), ak: ak, paramSpace: ps, } @@ -50,33 +51,32 @@ func NewBaseKeeper(ak types.AccountKeeper, // vesting and vested coins. // The coins are then transferred from the delegator address to a ModuleAccount address. // If any of the delegation amounts are negative, an error is returned. -func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) sdk.Error { - +func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error { delegatorAcc := keeper.ak.GetAccount(ctx, delegatorAddr) if delegatorAcc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", delegatorAddr)) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", delegatorAddr) } moduleAcc := keeper.ak.GetAccount(ctx, moduleAccAddr) if moduleAcc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", moduleAccAddr)) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleAccAddr) } if !amt.IsValid() { - return sdk.ErrInvalidCoins(amt.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } oldCoins := delegatorAcc.GetCoins() _, hasNeg := oldCoins.SafeSub(amt) if hasNeg { - return sdk.ErrInsufficientCoins( - fmt.Sprintf("insufficient account funds; %s < %s", oldCoins, amt), + return sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", oldCoins, amt, ) } if err := trackDelegation(delegatorAcc, ctx.BlockHeader().Time, amt); err != nil { - return sdk.ErrInternal(fmt.Sprintf("failed to track delegation: %v", err)) + return sdkerrors.Wrap(err, "failed to track delegation") } keeper.ak.SetAccount(ctx, delegatorAcc) @@ -94,28 +94,27 @@ func (keeper BaseKeeper) DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAcc // vesting and vested coins. // The coins are then transferred from a ModuleAccount address to the delegator address. // If any of the undelegation amounts are negative, an error is returned. -func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) sdk.Error { - +func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error { delegatorAcc := keeper.ak.GetAccount(ctx, delegatorAddr) if delegatorAcc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("account %s does not exist", delegatorAddr)) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", delegatorAddr) } moduleAcc := keeper.ak.GetAccount(ctx, moduleAccAddr) if moduleAcc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", moduleAccAddr)) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleAccAddr) } if !amt.IsValid() { - return sdk.ErrInvalidCoins(amt.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } oldCoins := moduleAcc.GetCoins() newCoins, hasNeg := oldCoins.SafeSub(amt) if hasNeg { - return sdk.ErrInsufficientCoins( - fmt.Sprintf("insufficient account funds; %s < %s", oldCoins, amt), + return sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", oldCoins, amt, ) } @@ -125,7 +124,7 @@ func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegat } if err := trackUndelegation(delegatorAcc, amt); err != nil { - return sdk.ErrInternal(fmt.Sprintf("failed to track undelegation: %v", err)) + return sdkerrors.Wrap(err, "failed to track undelegation") } keeper.ak.SetAccount(ctx, delegatorAcc) @@ -137,12 +136,12 @@ func (keeper BaseKeeper) UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegat type SendKeeper interface { ViewKeeper - InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) sdk.Error - SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error + InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error - SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) - AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) - SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) sdk.Error + SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) + AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) + SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error GetSendEnabled(ctx sdk.Context) bool SetSendEnabled(ctx sdk.Context, enabled bool) @@ -165,11 +164,12 @@ type BaseSendKeeper struct { } // NewBaseSendKeeper returns a new BaseSendKeeper. -func NewBaseSendKeeper(ak types.AccountKeeper, - paramSpace params.Subspace, codespace sdk.CodespaceType, blacklistedAddrs map[string]bool) BaseSendKeeper { +func NewBaseSendKeeper( + ak types.AccountKeeper, paramSpace params.Subspace, blacklistedAddrs map[string]bool, +) BaseSendKeeper { return BaseSendKeeper{ - BaseViewKeeper: NewBaseViewKeeper(ak, codespace), + BaseViewKeeper: NewBaseViewKeeper(ak), ak: ak, paramSpace: paramSpace, blacklistedAddrs: blacklistedAddrs, @@ -177,7 +177,7 @@ func NewBaseSendKeeper(ak types.AccountKeeper, } // InputOutputCoins handles a list of inputs and outputs -func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) sdk.Error { +func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error { // Safety check ensuring that when sending coins the keeper must maintain the // Check supply invariant and validity of Coins. if err := types.ValidateInputsOutputs(inputs, outputs); err != nil { @@ -216,7 +216,7 @@ func (keeper BaseSendKeeper) InputOutputCoins(ctx sdk.Context, inputs []types.In } // SendCoins moves coins from one account to another -func (keeper BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error { +func (keeper BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeTransfer, @@ -245,10 +245,9 @@ func (keeper BaseSendKeeper) SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, // SubtractCoins subtracts amt from the coins at the addr. // // CONTRACT: If the account is a vesting account, the amount has to be spendable. -func (keeper BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) { - +func (keeper BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) { if !amt.IsValid() { - return nil, sdk.ErrInvalidCoins(amt.String()) + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } oldCoins, spendableCoins := sdk.NewCoins(), sdk.NewCoins() @@ -263,8 +262,8 @@ func (keeper BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, // So the check here is sufficient instead of subtracting from oldCoins. _, hasNeg := spendableCoins.SafeSub(amt) if hasNeg { - return amt, sdk.ErrInsufficientCoins( - fmt.Sprintf("insufficient account funds; %s < %s", spendableCoins, amt), + return amt, sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", spendableCoins, amt, ) } @@ -275,18 +274,17 @@ func (keeper BaseSendKeeper) SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, } // AddCoins adds amt to the coins at the addr. -func (keeper BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) { - +func (keeper BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) { if !amt.IsValid() { - return nil, sdk.ErrInvalidCoins(amt.String()) + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } oldCoins := keeper.GetCoins(ctx, addr) newCoins := oldCoins.Add(amt) if newCoins.IsAnyNegative() { - return amt, sdk.ErrInsufficientCoins( - fmt.Sprintf("insufficient account funds; %s < %s", oldCoins, amt), + return amt, sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, "insufficient account funds; %s < %s", oldCoins, amt, ) } @@ -295,10 +293,9 @@ func (keeper BaseSendKeeper) AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt } // SetCoins sets the coins at the addr. -func (keeper BaseSendKeeper) SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) sdk.Error { - +func (keeper BaseSendKeeper) SetCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) error { if !amt.IsValid() { - return sdk.ErrInvalidCoins(amt.String()) + sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, amt.String()) } acc := keeper.ak.GetAccount(ctx, addr) @@ -340,19 +337,16 @@ var _ ViewKeeper = (*BaseViewKeeper)(nil) type ViewKeeper interface { GetCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins HasCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) bool - - Codespace() sdk.CodespaceType } // BaseViewKeeper implements a read only keeper implementation of ViewKeeper. type BaseViewKeeper struct { - ak types.AccountKeeper - codespace sdk.CodespaceType + ak types.AccountKeeper } // NewBaseViewKeeper returns a new BaseViewKeeper. -func NewBaseViewKeeper(ak types.AccountKeeper, codespace sdk.CodespaceType) BaseViewKeeper { - return BaseViewKeeper{ak: ak, codespace: codespace} +func NewBaseViewKeeper(ak types.AccountKeeper) BaseViewKeeper { + return BaseViewKeeper{ak: ak} } // Logger returns a module-specific logger. @@ -374,11 +368,6 @@ func (keeper BaseViewKeeper) HasCoins(ctx sdk.Context, addr sdk.AccAddress, amt return keeper.GetCoins(ctx, addr).IsAllGTE(amt) } -// Codespace returns the keeper's codespace. -func (keeper BaseViewKeeper) Codespace() sdk.CodespaceType { - return keeper.codespace -} - // CONTRACT: assumes that amt is valid. func trackDelegation(acc authexported.Account, blockTime time.Time, amt sdk.Coins) error { vacc, ok := acc.(vestexported.VestingAccount) diff --git a/x/bank/internal/keeper/keeper_test.go b/x/bank/internal/keeper/keeper_test.go index ba6c3f56c440..f93ddaa52969 100644 --- a/x/bank/internal/keeper/keeper_test.go +++ b/x/bank/internal/keeper/keeper_test.go @@ -65,8 +65,7 @@ func TestKeeper(t *testing.T) { require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - err2 := app.BankKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) - require.Implements(t, (*sdk.Error)(nil), err2) + app.BankKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) require.True(t, app.BankKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) require.True(t, app.BankKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) @@ -109,7 +108,7 @@ func TestSendKeeper(t *testing.T) { blacklistedAddrs := make(map[string]bool) paramSpace := app.ParamsKeeper.Subspace("newspace") - sendKeeper := keep.NewBaseSendKeeper(app.AccountKeeper, paramSpace, types.DefaultCodespace, blacklistedAddrs) + sendKeeper := keep.NewBaseSendKeeper(app.AccountKeeper, paramSpace, blacklistedAddrs) app.BankKeeper.SetSendEnabled(ctx, true) addr := sdk.AccAddress([]byte("addr1")) @@ -136,8 +135,7 @@ func TestSendKeeper(t *testing.T) { require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) - err := sendKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) - require.Implements(t, (*sdk.Error)(nil), err) + sendKeeper.SendCoins(ctx, addr, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 50))) require.True(t, sendKeeper.GetCoins(ctx, addr).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 10)))) require.True(t, sendKeeper.GetCoins(ctx, addr2).IsEqual(sdk.NewCoins(sdk.NewInt64Coin("foocoin", 5)))) @@ -149,7 +147,7 @@ func TestSendKeeper(t *testing.T) { // validate coins with invalid denoms or negative values cannot be sent // NOTE: We must use the Coin literal as the constructor does not allow // negative values. - err = sendKeeper.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.Coin{Denom: "FOOCOIN", Amount: sdk.NewInt(-5)}}) + err := sendKeeper.SendCoins(ctx, addr, addr2, sdk.Coins{sdk.Coin{Denom: "FOOCOIN", Amount: sdk.NewInt(-5)}}) require.Error(t, err) } @@ -202,7 +200,7 @@ func TestViewKeeper(t *testing.T) { app, ctx := createTestApp(false) //paramSpace := app.ParamsKeeper.Subspace(types.DefaultParamspace) - viewKeeper := keep.NewBaseViewKeeper(app.AccountKeeper, types.DefaultCodespace) + viewKeeper := keep.NewBaseViewKeeper(app.AccountKeeper) addr := sdk.AccAddress([]byte("addr1")) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) diff --git a/x/bank/internal/keeper/querier.go b/x/bank/internal/keeper/querier.go index bf303e2930fa..165d01879621 100644 --- a/x/bank/internal/keeper/querier.go +++ b/x/bank/internal/keeper/querier.go @@ -1,12 +1,11 @@ package keeper import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" ) @@ -17,24 +16,24 @@ const ( // NewQuerier returns a new sdk.Keeper instance. func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case QueryBalance: return queryBalance(ctx, req, k) default: - return nil, sdk.ErrUnknownRequest("unknown bank query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) } } } // queryBalance fetch an account's balance for the supplied height. // Height and account address are passed as first and second path components respectively. -func queryBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryBalanceParams if err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms); err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } coins := k.GetCoins(ctx, params.Address) @@ -44,7 +43,7 @@ func queryBalance(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk bz, err := codec.MarshalJSONIndent(types.ModuleCdc, coins) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil diff --git a/x/bank/internal/types/errors.go b/x/bank/internal/types/errors.go index d9c0c7d11d1d..157408c941b7 100644 --- a/x/bank/internal/types/errors.go +++ b/x/bank/internal/types/errors.go @@ -1,33 +1,13 @@ package types import ( - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// Bank errors reserve 100 ~ 199. -const ( - DefaultCodespace sdk.CodespaceType = ModuleName - - CodeSendDisabled sdk.CodeType = 101 - CodeInvalidInputsOutputs sdk.CodeType = 102 +// x/bank module sentinel errors +var ( + ErrNoInputs = sdkerrors.Register(ModuleName, 1, "no inputs to send transaction") + ErrNoOutputs = sdkerrors.Register(ModuleName, 2, "no outputs to send transaction") + ErrInputOutputMismatch = sdkerrors.Register(ModuleName, 3, "sum inputs != sum outputs") + ErrSendDisabled = sdkerrors.Register(ModuleName, 4, "send transactions are disabled") ) - -// ErrNoInputs is an error -func ErrNoInputs(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInputsOutputs, "no inputs to send transaction") -} - -// ErrNoOutputs is an error -func ErrNoOutputs(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInputsOutputs, "no outputs to send transaction") -} - -// ErrInputOutputMismatch is an error -func ErrInputOutputMismatch(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInputsOutputs, "sum inputs != sum outputs") -} - -// ErrSendDisabled is an error -func ErrSendDisabled(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeSendDisabled, "send transactions are currently disabled") -} diff --git a/x/bank/internal/types/msgs.go b/x/bank/internal/types/msgs.go index 58336e24d9e4..c8fdaa5afe92 100644 --- a/x/bank/internal/types/msgs.go +++ b/x/bank/internal/types/msgs.go @@ -2,6 +2,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // RouterKey is they name of the bank module @@ -28,18 +29,18 @@ func (msg MsgSend) Route() string { return RouterKey } func (msg MsgSend) Type() string { return "send" } // ValidateBasic Implements Msg. -func (msg MsgSend) ValidateBasic() sdk.Error { +func (msg MsgSend) ValidateBasic() error { if msg.FromAddress.Empty() { - return sdk.ErrInvalidAddress("missing sender address") + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing sender address") } if msg.ToAddress.Empty() { - return sdk.ErrInvalidAddress("missing recipient address") + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing recipient address") } if !msg.Amount.IsValid() { - return sdk.ErrInvalidCoins("send amount is invalid: " + msg.Amount.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) } if !msg.Amount.IsAllPositive() { - return sdk.ErrInsufficientCoins("send amount must be positive") + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) } return nil } @@ -74,14 +75,14 @@ func (msg MsgMultiSend) Route() string { return RouterKey } func (msg MsgMultiSend) Type() string { return "multisend" } // ValidateBasic Implements Msg. -func (msg MsgMultiSend) ValidateBasic() sdk.Error { +func (msg MsgMultiSend) ValidateBasic() error { // this just makes sure all the inputs and outputs are properly formatted, // not that they actually have the money inside if len(msg.Inputs) == 0 { - return ErrNoInputs(DefaultCodespace).TraceSDK("") + return ErrNoInputs } if len(msg.Outputs) == 0 { - return ErrNoOutputs(DefaultCodespace).TraceSDK("") + return ErrNoOutputs } return ValidateInputsOutputs(msg.Inputs, msg.Outputs) @@ -108,15 +109,15 @@ type Input struct { } // ValidateBasic - validate transaction input -func (in Input) ValidateBasic() sdk.Error { +func (in Input) ValidateBasic() error { if len(in.Address) == 0 { - return sdk.ErrInvalidAddress(in.Address.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "input address missing") } if !in.Coins.IsValid() { - return sdk.ErrInvalidCoins(in.Coins.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, in.Coins.String()) } if !in.Coins.IsAllPositive() { - return sdk.ErrInvalidCoins(in.Coins.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, in.Coins.String()) } return nil } @@ -136,15 +137,15 @@ type Output struct { } // ValidateBasic - validate transaction output -func (out Output) ValidateBasic() sdk.Error { +func (out Output) ValidateBasic() error { if len(out.Address) == 0 { - return sdk.ErrInvalidAddress(out.Address.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "output address missing") } if !out.Coins.IsValid() { - return sdk.ErrInvalidCoins(out.Coins.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, out.Coins.String()) } if !out.Coins.IsAllPositive() { - return sdk.ErrInvalidCoins(out.Coins.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, out.Coins.String()) } return nil } @@ -159,26 +160,28 @@ func NewOutput(addr sdk.AccAddress, coins sdk.Coins) Output { // ValidateInputsOutputs validates that each respective input and output is // valid and that the sum of inputs is equal to the sum of outputs. -func ValidateInputsOutputs(inputs []Input, outputs []Output) sdk.Error { +func ValidateInputsOutputs(inputs []Input, outputs []Output) error { var totalIn, totalOut sdk.Coins for _, in := range inputs { if err := in.ValidateBasic(); err != nil { - return err.TraceSDK("") + return err } + totalIn = totalIn.Add(in.Coins) } for _, out := range outputs { if err := out.ValidateBasic(); err != nil { - return err.TraceSDK("") + return err } + totalOut = totalOut.Add(out.Coins) } // make sure inputs and outputs match if !totalIn.IsEqual(totalOut) { - return ErrInputOutputMismatch(DefaultCodespace) + return ErrInputOutputMismatch } return nil diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index 71a88386c960..7cf08a8452f2 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -1,7 +1,6 @@ package simulation import ( - "errors" "math/rand" "github.com/tendermint/tendermint/crypto" @@ -115,9 +114,9 @@ func sendMsgSend( privkeys..., ) - res := app.Deliver(tx) - if !res.IsOK() { - return errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return err } return nil @@ -259,9 +258,9 @@ func sendMsgMultiSend( privkeys..., ) - res := app.Deliver(tx) - if !res.IsOK() { - return errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return err } return nil diff --git a/x/crisis/alias.go b/x/crisis/alias.go index 6c176e265544..1b05371f376b 100644 --- a/x/crisis/alias.go +++ b/x/crisis/alias.go @@ -1,38 +1,30 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/crisis/types package crisis +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/crisis/internal/keeper" "github.com/cosmos/cosmos-sdk/x/crisis/internal/types" ) const ( - DefaultCodespace = types.DefaultCodespace - CodeInvalidInput = types.CodeInvalidInput - ModuleName = types.ModuleName - DefaultParamspace = types.DefaultParamspace - + ModuleName = types.ModuleName + DefaultParamspace = types.DefaultParamspace EventTypeInvariant = types.EventTypeInvariant AttributeValueCrisis = types.AttributeValueCrisis AttributeKeyRoute = types.AttributeKeyRoute ) var ( - // functions aliases - RegisterCodec = types.RegisterCodec - ErrNilSender = types.ErrNilSender - ErrUnknownInvariant = types.ErrUnknownInvariant - NewGenesisState = types.NewGenesisState - DefaultGenesisState = types.DefaultGenesisState - NewMsgVerifyInvariant = types.NewMsgVerifyInvariant - ParamKeyTable = types.ParamKeyTable - NewInvarRoute = types.NewInvarRoute - NewKeeper = keeper.NewKeeper - - // variable aliases + RegisterCodec = types.RegisterCodec + ErrNoSender = types.ErrNoSender + ErrUnknownInvariant = types.ErrUnknownInvariant + NewGenesisState = types.NewGenesisState + DefaultGenesisState = types.DefaultGenesisState + NewMsgVerifyInvariant = types.NewMsgVerifyInvariant + ParamKeyTable = types.ParamKeyTable + NewInvarRoute = types.NewInvarRoute + NewKeeper = keeper.NewKeeper ModuleCdc = types.ModuleCdc ParamStoreKeyConstantFee = types.ParamStoreKeyConstantFee ) diff --git a/x/crisis/handler.go b/x/crisis/handler.go index 9ff52c2f339e..c7e58b6861be 100644 --- a/x/crisis/handler.go +++ b/x/crisis/handler.go @@ -1,9 +1,8 @@ package crisis import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/crisis/internal/keeper" "github.com/cosmos/cosmos-sdk/x/crisis/internal/types" ) @@ -12,7 +11,7 @@ import ( const RouterKey = types.ModuleName func NewHandler(k keeper.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -20,18 +19,16 @@ func NewHandler(k keeper.Keeper) sdk.Handler { return handleMsgVerifyInvariant(ctx, msg, k) default: - errMsg := fmt.Sprintf("unrecognized crisis message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized crisis message type: %T", msg) } } } -func handleMsgVerifyInvariant(ctx sdk.Context, msg types.MsgVerifyInvariant, k keeper.Keeper) sdk.Result { - // remove the constant fee +func handleMsgVerifyInvariant(ctx sdk.Context, msg types.MsgVerifyInvariant, k keeper.Keeper) (*sdk.Result, error) { constantFee := sdk.NewCoins(k.GetConstantFee(ctx)) if err := k.SendCoinsFromAccountToFeeCollector(ctx, msg.Sender, constantFee); err != nil { - return err.Result() + return nil, err } // use a cached context to avoid gas costs during invariants @@ -51,7 +48,7 @@ func handleMsgVerifyInvariant(ctx sdk.Context, msg types.MsgVerifyInvariant, k k } if !found { - return types.ErrUnknownInvariant(types.DefaultCodespace).Result() + return nil, types.ErrUnknownInvariant } if stop { @@ -86,5 +83,5 @@ func handleMsgVerifyInvariant(ctx sdk.Context, msg types.MsgVerifyInvariant, k k ), }) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } diff --git a/x/crisis/handler_test.go b/x/crisis/handler_test.go index 064d6234bc9b..f4c2f8182dbf 100644 --- a/x/crisis/handler_test.go +++ b/x/crisis/handler_test.go @@ -69,14 +69,18 @@ func TestHandleMsgVerifyInvariant(t *testing.T) { switch tc.expectedResult { case "fail": - res := h(ctx, tc.msg) - require.False(t, res.IsOK()) + res, err := h(ctx, tc.msg) + require.Error(t, err) + require.Nil(t, res) + case "pass": - res := h(ctx, tc.msg) - require.True(t, res.IsOK()) + res, err := h(ctx, tc.msg) + require.NoError(t, err) + require.NotNil(t, res) + case "panic": require.Panics(t, func() { - _ = h(ctx, tc.msg) + h(ctx, tc.msg) }) } }) @@ -92,7 +96,10 @@ func TestHandleMsgVerifyInvariantWithNotEnoughSenderCoins(t *testing.T) { h := crisis.NewHandler(app.CrisisKeeper) msg := crisis.NewMsgVerifyInvariant(sender, testModuleName, dummyRouteWhichPasses.Route) - require.False(t, h(ctx, msg).IsOK()) + + res, err := h(ctx, msg) + require.Error(t, err) + require.Nil(t, res) } func TestHandleMsgVerifyInvariantWithInvariantBrokenAndNotEnoughPoolCoins(t *testing.T) { @@ -106,8 +113,9 @@ func TestHandleMsgVerifyInvariantWithInvariantBrokenAndNotEnoughPoolCoins(t *tes h := crisis.NewHandler(app.CrisisKeeper) msg := crisis.NewMsgVerifyInvariant(sender, testModuleName, dummyRouteWhichFails.Route) - var res sdk.Result + + var res *sdk.Result require.Panics(t, func() { - res = h(ctx, msg) + res, _ = h(ctx, msg) }, fmt.Sprintf("%v", res)) } diff --git a/x/crisis/internal/keeper/keeper.go b/x/crisis/internal/keeper/keeper.go index cb6f9a6548d8..f4c8163bb740 100644 --- a/x/crisis/internal/keeper/keeper.go +++ b/x/crisis/internal/keeper/keeper.go @@ -90,6 +90,6 @@ func (k Keeper) AssertInvariants(ctx sdk.Context) { func (k Keeper) InvCheckPeriod() uint { return k.invCheckPeriod } // SendCoinsFromAccountToFeeCollector transfers amt to the fee collector account. -func (k Keeper) SendCoinsFromAccountToFeeCollector(ctx sdk.Context, senderAddr sdk.AccAddress, amt sdk.Coins) sdk.Error { +func (k Keeper) SendCoinsFromAccountToFeeCollector(ctx sdk.Context, senderAddr sdk.AccAddress, amt sdk.Coins) error { return k.supplyKeeper.SendCoinsFromAccountToModule(ctx, senderAddr, k.feeCollectorName, amt) } diff --git a/x/crisis/internal/types/errors.go b/x/crisis/internal/types/errors.go index 3b7392abfae6..ac63f3ff43de 100644 --- a/x/crisis/internal/types/errors.go +++ b/x/crisis/internal/types/errors.go @@ -1,23 +1,11 @@ package types import ( - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -const ( - // default codespace for crisis module - DefaultCodespace sdk.CodespaceType = ModuleName - - // CodeInvalidInput is the codetype for invalid input for the crisis module - CodeInvalidInput sdk.CodeType = 103 +// x/crisis module sentinel errors +var ( + ErrNoSender = sdkerrors.Register(ModuleName, 1, "sender address is empty") + ErrUnknownInvariant = sdkerrors.Register(ModuleName, 2, "unknown invariant") ) - -// ErrNilSender - no sender provided for the input -func ErrNilSender(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "sender address is nil") -} - -// ErrUnknownInvariant - unknown invariant provided -func ErrUnknownInvariant(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "unknown invariant") -} diff --git a/x/crisis/internal/types/expected_keepers.go b/x/crisis/internal/types/expected_keepers.go index 5690c0c38688..3cd0e9e7f57a 100644 --- a/x/crisis/internal/types/expected_keepers.go +++ b/x/crisis/internal/types/expected_keepers.go @@ -6,5 +6,5 @@ import ( // SupplyKeeper defines the expected supply keeper (noalias) type SupplyKeeper interface { - SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error } diff --git a/x/crisis/internal/types/msgs.go b/x/crisis/internal/types/msgs.go index e16ffb528e0c..f496df636b60 100644 --- a/x/crisis/internal/types/msgs.go +++ b/x/crisis/internal/types/msgs.go @@ -39,9 +39,9 @@ func (msg MsgVerifyInvariant) GetSignBytes() []byte { } // quick validity check -func (msg MsgVerifyInvariant) ValidateBasic() sdk.Error { +func (msg MsgVerifyInvariant) ValidateBasic() error { if msg.Sender.Empty() { - return ErrNilSender(DefaultCodespace) + return ErrNoSender } return nil } diff --git a/x/distribution/alias.go b/x/distribution/alias.go index de6f269e6a1c..ff181d7331e3 100644 --- a/x/distribution/alias.go +++ b/x/distribution/alias.go @@ -10,11 +10,6 @@ import ( const ( DefaultParamspace = keeper.DefaultParamspace - DefaultCodespace = types.DefaultCodespace - CodeInvalidInput = types.CodeInvalidInput - CodeNoDistributionInfo = types.CodeNoDistributionInfo - CodeNoValidatorCommission = types.CodeNoValidatorCommission - CodeSetWithdrawAddrDisabled = types.CodeSetWithdrawAddrDisabled ModuleName = types.ModuleName StoreKey = types.StoreKey RouterKey = types.RouterKey @@ -70,11 +65,13 @@ var ( CreateTestInputAdvanced = keeper.CreateTestInputAdvanced RegisterCodec = types.RegisterCodec NewDelegatorStartingInfo = types.NewDelegatorStartingInfo - ErrNilDelegatorAddr = types.ErrNilDelegatorAddr - ErrNilWithdrawAddr = types.ErrNilWithdrawAddr - ErrNilValidatorAddr = types.ErrNilValidatorAddr - ErrNoDelegationDistInfo = types.ErrNoDelegationDistInfo + ErrEmptyDelegatorAddr = types.ErrEmptyDelegatorAddr + ErrEmptyWithdrawAddr = types.ErrEmptyWithdrawAddr + ErrEmptyValidatorAddr = types.ErrEmptyValidatorAddr + ErrEmptyDelegationDistInfo = types.ErrEmptyDelegationDistInfo ErrNoValidatorDistInfo = types.ErrNoValidatorDistInfo + ErrNoValidatorExists = types.ErrNoValidatorExists + ErrNoDelegationExists = types.ErrNoDelegationExists ErrNoValidatorCommission = types.ErrNoValidatorCommission ErrSetWithdrawAddrDisabled = types.ErrSetWithdrawAddrDisabled ErrBadDistribution = types.ErrBadDistribution @@ -134,7 +131,6 @@ type ( Hooks = keeper.Hooks Keeper = keeper.Keeper DelegatorStartingInfo = types.DelegatorStartingInfo - CodeType = types.CodeType FeePool = types.FeePool DelegatorWithdrawInfo = types.DelegatorWithdrawInfo ValidatorOutstandingRewardsRecord = types.ValidatorOutstandingRewardsRecord diff --git a/x/distribution/handler.go b/x/distribution/handler.go index 90c4bc14de93..642b9e0d89a1 100644 --- a/x/distribution/handler.go +++ b/x/distribution/handler.go @@ -1,16 +1,15 @@ package distribution import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/distribution/keeper" "github.com/cosmos/cosmos-sdk/x/distribution/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) func NewHandler(k keeper.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -27,18 +26,17 @@ func NewHandler(k keeper.Keeper) sdk.Handler { return handleMsgFundCommunityPool(ctx, msg, k) default: - errMsg := fmt.Sprintf("unrecognized distribution message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized distribution message type: %T", msg) } } } // These functions assume everything has been authenticated (ValidateBasic passed, and signatures checked) -func handleMsgModifyWithdrawAddress(ctx sdk.Context, msg types.MsgSetWithdrawAddress, k keeper.Keeper) sdk.Result { +func handleMsgModifyWithdrawAddress(ctx sdk.Context, msg types.MsgSetWithdrawAddress, k keeper.Keeper) (*sdk.Result, error) { err := k.SetWithdrawAddr(ctx, msg.DelegatorAddress, msg.WithdrawAddress) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -49,13 +47,13 @@ func handleMsgModifyWithdrawAddress(ctx sdk.Context, msg types.MsgSetWithdrawAdd ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgWithdrawDelegatorReward(ctx sdk.Context, msg types.MsgWithdrawDelegatorReward, k keeper.Keeper) sdk.Result { +func handleMsgWithdrawDelegatorReward(ctx sdk.Context, msg types.MsgWithdrawDelegatorReward, k keeper.Keeper) (*sdk.Result, error) { _, err := k.WithdrawDelegationRewards(ctx, msg.DelegatorAddress, msg.ValidatorAddress) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -66,13 +64,13 @@ func handleMsgWithdrawDelegatorReward(ctx sdk.Context, msg types.MsgWithdrawDele ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgWithdrawValidatorCommission(ctx sdk.Context, msg types.MsgWithdrawValidatorCommission, k keeper.Keeper) sdk.Result { +func handleMsgWithdrawValidatorCommission(ctx sdk.Context, msg types.MsgWithdrawValidatorCommission, k keeper.Keeper) (*sdk.Result, error) { _, err := k.WithdrawValidatorCommission(ctx, msg.ValidatorAddress) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -83,12 +81,12 @@ func handleMsgWithdrawValidatorCommission(ctx sdk.Context, msg types.MsgWithdraw ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgFundCommunityPool(ctx sdk.Context, msg types.MsgFundCommunityPool, k keeper.Keeper) sdk.Result { +func handleMsgFundCommunityPool(ctx sdk.Context, msg types.MsgFundCommunityPool, k keeper.Keeper) (*sdk.Result, error) { if err := k.FundCommunityPool(ctx, msg.Amount, msg.Depositor); err != nil { - return sdk.ResultFromError(err) + return nil, err } ctx.EventManager().EmitEvent( @@ -99,18 +97,17 @@ func handleMsgFundCommunityPool(ctx sdk.Context, msg types.MsgFundCommunityPool, ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } func NewCommunityPoolSpendProposalHandler(k Keeper) govtypes.Handler { - return func(ctx sdk.Context, content govtypes.Content) sdk.Error { + return func(ctx sdk.Context, content govtypes.Content) error { switch c := content.(type) { case types.CommunityPoolSpendProposal: return keeper.HandleCommunityPoolSpendProposal(ctx, k, c) default: - errMsg := fmt.Sprintf("unrecognized distr proposal content type: %T", c) - return sdk.ErrUnknownRequest(errMsg) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized distr proposal content type: %T", c) } } } diff --git a/x/distribution/keeper/allocation_test.go b/x/distribution/keeper/allocation_test.go index 8f1b84c5f35c..83821ea3820d 100644 --- a/x/distribution/keeper/allocation_test.go +++ b/x/distribution/keeper/allocation_test.go @@ -16,9 +16,15 @@ func TestAllocateTokensToValidatorWithCommission(t *testing.T) { // create validator with 50% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, - sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + msg := staking.NewMsgCreateValidator( + valOpAddr1, valConsPk1, + sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt(), + ) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) + val := sk.Validator(ctx, valOpAddr1) // allocate tokens @@ -45,13 +51,19 @@ func TestAllocateTokensToManyValidators(t *testing.T) { commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // create second validator with 0% commission commission = staking.NewCommissionRates(sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0)) msg = staking.NewMsgCreateValidator(valOpAddr2, valConsPk2, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err = sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) abciValA := abci.Validator{ Address: valConsPk1.Address(), @@ -76,7 +88,7 @@ func TestAllocateTokensToManyValidators(t *testing.T) { feeCollector := supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName) require.NotNil(t, feeCollector) - err := feeCollector.SetCoins(fees) + err = feeCollector.SetCoins(fees) require.NoError(t, err) ak.SetAccount(ctx, feeCollector) @@ -116,19 +128,25 @@ func TestAllocateTokensTruncation(t *testing.T) { commission := staking.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(110)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // create second validator with 10% commission commission = staking.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0)) msg = staking.NewMsgCreateValidator(valOpAddr2, valConsPk2, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + res, err = sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // create third validator with 10% commission commission = staking.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDec(0)) msg = staking.NewMsgCreateValidator(valOpAddr3, valConsPk3, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + res, err = sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) abciValA := abci.Validator{ Address: valConsPk1.Address(), @@ -159,7 +177,7 @@ func TestAllocateTokensTruncation(t *testing.T) { feeCollector := supplyKeeper.GetModuleAccount(ctx, k.feeCollectorName) require.NotNil(t, feeCollector) - err := feeCollector.SetCoins(fees) + err = feeCollector.SetCoins(fees) require.NoError(t, err) ak.SetAccount(ctx, feeCollector) diff --git a/x/distribution/keeper/delegation.go b/x/distribution/keeper/delegation.go index 4044c4d1961a..7b28b6048eaf 100644 --- a/x/distribution/keeper/delegation.go +++ b/x/distribution/keeper/delegation.go @@ -136,10 +136,10 @@ func (k Keeper) calculateDelegationRewards(ctx sdk.Context, val exported.Validat return rewards } -func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val exported.ValidatorI, del exported.DelegationI) (sdk.Coins, sdk.Error) { +func (k Keeper) withdrawDelegationRewards(ctx sdk.Context, val exported.ValidatorI, del exported.DelegationI) (sdk.Coins, error) { // check existence of delegator starting info if !k.HasDelegatorStartingInfo(ctx, del.GetValidatorAddr(), del.GetDelegatorAddr()) { - return nil, types.ErrNoDelegationDistInfo(k.codespace) + return nil, types.ErrEmptyDelegationDistInfo } // end current period and calculate rewards diff --git a/x/distribution/keeper/delegation_test.go b/x/distribution/keeper/delegation_test.go index db6f6fb434ea..6d23ad958991 100644 --- a/x/distribution/keeper/delegation_test.go +++ b/x/distribution/keeper/delegation_test.go @@ -15,9 +15,13 @@ func TestCalculateRewardsBasic(t *testing.T) { // create validator with 50% commission commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, - sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + msg := staking.NewMsgCreateValidator( + valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt(), + ) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -72,8 +76,10 @@ func TestCalculateRewardsAfterSlash(t *testing.T) { valTokens := sdk.TokensFromConsensusPower(valPower) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt()) - got := sh(ctx, msg) - require.True(t, got.IsOK(), "%v", got) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -135,7 +141,10 @@ func TestCalculateRewardsAfterManySlashes(t *testing.T) { commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -207,7 +216,10 @@ func TestCalculateRewardsMultiDelegator(t *testing.T) { commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -226,7 +238,11 @@ func TestCalculateRewardsMultiDelegator(t *testing.T) { // second delegation msg2 := staking.NewMsgDelegate(sdk.AccAddress(valOpAddr2), valOpAddr1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))) - require.True(t, sh(ctx, msg2).IsOK()) + + res, err = sh(ctx, msg2) + require.NoError(t, err) + require.NotNil(t, res) + del2 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr2), valOpAddr1) // fetch updated validator @@ -280,7 +296,10 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) { sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt(), ) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // assert correct initial balance expTokens := balanceTokens.Sub(valTokens) @@ -308,7 +327,7 @@ func TestWithdrawDelegationRewardsBasic(t *testing.T) { require.Equal(t, uint64(2), k.GetValidatorHistoricalReferenceCount(ctx)) // withdraw rewards - _, err := k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) + _, err = k.WithdrawDelegationRewards(ctx, sdk.AccAddress(valOpAddr1), valOpAddr1) require.Nil(t, err) // historical count should still be 2 (added one record, cleared one) @@ -343,7 +362,10 @@ func TestCalculateRewardsAfterManySlashesInSameBlock(t *testing.T) { commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -410,7 +432,10 @@ func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { valTokens := sdk.TokensFromConsensusPower(power) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, valTokens), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -436,7 +461,11 @@ func TestCalculateRewardsMultiDelegatorMultiSlash(t *testing.T) { delTokens := sdk.TokensFromConsensusPower(100) msg2 := staking.NewMsgDelegate(sdk.AccAddress(valOpAddr2), valOpAddr1, sdk.NewCoin(sdk.DefaultBondDenom, delTokens)) - require.True(t, sh(ctx, msg2).IsOK()) + + res, err = sh(ctx, msg2) + require.NoError(t, err) + require.NotNil(t, res) + del2 := sk.Delegation(ctx, sdk.AccAddress(valOpAddr2), valOpAddr1) // end block @@ -491,7 +520,10 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { commission := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, commission, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond validator staking.EndBlocker(ctx, sk) @@ -511,7 +543,9 @@ func TestCalculateRewardsMultiDelegatorMultWithdraw(t *testing.T) { // second delegation msg2 := staking.NewMsgDelegate(sdk.AccAddress(valOpAddr2), valOpAddr1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))) - require.True(t, sh(ctx, msg2).IsOK()) + res, err = sh(ctx, msg2) + require.NoError(t, err) + require.NotNil(t, res) // historical count should be 3 (second delegation init) require.Equal(t, uint64(3), k.GetValidatorHistoricalReferenceCount(ctx)) diff --git a/x/distribution/keeper/fee_pool.go b/x/distribution/keeper/fee_pool.go index a16e8258c029..34ad5f0d0d06 100644 --- a/x/distribution/keeper/fee_pool.go +++ b/x/distribution/keeper/fee_pool.go @@ -7,7 +7,7 @@ import ( // DistributeFromFeePool distributes funds from the distribution module account to // a receiver address while updating the community pool -func (k Keeper) DistributeFromFeePool(ctx sdk.Context, amount sdk.Coins, receiveAddr sdk.AccAddress) sdk.Error { +func (k Keeper) DistributeFromFeePool(ctx sdk.Context, amount sdk.Coins, receiveAddr sdk.AccAddress) error { feePool := k.GetFeePool(ctx) // NOTE the community pool isn't a module account, however its coins @@ -15,8 +15,9 @@ func (k Keeper) DistributeFromFeePool(ctx sdk.Context, amount sdk.Coins, receive // must be reduced separately from the SendCoinsFromModuleToAccount call newPool, negative := feePool.CommunityPool.SafeSub(sdk.NewDecCoins(amount)) if negative { - return types.ErrBadDistribution(k.codespace) + return types.ErrBadDistribution } + feePool.CommunityPool = newPool err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, receiveAddr, amount) diff --git a/x/distribution/keeper/keeper.go b/x/distribution/keeper/keeper.go index 6aca0d86fa10..76b582bae209 100644 --- a/x/distribution/keeper/keeper.go +++ b/x/distribution/keeper/keeper.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/params" @@ -19,17 +20,17 @@ type Keeper struct { stakingKeeper types.StakingKeeper supplyKeeper types.SupplyKeeper - codespace sdk.CodespaceType - blacklistedAddrs map[string]bool feeCollectorName string // name of the FeeCollector ModuleAccount } // NewKeeper creates a new distribution Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, - sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, codespace sdk.CodespaceType, - feeCollectorName string, blacklistedAddrs map[string]bool) Keeper { +func NewKeeper( + cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, + sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string, + blacklistedAddrs map[string]bool, +) Keeper { // ensure distribution module account is set if addr := supplyKeeper.GetModuleAddress(types.ModuleName); addr == nil { @@ -42,7 +43,6 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, paramSpace: paramSpace.WithKeyTable(ParamKeyTable()), stakingKeeper: sk, supplyKeeper: supplyKeeper, - codespace: codespace, feeCollectorName: feeCollectorName, blacklistedAddrs: blacklistedAddrs, } @@ -54,13 +54,13 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { } // SetWithdrawAddr sets a new address that will receive the rewards upon withdrawal -func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) sdk.Error { +func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) error { if k.blacklistedAddrs[withdrawAddr.String()] { - return sdk.ErrUnauthorized(fmt.Sprintf("%s is blacklisted from receiving external funds", withdrawAddr)) + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is blacklisted from receiving external funds", withdrawAddr) } if !k.GetWithdrawAddrEnabled(ctx) { - return types.ErrSetWithdrawAddrDisabled(k.codespace) + return types.ErrSetWithdrawAddrDisabled } ctx.EventManager().EmitEvent( @@ -75,15 +75,15 @@ func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, w } // withdraw rewards from a delegation -func (k Keeper) WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, sdk.Error) { +func (k Keeper) WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) { val := k.stakingKeeper.Validator(ctx, valAddr) if val == nil { - return nil, types.ErrNoValidatorDistInfo(k.codespace) + return nil, types.ErrNoValidatorDistInfo } del := k.stakingKeeper.Delegation(ctx, delAddr, valAddr) if del == nil { - return nil, types.ErrNoDelegationDistInfo(k.codespace) + return nil, types.ErrEmptyDelegationDistInfo } // withdraw rewards @@ -106,11 +106,11 @@ func (k Keeper) WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddres } // withdraw validator commission -func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddress) (sdk.Coins, sdk.Error) { +func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddress) (sdk.Coins, error) { // fetch validator accumulated commission accumCommission := k.GetValidatorAccumulatedCommission(ctx, valAddr) if accumCommission.IsZero() { - return nil, types.ErrNoValidatorCommission(k.codespace) + return nil, types.ErrNoValidatorCommission } commission, remainder := accumCommission.TruncateDecimal() @@ -147,6 +147,7 @@ func (k Keeper) GetTotalRewards(ctx sdk.Context) (totalRewards sdk.DecCoins) { return false }, ) + return totalRewards } diff --git a/x/distribution/keeper/proposal_handler.go b/x/distribution/keeper/proposal_handler.go index 2daf2245ed76..f60a3f88154d 100644 --- a/x/distribution/keeper/proposal_handler.go +++ b/x/distribution/keeper/proposal_handler.go @@ -4,13 +4,14 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/distribution/types" ) // HandleCommunityPoolSpendProposal is a handler for executing a passed community spend proposal -func HandleCommunityPoolSpendProposal(ctx sdk.Context, k Keeper, p types.CommunityPoolSpendProposal) sdk.Error { +func HandleCommunityPoolSpendProposal(ctx sdk.Context, k Keeper, p types.CommunityPoolSpendProposal) error { if k.blacklistedAddrs[p.Recipient.String()] { - return sdk.ErrUnauthorized(fmt.Sprintf("%s is blacklisted from receiving external funds", p.Recipient)) + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is blacklisted from receiving external funds", p.Recipient) } err := k.DistributeFromFeePool(ctx, p.Amount, p.Recipient) diff --git a/x/distribution/keeper/querier.go b/x/distribution/keeper/querier.go index a057340340db..7e7c404cee14 100644 --- a/x/distribution/keeper/querier.go +++ b/x/distribution/keeper/querier.go @@ -2,18 +2,18 @@ package keeper import ( "encoding/json" - "fmt" abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/distribution/types" "github.com/cosmos/cosmos-sdk/x/staking/exported" ) func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryParams: return queryParams(ctx, path[1:], req, k) @@ -43,82 +43,93 @@ func NewQuerier(k Keeper) sdk.Querier { return queryCommunityPool(ctx, path[1:], req, k) default: - return nil, sdk.ErrUnknownRequest("unknown distr query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) } } } -func queryParams(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryParams(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, error) { switch path[0] { case types.ParamCommunityTax: bz, err := codec.MarshalJSONIndent(k.cdc, k.GetCommunityTax(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + case types.ParamBaseProposerReward: bz, err := codec.MarshalJSONIndent(k.cdc, k.GetBaseProposerReward(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + case types.ParamBonusProposerReward: bz, err := codec.MarshalJSONIndent(k.cdc, k.GetBonusProposerReward(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + case types.ParamWithdrawAddrEnabled: bz, err := codec.MarshalJSONIndent(k.cdc, k.GetWithdrawAddrEnabled(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + default: - return nil, sdk.ErrUnknownRequest(fmt.Sprintf("%s is not a valid query request path", req.Path)) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "%s is not a valid query request path", req.Path) } } -func queryValidatorOutstandingRewards(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidatorOutstandingRewards(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorOutstandingRewardsParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } + rewards := k.GetValidatorOutstandingRewards(ctx, params.ValidatorAddress) if rewards == nil { rewards = sdk.DecCoins{} } + bz, err := codec.MarshalJSONIndent(k.cdc, rewards) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } -func queryValidatorCommission(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidatorCommission(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorCommissionParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } + commission := k.GetValidatorAccumulatedCommission(ctx, params.ValidatorAddress) if commission == nil { commission = sdk.DecCoins{} } + bz, err := codec.MarshalJSONIndent(k.cdc, commission) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } -func queryValidatorSlashes(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidatorSlashes(ctx sdk.Context, path []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorSlashesParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } + events := make([]types.ValidatorSlashEvent, 0) k.IterateValidatorSlashEventsBetween(ctx, params.ValidatorAddress, params.StartingHeight, params.EndingHeight, func(height uint64, event types.ValidatorSlashEvent) (stop bool) { @@ -126,18 +137,20 @@ func queryValidatorSlashes(ctx sdk.Context, path []string, req abci.RequestQuery return false }, ) + bz, err := codec.MarshalJSONIndent(k.cdc, events) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } -func queryDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegationRewardsParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } // cache-wrap context as to not persist state changes during querying @@ -145,14 +158,12 @@ func queryDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, val := k.stakingKeeper.Validator(ctx, params.ValidatorAddress) if val == nil { - // TODO: Should use ErrNoValidatorFound from staking/types - return nil, sdk.ErrInternal(fmt.Sprintf("validator %s does not exist", params.ValidatorAddress)) + return nil, sdkerrors.Wrap(types.ErrNoValidatorExists, params.ValidatorAddress.String()) } del := k.stakingKeeper.Delegation(ctx, params.DelegatorAddress, params.ValidatorAddress) if del == nil { - // TODO: Should use ErrNoDelegation from staking/types - return nil, sdk.ErrInternal("delegation does not exist") + return nil, types.ErrNoDelegationExists } endingPeriod := k.incrementValidatorPeriod(ctx, val) @@ -163,17 +174,17 @@ func queryDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, bz, err := codec.MarshalJSONIndent(k.cdc, rewards) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil } -func queryDelegatorTotalRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorTotalRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegatorParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } // cache-wrap context as to not persist state changes during querying @@ -192,24 +203,26 @@ func queryDelegatorTotalRewards(ctx sdk.Context, _ []string, req abci.RequestQue delRewards = append(delRewards, types.NewDelegationDelegatorReward(valAddr, delReward)) total = total.Add(delReward) + return false }, ) totalRewards := types.NewQueryDelegatorTotalRewardsResponse(delRewards, total) + bz, err := json.Marshal(totalRewards) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil } -func queryDelegatorValidators(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorValidators(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegatorParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } // cache-wrap context as to not persist state changes during querying @@ -227,16 +240,17 @@ func queryDelegatorValidators(ctx sdk.Context, _ []string, req abci.RequestQuery bz, err := codec.MarshalJSONIndent(k.cdc, validators) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } -func queryDelegatorWithdrawAddress(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorWithdrawAddress(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegatorWithdrawAddrParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } // cache-wrap context as to not persist state changes during querying @@ -245,20 +259,22 @@ func queryDelegatorWithdrawAddress(ctx sdk.Context, _ []string, req abci.Request bz, err := codec.MarshalJSONIndent(k.cdc, withdrawAddr) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil } -func queryCommunityPool(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryCommunityPool(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper) ([]byte, error) { pool := k.GetFeePoolCommunityCoins(ctx) if pool == nil { pool = sdk.DecCoins{} } + bz, err := k.cdc.MarshalJSON(pool) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } diff --git a/x/distribution/keeper/querier_test.go b/x/distribution/keeper/querier_test.go index 2a2d1455f9db..e70ca2ea0f4b 100644 --- a/x/distribution/keeper/querier_test.go +++ b/x/distribution/keeper/querier_test.go @@ -189,10 +189,16 @@ func TestQueries(t *testing.T) { // test delegation rewards query sh := staking.NewHandler(sk) comm := staking.NewCommissionRates(sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDec(0)) - msg := staking.NewMsgCreateValidator(valOpAddr1, valConsPk1, - sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, comm, sdk.OneInt()) - require.True(t, sh(ctx, msg).IsOK()) + msg := staking.NewMsgCreateValidator( + valOpAddr1, valConsPk1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)), staking.Description{}, comm, sdk.OneInt(), + ) + + res, err := sh(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) + val := sk.Validator(ctx, valOpAddr1) rewards := getQueriedDelegationRewards(t, ctx, cdc, querier, sdk.AccAddress(valOpAddr1), valOpAddr1) require.True(t, rewards.IsZero()) diff --git a/x/distribution/keeper/test_common.go b/x/distribution/keeper/test_common.go index 73c709e317e1..1d53c9d1816a 100644 --- a/x/distribution/keeper/test_common.go +++ b/x/distribution/keeper/test_common.go @@ -119,11 +119,11 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, blacklistedAddrs[distrAcc.GetAddress().String()] = true cdc := MakeTestCodec() - pk := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace) + pk := params.NewKeeper(cdc, keyParams, tkeyParams) ctx := sdk.NewContext(ms, abci.Header{ChainID: "foochainid"}, isCheckTx, log.NewNopLogger()) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, types.ModuleName: nil, @@ -132,10 +132,10 @@ func CreateTestInputAdvanced(t *testing.T, isCheckTx bool, initPower int64, } supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms) - sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) + sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) - keeper := NewKeeper(cdc, keyDistr, pk.Subspace(DefaultParamspace), sk, supplyKeeper, types.DefaultCodespace, auth.FeeCollectorName, blacklistedAddrs) + keeper := NewKeeper(cdc, keyDistr, pk.Subspace(DefaultParamspace), sk, supplyKeeper, auth.FeeCollectorName, blacklistedAddrs) initCoins := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens)) totalSupply := sdk.NewCoins(sdk.NewCoin(sk.BondDenom(ctx), initTokens.MulRaw(int64(len(TestAddrs))))) diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index 9a9dea6b8d4b..d2857e6c5aff 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -1,7 +1,6 @@ package simulation import ( - "errors" "fmt" "math/rand" @@ -109,9 +108,9 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, k keeper.Keeper) simu simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -155,9 +154,9 @@ func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, k keeper.Keeper, simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -204,9 +203,9 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Kee simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -254,9 +253,9 @@ func SimulateMsgFundCommunityPool(ak types.AccountKeeper, k keeper.Keeper, sk st funder.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil diff --git a/x/distribution/types/errors.go b/x/distribution/types/errors.go index 2b6394114133..c06b731b6ee4 100644 --- a/x/distribution/types/errors.go +++ b/x/distribution/types/errors.go @@ -1,47 +1,21 @@ -// nolint package types import ( - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -type CodeType = sdk.CodeType - -const ( - DefaultCodespace sdk.CodespaceType = "distr" - CodeInvalidInput CodeType = 103 - CodeNoDistributionInfo CodeType = 104 - CodeNoValidatorCommission CodeType = 105 - CodeSetWithdrawAddrDisabled CodeType = 106 +// x/distribution module sentinel errors +var ( + ErrEmptyDelegatorAddr = sdkerrors.Register(ModuleName, 1, "delegator address is empty") + ErrEmptyWithdrawAddr = sdkerrors.Register(ModuleName, 2, "withdraw address is empty") + ErrEmptyValidatorAddr = sdkerrors.Register(ModuleName, 3, "validator address is empty") + ErrEmptyDelegationDistInfo = sdkerrors.Register(ModuleName, 4, "no delegation distribution info") + ErrNoValidatorDistInfo = sdkerrors.Register(ModuleName, 5, "no validator distribution info") + ErrNoValidatorCommission = sdkerrors.Register(ModuleName, 6, "no validator commission to withdraw") + ErrSetWithdrawAddrDisabled = sdkerrors.Register(ModuleName, 7, "set withdraw address disabled") + ErrBadDistribution = sdkerrors.Register(ModuleName, 8, "community pool does not have sufficient coins to distribute") + ErrInvalidProposalAmount = sdkerrors.Register(ModuleName, 9, "invalid community pool spend proposal amount") + ErrEmptyProposalRecipient = sdkerrors.Register(ModuleName, 10, "invalid community pool spend proposal recipient") + ErrNoValidatorExists = sdkerrors.Register(ModuleName, 11, "validator does not exist") + ErrNoDelegationExists = sdkerrors.Register(ModuleName, 12, "delegation does not exist") ) - -func ErrNilDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "delegator address is nil") -} -func ErrNilWithdrawAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "withdraw address is nil") -} -func ErrNilValidatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "validator address is nil") -} -func ErrNoDelegationDistInfo(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeNoDistributionInfo, "no delegation distribution info") -} -func ErrNoValidatorDistInfo(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeNoDistributionInfo, "no validator distribution info") -} -func ErrNoValidatorCommission(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeNoValidatorCommission, "no validator commission to withdraw") -} -func ErrSetWithdrawAddrDisabled(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeSetWithdrawAddrDisabled, "set withdraw address disabled") -} -func ErrBadDistribution(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "community pool does not have sufficient coins to distribute") -} -func ErrInvalidProposalAmount(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "invalid community pool spend proposal amount") -} -func ErrEmptyProposalRecipient(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "invalid community pool spend proposal recipient") -} diff --git a/x/distribution/types/expected_keepers.go b/x/distribution/types/expected_keepers.go index a51bc9d0403f..faa2f37235da 100644 --- a/x/distribution/types/expected_keepers.go +++ b/x/distribution/types/expected_keepers.go @@ -70,7 +70,7 @@ type SupplyKeeper interface { // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 SetModuleAccount(sdk.Context, supplyexported.ModuleAccountI) - SendCoinsFromModuleToModule(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) sdk.Error - SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error + SendCoinsFromModuleToModule(ctx sdk.Context, senderModule string, recipientModule string, amt sdk.Coins) error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error } diff --git a/x/distribution/types/msg.go b/x/distribution/types/msg.go index 408983cb0ff2..2068caef149e 100644 --- a/x/distribution/types/msg.go +++ b/x/distribution/types/msg.go @@ -3,6 +3,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // Verify interface at compile time @@ -36,13 +37,14 @@ func (msg MsgSetWithdrawAddress) GetSignBytes() []byte { } // quick validity check -func (msg MsgSetWithdrawAddress) ValidateBasic() sdk.Error { +func (msg MsgSetWithdrawAddress) ValidateBasic() error { if msg.DelegatorAddress.Empty() { - return ErrNilDelegatorAddr(DefaultCodespace) + return ErrEmptyDelegatorAddr } if msg.WithdrawAddress.Empty() { - return ErrNilWithdrawAddr(DefaultCodespace) + return ErrEmptyWithdrawAddr } + return nil } @@ -74,12 +76,12 @@ func (msg MsgWithdrawDelegatorReward) GetSignBytes() []byte { } // quick validity check -func (msg MsgWithdrawDelegatorReward) ValidateBasic() sdk.Error { +func (msg MsgWithdrawDelegatorReward) ValidateBasic() error { if msg.DelegatorAddress.Empty() { - return ErrNilDelegatorAddr(DefaultCodespace) + return ErrEmptyDelegatorAddr } if msg.ValidatorAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } return nil } @@ -110,9 +112,9 @@ func (msg MsgWithdrawValidatorCommission) GetSignBytes() []byte { } // quick validity check -func (msg MsgWithdrawValidatorCommission) ValidateBasic() sdk.Error { +func (msg MsgWithdrawValidatorCommission) ValidateBasic() error { if msg.ValidatorAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } return nil } @@ -155,12 +157,12 @@ func (msg MsgFundCommunityPool) GetSignBytes() []byte { } // ValidateBasic performs basic MsgFundCommunityPool message validation. -func (msg MsgFundCommunityPool) ValidateBasic() sdk.Error { +func (msg MsgFundCommunityPool) ValidateBasic() error { if !msg.Amount.IsValid() { - return sdk.ErrInvalidCoins(msg.Amount.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) } if msg.Depositor.Empty() { - return sdk.ErrInvalidAddress(msg.Depositor.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Depositor.String()) } return nil diff --git a/x/distribution/types/proposal.go b/x/distribution/types/proposal.go index 0562d81df18d..931e111ba719 100644 --- a/x/distribution/types/proposal.go +++ b/x/distribution/types/proposal.go @@ -47,17 +47,18 @@ func (csp CommunityPoolSpendProposal) ProposalRoute() string { return RouterKey func (csp CommunityPoolSpendProposal) ProposalType() string { return ProposalTypeCommunityPoolSpend } // ValidateBasic runs basic stateless validity checks -func (csp CommunityPoolSpendProposal) ValidateBasic() sdk.Error { - err := govtypes.ValidateAbstract(DefaultCodespace, csp) +func (csp CommunityPoolSpendProposal) ValidateBasic() error { + err := govtypes.ValidateAbstract(csp) if err != nil { return err } if !csp.Amount.IsValid() { - return ErrInvalidProposalAmount(DefaultCodespace) + return ErrInvalidProposalAmount } if csp.Recipient.Empty() { - return ErrEmptyProposalRecipient(DefaultCodespace) + return ErrEmptyProposalRecipient } + return nil } diff --git a/x/evidence/alias.go b/x/evidence/alias.go index 411f39751578..29b8447a365e 100644 --- a/x/evidence/alias.go +++ b/x/evidence/alias.go @@ -8,23 +8,19 @@ import ( // nolint const ( - ModuleName = types.ModuleName - StoreKey = types.StoreKey - RouterKey = types.RouterKey - QuerierRoute = types.QuerierRoute - DefaultParamspace = types.DefaultParamspace - QueryEvidence = types.QueryEvidence - QueryAllEvidence = types.QueryAllEvidence - QueryParameters = types.QueryParameters - CodeNoEvidenceHandlerExists = types.CodeNoEvidenceHandlerExists - CodeInvalidEvidence = types.CodeInvalidEvidence - CodeNoEvidenceExists = types.CodeNoEvidenceExists - TypeMsgSubmitEvidence = types.TypeMsgSubmitEvidence - DefaultCodespace = types.DefaultCodespace - EventTypeSubmitEvidence = types.EventTypeSubmitEvidence - AttributeValueCategory = types.AttributeValueCategory - AttributeKeyEvidenceHash = types.AttributeKeyEvidenceHash - DefaultMaxEvidenceAge = types.DefaultMaxEvidenceAge + ModuleName = types.ModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute + DefaultParamspace = types.DefaultParamspace + QueryEvidence = types.QueryEvidence + QueryAllEvidence = types.QueryAllEvidence + QueryParameters = types.QueryParameters + TypeMsgSubmitEvidence = types.TypeMsgSubmitEvidence + EventTypeSubmitEvidence = types.EventTypeSubmitEvidence + AttributeValueCategory = types.AttributeValueCategory + AttributeKeyEvidenceHash = types.AttributeKeyEvidenceHash + DefaultMaxEvidenceAge = types.DefaultMaxEvidenceAge ) var ( diff --git a/x/evidence/genesis_test.go b/x/evidence/genesis_test.go index a77b847db177..10a8a2c75730 100644 --- a/x/evidence/genesis_test.go +++ b/x/evidence/genesis_test.go @@ -32,8 +32,7 @@ func (suite *GenesisTestSuite) SetupTest() { // recreate keeper in order to use custom testing types evidenceKeeper := evidence.NewKeeper( - cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), - evidence.DefaultCodespace, app.StakingKeeper, app.SlashingKeeper, + cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), app.StakingKeeper, app.SlashingKeeper, ) router := evidence.NewRouter() router = router.AddRoute(types.TestEvidenceRouteEquivocation, types.TestEquivocationHandler(*evidenceKeeper)) diff --git a/x/evidence/handler.go b/x/evidence/handler.go index 714da444c444..d5af1206bc01 100644 --- a/x/evidence/handler.go +++ b/x/evidence/handler.go @@ -1,13 +1,12 @@ package evidence import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) func NewHandler(k Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -15,14 +14,14 @@ func NewHandler(k Keeper) sdk.Handler { return handleMsgSubmitEvidence(ctx, k, msg) default: - return sdk.ErrUnknownRequest(fmt.Sprintf("unrecognized %s message type: %T", ModuleName, msg)).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } } } -func handleMsgSubmitEvidence(ctx sdk.Context, k Keeper, msg MsgSubmitEvidence) sdk.Result { +func handleMsgSubmitEvidence(ctx sdk.Context, k Keeper, msg MsgSubmitEvidence) (*sdk.Result, error) { if err := k.SubmitEvidence(ctx, msg.Evidence); err != nil { - return sdk.ConvertError(err).Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -33,8 +32,8 @@ func handleMsgSubmitEvidence(ctx sdk.Context, k Keeper, msg MsgSubmitEvidence) s ), ) - return sdk.Result{ + return &sdk.Result{ Data: msg.Evidence.Hash(), Events: ctx.EventManager().Events(), - } + }, nil } diff --git a/x/evidence/handler_test.go b/x/evidence/handler_test.go index 1957778950ad..e5798bd01482 100644 --- a/x/evidence/handler_test.go +++ b/x/evidence/handler_test.go @@ -31,8 +31,7 @@ func (suite *HandlerTestSuite) SetupTest() { // recreate keeper in order to use custom testing types evidenceKeeper := evidence.NewKeeper( - cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), - evidence.DefaultCodespace, app.StakingKeeper, app.SlashingKeeper, + cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), app.StakingKeeper, app.SlashingKeeper, ) router := evidence.NewRouter() router = router.AddRoute(types.TestEvidenceRouteEquivocation, types.TestEquivocationHandler(*evidenceKeeper)) @@ -66,8 +65,9 @@ func (suite *HandlerTestSuite) TestMsgSubmitEvidence_Valid() { ctx := suite.ctx.WithIsCheckTx(false) msg := evidence.NewMsgSubmitEvidence(e, s) - res := suite.handler(ctx, msg) - suite.True(res.IsOK()) + res, err := suite.handler(ctx, msg) + suite.NoError(err) + suite.NotNil(res) suite.Equal(e.Hash().Bytes(), res.Data) } @@ -94,8 +94,9 @@ func (suite *HandlerTestSuite) TestMsgSubmitEvidence_Invalid() { ctx := suite.ctx.WithIsCheckTx(false) msg := evidence.NewMsgSubmitEvidence(e, s) - res := suite.handler(ctx, msg) - suite.False(res.IsOK()) + res, err := suite.handler(ctx, msg) + suite.Error(err) + suite.Nil(res) } func TestHandlerTestSuite(t *testing.T) { diff --git a/x/evidence/internal/keeper/infraction_test.go b/x/evidence/internal/keeper/infraction_test.go index ca68948f5eb1..cbef53de1921 100644 --- a/x/evidence/internal/keeper/infraction_test.go +++ b/x/evidence/internal/keeper/infraction_test.go @@ -28,8 +28,9 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign() { operatorAddr, val := valAddresses[0], pubkeys[0] // create validator - res := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, amt)) - suite.True(res.IsOK(), res.Log) + res, err := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, amt)) + suite.NoError(err) + suite.NotNil(res) // execute end-blocker and verify validator attributes staking.EndBlocker(ctx, suite.app.StakingKeeper) @@ -78,8 +79,9 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign() { validator, _ := suite.app.StakingKeeper.GetValidator(ctx, operatorAddr) totalBond := validator.TokensFromShares(del.GetShares()).TruncateInt() msgUnbond := staking.NewMsgUndelegate(sdk.AccAddress(operatorAddr), operatorAddr, sdk.NewCoin(stakingParams.BondDenom, totalBond)) - res = staking.NewHandler(suite.app.StakingKeeper)(ctx, msgUnbond) - suite.True(res.IsOK()) + res, err = staking.NewHandler(suite.app.StakingKeeper)(ctx, msgUnbond) + suite.NoError(err) + suite.NotNil(res) } func (suite *KeeperTestSuite) TestHandleDoubleSign_TooOld() { @@ -92,8 +94,9 @@ func (suite *KeeperTestSuite) TestHandleDoubleSign_TooOld() { operatorAddr, val := valAddresses[0], pubkeys[0] // create validator - res := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, amt)) - suite.True(res.IsOK(), res.Log) + res, err := staking.NewHandler(suite.app.StakingKeeper)(ctx, newTestMsgCreateValidator(operatorAddr, val, amt)) + suite.NoError(err) + suite.NotNil(res) // execute end-blocker and verify validator attributes staking.EndBlocker(ctx, suite.app.StakingKeeper) diff --git a/x/evidence/internal/keeper/keeper.go b/x/evidence/internal/keeper/keeper.go index 26b45db7d69d..fd6c8027d8fd 100644 --- a/x/evidence/internal/keeper/keeper.go +++ b/x/evidence/internal/keeper/keeper.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/evidence/internal/types" "github.com/cosmos/cosmos-sdk/x/params" @@ -24,11 +25,10 @@ type Keeper struct { router types.Router stakingKeeper types.StakingKeeper slashingKeeper types.SlashingKeeper - codespace sdk.CodespaceType } func NewKeeper( - cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace params.Subspace, codespace sdk.CodespaceType, + cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace params.Subspace, stakingKeeper types.StakingKeeper, slashingKeeper types.SlashingKeeper, ) *Keeper { @@ -43,7 +43,6 @@ func NewKeeper( paramSpace: paramSpace, stakingKeeper: stakingKeeper, slashingKeeper: slashingKeeper, - codespace: codespace, } } @@ -74,7 +73,7 @@ func (k *Keeper) SetRouter(rtr types.Router) { // no handler exists, an error is returned. func (k Keeper) GetEvidenceHandler(evidenceRoute string) (types.Handler, error) { if !k.router.HasRoute(evidenceRoute) { - return nil, types.ErrNoEvidenceHandlerExists(k.codespace, evidenceRoute) + return nil, sdkerrors.Wrap(types.ErrNoEvidenceHandlerExists, evidenceRoute) } return k.router.GetRoute(evidenceRoute), nil @@ -86,15 +85,15 @@ func (k Keeper) GetEvidenceHandler(evidenceRoute string) (types.Handler, error) // persisted. func (k Keeper) SubmitEvidence(ctx sdk.Context, evidence exported.Evidence) error { if _, ok := k.GetEvidence(ctx, evidence.Hash()); ok { - return types.ErrEvidenceExists(k.codespace, evidence.Hash().String()) + return sdkerrors.Wrap(types.ErrEvidenceExists, evidence.Hash().String()) } if !k.router.HasRoute(evidence.Route()) { - return types.ErrNoEvidenceHandlerExists(k.codespace, evidence.Route()) + return sdkerrors.Wrap(types.ErrNoEvidenceHandlerExists, evidence.Route()) } handler := k.router.GetRoute(evidence.Route()) if err := handler(ctx, evidence); err != nil { - return types.ErrInvalidEvidence(k.codespace, err.Error()) + return sdkerrors.Wrap(types.ErrInvalidEvidence, err.Error()) } ctx.EventManager().EmitEvent( diff --git a/x/evidence/internal/keeper/keeper_test.go b/x/evidence/internal/keeper/keeper_test.go index bde9f08f02ce..45347ab96be0 100644 --- a/x/evidence/internal/keeper/keeper_test.go +++ b/x/evidence/internal/keeper/keeper_test.go @@ -66,8 +66,7 @@ func (suite *KeeperTestSuite) SetupTest() { // recreate keeper in order to use custom testing types evidenceKeeper := evidence.NewKeeper( - cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), - evidence.DefaultCodespace, app.StakingKeeper, app.SlashingKeeper, + cdc, app.GetKey(evidence.StoreKey), app.GetSubspace(evidence.ModuleName), app.StakingKeeper, app.SlashingKeeper, ) router := evidence.NewRouter() router = router.AddRoute(types.TestEvidenceRouteEquivocation, types.TestEquivocationHandler(*evidenceKeeper)) diff --git a/x/evidence/internal/keeper/querier.go b/x/evidence/internal/keeper/querier.go index dfbda68f66d6..cbb616677e8f 100644 --- a/x/evidence/internal/keeper/querier.go +++ b/x/evidence/internal/keeper/querier.go @@ -14,7 +14,7 @@ import ( ) func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { var ( res []byte err error @@ -31,10 +31,10 @@ func NewQuerier(k Keeper) sdk.Querier { res, err = queryAllEvidence(ctx, req, k) default: - err = sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint", types.ModuleName) + err = sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } - return res, sdk.ConvertError(err) + return res, err } } @@ -64,7 +64,7 @@ func queryEvidence(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, er evidence, ok := k.GetEvidence(ctx, hash) if !ok { - return nil, types.ErrNoEvidenceExists(k.codespace, params.EvidenceHash) + return nil, sdkerrors.Wrap(types.ErrNoEvidenceExists, params.EvidenceHash) } res, err := codec.MarshalJSONIndent(k.cdc, evidence) diff --git a/x/evidence/internal/types/errors.go b/x/evidence/internal/types/errors.go index 2054cee9fb66..83ffe06002ae 100644 --- a/x/evidence/internal/types/errors.go +++ b/x/evidence/internal/types/errors.go @@ -2,57 +2,13 @@ package types import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// Error codes specific to the evidence module -const ( - DefaultCodespace sdk.CodespaceType = ModuleName - - CodeNoEvidenceHandlerExists sdk.CodeType = 1 - CodeInvalidEvidence sdk.CodeType = 2 - CodeNoEvidenceExists sdk.CodeType = 3 - CodeEvidenceExists sdk.CodeType = 4 +// x/evidence module sentinel errors +var ( + ErrNoEvidenceHandlerExists = sdkerrors.Register(ModuleName, 1, "unregistered handler for evidence type") + ErrInvalidEvidence = sdkerrors.Register(ModuleName, 2, "invalid evidence") + ErrNoEvidenceExists = sdkerrors.Register(ModuleName, 3, "evidence does not exist") + ErrEvidenceExists = sdkerrors.Register(ModuleName, 4, "evidence already exists") ) - -// ErrNoEvidenceHandlerExists returns a typed ABCI error for an invalid evidence -// handler route. -func ErrNoEvidenceHandlerExists(codespace sdk.CodespaceType, route string) error { - return sdkerrors.New( - string(codespace), - uint32(CodeNoEvidenceHandlerExists), - fmt.Sprintf("route '%s' does not have a registered evidence handler", route), - ) -} - -// ErrInvalidEvidence returns a typed ABCI error for invalid evidence. -func ErrInvalidEvidence(codespace sdk.CodespaceType, msg string) error { - return sdkerrors.New( - string(codespace), - uint32(CodeInvalidEvidence), - fmt.Sprintf("invalid evidence: %s", msg), - ) -} - -// ErrNoEvidenceExists returns a typed ABCI error for Evidence that does not exist -// for a given hash. -func ErrNoEvidenceExists(codespace sdk.CodespaceType, hash string) error { - return sdkerrors.New( - string(codespace), - uint32(CodeNoEvidenceExists), - fmt.Sprintf("evidence with hash %s does not exist", hash), - ) -} - -// ErrEvidenceExists returns a typed ABCI error for Evidence that already exists -// by hash in state. -func ErrEvidenceExists(codespace sdk.CodespaceType, hash string) error { - return sdkerrors.New( - string(codespace), - uint32(CodeEvidenceExists), - fmt.Sprintf("evidence with hash %s already exists", hash), - ) -} diff --git a/x/evidence/internal/types/msgs.go b/x/evidence/internal/types/msgs.go index b09f120da927..3fbb50844f57 100644 --- a/x/evidence/internal/types/msgs.go +++ b/x/evidence/internal/types/msgs.go @@ -33,15 +33,15 @@ func (m MsgSubmitEvidence) Route() string { return RouterKey } func (m MsgSubmitEvidence) Type() string { return TypeMsgSubmitEvidence } // ValidateBasic performs basic (non-state-dependant) validation on a MsgSubmitEvidence. -func (m MsgSubmitEvidence) ValidateBasic() sdk.Error { +func (m MsgSubmitEvidence) ValidateBasic() error { if m.Evidence == nil { - return sdk.ConvertError(ErrInvalidEvidence(DefaultCodespace, "missing evidence")) + return sdkerrors.Wrap(ErrInvalidEvidence, "missing evidence") } if err := m.Evidence.ValidateBasic(); err != nil { - return sdk.ConvertError(err) + return err } if m.Submitter.Empty() { - return sdk.ConvertError(sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, m.Submitter.String())) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, m.Submitter.String()) } return nil diff --git a/x/genutil/client/rest/query.go b/x/genutil/client/rest/query.go index 4f0f318aa201..0159223e8e7c 100644 --- a/x/genutil/client/rest/query.go +++ b/x/genutil/client/rest/query.go @@ -1,6 +1,7 @@ package rest import ( + "fmt" "net/http" "github.com/cosmos/cosmos-sdk/client/context" @@ -14,15 +15,19 @@ import ( func QueryGenesisTxs(cliCtx context.CLIContext, w http.ResponseWriter) { resultGenesis, err := cliCtx.Client.Genesis() if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, - sdk.AppendMsgToErr("could not retrieve genesis from client", err.Error())) + rest.WriteErrorResponse( + w, http.StatusInternalServerError, + fmt.Sprintf("failed to retrieve genesis from client: %s", err), + ) return } appState, err := types.GenesisStateFromGenDoc(cliCtx.Codec, *resultGenesis.Genesis) if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, - sdk.AppendMsgToErr("could not decode genesis doc", err.Error())) + rest.WriteErrorResponse( + w, http.StatusInternalServerError, + fmt.Sprintf("failed to decode genesis doc: %s", err), + ) return } @@ -31,8 +36,10 @@ func QueryGenesisTxs(cliCtx context.CLIContext, w http.ResponseWriter) { for i, tx := range genState.GenTxs { err := cliCtx.Codec.UnmarshalJSON(tx, &genTxs[i]) if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, - sdk.AppendMsgToErr("could not decode genesis transaction", err.Error())) + rest.WriteErrorResponse( + w, http.StatusInternalServerError, + fmt.Sprintf("failed to decode genesis transaction: %s", err), + ) return } } diff --git a/x/gov/abci.go b/x/gov/abci.go index 31b1f40c9d2a..21db8f5cd2c2 100644 --- a/x/gov/abci.go +++ b/x/gov/abci.go @@ -65,7 +65,7 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) { } else { proposal.Status = StatusFailed tagValue = types.AttributeValueProposalFailed - logMsg = fmt.Sprintf("passed, but failed on execution: %s", err.ABCILog()) + logMsg = fmt.Sprintf("passed, but failed on execution: %s", err) } } else { proposal.Status = StatusRejected diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index 42616b36c00b..6ee3a3075920 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -32,8 +32,9 @@ func TestTickExpiredDepositPeriod(t *testing.T) { input.addrs[0], ) - res := govHandler(ctx, newProposalMsg) - require.True(t, res.IsOK()) + res, err := govHandler(ctx, newProposalMsg) + require.NoError(t, err) + require.NotNil(t, res) inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) @@ -81,8 +82,9 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { input.addrs[0], ) - res := govHandler(ctx, newProposalMsg) - require.True(t, res.IsOK()) + res, err := govHandler(ctx, newProposalMsg) + require.NoError(t, err) + require.NotNil(t, res) inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, inactiveQueue.Valid()) @@ -102,8 +104,9 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { input.addrs[0], ) - res = govHandler(ctx, newProposalMsg2) - require.True(t, res.IsOK()) + res, err = govHandler(ctx, newProposalMsg2) + require.NoError(t, err) + require.NotNil(t, res) newHeader = ctx.BlockHeader() newHeader.Time = ctx.BlockHeader().Time.Add(input.keeper.GetDepositParams(ctx).MaxDepositPeriod).Add(time.Duration(-1) * time.Second) @@ -152,8 +155,10 @@ func TestTickPassedDepositPeriod(t *testing.T) { input.addrs[0], ) - res := govHandler(ctx, newProposalMsg) - require.True(t, res.IsOK()) + res, err := govHandler(ctx, newProposalMsg) + require.NoError(t, err) + require.NotNil(t, res) + proposalID := GetProposalIDFromBytes(res.Data) inactiveQueue = input.keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) @@ -169,8 +174,10 @@ func TestTickPassedDepositPeriod(t *testing.T) { inactiveQueue.Close() newDepositMsg := NewMsgDeposit(input.addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}) - res = govHandler(ctx, newDepositMsg) - require.True(t, res.IsOK()) + + res, err = govHandler(ctx, newDepositMsg) + require.NoError(t, err) + require.NotNil(t, res) activeQueue = input.keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time) require.False(t, activeQueue.Valid()) @@ -197,8 +204,10 @@ func TestTickPassedVotingPeriod(t *testing.T) { proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(5))} newProposalMsg := NewMsgSubmitProposal(keep.TestProposal, proposalCoins, input.addrs[0]) - res := govHandler(ctx, newProposalMsg) - require.True(t, res.IsOK()) + res, err := govHandler(ctx, newProposalMsg) + require.NoError(t, err) + require.NotNil(t, res) + proposalID := GetProposalIDFromBytes(res.Data) newHeader := ctx.BlockHeader() @@ -206,8 +215,10 @@ func TestTickPassedVotingPeriod(t *testing.T) { ctx = ctx.WithBlockHeader(newHeader) newDepositMsg := NewMsgDeposit(input.addrs[1], proposalID, proposalCoins) - res = govHandler(ctx, newDepositMsg) - require.True(t, res.IsOK()) + + res, err = govHandler(ctx, newDepositMsg) + require.NoError(t, err) + require.NotNil(t, res) newHeader = ctx.BlockHeader() newHeader.Time = ctx.BlockHeader().Time.Add(input.keeper.GetDepositParams(ctx).MaxDepositPeriod).Add(input.keeper.GetVotingParams(ctx).VotingPeriod) @@ -259,8 +270,10 @@ func TestProposalPassedEndblocker(t *testing.T) { proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10))} newDepositMsg := NewMsgDeposit(input.addrs[0], proposal.ProposalID, proposalCoins) - res := handler(ctx, newDepositMsg) - require.True(t, res.IsOK()) + + res, err := handler(ctx, newDepositMsg) + require.NoError(t, err) + require.NotNil(t, res) macc = input.keeper.GetGovernanceAccount(ctx) require.NotNil(t, macc) @@ -308,8 +321,10 @@ func TestEndBlockerProposalHandlerFailed(t *testing.T) { proposalCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10))) newDepositMsg := NewMsgDeposit(input.addrs[0], proposal.ProposalID, proposalCoins) - res := handler(ctx, newDepositMsg) - require.True(t, res.IsOK()) + + res, err := handler(ctx, newDepositMsg) + require.NoError(t, err) + require.NotNil(t, res) err = input.keeper.AddVote(ctx, proposal.ProposalID, input.addrs[0], OptionYes) require.NoError(t, err) diff --git a/x/gov/alias.go b/x/gov/alias.go index 0ca57b7a39fc..df5f2cb9ce77 100644 --- a/x/gov/alias.go +++ b/x/gov/alias.go @@ -1,62 +1,47 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/gov/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/gov/types package gov +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" ) const ( - MaxDescriptionLength = types.MaxDescriptionLength - MaxTitleLength = types.MaxTitleLength - DefaultCodespace = types.DefaultCodespace - CodeUnknownProposal = types.CodeUnknownProposal - CodeInactiveProposal = types.CodeInactiveProposal - CodeAlreadyActiveProposal = types.CodeAlreadyActiveProposal - CodeAlreadyFinishedProposal = types.CodeAlreadyFinishedProposal - CodeAddressNotStaked = types.CodeAddressNotStaked - CodeInvalidContent = types.CodeInvalidContent - CodeInvalidProposalType = types.CodeInvalidProposalType - CodeInvalidVote = types.CodeInvalidVote - CodeInvalidGenesis = types.CodeInvalidGenesis - CodeInvalidProposalStatus = types.CodeInvalidProposalStatus - CodeProposalHandlerNotExists = types.CodeProposalHandlerNotExists - DefaultPeriod = types.DefaultPeriod - ModuleName = types.ModuleName - StoreKey = types.StoreKey - RouterKey = types.RouterKey - QuerierRoute = types.QuerierRoute - DefaultParamspace = types.DefaultParamspace - TypeMsgDeposit = types.TypeMsgDeposit - TypeMsgVote = types.TypeMsgVote - TypeMsgSubmitProposal = types.TypeMsgSubmitProposal - StatusNil = types.StatusNil - StatusDepositPeriod = types.StatusDepositPeriod - StatusVotingPeriod = types.StatusVotingPeriod - StatusPassed = types.StatusPassed - StatusRejected = types.StatusRejected - StatusFailed = types.StatusFailed - ProposalTypeText = types.ProposalTypeText - QueryParams = types.QueryParams - QueryProposals = types.QueryProposals - QueryProposal = types.QueryProposal - QueryDeposits = types.QueryDeposits - QueryDeposit = types.QueryDeposit - QueryVotes = types.QueryVotes - QueryVote = types.QueryVote - QueryTally = types.QueryTally - ParamDeposit = types.ParamDeposit - ParamVoting = types.ParamVoting - ParamTallying = types.ParamTallying - OptionEmpty = types.OptionEmpty - OptionYes = types.OptionYes - OptionAbstain = types.OptionAbstain - OptionNo = types.OptionNo - OptionNoWithVeto = types.OptionNoWithVeto + MaxDescriptionLength = types.MaxDescriptionLength + MaxTitleLength = types.MaxTitleLength + DefaultPeriod = types.DefaultPeriod + ModuleName = types.ModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute + DefaultParamspace = types.DefaultParamspace + TypeMsgDeposit = types.TypeMsgDeposit + TypeMsgVote = types.TypeMsgVote + TypeMsgSubmitProposal = types.TypeMsgSubmitProposal + StatusNil = types.StatusNil + StatusDepositPeriod = types.StatusDepositPeriod + StatusVotingPeriod = types.StatusVotingPeriod + StatusPassed = types.StatusPassed + StatusRejected = types.StatusRejected + StatusFailed = types.StatusFailed + ProposalTypeText = types.ProposalTypeText + QueryParams = types.QueryParams + QueryProposals = types.QueryProposals + QueryProposal = types.QueryProposal + QueryDeposits = types.QueryDeposits + QueryDeposit = types.QueryDeposit + QueryVotes = types.QueryVotes + QueryVote = types.QueryVote + QueryTally = types.QueryTally + ParamDeposit = types.ParamDeposit + ParamVoting = types.ParamVoting + ParamTallying = types.ParamTallying + OptionEmpty = types.OptionEmpty + OptionYes = types.OptionYes + OptionAbstain = types.OptionAbstain + OptionNo = types.OptionNo + OptionNoWithVeto = types.OptionNoWithVeto ) var ( diff --git a/x/gov/genesis_test.go b/x/gov/genesis_test.go index 1beb0baecaa6..8626e7821e5f 100644 --- a/x/gov/genesis_test.go +++ b/x/gov/genesis_test.go @@ -29,7 +29,7 @@ func TestImportExportQueues(t *testing.T) { require.NoError(t, err) proposalID2 := proposal2.ProposalID - err, votingStarted := input.keeper.AddDeposit(ctx, proposalID2, input.addrs[0], input.keeper.GetDepositParams(ctx).MinDeposit) + votingStarted, err := input.keeper.AddDeposit(ctx, proposalID2, input.addrs[0], input.keeper.GetDepositParams(ctx).MinDeposit) require.NoError(t, err) require.True(t, votingStarted) diff --git a/x/gov/handler.go b/x/gov/handler.go index 47efe4473cd4..4e4aee2c5334 100644 --- a/x/gov/handler.go +++ b/x/gov/handler.go @@ -4,12 +4,13 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/gov/types" ) // NewHandler creates an sdk.Handler for all the gov type messages func NewHandler(keeper Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -23,21 +24,20 @@ func NewHandler(keeper Keeper) sdk.Handler { return handleMsgVote(ctx, keeper, msg) default: - errMsg := fmt.Sprintf("unrecognized gov message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } } } -func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitProposal) sdk.Result { +func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitProposal) (*sdk.Result, error) { proposal, err := keeper.SubmitProposal(ctx, msg.Content) if err != nil { - return err.Result() + return nil, err } - err, votingStarted := keeper.AddDeposit(ctx, proposal.ProposalID, msg.Proposer, msg.InitialDeposit) + votingStarted, err := keeper.AddDeposit(ctx, proposal.ProposalID, msg.Proposer, msg.InitialDeposit) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -56,16 +56,16 @@ func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitPropos } ctx.EventManager().EmitEvent(submitEvent) - return sdk.Result{ + return &sdk.Result{ Data: GetProposalIDBytes(proposal.ProposalID), Events: ctx.EventManager().Events(), - } + }, nil } -func handleMsgDeposit(ctx sdk.Context, keeper Keeper, msg MsgDeposit) sdk.Result { - err, votingStarted := keeper.AddDeposit(ctx, msg.ProposalID, msg.Depositor, msg.Amount) +func handleMsgDeposit(ctx sdk.Context, keeper Keeper, msg MsgDeposit) (*sdk.Result, error) { + votingStarted, err := keeper.AddDeposit(ctx, msg.ProposalID, msg.Depositor, msg.Amount) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -85,13 +85,13 @@ func handleMsgDeposit(ctx sdk.Context, keeper Keeper, msg MsgDeposit) sdk.Result ) } - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgVote(ctx sdk.Context, keeper Keeper, msg MsgVote) sdk.Result { +func handleMsgVote(ctx sdk.Context, keeper Keeper, msg MsgVote) (*sdk.Result, error) { err := keeper.AddVote(ctx, msg.ProposalID, msg.Voter, msg.Option) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -102,6 +102,5 @@ func handleMsgVote(ctx sdk.Context, keeper Keeper, msg MsgVote) sdk.Result { ), ) - return sdk.Result{Events: ctx.EventManager().Events()} - + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } diff --git a/x/gov/handler_test.go b/x/gov/handler_test.go index 33dec83ff121..134b25ff0fc5 100644 --- a/x/gov/handler_test.go +++ b/x/gov/handler_test.go @@ -15,7 +15,8 @@ func TestInvalidMsg(t *testing.T) { k := Keeper{} h := NewHandler(k) - res := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) - require.False(t, res.IsOK()) - require.True(t, strings.Contains(res.Log, "unrecognized gov message type")) + res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) + require.Error(t, err) + require.Nil(t, res) + require.True(t, strings.Contains(err.Error(), "unrecognized gov message type")) } diff --git a/x/gov/keeper/deposit.go b/x/gov/keeper/deposit.go index 426d43d4f14e..c86df046e5e0 100644 --- a/x/gov/keeper/deposit.go +++ b/x/gov/keeper/deposit.go @@ -4,6 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -93,22 +94,22 @@ func (keeper Keeper) IterateDeposits(ctx sdk.Context, proposalID uint64, cb func // AddDeposit adds or updates a deposit of a specific depositor on a specific proposal // Activates voting period when appropriate -func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress, depositAmount sdk.Coins) (sdk.Error, bool) { +func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress, depositAmount sdk.Coins) (bool, error) { // Checks to see if proposal exists proposal, ok := keeper.GetProposal(ctx, proposalID) if !ok { - return types.ErrUnknownProposal(keeper.codespace, proposalID), false + return false, sdkerrors.Wrapf(types.ErrUnknownProposal, "%d", proposalID) } // Check if proposal is still depositable if (proposal.Status != types.StatusDepositPeriod) && (proposal.Status != types.StatusVotingPeriod) { - return types.ErrInactiveProposal(keeper.codespace, proposalID), false + return false, sdkerrors.Wrapf(types.ErrInactiveProposal, "%d", proposalID) } // update the governance module's account coins pool err := keeper.supplyKeeper.SendCoinsFromAccountToModule(ctx, depositorAddr, types.ModuleName, depositAmount) if err != nil { - return err, false + return false, err } // Update proposal @@ -139,7 +140,7 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAdd ) keeper.SetDeposit(ctx, deposit) - return nil, activatedVotingPeriod + return activatedVotingPeriod, nil } // RefundDeposits refunds and deletes all the deposits on a specific proposal diff --git a/x/gov/keeper/deposit_test.go b/x/gov/keeper/deposit_test.go index c6c229893119..b5d6cce405a2 100644 --- a/x/gov/keeper/deposit_test.go +++ b/x/gov/keeper/deposit_test.go @@ -33,7 +33,7 @@ func TestDeposits(t *testing.T) { require.True(t, proposal.VotingStartTime.Equal(time.Time{})) // Check first deposit - err, votingStarted := keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fourStake) + votingStarted, err := keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fourStake) require.NoError(t, err) require.False(t, votingStarted) deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[0]) @@ -46,7 +46,7 @@ func TestDeposits(t *testing.T) { require.Equal(t, addr0Initial.Sub(fourStake), ak.GetAccount(ctx, TestAddrs[0]).GetCoins()) // Check a second deposit from same address - err, votingStarted = keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fiveStake) + votingStarted, err = keeper.AddDeposit(ctx, proposalID, TestAddrs[0], fiveStake) require.NoError(t, err) require.False(t, votingStarted) deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[0]) @@ -59,7 +59,7 @@ func TestDeposits(t *testing.T) { require.Equal(t, addr0Initial.Sub(fourStake).Sub(fiveStake), ak.GetAccount(ctx, TestAddrs[0]).GetCoins()) // Check third deposit from a new address - err, votingStarted = keeper.AddDeposit(ctx, proposalID, TestAddrs[1], fourStake) + votingStarted, err = keeper.AddDeposit(ctx, proposalID, TestAddrs[1], fourStake) require.NoError(t, err) require.True(t, votingStarted) deposit, found = keeper.GetDeposit(ctx, proposalID, TestAddrs[1]) diff --git a/x/gov/keeper/keeper.go b/x/gov/keeper/keeper.go index b322d3e6b4cd..7a51e6e2bf29 100644 --- a/x/gov/keeper/keeper.go +++ b/x/gov/keeper/keeper.go @@ -29,9 +29,6 @@ type Keeper struct { // The codec codec for binary encoding/decoding. cdc *codec.Codec - // Reserved codespace - codespace sdk.CodespaceType - // Proposal router router types.Router } @@ -45,7 +42,7 @@ type Keeper struct { // CONTRACT: the parameter Subspace must have the param key table already initialized func NewKeeper( cdc *codec.Codec, key sdk.StoreKey, paramSpace types.ParamSubspace, - supplyKeeper types.SupplyKeeper, sk types.StakingKeeper, codespace sdk.CodespaceType, rtr types.Router, + supplyKeeper types.SupplyKeeper, sk types.StakingKeeper, rtr types.Router, ) Keeper { // ensure governance module account is set @@ -64,7 +61,6 @@ func NewKeeper( supplyKeeper: supplyKeeper, sk: sk, cdc: cdc, - codespace: codespace, router: rtr, } } diff --git a/x/gov/keeper/proposal.go b/x/gov/keeper/proposal.go index 2580565d38d4..c5d569314fb2 100644 --- a/x/gov/keeper/proposal.go +++ b/x/gov/keeper/proposal.go @@ -5,13 +5,14 @@ import ( "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/gov/types" ) // SubmitProposal create new proposal given a content -func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content) (types.Proposal, sdk.Error) { +func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content) (types.Proposal, error) { if !keeper.router.HasRoute(content.ProposalRoute()) { - return types.Proposal{}, types.ErrNoProposalHandlerExists(keeper.codespace, content) + return types.Proposal{}, sdkerrors.Wrap(types.ErrNoProposalHandlerExists, content.ProposalRoute()) } // Execute the proposal content in a cache-wrapped context to validate the @@ -20,7 +21,7 @@ func (keeper Keeper) SubmitProposal(ctx sdk.Context, content types.Content) (typ cacheCtx, _ := ctx.CacheContext() handler := keeper.router.GetRoute(content.ProposalRoute()) if err := handler(cacheCtx, content); err != nil { - return types.Proposal{}, types.ErrInvalidProposalContent(keeper.codespace, err.Result().Log) + return types.Proposal{}, sdkerrors.Wrap(types.ErrInvalidProposalContent, err.Error()) } proposalID, err := keeper.GetProposalID(ctx) @@ -149,12 +150,13 @@ func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, params types.QueryPro } // GetProposalID gets the highest proposal ID -func (keeper Keeper) GetProposalID(ctx sdk.Context) (proposalID uint64, err sdk.Error) { +func (keeper Keeper) GetProposalID(ctx sdk.Context) (proposalID uint64, err error) { store := ctx.KVStore(keeper.storeKey) bz := store.Get(types.ProposalIDKey) if bz == nil { - return 0, types.ErrInvalidGenesis(keeper.codespace, "initial proposal ID hasn't been set") + return 0, sdkerrors.Wrap(types.ErrInvalidGenesis, "initial proposal ID hasn't been set") } + proposalID = types.GetProposalIDFromBytes(bz) return proposalID, nil } diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index c359f1e5e1c8..67208bef6101 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -1,6 +1,7 @@ package keeper import ( + "errors" "strings" "testing" "time" @@ -51,12 +52,12 @@ func TestActivateVotingPeriod(t *testing.T) { type validProposal struct{} -func (validProposal) GetTitle() string { return "title" } -func (validProposal) GetDescription() string { return "description" } -func (validProposal) ProposalRoute() string { return types.RouterKey } -func (validProposal) ProposalType() string { return types.ProposalTypeText } -func (validProposal) String() string { return "" } -func (validProposal) ValidateBasic() sdk.Error { return nil } +func (validProposal) GetTitle() string { return "title" } +func (validProposal) GetDescription() string { return "description" } +func (validProposal) ProposalRoute() string { return types.RouterKey } +func (validProposal) ProposalType() string { return types.ProposalTypeText } +func (validProposal) String() string { return "" } +func (validProposal) ValidateBasic() error { return nil } type invalidProposalTitle1 struct{ validProposal } @@ -80,8 +81,8 @@ func (invalidProposalRoute) ProposalRoute() string { return "nonexistingroute" } type invalidProposalValidation struct{ validProposal } -func (invalidProposalValidation) ValidateBasic() sdk.Error { - return sdk.NewError(sdk.CodespaceUndefined, sdk.CodeInternal, "") +func (invalidProposalValidation) ValidateBasic() error { + return errors.New("invalid proposal") } func registerTestCodec(cdc *codec.Codec) { @@ -101,7 +102,7 @@ func TestSubmitProposal(t *testing.T) { testCases := []struct { content types.Content - expectedErr sdk.Error + expectedErr error }{ {validProposal{}, nil}, // Keeper does not check the validity of title and description, no error @@ -110,14 +111,14 @@ func TestSubmitProposal(t *testing.T) { {invalidProposalDesc1{}, nil}, {invalidProposalDesc2{}, nil}, // error only when invalid route - {invalidProposalRoute{}, types.ErrNoProposalHandlerExists(types.DefaultCodespace, invalidProposalRoute{})}, + {invalidProposalRoute{}, types.ErrNoProposalHandlerExists}, // Keeper does not call ValidateBasic, msg.ValidateBasic does {invalidProposalValidation{}, nil}, } - for _, tc := range testCases { + for i, tc := range testCases { _, err := keeper.SubmitProposal(ctx, tc.content) - require.Equal(t, tc.expectedErr, err, "unexpected type of error: %s", err) + require.True(t, errors.Is(tc.expectedErr, err), "tc #%d; got: %v, expected: %v", i, err, tc.expectedErr) } } diff --git a/x/gov/keeper/querier.go b/x/gov/keeper/querier.go index b5efc7619b05..9545e5e29b83 100644 --- a/x/gov/keeper/querier.go +++ b/x/gov/keeper/querier.go @@ -1,19 +1,18 @@ package keeper import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/gov/types" ) // NewQuerier creates a new gov Querier instance func NewQuerier(keeper Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryParams: return queryParams(ctx, path[1:], req, keeper) @@ -40,94 +39,100 @@ func NewQuerier(keeper Keeper) sdk.Querier { return queryTally(ctx, path[1:], req, keeper) default: - return nil, sdk.ErrUnknownRequest("unknown gov query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) } } } -func queryParams(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryParams(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { switch path[0] { case types.ParamDeposit: bz, err := codec.MarshalJSONIndent(keeper.cdc, keeper.GetDepositParams(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + case types.ParamVoting: bz, err := codec.MarshalJSONIndent(keeper.cdc, keeper.GetVotingParams(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + case types.ParamTallying: bz, err := codec.MarshalJSONIndent(keeper.cdc, keeper.GetTallyParams(ctx)) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil + default: - return nil, sdk.ErrUnknownRequest(fmt.Sprintf("%s is not a valid query request path", req.Path)) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "%s is not a valid query request path", req.Path) } } // nolint: unparam -func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryProposalParams err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } proposal, ok := keeper.GetProposal(ctx, params.ProposalID) if !ok { - return nil, types.ErrUnknownProposal(types.DefaultCodespace, params.ProposalID) + return nil, sdkerrors.Wrapf(types.ErrUnknownProposal, "%d", params.ProposalID) } bz, err := codec.MarshalJSONIndent(keeper.cdc, proposal) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } // nolint: unparam -func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryDepositParams err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } deposit, _ := keeper.GetDeposit(ctx, params.ProposalID, params.Depositor) bz, err := codec.MarshalJSONIndent(keeper.cdc, deposit) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } // nolint: unparam -func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryVoteParams err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } vote, _ := keeper.GetVote(ctx, params.ProposalID, params.Voter) bz, err := codec.MarshalJSONIndent(keeper.cdc, vote) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } // nolint: unparam -func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryProposalParams err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } deposits := keeper.GetDeposits(ctx, params.ProposalID) @@ -137,24 +142,25 @@ func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper bz, err := codec.MarshalJSONIndent(keeper.cdc, deposits) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } // nolint: unparam -func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryProposalParams err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } proposalID := params.ProposalID proposal, ok := keeper.GetProposal(ctx, proposalID) if !ok { - return nil, types.ErrUnknownProposal(types.DefaultCodespace, proposalID) + return nil, sdkerrors.Wrapf(types.ErrUnknownProposal, "%d", proposalID) } var tallyResult types.TallyResult @@ -162,8 +168,10 @@ func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke switch { case proposal.Status == types.StatusDepositPeriod: tallyResult = types.EmptyTallyResult() + case proposal.Status == types.StatusPassed || proposal.Status == types.StatusRejected: tallyResult = proposal.FinalTallyResult + default: // proposal is in voting period _, _, tallyResult = keeper.Tally(ctx, proposal) @@ -171,18 +179,18 @@ func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke bz, err := codec.MarshalJSONIndent(keeper.cdc, tallyResult) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } // nolint: unparam -func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryProposalVotesParams err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) - if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } votes := keeper.GetVotes(ctx, params.ProposalID) @@ -199,17 +207,17 @@ func queryVotes(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Ke bz, err := codec.MarshalJSONIndent(keeper.cdc, votes) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return bz, nil } -func queryProposals(ctx sdk.Context, _ []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryProposals(ctx sdk.Context, _ []string, req abci.RequestQuery, keeper Keeper) ([]byte, error) { var params types.QueryProposalsParams - err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("failed to parse params", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } proposals := keeper.GetProposalsFiltered(ctx, params) @@ -219,7 +227,7 @@ func queryProposals(ctx sdk.Context, _ []string, req abci.RequestQuery, keeper K bz, err := codec.MarshalJSONIndent(keeper.cdc, proposals) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return bz, nil diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index a5f781da1807..b8cce877608c 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -156,7 +156,7 @@ func TestQueries(t *testing.T) { proposal1, err := keeper.SubmitProposal(ctx, tp) require.NoError(t, err) deposit1 := types.NewDeposit(proposal1.ProposalID, TestAddrs[0], oneCoins) - err, _ = keeper.AddDeposit(ctx, deposit1.ProposalID, deposit1.Depositor, deposit1.Amount) + _, err = keeper.AddDeposit(ctx, deposit1.ProposalID, deposit1.Depositor, deposit1.Amount) require.NoError(t, err) proposal1.TotalDeposit = proposal1.TotalDeposit.Add(deposit1.Amount) @@ -164,7 +164,7 @@ func TestQueries(t *testing.T) { proposal2, err := keeper.SubmitProposal(ctx, tp) require.NoError(t, err) deposit2 := types.NewDeposit(proposal2.ProposalID, TestAddrs[0], consCoins) - err, _ = keeper.AddDeposit(ctx, deposit2.ProposalID, deposit2.Depositor, deposit2.Amount) + _, err = keeper.AddDeposit(ctx, deposit2.ProposalID, deposit2.Depositor, deposit2.Amount) require.NoError(t, err) proposal2.TotalDeposit = proposal2.TotalDeposit.Add(deposit2.Amount) @@ -173,14 +173,14 @@ func TestQueries(t *testing.T) { proposal3, err := keeper.SubmitProposal(ctx, tp) require.NoError(t, err) deposit3 := types.NewDeposit(proposal3.ProposalID, TestAddrs[1], oneCoins) - err, _ = keeper.AddDeposit(ctx, deposit3.ProposalID, deposit3.Depositor, deposit3.Amount) + _, err = keeper.AddDeposit(ctx, deposit3.ProposalID, deposit3.Depositor, deposit3.Amount) require.NoError(t, err) proposal3.TotalDeposit = proposal3.TotalDeposit.Add(deposit3.Amount) // TestAddrs[1] deposits on proposals #2 & #3 deposit4 := types.NewDeposit(proposal2.ProposalID, TestAddrs[1], depositParams.MinDeposit) - err, _ = keeper.AddDeposit(ctx, deposit4.ProposalID, deposit4.Depositor, deposit4.Amount) + _, err = keeper.AddDeposit(ctx, deposit4.ProposalID, deposit4.Depositor, deposit4.Amount) require.NoError(t, err) proposal2.TotalDeposit = proposal2.TotalDeposit.Add(deposit4.Amount) @@ -188,7 +188,7 @@ func TestQueries(t *testing.T) { proposal2.VotingEndTime = proposal2.VotingEndTime.Add(types.DefaultPeriod) deposit5 := types.NewDeposit(proposal3.ProposalID, TestAddrs[1], depositParams.MinDeposit) - err, _ = keeper.AddDeposit(ctx, deposit5.ProposalID, deposit5.Depositor, deposit5.Amount) + _, err = keeper.AddDeposit(ctx, deposit5.ProposalID, deposit5.Depositor, deposit5.Amount) require.NoError(t, err) proposal3.TotalDeposit = proposal3.TotalDeposit.Add(deposit5.Amount) diff --git a/x/gov/keeper/test_common.go b/x/gov/keeper/test_common.go index 781964a206d5..777d71a8c887 100644 --- a/x/gov/keeper/test_common.go +++ b/x/gov/keeper/test_common.go @@ -139,19 +139,19 @@ func createTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - pk := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace) + pk := params.NewKeeper(cdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, pk.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(accountKeeper, pk.Subspace(bank.DefaultParamspace), blacklistedAddrs) supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms) - sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) + sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace)) sk.SetParams(ctx, staking.DefaultParams()) rtr := types.NewRouter(). AddRoute(types.RouterKey, types.ProposalHandler) keeper := NewKeeper( - cdc, keyGov, pk.Subspace(types.DefaultParamspace).WithKeyTable(types.ParamKeyTable()), supplyKeeper, sk, types.DefaultCodespace, rtr, + cdc, keyGov, pk.Subspace(types.DefaultParamspace).WithKeyTable(types.ParamKeyTable()), supplyKeeper, sk, rtr, ) keeper.SetProposalID(ctx, types.DefaultStartingProposalID) diff --git a/x/gov/keeper/vote.go b/x/gov/keeper/vote.go index 0204e56be273..309446714287 100644 --- a/x/gov/keeper/vote.go +++ b/x/gov/keeper/vote.go @@ -4,21 +4,22 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/gov/types" ) // AddVote adds a vote on a specific proposal -func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, option types.VoteOption) sdk.Error { +func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, option types.VoteOption) error { proposal, ok := keeper.GetProposal(ctx, proposalID) if !ok { - return types.ErrUnknownProposal(keeper.codespace, proposalID) + return sdkerrors.Wrapf(types.ErrUnknownProposal, "%d", proposalID) } if proposal.Status != types.StatusVotingPeriod { - return types.ErrInactiveProposal(keeper.codespace, proposalID) + return sdkerrors.Wrapf(types.ErrInactiveProposal, "%d", proposalID) } if !types.ValidVoteOption(option) { - return types.ErrInvalidVote(keeper.codespace, option.String()) + return sdkerrors.Wrap(types.ErrInvalidVote, option.String()) } vote := types.NewVote(proposalID, voterAddr, option) diff --git a/x/gov/legacy/v0_36/types.go b/x/gov/legacy/v0_36/types.go index f18cddac1c50..faaaa4e32171 100644 --- a/x/gov/legacy/v0_36/types.go +++ b/x/gov/legacy/v0_36/types.go @@ -16,14 +16,10 @@ const ( ModuleName = "gov" RouterKey = ModuleName - DefaultCodespace sdk.CodespaceType = "gov" - ProposalTypeText string = "Text" MaxDescriptionLength int = 5000 MaxTitleLength int = 140 - - CodeInvalidContent sdk.CodeType = 6 ) var ( @@ -44,7 +40,7 @@ type ( GetDescription() string ProposalRoute() string ProposalType() string - ValidateBasic() sdk.Error + ValidateBasic() error String() string } @@ -94,11 +90,11 @@ func NewTextProposal(title, description string) Content { return TextProposal{title, description} } -func (tp TextProposal) GetTitle() string { return tp.Title } -func (tp TextProposal) GetDescription() string { return tp.Description } -func (tp TextProposal) ProposalRoute() string { return RouterKey } -func (tp TextProposal) ProposalType() string { return ProposalTypeText } -func (tp TextProposal) ValidateBasic() sdk.Error { return ValidateAbstract(DefaultCodespace, tp) } +func (tp TextProposal) GetTitle() string { return tp.Title } +func (tp TextProposal) GetDescription() string { return tp.Description } +func (tp TextProposal) ProposalRoute() string { return RouterKey } +func (tp TextProposal) ProposalType() string { return ProposalTypeText } +func (tp TextProposal) ValidateBasic() error { return ValidateAbstract(tp) } func (tp TextProposal) String() string { return fmt.Sprintf(`Text Proposal: @@ -107,25 +103,25 @@ func (tp TextProposal) String() string { `, tp.Title, tp.Description) } -func ErrInvalidProposalContent(cs sdk.CodespaceType, msg string) sdk.Error { - return sdk.NewError(cs, CodeInvalidContent, fmt.Sprintf("invalid proposal content: %s", msg)) +func ErrInvalidProposalContent(msg string) error { + return fmt.Errorf("invalid proposal content: %s", msg) } -func ValidateAbstract(codespace sdk.CodespaceType, c Content) sdk.Error { +func ValidateAbstract(c Content) error { title := c.GetTitle() if len(strings.TrimSpace(title)) == 0 { - return ErrInvalidProposalContent(codespace, "proposal title cannot be blank") + return ErrInvalidProposalContent("proposal title cannot be blank") } if len(title) > MaxTitleLength { - return ErrInvalidProposalContent(codespace, fmt.Sprintf("proposal title is longer than max length of %d", MaxTitleLength)) + return ErrInvalidProposalContent(fmt.Sprintf("proposal title is longer than max length of %d", MaxTitleLength)) } description := c.GetDescription() if len(description) == 0 { - return ErrInvalidProposalContent(codespace, "proposal description cannot be blank") + return ErrInvalidProposalContent("proposal description cannot be blank") } if len(description) > MaxDescriptionLength { - return ErrInvalidProposalContent(codespace, fmt.Sprintf("proposal description is longer than max length of %d", MaxDescriptionLength)) + return ErrInvalidProposalContent(fmt.Sprintf("proposal description is longer than max length of %d", MaxDescriptionLength)) } return nil diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index 0e0bcd06f600..b53a97350146 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -1,7 +1,6 @@ package simulation import ( - "errors" "math" "math/rand" "time" @@ -148,9 +147,9 @@ func SimulateSubmitProposal( simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } opMsg := simulation.NewOperationMsg(msg, true, "") @@ -231,9 +230,9 @@ func SimulateMsgDeposit(ak types.AccountKeeper, k keeper.Keeper) simulation.Oper simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -289,9 +288,9 @@ func operationSimulateMsgVote(ak types.AccountKeeper, k keeper.Keeper, simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 36479f7fa0c2..7ecd4bd50f68 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -4,7 +4,7 @@ package gov import ( "bytes" - "fmt" + "errors" "log" "sort" "testing" @@ -16,6 +16,7 @@ import ( "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/bank" keep "github.com/cosmos/cosmos-sdk/x/gov/keeper" @@ -43,8 +44,11 @@ type testInput struct { privKeys []crypto.PrivKey } -func getMockApp(t *testing.T, numGenAccs int, genState types.GenesisState, genAccs []authexported.Account, - handler func(ctx sdk.Context, c types.Content) sdk.Error) testInput { +func getMockApp( + t *testing.T, numGenAccs int, genState types.GenesisState, genAccs []authexported.Account, + handler func(ctx sdk.Context, c types.Content) error, +) testInput { + mApp := mock.NewApp() staking.RegisterCodec(mApp.Cdc) @@ -69,7 +73,7 @@ func getMockApp(t *testing.T, numGenAccs int, genState types.GenesisState, genAc rtr := types.NewRouter(). AddRoute(types.RouterKey, handler) - bk := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs) + bk := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ types.ModuleName: {supply.Burner}, @@ -78,11 +82,11 @@ func getMockApp(t *testing.T, numGenAccs int, genState types.GenesisState, genAc } supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bk, maccPerms) sk := staking.NewKeeper( - mApp.Cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace, + mApp.Cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace), ) keeper := keep.NewKeeper( - mApp.Cdc, keyGov, pk.Subspace(DefaultParamspace).WithKeyTable(ParamKeyTable()), supplyKeeper, sk, types.DefaultCodespace, rtr, + mApp.Cdc, keyGov, pk.Subspace(DefaultParamspace).WithKeyTable(ParamKeyTable()), supplyKeeper, sk, rtr, ) mApp.Router().AddRoute(types.RouterKey, NewHandler(keeper)) @@ -193,20 +197,19 @@ const contextKeyBadProposal = "contextKeyBadProposal" // badProposalHandler implements a governance proposal handler that is identical // to the actual handler except this fails if the context doesn't contain a value // for the key contextKeyBadProposal or if the value is false. -func badProposalHandler(ctx sdk.Context, c types.Content) sdk.Error { +func badProposalHandler(ctx sdk.Context, c types.Content) error { switch c.ProposalType() { case types.ProposalTypeText: v := ctx.Value(contextKeyBadProposal) if v == nil || !v.(bool) { - return sdk.ErrInternal("proposal failed") + return errors.New("proposal failed") } return nil default: - msg := fmt.Sprintf("unrecognized gov proposal type: %s", c.ProposalType()) - return sdk.ErrUnknownRequest(msg) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized gov proposal type: %s", c.ProposalType()) } } @@ -229,7 +232,8 @@ func createValidators(t *testing.T, stakingHandler sdk.Handler, ctx sdk.Context, keep.TestDescription, keep.TestCommissionRates, sdk.OneInt(), ) - res := stakingHandler(ctx, valCreateMsg) - require.True(t, res.IsOK()) + res, err := stakingHandler(ctx, valCreateMsg) + require.NoError(t, err) + require.NotNil(t, res) } } diff --git a/x/gov/types/content.go b/x/gov/types/content.go index 22a7f7a4af62..21d70d5ab1e8 100644 --- a/x/gov/types/content.go +++ b/x/gov/types/content.go @@ -1,10 +1,10 @@ package types import ( - "fmt" "strings" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // Constants pertaining to a Content object @@ -22,31 +22,31 @@ type Content interface { GetDescription() string ProposalRoute() string ProposalType() string - ValidateBasic() sdk.Error + ValidateBasic() error String() string } // Handler defines a function that handles a proposal after it has passed the // governance process. -type Handler func(ctx sdk.Context, content Content) sdk.Error +type Handler func(ctx sdk.Context, content Content) error // ValidateAbstract validates a proposal's abstract contents returning an error // if invalid. -func ValidateAbstract(codespace sdk.CodespaceType, c Content) sdk.Error { +func ValidateAbstract(c Content) error { title := c.GetTitle() if len(strings.TrimSpace(title)) == 0 { - return ErrInvalidProposalContent(codespace, "proposal title cannot be blank") + return sdkerrors.Wrap(ErrInvalidProposalContent, "proposal title cannot be blank") } if len(title) > MaxTitleLength { - return ErrInvalidProposalContent(codespace, fmt.Sprintf("proposal title is longer than max length of %d", MaxTitleLength)) + return sdkerrors.Wrapf(ErrInvalidProposalContent, "proposal title is longer than max length of %d", MaxTitleLength) } description := c.GetDescription() if len(description) == 0 { - return ErrInvalidProposalContent(codespace, "proposal description cannot be blank") + return sdkerrors.Wrap(ErrInvalidProposalContent, "proposal description cannot be blank") } if len(description) > MaxDescriptionLength { - return ErrInvalidProposalContent(codespace, fmt.Sprintf("proposal description is longer than max length of %d", MaxDescriptionLength)) + return sdkerrors.Wrapf(ErrInvalidProposalContent, "proposal description is longer than max length of %d", MaxDescriptionLength) } return nil diff --git a/x/gov/types/errors.go b/x/gov/types/errors.go index dfc7bf5a4596..2327a6f05b5e 100644 --- a/x/gov/types/errors.go +++ b/x/gov/types/errors.go @@ -1,66 +1,17 @@ package types -// DONTCOVER - import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// Codes for governance errors -const ( - DefaultCodespace sdk.CodespaceType = ModuleName - - CodeUnknownProposal sdk.CodeType = 1 - CodeInactiveProposal sdk.CodeType = 2 - CodeAlreadyActiveProposal sdk.CodeType = 3 - CodeAlreadyFinishedProposal sdk.CodeType = 4 - CodeAddressNotStaked sdk.CodeType = 5 - CodeInvalidContent sdk.CodeType = 6 - CodeInvalidProposalType sdk.CodeType = 7 - CodeInvalidVote sdk.CodeType = 8 - CodeInvalidGenesis sdk.CodeType = 9 - CodeInvalidProposalStatus sdk.CodeType = 10 - CodeProposalHandlerNotExists sdk.CodeType = 11 +// x/gov module sentinel errors +var ( + ErrUnknownProposal = sdkerrors.Register(ModuleName, 1, "unknown proposal") + ErrInactiveProposal = sdkerrors.Register(ModuleName, 2, "inactive proposal") + ErrAlreadyActiveProposal = sdkerrors.Register(ModuleName, 3, "proposal already active") + ErrInvalidProposalContent = sdkerrors.Register(ModuleName, 4, "invalid proposal content") + ErrInvalidProposalType = sdkerrors.Register(ModuleName, 5, "invalid proposal type") + ErrInvalidVote = sdkerrors.Register(ModuleName, 6, "invalid vote option") + ErrInvalidGenesis = sdkerrors.Register(ModuleName, 7, "invalid genesis state") + ErrNoProposalHandlerExists = sdkerrors.Register(ModuleName, 8, "no handler exists for proposal type") ) - -// ErrUnknownProposal error for unknown proposals -func ErrUnknownProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error { - return sdk.NewError(codespace, CodeUnknownProposal, fmt.Sprintf("unknown proposal with id %d", proposalID)) -} - -// ErrInactiveProposal error for inactive (i.e finalized) proposals -func ErrInactiveProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error { - return sdk.NewError(codespace, CodeInactiveProposal, fmt.Sprintf("inactive proposal with id %d", proposalID)) -} - -// ErrAlreadyActiveProposal error for proposals that are already active -func ErrAlreadyActiveProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error { - return sdk.NewError(codespace, CodeAlreadyActiveProposal, fmt.Sprintf("proposal %d has been already active", proposalID)) -} - -// ErrInvalidProposalContent error for invalid proposal title or description -func ErrInvalidProposalContent(cs sdk.CodespaceType, msg string) sdk.Error { - return sdk.NewError(cs, CodeInvalidContent, fmt.Sprintf("invalid proposal content: %s", msg)) -} - -// ErrInvalidProposalType error for non registered proposal types -func ErrInvalidProposalType(codespace sdk.CodespaceType, proposalType string) sdk.Error { - return sdk.NewError(codespace, CodeInvalidProposalType, fmt.Sprintf("proposal type '%s' is not valid", proposalType)) -} - -// ErrInvalidVote error for an invalid vote option -func ErrInvalidVote(codespace sdk.CodespaceType, voteOption string) sdk.Error { - return sdk.NewError(codespace, CodeInvalidVote, fmt.Sprintf("'%v' is not a valid voting option", voteOption)) -} - -// ErrInvalidGenesis error for an invalid governance GenesisState -func ErrInvalidGenesis(codespace sdk.CodespaceType, msg string) sdk.Error { - return sdk.NewError(codespace, CodeInvalidVote, msg) -} - -// ErrNoProposalHandlerExists error when proposal handler is not defined -func ErrNoProposalHandlerExists(codespace sdk.CodespaceType, content interface{}) sdk.Error { - return sdk.NewError(codespace, CodeProposalHandlerNotExists, fmt.Sprintf("'%T' does not have a corresponding handler", content)) -} diff --git a/x/gov/types/expected_keepers.go b/x/gov/types/expected_keepers.go index c0fda62d61fe..31e5d1e05cff 100644 --- a/x/gov/types/expected_keepers.go +++ b/x/gov/types/expected_keepers.go @@ -21,21 +21,23 @@ type SupplyKeeper interface { // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 SetModuleAccount(sdk.Context, supplyexported.ModuleAccountI) - SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error - BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error } // StakingKeeper expected staking keeper (Validator and Delegator sets) (noalias) type StakingKeeper interface { // iterate through bonded validators by operator address, execute func for each validator - IterateBondedValidatorsByPower(sdk.Context, - func(index int64, validator stakingexported.ValidatorI) (stop bool)) + IterateBondedValidatorsByPower( + sdk.Context, func(index int64, validator stakingexported.ValidatorI) (stop bool), + ) TotalBondedTokens(sdk.Context) sdk.Int // total bonded tokens within the validator set - - IterateDelegations(ctx sdk.Context, delegator sdk.AccAddress, - fn func(index int64, delegation stakingexported.DelegationI) (stop bool)) + IterateDelegations( + ctx sdk.Context, delegator sdk.AccAddress, + fn func(index int64, delegation stakingexported.DelegationI) (stop bool), + ) } // AccountKeeper defines the expected account keeper (noalias) diff --git a/x/gov/types/msgs.go b/x/gov/types/msgs.go index b5b85ca167ea..882e0c560c31 100644 --- a/x/gov/types/msgs.go +++ b/x/gov/types/msgs.go @@ -4,6 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // Governance message types and routes @@ -35,21 +36,21 @@ func (msg MsgSubmitProposal) Route() string { return RouterKey } func (msg MsgSubmitProposal) Type() string { return TypeMsgSubmitProposal } // ValidateBasic implements Msg -func (msg MsgSubmitProposal) ValidateBasic() sdk.Error { +func (msg MsgSubmitProposal) ValidateBasic() error { if msg.Content == nil { - return ErrInvalidProposalContent(DefaultCodespace, "missing content") + return sdkerrors.Wrap(ErrInvalidProposalContent, "missing content") } if msg.Proposer.Empty() { - return sdk.ErrInvalidAddress(msg.Proposer.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Proposer.String()) } if !msg.InitialDeposit.IsValid() { - return sdk.ErrInvalidCoins(msg.InitialDeposit.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.InitialDeposit.String()) } if msg.InitialDeposit.IsAnyNegative() { - return sdk.ErrInvalidCoins(msg.InitialDeposit.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.InitialDeposit.String()) } if !IsValidProposalType(msg.Content.ProposalType()) { - return ErrInvalidProposalType(DefaultCodespace, msg.Content.ProposalType()) + return sdkerrors.Wrap(ErrInvalidProposalType, msg.Content.ProposalType()) } return msg.Content.ValidateBasic() @@ -93,15 +94,15 @@ func (msg MsgDeposit) Route() string { return RouterKey } func (msg MsgDeposit) Type() string { return TypeMsgDeposit } // ValidateBasic implements Msg -func (msg MsgDeposit) ValidateBasic() sdk.Error { +func (msg MsgDeposit) ValidateBasic() error { if msg.Depositor.Empty() { - return sdk.ErrInvalidAddress(msg.Depositor.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Depositor.String()) } if !msg.Amount.IsValid() { - return sdk.ErrInvalidCoins(msg.Amount.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) } if msg.Amount.IsAnyNegative() { - return sdk.ErrInvalidCoins(msg.Amount.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) } return nil @@ -146,12 +147,12 @@ func (msg MsgVote) Route() string { return RouterKey } func (msg MsgVote) Type() string { return TypeMsgVote } // ValidateBasic implements Msg -func (msg MsgVote) ValidateBasic() sdk.Error { +func (msg MsgVote) ValidateBasic() error { if msg.Voter.Empty() { - return sdk.ErrInvalidAddress(msg.Voter.String()) + return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, msg.Voter.String()) } if !ValidVoteOption(msg.Option) { - return ErrInvalidVote(DefaultCodespace, msg.Option.String()) + return sdkerrors.Wrap(ErrInvalidVote, msg.Option.String()) } return nil diff --git a/x/gov/types/proposal.go b/x/gov/types/proposal.go index a02f7b54d6b9..945cf786687b 100644 --- a/x/gov/types/proposal.go +++ b/x/gov/types/proposal.go @@ -7,6 +7,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // DefaultStartingProposalID is 1 @@ -232,7 +233,7 @@ func (tp TextProposal) ProposalRoute() string { return RouterKey } func (tp TextProposal) ProposalType() string { return ProposalTypeText } // ValidateBasic validates the content's title and description of the proposal -func (tp TextProposal) ValidateBasic() sdk.Error { return ValidateAbstract(DefaultCodespace, tp) } +func (tp TextProposal) ValidateBasic() error { return ValidateAbstract(tp) } // String implements Stringer interface func (tp TextProposal) String() string { @@ -280,14 +281,13 @@ func IsValidProposalType(ty string) bool { // proposals (ie. TextProposal ). Since these are // merely signaling mechanisms at the moment and do not affect state, it // performs a no-op. -func ProposalHandler(_ sdk.Context, c Content) sdk.Error { +func ProposalHandler(_ sdk.Context, c Content) error { switch c.ProposalType() { case ProposalTypeText: // both proposal types do not change state so this performs a no-op return nil default: - errMsg := fmt.Sprintf("unrecognized gov proposal type: %s", c.ProposalType()) - return sdk.ErrUnknownRequest(errMsg) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized gov proposal type: %s", c.ProposalType()) } } diff --git a/x/mint/alias.go b/x/mint/alias.go index 9572d077b458..c6d2330f9a8b 100644 --- a/x/mint/alias.go +++ b/x/mint/alias.go @@ -1,10 +1,7 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/mint/internal/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/mint/internal/types package mint +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/mint/internal/keeper" "github.com/cosmos/cosmos-sdk/x/mint/internal/types" diff --git a/x/mint/internal/keeper/keeper.go b/x/mint/internal/keeper/keeper.go index ff4bd029dfda..3be3146fdf68 100644 --- a/x/mint/internal/keeper/keeper.go +++ b/x/mint/internal/keeper/keeper.go @@ -24,7 +24,8 @@ type Keeper struct { // NewKeeper creates a new mint Keeper instance func NewKeeper( cdc *codec.Codec, key sdk.StoreKey, paramSpace params.Subspace, - sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string) Keeper { + sk types.StakingKeeper, supplyKeeper types.SupplyKeeper, feeCollectorName string, +) Keeper { // ensure mint module account is set if addr := supplyKeeper.GetModuleAddress(types.ModuleName); addr == nil { @@ -96,16 +97,17 @@ func (k Keeper) BondedRatio(ctx sdk.Context) sdk.Dec { // MintCoins implements an alias call to the underlying supply keeper's // MintCoins to be used in BeginBlocker. -func (k Keeper) MintCoins(ctx sdk.Context, newCoins sdk.Coins) sdk.Error { +func (k Keeper) MintCoins(ctx sdk.Context, newCoins sdk.Coins) error { if newCoins.Empty() { // skip as no coins need to be minted return nil } + return k.supplyKeeper.MintCoins(ctx, types.ModuleName, newCoins) } // AddCollectedFees implements an alias call to the underlying supply keeper's // AddCollectedFees to be used in BeginBlocker. -func (k Keeper) AddCollectedFees(ctx sdk.Context, fees sdk.Coins) sdk.Error { +func (k Keeper) AddCollectedFees(ctx sdk.Context, fees sdk.Coins) error { return k.supplyKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, k.feeCollectorName, fees) } diff --git a/x/mint/internal/keeper/querier.go b/x/mint/internal/keeper/querier.go index fe3943f0896a..258d1b111ed2 100644 --- a/x/mint/internal/keeper/querier.go +++ b/x/mint/internal/keeper/querier.go @@ -1,18 +1,17 @@ package keeper import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/mint/internal/types" ) // NewQuerier returns a minting Querier handler. func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, _ abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, _ abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryParameters: return queryParams(ctx, k) @@ -24,39 +23,39 @@ func NewQuerier(k Keeper) sdk.Querier { return queryAnnualProvisions(ctx, k) default: - return nil, sdk.ErrUnknownRequest(fmt.Sprintf("unknown minting query endpoint: %s", path[0])) + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query path: %s", path[0]) } } } -func queryParams(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { +func queryParams(ctx sdk.Context, k Keeper) ([]byte, error) { params := k.GetParams(ctx) res, err := codec.MarshalJSONIndent(k.cdc, params) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryInflation(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { +func queryInflation(ctx sdk.Context, k Keeper) ([]byte, error) { minter := k.GetMinter(ctx) res, err := codec.MarshalJSONIndent(k.cdc, minter.Inflation) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryAnnualProvisions(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { +func queryAnnualProvisions(ctx sdk.Context, k Keeper) ([]byte, error) { minter := k.GetMinter(ctx) res, err := codec.MarshalJSONIndent(k.cdc, minter.AnnualProvisions) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil diff --git a/x/mint/internal/types/expected_keepers.go b/x/mint/internal/types/expected_keepers.go index 564a0136b5c7..ea20619164d3 100644 --- a/x/mint/internal/types/expected_keepers.go +++ b/x/mint/internal/types/expected_keepers.go @@ -18,7 +18,7 @@ type SupplyKeeper interface { // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 SetModuleAccount(sdk.Context, exported.ModuleAccountI) - SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) sdk.Error - MintCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error + MintCoins(ctx sdk.Context, name string, amt sdk.Coins) error } diff --git a/x/mock/app.go b/x/mock/app.go index 1e59e050507b..d0cee9f592af 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -64,7 +64,7 @@ func NewApp() *App { } // define keepers - app.ParamsKeeper = params.NewKeeper(app.Cdc, app.KeyParams, app.TKeyParams, params.DefaultCodespace) + app.ParamsKeeper = params.NewKeeper(app.Cdc, app.KeyParams, app.TKeyParams) app.AccountKeeper = auth.NewAccountKeeper( app.Cdc, diff --git a/x/mock/app_test.go b/x/mock/app_test.go index db5e29522539..95bed4fda085 100644 --- a/x/mock/app_test.go +++ b/x/mock/app_test.go @@ -7,6 +7,7 @@ import ( abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/supply/exported" ) @@ -32,18 +33,20 @@ func (tx testMsg) GetMemo() string { return "" } func (tx testMsg) GetSignBytes() []byte { return nil } func (tx testMsg) GetSigners() []sdk.AccAddress { return tx.signers } func (tx testMsg) GetSignatures() []auth.StdSignature { return nil } -func (tx testMsg) ValidateBasic() sdk.Error { +func (tx testMsg) ValidateBasic() error { if tx.positiveNum >= 0 { return nil } - return sdk.ErrTxDecode("positiveNum should be a non-negative integer.") + return sdkerrors.Wrap(sdkerrors.ErrTxDecode, "positiveNum should be a non-negative integer") } // getMockApp returns an initialized mock application. func getMockApp(t *testing.T) *App { mApp := NewApp() - mApp.Router().AddRoute(msgRoute, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return }) + mApp.Router().AddRoute(msgRoute, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + return &sdk.Result{}, nil + }) require.NoError(t, mApp.CompleteSetup()) return mApp @@ -71,15 +74,16 @@ func TestCheckAndDeliverGenTx(t *testing.T) { // Signing a tx with the wrong privKey should result in an auth error header = abci.Header{Height: mApp.LastBlockHeight() + 1} - res := SignCheckDeliver( + _, _, err := SignCheckDeliver( t, mApp.Cdc, mApp.BaseApp, header, []sdk.Msg{msg}, []uint64{accs[1].GetAccountNumber()}, []uint64{accs[1].GetSequence() + 1}, true, false, privKeys[1], ) // Will fail on SetPubKey decorator - require.Equal(t, sdk.CodeInvalidPubKey, res.Code, res.Log) - require.Equal(t, sdk.CodespaceRoot, res.Codespace) + space, code, log := sdkerrors.ABCIInfo(err, false) + require.Equal(t, sdkerrors.ErrInvalidPubKey.ABCICode(), code, log) + require.Equal(t, sdkerrors.ErrInvalidPubKey.Codespace(), space) // Resigning the tx with the correct privKey should result in an OK result header = abci.Header{Height: mApp.LastBlockHeight() + 1} diff --git a/x/mock/test_utils.go b/x/mock/test_utils.go index 2b5978823363..11073e64f413 100644 --- a/x/mock/test_utils.go +++ b/x/mock/test_utils.go @@ -55,17 +55,19 @@ func CheckBalance(t *testing.T, app *App, addr sdk.AccAddress, exp sdk.Coins) { func CheckGenTx( t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accNums []uint64, seq []uint64, expPass bool, priv ...crypto.PrivKey, -) sdk.Result { +) (sdk.GasInfo, *sdk.Result, error) { tx := GenTx(msgs, accNums, seq, priv...) - res := app.Check(tx) + gInfo, res, err := app.Check(tx) if expPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.NoError(t, err) + require.NotNil(t, res) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.Error(t, err) + require.Nil(t, res) } - return res + return gInfo, res, err } // SignCheckDeliver checks a generated signed transaction and simulates a @@ -75,7 +77,7 @@ func CheckGenTx( func SignCheckDeliver( t *testing.T, cdc *codec.Codec, app *baseapp.BaseApp, header abci.Header, msgs []sdk.Msg, accNums, seq []uint64, expSimPass, expPass bool, priv ...crypto.PrivKey, -) sdk.Result { +) (sdk.GasInfo, *sdk.Result, error) { tx := GenTx(msgs, accNums, seq, priv...) @@ -83,26 +85,31 @@ func SignCheckDeliver( require.Nil(t, err) // Must simulate now as CheckTx doesn't run Msgs anymore - res := app.Simulate(txBytes, tx) + _, res, err := app.Simulate(txBytes, tx) if expSimPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.NoError(t, err) + require.NotNil(t, res) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.Error(t, err) + require.Nil(t, res) } // Simulate a sending a transaction and committing a block app.BeginBlock(abci.RequestBeginBlock{Header: header}) - res = app.Deliver(tx) + + gInfo, res, err := app.Deliver(tx) if expPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.NoError(t, err) + require.NotNil(t, res) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.Error(t, err) + require.Nil(t, res) } app.EndBlock(abci.RequestEndBlock{}) app.Commit() - return res + return gInfo, res, err } diff --git a/x/mock/types.go b/x/mock/types.go index 14ec10772006..56912780dac1 100644 --- a/x/mock/types.go +++ b/x/mock/types.go @@ -4,7 +4,7 @@ import ( "github.com/tendermint/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" - + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/supply" "github.com/cosmos/cosmos-sdk/x/supply/exported" @@ -22,24 +22,23 @@ func NewDummySupplyKeeper(ak auth.AccountKeeper) DummySupplyKeeper { } // SendCoinsFromAccountToModule for the dummy supply keeper -func (sk DummySupplyKeeper) SendCoinsFromAccountToModule(ctx sdk.Context, fromAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error { - +func (sk DummySupplyKeeper) SendCoinsFromAccountToModule(ctx sdk.Context, fromAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error { fromAcc := sk.ak.GetAccount(ctx, fromAddr) moduleAcc := sk.GetModuleAccount(ctx, recipientModule) newFromCoins, hasNeg := fromAcc.GetCoins().SafeSub(amt) if hasNeg { - return sdk.ErrInsufficientCoins(fromAcc.GetCoins().String()) + return sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, fromAcc.GetCoins().String()) } newToCoins := moduleAcc.GetCoins().Add(amt) if err := fromAcc.SetCoins(newFromCoins); err != nil { - return sdk.ErrInternal(err.Error()) + return err } if err := moduleAcc.SetCoins(newToCoins); err != nil { - return sdk.ErrInternal(err.Error()) + return err } sk.ak.SetAccount(ctx, fromAcc) diff --git a/x/params/alias.go b/x/params/alias.go index ace601c219dc..1198e93cede3 100644 --- a/x/params/alias.go +++ b/x/params/alias.go @@ -1,10 +1,6 @@ package params // nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/params/subspace -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/params/types import ( "github.com/cosmos/cosmos-sdk/x/params/subspace" @@ -12,15 +8,11 @@ import ( ) const ( - StoreKey = subspace.StoreKey - TStoreKey = subspace.TStoreKey - DefaultCodespace = types.DefaultCodespace - CodeUnknownSubspace = types.CodeUnknownSubspace - CodeSettingParameter = types.CodeSettingParameter - CodeEmptyData = types.CodeEmptyData - ModuleName = types.ModuleName - RouterKey = types.RouterKey - ProposalTypeChange = types.ProposalTypeChange + StoreKey = subspace.StoreKey + TStoreKey = subspace.TStoreKey + ModuleName = types.ModuleName + RouterKey = types.RouterKey + ProposalTypeChange = types.ProposalTypeChange ) var ( diff --git a/x/params/commmon_test.go b/x/params/commmon_test.go index 5ca01ad98d40..ecebf8eb2e60 100644 --- a/x/params/commmon_test.go +++ b/x/params/commmon_test.go @@ -43,7 +43,7 @@ func testComponents() (*codec.Codec, sdk.Context, sdk.StoreKey, sdk.StoreKey, Ke mkey := sdk.NewKVStoreKey("test") tkey := sdk.NewTransientStoreKey("transient_test") ctx := defaultContext(mkey, tkey) - keeper := NewKeeper(cdc, mkey, tkey, DefaultCodespace) + keeper := NewKeeper(cdc, mkey, tkey) return cdc, ctx, mkey, tkey, keeper } diff --git a/x/params/keeper.go b/x/params/keeper.go index 9e91259df656..c3532f32834f 100644 --- a/x/params/keeper.go +++ b/x/params/keeper.go @@ -13,21 +13,19 @@ import ( // Keeper of the global paramstore type Keeper struct { - cdc *codec.Codec - key sdk.StoreKey - tkey sdk.StoreKey - codespace sdk.CodespaceType - spaces map[string]*Subspace + cdc *codec.Codec + key sdk.StoreKey + tkey sdk.StoreKey + spaces map[string]*Subspace } // NewKeeper constructs a params keeper -func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey, codespace sdk.CodespaceType) Keeper { +func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey) Keeper { return Keeper{ - cdc: cdc, - key: key, - tkey: tkey, - codespace: codespace, - spaces: make(map[string]*Subspace), + cdc: cdc, + key: key, + tkey: tkey, + spaces: make(map[string]*Subspace), } } diff --git a/x/params/proposal_handler.go b/x/params/proposal_handler.go index e2e976454275..339cfd7410ce 100644 --- a/x/params/proposal_handler.go +++ b/x/params/proposal_handler.go @@ -4,28 +4,28 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) // NewParamChangeProposalHandler creates a new governance Handler for a ParamChangeProposal func NewParamChangeProposalHandler(k Keeper) govtypes.Handler { - return func(ctx sdk.Context, content govtypes.Content) sdk.Error { + return func(ctx sdk.Context, content govtypes.Content) error { switch c := content.(type) { case ParameterChangeProposal: return handleParameterChangeProposal(ctx, k, c) default: - errMsg := fmt.Sprintf("unrecognized param proposal content type: %T", c) - return sdk.ErrUnknownRequest(errMsg) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized param proposal content type: %T", c) } } } -func handleParameterChangeProposal(ctx sdk.Context, k Keeper, p ParameterChangeProposal) sdk.Error { +func handleParameterChangeProposal(ctx sdk.Context, k Keeper, p ParameterChangeProposal) error { for _, c := range p.Changes { ss, ok := k.GetSubspace(c.Subspace) if !ok { - return ErrUnknownSubspace(k.codespace, c.Subspace) + return sdkerrors.Wrap(ErrUnknownSubspace, c.Subspace) } k.Logger(ctx).Info( @@ -33,7 +33,7 @@ func handleParameterChangeProposal(ctx sdk.Context, k Keeper, p ParameterChangeP ) if err := ss.Update(ctx, []byte(c.Key), []byte(c.Value)); err != nil { - return ErrSettingParameter(k.codespace, c.Key, c.Value, err.Error()) + return sdkerrors.Wrapf(ErrSettingParameter, "key: %s, value: %s, err: %s", c.Key, c.Value, err.Error()) } } diff --git a/x/params/proposal_handler_test.go b/x/params/proposal_handler_test.go index 841f832160c5..9d83975c1020 100644 --- a/x/params/proposal_handler_test.go +++ b/x/params/proposal_handler_test.go @@ -74,7 +74,7 @@ func newTestInput(t *testing.T) testInput { err := cms.LoadLatestVersion() require.Nil(t, err) - keeper := params.NewKeeper(cdc, keyParams, tKeyParams, params.DefaultCodespace) + keeper := params.NewKeeper(cdc, keyParams, tKeyParams) ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) return testInput{ctx, cdc, keeper} diff --git a/x/params/types/errors.go b/x/params/types/errors.go index 12726b0322f5..4b218d9444ee 100644 --- a/x/params/types/errors.go +++ b/x/params/types/errors.go @@ -1,46 +1,15 @@ package types import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// Param module codespace constants -const ( - DefaultCodespace sdk.CodespaceType = "params" - - CodeUnknownSubspace sdk.CodeType = 1 - CodeSettingParameter sdk.CodeType = 2 - CodeEmptyData sdk.CodeType = 3 +// x/params module sentinel errors +var ( + ErrUnknownSubspace = sdkerrors.Register(ModuleName, 1, "unknown subspace") + ErrSettingParameter = sdkerrors.Register(ModuleName, 2, "failed to set parameter") + ErrEmptyChanges = sdkerrors.Register(ModuleName, 3, "submitted parameter changes are empty") + ErrEmptySubspace = sdkerrors.Register(ModuleName, 4, "parameter subspace is empty") + ErrEmptyKey = sdkerrors.Register(ModuleName, 5, "parameter key is empty") + ErrEmptyValue = sdkerrors.Register(ModuleName, 6, "parameter value is empty") ) - -// ErrUnknownSubspace returns an unknown subspace error. -func ErrUnknownSubspace(codespace sdk.CodespaceType, space string) sdk.Error { - return sdk.NewError(codespace, CodeUnknownSubspace, fmt.Sprintf("unknown subspace %s", space)) -} - -// ErrSettingParameter returns an error for failing to set a parameter. -func ErrSettingParameter(codespace sdk.CodespaceType, key, value, msg string) sdk.Error { - return sdk.NewError(codespace, CodeSettingParameter, fmt.Sprintf("error setting parameter %s on %s: %s", value, key, msg)) -} - -// ErrEmptyChanges returns an error for empty parameter changes. -func ErrEmptyChanges(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeEmptyData, "submitted parameter changes are empty") -} - -// ErrEmptySubspace returns an error for an empty subspace. -func ErrEmptySubspace(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeEmptyData, "parameter subspace is empty") -} - -// ErrEmptyKey returns an error for when an empty key is given. -func ErrEmptyKey(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeEmptyData, "parameter key is empty") -} - -// ErrEmptyValue returns an error for when an empty key is given. -func ErrEmptyValue(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeEmptyData, "parameter value is empty") -} diff --git a/x/params/types/proposal.go b/x/params/types/proposal.go index a4bcefab2df6..78f200d143e9 100644 --- a/x/params/types/proposal.go +++ b/x/params/types/proposal.go @@ -4,7 +4,6 @@ import ( "fmt" "strings" - sdk "github.com/cosmos/cosmos-sdk/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -46,8 +45,8 @@ func (pcp ParameterChangeProposal) ProposalRoute() string { return RouterKey } func (pcp ParameterChangeProposal) ProposalType() string { return ProposalTypeChange } // ValidateBasic validates the parameter change proposal -func (pcp ParameterChangeProposal) ValidateBasic() sdk.Error { - err := govtypes.ValidateAbstract(DefaultCodespace, pcp) +func (pcp ParameterChangeProposal) ValidateBasic() error { + err := govtypes.ValidateAbstract(pcp) if err != nil { return err } @@ -98,20 +97,20 @@ func (pc ParamChange) String() string { // ValidateChanges performs basic validation checks over a set of ParamChange. It // returns an error if any ParamChange is invalid. -func ValidateChanges(changes []ParamChange) sdk.Error { +func ValidateChanges(changes []ParamChange) error { if len(changes) == 0 { - return ErrEmptyChanges(DefaultCodespace) + return ErrEmptyChanges } for _, pc := range changes { if len(pc.Subspace) == 0 { - return ErrEmptySubspace(DefaultCodespace) + return ErrEmptySubspace } if len(pc.Key) == 0 { - return ErrEmptyKey(DefaultCodespace) + return ErrEmptyKey } if len(pc.Value) == 0 { - return ErrEmptyValue(DefaultCodespace) + return ErrEmptyValue } } diff --git a/x/slashing/abci_test.go b/x/slashing/abci_test.go index 84d36c6ee083..bcd1ee7ce8a2 100644 --- a/x/slashing/abci_test.go +++ b/x/slashing/abci_test.go @@ -20,8 +20,10 @@ func TestBeginBlocker(t *testing.T) { addr, pk := slashingkeeper.Addrs[2], slashingkeeper.Pks[2] // bond the validator - got := staking.NewHandler(sk)(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, pk, amt)) - require.True(t, got.IsOK()) + res, err := staking.NewHandler(sk)(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, pk, amt)) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) require.Equal( t, ck.GetCoins(ctx, sdk.AccAddress(addr)), diff --git a/x/slashing/alias.go b/x/slashing/alias.go index 677228182c0d..38d556a6e492 100644 --- a/x/slashing/alias.go +++ b/x/slashing/alias.go @@ -1,23 +1,13 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/slashing/internal/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/slashing/internal/types package slashing +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/slashing/internal/keeper" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" ) const ( - DefaultCodespace = types.DefaultCodespace - CodeInvalidValidator = types.CodeInvalidValidator - CodeValidatorJailed = types.CodeValidatorJailed - CodeValidatorNotJailed = types.CodeValidatorNotJailed - CodeMissingSelfDelegation = types.CodeMissingSelfDelegation - CodeSelfDelegationTooLow = types.CodeSelfDelegationTooLow - CodeMissingSigningInfo = types.CodeMissingSigningInfo ModuleName = types.ModuleName StoreKey = types.StoreKey RouterKey = types.RouterKey @@ -89,7 +79,6 @@ var ( type ( Hooks = keeper.Hooks Keeper = keeper.Keeper - CodeType = types.CodeType GenesisState = types.GenesisState MissedBlock = types.MissedBlock MsgUnjail = types.MsgUnjail diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 8704333b75b8..23dd43e590bf 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -3,6 +3,7 @@ package slashing import ( + "errors" "testing" "github.com/stretchr/testify/require" @@ -47,15 +48,15 @@ func getMockApp(t *testing.T) (*mock.App, staking.Keeper, Keeper) { blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(mapp.AccountKeeper, mapp.ParamsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, staking.NotBondedPoolName: {supply.Burner, supply.Staking}, staking.BondedPoolName: {supply.Burner, supply.Staking}, } supplyKeeper := supply.NewKeeper(mapp.Cdc, keySupply, mapp.AccountKeeper, bankKeeper, maccPerms) - stakingKeeper := staking.NewKeeper(mapp.Cdc, keyStaking, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) - keeper := NewKeeper(mapp.Cdc, keySlashing, stakingKeeper, mapp.ParamsKeeper.Subspace(DefaultParamspace), DefaultCodespace) + stakingKeeper := staking.NewKeeper(mapp.Cdc, keyStaking, supplyKeeper, mapp.ParamsKeeper.Subspace(staking.DefaultParamspace)) + keeper := NewKeeper(mapp.Cdc, keySlashing, stakingKeeper, mapp.ParamsKeeper.Subspace(DefaultParamspace)) mapp.Router().AddRoute(staking.RouterKey, staking.NewHandler(stakingKeeper)) mapp.Router().AddRoute(RouterKey, NewHandler(keeper)) @@ -152,7 +153,8 @@ func TestSlashingMsgs(t *testing.T) { // unjail should fail with unknown validator header = abci.Header{Height: mapp.LastBlockHeight() + 1} - res := mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{unjailMsg}, []uint64{0}, []uint64{1}, false, false, priv1) - require.EqualValues(t, CodeValidatorNotJailed, res.Code) - require.EqualValues(t, DefaultCodespace, res.Codespace) + _, res, err := mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{unjailMsg}, []uint64{0}, []uint64{1}, false, false, priv1) + require.Error(t, err) + require.Nil(t, res) + require.True(t, errors.Is(ErrValidatorNotJailed, err)) } diff --git a/x/slashing/handler.go b/x/slashing/handler.go index 3c338d0bc7b2..fe4ef7cb7c2e 100644 --- a/x/slashing/handler.go +++ b/x/slashing/handler.go @@ -1,15 +1,14 @@ package slashing import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" ) // NewHandler creates an sdk.Handler for all the slashing type messages func NewHandler(k Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -17,19 +16,17 @@ func NewHandler(k Keeper) sdk.Handler { return handleMsgUnjail(ctx, msg, k) default: - errMsg := fmt.Sprintf("unrecognized slashing message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } } } // Validators must submit a transaction to unjail itself after // having been jailed (and thus unbonded) for downtime -func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result { - +func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) (*sdk.Result, error) { err := k.Unjail(ctx, msg.ValidatorAddr) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvent( @@ -40,5 +37,5 @@ func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result { ), ) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index e0d5228326da..a137ff8d0d08 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -1,6 +1,7 @@ package slashing import ( + "errors" "strings" "testing" "time" @@ -20,9 +21,12 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { slh := NewHandler(keeper) amt := sdk.TokensFromConsensusPower(100) addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] + msg := slashingkeeper.NewTestMsgCreateValidator(addr, val, amt) - got := staking.NewHandler(sk)(ctx, msg) - require.True(t, got.IsOK(), "%v", got) + res, err := staking.NewHandler(sk)(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) require.Equal( @@ -32,10 +36,10 @@ func TestCannotUnjailUnlessJailed(t *testing.T) { require.Equal(t, amt, sk.Validator(ctx, addr).GetBondedTokens()) // assert non-jailed validator can't be unjailed - got = slh(ctx, NewMsgUnjail(addr)) - require.False(t, got.IsOK(), "allowed unjail of non-jailed validator") - require.EqualValues(t, CodeValidatorNotJailed, got.Code) - require.EqualValues(t, DefaultCodespace, got.Codespace) + res, err = slh(ctx, NewMsgUnjail(addr)) + require.Error(t, err) + require.Nil(t, res) + require.True(t, errors.Is(ErrValidatorNotJailed, err)) } func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { @@ -46,8 +50,11 @@ func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { addr, val, amt := slashingkeeper.Addrs[0], slashingkeeper.Pks[0], sdk.TokensFromConsensusPower(amtInt) msg := slashingkeeper.NewTestMsgCreateValidator(addr, val, amt) msg.MinSelfDelegation = amt - got := staking.NewHandler(sk)(ctx, msg) - require.True(t, got.IsOK()) + + res, err := staking.NewHandler(sk)(ctx, msg) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) require.Equal( @@ -57,15 +64,17 @@ func TestCannotUnjailUnlessMeetMinSelfDelegation(t *testing.T) { unbondAmt := sdk.NewCoin(sk.GetParams(ctx).BondDenom, sdk.OneInt()) undelegateMsg := staking.NewMsgUndelegate(sdk.AccAddress(addr), addr, unbondAmt) - got = staking.NewHandler(sk)(ctx, undelegateMsg) + res, err = staking.NewHandler(sk)(ctx, undelegateMsg) + require.NoError(t, err) + require.NotNil(t, res) require.True(t, sk.Validator(ctx, addr).IsJailed()) // assert non-jailed validator can't be unjailed - got = slh(ctx, NewMsgUnjail(addr)) - require.False(t, got.IsOK(), "allowed unjail of validator with less than MinSelfDelegation") - require.EqualValues(t, CodeValidatorNotJailed, got.Code) - require.EqualValues(t, DefaultCodespace, got.Codespace) + res, err = slh(ctx, NewMsgUnjail(addr)) + require.Error(t, err) + require.Nil(t, res) + require.True(t, errors.Is(ErrSelfDelegationTooLowToUnjail, err)) } func TestJailedValidatorDelegations(t *testing.T) { @@ -80,8 +89,9 @@ func TestJailedValidatorDelegations(t *testing.T) { valAddr, consAddr := slashingkeeper.Addrs[1], sdk.ConsAddress(slashingkeeper.Addrs[0]) msgCreateVal := slashingkeeper.NewTestMsgCreateValidator(valAddr, valPubKey, bondAmount) - got := staking.NewHandler(stakingKeeper)(ctx, msgCreateVal) - require.True(t, got.IsOK(), "expected create validator msg to be ok, got: %v", got) + res, err := staking.NewHandler(stakingKeeper)(ctx, msgCreateVal) + require.NoError(t, err) + require.NotNil(t, res) // end block staking.EndBlocker(ctx, stakingKeeper) @@ -93,17 +103,19 @@ func TestJailedValidatorDelegations(t *testing.T) { // delegate tokens to the validator delAddr := sdk.AccAddress(slashingkeeper.Addrs[2]) msgDelegate := slashingkeeper.NewTestMsgDelegate(delAddr, valAddr, bondAmount) - got = staking.NewHandler(stakingKeeper)(ctx, msgDelegate) - require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + res, err = staking.NewHandler(stakingKeeper)(ctx, msgDelegate) + require.NoError(t, err) + require.NotNil(t, res) unbondAmt := sdk.NewCoin(stakingKeeper.GetParams(ctx).BondDenom, bondAmount) // unbond validator total self-delegations (which should jail the validator) msgUndelegate := staking.NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) - got = staking.NewHandler(stakingKeeper)(ctx, msgUndelegate) - require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got: %v", got) + res, err = staking.NewHandler(stakingKeeper)(ctx, msgUndelegate) + require.NoError(t, err) + require.NotNil(t, res) - err := stakingKeeper.CompleteUnbonding(ctx, sdk.AccAddress(valAddr), valAddr) + err = stakingKeeper.CompleteUnbonding(ctx, sdk.AccAddress(valAddr), valAddr) require.Nil(t, err, "expected complete unbonding validator to be ok, got: %v", err) // verify validator still exists and is jailed @@ -112,26 +124,30 @@ func TestJailedValidatorDelegations(t *testing.T) { require.True(t, validator.IsJailed()) // verify the validator cannot unjail itself - got = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) - require.False(t, got.IsOK(), "expected jailed validator to not be able to unjail, got: %v", got) + res, err = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) + require.Error(t, err) + require.Nil(t, res) // self-delegate to validator msgSelfDelegate := slashingkeeper.NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) - got = staking.NewHandler(stakingKeeper)(ctx, msgSelfDelegate) - require.True(t, got.IsOK(), "expected delegation to not be ok, got %v", got) + res, err = staking.NewHandler(stakingKeeper)(ctx, msgSelfDelegate) + require.NoError(t, err) + require.NotNil(t, res) // verify the validator can now unjail itself - got = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) - require.True(t, got.IsOK(), "expected jailed validator to be able to unjail, got: %v", got) + res, err = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr)) + require.NoError(t, err) + require.NotNil(t, res) } func TestInvalidMsg(t *testing.T) { k := Keeper{} h := NewHandler(k) - res := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) - require.False(t, res.IsOK()) - require.True(t, strings.Contains(res.Log, "unrecognized slashing message type")) + res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) + require.Error(t, err) + require.Nil(t, res) + require.True(t, strings.Contains(err.Error(), "unrecognized slashing message type")) } // Test a validator through uptime, downtime, revocation, @@ -145,8 +161,11 @@ func TestHandleAbsentValidator(t *testing.T) { addr, val := slashingkeeper.Addrs[0], slashingkeeper.Pks[0] sh := staking.NewHandler(sk) slh := NewHandler(keeper) - got := sh(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, val, amt)) - require.True(t, got.IsOK()) + + res, err := sh(ctx, slashingkeeper.NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) require.Equal( @@ -228,13 +247,15 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, amt.Int64()-slashAmt, validator.GetTokens().Int64()) // unrevocation should fail prior to jail expiration - got = slh(ctx, types.NewMsgUnjail(addr)) - require.False(t, got.IsOK()) + res, err = slh(ctx, types.NewMsgUnjail(addr)) + require.Error(t, err) + require.Nil(t, res) // unrevocation should succeed after jail expiration ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.DowntimeJailDuration(ctx))}) - got = slh(ctx, types.NewMsgUnjail(addr)) - require.True(t, got.IsOK()) + res, err = slh(ctx, types.NewMsgUnjail(addr)) + require.NoError(t, err) + require.NotNil(t, res) // end block staking.EndBlocker(ctx, sk) diff --git a/x/slashing/internal/keeper/keeper.go b/x/slashing/internal/keeper/keeper.go index b7a3706369f9..e725519314d1 100644 --- a/x/slashing/internal/keeper/keeper.go +++ b/x/slashing/internal/keeper/keeper.go @@ -17,19 +17,16 @@ type Keeper struct { cdc *codec.Codec sk types.StakingKeeper paramspace types.ParamSubspace - codespace sdk.CodespaceType } // NewKeeper creates a slashing keeper -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, sk types.StakingKeeper, paramspace types.ParamSubspace, codespace sdk.CodespaceType) Keeper { - keeper := Keeper{ +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, sk types.StakingKeeper, paramspace types.ParamSubspace) Keeper { + return Keeper{ storeKey: key, cdc: cdc, sk: sk, paramspace: paramspace.WithKeyTable(types.ParamKeyTable()), - codespace: codespace, } - return keeper } // Logger returns a module-specific logger. diff --git a/x/slashing/internal/keeper/keeper_test.go b/x/slashing/internal/keeper/keeper_test.go index 54b77848a043..52eb6b59b77a 100644 --- a/x/slashing/internal/keeper/keeper_test.go +++ b/x/slashing/internal/keeper/keeper_test.go @@ -25,8 +25,10 @@ func TestHandleNewValidator(t *testing.T) { ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1) // Validator created - got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) - require.True(t, got.IsOK()) + res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) require.Equal( @@ -65,8 +67,10 @@ func TestHandleAlreadyJailed(t *testing.T) { amt := sdk.TokensFromConsensusPower(power) addr, val := Addrs[0], Pks[0] sh := staking.NewHandler(sk) - got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) - require.True(t, got.IsOK()) + res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) // 1000 first blocks OK @@ -119,8 +123,10 @@ func TestValidatorDippingInAndOut(t *testing.T) { addr, val := Addrs[0], Pks[0] consAddr := sdk.ConsAddress(addr) sh := staking.NewHandler(sk) - got := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) - require.True(t, got.IsOK()) + res, err := sh(ctx, NewTestMsgCreateValidator(addr, val, amt)) + require.NoError(t, err) + require.NotNil(t, res) + staking.EndBlocker(ctx, sk) // 100 first blocks OK @@ -132,8 +138,10 @@ func TestValidatorDippingInAndOut(t *testing.T) { // kick first validator out of validator set newAmt := sdk.TokensFromConsensusPower(101) - got = sh(ctx, NewTestMsgCreateValidator(Addrs[1], Pks[1], newAmt)) - require.True(t, got.IsOK()) + res, err = sh(ctx, NewTestMsgCreateValidator(Addrs[1], Pks[1], newAmt)) + require.NoError(t, err) + require.NotNil(t, res) + validatorUpdates := staking.EndBlocker(ctx, sk) require.Equal(t, 2, len(validatorUpdates)) validator, _ := sk.GetValidator(ctx, addr) @@ -145,8 +153,10 @@ func TestValidatorDippingInAndOut(t *testing.T) { // validator added back in delTokens := sdk.TokensFromConsensusPower(50) - got = sh(ctx, NewTestMsgDelegate(sdk.AccAddress(Addrs[2]), Addrs[0], delTokens)) - require.True(t, got.IsOK()) + res, err = sh(ctx, NewTestMsgDelegate(sdk.AccAddress(Addrs[2]), Addrs[0], delTokens)) + require.NoError(t, err) + require.NotNil(t, res) + validatorUpdates = staking.EndBlocker(ctx, sk) require.Equal(t, 2, len(validatorUpdates)) validator, _ = sk.GetValidator(ctx, addr) diff --git a/x/slashing/internal/keeper/querier.go b/x/slashing/internal/keeper/querier.go index 4633d8ba50e9..11b365e1ee1b 100644 --- a/x/slashing/internal/keeper/querier.go +++ b/x/slashing/internal/keeper/querier.go @@ -1,70 +1,72 @@ package keeper import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" ) // NewQuerier creates a new querier for slashing clients. func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryParameters: return queryParams(ctx, k) + case types.QuerySigningInfo: return querySigningInfo(ctx, req, k) + case types.QuerySigningInfos: return querySigningInfos(ctx, req, k) + default: - return nil, sdk.ErrUnknownRequest("unknown staking query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } } } -func queryParams(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { +func queryParams(ctx sdk.Context, k Keeper) ([]byte, error) { params := k.GetParams(ctx) res, err := codec.MarshalJSONIndent(types.ModuleCdc, params) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func querySigningInfo(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func querySigningInfo(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QuerySigningInfoParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } signingInfo, found := k.GetValidatorSigningInfo(ctx, params.ConsAddress) if !found { - return nil, types.ErrNoSigningInfoFound(types.DefaultCodespace, params.ConsAddress) + return nil, sdkerrors.Wrap(types.ErrNoSigningInfoFound, params.ConsAddress.String()) } res, err := codec.MarshalJSONIndent(types.ModuleCdc, signingInfo) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func querySigningInfos(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func querySigningInfos(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QuerySigningInfosParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } var signingInfos []types.ValidatorSigningInfo @@ -83,7 +85,7 @@ func querySigningInfos(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte res, err := codec.MarshalJSONIndent(types.ModuleCdc, signingInfos) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil diff --git a/x/slashing/internal/keeper/test_common.go b/x/slashing/internal/keeper/test_common.go index 721967ca88c4..eb8870c1d199 100644 --- a/x/slashing/internal/keeper/test_common.go +++ b/x/slashing/internal/keeper/test_common.go @@ -88,10 +88,10 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace) + paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) - bk := bank.NewBaseKeeper(accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs) + bk := bank.NewBaseKeeper(accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, staking.NotBondedPoolName: {supply.Burner, supply.Staking}, @@ -102,7 +102,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, InitTokens.MulRaw(int64(len(Addrs))))) supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) + sk := staking.NewKeeper(cdc, keyStaking, supplyKeeper, paramsKeeper.Subspace(staking.DefaultParamspace)) genesis := staking.DefaultGenesisState() // set module accounts @@ -117,7 +117,7 @@ func CreateTestInput(t *testing.T, defaults types.Params) (sdk.Context, bank.Kee } require.Nil(t, err) paramstore := paramsKeeper.Subspace(types.DefaultParamspace) - keeper := NewKeeper(cdc, keySlashing, &sk, paramstore, types.DefaultCodespace) + keeper := NewKeeper(cdc, keySlashing, &sk, paramstore) keeper.SetParams(ctx, defaults) sk.SetHooks(keeper.Hooks()) diff --git a/x/slashing/internal/keeper/unjail.go b/x/slashing/internal/keeper/unjail.go index 3fdab405eb91..51fda4855382 100644 --- a/x/slashing/internal/keeper/unjail.go +++ b/x/slashing/internal/keeper/unjail.go @@ -7,42 +7,42 @@ import ( // Unjail calls the staking Unjail function to unjail a validator if the // jailed period has concluded -func (k Keeper) Unjail(ctx sdk.Context, validatorAddr sdk.ValAddress) sdk.Error { +func (k Keeper) Unjail(ctx sdk.Context, validatorAddr sdk.ValAddress) error { validator := k.sk.Validator(ctx, validatorAddr) if validator == nil { - return types.ErrNoValidatorForAddress(k.codespace) + return types.ErrNoValidatorForAddress } // cannot be unjailed if no self-delegation exists selfDel := k.sk.Delegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr) if selfDel == nil { - return types.ErrMissingSelfDelegation(k.codespace) + return types.ErrMissingSelfDelegation } if validator.TokensFromShares(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) { - return types.ErrSelfDelegationTooLowToUnjail(k.codespace) + return types.ErrSelfDelegationTooLowToUnjail } // cannot be unjailed if not jailed if !validator.IsJailed() { - return types.ErrValidatorNotJailed(k.codespace) + return types.ErrValidatorNotJailed } consAddr := sdk.ConsAddress(validator.GetConsPubKey().Address()) info, found := k.GetValidatorSigningInfo(ctx, consAddr) if !found { - return types.ErrNoValidatorForAddress(k.codespace) + return types.ErrNoValidatorForAddress } // cannot be unjailed if tombstoned if info.Tombstoned { - return types.ErrValidatorJailed(k.codespace) + return types.ErrValidatorJailed } // cannot be unjailed until out of jail if ctx.BlockHeader().Time.Before(info.JailedUntil) { - return types.ErrValidatorJailed(k.codespace) + return types.ErrValidatorJailed } k.sk.Unjail(ctx, consAddr) diff --git a/x/slashing/internal/types/errors.go b/x/slashing/internal/types/errors.go index b00e6e4f94ab..290ed36cad66 100644 --- a/x/slashing/internal/types/errors.go +++ b/x/slashing/internal/types/errors.go @@ -1,53 +1,16 @@ -//nolint package types import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// DONTCOVER - -// Local code type -type CodeType = sdk.CodeType - -const ( - // Default slashing codespace - DefaultCodespace sdk.CodespaceType = ModuleName - - CodeInvalidValidator CodeType = 101 - CodeValidatorJailed CodeType = 102 - CodeValidatorNotJailed CodeType = 103 - CodeMissingSelfDelegation CodeType = 104 - CodeSelfDelegationTooLow CodeType = 105 - CodeMissingSigningInfo CodeType = 106 +// x/slashing module sentinel errors +var ( + ErrNoValidatorForAddress = sdkerrors.Register(ModuleName, 1, "address is not associated with any known validator") + ErrBadValidatorAddr = sdkerrors.Register(ModuleName, 2, "validator does not exist for that address") + ErrValidatorJailed = sdkerrors.Register(ModuleName, 3, "validator still jailed; cannot be unjailed") + ErrValidatorNotJailed = sdkerrors.Register(ModuleName, 4, "validator not jailed; cannot be unjailed") + ErrMissingSelfDelegation = sdkerrors.Register(ModuleName, 5, "validator has no self-delegation; cannot be unjailed") + ErrSelfDelegationTooLowToUnjail = sdkerrors.Register(ModuleName, 6, "validator's self delegation less than minimum; cannot be unjailed") + ErrNoSigningInfoFound = sdkerrors.Register(ModuleName, 7, "no validator signing info found") ) - -func ErrNoValidatorForAddress(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "that address is not associated with any known validator") -} - -func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address") -} - -func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeValidatorJailed, "validator still jailed, cannot yet be unjailed") -} - -func ErrValidatorNotJailed(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeValidatorNotJailed, "validator not jailed, cannot be unjailed") -} - -func ErrMissingSelfDelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeMissingSelfDelegation, "validator has no self-delegation; cannot be unjailed") -} - -func ErrSelfDelegationTooLowToUnjail(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeValidatorNotJailed, "validator's self delegation less than MinSelfDelegation, cannot be unjailed") -} - -func ErrNoSigningInfoFound(codespace sdk.CodespaceType, consAddr sdk.ConsAddress) sdk.Error { - return sdk.NewError(codespace, CodeMissingSigningInfo, fmt.Sprintf("no signing info found for address: %s", consAddr)) -} diff --git a/x/slashing/internal/types/msg.go b/x/slashing/internal/types/msg.go index 3513d3b6c12b..b2ccdce173ba 100644 --- a/x/slashing/internal/types/msg.go +++ b/x/slashing/internal/types/msg.go @@ -33,9 +33,9 @@ func (msg MsgUnjail) GetSignBytes() []byte { } // ValidateBasic validity check for the AnteHandler -func (msg MsgUnjail) ValidateBasic() sdk.Error { +func (msg MsgUnjail) ValidateBasic() error { if msg.ValidatorAddr.Empty() { - return ErrBadValidatorAddr(DefaultCodespace) + return ErrBadValidatorAddr } return nil } diff --git a/x/slashing/simulation/operations.go b/x/slashing/simulation/operations.go index 3e2a3bc78bad..f5e263b778dc 100644 --- a/x/slashing/simulation/operations.go +++ b/x/slashing/simulation/operations.go @@ -93,7 +93,7 @@ func SimulateMsgUnjail(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper simAccount.PrivKey, ) - res := app.Deliver(tx) + _, res, err := app.Deliver(tx) // result should fail if: // - validator cannot be unjailed due to tombstone @@ -102,7 +102,7 @@ func SimulateMsgUnjail(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper if info.Tombstoned || ctx.BlockHeader().Time.Before(info.JailedUntil) || validator.TokensFromShares(selfDel.GetShares()).TruncateInt().LT(validator.GetMinSelfDelegation()) { - if res.IsOK() { + if res != nil && err == nil { if info.Tombstoned { return simulation.NewOperationMsg(msg, true, ""), nil, errors.New("validator should not have been unjailed if validator tombstoned") } @@ -117,7 +117,7 @@ func SimulateMsgUnjail(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper return simulation.NewOperationMsg(msg, false, ""), nil, nil } - if !res.IsOK() { + if err != nil { return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) } diff --git a/x/staking/alias.go b/x/staking/alias.go index 887b9b7bf690..51c7eecc7087 100644 --- a/x/staking/alias.go +++ b/x/staking/alias.go @@ -1,11 +1,7 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/staking/keeper -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/staking/types -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/staking/exported package staking +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/staking/exported" "github.com/cosmos/cosmos-sdk/x/staking/keeper" @@ -14,16 +10,6 @@ import ( const ( DefaultParamspace = keeper.DefaultParamspace - DefaultCodespace = types.DefaultCodespace - CodeInvalidValidator = types.CodeInvalidValidator - CodeInvalidDelegation = types.CodeInvalidDelegation - CodeInvalidInput = types.CodeInvalidInput - CodeValidatorJailed = types.CodeValidatorJailed - CodeInvalidHistoricalInfo = types.CodeInvalidHistoricalInfo - CodeInvalidAddress = types.CodeInvalidAddress - CodeUnauthorized = types.CodeUnauthorized - CodeInternal = types.CodeInternal - CodeUnknownRequest = types.CodeUnknownRequest ModuleName = types.ModuleName StoreKey = types.StoreKey TStoreKey = types.TStoreKey @@ -92,7 +78,7 @@ var ( MustMarshalHistoricalInfo = types.MustMarshalHistoricalInfo MustUnmarshalHistoricalInfo = types.MustUnmarshalHistoricalInfo UnmarshalHistoricalInfo = types.UnmarshalHistoricalInfo - ErrNilValidatorAddr = types.ErrNilValidatorAddr + ErrEmptyValidatorAddr = types.ErrEmptyValidatorAddr ErrBadValidatorAddr = types.ErrBadValidatorAddr ErrNoValidatorFound = types.ErrNoValidatorFound ErrValidatorOwnerExists = types.ErrValidatorOwnerExists @@ -100,7 +86,6 @@ var ( ErrValidatorPubKeyTypeNotSupported = types.ErrValidatorPubKeyTypeNotSupported ErrValidatorJailed = types.ErrValidatorJailed ErrBadRemoveValidator = types.ErrBadRemoveValidator - ErrDescriptionLength = types.ErrDescriptionLength ErrCommissionNegative = types.ErrCommissionNegative ErrCommissionHuge = types.ErrCommissionHuge ErrCommissionGTMaxRate = types.ErrCommissionGTMaxRate @@ -111,7 +96,7 @@ var ( ErrSelfDelegationBelowMinimum = types.ErrSelfDelegationBelowMinimum ErrMinSelfDelegationInvalid = types.ErrMinSelfDelegationInvalid ErrMinSelfDelegationDecreased = types.ErrMinSelfDelegationDecreased - ErrNilDelegatorAddr = types.ErrNilDelegatorAddr + ErrEmptyDelegatorAddr = types.ErrEmptyDelegatorAddr ErrBadDenom = types.ErrBadDenom ErrBadDelegationAddr = types.ErrBadDelegationAddr ErrBadDelegationAmount = types.ErrBadDelegationAmount @@ -129,14 +114,13 @@ var ( ErrBadRedelegationAddr = types.ErrBadRedelegationAddr ErrNoRedelegation = types.ErrNoRedelegation ErrSelfRedelegation = types.ErrSelfRedelegation - ErrVerySmallRedelegation = types.ErrVerySmallRedelegation + ErrTinyRedelegationAmount = types.ErrTinyRedelegationAmount ErrBadRedelegationDst = types.ErrBadRedelegationDst ErrTransitiveRedelegation = types.ErrTransitiveRedelegation ErrMaxRedelegationEntries = types.ErrMaxRedelegationEntries ErrDelegatorShareExRateInvalid = types.ErrDelegatorShareExRateInvalid ErrBothShareMsgsGiven = types.ErrBothShareMsgsGiven ErrNeitherShareMsgsGiven = types.ErrNeitherShareMsgsGiven - ErrMissingSignature = types.ErrMissingSignature ErrInvalidHistoricalInfo = types.ErrInvalidHistoricalInfo ErrNoHistoricalInfo = types.ErrNoHistoricalInfo NewGenesisState = types.NewGenesisState @@ -233,7 +217,6 @@ type ( RedelegationResponse = types.RedelegationResponse RedelegationEntryResponse = types.RedelegationEntryResponse RedelegationResponses = types.RedelegationResponses - CodeType = types.CodeType GenesisState = types.GenesisState LastValidatorPower = types.LastValidatorPower MultiStakingHooks = types.MultiStakingHooks diff --git a/x/staking/app_test.go b/x/staking/app_test.go index 0c2615d7a3ea..a56923113380 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -35,14 +35,14 @@ func getMockApp(t *testing.T) (*mock.App, Keeper) { blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - bankKeeper := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace, blacklistedAddrs) + bankKeeper := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), blacklistedAddrs) maccPerms := map[string][]string{ auth.FeeCollectorName: nil, types.NotBondedPoolName: {supply.Burner, supply.Staking}, types.BondedPoolName: {supply.Burner, supply.Staking}, } supplyKeeper := supply.NewKeeper(mApp.Cdc, keySupply, mApp.AccountKeeper, bankKeeper, maccPerms) - keeper := NewKeeper(mApp.Cdc, keyStaking, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace), DefaultCodespace) + keeper := NewKeeper(mApp.Cdc, keyStaking, supplyKeeper, mApp.ParamsKeeper.Subspace(DefaultParamspace)) mApp.Router().AddRoute(RouterKey, NewHandler(keeper)) mApp.SetEndBlocker(getEndBlocker(keeper)) diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index 34ed0abce3c7..374d061e070a 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -119,8 +119,9 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command { if minSelfDelegationString != "" { msb, ok := sdk.NewIntFromString(minSelfDelegationString) if !ok { - return fmt.Errorf(types.ErrMinSelfDelegationInvalid(types.DefaultCodespace).Error()) + return types.ErrMinSelfDelegationInvalid } + newMinSelfDelegation = &msb } @@ -378,7 +379,7 @@ func BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr auth.TxBuilder) ( msbStr := viper.GetString(FlagMinSelfDelegation) minSelfDelegation, ok := sdk.NewIntFromString(msbStr) if !ok { - return txBldr, nil, fmt.Errorf(types.ErrMinSelfDelegationInvalid(types.DefaultCodespace).Error()) + return txBldr, nil, types.ErrMinSelfDelegationInvalid } msg := types.NewMsgCreateValidator( diff --git a/x/staking/exported/exported.go b/x/staking/exported/exported.go index eae33c8ee105..7c8a257cd342 100644 --- a/x/staking/exported/exported.go +++ b/x/staking/exported/exported.go @@ -15,24 +15,24 @@ type DelegationI interface { // ValidatorI expected validator functions type ValidatorI interface { - IsJailed() bool // whether the validator is jailed - GetMoniker() string // moniker of the validator - GetStatus() sdk.BondStatus // status of the validator - IsBonded() bool // check if has a bonded status - IsUnbonded() bool // check if has status unbonded - IsUnbonding() bool // check if has status unbonding - GetOperator() sdk.ValAddress // operator address to receive/return validators coins - GetConsPubKey() crypto.PubKey // validation consensus pubkey - GetConsAddr() sdk.ConsAddress // validation consensus address - GetTokens() sdk.Int // validation tokens - GetBondedTokens() sdk.Int // validator bonded tokens - GetConsensusPower() int64 // validation power in tendermint - GetCommission() sdk.Dec // validator commission rate - GetMinSelfDelegation() sdk.Int // validator minimum self delegation - GetDelegatorShares() sdk.Dec // total outstanding delegator shares - TokensFromShares(sdk.Dec) sdk.Dec // token worth of provided delegator shares - TokensFromSharesTruncated(sdk.Dec) sdk.Dec // token worth of provided delegator shares, truncated - TokensFromSharesRoundUp(sdk.Dec) sdk.Dec // token worth of provided delegator shares, rounded up - SharesFromTokens(amt sdk.Int) (sdk.Dec, sdk.Error) // shares worth of delegator's bond - SharesFromTokensTruncated(amt sdk.Int) (sdk.Dec, sdk.Error) // truncated shares worth of delegator's bond + IsJailed() bool // whether the validator is jailed + GetMoniker() string // moniker of the validator + GetStatus() sdk.BondStatus // status of the validator + IsBonded() bool // check if has a bonded status + IsUnbonded() bool // check if has status unbonded + IsUnbonding() bool // check if has status unbonding + GetOperator() sdk.ValAddress // operator address to receive/return validators coins + GetConsPubKey() crypto.PubKey // validation consensus pubkey + GetConsAddr() sdk.ConsAddress // validation consensus address + GetTokens() sdk.Int // validation tokens + GetBondedTokens() sdk.Int // validator bonded tokens + GetConsensusPower() int64 // validation power in tendermint + GetCommission() sdk.Dec // validator commission rate + GetMinSelfDelegation() sdk.Int // validator minimum self delegation + GetDelegatorShares() sdk.Dec // total outstanding delegator shares + TokensFromShares(sdk.Dec) sdk.Dec // token worth of provided delegator shares + TokensFromSharesTruncated(sdk.Dec) sdk.Dec // token worth of provided delegator shares, truncated + TokensFromSharesRoundUp(sdk.Dec) sdk.Dec // token worth of provided delegator shares, rounded up + SharesFromTokens(amt sdk.Int) (sdk.Dec, error) // shares worth of delegator's bond + SharesFromTokensTruncated(amt sdk.Int) (sdk.Dec, error) // truncated shares worth of delegator's bond } diff --git a/x/staking/handler.go b/x/staking/handler.go index 376da255ea1c..da5933930382 100644 --- a/x/staking/handler.go +++ b/x/staking/handler.go @@ -1,19 +1,19 @@ package staking import ( - "fmt" "time" "github.com/tendermint/tendermint/libs/common" tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" ) func NewHandler(k keeper.Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -33,8 +33,7 @@ func NewHandler(k keeper.Keeper) sdk.Handler { return handleMsgUndelegate(ctx, msg, k) default: - errMsg := fmt.Sprintf("unrecognized staking message type: %T", msg) - return sdk.ErrUnknownRequest(errMsg).Result() + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } } } @@ -42,30 +41,31 @@ func NewHandler(k keeper.Keeper) sdk.Handler { // These functions assume everything has been authenticated, // now we just perform action and save -func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k keeper.Keeper) sdk.Result { +func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k keeper.Keeper) (*sdk.Result, error) { // check to see if the pubkey or sender has been registered before if _, found := k.GetValidator(ctx, msg.ValidatorAddress); found { - return ErrValidatorOwnerExists(k.Codespace()).Result() + return nil, ErrValidatorOwnerExists } if _, found := k.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(msg.PubKey)); found { - return ErrValidatorPubKeyExists(k.Codespace()).Result() + return nil, ErrValidatorPubKeyExists } if msg.Value.Denom != k.BondDenom(ctx) { - return ErrBadDenom(k.Codespace()).Result() + return nil, ErrBadDenom } if _, err := msg.Description.EnsureLength(); err != nil { - return err.Result() + return nil, err } if ctx.ConsensusParams() != nil { tmPubKey := tmtypes.TM2PB.PubKey(msg.PubKey) if !common.StringInSlice(tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes) { - return ErrValidatorPubKeyTypeNotSupported(k.Codespace(), - tmPubKey.Type, - ctx.ConsensusParams().Validator.PubKeyTypes).Result() + return nil, sdkerrors.Wrapf( + ErrValidatorPubKeyTypeNotSupported, + "got: %s, valid: %s", tmPubKey.Type, ctx.ConsensusParams().Validator.PubKeyTypes, + ) } } @@ -76,7 +76,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k ) validator, err := validator.SetInitialCommission(commission) if err != nil { - return err.Result() + return nil, err } validator.MinSelfDelegation = msg.MinSelfDelegation @@ -93,7 +93,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k // NOTE source will always be from a wallet which are unbonded _, err = k.Delegate(ctx, msg.DelegatorAddress, msg.Value.Amount, sdk.Unbonded, validator, true) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvents(sdk.Events{ @@ -109,20 +109,20 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k ), }) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keeper.Keeper) sdk.Result { +func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keeper.Keeper) (*sdk.Result, error) { // validator must already be registered validator, found := k.GetValidator(ctx, msg.ValidatorAddress) if !found { - return ErrNoValidatorFound(k.Codespace()).Result() + return nil, ErrNoValidatorFound } // replace all editable fields (clients should autofill existing values) description, err := validator.Description.UpdateDescription(msg.Description) if err != nil { - return err.Result() + return nil, err } validator.Description = description @@ -130,7 +130,7 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe if msg.CommissionRate != nil { commission, err := k.UpdateValidatorCommission(ctx, validator, *msg.CommissionRate) if err != nil { - return err.Result() + return nil, err } // call the before-modification hook since we're about to update the commission @@ -141,11 +141,12 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe if msg.MinSelfDelegation != nil { if !msg.MinSelfDelegation.GT(validator.MinSelfDelegation) { - return ErrMinSelfDelegationDecreased(k.Codespace()).Result() + return nil, ErrMinSelfDelegationDecreased } if msg.MinSelfDelegation.GT(validator.Tokens) { - return ErrSelfDelegationBelowMinimum(k.Codespace()).Result() + return nil, ErrSelfDelegationBelowMinimum } + validator.MinSelfDelegation = (*msg.MinSelfDelegation) } @@ -164,23 +165,23 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe ), }) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) sdk.Result { +func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) (*sdk.Result, error) { validator, found := k.GetValidator(ctx, msg.ValidatorAddress) if !found { - return ErrNoValidatorFound(k.Codespace()).Result() + return nil, ErrNoValidatorFound } if msg.Amount.Denom != k.BondDenom(ctx) { - return ErrBadDenom(k.Codespace()).Result() + return nil, ErrBadDenom } // NOTE: source funds are always unbonded _, err := k.Delegate(ctx, msg.DelegatorAddress, msg.Amount.Amount, sdk.Unbonded, validator, true) if err != nil { - return err.Result() + return nil, err } ctx.EventManager().EmitEvents(sdk.Events{ @@ -196,24 +197,24 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) ), }) - return sdk.Result{Events: ctx.EventManager().Events()} + return &sdk.Result{Events: ctx.EventManager().Events()}, nil } -func handleMsgUndelegate(ctx sdk.Context, msg types.MsgUndelegate, k keeper.Keeper) sdk.Result { +func handleMsgUndelegate(ctx sdk.Context, msg types.MsgUndelegate, k keeper.Keeper) (*sdk.Result, error) { shares, err := k.ValidateUnbondAmount( ctx, msg.DelegatorAddress, msg.ValidatorAddress, msg.Amount.Amount, ) if err != nil { - return err.Result() + return nil, err } if msg.Amount.Denom != k.BondDenom(ctx) { - return ErrBadDenom(k.Codespace()).Result() + return nil, ErrBadDenom } completionTime, err := k.Undelegate(ctx, msg.DelegatorAddress, msg.ValidatorAddress, shares) if err != nil { - return err.Result() + return nil, err } completionTimeBz := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(completionTime) @@ -231,26 +232,26 @@ func handleMsgUndelegate(ctx sdk.Context, msg types.MsgUndelegate, k keeper.Keep ), }) - return sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().Events()} + return &sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().Events()}, nil } -func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k keeper.Keeper) sdk.Result { +func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k keeper.Keeper) (*sdk.Result, error) { shares, err := k.ValidateUnbondAmount( ctx, msg.DelegatorAddress, msg.ValidatorSrcAddress, msg.Amount.Amount, ) if err != nil { - return err.Result() + return nil, err } if msg.Amount.Denom != k.BondDenom(ctx) { - return ErrBadDenom(k.Codespace()).Result() + return nil, ErrBadDenom } completionTime, err := k.BeginRedelegation( ctx, msg.DelegatorAddress, msg.ValidatorSrcAddress, msg.ValidatorDstAddress, shares, ) if err != nil { - return err.Result() + return nil, err } completionTimeBz := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(completionTime) @@ -269,5 +270,5 @@ func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k k ), }) - return sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().Events()} + return &sdk.Result{Data: completionTimeBz, Events: ctx.EventManager().Events()}, nil } diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index 0e999ba9b43b..92147eabb097 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -26,8 +26,9 @@ func TestValidatorByPowerIndex(t *testing.T) { // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // must end-block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -47,8 +48,9 @@ func TestValidatorByPowerIndex(t *testing.T) { // create a second validator keep it bonded msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], initBond) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // must end-block updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -84,11 +86,12 @@ func TestValidatorByPowerIndex(t *testing.T) { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, totalBond) msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -108,8 +111,9 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator1 := NewTestMsgCreateValidator(addr1, pk1, valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator1, keeper) - require.True(t, got.IsOK(), "%v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator1, keeper) + require.NoError(t, err) + require.NotNil(t, res) keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -124,18 +128,21 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) { // two validators can't have the same operator address msgCreateValidator2 := NewTestMsgCreateValidator(addr1, pk2, valTokens) - got = handleMsgCreateValidator(ctx, msgCreateValidator2, keeper) - require.False(t, got.IsOK(), "%v", got) + res, err = handleMsgCreateValidator(ctx, msgCreateValidator2, keeper) + require.Error(t, err) + require.Nil(t, res) // two validators can't have the same pubkey msgCreateValidator3 := NewTestMsgCreateValidator(addr2, pk1, valTokens) - got = handleMsgCreateValidator(ctx, msgCreateValidator3, keeper) - require.False(t, got.IsOK(), "%v", got) + res, err = handleMsgCreateValidator(ctx, msgCreateValidator3, keeper) + require.Error(t, err) + require.Nil(t, res) // must have different pubkey and operator msgCreateValidator4 := NewTestMsgCreateValidator(addr2, pk2, valTokens) - got = handleMsgCreateValidator(ctx, msgCreateValidator4, keeper) - require.True(t, got.IsOK(), "%v", got) + res, err = handleMsgCreateValidator(ctx, msgCreateValidator4, keeper) + require.NoError(t, err) + require.NotNil(t, res) // must end-block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -160,15 +167,17 @@ func TestInvalidPubKeyTypeMsgCreateValidator(t *testing.T) { // invalid pukKey type should not be allowed msgCreateValidator := NewTestMsgCreateValidator(addr, invalidPk, sdk.NewInt(10)) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.False(t, got.IsOK(), "%v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.Error(t, err) + require.Nil(t, res) ctx = ctx.WithConsensusParams(&abci.ConsensusParams{ Validator: &abci.ValidatorParams{PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeSecp256k1}}, }) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "%v", got) + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) } func TestLegacyValidatorDelegations(t *testing.T) { @@ -181,8 +190,9 @@ func TestLegacyValidatorDelegations(t *testing.T) { // create validator msgCreateVal := NewTestMsgCreateValidator(valAddr, valConsPubKey, bondAmount) - got := handleMsgCreateValidator(ctx, msgCreateVal, keeper) - require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateVal, keeper) + require.NoError(t, err) + require.NotNil(t, res) // must end-block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -197,8 +207,9 @@ func TestLegacyValidatorDelegations(t *testing.T) { // delegate tokens to the validator msgDelegate := NewTestMsgDelegate(delAddr, valAddr, bondAmount) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // verify validator bonded shares validator, found = keeper.GetValidator(ctx, valAddr) @@ -210,11 +221,12 @@ func TestLegacyValidatorDelegations(t *testing.T) { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, bondAmount) msgUndelegate := NewMsgUndelegate(sdk.AccAddress(valAddr), valAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got %v", got) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -232,8 +244,9 @@ func TestLegacyValidatorDelegations(t *testing.T) { // verify the validator can still self-delegate msgSelfDelegate := NewTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount) - got = handleMsgDelegate(ctx, msgSelfDelegate, keeper) - require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgSelfDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // verify validator bonded shares validator, found = keeper.GetValidator(ctx, valAddr) @@ -246,8 +259,9 @@ func TestLegacyValidatorDelegations(t *testing.T) { // verify the validator can now accept delegations msgDelegate = NewTestMsgDelegate(delAddr, valAddr, bondAmount) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // verify validator bonded shares validator, found = keeper.GetValidator(ctx, valAddr) @@ -273,8 +287,9 @@ func TestIncrementsMsgDelegate(t *testing.T) { // first create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], bondAmount) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // apply TM updates keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -301,8 +316,9 @@ func TestIncrementsMsgDelegate(t *testing.T) { for i := int64(0); i < 5; i++ { ctx = ctx.WithBlockHeight(i) - got := handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) + res, err := handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) //Check that the accounts and the bond account have the appropriate values validator, found := keeper.GetValidator(ctx, validatorAddr) @@ -340,8 +356,9 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // must end-block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -357,8 +374,9 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) { newMinSelfDelegation := sdk.OneInt() msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) - got = handleMsgEditValidator(ctx, msgEditValidator, keeper) - require.False(t, got.IsOK(), "should not be able to decrease minSelfDelegation") + res, err = handleMsgEditValidator(ctx, msgEditValidator, keeper) + require.Error(t, err) + require.Nil(t, res) } func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { @@ -371,8 +389,9 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { // create validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) msgCreateValidator.MinSelfDelegation = sdk.NewInt(2) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // must end-block updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -388,8 +407,9 @@ func TestEditValidatorIncreaseMinSelfDelegationBeyondCurrentBond(t *testing.T) { newMinSelfDelegation := initBond.Add(sdk.OneInt()) msgEditValidator := NewMsgEditValidator(validatorAddr, Description{}, nil, &newMinSelfDelegation) - got = handleMsgEditValidator(ctx, msgEditValidator, keeper) - require.False(t, got.IsOK(), "should not be able to increase minSelfDelegation above current self delegation") + res, err = handleMsgEditValidator(ctx, msgEditValidator, keeper) + require.Error(t, err) + require.Nil(t, res) } func TestIncrementsMsgUnbond(t *testing.T) { @@ -404,15 +424,17 @@ func TestIncrementsMsgUnbond(t *testing.T) { validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1] msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // initial balance amt1 := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(denom) msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, initBond) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // balance should have been subtracted after delegation amt2 := accMapper.GetAccount(ctx, delegatorAddr).GetCoins().AmountOf(denom) @@ -431,12 +453,15 @@ func TestIncrementsMsgUnbond(t *testing.T) { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) numUnbonds := int64(5) + for i := int64(0); i < numUnbonds; i++ { + res, err := handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) - got := handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) + ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -474,11 +499,12 @@ func TestIncrementsMsgUnbond(t *testing.T) { initBond, } - for i, c := range errorCases { + for _, c := range errorCases { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, c) msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.False(t, got.IsOK(), "expected unbond msg to fail, index: %v", i) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.Error(t, err) + require.Nil(t, res) } leftBonded := initBond.Sub(unbondAmt.Amount.Mul(sdk.NewInt(numUnbonds))) @@ -486,9 +512,9 @@ func TestIncrementsMsgUnbond(t *testing.T) { // should be able to unbond remaining unbondAmt = sdk.NewCoin(sdk.DefaultBondDenom, leftBonded) msgUndelegate = NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), - "got: %v\nmsgUnbond: %v\nshares: %s\nleftBonded: %s\n", got.Log, msgUndelegate, unbondAmt, leftBonded) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) + require.NotNil(t, res, "msgUnbond: %v\nshares: %s\nleftBonded: %s\n", msgUndelegate, unbondAmt, leftBonded) } func TestMultipleMsgCreateValidator(t *testing.T) { @@ -516,8 +542,9 @@ func TestMultipleMsgCreateValidator(t *testing.T) { valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidatorOnBehalfOf := NewTestMsgCreateValidator(validatorAddr, keep.PKs[i], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidatorOnBehalfOf, keeper) + require.NoError(t, err) + require.NotNil(t, res) // verify that the account is bonded validators := keeper.GetValidators(ctx, 100) @@ -541,11 +568,12 @@ func TestMultipleMsgCreateValidator(t *testing.T) { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) msgUndelegate := NewMsgUndelegate(delegatorAddrs[i], validatorAddr, unbondAmt) // remove delegation - got := handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) + res, err := handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) // adds validator into unbonding queue EndBlocker(ctx, keeper) @@ -572,14 +600,16 @@ func TestMultipleMsgDelegate(t *testing.T) { // first make a validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // delegate multiple parties - for i, delegatorAddr := range delegatorAddrs { + for _, delegatorAddr := range delegatorAddrs { msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - got := handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) + res, err := handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // check that the account is bonded bond, found := keeper.GetDelegation(ctx, delegatorAddr, validatorAddr) @@ -588,15 +618,16 @@ func TestMultipleMsgDelegate(t *testing.T) { } // unbond them all - for i, delegatorAddr := range delegatorAddrs { + for _, delegatorAddr := range delegatorAddrs { unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) msgUndelegate := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - got := handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) + res, err := handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -613,22 +644,25 @@ func TestJailValidator(t *testing.T) { // create the validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // bond a delegator msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // unbond the validators bond portion unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) - require.True(t, got.IsOK(), "expected no error: %v", got) + res, err = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -640,16 +674,18 @@ func TestJailValidator(t *testing.T) { // test that the delegator can still withdraw their bonds msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper) - require.True(t, got.IsOK(), "expected no error") - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + res, err = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper) + require.NoError(t, err) + require.NotNil(t, res) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) // verify that the pubkey can now be reused - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected ok, got %v", got) + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) } func TestValidatorQueue(t *testing.T) { @@ -664,25 +700,28 @@ func TestValidatorQueue(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // bond a delegator delTokens := sdk.TokensFromConsensusPower(10) msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, delTokens) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) EndBlocker(ctx, keeper) // unbond the all self-delegation to put validator in unbonding state unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, delTokens) msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) - require.True(t, got.IsOK(), "expected no error: %v", got) + res, err = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -722,16 +761,18 @@ func TestUnbondingPeriod(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) EndBlocker(ctx, keeper) // begin unbonding unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(10)) msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error") + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) origHeader := ctx.BlockHeader() @@ -762,29 +803,33 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) { // create the validator msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // bond a delegator msgDelegate := NewTestMsgDelegate(delegatorAddr, validatorAddr, sdk.NewInt(10)) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected ok, got %v", got) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // unbond the validators bond portion unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) msgUndelegateValidator := NewMsgUndelegate(sdk.AccAddress(validatorAddr), validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) - require.True(t, got.IsOK(), "expected no error") + res, err = handleMsgUndelegate(ctx, msgUndelegateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // change the ctx to Block Time one second before the validator would have unbonded var finishTime time.Time - types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime.Add(time.Second * -1)) // unbond the delegator from the validator msgUndelegateDelegator := NewMsgUndelegate(delegatorAddr, validatorAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper) - require.True(t, got.IsOK(), "expected no error") + res, err = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper) + require.NoError(t, err) + require.NotNil(t, res) ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(keeper.UnbondingTime(ctx))) @@ -813,24 +858,27 @@ func TestRedelegationPeriod(t *testing.T) { // initial balance amt1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // balance should have been subtracted after creation amt2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom) require.Equal(t, amt1.Sub(sdk.NewInt(10)).Int64(), amt2.Int64(), "expected coins to be subtracted") msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], sdk.NewInt(10)) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) bal1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins() // begin redelegate redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error, %v", got) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // origin account should not lose tokens as with a regular delegation bal2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins() @@ -867,27 +915,32 @@ func TestTransitiveRedelegation(t *testing.T) { // create the validators msgCreateValidator := NewTestMsgCreateValidator(validatorAddr, keep.PKs[0], sdk.NewInt(10)) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], sdk.NewInt(10)) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], sdk.NewInt(10)) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // begin redelegate redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)) msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, redAmt) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error, %v", got) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // cannot redelegation to next validator while first delegation exists msgBeginRedelegate = NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, redAmt) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.Error(t, err) + require.Nil(t, res) params := keeper.GetParams(ctx) ctx = ctx.WithBlockTime(blockTime.Add(params.UnbondingTime)) @@ -896,8 +949,9 @@ func TestTransitiveRedelegation(t *testing.T) { EndBlocker(ctx, keeper) // now should be able to redelegate from the second validator to the third - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error", got.Log) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) } func TestMultipleRedelegationAtSameTime(t *testing.T) { @@ -913,12 +967,14 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { // create the validators valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(valAddr2, keep.PKs[1], valTokens) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond them EndBlocker(ctx, keeper) @@ -927,8 +983,9 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error, %v", got) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // there should only be one entry in the redelegation object rd, found := keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) @@ -936,8 +993,9 @@ func TestMultipleRedelegationAtSameTime(t *testing.T) { require.Len(t, rd.Entries, 1) // start a second redelegation at this same time as the first - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error, msg: %v", msgBeginRedelegate) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // now there should be two entries rd, found = keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) @@ -965,12 +1023,14 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { // create the validators valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(valAddr2, keep.PKs[1], valTokens) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond them EndBlocker(ctx, keeper) @@ -979,13 +1039,15 @@ func TestMultipleRedelegationAtUniqueTimes(t *testing.T) { selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) redAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) msgBeginRedelegate := NewMsgBeginRedelegate(selfDelAddr, valAddr, valAddr2, redAmt) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error, %v", got) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // move forward in time and start a second redelegation ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error, msg: %v", msgBeginRedelegate) + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // now there should be two entries rd, found := keeper.GetRedelegation(ctx, selfDelAddr, valAddr, valAddr2) @@ -1018,8 +1080,9 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond EndBlocker(ctx, keeper) @@ -1028,8 +1091,9 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error, %v", got) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // there should only be one entry in the ubd object ubd, found := keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) @@ -1037,8 +1101,9 @@ func TestMultipleUnbondingDelegationAtSameTime(t *testing.T) { require.Len(t, ubd.Entries, 1) // start a second ubd at this same time as the first - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error, msg: %v", msgUndelegate) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // now there should be two entries ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) @@ -1065,8 +1130,9 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { // create the validator valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valAddr, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // end block to bond EndBlocker(ctx, keeper) @@ -1075,8 +1141,9 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { selfDelAddr := sdk.AccAddress(valAddr) // (the validator is it's own delegator) unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens.QuoRaw(2)) msgUndelegate := NewMsgUndelegate(selfDelAddr, valAddr, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error, %v", got) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // there should only be one entry in the ubd object ubd, found := keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) @@ -1085,8 +1152,9 @@ func TestMultipleUnbondingDelegationAtUniqueTimes(t *testing.T) { // move forwaubd in time and start a second redelegation ctx = ctx.WithBlockTime(ctx.BlockHeader().Time.Add(5 * time.Second)) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error, msg: %v", msgUndelegate) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // now there should be two entries ubd, found = keeper.GetUnbondingDelegation(ctx, selfDelAddr, valAddr) @@ -1121,24 +1189,30 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { // add three validators valTokens1 := sdk.TokensFromConsensusPower(50) msgCreateValidator := NewTestMsgCreateValidator(validatorAddr1, keep.PKs[0], valTokens1) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) + // apply TM updates keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 1, len(keeper.GetLastValidators(ctx))) valTokens2 := sdk.TokensFromConsensusPower(30) msgCreateValidator = NewTestMsgCreateValidator(validatorAddr2, keep.PKs[1], valTokens2) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) + // apply TM updates keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(keeper.GetLastValidators(ctx))) valTokens3 := sdk.TokensFromConsensusPower(10) msgCreateValidator = NewTestMsgCreateValidator(validatorAddr3, keep.PKs[2], valTokens3) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) + // apply TM updates keeper.ApplyAndReturnValidatorSetUpdates(ctx) require.Equal(t, 2, len(keeper.GetLastValidators(ctx))) @@ -1146,8 +1220,9 @@ func TestUnbondingWhenExcessValidators(t *testing.T) { // unbond the validator-2 unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, valTokens2) msgUndelegate := NewMsgUndelegate(sdk.AccAddress(validatorAddr2), validatorAddr2, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgUndelegate") + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // apply TM updates keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -1169,17 +1244,20 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { valTokens := sdk.TokensFromConsensusPower(10) msgCreateValidator := NewTestMsgCreateValidator(valA, keep.PKs[0], valTokens) - got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err := handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgCreateValidator = NewTestMsgCreateValidator(valB, keep.PKs[1], valTokens) - got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator") + res, err = handleMsgCreateValidator(ctx, msgCreateValidator, keeper) + require.NoError(t, err) + require.NotNil(t, res) // delegate 10 stake msgDelegate := NewTestMsgDelegate(del, valA, valTokens) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgDelegate") + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // apply Tendermint updates updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) @@ -1191,14 +1269,16 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) { // begin unbonding 4 stake unbondAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(4)) msgUndelegate := NewMsgUndelegate(del, valA, unbondAmt) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgUndelegate") + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // begin redelegate 6 stake redAmt := sdk.NewCoin(sdk.DefaultBondDenom, sdk.TokensFromConsensusPower(6)) msgBeginRedelegate := NewMsgBeginRedelegate(del, valA, valB, redAmt) - got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) - require.True(t, got.IsOK(), "expected no error on runMsgBeginRedelegate") + res, err = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) // destination delegation should have 6 shares delegation, found := keeper.GetDelegation(ctx, del, valB) @@ -1266,9 +1346,10 @@ func TestInvalidMsg(t *testing.T) { k := keep.Keeper{} h := NewHandler(k) - res := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) - require.False(t, res.IsOK()) - require.True(t, strings.Contains(res.Log, "unrecognized staking message type")) + res, err := h(sdk.NewContext(nil, abci.Header{}, false, nil), sdk.NewTestMsg()) + require.Error(t, err) + require.Nil(t, res) + require.True(t, strings.Contains(err.Error(), "unrecognized staking message type")) } func TestInvalidCoinDenom(t *testing.T) { @@ -1283,33 +1364,47 @@ func TestInvalidCoinDenom(t *testing.T) { commission := types.NewCommissionRates(sdk.OneDec(), sdk.OneDec(), sdk.ZeroDec()) msgCreate := types.NewMsgCreateValidator(valA, keep.PKs[0], invalidCoin, Description{}, commission, sdk.OneInt()) - got := handleMsgCreateValidator(ctx, msgCreate, keeper) - require.False(t, got.IsOK()) + res, err := handleMsgCreateValidator(ctx, msgCreate, keeper) + require.Error(t, err) + require.Nil(t, res) + msgCreate = types.NewMsgCreateValidator(valA, keep.PKs[0], validCoin, Description{}, commission, sdk.OneInt()) - got = handleMsgCreateValidator(ctx, msgCreate, keeper) - require.True(t, got.IsOK()) + res, err = handleMsgCreateValidator(ctx, msgCreate, keeper) + require.NoError(t, err) + require.NotNil(t, res) + msgCreate = types.NewMsgCreateValidator(valB, keep.PKs[1], validCoin, Description{}, commission, sdk.OneInt()) - got = handleMsgCreateValidator(ctx, msgCreate, keeper) - require.True(t, got.IsOK()) + res, err = handleMsgCreateValidator(ctx, msgCreate, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgDelegate := types.NewMsgDelegate(delAddr, valA, invalidCoin) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.False(t, got.IsOK()) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.Error(t, err) + require.Nil(t, res) + msgDelegate = types.NewMsgDelegate(delAddr, valA, validCoin) - got = handleMsgDelegate(ctx, msgDelegate, keeper) - require.True(t, got.IsOK()) + res, err = handleMsgDelegate(ctx, msgDelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgUndelegate := types.NewMsgUndelegate(delAddr, valA, invalidCoin) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.False(t, got.IsOK()) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.Error(t, err) + require.Nil(t, res) + msgUndelegate = types.NewMsgUndelegate(delAddr, valA, oneCoin) - got = handleMsgUndelegate(ctx, msgUndelegate, keeper) - require.True(t, got.IsOK()) + res, err = handleMsgUndelegate(ctx, msgUndelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) msgRedelegate := types.NewMsgBeginRedelegate(delAddr, valA, valB, invalidCoin) - got = handleMsgBeginRedelegate(ctx, msgRedelegate, keeper) - require.False(t, got.IsOK()) + res, err = handleMsgBeginRedelegate(ctx, msgRedelegate, keeper) + require.Error(t, err) + require.Nil(t, res) + msgRedelegate = types.NewMsgBeginRedelegate(delAddr, valA, valB, oneCoin) - got = handleMsgBeginRedelegate(ctx, msgRedelegate, keeper) - require.True(t, got.IsOK()) + res, err = handleMsgBeginRedelegate(ctx, msgRedelegate, keeper) + require.NoError(t, err) + require.NotNil(t, res) } diff --git a/x/staking/keeper/delegation.go b/x/staking/keeper/delegation.go index 3aa244b3b3c9..faf8ba415ef7 100644 --- a/x/staking/keeper/delegation.go +++ b/x/staking/keeper/delegation.go @@ -6,6 +6,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -456,14 +457,16 @@ func (k Keeper) DequeueAllMatureRedelegationQueue(ctx sdk.Context, currTime time // Perform a delegation, set/update everything necessary within the store. // tokenSrc indicates the bond status of the incoming funds. -func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Int, tokenSrc sdk.BondStatus, - validator types.Validator, subtractAccount bool) (newShares sdk.Dec, err sdk.Error) { +func (k Keeper) Delegate( + ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Int, tokenSrc sdk.BondStatus, + validator types.Validator, subtractAccount bool, +) (newShares sdk.Dec, err error) { // In some situations, the exchange rate becomes invalid, e.g. if // Validator loses all tokens due to slashing. In this case, // make all future delegations invalid. if validator.InvalidExRate() { - return sdk.ZeroDec(), types.ErrDelegatorShareExRateInvalid(k.Codespace()) + return sdk.ZeroDec(), types.ErrDelegatorShareExRateInvalid } // Get or create the delegation object @@ -534,13 +537,14 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.In } // unbond a particular delegation and perform associated store operations -func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, - shares sdk.Dec) (amount sdk.Int, err sdk.Error) { +func (k Keeper) unbond( + ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, shares sdk.Dec, +) (amount sdk.Int, err error) { // check if a delegation object exists in the store delegation, found := k.GetDelegation(ctx, delAddr, valAddr) if !found { - return amount, types.ErrNoDelegatorForAddress(k.Codespace()) + return amount, types.ErrNoDelegatorForAddress } // call the before-delegation-modified hook @@ -548,13 +552,13 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA // ensure that we have enough shares to remove if delegation.Shares.LT(shares) { - return amount, types.ErrNotEnoughDelegationShares(k.Codespace(), delegation.Shares.String()) + return amount, sdkerrors.Wrap(types.ErrNotEnoughDelegationShares, delegation.Shares.String()) } // get validator validator, found := k.GetValidator(ctx, valAddr) if !found { - return amount, types.ErrNoValidatorFound(k.Codespace()) + return amount, types.ErrNoValidatorFound } // subtract shares from delegation @@ -628,15 +632,15 @@ func (k Keeper) getBeginInfo( // processed during the staking EndBlocker. func (k Keeper) Undelegate( ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec, -) (time.Time, sdk.Error) { +) (time.Time, error) { validator, found := k.GetValidator(ctx, valAddr) if !found { - return time.Time{}, types.ErrNoDelegatorForAddress(k.Codespace()) + return time.Time{}, types.ErrNoDelegatorForAddress } if k.HasMaxUnbondingDelegationEntries(ctx, delAddr, valAddr) { - return time.Time{}, types.ErrMaxUnbondingDelegationEntries(k.Codespace()) + return time.Time{}, types.ErrMaxUnbondingDelegationEntries } returnAmount, err := k.unbond(ctx, delAddr, valAddr, sharesAmount) @@ -658,12 +662,10 @@ func (k Keeper) Undelegate( // CompleteUnbonding completes the unbonding of all mature entries in the // retrieved unbonding delegation object. -func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, - valAddr sdk.ValAddress) sdk.Error { - +func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { ubd, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr) if !found { - return types.ErrNoUnbondingDelegation(k.Codespace()) + return types.ErrNoUnbondingDelegation } ctxTime := ctx.BlockHeader().Time @@ -697,31 +699,31 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, } // begin unbonding / redelegation; create a redelegation record -func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, - valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec) ( - completionTime time.Time, errSdk sdk.Error) { +func (k Keeper) BeginRedelegation( + ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec, +) (completionTime time.Time, err error) { if bytes.Equal(valSrcAddr, valDstAddr) { - return time.Time{}, types.ErrSelfRedelegation(k.Codespace()) + return time.Time{}, types.ErrSelfRedelegation } dstValidator, found := k.GetValidator(ctx, valDstAddr) if !found { - return time.Time{}, types.ErrBadRedelegationDst(k.Codespace()) + return time.Time{}, types.ErrBadRedelegationDst } srcValidator, found := k.GetValidator(ctx, valSrcAddr) if !found { - return time.Time{}, types.ErrBadRedelegationDst(k.Codespace()) + return time.Time{}, types.ErrBadRedelegationDst } // check if this is a transitive redelegation if k.HasReceivingRedelegation(ctx, delAddr, valSrcAddr) { - return time.Time{}, types.ErrTransitiveRedelegation(k.Codespace()) + return time.Time{}, types.ErrTransitiveRedelegation } if k.HasMaxRedelegationEntries(ctx, delAddr, valSrcAddr, valDstAddr) { - return time.Time{}, types.ErrMaxRedelegationEntries(k.Codespace()) + return time.Time{}, types.ErrMaxRedelegationEntries } returnAmount, err := k.unbond(ctx, delAddr, valSrcAddr, sharesAmount) @@ -730,7 +732,7 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, } if returnAmount.IsZero() { - return time.Time{}, types.ErrVerySmallRedelegation(k.Codespace()) + return time.Time{}, types.ErrTinyRedelegationAmount } sharesCreated, err := k.Delegate(ctx, delAddr, returnAmount, srcValidator.GetStatus(), dstValidator, false) @@ -745,20 +747,23 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, return completionTime, nil } - red := k.SetRedelegationEntry(ctx, delAddr, valSrcAddr, valDstAddr, - height, completionTime, returnAmount, sharesAmount, sharesCreated) + red := k.SetRedelegationEntry( + ctx, delAddr, valSrcAddr, valDstAddr, + height, completionTime, returnAmount, sharesAmount, sharesCreated, + ) k.InsertRedelegationQueue(ctx, red, completionTime) return completionTime, nil } // CompleteRedelegation completes the unbonding of all mature entries in the // retrieved unbonding delegation object. -func (k Keeper) CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, - valSrcAddr, valDstAddr sdk.ValAddress) sdk.Error { +func (k Keeper) CompleteRedelegation( + ctx sdk.Context, delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress, +) error { red, found := k.GetRedelegation(ctx, delAddr, valSrcAddr, valDstAddr) if !found { - return types.ErrNoRedelegation(k.Codespace()) + return types.ErrNoRedelegation } ctxTime := ctx.BlockHeader().Time @@ -787,16 +792,16 @@ func (k Keeper) CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress, // amount of respective shares is returned, otherwise an error is returned. func (k Keeper) ValidateUnbondAmount( ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt sdk.Int, -) (shares sdk.Dec, err sdk.Error) { +) (shares sdk.Dec, err error) { validator, found := k.GetValidator(ctx, valAddr) if !found { - return shares, types.ErrNoValidatorFound(k.Codespace()) + return shares, types.ErrNoValidatorFound } del, found := k.GetDelegation(ctx, delAddr, valAddr) if !found { - return shares, types.ErrNoDelegation(k.Codespace()) + return shares, types.ErrNoDelegation } shares, err = validator.SharesFromTokens(amt) @@ -811,7 +816,7 @@ func (k Keeper) ValidateUnbondAmount( delShares := del.GetShares() if sharesTruncated.GT(delShares) { - return shares, types.ErrBadSharesAmount(k.Codespace()) + return shares, types.ErrBadSharesAmount } // Cap the shares at the delegation's shares. Shares being greater could occur diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index a63f5cf1ed68..fd51603115b7 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -29,14 +29,12 @@ type Keeper struct { paramstore params.Subspace validatorCache map[string]cachedValidator validatorCacheList *list.List - - // codespace - codespace sdk.CodespaceType } // NewKeeper creates a new staking Keeper instance -func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, supplyKeeper types.SupplyKeeper, - paramstore params.Subspace, codespace sdk.CodespaceType) Keeper { +func NewKeeper( + cdc *codec.Codec, key sdk.StoreKey, supplyKeeper types.SupplyKeeper, paramstore params.Subspace, +) Keeper { // ensure bonded and not bonded module accounts are set if addr := supplyKeeper.GetModuleAddress(types.BondedPoolName); addr == nil { @@ -55,7 +53,6 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, supplyKeeper types.SupplyKeep hooks: nil, validatorCache: make(map[string]cachedValidator, aminoCacheSize), validatorCacheList: list.New(), - codespace: codespace, } } @@ -73,11 +70,6 @@ func (k *Keeper) SetHooks(sh types.StakingHooks) *Keeper { return k } -// return the codespace -func (k Keeper) Codespace() sdk.CodespaceType { - return k.codespace -} - // Load the last total validator power. func (k Keeper) GetLastTotalPower(ctx sdk.Context) (power sdk.Int) { store := ctx.KVStore(k.storeKey) diff --git a/x/staking/keeper/pool.go b/x/staking/keeper/pool.go index 4ceb02446d93..004013ed8fe4 100644 --- a/x/staking/keeper/pool.go +++ b/x/staking/keeper/pool.go @@ -35,7 +35,7 @@ func (k Keeper) notBondedTokensToBonded(ctx sdk.Context, tokens sdk.Int) { } // burnBondedTokens removes coins from the bonded pool module account -func (k Keeper) burnBondedTokens(ctx sdk.Context, amt sdk.Int) sdk.Error { +func (k Keeper) burnBondedTokens(ctx sdk.Context, amt sdk.Int) error { if !amt.IsPositive() { // skip as no coins need to be burned return nil @@ -45,7 +45,7 @@ func (k Keeper) burnBondedTokens(ctx sdk.Context, amt sdk.Int) sdk.Error { } // burnNotBondedTokens removes coins from the not bonded pool module account -func (k Keeper) burnNotBondedTokens(ctx sdk.Context, amt sdk.Int) sdk.Error { +func (k Keeper) burnNotBondedTokens(ctx sdk.Context, amt sdk.Int) error { if !amt.IsPositive() { // skip as no coins need to be burned return nil diff --git a/x/staking/keeper/querier.go b/x/staking/keeper/querier.go index 15bc59ee5ff6..bc8a5b5b7fc0 100644 --- a/x/staking/keeper/querier.go +++ b/x/staking/keeper/querier.go @@ -1,7 +1,7 @@ package keeper import ( - "fmt" + "errors" "strings" abci "github.com/tendermint/tendermint/abci/types" @@ -9,53 +9,68 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/staking/types" ) // creates a querier for staking REST endpoints func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryValidators: return queryValidators(ctx, req, k) + case types.QueryValidator: return queryValidator(ctx, req, k) + case types.QueryValidatorDelegations: return queryValidatorDelegations(ctx, req, k) + case types.QueryValidatorUnbondingDelegations: return queryValidatorUnbondingDelegations(ctx, req, k) + case types.QueryDelegation: return queryDelegation(ctx, req, k) + case types.QueryUnbondingDelegation: return queryUnbondingDelegation(ctx, req, k) + case types.QueryDelegatorDelegations: return queryDelegatorDelegations(ctx, req, k) + case types.QueryDelegatorUnbondingDelegations: return queryDelegatorUnbondingDelegations(ctx, req, k) + case types.QueryRedelegations: return queryRedelegations(ctx, req, k) + case types.QueryDelegatorValidators: return queryDelegatorValidators(ctx, req, k) + case types.QueryDelegatorValidator: return queryDelegatorValidator(ctx, req, k) + case types.QueryHistoricalInfo: return queryHistoricalInfo(ctx, req, k) + case types.QueryPool: return queryPool(ctx, k) + case types.QueryParameters: return queryParameters(ctx, k) + default: - return nil, sdk.ErrUnknownRequest("unknown staking query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } } } -func queryValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorsParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } validators := k.GetAllValidators(ctx) @@ -76,45 +91,45 @@ func queryValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, res, err := codec.MarshalJSONIndent(types.ModuleCdc, filteredVals) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryValidator(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidator(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } validator, found := k.GetValidator(ctx, params.ValidatorAddr) if !found { - return nil, types.ErrNoValidatorFound(types.DefaultCodespace) + return nil, types.ErrNoValidatorFound } res, err := codec.MarshalJSONIndent(types.ModuleCdc, validator) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryValidatorDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidatorDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } delegations := k.GetValidatorDelegations(ctx, params.ValidatorAddr) delegationResps, err := delegationsToDelegationResponses(ctx, k, delegations) if err != nil { - return nil, sdk.ErrInternal(err.Error()) + return nil, err } if delegationResps == nil { @@ -123,18 +138,18 @@ func queryValidatorDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) res, err := codec.MarshalJSONIndent(types.ModuleCdc, delegationResps) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryValidatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryValidatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryValidatorParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } unbonds := k.GetUnbondingDelegationsFromValidator(ctx, params.ValidatorAddr) @@ -144,24 +159,24 @@ func queryValidatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, res, err := codec.MarshalJSONIndent(types.ModuleCdc, unbonds) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryDelegatorDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegatorParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } delegations := k.GetAllDelegatorDelegations(ctx, params.DelegatorAddr) delegationResps, err := delegationsToDelegationResponses(ctx, k, delegations) if err != nil { - return nil, sdk.ErrInternal(err.Error()) + return nil, err } if delegationResps == nil { @@ -170,18 +185,18 @@ func queryDelegatorDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) res, err := codec.MarshalJSONIndent(types.ModuleCdc, delegationResps) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryDelegatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegatorParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } unbondingDelegations := k.GetAllUnbondingDelegations(ctx, params.DelegatorAddr) @@ -191,20 +206,20 @@ func queryDelegatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, res, err := codec.MarshalJSONIndent(types.ModuleCdc, unbondingDelegations) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryDelegatorValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryDelegatorParams stakingParams := k.GetParams(ctx) err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } validators := k.GetDelegatorValidators(ctx, params.DelegatorAddr, stakingParams.MaxValidators) @@ -214,86 +229,86 @@ func queryDelegatorValidators(ctx sdk.Context, req abci.RequestQuery, k Keeper) res, err := codec.MarshalJSONIndent(types.ModuleCdc, validators) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryDelegatorValidator(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegatorValidator(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryBondsParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } validator, err := k.GetDelegatorValidator(ctx, params.DelegatorAddr, params.ValidatorAddr) if err != nil { - return nil, sdk.ErrInternal(err.Error()) + return nil, err } res, err := codec.MarshalJSONIndent(types.ModuleCdc, validator) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryDelegation(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryDelegation(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryBondsParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } delegation, found := k.GetDelegation(ctx, params.DelegatorAddr, params.ValidatorAddr) if !found { - return nil, types.ErrNoDelegation(types.DefaultCodespace) + return nil, types.ErrNoDelegation } delegationResp, err := delegationToDelegationResponse(ctx, k, delegation) if err != nil { - return nil, sdk.ErrInternal(err.Error()) + return nil, err } res, err := codec.MarshalJSONIndent(types.ModuleCdc, delegationResp) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryUnbondingDelegation(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryUnbondingDelegation(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryBondsParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } unbond, found := k.GetUnbondingDelegation(ctx, params.DelegatorAddr, params.ValidatorAddr) if !found { - return nil, types.ErrNoUnbondingDelegation(types.DefaultCodespace) + return nil, types.ErrNoUnbondingDelegation } res, err := codec.MarshalJSONIndent(types.ModuleCdc, unbond) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryRedelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryRedelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryRedelegationParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(string(req.Data)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } var redels []types.Redelegation @@ -302,7 +317,7 @@ func queryRedelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byt case !params.DelegatorAddr.Empty() && !params.SrcValidatorAddr.Empty() && !params.DstValidatorAddr.Empty(): redel, found := k.GetRedelegation(ctx, params.DelegatorAddr, params.SrcValidatorAddr, params.DstValidatorAddr) if !found { - return nil, types.ErrNoRedelegation(types.DefaultCodespace) + return nil, types.ErrNoRedelegation } redels = []types.Redelegation{redel} @@ -314,7 +329,7 @@ func queryRedelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byt redelResponses, err := redelegationsToRedelegationResponses(ctx, k, redels) if err != nil { - return nil, sdk.ErrInternal(err.Error()) + return nil, err } if redelResponses == nil { @@ -323,39 +338,40 @@ func queryRedelegations(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byt res, err := codec.MarshalJSONIndent(types.ModuleCdc, redelResponses) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryHistoricalInfo(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryHistoricalInfo(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryHistoricalInfoParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrUnknownRequest(string(req.Data)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } hi, found := k.GetHistoricalInfo(ctx, params.Height) if !found { - return nil, types.ErrNoHistoricalInfo(types.DefaultCodespace) + return nil, types.ErrNoHistoricalInfo } res, err := codec.MarshalJSONIndent(types.ModuleCdc, hi) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryPool(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { +func queryPool(ctx sdk.Context, k Keeper) ([]byte, error) { bondDenom := k.BondDenom(ctx) + bondedPool := k.GetBondedPool(ctx) notBondedPool := k.GetNotBondedPool(ctx) if bondedPool == nil || notBondedPool == nil { - return nil, sdk.ErrInternal("pool accounts haven't been set") + return nil, errors.New("pool accounts haven't been set") } pool := types.NewPool( @@ -365,18 +381,18 @@ func queryPool(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { res, err := codec.MarshalJSONIndent(types.ModuleCdc, pool) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func queryParameters(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { +func queryParameters(ctx sdk.Context, k Keeper) ([]byte, error) { params := k.GetParams(ctx) res, err := codec.MarshalJSONIndent(types.ModuleCdc, params) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil @@ -385,10 +401,10 @@ func queryParameters(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { //______________________________________________________ // util -func delegationToDelegationResponse(ctx sdk.Context, k Keeper, del types.Delegation) (types.DelegationResponse, sdk.Error) { +func delegationToDelegationResponse(ctx sdk.Context, k Keeper, del types.Delegation) (types.DelegationResponse, error) { val, found := k.GetValidator(ctx, del.ValidatorAddress) if !found { - return types.DelegationResponse{}, types.ErrNoValidatorFound(types.DefaultCodespace) + return types.DelegationResponse{}, types.ErrNoValidatorFound } return types.NewDelegationResp( @@ -401,7 +417,7 @@ func delegationToDelegationResponse(ctx sdk.Context, k Keeper, del types.Delegat func delegationsToDelegationResponses( ctx sdk.Context, k Keeper, delegations types.Delegations, -) (types.DelegationResponses, sdk.Error) { +) (types.DelegationResponses, error) { resp := make(types.DelegationResponses, len(delegations)) for i, del := range delegations { @@ -418,13 +434,13 @@ func delegationsToDelegationResponses( func redelegationsToRedelegationResponses( ctx sdk.Context, k Keeper, redels types.Redelegations, -) (types.RedelegationResponses, sdk.Error) { +) (types.RedelegationResponses, error) { resp := make(types.RedelegationResponses, len(redels)) for i, redel := range redels { val, found := k.GetValidator(ctx, redel.ValidatorDstAddress) if !found { - return nil, types.ErrNoValidatorFound(types.DefaultCodespace) + return nil, types.ErrNoValidatorFound } entryResponses := make([]types.RedelegationEntryResponse, len(redel.Entries)) diff --git a/x/staking/keeper/query_utils.go b/x/staking/keeper/query_utils.go index 6bde68f5df6e..336bb842ab9e 100644 --- a/x/staking/keeper/query_utils.go +++ b/x/staking/keeper/query_utils.go @@ -21,7 +21,7 @@ func (k Keeper) GetDelegatorValidators(ctx sdk.Context, delegatorAddr sdk.AccAdd validator, found := k.GetValidator(ctx, delegation.ValidatorAddress) if !found { - panic(types.ErrNoValidatorFound(types.DefaultCodespace)) + panic(types.ErrNoValidatorFound) } validators[i] = validator i++ @@ -31,16 +31,16 @@ func (k Keeper) GetDelegatorValidators(ctx sdk.Context, delegatorAddr sdk.AccAdd // return a validator that a delegator is bonded to func (k Keeper) GetDelegatorValidator(ctx sdk.Context, delegatorAddr sdk.AccAddress, - validatorAddr sdk.ValAddress) (validator types.Validator, err sdk.Error) { + validatorAddr sdk.ValAddress) (validator types.Validator, err error) { delegation, found := k.GetDelegation(ctx, delegatorAddr, validatorAddr) if !found { - return validator, types.ErrNoDelegation(types.DefaultCodespace) + return validator, types.ErrNoDelegation } validator, found = k.GetValidator(ctx, delegation.ValidatorAddress) if !found { - panic(types.ErrNoValidatorFound(types.DefaultCodespace)) + panic(types.ErrNoValidatorFound) } return } diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/test_common.go index 51d7f71ae9d6..0d730b48b3ca 100644 --- a/x/staking/keeper/test_common.go +++ b/x/staking/keeper/test_common.go @@ -115,7 +115,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context blacklistedAddrs[notBondedPool.GetAddress().String()] = true blacklistedAddrs[bondPool.GetAddress().String()] = true - pk := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace) + pk := params.NewKeeper(cdc, keyParams, tkeyParams) accountKeeper := auth.NewAccountKeeper( cdc, // amino codec @@ -127,7 +127,6 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context bk := bank.NewBaseKeeper( accountKeeper, pk.Subspace(bank.DefaultParamspace), - bank.DefaultCodespace, blacklistedAddrs, ) @@ -144,7 +143,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, initPower int64) (sdk.Context supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply)) - keeper := NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(DefaultParamspace), types.DefaultCodespace) + keeper := NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(DefaultParamspace)) keeper.SetParams(ctx, types.DefaultParams()) // set module accounts diff --git a/x/staking/keeper/validator.go b/x/staking/keeper/validator.go index cd5e912ca92a..48ecbb384313 100644 --- a/x/staking/keeper/validator.go +++ b/x/staking/keeper/validator.go @@ -156,7 +156,7 @@ func (k Keeper) RemoveValidatorTokens(ctx sdk.Context, // UpdateValidatorCommission attempts to update a validator's commission rate. // An error is returned if the new commission rate is invalid. func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, - validator types.Validator, newRate sdk.Dec) (types.Commission, sdk.Error) { + validator types.Validator, newRate sdk.Dec) (types.Commission, error) { commission := validator.Commission blockTime := ctx.BlockHeader().Time diff --git a/x/staking/simulation/operations.go b/x/staking/simulation/operations.go index 8ddea88aa7c6..b1a932270641 100644 --- a/x/staking/simulation/operations.go +++ b/x/staking/simulation/operations.go @@ -1,7 +1,6 @@ package simulation import ( - "errors" "fmt" "math/rand" @@ -161,9 +160,9 @@ func SimulateMsgCreateValidator(ak types.AccountKeeper, k keeper.Keeper) simulat simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -226,9 +225,9 @@ func SimulateMsgEditValidator(ak types.AccountKeeper, k keeper.Keeper) simulatio simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -293,9 +292,9 @@ func SimulateMsgDelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.Ope simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -373,9 +372,9 @@ func SimulateMsgUndelegate(ak types.AccountKeeper, k keeper.Keeper) simulation.O simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil @@ -479,9 +478,9 @@ func SimulateMsgBeginRedelegate(ak types.AccountKeeper, k keeper.Keeper) simulat simAccount.PrivKey, ) - res := app.Deliver(tx) - if !res.IsOK() { - return simulation.NoOpMsg(types.ModuleName), nil, errors.New(res.Log) + _, _, err = app.Deliver(tx) + if err != nil { + return simulation.NoOpMsg(types.ModuleName), nil, err } return simulation.NewOperationMsg(msg, true, ""), nil, nil diff --git a/x/staking/types/commission.go b/x/staking/types/commission.go index f447c452822f..38ab8e06a703 100644 --- a/x/staking/types/commission.go +++ b/x/staking/types/commission.go @@ -67,31 +67,31 @@ func (c Commission) String() string { // Validate performs basic sanity validation checks of initial commission // parameters. If validation fails, an SDK error is returned. -func (c CommissionRates) Validate() sdk.Error { +func (c CommissionRates) Validate() error { switch { case c.MaxRate.IsNegative(): // max rate cannot be negative - return ErrCommissionNegative(DefaultCodespace) + return ErrCommissionNegative case c.MaxRate.GT(sdk.OneDec()): // max rate cannot be greater than 1 - return ErrCommissionHuge(DefaultCodespace) + return ErrCommissionHuge case c.Rate.IsNegative(): // rate cannot be negative - return ErrCommissionNegative(DefaultCodespace) + return ErrCommissionNegative case c.Rate.GT(c.MaxRate): // rate cannot be greater than the max rate - return ErrCommissionGTMaxRate(DefaultCodespace) + return ErrCommissionGTMaxRate case c.MaxChangeRate.IsNegative(): // change rate cannot be negative - return ErrCommissionChangeRateNegative(DefaultCodespace) + return ErrCommissionChangeRateNegative case c.MaxChangeRate.GT(c.MaxRate): // change rate cannot be greater than the max rate - return ErrCommissionChangeRateGTMaxRate(DefaultCodespace) + return ErrCommissionChangeRateGTMaxRate } return nil @@ -99,23 +99,23 @@ func (c CommissionRates) Validate() sdk.Error { // ValidateNewRate performs basic sanity validation checks of a new commission // rate. If validation fails, an SDK error is returned. -func (c Commission) ValidateNewRate(newRate sdk.Dec, blockTime time.Time) sdk.Error { +func (c Commission) ValidateNewRate(newRate sdk.Dec, blockTime time.Time) error { switch { case blockTime.Sub(c.UpdateTime).Hours() < 24: // new rate cannot be changed more than once within 24 hours - return ErrCommissionUpdateTime(DefaultCodespace) + return ErrCommissionUpdateTime case newRate.IsNegative(): // new rate cannot be negative - return ErrCommissionNegative(DefaultCodespace) + return ErrCommissionNegative case newRate.GT(c.MaxRate): // new rate cannot be greater than the max rate - return ErrCommissionGTMaxRate(DefaultCodespace) + return ErrCommissionGTMaxRate case newRate.Sub(c.Rate).GT(c.MaxChangeRate): // new rate % points change cannot be greater than the max change rate - return ErrCommissionGTMaxChangeRate(DefaultCodespace) + return ErrCommissionGTMaxChangeRate } return nil diff --git a/x/staking/types/errors.go b/x/staking/types/errors.go index 523e720e2d98..d3ccf0a9dac2 100644 --- a/x/staking/types/errors.go +++ b/x/staking/types/errors.go @@ -1,223 +1,59 @@ -// nolint package types import ( - "fmt" - "strings" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -type CodeType = sdk.CodeType - -const ( - DefaultCodespace sdk.CodespaceType = ModuleName - - CodeInvalidValidator CodeType = 101 - CodeInvalidDelegation CodeType = 102 - CodeInvalidInput CodeType = 103 - CodeValidatorJailed CodeType = 104 - CodeInvalidHistoricalInfo CodeType = 105 - CodeInvalidAddress CodeType = sdk.CodeInvalidAddress - CodeUnauthorized CodeType = sdk.CodeUnauthorized - CodeInternal CodeType = sdk.CodeInternal - CodeUnknownRequest CodeType = sdk.CodeUnknownRequest +// x/staking module sentinel errors +// +// TODO: Many of these errors are redundant. They should be removed and replaced +// by sdkerrors.ErrInvalidRequest. +// +// REF: https://github.com/cosmos/cosmos-sdk/issues/5450 +var ( + ErrEmptyValidatorAddr = sdkerrors.Register(ModuleName, 1, "empty validator address") + ErrBadValidatorAddr = sdkerrors.Register(ModuleName, 2, "validator address is invalid") + ErrNoValidatorFound = sdkerrors.Register(ModuleName, 3, "validator does not exist") + ErrValidatorOwnerExists = sdkerrors.Register(ModuleName, 4, "validator already exist for this operator address; must use new validator operator address") + ErrValidatorPubKeyExists = sdkerrors.Register(ModuleName, 5, "validator already exist for this pubkey; must use new validator pubkey") + ErrValidatorPubKeyTypeNotSupported = sdkerrors.Register(ModuleName, 6, "validator pubkey type is not supported") + ErrValidatorJailed = sdkerrors.Register(ModuleName, 7, "validator for this address is currently jailed") + ErrBadRemoveValidator = sdkerrors.Register(ModuleName, 8, "failed to remove validator") + ErrCommissionNegative = sdkerrors.Register(ModuleName, 9, "commission must be positive") + ErrCommissionHuge = sdkerrors.Register(ModuleName, 10, "commission cannot be more than 100%") + ErrCommissionGTMaxRate = sdkerrors.Register(ModuleName, 11, "commission cannot be more than the max rate") + ErrCommissionUpdateTime = sdkerrors.Register(ModuleName, 12, "commission cannot be changed more than once in 24h") + ErrCommissionChangeRateNegative = sdkerrors.Register(ModuleName, 13, "commission change rate must be positive") + ErrCommissionChangeRateGTMaxRate = sdkerrors.Register(ModuleName, 14, "commission change rate cannot be more than the max rate") + ErrCommissionGTMaxChangeRate = sdkerrors.Register(ModuleName, 15, "commission cannot be changed more than max change rate") + ErrSelfDelegationBelowMinimum = sdkerrors.Register(ModuleName, 16, "validator's self delegation must be greater than their minimum self delegation") + ErrMinSelfDelegationInvalid = sdkerrors.Register(ModuleName, 17, "minimum self delegation must be a positive integer") + ErrMinSelfDelegationDecreased = sdkerrors.Register(ModuleName, 18, "minimum self delegation cannot be decrease") + ErrEmptyDelegatorAddr = sdkerrors.Register(ModuleName, 19, "empty delegator address") + ErrBadDenom = sdkerrors.Register(ModuleName, 20, "invalid coin denomination") + ErrBadDelegationAddr = sdkerrors.Register(ModuleName, 21, "invalid address for (address, validator) tuple") + ErrBadDelegationAmount = sdkerrors.Register(ModuleName, 22, "invalid delegation amount") + ErrNoDelegation = sdkerrors.Register(ModuleName, 23, "no delegation for (address, validator) tuple") + ErrBadDelegatorAddr = sdkerrors.Register(ModuleName, 24, "delegator does not exist with address") + ErrNoDelegatorForAddress = sdkerrors.Register(ModuleName, 25, "delegator does not contain delegation") + ErrInsufficientShares = sdkerrors.Register(ModuleName, 26, "insufficient delegation shares") + ErrDelegationValidatorEmpty = sdkerrors.Register(ModuleName, 27, "cannot delegate to an empty validator") + ErrNotEnoughDelegationShares = sdkerrors.Register(ModuleName, 28, "not enough delegation shares") + ErrBadSharesAmount = sdkerrors.Register(ModuleName, 29, "invalid shares amount") + ErrBadSharesPercent = sdkerrors.Register(ModuleName, 30, "Invalid shares percent") + ErrNotMature = sdkerrors.Register(ModuleName, 31, "entry not mature") + ErrNoUnbondingDelegation = sdkerrors.Register(ModuleName, 32, "no unbonding delegation found") + ErrMaxUnbondingDelegationEntries = sdkerrors.Register(ModuleName, 33, "too many unbonding delegation entries for (delegator, validator) tuple") + ErrBadRedelegationAddr = sdkerrors.Register(ModuleName, 34, "invalid address for (address, src-validator, dst-validator) tuple") + ErrNoRedelegation = sdkerrors.Register(ModuleName, 35, "no redelegation found") + ErrSelfRedelegation = sdkerrors.Register(ModuleName, 36, "cannot redelegate to the same validator") + ErrTinyRedelegationAmount = sdkerrors.Register(ModuleName, 37, "too few tokens to redelegate (truncates to zero tokens)") + ErrBadRedelegationDst = sdkerrors.Register(ModuleName, 38, "redelegation destination validator not found") + ErrTransitiveRedelegation = sdkerrors.Register(ModuleName, 39, "redelegation to this validator already in progress; first redelegation to this validator must complete before next redelegation") + ErrMaxRedelegationEntries = sdkerrors.Register(ModuleName, 40, "too many redelegation entries for (delegator, src-validator, dst-validator) tuple") + ErrDelegatorShareExRateInvalid = sdkerrors.Register(ModuleName, 41, "cannot delegate to validators with invalid (zero) ex-rate") + ErrBothShareMsgsGiven = sdkerrors.Register(ModuleName, 42, "both shares amount and shares percent provided") + ErrNeitherShareMsgsGiven = sdkerrors.Register(ModuleName, 43, "neither shares amount nor shares percent provided") + ErrInvalidHistoricalInfo = sdkerrors.Register(ModuleName, 44, "invalid historical info") + ErrNoHistoricalInfo = sdkerrors.Register(ModuleName, 45, "no historical info found") ) - -//validator -func ErrNilValidatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "validator address is nil") -} - -func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidAddress, "validator address is invalid") -} - -func ErrNoValidatorFound(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address") -} - -func ErrValidatorOwnerExists(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "validator already exist for this operator address, must use new validator operator address") -} - -func ErrValidatorPubKeyExists(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "validator already exist for this pubkey, must use new validator pubkey") -} - -func ErrValidatorPubKeyTypeNotSupported(codespace sdk.CodespaceType, keyType string, supportedTypes []string) sdk.Error { - msg := fmt.Sprintf("validator pubkey type %s is not supported, must use %s", keyType, strings.Join(supportedTypes, ",")) - return sdk.NewError(codespace, CodeInvalidValidator, msg) -} - -func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "validator for this address is currently jailed") -} - -func ErrBadRemoveValidator(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "error removing validator") -} - -func ErrDescriptionLength(codespace sdk.CodespaceType, descriptor string, got, max int) sdk.Error { - msg := fmt.Sprintf("bad description length for %v, got length %v, max is %v", descriptor, got, max) - return sdk.NewError(codespace, CodeInvalidValidator, msg) -} - -func ErrCommissionNegative(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission must be positive") -} - -func ErrCommissionHuge(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than 100%") -} - -func ErrCommissionGTMaxRate(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than the max rate") -} - -func ErrCommissionUpdateTime(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be changed more than once in 24h") -} - -func ErrCommissionChangeRateNegative(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission change rate must be positive") -} - -func ErrCommissionChangeRateGTMaxRate(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission change rate cannot be more than the max rate") -} - -func ErrCommissionGTMaxChangeRate(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be changed more than max change rate") -} - -func ErrSelfDelegationBelowMinimum(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "validator's self delegation must be greater than their minimum self delegation") -} - -func ErrMinSelfDelegationInvalid(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "minimum self delegation must be a positive integer") -} - -func ErrMinSelfDelegationDecreased(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "minimum self delegation cannot be decrease") -} - -func ErrNilDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "delegator address is nil") -} - -func ErrBadDenom(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "invalid coin denomination") -} - -func ErrBadDelegationAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "unexpected address length for this (address, validator) pair") -} - -func ErrBadDelegationAmount(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "amount must be > 0") -} - -func ErrNoDelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "no delegation for this (address, validator) pair") -} - -func ErrBadDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not exist for that address") -} - -func ErrNoDelegatorForAddress(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not contain this delegation") -} - -func ErrInsufficientShares(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "insufficient delegation shares") -} - -func ErrDelegationValidatorEmpty(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "cannot delegate to an empty validator") -} - -func ErrNotEnoughDelegationShares(codespace sdk.CodespaceType, shares string) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, fmt.Sprintf("not enough shares only have %v", shares)) -} - -func ErrBadSharesAmount(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "shares must be > 0") -} - -func ErrBadSharesPercent(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "shares percent must be >0 and <=1") -} - -func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min time.Time) sdk.Error { - msg := fmt.Sprintf("%v is not mature requires a min %v of %v, currently it is %v", - operation, descriptor, got, min) - return sdk.NewError(codespace, CodeUnauthorized, msg) -} - -func ErrNoUnbondingDelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "no unbonding delegation found") -} - -func ErrMaxUnbondingDelegationEntries(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, - "too many unbonding delegation entries in this delegator/validator duo, please wait for some entries to mature") -} - -func ErrBadRedelegationAddr(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "unexpected address length for this (address, srcValidator, dstValidator) tuple") -} - -func ErrNoRedelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "no redelegation found") -} - -func ErrSelfRedelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "cannot redelegate to the same validator") -} - -func ErrVerySmallRedelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "too few tokens to redelegate, truncates to zero tokens") -} - -func ErrBadRedelegationDst(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, "redelegation validator not found") -} - -func ErrTransitiveRedelegation(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, - "redelegation to this validator already in progress, first redelegation to this validator must complete before next redelegation") -} - -func ErrMaxRedelegationEntries(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, - "too many redelegation entries in this delegator/src-validator/dst-validator trio, please wait for some entries to mature") -} - -func ErrDelegatorShareExRateInvalid(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidDelegation, - "cannot delegate to validators with invalid (zero) ex-rate") -} - -func ErrBothShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "both shares amount and shares percent provided") -} - -func ErrNeitherShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidInput, "neither shares amount nor shares percent provided") -} - -func ErrMissingSignature(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidValidator, "missing signature") -} - -func ErrInvalidHistoricalInfo(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidHistoricalInfo, "invalid historical info") -} - -func ErrNoHistoricalInfo(codespace sdk.CodespaceType) sdk.Error { - return sdk.NewError(codespace, CodeInvalidHistoricalInfo, "no historical info found") -} diff --git a/x/staking/types/expected_keepers.go b/x/staking/types/expected_keepers.go index 8f346a71c4cb..5e98f0abbed0 100644 --- a/x/staking/types/expected_keepers.go +++ b/x/staking/types/expected_keepers.go @@ -29,11 +29,11 @@ type SupplyKeeper interface { // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 SetModuleAccount(sdk.Context, supplyexported.ModuleAccountI) - SendCoinsFromModuleToModule(ctx sdk.Context, senderPool, recipientPool string, amt sdk.Coins) sdk.Error - UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - DelegateCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error + SendCoinsFromModuleToModule(ctx sdk.Context, senderPool, recipientPool string, amt sdk.Coins) error + UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + DelegateCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error - BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error + BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error } // ValidatorSet expected properties for the set of all validators (noalias) diff --git a/x/staking/types/historical_info.go b/x/staking/types/historical_info.go index 8fae88f07f4e..78db1e7dd4a9 100644 --- a/x/staking/types/historical_info.go +++ b/x/staking/types/historical_info.go @@ -48,10 +48,10 @@ func UnmarshalHistoricalInfo(cdc *codec.Codec, value []byte) (hi HistoricalInfo, // ValidateBasic will ensure HistoricalInfo is not nil and sorted func ValidateBasic(hi HistoricalInfo) error { if len(hi.ValSet) == 0 { - return sdkerrors.Wrap(ErrInvalidHistoricalInfo(DefaultCodespace), "ValidatorSer is nil") + return sdkerrors.Wrap(ErrInvalidHistoricalInfo, "validator set is empty") } if !sort.IsSorted(Validators(hi.ValSet)) { - return sdkerrors.Wrap(ErrInvalidHistoricalInfo(DefaultCodespace), "ValidatorSet is not sorted by address") + return sdkerrors.Wrap(ErrInvalidHistoricalInfo, "validator set is not sorted by address") } return nil } diff --git a/x/staking/types/msg.go b/x/staking/types/msg.go index fa44090ac747..8b47cfec443c 100644 --- a/x/staking/types/msg.go +++ b/x/staking/types/msg.go @@ -8,6 +8,7 @@ import ( yaml "gopkg.in/yaml.v2" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // ensure Msg interface compliance at compile time @@ -151,34 +152,34 @@ func (msg MsgCreateValidator) GetSignBytes() []byte { } // ValidateBasic implements the sdk.Msg interface. -func (msg MsgCreateValidator) ValidateBasic() sdk.Error { +func (msg MsgCreateValidator) ValidateBasic() error { // note that unmarshaling from bech32 ensures either empty or valid if msg.DelegatorAddress.Empty() { - return ErrNilDelegatorAddr(DefaultCodespace) + return ErrEmptyDelegatorAddr } if msg.ValidatorAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } if !sdk.AccAddress(msg.ValidatorAddress).Equals(msg.DelegatorAddress) { - return ErrBadValidatorAddr(DefaultCodespace) + return ErrBadValidatorAddr } if !msg.Value.Amount.IsPositive() { - return ErrBadDelegationAmount(DefaultCodespace) + return ErrBadDelegationAmount } if msg.Description == (Description{}) { - return sdk.NewError(DefaultCodespace, CodeInvalidInput, "description must be included") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "empty description") } if msg.Commission == (CommissionRates{}) { - return sdk.NewError(DefaultCodespace, CodeInvalidInput, "commission must be included") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "empty commission") } if err := msg.Commission.Validate(); err != nil { return err } if !msg.MinSelfDelegation.IsPositive() { - return ErrMinSelfDelegationInvalid(DefaultCodespace) + return ErrMinSelfDelegationInvalid } if msg.Value.Amount.LT(msg.MinSelfDelegation) { - return ErrSelfDelegationBelowMinimum(DefaultCodespace) + return ErrSelfDelegationBelowMinimum } return nil @@ -226,22 +227,19 @@ func (msg MsgEditValidator) GetSignBytes() []byte { } // ValidateBasic implements the sdk.Msg interface. -func (msg MsgEditValidator) ValidateBasic() sdk.Error { +func (msg MsgEditValidator) ValidateBasic() error { if msg.ValidatorAddress.Empty() { - return sdk.NewError(DefaultCodespace, CodeInvalidInput, "nil validator address") + return ErrEmptyValidatorAddr } - if msg.Description == (Description{}) { - return sdk.NewError(DefaultCodespace, CodeInvalidInput, "transaction must include some information to modify") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "empty description") } - if msg.MinSelfDelegation != nil && !msg.MinSelfDelegation.IsPositive() { - return ErrMinSelfDelegationInvalid(DefaultCodespace) + return ErrMinSelfDelegationInvalid } - if msg.CommissionRate != nil { if msg.CommissionRate.GT(sdk.OneDec()) || msg.CommissionRate.IsNegative() { - return sdk.NewError(DefaultCodespace, CodeInvalidInput, "commission rate must be between 0 and 1, inclusive") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "commission rate must be between 0 and 1 (inclusive)") } } @@ -282,15 +280,15 @@ func (msg MsgDelegate) GetSignBytes() []byte { } // ValidateBasic implements the sdk.Msg interface. -func (msg MsgDelegate) ValidateBasic() sdk.Error { +func (msg MsgDelegate) ValidateBasic() error { if msg.DelegatorAddress.Empty() { - return ErrNilDelegatorAddr(DefaultCodespace) + return ErrEmptyDelegatorAddr } if msg.ValidatorAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } if !msg.Amount.Amount.IsPositive() { - return ErrBadDelegationAmount(DefaultCodespace) + return ErrBadDelegationAmount } return nil } @@ -335,18 +333,18 @@ func (msg MsgBeginRedelegate) GetSignBytes() []byte { } // ValidateBasic implements the sdk.Msg interface. -func (msg MsgBeginRedelegate) ValidateBasic() sdk.Error { +func (msg MsgBeginRedelegate) ValidateBasic() error { if msg.DelegatorAddress.Empty() { - return ErrNilDelegatorAddr(DefaultCodespace) + return ErrEmptyDelegatorAddr } if msg.ValidatorSrcAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } if msg.ValidatorDstAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } if !msg.Amount.Amount.IsPositive() { - return ErrBadSharesAmount(DefaultCodespace) + return ErrBadSharesAmount } return nil } @@ -383,15 +381,15 @@ func (msg MsgUndelegate) GetSignBytes() []byte { } // ValidateBasic implements the sdk.Msg interface. -func (msg MsgUndelegate) ValidateBasic() sdk.Error { +func (msg MsgUndelegate) ValidateBasic() error { if msg.DelegatorAddress.Empty() { - return ErrNilDelegatorAddr(DefaultCodespace) + return ErrEmptyDelegatorAddr } if msg.ValidatorAddress.Empty() { - return ErrNilValidatorAddr(DefaultCodespace) + return ErrEmptyValidatorAddr } if !msg.Amount.Amount.IsPositive() { - return ErrBadSharesAmount(DefaultCodespace) + return ErrBadSharesAmount } return nil } diff --git a/x/staking/types/validator.go b/x/staking/types/validator.go index 37e6cbc02575..2ac2903dcf0b 100644 --- a/x/staking/types/validator.go +++ b/x/staking/types/validator.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/staking/exported" ) @@ -304,7 +305,7 @@ func NewDescription(moniker, identity, website, securityContact, details string) // UpdateDescription updates the fields of a given description. An error is // returned if the resulting description contains an invalid length. -func (d Description) UpdateDescription(d2 Description) (Description, sdk.Error) { +func (d Description) UpdateDescription(d2 Description) (Description, error) { if d2.Moniker == DoNotModifyDesc { d2.Moniker = d.Moniker } @@ -331,21 +332,21 @@ func (d Description) UpdateDescription(d2 Description) (Description, sdk.Error) } // EnsureLength ensures the length of a validator's description. -func (d Description) EnsureLength() (Description, sdk.Error) { +func (d Description) EnsureLength() (Description, error) { if len(d.Moniker) > MaxMonikerLength { - return d, ErrDescriptionLength(DefaultCodespace, "moniker", len(d.Moniker), MaxMonikerLength) + return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid moniker length; got: %d, max: %d", len(d.Moniker), MaxMonikerLength) } if len(d.Identity) > MaxIdentityLength { - return d, ErrDescriptionLength(DefaultCodespace, "identity", len(d.Identity), MaxIdentityLength) + return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid identity length; got: %d, max: %d", len(d.Identity), MaxIdentityLength) } if len(d.Website) > MaxWebsiteLength { - return d, ErrDescriptionLength(DefaultCodespace, "website", len(d.Website), MaxWebsiteLength) + return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid website length; got: %d, max: %d", len(d.Website), MaxWebsiteLength) } if len(d.SecurityContact) > MaxSecurityContactLength { - return d, ErrDescriptionLength(DefaultCodespace, "security contact", len(d.SecurityContact), MaxSecurityContactLength) + return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid security contact length; got: %d, max: %d", len(d.SecurityContact), MaxSecurityContactLength) } if len(d.Details) > MaxDetailsLength { - return d, ErrDescriptionLength(DefaultCodespace, "details", len(d.Details), MaxDetailsLength) + return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid details length; got: %d, max: %d", len(d.Details), MaxDetailsLength) } return d, nil @@ -371,7 +372,7 @@ func (v Validator) ABCIValidatorUpdateZero() abci.ValidatorUpdate { // SetInitialCommission attempts to set a validator's initial commission. An // error is returned if the commission is invalid. -func (v Validator) SetInitialCommission(commission Commission) (Validator, sdk.Error) { +func (v Validator) SetInitialCommission(commission Commission) (Validator, error) { if err := commission.Validate(); err != nil { return v, err } @@ -405,9 +406,9 @@ func (v Validator) TokensFromSharesRoundUp(shares sdk.Dec) sdk.Dec { // SharesFromTokens returns the shares of a delegation given a bond amount. It // returns an error if the validator has no tokens. -func (v Validator) SharesFromTokens(amt sdk.Int) (sdk.Dec, sdk.Error) { +func (v Validator) SharesFromTokens(amt sdk.Int) (sdk.Dec, error) { if v.Tokens.IsZero() { - return sdk.ZeroDec(), ErrInsufficientShares(DefaultCodespace) + return sdk.ZeroDec(), ErrInsufficientShares } return v.GetDelegatorShares().MulInt(amt).QuoInt(v.GetTokens()), nil @@ -415,9 +416,9 @@ func (v Validator) SharesFromTokens(amt sdk.Int) (sdk.Dec, sdk.Error) { // SharesFromTokensTruncated returns the truncated shares of a delegation given // a bond amount. It returns an error if the validator has no tokens. -func (v Validator) SharesFromTokensTruncated(amt sdk.Int) (sdk.Dec, sdk.Error) { +func (v Validator) SharesFromTokensTruncated(amt sdk.Int) (sdk.Dec, error) { if v.Tokens.IsZero() { - return sdk.ZeroDec(), ErrInsufficientShares(DefaultCodespace) + return sdk.ZeroDec(), ErrInsufficientShares } return v.GetDelegatorShares().MulInt(amt).QuoTruncate(v.GetTokens().ToDec()), nil diff --git a/x/supply/alias.go b/x/supply/alias.go index 9bc7f5f13530..1138f7c5eee2 100644 --- a/x/supply/alias.go +++ b/x/supply/alias.go @@ -38,8 +38,7 @@ var ( DefaultSupply = types.DefaultSupply // variable aliases - DefaultCodespace = keeper.DefaultCodespace - ModuleCdc = types.ModuleCdc + ModuleCdc = types.ModuleCdc ) type ( diff --git a/x/supply/internal/keeper/bank.go b/x/supply/internal/keeper/bank.go index 60efbc4c3df5..9117286aaeb6 100644 --- a/x/supply/internal/keeper/bank.go +++ b/x/supply/internal/keeper/bank.go @@ -4,103 +4,110 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/supply/internal/types" ) -// SendCoinsFromModuleToAccount transfers coins from a ModuleAccount to an AccAddress -func (k Keeper) SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, - recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error { +// SendCoinsFromModuleToAccount transfers coins from a ModuleAccount to an AccAddress. +// It will panic if the module account does not exist. +func (k Keeper) SendCoinsFromModuleToAccount( + ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins, +) error { senderAddr := k.GetModuleAddress(senderModule) if senderAddr == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", senderModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", senderModule)) } return k.bk.SendCoins(ctx, senderAddr, recipientAddr, amt) } -// SendCoinsFromModuleToModule transfers coins from a ModuleAccount to another -func (k Keeper) SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) sdk.Error { +// SendCoinsFromModuleToModule transfers coins from a ModuleAccount to another. +// It will panic if either module account does not exist. +func (k Keeper) SendCoinsFromModuleToModule( + ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins, +) error { senderAddr := k.GetModuleAddress(senderModule) if senderAddr == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", senderModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", senderModule)) } - // create the account if it doesn't yet exist recipientAcc := k.GetModuleAccount(ctx, recipientModule) if recipientAcc == nil { - panic(fmt.Sprintf("module account %s isn't able to be created", recipientModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", recipientModule)) } return k.bk.SendCoins(ctx, senderAddr, recipientAcc.GetAddress(), amt) } -// SendCoinsFromAccountToModule transfers coins from an AccAddress to a ModuleAccount -func (k Keeper) SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, - recipientModule string, amt sdk.Coins) sdk.Error { +// SendCoinsFromAccountToModule transfers coins from an AccAddress to a ModuleAccount. +// It will panic if the module account does not exist. +func (k Keeper) SendCoinsFromAccountToModule( + ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins, +) error { - // create the account if it doesn't yet exist recipientAcc := k.GetModuleAccount(ctx, recipientModule) if recipientAcc == nil { - panic(fmt.Sprintf("module account %s isn't able to be created", recipientModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", recipientModule)) } return k.bk.SendCoins(ctx, senderAddr, recipientAcc.GetAddress(), amt) } -// DelegateCoinsFromAccountToModule delegates coins and transfers -// them from a delegator account to a module account -func (k Keeper) DelegateCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, - recipientModule string, amt sdk.Coins) sdk.Error { +// DelegateCoinsFromAccountToModule delegates coins and transfers them from a +// delegator account to a module account. It will panic if the module account +// does not exist or is unauthorized. +func (k Keeper) DelegateCoinsFromAccountToModule( + ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins, +) error { - // create the account if it doesn't yet exist recipientAcc := k.GetModuleAccount(ctx, recipientModule) if recipientAcc == nil { - panic(fmt.Sprintf("module account %s isn't able to be created", recipientModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", recipientModule)) } if !recipientAcc.HasPermission(types.Staking) { - panic(fmt.Sprintf("module account %s does not have permissions to receive delegated coins", recipientModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to receive delegated coins", recipientModule)) } return k.bk.DelegateCoins(ctx, senderAddr, recipientAcc.GetAddress(), amt) } // UndelegateCoinsFromModuleToAccount undelegates the unbonding coins and transfers -// them from a module account to the delegator account -func (k Keeper) UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, - recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error { +// them from a module account to the delegator account. It will panic if the +// module account does not exist or is unauthorized. +func (k Keeper) UndelegateCoinsFromModuleToAccount( + ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins, +) error { acc := k.GetModuleAccount(ctx, senderModule) if acc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", senderModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", senderModule)) } if !acc.HasPermission(types.Staking) { - panic(fmt.Sprintf("module account %s does not have permissions to undelegate coins", senderModule)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to undelegate coins", senderModule)) } return k.bk.UndelegateCoins(ctx, acc.GetAddress(), recipientAddr, amt) } // MintCoins creates new coins from thin air and adds it to the module account. -// Panics if the name maps to a non-minter module account or if the amount is invalid. -func (k Keeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) sdk.Error { - - // create the account if it doesn't yet exist +// It will panic if the module account does not exist or is unauthorized. +func (k Keeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error { acc := k.GetModuleAccount(ctx, moduleName) if acc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", moduleName)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleName)) } if !acc.HasPermission(types.Minter) { - panic(fmt.Sprintf("module account %s does not have permissions to mint tokens", moduleName)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to mint tokens", moduleName)) } _, err := k.bk.AddCoins(ctx, acc.GetAddress(), amt) if err != nil { - panic(err) + return err } // update total supply @@ -116,22 +123,20 @@ func (k Keeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) sdk } // BurnCoins burns coins deletes coins from the balance of the module account. -// Panics if the name maps to a non-burner module account or if the amount is invalid. -func (k Keeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) sdk.Error { - - // create the account if it doesn't yet exist +// It will panic if the module account does not exist or is unauthorized. +func (k Keeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error { acc := k.GetModuleAccount(ctx, moduleName) if acc == nil { - return sdk.ErrUnknownAddress(fmt.Sprintf("module account %s does not exist", moduleName)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", moduleName)) } if !acc.HasPermission(types.Burner) { - panic(fmt.Sprintf("module account %s does not have permissions to burn tokens", moduleName)) + panic(sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "module account %s does not have permissions to burn tokens", moduleName)) } _, err := k.bk.SubtractCoins(ctx, acc.GetAddress(), amt) if err != nil { - panic(err) + return err } // update total supply diff --git a/x/supply/internal/keeper/bank_test.go b/x/supply/internal/keeper/bank_test.go index f0cb48f1fc1f..bdd0a9430a1d 100644 --- a/x/supply/internal/keeper/bank_test.go +++ b/x/supply/internal/keeper/bank_test.go @@ -48,15 +48,17 @@ func TestSendCoins(t *testing.T) { keeper.SetModuleAccount(ctx, burnerAcc) ak.SetAccount(ctx, baseAcc) - err = keeper.SendCoinsFromModuleToModule(ctx, "", holderAcc.GetName(), initCoins) - require.Error(t, err) + require.Panics(t, func() { + keeper.SendCoinsFromModuleToModule(ctx, "", holderAcc.GetName(), initCoins) + }) require.Panics(t, func() { keeper.SendCoinsFromModuleToModule(ctx, types.Burner, "", initCoins) }) - err = keeper.SendCoinsFromModuleToAccount(ctx, "", baseAcc.GetAddress(), initCoins) - require.Error(t, err) + require.Panics(t, func() { + keeper.SendCoinsFromModuleToAccount(ctx, "", baseAcc.GetAddress(), initCoins) + }) err = keeper.SendCoinsFromModuleToAccount(ctx, holderAcc.GetName(), baseAcc.GetAddress(), initCoins.Add(initCoins)) require.Error(t, err) @@ -90,13 +92,14 @@ func TestMintCoins(t *testing.T) { initialSupply := keeper.GetSupply(ctx) - require.Error(t, keeper.MintCoins(ctx, "", initCoins), "no module account") + require.Panics(t, func() { keeper.MintCoins(ctx, "", initCoins) }, "no module account") require.Panics(t, func() { keeper.MintCoins(ctx, types.Burner, initCoins) }, "invalid permission") - require.Panics(t, func() { keeper.MintCoins(ctx, types.Minter, sdk.Coins{sdk.Coin{"denom", sdk.NewInt(-10)}}) }, "insufficient coins") //nolint + err := keeper.MintCoins(ctx, types.Minter, sdk.Coins{sdk.Coin{Denom: "denom", Amount: sdk.NewInt(-10)}}) + require.Error(t, err, "insufficient coins") require.Panics(t, func() { keeper.MintCoins(ctx, randomPerm, initCoins) }) - err := keeper.MintCoins(ctx, types.Minter, initCoins) + err = keeper.MintCoins(ctx, types.Minter, initCoins) require.NoError(t, err) require.Equal(t, initCoins, getCoinsByName(ctx, keeper, ak, types.Minter)) require.Equal(t, initialSupply.GetTotal().Add(initCoins), keeper.GetSupply(ctx).GetTotal()) @@ -125,12 +128,13 @@ func TestBurnCoins(t *testing.T) { initialSupply = initialSupply.Inflate(initCoins) keeper.SetSupply(ctx, initialSupply) - require.Error(t, keeper.BurnCoins(ctx, "", initCoins), "no module account") + require.Panics(t, func() { keeper.BurnCoins(ctx, "", initCoins) }, "no module account") require.Panics(t, func() { keeper.BurnCoins(ctx, types.Minter, initCoins) }, "invalid permission") require.Panics(t, func() { keeper.BurnCoins(ctx, randomPerm, initialSupply.GetTotal()) }, "random permission") - require.Panics(t, func() { keeper.BurnCoins(ctx, types.Burner, initialSupply.GetTotal()) }, "insufficient coins") + err := keeper.BurnCoins(ctx, types.Burner, initialSupply.GetTotal()) + require.Error(t, err, "insufficient coins") - err := keeper.BurnCoins(ctx, types.Burner, initCoins) + err = keeper.BurnCoins(ctx, types.Burner, initCoins) require.NoError(t, err) require.Equal(t, sdk.Coins(nil), getCoinsByName(ctx, keeper, ak, types.Burner)) require.Equal(t, initialSupply.GetTotal().Sub(initCoins), keeper.GetSupply(ctx).GetTotal()) diff --git a/x/supply/internal/keeper/key.go b/x/supply/internal/keeper/key.go index 6428d5445c05..65a23382961f 100644 --- a/x/supply/internal/keeper/key.go +++ b/x/supply/internal/keeper/key.go @@ -1,13 +1,5 @@ package keeper -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/supply/internal/types" -) - -// DefaultCodespace from the supply module -var DefaultCodespace sdk.CodespaceType = types.ModuleName - // Keys for supply store // Items are stored with the following key: values // diff --git a/x/supply/internal/keeper/querier.go b/x/supply/internal/keeper/querier.go index 9b74a45ccbe6..093edd2c6bea 100644 --- a/x/supply/internal/keeper/querier.go +++ b/x/supply/internal/keeper/querier.go @@ -1,18 +1,17 @@ package keeper import ( - "fmt" - abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/supply/internal/types" ) // NewQuerier creates a querier for supply REST endpoints func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryTotalSupply: @@ -22,17 +21,17 @@ func NewQuerier(k Keeper) sdk.Querier { return querySupplyOf(ctx, req, k) default: - return nil, sdk.ErrUnknownRequest("unknown supply query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } } } -func queryTotalSupply(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryTotalSupply(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryTotalSupplyParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } totalSupply := k.GetSupply(ctx).GetTotal() @@ -46,25 +45,25 @@ func queryTotalSupply(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, res, err := totalSupply.MarshalJSON() if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil } -func querySupplyOf(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func querySupplyOf(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QuerySupplyOfParams err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } supply := k.GetSupply(ctx).GetTotal().AmountOf(params.Denom) res, err := supply.MarshalJSON() if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } return res, nil diff --git a/x/supply/internal/types/expected_keepers.go b/x/supply/internal/types/expected_keepers.go index bf0cc6ec328a..3ad1d8b13ce4 100644 --- a/x/supply/internal/types/expected_keepers.go +++ b/x/supply/internal/types/expected_keepers.go @@ -15,10 +15,10 @@ type AccountKeeper interface { // BankKeeper defines the expected bank keeper (noalias) type BankKeeper interface { - SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - DelegateCoins(ctx sdk.Context, fromAdd, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error - UndelegateCoins(ctx sdk.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) sdk.Error + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error + DelegateCoins(ctx sdk.Context, fromAdd, toAddr sdk.AccAddress, amt sdk.Coins) error + UndelegateCoins(ctx sdk.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) error - SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) - AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, sdk.Error) + SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) + AddCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error) } diff --git a/x/upgrade/abci_test.go b/x/upgrade/abci_test.go index edc71590dc0f..34c8944e0017 100644 --- a/x/upgrade/abci_test.go +++ b/x/upgrade/abci_test.go @@ -1,11 +1,13 @@ package upgrade_test import ( + "errors" "testing" "time" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/upgrade" @@ -37,25 +39,25 @@ func (s *TestSuite) SetupTest() { func (s *TestSuite) TestRequireName() { err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{}}) s.Require().NotNil(err) - s.Require().Equal(sdk.CodeUnknownRequest, err.Code()) + s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) } func (s *TestSuite) TestRequireFutureTime() { err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Time: s.ctx.BlockHeader().Time}}) s.Require().NotNil(err) - s.Require().Equal(sdk.CodeUnknownRequest, err.Code()) + s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) } func (s *TestSuite) TestRequireFutureBlock() { err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Height: s.ctx.BlockHeight()}}) s.Require().NotNil(err) - s.Require().Equal(sdk.CodeUnknownRequest, err.Code()) + s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) } func (s *TestSuite) TestCantSetBothTimeAndHeight() { err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Time: time.Now(), Height: s.ctx.BlockHeight() + 1}}) s.Require().NotNil(err) - s.Require().Equal(sdk.CodeUnknownRequest, err.Code()) + s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) } func (s *TestSuite) TestDoTimeUpgrade() { @@ -156,7 +158,7 @@ func (s *TestSuite) TestCantApplySameUpgradeTwice() { s.T().Log("Verify an upgrade named \"test\" can't be scheduled twice") err := s.handler(s.ctx, upgrade.SoftwareUpgradeProposal{Title: "prop", Plan: upgrade.Plan{Name: "test", Time: time.Now()}}) s.Require().NotNil(err) - s.Require().Equal(sdk.CodeUnknownRequest, err.Code()) + s.Require().True(errors.Is(sdkerrors.ErrInvalidRequest, err), err) } func (s *TestSuite) TestNoSpuriousUpgrades() { diff --git a/x/upgrade/alias.go b/x/upgrade/alias.go index b7324f2c3e41..fe36f23097bc 100644 --- a/x/upgrade/alias.go +++ b/x/upgrade/alias.go @@ -1,10 +1,7 @@ -// nolint -// autogenerated code using github.com/rigelrozanski/multitool -// aliases generated for the following subdirectories: -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/upgrade/internal/types -// ALIASGEN: github.com/cosmos/cosmos-sdk/x/upgrade/internal/keeper package upgrade +// nolint + import ( "github.com/cosmos/cosmos-sdk/x/upgrade/internal/keeper" "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" @@ -19,7 +16,6 @@ const ( DoneByte = types.DoneByte ProposalTypeSoftwareUpgrade = types.ProposalTypeSoftwareUpgrade ProposalTypeCancelSoftwareUpgrade = types.ProposalTypeCancelSoftwareUpgrade - DefaultCodespace = types.DefaultCodespace QueryCurrent = types.QueryCurrent QueryApplied = types.QueryApplied ) diff --git a/x/upgrade/handler.go b/x/upgrade/handler.go index 925d4e875c9d..8a4a9f89ab10 100644 --- a/x/upgrade/handler.go +++ b/x/upgrade/handler.go @@ -1,9 +1,8 @@ package upgrade import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -11,7 +10,7 @@ import ( // It enables SoftwareUpgradeProposal to propose an Upgrade, and CancelSoftwareUpgradeProposal // to abort a previously voted upgrade. func NewSoftwareUpgradeProposalHandler(k Keeper) govtypes.Handler { - return func(ctx sdk.Context, content govtypes.Content) sdk.Error { + return func(ctx sdk.Context, content govtypes.Content) error { switch c := content.(type) { case SoftwareUpgradeProposal: return handleSoftwareUpgradeProposal(ctx, k, c) @@ -20,17 +19,16 @@ func NewSoftwareUpgradeProposalHandler(k Keeper) govtypes.Handler { return handleCancelSoftwareUpgradeProposal(ctx, k, c) default: - errMsg := fmt.Sprintf("unrecognized software upgrade proposal content type: %T", c) - return sdk.ErrUnknownRequest(errMsg) + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized software upgrade proposal content type: %T", c) } } } -func handleSoftwareUpgradeProposal(ctx sdk.Context, k Keeper, p SoftwareUpgradeProposal) sdk.Error { +func handleSoftwareUpgradeProposal(ctx sdk.Context, k Keeper, p SoftwareUpgradeProposal) error { return k.ScheduleUpgrade(ctx, p.Plan) } -func handleCancelSoftwareUpgradeProposal(ctx sdk.Context, k Keeper, p CancelSoftwareUpgradeProposal) sdk.Error { +func handleCancelSoftwareUpgradeProposal(ctx sdk.Context, k Keeper, p CancelSoftwareUpgradeProposal) error { k.ClearUpgradePlan(ctx) return nil } diff --git a/x/upgrade/internal/keeper/keeper.go b/x/upgrade/internal/keeper/keeper.go index bb95ec6eafdb..e0c0823b0842 100644 --- a/x/upgrade/internal/keeper/keeper.go +++ b/x/upgrade/internal/keeper/keeper.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" "github.com/tendermint/tendermint/libs/log" ) @@ -36,26 +37,27 @@ func (k Keeper) SetUpgradeHandler(name string, upgradeHandler types.UpgradeHandl // ScheduleUpgrade schedules an upgrade based on the specified plan. // If there is another Plan already scheduled, it will overwrite it // (implicitly cancelling the current plan) -func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) sdk.Error { +func (k Keeper) ScheduleUpgrade(ctx sdk.Context, plan types.Plan) error { if err := plan.ValidateBasic(); err != nil { return err } if !plan.Time.IsZero() { if !plan.Time.After(ctx.BlockHeader().Time) { - return sdk.ErrUnknownRequest("upgrade cannot be scheduled in the past") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "upgrade cannot be scheduled in the past") } } else if plan.Height <= ctx.BlockHeight() { - return sdk.ErrUnknownRequest("upgrade cannot be scheduled in the past") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "upgrade cannot be scheduled in the past") } if k.getDoneHeight(ctx, plan.Name) != 0 { - return sdk.ErrUnknownRequest(fmt.Sprintf("upgrade with name %s has already been completed", plan.Name)) + return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "upgrade with name %s has already been completed", plan.Name) } bz := k.cdc.MustMarshalBinaryBare(plan) store := ctx.KVStore(k.storeKey) store.Set(types.PlanKey(), bz) + return nil } diff --git a/x/upgrade/internal/keeper/querier.go b/x/upgrade/internal/keeper/querier.go index 291f7bb9d049..164a2340c0a7 100644 --- a/x/upgrade/internal/keeper/querier.go +++ b/x/upgrade/internal/keeper/querier.go @@ -2,16 +2,16 @@ package keeper import ( "encoding/binary" - "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/upgrade/internal/types" abci "github.com/tendermint/tendermint/abci/types" ) // NewQuerier creates a querier for upgrade cli and REST endpoints func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case types.QueryCurrent: @@ -21,38 +21,40 @@ func NewQuerier(k Keeper) sdk.Querier { return queryApplied(ctx, req, k) default: - return nil, sdk.ErrUnknownRequest("unknown supply query endpoint") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } } } -func queryCurrent(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryCurrent(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { plan, has := k.GetUpgradePlan(ctx) if !has { - // empty data - client can respond Not Found return nil, nil } + res, err := k.cdc.MarshalJSON(&plan) if err != nil { - return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) } + return res, nil } -func queryApplied(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func queryApplied(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) { var params types.QueryAppliedParams err := k.cdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { - return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) } applied := k.getDoneHeight(ctx, params.Name) if applied == 0 { - // empty data - client can respond Not Found return nil, nil } + bz := make([]byte, 8) binary.BigEndian.PutUint64(bz, uint64(applied)) + return bz, nil } diff --git a/x/upgrade/internal/types/plan.go b/x/upgrade/internal/types/plan.go index 24fd28b72005..c2b88171e218 100644 --- a/x/upgrade/internal/types/plan.go +++ b/x/upgrade/internal/types/plan.go @@ -6,6 +6,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // Plan specifies information about a planned upgrade and when it should occur @@ -40,19 +41,20 @@ func (p Plan) String() string { } // ValidateBasic does basic validation of a Plan -func (p Plan) ValidateBasic() sdk.Error { +func (p Plan) ValidateBasic() error { if len(p.Name) == 0 { - return sdk.ErrUnknownRequest("name cannot be empty") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "name cannot be empty") } if p.Height < 0 { - return sdk.ErrUnknownRequest("height cannot be negative") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "height cannot be negative") } if p.Time.IsZero() && p.Height == 0 { - return sdk.ErrUnknownRequest("must set either time or height") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "must set either time or height") } if !p.Time.IsZero() && p.Height != 0 { - return sdk.ErrUnknownRequest("cannot set both time and height") + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "cannot set both time and height") } + return nil } diff --git a/x/upgrade/internal/types/proposal.go b/x/upgrade/internal/types/proposal.go index 3dc54f494f60..958c10674645 100644 --- a/x/upgrade/internal/types/proposal.go +++ b/x/upgrade/internal/types/proposal.go @@ -3,14 +3,12 @@ package types import ( "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov" ) const ( - ProposalTypeSoftwareUpgrade string = "SoftwareUpgrade" - ProposalTypeCancelSoftwareUpgrade string = "CancelSoftwareUpgrade" - DefaultCodespace sdk.CodespaceType = "upgrade" + ProposalTypeSoftwareUpgrade string = "SoftwareUpgrade" + ProposalTypeCancelSoftwareUpgrade string = "CancelSoftwareUpgrade" ) // Software Upgrade Proposals @@ -39,11 +37,11 @@ func (sup SoftwareUpgradeProposal) GetTitle() string { return sup.Title } func (sup SoftwareUpgradeProposal) GetDescription() string { return sup.Description } func (sup SoftwareUpgradeProposal) ProposalRoute() string { return RouterKey } func (sup SoftwareUpgradeProposal) ProposalType() string { return ProposalTypeSoftwareUpgrade } -func (sup SoftwareUpgradeProposal) ValidateBasic() sdk.Error { +func (sup SoftwareUpgradeProposal) ValidateBasic() error { if err := sup.Plan.ValidateBasic(); err != nil { return err } - return gov.ValidateAbstract(DefaultCodespace, sup) + return gov.ValidateAbstract(sup) } func (sup SoftwareUpgradeProposal) String() string { @@ -73,8 +71,8 @@ func (sup CancelSoftwareUpgradeProposal) ProposalRoute() string { return Router func (sup CancelSoftwareUpgradeProposal) ProposalType() string { return ProposalTypeCancelSoftwareUpgrade } -func (sup CancelSoftwareUpgradeProposal) ValidateBasic() sdk.Error { - return gov.ValidateAbstract(DefaultCodespace, sup) +func (sup CancelSoftwareUpgradeProposal) ValidateBasic() error { + return gov.ValidateAbstract(sup) } func (sup CancelSoftwareUpgradeProposal) String() string {