@agoric/casting 0.3.5-pismo-dev-0d5327f.0 → 0.4.1-dev-bf4b59f.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +1 -1
  3. package/jsconfig.build.json +12 -0
  4. package/jsconfig.json +1 -15
  5. package/node-fetch-shim.d.ts +2 -0
  6. package/node-fetch-shim.d.ts.map +1 -0
  7. package/node-fetch-shim.js +3 -0
  8. package/package.json +22 -17
  9. package/src/casting-spec.d.ts +16 -0
  10. package/src/casting-spec.d.ts.map +1 -0
  11. package/src/casting-spec.js +39 -6
  12. package/src/change-follower.d.ts +2 -0
  13. package/src/change-follower.d.ts.map +1 -0
  14. package/src/change-follower.js +0 -1
  15. package/src/defaults.d.ts +21 -0
  16. package/src/defaults.d.ts.map +1 -0
  17. package/src/defaults.js +8 -3
  18. package/src/follower-cosmjs.d.ts +12 -0
  19. package/src/follower-cosmjs.d.ts.map +1 -0
  20. package/src/follower-cosmjs.js +114 -143
  21. package/src/follower.d.ts +2 -0
  22. package/src/follower.d.ts.map +1 -0
  23. package/src/follower.js +7 -7
  24. package/src/iterable.d.ts +24 -0
  25. package/src/iterable.d.ts.map +1 -0
  26. package/src/iterable.js +3 -45
  27. package/src/leader-netconfig.d.ts +4 -0
  28. package/src/leader-netconfig.d.ts.map +1 -0
  29. package/src/leader-netconfig.js +7 -6
  30. package/src/leader.d.ts +2 -0
  31. package/src/leader.d.ts.map +1 -0
  32. package/src/leader.js +0 -1
  33. package/src/main.d.ts +9 -0
  34. package/src/main.d.ts.map +1 -0
  35. package/src/main.js +2 -0
  36. package/src/netconfig.d.ts +47 -0
  37. package/src/netconfig.d.ts.map +1 -0
  38. package/src/netconfig.js +40 -0
  39. package/src/shuffle.d.ts +2 -0
  40. package/src/shuffle.d.ts.map +1 -0
  41. package/src/shuffle.js +0 -2
  42. package/src/types.d.ts +54 -0
  43. package/src/types.d.ts.map +1 -0
  44. package/src/types.js +3 -3
  45. package/test/deploy.js +1 -2
  46. package/test/fake-rpc-server.js +6 -3
  47. package/test/test-mvp.js +1 -1
  48. package/test/test-netconfig.js +48 -0
@@ -1,4 +1,3 @@
1
- // @ts-check
2
1
  /* global fetch */
3
2
  import { makeRoundRobinLeader } from './leader.js';
