@agoric/cosmos 0.34.2-dev-7cc5def.0 → 0.35.0-u11.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/CHANGELOG.md +45 -0
- package/app/app.go +10 -1
- package/cmd/agd/main.go +5 -2
- package/daemon/cmd/root.go +93 -3
- package/git-revision.txt +1 -1
- package/package.json +3 -3
- package/proto/agoric/vstorage/query.proto +1 -53
- package/x/swingset/genesis.go +88 -15
- package/x/swingset/keeper/swing_store_exports_handler.go +64 -42
- package/x/swingset/module.go +22 -10
- package/x/swingset/types/default-params.go +1 -1
- package/x/swingset/types/msgs.pb.go +16 -16
- package/x/vibc/ibc.go +2 -1
- package/x/vibc/keeper/keeper.go +15 -1
- package/x/vibc/types/expected_keepers.go +1 -2
- package/x/vstorage/keeper/grpc_query.go +0 -221
- package/x/vstorage/types/query.pb.go +36 -646
- package/x/vstorage/types/query.pb.gw.go +0 -119
- package/x/vstorage/README.md +0 -95
- package/x/vstorage/capdata/capdata.go +0 -298
- package/x/vstorage/capdata/capdata_test.go +0 -352
- package/x/vstorage/keeper/keeper_grpc_test.go +0 -300
|
@@ -87,78 +87,6 @@ func local_request_Query_Data_0(ctx context.Context, marshaler runtime.Marshaler
|
|
|
87
87
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
var (
|
|
91
|
-
filter_Query_CapData_0 = &utilities.DoubleArray{Encoding: map[string]int{"path": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
func request_Query_CapData_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
|
95
|
-
var protoReq QueryCapDataRequest
|
|
96
|
-
var metadata runtime.ServerMetadata
|
|
97
|
-
|
|
98
|
-
var (
|
|
99
|
-
val string
|
|
100
|
-
ok bool
|
|
101
|
-
err error
|
|
102
|
-
_ = err
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
val, ok = pathParams["path"]
|
|
106
|
-
if !ok {
|
|
107
|
-
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "path")
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
protoReq.Path, err = runtime.String(val)
|
|
111
|
-
|
|
112
|
-
if err != nil {
|
|
113
|
-
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "path", err)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if err := req.ParseForm(); err != nil {
|
|
117
|
-
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
|
118
|
-
}
|
|
119
|
-
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_CapData_0); err != nil {
|
|
120
|
-
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
msg, err := client.CapData(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
|
124
|
-
return msg, metadata, err
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
func local_request_Query_CapData_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
|
129
|
-
var protoReq QueryCapDataRequest
|
|
130
|
-
var metadata runtime.ServerMetadata
|
|
131
|
-
|
|
132
|
-
var (
|
|
133
|
-
val string
|
|
134
|
-
ok bool
|
|
135
|
-
err error
|
|
136
|
-
_ = err
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
val, ok = pathParams["path"]
|
|
140
|
-
if !ok {
|
|
141
|
-
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "path")
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
protoReq.Path, err = runtime.String(val)
|
|
145
|
-
|
|
146
|
-
if err != nil {
|
|
147
|
-
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "path", err)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if err := req.ParseForm(); err != nil {
|
|
151
|
-
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
|
152
|
-
}
|
|
153
|
-
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_CapData_0); err != nil {
|
|
154
|
-
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
msg, err := server.CapData(ctx, &protoReq)
|
|
158
|
-
return msg, metadata, err
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
90
|
var (
|
|
163
91
|
filter_Query_Children_0 = &utilities.DoubleArray{Encoding: map[string]int{"path": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
|
164
92
|
)
|
|
@@ -260,29 +188,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
|
|
|
260
188
|
|
|
261
189
|
})
|
|
262
190
|
|
|
263
|
-
mux.Handle("GET", pattern_Query_CapData_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
|
264
|
-
ctx, cancel := context.WithCancel(req.Context())
|
|
265
|
-
defer cancel()
|
|
266
|
-
var stream runtime.ServerTransportStream
|
|
267
|
-
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
|
268
|
-
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
|
269
|
-
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
|
|
270
|
-
if err != nil {
|
|
271
|
-
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
|
272
|
-
return
|
|
273
|
-
}
|
|
274
|
-
resp, md, err := local_request_Query_CapData_0(rctx, inboundMarshaler, server, req, pathParams)
|
|
275
|
-
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
|
276
|
-
ctx = runtime.NewServerMetadataContext(ctx, md)
|
|
277
|
-
if err != nil {
|
|
278
|
-
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
|
279
|
-
return
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
forward_Query_CapData_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
|
283
|
-
|
|
284
|
-
})
|
|
285
|
-
|
|
286
191
|
mux.Handle("GET", pattern_Query_Children_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
|
287
192
|
ctx, cancel := context.WithCancel(req.Context())
|
|
288
193
|
defer cancel()
|
|
@@ -367,26 +272,6 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
|
|
|
367
272
|
|
|
368
273
|
})
|
|
369
274
|
|
|
370
|
-
mux.Handle("GET", pattern_Query_CapData_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
|
371
|
-
ctx, cancel := context.WithCancel(req.Context())
|
|
372
|
-
defer cancel()
|
|
373
|
-
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
|
374
|
-
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
|
375
|
-
if err != nil {
|
|
376
|
-
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
|
377
|
-
return
|
|
378
|
-
}
|
|
379
|
-
resp, md, err := request_Query_CapData_0(rctx, inboundMarshaler, client, req, pathParams)
|
|
380
|
-
ctx = runtime.NewServerMetadataContext(ctx, md)
|
|
381
|
-
if err != nil {
|
|
382
|
-
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
|
383
|
-
return
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
forward_Query_CapData_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
|
387
|
-
|
|
388
|
-
})
|
|
389
|
-
|
|
390
275
|
mux.Handle("GET", pattern_Query_Children_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
|
391
276
|
ctx, cancel := context.WithCancel(req.Context())
|
|
392
277
|
defer cancel()
|
|
@@ -413,15 +298,11 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
|
|
|
413
298
|
var (
|
|
414
299
|
pattern_Query_Data_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"agoric", "vstorage", "data", "path"}, "", runtime.AssumeColonVerbOpt(false)))
|
|
415
300
|
|
|
416
|
-
pattern_Query_CapData_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"agoric", "vstorage", "capdata", "path"}, "", runtime.AssumeColonVerbOpt(false)))
|
|
417
|
-
|
|
418
301
|
pattern_Query_Children_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"agoric", "vstorage", "children", "path"}, "", runtime.AssumeColonVerbOpt(false)))
|
|
419
302
|
)
|
|
420
303
|
|
|
421
304
|
var (
|
|
422
305
|
forward_Query_Data_0 = runtime.ForwardResponseMessage
|
|
423
306
|
|
|
424
|
-
forward_Query_CapData_0 = runtime.ForwardResponseMessage
|
|
425
|
-
|
|
426
307
|
forward_Query_Children_0 = runtime.ForwardResponseMessage
|
|
427
308
|
)
|
package/x/vstorage/README.md
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
# Virtual Storage
|
|
2
|
-
|
|
3
|
-
This module manages "[IAVL](https://github.com/cosmos/iavl)" chain storage data with a hierarchical keyspace in which each key is a "[path](./types/path_keys.go)" composed of zero or more dot-separated nonempty segments in a restricted alphabet. It exposes gRPC endpoints to arbitrary external clients for reading data, and internal read/write interfaces for use by SwingSet (which itself manages further subtree-scoped attenuation).
|
|
4
|
-
|
|
5
|
-
## Internal Go interface
|
|
6
|
-
|
|
7
|
-
[Keeper](./keeper/keeper.go)
|
|
8
|
-
* generic
|
|
9
|
-
* GetChildren
|
|
10
|
-
* GetEntry
|
|
11
|
-
* HasEntry
|
|
12
|
-
* HasStorage
|
|
13
|
-
* SetStorage[AndNotify]
|
|
14
|
-
* StreamCell-oriented (a StreamCell captures a block height and an array of values)
|
|
15
|
-
* AppendStorageValue[AndNotify]
|
|
16
|
-
* queue-oriented (a queue stores items at paths like "$prefix.$n", documenting
|
|
17
|
-
the n for the next item to be consumed at "$prefix.head" and the n for the next
|
|
18
|
-
next item to be pushed at "$prefix.tail" such that the queue is empty when both
|
|
19
|
-
head and tail store the same n)
|
|
20
|
-
* GetQueueLength
|
|
21
|
-
* PushQueueItem
|
|
22
|
-
|
|
23
|
-
## Internal JSON interface
|
|
24
|
-
|
|
25
|
-
This is used by the SwingSet "bridge".
|
|
26
|
-
|
|
27
|
-
[Receive](./vstorage.go) with input `{ "method": "...", "args": [...] }`
|
|
28
|
-
* generic
|
|
29
|
-
* method "entries", args path
|
|
30
|
-
* method "get"/"has", args path
|
|
31
|
-
* method "set"/"setWithoutNotify", args [[path, value?], ...]
|
|
32
|
-
* method "children", args path
|
|
33
|
-
* method "values", args path (returns values for children in the same order as method "children")
|
|
34
|
-
* method "size", args path (returns the count of children)
|
|
35
|
-
* StreamCell-oriented
|
|
36
|
-
* method "append", args [[path, value?], ...]
|
|
37
|
-
|
|
38
|
-
## CLI
|
|
39
|
-
|
|
40
|
-
A blockchain node may be interrogated by RPC using `agd [--node $url] query vstorage $command` via [client/cli](./client/cli/query.go).
|
|
41
|
-
* `children [--height $blockHeight] [-o {text,json}] [$path]`
|
|
42
|
-
* `data [--height $blockHeight] [-o {text,json}] $path`
|
|
43
|
-
|
|
44
|
-
Examples:
|
|
45
|
-
```sh
|
|
46
|
-
$ agd --node https://main.rpc.agoric.net:443/ query vstorage children published.reserve
|
|
47
|
-
children:
|
|
48
|
-
- governance
|
|
49
|
-
- metrics
|
|
50
|
-
pagination: null
|
|
51
|
-
|
|
52
|
-
$ agd --node https://main.rpc.agoric.net:443/ query vstorage children -o json published.reserve
|
|
53
|
-
{"children":["governance","metrics"],"pagination":null}
|
|
54
|
-
|
|
55
|
-
$ agd --node https://main.rpc.agoric.net:443/ query vstorage data published.reserve.metrics
|
|
56
|
-
value: '{"blockHeight":"11030240","values":["{\"body\":\"#{\\\"allocations\\\":{\\\"Fee\\\":{\\\"brand\\\":\\\"$0.Alleged:
|
|
57
|
-
IST brand\\\",\\\"value\\\":\\\"+20053582387\\\"}},\\\"shortfallBalance\\\":{\\\"brand\\\":\\\"$0\\\",\\\"value\\\":\\\"+0\\\"},\\\"totalFeeBurned\\\":{\\\"brand\\\":\\\"$0\\\",\\\"value\\\":\\\"+0\\\"},\\\"totalFeeMinted\\\":{\\\"brand\\\":\\\"$0\\\",\\\"value\\\":\\\"+0\\\"}}\",\"slots\":[\"board0257\"]}"]}'
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## External protobuf interface
|
|
61
|
-
|
|
62
|
-
RPC via [Querier](./keeper/grpc_query.go),
|
|
63
|
-
and [CometBFT method "abci_query"](https://docs.cometbft.com/main/rpc/#/ABCI/abci_query)
|
|
64
|
-
with params `path` "/agoric.vstorage.Query/..."
|
|
65
|
-
and `data` \<serialized protobuf per [vstorage/query.proto](../../proto/agoric/vstorage/query.proto)>
|
|
66
|
-
(also via [Querier](./keeper/grpc_query.go))
|
|
67
|
-
* /agoric.vstorage.Query/CapData
|
|
68
|
-
* /agoric.vstorage.Query/Children
|
|
69
|
-
* /agoric.vstorage.Query/Data
|
|
70
|
-
|
|
71
|
-
## External JSON interface
|
|
72
|
-
|
|
73
|
-
As described at [Cosmos SDK: Using the REST Endpoints](https://docs.cosmos.network/main/run-node/interact-node#using-the-rest-endpoints), a blockchain node whose [`app.toml` configuration](https://docs.cosmos.network/main/run-node/run-node#configuring-the-node-using-apptoml-and-configtoml) enables the "REST" API server uses [gRPC-Gateway](https://grpc-ecosystem.github.io/grpc-gateway/) and `google.api.http` annotations in [vstorage/query.proto](../../proto/agoric/vstorage/query.proto) to automatically translate the protobuf-based RPC endpoints into URL paths that accept query parameters and emit JSON.
|
|
74
|
-
* /agoric/vstorage/capdata/$path?remotableValueFormat={object,string}[&mediaType=JSON%20Lines][&itemFormat=flat]
|
|
75
|
-
* /agoric/vstorage/children/$path
|
|
76
|
-
* /agoric/vstorage/data/$path
|
|
77
|
-
|
|
78
|
-
Example:
|
|
79
|
-
```sh
|
|
80
|
-
$ curl -sS 'https://main.api.agoric.net/agoric/vstorage/children/published.committees'
|
|
81
|
-
{
|
|
82
|
-
"children": [
|
|
83
|
-
"Economic_Committee"
|
|
84
|
-
],
|
|
85
|
-
"pagination": null
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## Arbitrary-response HTTP interface
|
|
90
|
-
|
|
91
|
-
This depends upon appModule `LegacyQuerierHandler` functionality that is [removed from cosmos-sdk as of v0.47](https://github.com/cosmos/cosmos-sdk/blob/fa4d87ef7e6d87aaccc94c337ffd2fe90fcb7a9d/CHANGELOG.md#api-breaking-changes-3)
|
|
92
|
-
|
|
93
|
-
[legacy querier](./keeper/querier.go)
|
|
94
|
-
* /custom/vstorage/children/$path
|
|
95
|
-
* /custom/vstorage/data/$path
|
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
package capdata
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"bytes"
|
|
5
|
-
"encoding/json"
|
|
6
|
-
"fmt"
|
|
7
|
-
"regexp"
|
|
8
|
-
"strconv"
|
|
9
|
-
"strings"
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
// JsonMarshal returns JSON text representing its input,
|
|
13
|
-
// without special replacement of "<", ">", "&", U+2028, or U+2029.
|
|
14
|
-
func JsonMarshal(val any) ([]byte, error) {
|
|
15
|
-
buf := &bytes.Buffer{}
|
|
16
|
-
encoder := json.NewEncoder(buf)
|
|
17
|
-
encoder.SetEscapeHTML(false)
|
|
18
|
-
if err := encoder.Encode(val); err != nil {
|
|
19
|
-
return nil, err
|
|
20
|
-
}
|
|
21
|
-
// Return without a trailing line feed.
|
|
22
|
-
lineTerminatedJson := buf.Bytes()
|
|
23
|
-
return bytes.TrimSuffix(lineTerminatedJson, []byte("\n")), nil
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// cf. https://github.com/endojs/endo/tree/master/packages/marshal
|
|
27
|
-
|
|
28
|
-
type Capdata struct {
|
|
29
|
-
Body string `json:"body"`
|
|
30
|
-
Slots []interface{} `json:"slots"`
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
var validBigint = regexp.MustCompile(`^-?(?:0|[1-9][0-9]*)$`)
|
|
34
|
-
|
|
35
|
-
type CapdataBigint struct {
|
|
36
|
-
Normalized string
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
type CapdataRemotable struct {
|
|
40
|
-
Id interface{}
|
|
41
|
-
Iface *string
|
|
42
|
-
Representation interface{}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
func NewCapdataBigint(str string) *CapdataBigint {
|
|
46
|
-
if !validBigint.MatchString(str) {
|
|
47
|
-
return nil
|
|
48
|
-
}
|
|
49
|
-
bigint := CapdataBigint{str}
|
|
50
|
-
return &bigint
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
func (r *CapdataRemotable) MarshalJSON() ([]byte, error) {
|
|
54
|
-
return JsonMarshal(r.Representation)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
type CapdataValueTransformations struct {
|
|
58
|
-
Bigint func(*CapdataBigint) interface{}
|
|
59
|
-
Remotable func(*CapdataRemotable) interface{}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// upsertCapdataRemotable either adds a new CapdataRemotable to `remotables` at the specified
|
|
63
|
-
// slot index or updates the iface of the value that is already there, ensuring lack of iface name
|
|
64
|
-
// inconsistency (iteration order is not guaranteed to correspond with JSON text like it does in
|
|
65
|
-
// JavaScript, so we must accept encountering the "first" reference to a slot late
|
|
66
|
-
// and must therefore also defer transformations).
|
|
67
|
-
func upsertCapdataRemotable(remotables map[uint64]*CapdataRemotable, slotIndex uint64, id interface{}, iface *string) (*CapdataRemotable, error) {
|
|
68
|
-
r := remotables[slotIndex]
|
|
69
|
-
if r == nil {
|
|
70
|
-
r = new(CapdataRemotable)
|
|
71
|
-
r.Id = id
|
|
72
|
-
r.Iface = iface
|
|
73
|
-
remotables[slotIndex] = r
|
|
74
|
-
} else if iface != nil {
|
|
75
|
-
if r.Iface != nil && *iface != *r.Iface {
|
|
76
|
-
return nil, fmt.Errorf("slot iface mismatch: %q", *iface)
|
|
77
|
-
}
|
|
78
|
-
r.Iface = iface
|
|
79
|
-
}
|
|
80
|
-
return r, nil
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// decodeCapdataLegacyValue decodes the non-smallcaps encoding of
|
|
84
|
-
// https://github.com/endojs/endo/blob/master/packages/marshal/src/encodeToCapData.js
|
|
85
|
-
func decodeCapdataLegacyValue(
|
|
86
|
-
encoded interface{},
|
|
87
|
-
slots []interface{},
|
|
88
|
-
remotables map[uint64]*CapdataRemotable,
|
|
89
|
-
transformations CapdataValueTransformations,
|
|
90
|
-
) (interface{}, error) {
|
|
91
|
-
if arr, ok := encoded.([]interface{}); ok {
|
|
92
|
-
for i, v := range arr {
|
|
93
|
-
decoded, err := decodeCapdataLegacyValue(v, slots, remotables, transformations)
|
|
94
|
-
if err != nil {
|
|
95
|
-
return nil, err
|
|
96
|
-
}
|
|
97
|
-
arr[i] = decoded
|
|
98
|
-
}
|
|
99
|
-
return arr, nil
|
|
100
|
-
} else if obj, ok := encoded.(map[string]interface{}); ok {
|
|
101
|
-
if qclassVal, ok := obj["@qclass"]; ok {
|
|
102
|
-
qclass, ok := qclassVal.(string)
|
|
103
|
-
if !ok {
|
|
104
|
-
return nil, fmt.Errorf("invalid @qclass: %q", qclassVal)
|
|
105
|
-
}
|
|
106
|
-
switch qclass {
|
|
107
|
-
case "bigint":
|
|
108
|
-
var bigint *CapdataBigint
|
|
109
|
-
digitsVal := obj["digits"]
|
|
110
|
-
if digitsStr, ok := digitsVal.(string); ok {
|
|
111
|
-
bigint = NewCapdataBigint(digitsStr)
|
|
112
|
-
}
|
|
113
|
-
if bigint == nil {
|
|
114
|
-
return nil, fmt.Errorf("invalid bigint: %q", digitsVal)
|
|
115
|
-
}
|
|
116
|
-
if transformations.Bigint == nil {
|
|
117
|
-
return nil, fmt.Errorf("untransformed bigint")
|
|
118
|
-
}
|
|
119
|
-
return transformations.Bigint(bigint), nil
|
|
120
|
-
case "slot":
|
|
121
|
-
var iface *string
|
|
122
|
-
slotIndexVal, ifaceVal := obj["index"], obj["iface"]
|
|
123
|
-
slotIndexNum, ok := slotIndexVal.(float64)
|
|
124
|
-
slotIndex := uint64(slotIndexNum)
|
|
125
|
-
if !ok || float64(slotIndex) != slotIndexNum || slotIndex >= uint64(len(slots)) {
|
|
126
|
-
return nil, fmt.Errorf("invalid slot index: %q", slotIndexVal)
|
|
127
|
-
}
|
|
128
|
-
if ifaceStr, ok := ifaceVal.(string); ok {
|
|
129
|
-
iface = &ifaceStr
|
|
130
|
-
} else if ifaceVal != nil {
|
|
131
|
-
return nil, fmt.Errorf("invalid slot iface: %q", ifaceVal)
|
|
132
|
-
}
|
|
133
|
-
return upsertCapdataRemotable(remotables, slotIndex, slots[slotIndex], iface)
|
|
134
|
-
case "hilbert":
|
|
135
|
-
fallthrough
|
|
136
|
-
case "undefined":
|
|
137
|
-
fallthrough
|
|
138
|
-
case "NaN":
|
|
139
|
-
fallthrough
|
|
140
|
-
case "Infinity":
|
|
141
|
-
fallthrough
|
|
142
|
-
case "symbol":
|
|
143
|
-
fallthrough
|
|
144
|
-
case "tagged":
|
|
145
|
-
fallthrough
|
|
146
|
-
case "error":
|
|
147
|
-
fallthrough
|
|
148
|
-
case "-Infinity":
|
|
149
|
-
return nil, fmt.Errorf("not implemented: @qclass %q", qclass)
|
|
150
|
-
default:
|
|
151
|
-
return nil, fmt.Errorf("unrecognized @qclass: %q", qclass)
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
for k, v := range obj {
|
|
155
|
-
decoded, err := decodeCapdataLegacyValue(v, slots, remotables, transformations)
|
|
156
|
-
if err != nil {
|
|
157
|
-
return nil, err
|
|
158
|
-
}
|
|
159
|
-
obj[k] = decoded
|
|
160
|
-
}
|
|
161
|
-
return obj, nil
|
|
162
|
-
} else {
|
|
163
|
-
return encoded, nil
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// decodeCapdataSmallcapsValue decodes the "smallcaps" encoding from
|
|
168
|
-
// https://github.com/endojs/endo/blob/master/packages/marshal/src/encodeToSmallcaps.js
|
|
169
|
-
func decodeCapdataSmallcapsValue(
|
|
170
|
-
encoded interface{},
|
|
171
|
-
slots []interface{},
|
|
172
|
-
remotables map[uint64]*CapdataRemotable,
|
|
173
|
-
transformations CapdataValueTransformations,
|
|
174
|
-
) (interface{}, error) {
|
|
175
|
-
if arr, ok := encoded.([]interface{}); ok {
|
|
176
|
-
for i, v := range arr {
|
|
177
|
-
decoded, err := decodeCapdataSmallcapsValue(v, slots, remotables, transformations)
|
|
178
|
-
if err != nil {
|
|
179
|
-
return nil, err
|
|
180
|
-
}
|
|
181
|
-
arr[i] = decoded
|
|
182
|
-
}
|
|
183
|
-
return arr, nil
|
|
184
|
-
} else if encodedObj, ok := encoded.(map[string]interface{}); ok {
|
|
185
|
-
if _, ok := encodedObj["#tag"]; ok {
|
|
186
|
-
return nil, fmt.Errorf("not implemented: #tag")
|
|
187
|
-
}
|
|
188
|
-
if _, ok := encodedObj["#error"]; ok {
|
|
189
|
-
return nil, fmt.Errorf("not implemented: #error")
|
|
190
|
-
}
|
|
191
|
-
// We need a distinct output map to avoid reprocessing already-decoded keys.
|
|
192
|
-
decodedObj := make(map[string]interface{}, len(encodedObj))
|
|
193
|
-
for encodedK, v := range encodedObj {
|
|
194
|
-
if strings.HasPrefix(encodedK, "#") {
|
|
195
|
-
return nil, fmt.Errorf("unrecognized record type: %q", encodedK)
|
|
196
|
-
}
|
|
197
|
-
decodedK, err := decodeCapdataSmallcapsValue(encodedK, slots, remotables, CapdataValueTransformations{})
|
|
198
|
-
k, ok := decodedK.(string)
|
|
199
|
-
if err != nil || !ok {
|
|
200
|
-
return nil, fmt.Errorf("invalid copyRecord key: %q", encodedK)
|
|
201
|
-
}
|
|
202
|
-
decoded, err := decodeCapdataSmallcapsValue(v, slots, remotables, transformations)
|
|
203
|
-
if err != nil {
|
|
204
|
-
return nil, err
|
|
205
|
-
}
|
|
206
|
-
decodedObj[k] = decoded
|
|
207
|
-
}
|
|
208
|
-
return decodedObj, nil
|
|
209
|
-
} else if str, ok := encoded.(string); ok {
|
|
210
|
-
if len(str) == 0 {
|
|
211
|
-
return str, nil
|
|
212
|
-
}
|
|
213
|
-
switch str[0] {
|
|
214
|
-
case '!':
|
|
215
|
-
return str[1:], nil
|
|
216
|
-
case '+':
|
|
217
|
-
// Normalize to no leading "+".
|
|
218
|
-
str = str[1:]
|
|
219
|
-
fallthrough
|
|
220
|
-
case '-':
|
|
221
|
-
bigint := NewCapdataBigint(str)
|
|
222
|
-
if bigint == nil {
|
|
223
|
-
return nil, fmt.Errorf("invalid bigint: %q", encoded.(string))
|
|
224
|
-
}
|
|
225
|
-
if transformations.Bigint == nil {
|
|
226
|
-
return nil, fmt.Errorf("untransformed bigint")
|
|
227
|
-
}
|
|
228
|
-
return transformations.Bigint(bigint), nil
|
|
229
|
-
case '$':
|
|
230
|
-
var slotIndexStr string
|
|
231
|
-
var iface *string
|
|
232
|
-
if dotIndex := strings.IndexByte(str, '.'); dotIndex >= 0 {
|
|
233
|
-
slotIndexStr = str[1:dotIndex]
|
|
234
|
-
ifaceStr := str[dotIndex+1:]
|
|
235
|
-
iface = &ifaceStr
|
|
236
|
-
} else {
|
|
237
|
-
slotIndexStr = str[1:]
|
|
238
|
-
}
|
|
239
|
-
slotIndex, err := strconv.ParseUint(slotIndexStr, 10, 0)
|
|
240
|
-
if err != nil || slotIndex >= uint64(len(slots)) {
|
|
241
|
-
return nil, fmt.Errorf("invalid slot index: %q", str)
|
|
242
|
-
}
|
|
243
|
-
r, err := upsertCapdataRemotable(remotables, slotIndex, slots[slotIndex], iface)
|
|
244
|
-
if err != nil {
|
|
245
|
-
return nil, fmt.Errorf("slot iface mismatch: %q", str)
|
|
246
|
-
}
|
|
247
|
-
return r, nil
|
|
248
|
-
case '#':
|
|
249
|
-
fallthrough
|
|
250
|
-
case '%':
|
|
251
|
-
fallthrough
|
|
252
|
-
case '&':
|
|
253
|
-
return nil, fmt.Errorf("not implemented: %q", str)
|
|
254
|
-
default:
|
|
255
|
-
if str[0] >= '!' && str[0] <= '-' {
|
|
256
|
-
return nil, fmt.Errorf("invalid smallcaps encoding prefix: %q", str[:1])
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
return str, nil
|
|
260
|
-
} else {
|
|
261
|
-
return encoded, nil
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// DecodeSerializedCapdata accepts JSON text representing encoded CapData and
|
|
266
|
-
// decodes it, applying specified transformations for values that otherwise
|
|
267
|
-
// hinder interchange.
|
|
268
|
-
func DecodeSerializedCapdata(
|
|
269
|
-
serializedCapdata string,
|
|
270
|
-
transformations CapdataValueTransformations,
|
|
271
|
-
) (interface{}, error) {
|
|
272
|
-
var capdata Capdata
|
|
273
|
-
if err := json.Unmarshal([]byte(serializedCapdata), &capdata); err != nil {
|
|
274
|
-
return nil, err
|
|
275
|
-
}
|
|
276
|
-
if capdata.Body == "" || capdata.Slots == nil {
|
|
277
|
-
return nil, fmt.Errorf("invalid CapData")
|
|
278
|
-
}
|
|
279
|
-
serializedBody, decodeValue := capdata.Body, decodeCapdataLegacyValue
|
|
280
|
-
if strings.HasPrefix(serializedBody, "#") {
|
|
281
|
-
serializedBody, decodeValue = serializedBody[1:], decodeCapdataSmallcapsValue
|
|
282
|
-
}
|
|
283
|
-
var encoded interface{}
|
|
284
|
-
if err := json.Unmarshal([]byte(serializedBody), &encoded); err != nil {
|
|
285
|
-
return nil, err
|
|
286
|
-
}
|
|
287
|
-
remotables := map[uint64]*CapdataRemotable{}
|
|
288
|
-
decoded, err := decodeValue(encoded, capdata.Slots, remotables, transformations)
|
|
289
|
-
if err == nil && len(remotables) > 0 {
|
|
290
|
-
if transformations.Remotable == nil {
|
|
291
|
-
return nil, fmt.Errorf("untransformed remotable")
|
|
292
|
-
}
|
|
293
|
-
for _, r := range remotables {
|
|
294
|
-
r.Representation = transformations.Remotable(r)
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return decoded, err
|
|
298
|
-
}
|