agoric 0.21.2-other-dev-8f8782b.0 → 0.21.2-other-dev-3eb1a1d.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/src/lib/rpc.js DELETED
@@ -1,272 +0,0 @@
1
- // @ts-check
2
- /* eslint-disable @jessie.js/no-nested-await */
3
- /* global Buffer, fetch, process */
4
-
5
- import { NonNullish } from '@agoric/assert';
6
- import {
7
- boardSlottingMarshaller,
8
- makeBoardRemote,
9
- } from '@agoric/vats/tools/board-utils.js';
10
-
11
- export { boardSlottingMarshaller };
12
-
13
- export const networkConfigUrl = agoricNetSubdomain =>
14
- `https://${agoricNetSubdomain}.agoric.net/network-config`;
15
- export const rpcUrl = agoricNetSubdomain =>
16
- `https://${agoricNetSubdomain}.rpc.agoric.net:443`;
17
-
18
- /**
19
- * @typedef {{ rpcAddrs: string[], chainName: string }} MinimalNetworkConfig
20
- */
21
-
22
- /**
23
- * @param {string} str
24
- * @returns {Promise<MinimalNetworkConfig>}
25
- */
26
- const fromAgoricNet = str => {
27
- const [netName, chainName] = str.split(',');
28
- if (chainName) {
29
- return Promise.resolve({ chainName, rpcAddrs: [rpcUrl(netName)] });
30
- }
31
- return fetch(networkConfigUrl(netName)).then(res => res.json());
32
- };
33
-
34
- /**
35
- * @param {typeof process.env} env
36
- * @returns {Promise<MinimalNetworkConfig>}
37
- */
38
- export const getNetworkConfig = async env => {
39
- if (!('AGORIC_NET' in env) || env.AGORIC_NET === 'local') {
40
- return { rpcAddrs: ['http://0.0.0.0:26657'], chainName: 'agoriclocal' };
41
- }
42
-
43
- return fromAgoricNet(NonNullish(env.AGORIC_NET)).catch(err => {
44
- throw Error(
45
- `cannot get network config (${env.AGORIC_NET || 'local'}): ${
46
- err.message
47
- }`,
48
- );
49
- });
50
- };
51
-
52
- /** @type {MinimalNetworkConfig} */
53
- export const networkConfig = await getNetworkConfig(process.env);
54
- // console.warn('networkConfig', networkConfig);
55
-
56
- /**
57
- * @param {object} powers
58
- * @param {typeof window.fetch} powers.fetch
59
- * @param {MinimalNetworkConfig} config
60
- */
61
- export const makeVStorage = (powers, config = networkConfig) => {
62
- /** @param {string} path */
63
- const getJSON = path => {
64
- const url = config.rpcAddrs[0] + path;
65
- // console.warn('fetching', url);
66
- return powers.fetch(url, { keepalive: true }).then(res => res.json());
67
- };
68
- // height=0 is the same as omitting height and implies the highest block
69
- const url = (path = 'published', { kind = 'children', height = 0 } = {}) =>
70
- `/abci_query?path=%22/custom/vstorage/${kind}/${path}%22&height=${height}`;
71
-
72
- const readStorage = (path = 'published', { kind = 'children', height = 0 }) =>
73
- getJSON(url(path, { kind, height }))
74
- .catch(err => {
75
- throw Error(`cannot read ${kind} of ${path}: ${err.message}`);
76
- })
77
- .then(data => {
78
- const {
79
- result: { response },
80
- } = data;
81
- if (response?.code !== 0) {
82
- throw Error(
83
- `error code ${response?.code} reading ${kind} of ${path}: ${response.log}`,
84
- );
85
- }
86
- return data;
87
- });
88
-
89
- return {
90
- url,
91
- decode({ result: { response } }) {
92
- const { code } = response;
93
- if (code !== 0) {
94
- throw response;
95
- }
96
- const { value } = response;
97
- return Buffer.from(value, 'base64').toString();
98
- },
99
- /**
100
- *
101
- * @param {string} path
102
- * @returns {Promise<string>} latest vstorage value at path
103
- */
104
- async readLatest(path = 'published') {
105
- const raw = await readStorage(path, { kind: 'data' });
106
- return this.decode(raw);
107
- },
108
- async keys(path = 'published') {
109
- const raw = await readStorage(path, { kind: 'children' });
110
- return JSON.parse(this.decode(raw)).children;
111
- },
112
- /**
113
- * @param {string} path
114
- * @param {number} [height] default is highest
115
- * @returns {Promise<{blockHeight: number, values: string[]}>}
116
- */
117
- async readAt(path, height = undefined) {
118
- const raw = await readStorage(path, { kind: 'data', height });
119
- const txt = this.decode(raw);
120
- /** @type {{ value: string }} */
121
- const { value } = JSON.parse(txt);
122
- return JSON.parse(value);
123
- },
124
- /**
125
- * Read values going back as far as available
126
- *
127
- * @param {string} path
128
- * @param {number | string} [minHeight]
129
- * @returns {Promise<string[]>}
130
- */
131
- async readFully(path, minHeight = undefined) {
132
- const parts = [];
133
- // undefined the first iteration, to query at the highest
134
- let blockHeight;
135
- do {
136
- // console.debug('READING', { blockHeight });
137
- let values;
138
- try {
139
- // eslint-disable-next-line no-await-in-loop
140
- ({ blockHeight, values } = await this.readAt(
141
- path,
142
- blockHeight && Number(blockHeight) - 1,
143
- ));
144
- // console.debug('readAt returned', { blockHeight });
145
- } catch (err) {
146
- if (err.message.match(/unknown request/)) {
147
- // console.error(err);
148
- break;
149
- }
150
- throw err;
151
- }
152
- parts.push(values);
153
- // console.debug('PUSHED', values);
154
- // console.debug('NEW', { blockHeight, minHeight });
155
- if (minHeight && Number(blockHeight) <= Number(minHeight)) break;
156
- } while (blockHeight > 0);
157
- return parts.flat();
158
- },
159
- };
160
- };
161
- /** @typedef {ReturnType<typeof makeVStorage>} VStorage */
162
-
163
- export const makeFromBoard = () => {
164
- const cache = new Map();
165
- const convertSlotToVal = (boardId, iface) => {
166
- if (cache.has(boardId)) {
167
- return cache.get(boardId);
168
- }
169
- const val = makeBoardRemote({ boardId, iface });
170
- cache.set(boardId, val);
171
- return val;
172
- };
173
- return harden({ convertSlotToVal });
174
- };
175
- /** @typedef {ReturnType<typeof makeFromBoard>} IdMap */
176
-
177
- export const storageHelper = {
178
- /** @param { string } txt */
179
- parseCapData: txt => {
180
- assert(typeof txt === 'string', typeof txt);
181
- /** @type {{ value: string }} */
182
- const { value } = JSON.parse(txt);
183
- const specimen = JSON.parse(value);
184
- const { blockHeight, values } = specimen;
185
- assert(values, `empty values in specimen ${value}`);
186
- const capDatas = storageHelper.parseMany(values);
187
- return { blockHeight, capDatas };
188
- },
189
- /**
190
- * @param {string} txt
191
- * @param {IdMap} ctx
192
- */
193
- unserializeTxt: (txt, ctx) => {
194
- const { capDatas } = storageHelper.parseCapData(txt);
195
- return capDatas.map(capData =>
196
- boardSlottingMarshaller(ctx.convertSlotToVal).fromCapData(capData),
197
- );
198
- },
199
- /** @param {string[]} capDataStrings array of stringified capData */
200
- parseMany: capDataStrings => {
201
- assert(capDataStrings && capDataStrings.length);
202
- /** @type {{ body: string, slots: string[] }[]} */
203
- const capDatas = capDataStrings.map(s => JSON.parse(s));
204
- for (const capData of capDatas) {
205
- assert(typeof capData === 'object' && capData !== null);
206
- assert('body' in capData && 'slots' in capData);
207
- assert(typeof capData.body === 'string');
208
- assert(Array.isArray(capData.slots));
209
- }
210
- return capDatas;
211
- },
212
- };
213
- harden(storageHelper);
214
-
215
- /**
216
- * @param {IdMap} ctx
217
- * @param {VStorage} vstorage
218
- * @returns {Promise<import('@agoric/vats/tools/board-utils.js').AgoricNamesRemotes>}
219
- */
220
- export const makeAgoricNames = async (ctx, vstorage) => {
221
- const reverse = {};
222
- const entries = await Promise.all(
223
- ['brand', 'instance', 'vbankAsset'].map(async kind => {
224
- const content = await vstorage.readLatest(
225
- `published.agoricNames.${kind}`,
226
- );
227
- /** @type {Array<[string, import('@agoric/vats/tools/board-utils.js').BoardRemote]>} */
228
- const parts = storageHelper.unserializeTxt(content, ctx).at(-1);
229
- for (const [name, remote] of parts) {
230
- if ('getBoardId' in remote) {
231
- reverse[remote.getBoardId()] = name;
232
- }
233
- }
234
- return [kind, Object.fromEntries(parts)];
235
- }),
236
- );
237
- return { ...Object.fromEntries(entries), reverse };
238
- };
239
-
240
- /**
241
- * @param {{ fetch: typeof window.fetch }} io
242
- * @param {MinimalNetworkConfig} config
243
- */
244
- export const makeRpcUtils = async ({ fetch }, config = networkConfig) => {
245
- try {
246
- const vstorage = makeVStorage({ fetch }, config);
247
- const fromBoard = makeFromBoard();
248
- const agoricNames = await makeAgoricNames(fromBoard, vstorage);
249
-
250
- const unserializer = boardSlottingMarshaller(fromBoard.convertSlotToVal);
251
-
252
- /** @type {(txt: string) => unknown} */
253
- const unserializeHead = txt =>
254
- storageHelper.unserializeTxt(txt, fromBoard).at(-1);
255
-
256
- /** @type {(path: string) => Promise<unknown>} */
257
- const readLatestHead = path =>
258
- vstorage.readLatest(path).then(unserializeHead);
259
-
260
- return {
261
- agoricNames,
262
- fromBoard,
263
- readLatestHead,
264
- unserializeHead,
265
- unserializer,
266
- vstorage,
267
- };
268
- } catch (err) {
269
- throw Error(`RPC failure (${config.rpcAddrs}): ${err.message}`);
270
- }
271
- };
272
- /** @typedef {Awaited<ReturnType<typeof makeRpcUtils>>} RpcUtils */