From e4f2fa04230a4fb27b360299ca72900b7eebb566 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 8 Jul 2021 17:25:40 +0800 Subject: [PATCH] feat!: support debug trace QueryResult (#9576) ## Description To let abci query response include more detailed error message with node started with `--trace`. --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [x] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [x] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [x] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) --- CHANGELOG.md | 1 + baseapp/abci.go | 37 +++++++++++++++++-------------------- store/iavl/store.go | 4 ++-- store/rootmulti/store.go | 10 +++++----- types/errors/abci.go | 4 ++-- 5 files changed, 27 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18bfb37b1..5abe6fcf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#9533](https://github.com/cosmos/cosmos-sdk/pull/9533) Added a new gRPC method, `DenomOwners`, in `x/bank` to query for all account holders of a specific denomination. * (bank) [\#9618](https://github.com/cosmos/cosmos-sdk/pull/9618) Update bank.Metadata: add URI and URIHash attributes. +* [\#9576](https://github.com/cosmos/cosmos-sdk/pull/9576) Add debug error message to query result when enabled ### API Breaking Changes diff --git a/baseapp/abci.go b/baseapp/abci.go index 3464a5d43..925f2f6b0 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -405,7 +405,7 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { // ref: https://github.com/cosmos/cosmos-sdk/pull/8039 defer func() { if r := recover(); r != nil { - res = sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrPanic, "%v", r)) + res = sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrPanic, "%v", r), app.trace) } }() @@ -422,7 +422,7 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { path := splitPath(req.Path) if len(path) == 0 { - sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no query path provided")) + sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no query path provided"), app.trace) } switch path[0] { @@ -440,7 +440,7 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { return handleQueryCustom(app, path, req) } - return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query path")) + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query path"), app.trace) } // ListSnapshots implements the ABCI interface. It delegates to app.snapshotManager if set. @@ -570,12 +570,12 @@ func (app *BaseApp) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) abci. func (app *BaseApp) handleQueryGRPC(handler GRPCQueryHandler, req abci.RequestQuery) abci.ResponseQuery { ctx, err := app.createQueryContext(req.Height, req.Prove) if err != nil { - return sdkerrors.QueryResult(err) + return sdkerrors.QueryResult(err, app.trace) } res, err := handler(ctx, req) if err != nil { - res = sdkerrors.QueryResult(gRPCErrorToSDKError(err)) + res = sdkerrors.QueryResult(gRPCErrorToSDKError(err), app.trace) res.Height = req.Height return res } @@ -746,7 +746,7 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res gInfo, res, err := app.Simulate(txBytes) if err != nil { - return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to simulate tx")) + return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to simulate tx"), app.trace) } simRes := &sdk.SimulationResponse{ @@ -756,7 +756,7 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res bz, err := codec.ProtoMarshalJSON(simRes, app.interfaceRegistry) if err != nil { - return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to JSON encode simulation response")) + return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to JSON encode simulation response"), app.trace) } return abci.ResponseQuery{ @@ -773,7 +773,7 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res } default: - return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query: %s", path)) + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown query: %s", path), app.trace) } } @@ -781,15 +781,14 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res sdkerrors.Wrap( sdkerrors.ErrUnknownRequest, "expected second parameter to be either 'simulate' or 'version', neither was present", - ), - ) + ), app.trace) } func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery { // "/store" prefix for store queries queryable, ok := app.cms.(sdk.Queryable) if !ok { - return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "multistore doesn't support queries")) + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "multistore doesn't support queries"), app.trace) } req.Path = "/" + strings.Join(path[1:], "/") @@ -799,8 +798,7 @@ func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.R sdkerrors.Wrap( sdkerrors.ErrInvalidRequest, "cannot query with proof when height <= 1; please provide a valid height", - ), - ) + ), app.trace) } resp := queryable.Query(req) @@ -815,8 +813,7 @@ func handleQueryP2P(app *BaseApp, path []string) abci.ResponseQuery { return sdkerrors.QueryResult( sdkerrors.Wrap( sdkerrors.ErrUnknownRequest, "path should be p2p filter ", - ), - ) + ), app.trace) } var resp abci.ResponseQuery @@ -833,7 +830,7 @@ func handleQueryP2P(app *BaseApp, path []string) abci.ResponseQuery { } default: - resp = sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "expected second parameter to be 'filter'")) + resp = sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "expected second parameter to be 'filter'"), app.trace) } return resp @@ -846,17 +843,17 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) abci. // 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 sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no route for custom query specified")) + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no route for custom query specified"), app.trace) } querier := app.queryRouter.Route(path[1]) if querier == nil { - return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "no custom querier found for route %s", path[1])) + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "no custom querier found for route %s", path[1]), app.trace) } ctx, err := app.createQueryContext(req.Height, req.Prove) if err != nil { - return sdkerrors.QueryResult(err) + return sdkerrors.QueryResult(err, app.trace) } // Passes the rest of the path as an argument to the querier. @@ -865,7 +862,7 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) abci. // []string{"proposal", "test"} as the path. resBytes, err := querier(ctx, path[2:], req) if err != nil { - res := sdkerrors.QueryResult(err) + res := sdkerrors.QueryResult(err, app.trace) res.Height = req.Height return res } diff --git a/store/iavl/store.go b/store/iavl/store.go index 440b26754..9b63a9a80 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -279,7 +279,7 @@ func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { defer telemetry.MeasureSince(time.Now(), "store", "iavl", "query") if len(req.Data) == 0 { - return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrTxDecode, "query cannot be zero length")) + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrTxDecode, "query cannot be zero length"), false) } tree := st.tree @@ -339,7 +339,7 @@ func (st *Store) Query(req abci.RequestQuery) (res abci.ResponseQuery) { res.Value = bz default: - return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unexpected query path: %v", req.Path)) + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unexpected query path: %v", req.Path), false) } return res diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 471a24efe..da095d680 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -529,17 +529,17 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { path := req.Path storeName, subpath, err := parsePath(path) if err != nil { - return sdkerrors.QueryResult(err) + return sdkerrors.QueryResult(err, false) } store := rs.getStoreByName(storeName) if store == nil { - return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "no such store: %s", storeName)) + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "no such store: %s", storeName), false) } queryable, ok := store.(types.Queryable) if !ok { - return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "store %s (type %T) doesn't support queries", storeName, store)) + return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "store %s (type %T) doesn't support queries", storeName, store), false) } // trim the path and make the query @@ -551,7 +551,7 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { } if res.ProofOps == nil || len(res.ProofOps.Ops) == 0 { - return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "proof is unexpectedly empty; ensure height has not been pruned")) + return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "proof is unexpectedly empty; ensure height has not been pruned"), false) } // If the request's height is the latest height we've committed, then utilize @@ -564,7 +564,7 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery { } else { commitInfo, err = getCommitInfo(rs.db, res.Height) if err != nil { - return sdkerrors.QueryResult(err) + return sdkerrors.QueryResult(err, false) } } diff --git a/types/errors/abci.go b/types/errors/abci.go index df85f6bc8..3f19d140c 100644 --- a/types/errors/abci.go +++ b/types/errors/abci.go @@ -67,8 +67,8 @@ func ResponseDeliverTx(err error, gw, gu uint64, debug bool) abci.ResponseDelive // 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) +func QueryResult(err error, debug bool) abci.ResponseQuery { + space, code, log := ABCIInfo(err, debug) return abci.ResponseQuery{ Codespace: space, Code: code,