4
3
  import {
@@ -6,8 +5,9 @@ import {
6
5
  DEFAULT_JITTER,
7
6
  DEFAULT_RETRY_CALLBACK,
8
7
  } from './defaults.js';
8
+ import { assertNetworkConfig } from './netconfig.js';
9
9
 
10
- const { details: X } = assert;
10
+ const { Fail } = assert;
11
11
 
12
12
  /**
13
13
  * @param {string[]} rpcAddrs
@@ -15,10 +15,10 @@ const { details: X } = assert;
15
15
  * @returns {import('./types.js').Leader}
16
16
  */
17
17
  export const makeLeaderFromRpcAddresses = (rpcAddrs, leaderOptions) => {
18
- assert(Array.isArray(rpcAddrs), X`rpcAddrs ${rpcAddrs} must be an array`);
18
+ Array.isArray(rpcAddrs) || Fail`rpcAddrs ${rpcAddrs} must be an array`;
19
19
 
20
20
  const rpcHrefs = rpcAddrs.map(rpcAddr => {
21
- assert.typeof(rpcAddr, 'string', X`rpcAddr ${rpcAddr} must be a string`);
21
+ typeof rpcAddr === 'string' || Fail`rpcAddr ${rpcAddr} must be a string`;
22
22
  // Don't remove explicit port numbers from the URL, because the Cosmos
23
23
  // `--node=xxx` flag requires them (it doesn't just assume that
24
24
  // `--node=https://testnet.rpc.agoric.net` is the same as
@@ -50,7 +50,9 @@ export const makeLeaderFromNetworkConfig = (netconfigURL, options = {}) => {
50
50
  const response = await fetch(netconfigURL, {
51
51
  headers: { accept: 'application/json' },
52
52
  });
53
- const { rpcAddrs } = await response.json();
53
+ const networkConfig = await response.json();
54
+ assertNetworkConfig(harden(networkConfig));
55
+ const { rpcAddrs } = networkConfig;
54
56
  // Our part succeeded, so reset the attempt counter.
55
57
  attempt = 0;
56
58
  return makeLeaderFromRpcAddresses(rpcAddrs, options);
@@ -77,4 +79,3 @@ export const makeLeader = (bootstrap = DEFAULT_BOOTSTRAP, options) => {
77
79
  }
78
80
  return makeLeaderFromRpcAddresses([bootstrap], options);
79
81
  };
80
- /** @typedef {ReturnType<typeof makeLeader>} Leader */
@@ -0,0 +1,2 @@
1
+ export function makeRoundRobinLeader(endpoints: string[], leaderOptions?: import('./types.js').LeaderOptions): import("./types.js").Leader;
2
+ //# sourceMappingURL=leader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leader.d.ts","sourceRoot":"","sources":["leader.js"],"names":[],"mappings":"AAWO,gDAHI,MAAM,EAAE,kBACR,OAAO,YAAY,EAAE,aAAa,+BA2E5C"}
package/src/leader.js CHANGED
@@ -1,4 +1,3 @@
1
- // @ts-check
2
1
  import { E, Far } from '@endo/far';
3
2
  import { DEFAULT_RETRY_CALLBACK, DEFAULT_JITTER } from './defaults.js';
4
3
  import { shuffle } from './shuffle.js';
package/src/main.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ export * from "./types.js";
2
+ export * from "./defaults.js";
3
+ export * from "./leader-netconfig.js";
4
+ export * from "./follower.js";
5
+ export * from "./follower-cosmjs.js";
6
+ export * from "./casting-spec.js";
7
+ export * from "./leader.js";
8
+ export * from "./iterable.js";
9
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["main.js"],"names":[],"mappings":""}
package/src/main.js CHANGED
@@ -1,3 +1,5 @@
1
+ // @jessie-check
2
+
1
3
  // eslint-disable-next-line import/export
2
4
  export * from './types.js'; // no named exports
3
5
  export * from './defaults.js';
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @typedef {object} NetworkConfig
3
+ * `peers` and `seeds` are only used for configuring full nodes participating in
4
+ * the chain’s p2p network, not for rpc clients. The `gci` is needed for rpc
5
+ * “light clients” to prove the ancestry of data fetched from the rpc node.
6
+ *
7
+ * @property {string[]} rpcAddrs endpoints serving https://docs.tendermint.com/v0.34/rpc/
8
+ * @property {string} chainName e.g. agoric-3
9
+ * @property {string[]} [apiAddrs] overrides for REST endpoints of RPC servers https://docs.cosmos.network/main/run-node/interact-node#using-the-rest-endpoints
10
+ * @property {string} [gci] - "global chain identifier", a hash of the genesis block
11
+ * @property {string[]} [peers] - a list of nodes used to start the p2p gossip (stored in a per-node “address book”, which is a file stored in that node’s data directory)
12
+ * @property {string[]} [seeds] - nodes which tell you about other peers but don't gossip actual data
13
+ */
14
+ export const NetworkConfigShape: import("@endo/patterns").Matcher;
15
+ export function assertNetworkConfig(specimen: unknown): asserts specimen is NetworkConfig;
16
+ /**
17
+ * `peers` and `seeds` are only used for configuring full nodes participating in
18
+ * the chain’s p2p network, not for rpc clients. The `gci` is needed for rpc
19
+ * “light clients” to prove the ancestry of data fetched from the rpc node.
20
+ */
21
+ export type NetworkConfig = {
22
+ /**
23
+ * endpoints serving https://docs.tendermint.com/v0.34/rpc/
24
+ */
25
+ rpcAddrs: string[];
26
+ /**
27
+ * e.g. agoric-3
28
+ */
29
+ chainName: string;
30
+ /**
31
+ * overrides for REST endpoints of RPC servers https://docs.cosmos.network/main/run-node/interact-node#using-the-rest-endpoints
32
+ */
33
+ apiAddrs?: string[] | undefined;
34
+ /**
35
+ * - "global chain identifier", a hash of the genesis block
36
+ */
37
+ gci?: string | undefined;
38
+ /**
39
+ * - a list of nodes used to start the p2p gossip (stored in a per-node “address book”, which is a file stored in that node’s data directory)
40
+ */
41
+ peers?: string[] | undefined;
42
+ /**
43
+ * - nodes which tell you about other peers but don't gossip actual data
44
+ */
45
+ seeds?: string[] | undefined;
46
+ };
47
+ //# sourceMappingURL=netconfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"netconfig.d.ts","sourceRoot":"","sources":["netconfig.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,kEAWE;AAQK,8CAJI,OAAO,qCAKuB;;;;;;;;;;cA3B3B,MAAM,EAAE;;;;eACR,MAAM"}
@@ -0,0 +1,40 @@
1
+ // @jessie-check
2
+
3
+ import { mustMatch, M } from '@agoric/store';
4
+
5
+ // NB: keep type and shape in sync manually until https://github.com/Agoric/agoric-sdk/issues/6160
6
+ /**
7
+ * @typedef {object} NetworkConfig
8
+ * `peers` and `seeds` are only used for configuring full nodes participating in
9
+ * the chain’s p2p network, not for rpc clients. The `gci` is needed for rpc
10
+ * “light clients” to prove the ancestry of data fetched from the rpc node.
11
+ *
12
+ * @property {string[]} rpcAddrs endpoints serving https://docs.tendermint.com/v0.34/rpc/
13
+ * @property {string} chainName e.g. agoric-3
14
+ * @property {string[]} [apiAddrs] overrides for REST endpoints of RPC servers https://docs.cosmos.network/main/run-node/interact-node#using-the-rest-endpoints
15
+ * @property {string} [gci] - "global chain identifier", a hash of the genesis block
16
+ * @property {string[]} [peers] - a list of nodes used to start the p2p gossip (stored in a per-node “address book”, which is a file stored in that node’s data directory)
17
+ * @property {string[]} [seeds] - nodes which tell you about other peers but don't gossip actual data
18
+ */
19
+ export const NetworkConfigShape = M.splitRecord(
20
+ harden({
21
+ chainName: M.string(),
22
+ rpcAddrs: M.arrayOf(M.string()),
23
+ }),
24
+ harden({
25
+ apiAddrs: M.arrayOf(M.string()),
26
+ gci: M.string(),
27
+ peers: M.arrayOf(M.string()),
28
+ seeds: M.arrayOf(M.string()),
29
+ }),
30
+ );
31
+ harden(NetworkConfigShape);
32
+
33
+ /**
34
+ * @param {unknown} specimen
35
+ * @returns {asserts specimen is NetworkConfig}
36
+ */
37
+
38
+ export const assertNetworkConfig = specimen =>
39
+ mustMatch(specimen, NetworkConfigShape);
40
+ harden(assertNetworkConfig);
@@ -0,0 +1,2 @@
1
+ export function shuffle<T>(a: T[]): void;
2
+ //# sourceMappingURL=shuffle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shuffle.d.ts","sourceRoot":"","sources":["shuffle.js"],"names":[],"mappings":"AAMO,yCAON"}
package/src/shuffle.js CHANGED
@@ -1,5 +1,3 @@
1
- // @ts-check
2
-
3
1
  /**
4
2
  * Modern version of Fisher-Yates shuffle algorithm (in-place).
5
3
  *
package/src/types.d.ts ADDED
@@ -0,0 +1,54 @@
1
+ export type ERef<T> = import('@endo/far').ERef<T>;
2
+ export type LeaderOptions = {
3
+ retryCallback?: ((where: string, err: any, attempt?: number) => Promise<void>) | null | undefined;
4
+ jitter?: ((where: string) => Promise<void>) | undefined;
5
+ keepPolling?: ((where: string) => Promise<boolean>) | undefined;
6
+ };
7
+ export type CastingChange = {
8
+ blockHeight?: number | undefined;
9
+ values: Uint8Array[];
10
+ };
11
+ export type Leader = {
12
+ retry: (where: string, error: any, attempt?: number) => Promise<void>;
13
+ jitter: (where: string) => Promise<void>;
14
+ getOptions: () => LeaderOptions;
15
+ mapEndpoints: <T>(where: string, callback: (endpoint: string) => Promise<T>) => Promise<T[]>;
16
+ watchCasting: (spec: ERef<CastingSpec>) => Promise<Follower<CastingChange>>;
17
+ };
18
+ export type LeaderOrMaker = ERef<Leader> | (() => ERef<Leader>);
19
+ export type Follower<T> = {
20
+ getLatestIterable: () => Promise<AsyncIterable<T>>;
21
+ getEachIterable: (options?: IterateEachOptions) => Promise<AsyncIterable<T>>;
22
+ getReverseIterable: (options?: IterateEachOptions) => Promise<AsyncIterable<T>>;
23
+ };
24
+ export type ValueFollowerElement<T> = {
25
+ value: T;
26
+ blockHeight: number;
27
+ currentBlockHeight: number;
28
+ };
29
+ export type Unserializer = Pick<import('@endo/marshal').Marshal<unknown>, 'fromCapData' | 'unserialize'>;
30
+ export type Crasher = {
31
+ crash: (...args: unknown[]) => void;
32
+ };
33
+ export type FollowerOptions = {
34
+ unserializer?: import("@endo/far").FarRef<Unserializer, import("@endo/eventual-send").DataOnly<Unserializer>> | null | undefined;
35
+ decode?: ((text: string) => any) | undefined;
36
+ proof?: "strict" | "optimistic" | "none" | undefined;
37
+ crasher?: import("@endo/far").FarRef<Crasher, import("@endo/eventual-send").DataOnly<Crasher>> | undefined;
38
+ };
39
+ export type CastingSpec = {
40
+ storeName?: string | undefined;
41
+ storeSubkey?: Uint8Array | undefined;
42
+ dataPrefixBytes?: Uint8Array | undefined;
43
+ noDataValue?: Uint8Array | undefined;
44
+ subscription?: ERef<Subscription<any>> | undefined;
45
+ notifier?: ERef<Notifier<any>> | undefined;
46
+ };
47
+ export type IterateEachOptions = {
48
+ height?: number | undefined;
49
+ };
50
+ export type StreamCell<T> = {
51
+ blockHeight: number;
52
+ values: Array<T>;
53
+ };
54
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.js"],"names":[],"mappings":"sBAO0B,OAAO,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;;6BAIvB,MAAM,OAAO,GAAG,YAAY,MAAM,KAAK,QAAQ,IAAI,CAAC;sBAC5D,MAAM,KAAK,QAAQ,IAAI,CAAC;2BACxB,MAAM,KAAK,QAAQ,OAAO,CAAC;;;;YAMnC,UAAU,EAAE;;;mBAKJ,MAAM,SAAS,GAAG,YAAY,MAAM,KAAK,QAAQ,IAAI,CAAC;oBACtD,MAAM,KAAK,QAAQ,IAAI,CAAC;gBAChC,MAAM,aAAa;6BACR,MAAM,uBAAuB,MAAM;yBACvC,KAAK,WAAW,CAAC,KAAK,QAAQ,SAAS,aAAa,CAAC,CAAC;;4BAG7D,KAAK,MAAM,CAAC,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;;uBAKnC,MAAM,QAAQ,cAAc,CAAC,CAAC,CAAC;gCACpB,kBAAkB,KAAK,QAAQ,cAAc,CAAC,CAAC,CAAC;mCAChD,kBAAkB,KAAK,QAAQ,cAAc,CAAC,CAAC,CAAC;;;WAO3D,CAAC;iBACD,MAAM;wBACN,MAAM;;2BAIP,KAAK,OAAO,eAAe,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa,CAAC;;qBAKlE,OAAO,EAAE,KAAK,IAAI;;;;qBAMrB,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;iBAuBrB,MAAM;YACN,MAAM,CAAC,CAAC"}
package/src/types.js CHANGED
@@ -1,4 +1,4 @@
1
- // @ts-check
1
+ // @jessie-check
2
2
 
3
3
  // Make this a module.
4
4
  import '@agoric/notifier';
@@ -49,8 +49,7 @@ export {};
49
49
  */
50
50
 
51
51
  /**
52
- * @typedef {object} Unserializer
53
- * @property {(data: import('@endo/marshal').CapData<unknown>) => any} unserialize
52
+ * @typedef {Pick<import('@endo/marshal').Marshal<unknown>, 'fromCapData' | 'unserialize'>} Unserializer
54
53
  */
55
54
 
56
55
  /**
@@ -71,6 +70,7 @@ export {};
71
70
  * @property {string} [storeName]
72
71
  * @property {Uint8Array} [storeSubkey]
73
72
  * @property {Uint8Array} [dataPrefixBytes]
73
+ * @property {Uint8Array} [noDataValue]
74
74
  * @property {ERef<Subscription<any>>} [subscription]
75
75
  * @property {ERef<Notifier<any>>} [notifier]
76
76
  */
package/test/deploy.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { E } from '@endo/far';
2
2
  import { iterateLatest, makeFollower } from '../src/main.js';
3
3
 
4
- const COLLATERAL = 'IbcATOM';
4
+ const COLLATERAL = 'ATOM';
5
5
  const getVaultManagerMetrics = async (homeP, { cache, lookup }) => {
6
6
  const zoe = E.get(homeP).zoe;
7
7
  const publicFacet = cache(`publicFacet.vault`, () =>
@@ -24,7 +24,6 @@ const getVaultManagerMetrics = async (homeP, { cache, lookup }) => {
24
24
  export default async (homeP, { cache, lookup, makeDefaultLeader }) => {
25
25
  // const storeKey = getStoreKeyFromCache(homeP, { cache, lookup });
26
26
  const storeKey = getVaultManagerMetrics(homeP, { cache, lookup });
27
- // const storeKey = ':published.amm.metrics';
28
27
 
29
28
  console.log('storeKey', await storeKey);
30
29
 
@@ -1,4 +1,3 @@
1
- // @ts-check
2
1
  import { Buffer } from 'buffer';
3
2
  import './lockdown.js';
4
3
 
@@ -9,6 +8,8 @@ import express from 'express';
9
8
 
10
9
  import { toAscii, toBase64 } from '@cosmjs/encoding';
11
10
 
11
+ const chainName = 'fakeChain';
12
+
12
13
  let lastPort = 8989;
13
14
 
14
15
  /**
@@ -95,11 +96,13 @@ export const startFakeServer = (t, fakeValues, options = {}) => {
95
96
  app.use(express.json());
96
97
  app.get('/bad-network-config', (req, res) => {
97
98
  res.json({
99
+ chainName,
98
100
  rpcAddrs: 'not an array',
99
101
  });
100
102
  });
101
103
  app.get('/network-config', (req, res) => {
102
104
  res.json({
105
+ chainName,
103
106
  rpcAddrs: [`http://localhost:${PORT}/tendermint-rpc`],
104
107
  });
105
108
  });
@@ -162,7 +165,7 @@ export const startFakeServer = (t, fakeValues, options = {}) => {
162
165
  if (batchSize > 0) {
163
166
  // Return a JSON stream cell.
164
167
  const serializedValues = values.map(val =>
165
- JSON.stringify(marshaller.serialize(val)),
168
+ JSON.stringify(marshaller.toCapData(val)),
166
169
  );
167
170
  responseValue = {
168
171
  blockHeight: String(desiredHeight - 1),
@@ -170,7 +173,7 @@ export const startFakeServer = (t, fakeValues, options = {}) => {
170
173
  };
171
174
  } else {
172
175
  // Return a single naked value.
173
- responseValue = marshaller.serialize(values[0]);
176
+ responseValue = marshaller.toCapData(values[0]);
174
177
  }
175
178
  const responseValueBase64 = encode(responseValue);
176
179
  const result = {
package/test/test-mvp.js CHANGED
@@ -138,7 +138,7 @@ test('bad network config', async t => {
138
138
  jitter: null,
139
139
  }),
140
140
  {
141
- message: /rpcAddrs .* must be an array/,
141
+ message: /rpcAddrs.*Must be a copyArray/,
142
142
  },
143
143
  );
144
144
  });
@@ -0,0 +1,48 @@
1
+ import { test } from './prepare-test-env-ava.js';
2
+ import { assertNetworkConfig } from '../src/netconfig.js';
3
+
4
+ test('https://main.agoric.net/network-config 2022-10-27', t => {
5
+ /**
6
+ * @type {import('@agoric/casting/src/netconfig.js').NetworkConfig}
7
+ */
8
+ const specimen = {
9
+ chainName: 'agoric-3',
10
+ gci: 'edef208d407403e6f478bc33dcf7bb294febc5bc6a423c720f0c9c50da5176d5',
11
+ peers: [
12
+ 'a26158a5cbb1df581dd6843ac427191af76d6d5d@104.154.240.50:26656',
13
+ '6e26a1b4afa6889f841d7957e8c2b5d50d32d485@95.216.53.26:26656',
14
+ ],
15
+ rpcAddrs: ['https://agoric-rpc.polkachu.com:443'],
16
+ apiAddrs: ['https://agoric-api.polkachu.com:443'],
17
+ // @ts-expect-error extraneous
18
+ oldRpcAddrs: ['https://main.rpc.agoric.net:443'],
19
+ seeds: [],
20
+ };
21
+ t.notThrows(() => assertNetworkConfig(harden(specimen)));
22
+ });
23
+
24
+ test('https://ollinet.agoric.net/network-config 2022-10-27', t => {
25
+ /**
26
+ * @type {import('@agoric/casting/src/netconfig.js').NetworkConfig}
27
+ */
28
+ const specimen = {
29
+ chainName: 'agoricollinet-44',
30
+ gci: 'https://ollinet.rpc.agoric.net:443/genesis',
31
+ peers: ['fb86a0993c694c981a28fa1ebd1fd692f345348b@34.67.167.8:26656'],
32
+ rpcAddrs: ['https://ollinet.rpc.agoric.net:443'],
33
+ seeds: ['0f04c4610b7511a64b8644944b907416db568590@34.172.146.145:26656'],
34
+ };
35
+ t.notThrows(() => assertNetworkConfig(harden(specimen)));
36
+ });
37
+
38
+ test('https://ollinet.agoric.net/network-config 2022-10-27 minus rpcAddrs', t => {
39
+ const specimen = {
40
+ chainName: 'agoricollinet-44',
41
+ gci: 'https://ollinet.rpc.agoric.net:443/genesis',
42
+ peers: ['fb86a0993c694c981a28fa1ebd1fd692f345348b@34.67.167.8:26656'],
43
+ seeds: ['0f04c4610b7511a64b8644944b907416db568590@34.172.146.145:26656'],
44
+ };
45
+ t.throws(() => assertNetworkConfig(harden(specimen)), {
46
+ message: /Must have missing properties \["rpcAddrs"\]/,
47
+ });
48
+ });