From 8c57bce806839dc3f9d4b8574dbf63c919af5b32 Mon Sep 17 00:00:00 2001 From: Mathieu Hofman Date: Thu, 16 Nov 2023 19:05:39 +0000 Subject: [PATCH 1/2] fix(cli): handle not found error in vstorage requests --- packages/agoric-cli/src/lib/rpc.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/agoric-cli/src/lib/rpc.js b/packages/agoric-cli/src/lib/rpc.js index 893922b7d94..fb6dc58d4f8 100644 --- a/packages/agoric-cli/src/lib/rpc.js +++ b/packages/agoric-cli/src/lib/rpc.js @@ -79,9 +79,13 @@ export const makeVStorage = (powers, config = networkConfig) => { result: { response }, } = data; if (response?.code !== 0) { - throw Error( + /** @type {any} */ + const err = Error( `error code ${response?.code} reading ${kind} of ${path}: ${response.log}`, ); + err.code = response?.code; + err.codespace = response?.codespace; + throw err; } return data; }); @@ -143,7 +147,14 @@ export const makeVStorage = (powers, config = networkConfig) => { )); // console.debug('readAt returned', { blockHeight }); } catch (err) { - if (err.message.match(/unknown request/)) { + if ( + // CosmosSDK ErrNotFound; there is no data at the path + (err.codespace === 'sdk' && err.code === 38) || + // CosmosSDK ErrUnknownRequest; misrepresentation of the same until + // https://github.com/Agoric/agoric-sdk/commit/dafc7c1708977aaa55e245dc09a73859cf1df192 + // TODO remove after upgrade-12 + err.message.match(/unknown request/) + ) { // console.error(err); break; } From 21db80e577f15bc7701a49b43abda3a06c4e68ec Mon Sep 17 00:00:00 2001 From: Mathieu Hofman Date: Fri, 17 Nov 2023 02:21:48 +0000 Subject: [PATCH 2/2] chore(x/vstorage): add querier test --- .../cosmos/x/vstorage/keeper/querier_test.go | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 golang/cosmos/x/vstorage/keeper/querier_test.go diff --git a/golang/cosmos/x/vstorage/keeper/querier_test.go b/golang/cosmos/x/vstorage/keeper/querier_test.go new file mode 100644 index 00000000000..c07494bb168 --- /dev/null +++ b/golang/cosmos/x/vstorage/keeper/querier_test.go @@ -0,0 +1,112 @@ +package keeper + +import ( + "bytes" + "testing" + + agoric "github.com/Agoric/agoric-sdk/golang/cosmos/types" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +func TestQuerier(t *testing.T) { + testKit := makeTestKit() + ctx, keeper := testKit.ctx, testKit.vstorageKeeper + legacyQuerierCdc := codec.NewAminoCodec(codec.NewLegacyAmino()) + querier := NewQuerier(keeper, legacyQuerierCdc.LegacyAmino) + + // Populate mock data + keeper.SetStorage(ctx, agoric.NewKVEntry("foo.bar", "42")) + keeper.SetStorage(ctx, agoric.NewKVEntry("foo.baz", "hello")) + + type testCase struct { + label string + path []string + expected []byte + err *sdkerrors.Error + } + testCases := []testCase{} + + // Test invalid endpoint + testCases = append(testCases, []testCase{ + {label: "invalid endpoint", + path: []string{"foo"}, + err: sdkerrors.ErrUnknownRequest, + }, + }...) + + // Test invalid arguments to valid data and children endpoints + for _, endpoint := range []string{"data", "children"} { + testCases = append(testCases, []testCase{ + {label: endpoint + ": no entry path", + path: []string{endpoint}, + err: sdkerrors.ErrInvalidRequest, + }, + {label: endpoint + ": too many segments", + path: []string{endpoint, "foo", "bar"}, + err: sdkerrors.ErrInvalidRequest, + }, + {label: endpoint + ": invalid path", + path: []string{endpoint, ".", ""}, + err: sdkerrors.ErrInvalidRequest, + }, + }...) + } + + // Test data endpoint with valid vstorage path + testCases = append(testCases, []testCase{ + {label: "data: non-existent path", + path: []string{"data", "bar"}, + // DO NOT CHANGE + // The UI and CLI check for the specific cosmos-sdk error code & codespace + err: sdkerrors.ErrNotFound, + }, + {label: "data: path with no data", + path: []string{"data", "foo"}, + // DO NOT CHANGE + // The UI and CLI check for the specific cosmos-sdk error code & codespace + err: sdkerrors.ErrNotFound, + }, + {label: "data: path with data", + path: []string{"data", "foo.bar"}, + expected: []byte("{\n \"value\": \"42\"\n}"), + }, + }...) + + // Ensure stability of cosmos-sdk error codes + if codespace, code, _ := sdkerrors.ABCIInfo(sdkerrors.ErrNotFound, true); codespace != "sdk" || code != 38 { + t.Errorf("cosmos-sdk ErrNotFound has codespace %s, code %d, expected sdk/38", codespace, code) + } + + // Test children endpoint with valid vstorage path + testCases = append(testCases, []testCase{ + {label: "children: non-existent path", + path: []string{"children", "bar"}, + expected: []byte("{\n \"children\": []\n}"), + }, + {label: "children: path with no children", + path: []string{"children", "foo.bar"}, + expected: []byte("{\n \"children\": []\n}"), + }, + {label: "children: path with children", + path: []string{"children", "foo"}, + expected: []byte("{\n \"children\": [\n \"bar\",\n \"baz\"\n ]\n}"), + }, + }...) + + for _, desc := range testCases { + res, err := querier(ctx, desc.path, abci.RequestQuery{}) + if desc.err != nil { + if err == nil { + t.Errorf("%s: got no error, want error %q", desc.label, *desc.err) + } else if codespace, code, _ := sdkerrors.ABCIInfo(err, true); codespace != desc.err.Codespace() || code != desc.err.ABCICode() { + t.Errorf("%s: got error %v, want error %q", desc.label, err, *desc.err) + } + } else if !bytes.Equal(res, desc.expected) { + t.Errorf("%s: wrong result: %#v, expected %#v", desc.label, string(res), string(desc.expected)) + } + } +}