@agoric/cosmos 0.34.2-dev-9f89f97.0 → 0.34.2-dev-dafc7c1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/git-revision.txt +1 -1
- package/package.json +2 -2
- package/x/vstorage/keeper/querier.go +31 -11
- package/x/vstorage/types/path_keys.go +22 -10
- package/x/vstorage/types/path_keys_test.go +84 -18
package/git-revision.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
dafc7c1
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/cosmos",
|
|
3
|
-
"version": "0.34.2-dev-
|
|
3
|
+
"version": "0.34.2-dev-dafc7c1.0+dafc7c1",
|
|
4
4
|
"description": "Connect JS to the Cosmos blockchain SDK",
|
|
5
5
|
"parsers": {
|
|
6
6
|
"js": "mjs"
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "dafc7c1708977aaa55e245dc09a73859cf1df192"
|
|
39
39
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
package keeper
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
-
"strings"
|
|
5
|
-
|
|
6
4
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
7
5
|
|
|
8
6
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
@@ -18,14 +16,36 @@ const (
|
|
|
18
16
|
QueryChildren = "children"
|
|
19
17
|
)
|
|
20
18
|
|
|
21
|
-
//
|
|
19
|
+
// getVstorageEntryPath validates that a request URL path represents a valid
|
|
20
|
+
// entry path with no extra data, and returns the path of that vstorage entry.
|
|
21
|
+
func getVstorageEntryPath(urlPathSegments []string) (string, error) {
|
|
22
|
+
if len(urlPathSegments) != 1 || types.ValidatePath(urlPathSegments[0]) != nil {
|
|
23
|
+
return "", sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid vstorage entry path")
|
|
24
|
+
}
|
|
25
|
+
return urlPathSegments[0], nil
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// NewQuerier returns the function for handling queries routed to this module.
|
|
29
|
+
// It performs its own routing based on the first slash-separated URL path
|
|
30
|
+
// segment (e.g., URL path `/data/foo.bar` is a request for the value associated
|
|
31
|
+
// with vstorage path "foo.bar", and `/children/foo.bar` is a request for the
|
|
32
|
+
// child path segments immediately underneath vstorage path "foo.bar" which may
|
|
33
|
+
// be used to extend it to a vstorage path such as "foo.bar.baz").
|
|
22
34
|
func NewQuerier(keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) sdk.Querier {
|
|
23
|
-
return func(ctx sdk.Context,
|
|
24
|
-
switch
|
|
35
|
+
return func(ctx sdk.Context, urlPathSegments []string, req abci.RequestQuery) (res []byte, err error) {
|
|
36
|
+
switch urlPathSegments[0] {
|
|
25
37
|
case QueryData:
|
|
26
|
-
|
|
38
|
+
entryPath, entryPathErr := getVstorageEntryPath(urlPathSegments[1:])
|
|
39
|
+
if entryPathErr != nil {
|
|
40
|
+
return nil, entryPathErr
|
|
41
|
+
}
|
|
42
|
+
return queryData(ctx, entryPath, req, keeper, legacyQuerierCdc)
|
|
27
43
|
case QueryChildren:
|
|
28
|
-
|
|
44
|
+
entryPath, entryPathErr := getVstorageEntryPath(urlPathSegments[1:])
|
|
45
|
+
if entryPathErr != nil {
|
|
46
|
+
return nil, entryPathErr
|
|
47
|
+
}
|
|
48
|
+
return queryChildren(ctx, entryPath, req, keeper, legacyQuerierCdc)
|
|
29
49
|
default:
|
|
30
50
|
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown vstorage query endpoint")
|
|
31
51
|
}
|
|
@@ -36,12 +56,12 @@ func NewQuerier(keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) sdk.Querier
|
|
|
36
56
|
func queryData(ctx sdk.Context, path string, req abci.RequestQuery, keeper Keeper, legacyQuerierCdc *codec.LegacyAmino) (res []byte, err error) {
|
|
37
57
|
entry := keeper.GetEntry(ctx, path)
|
|
38
58
|
if !entry.HasValue() {
|
|
39
|
-
return nil, sdkerrors.Wrap(sdkerrors.
|
|
59
|
+
return nil, sdkerrors.Wrap(sdkerrors.ErrNotFound, "no data for vstorage path")
|
|
40
60
|
}
|
|
41
61
|
|
|
42
|
-
bz,
|
|
43
|
-
if
|
|
44
|
-
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal,
|
|
62
|
+
bz, marshalErr := codec.MarshalJSONIndent(legacyQuerierCdc, types.Data{Value: entry.StringValue()})
|
|
63
|
+
if marshalErr != nil {
|
|
64
|
+
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, marshalErr.Error())
|
|
45
65
|
}
|
|
46
66
|
|
|
47
67
|
return bz, nil
|
|
@@ -7,9 +7,17 @@ import (
|
|
|
7
7
|
"strings"
|
|
8
8
|
)
|
|
9
9
|
|
|
10
|
-
// - A "path" is a sequence of zero or more dot-separated nonempty
|
|
11
|
-
//
|
|
12
|
-
//
|
|
10
|
+
// - A "path" is a sequence of zero or more dot-separated nonempty segments
|
|
11
|
+
// using a restricted alphabet of ASCII alphanumerics plus underscore and dash,
|
|
12
|
+
// consistent with packages/internal/src/lib-chainStorage.js but not currently
|
|
13
|
+
// enforcing a length restriction on path segments.
|
|
14
|
+
// So `""`, `"foo"`, and `"foo.bar__baz.qux--quux"` are paths but `"."`,
|
|
15
|
+
// `"foo/bar"`, `"fo\to"`, and `"foö"` are not.
|
|
16
|
+
// This alphabet might be expanded in the future, but such expansion SHOULD NOT
|
|
17
|
+
// include control characters (including those that are not ASCII, such as
|
|
18
|
+
// U+202E RIGHT-TO-LEFT OVERRIDE), slash `/` (which separates ABCI request path
|
|
19
|
+
// segments in e.g. `custom/vstorage/data/foo`), or backslash `\` (which should
|
|
20
|
+
// be reserved for adding escape sequences).
|
|
13
21
|
//
|
|
14
22
|
// - An encoded key for a path is the path prefixed with its length (in ASCII
|
|
15
23
|
// digits), separated by nul, followed by the path with dots replaced with nul.
|
|
@@ -42,22 +50,26 @@ func EncodedKeyToPath(key []byte) string {
|
|
|
42
50
|
return string(pathBytes)
|
|
43
51
|
}
|
|
44
52
|
|
|
45
|
-
var
|
|
53
|
+
var pathSegmentPattern = `[a-zA-Z0-9_-]+`
|
|
54
|
+
var pathSeparatorPattern = `\` + PathSeparator
|
|
55
|
+
var pathPattern = fmt.Sprintf(`^$|^%[1]s(%[2]s%[1]s)*$`, pathSegmentPattern, pathSeparatorPattern)
|
|
56
|
+
var pathMatcher = regexp.MustCompile(pathPattern)
|
|
46
57
|
|
|
47
58
|
func ValidatePath(path string) error {
|
|
48
|
-
if
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
|
-
if strings.Contains(path, PathSeparator+PathSeparator) {
|
|
52
|
-
return fmt.Errorf("path %q contains doubled separators", path)
|
|
59
|
+
if pathMatcher.MatchString(path) {
|
|
60
|
+
return nil
|
|
53
61
|
}
|
|
62
|
+
// Rescan the string to give a useful error message.
|
|
54
63
|
if strings.HasPrefix(path, PathSeparator) {
|
|
55
64
|
return fmt.Errorf("path %q starts with separator", path)
|
|
56
65
|
}
|
|
57
66
|
if strings.HasSuffix(path, PathSeparator) {
|
|
58
67
|
return fmt.Errorf("path %q ends with separator", path)
|
|
59
68
|
}
|
|
60
|
-
|
|
69
|
+
if strings.Contains(path, PathSeparator+PathSeparator) {
|
|
70
|
+
return fmt.Errorf("path %q contains doubled separators", path)
|
|
71
|
+
}
|
|
72
|
+
return fmt.Errorf("path %q contains invalid characters", path)
|
|
61
73
|
}
|
|
62
74
|
|
|
63
75
|
// PathToEncodedKey converts a path to a byte slice key
|
|
@@ -2,40 +2,106 @@ package types
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"bytes"
|
|
5
|
+
"fmt"
|
|
6
|
+
"strings"
|
|
5
7
|
"testing"
|
|
6
8
|
)
|
|
7
9
|
|
|
8
10
|
func Test_Key_Encoding(t *testing.T) {
|
|
9
11
|
tests := []struct {
|
|
10
|
-
name
|
|
11
|
-
|
|
12
|
-
key
|
|
12
|
+
name string
|
|
13
|
+
path string
|
|
14
|
+
key []byte
|
|
15
|
+
errContains string
|
|
13
16
|
}{
|
|
14
17
|
{
|
|
15
|
-
name:
|
|
16
|
-
|
|
17
|
-
key:
|
|
18
|
+
name: "empty path",
|
|
19
|
+
path: "",
|
|
20
|
+
key: []byte("0\x00"),
|
|
18
21
|
},
|
|
19
22
|
{
|
|
20
|
-
name:
|
|
21
|
-
|
|
22
|
-
key:
|
|
23
|
+
name: "single-segment path",
|
|
24
|
+
path: "some",
|
|
25
|
+
key: []byte("1\x00some"),
|
|
23
26
|
},
|
|
24
27
|
{
|
|
25
|
-
name:
|
|
26
|
-
|
|
27
|
-
key:
|
|
28
|
+
name: "multi-segment path",
|
|
29
|
+
path: "some.child.grandchild",
|
|
30
|
+
key: []byte("3\x00some\x00child\x00grandchild"),
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "non-letters",
|
|
34
|
+
path: "-_0_-",
|
|
35
|
+
key: []byte("1\x00-_0_-"),
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "lone dot",
|
|
39
|
+
path: ".",
|
|
40
|
+
errContains: "starts with separator",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "starts with dot",
|
|
44
|
+
path: ".foo",
|
|
45
|
+
errContains: "starts with separator",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "ends with dot",
|
|
49
|
+
path: "foo.",
|
|
50
|
+
errContains: "ends with separator",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "empty path segment",
|
|
54
|
+
path: "foo..bar",
|
|
55
|
+
errContains: "doubled separators",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "invalid path character U+0000 NUL",
|
|
59
|
+
path: "foo\x00bar",
|
|
60
|
+
errContains: "invalid character",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "invalid path character U+002F SOLIDUS",
|
|
64
|
+
path: "foo/bar",
|
|
65
|
+
errContains: "invalid character",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "invalid path character U+005C REVERSE SOLIDUS",
|
|
69
|
+
path: "foo\\bar",
|
|
70
|
+
errContains: "invalid character",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "invalid path character U+007C VERTICAL LINE",
|
|
74
|
+
path: "foo|bar",
|
|
75
|
+
errContains: "invalid character",
|
|
28
76
|
},
|
|
29
77
|
}
|
|
30
78
|
|
|
31
79
|
for _, tt := range tests {
|
|
80
|
+
if tt.key != nil {
|
|
81
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
82
|
+
if key := PathToEncodedKey(tt.path); !bytes.Equal(key, tt.key) {
|
|
83
|
+
t.Errorf("pathToKey(%q) = []byte(%q), want []byte(%q)", tt.path, key, tt.key)
|
|
84
|
+
}
|
|
85
|
+
if path := EncodedKeyToPath(tt.key); path != tt.path {
|
|
86
|
+
t.Errorf("keyToPath([]byte(%q)) = %q, want %q", tt.key, path, tt.path)
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
continue
|
|
90
|
+
}
|
|
91
|
+
expect := tt.errContains
|
|
32
92
|
t.Run(tt.name, func(t *testing.T) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
93
|
+
var key []byte
|
|
94
|
+
defer func() {
|
|
95
|
+
if err := recover(); err != nil {
|
|
96
|
+
errStr := fmt.Sprintf("%v", err)
|
|
97
|
+
if !strings.Contains(errStr, expect) {
|
|
98
|
+
t.Errorf("pathToKey(%q) = error %q, want error %v", tt.path, errStr, expect)
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
t.Errorf("pathToKey(%q) = []byte(%q), want error %v", tt.path, key, expect)
|
|
102
|
+
}
|
|
103
|
+
}()
|
|
104
|
+
key = PathToEncodedKey(tt.path)
|
|
39
105
|
})
|
|
40
106
|
}
|
|
41
107
|
}
|