@agoric/async-flow 0.1.1-upgrade-16-dev-8879538.0 → 0.1.1-upgrade-16-dev-24665a9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/async-flow",
3
- "version": "0.1.1-upgrade-16-dev-8879538.0+8879538",
3
+ "version": "0.1.1-upgrade-16-dev-24665a9.0+24665a9",
4
4
  "description": "Upgrade async functions at await points by replay",
5
5
  "type": "module",
6
6
  "repository": "https://github.com/Agoric/agoric-sdk",
@@ -24,9 +24,9 @@
24
24
  "author": "Agoric",
25
25
  "license": "Apache-2.0",
26
26
  "dependencies": {
27
- "@agoric/base-zone": "0.1.1-upgrade-16-dev-8879538.0+8879538",
28
- "@agoric/store": "0.9.3-upgrade-16-dev-8879538.0+8879538",
29
- "@agoric/vow": "0.1.1-upgrade-16-dev-8879538.0+8879538",
27
+ "@agoric/base-zone": "0.1.1-upgrade-16-dev-24665a9.0+24665a9",
28
+ "@agoric/store": "0.9.3-upgrade-16-dev-24665a9.0+24665a9",
29
+ "@agoric/vow": "0.1.1-upgrade-16-dev-24665a9.0+24665a9",
30
30
  "@endo/common": "^1.2.2",
31
31
  "@endo/errors": "^1.2.2",
32
32
  "@endo/eventual-send": "^1.2.2",
@@ -36,9 +36,9 @@
36
36
  "@endo/promise-kit": "^1.1.2"
37
37
  },
38
38
  "devDependencies": {
39
- "@agoric/internal": "0.3.3-upgrade-16-dev-8879538.0+8879538",
40
- "@agoric/swingset-liveslots": "0.10.3-upgrade-16-dev-8879538.0+8879538",
41
- "@agoric/zone": "0.2.3-upgrade-16-dev-8879538.0+8879538",
39
+ "@agoric/internal": "0.3.3-upgrade-16-dev-24665a9.0+24665a9",
40
+ "@agoric/swingset-liveslots": "0.10.3-upgrade-16-dev-24665a9.0+24665a9",
41
+ "@agoric/zone": "0.2.3-upgrade-16-dev-24665a9.0+24665a9",
42
42
  "@endo/env-options": "^1.1.4",
43
43
  "@endo/ses-ava": "^1.2.2",
44
44
  "ava": "^5.3.0"
@@ -62,5 +62,5 @@
62
62
  "typeCoverage": {
63
63
  "atLeast": 77.83
64
64
  },
65
- "gitHead": "8879538cd1d125a08346f02dd5701d0d70c90bb8"
65
+ "gitHead": "24665a97248b854fcb01185d360429301470ed57"
66
66
  }
@@ -18,10 +18,26 @@ export function makeReplayMembrane(log: import("@endo/exo").Guarded<{
18
18
  guestToHost(g: any): any;
19
19
  hostToGuest(h: any): any;
20
20
  }>, vowTools: {
21
- when: <T, TResult1 = import("@agoric/vow").Unwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("@agoric/vow").Unwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>;
22
- watch: <T_1 = unknown, TResult1_1 = T_1, TResult2_1 = T_1, C = unknown>(specimenP: import("@agoric/vow").ERef<T_1 | Vow<T_1>>, watcher?: import("@agoric/vow").Watcher<T_1, TResult1_1, TResult2_1> | undefined, watcherContext?: C | undefined) => Vow<TResult1_1 | TResult2_1>;
21
+ when: <T, TResult1 = import("@agoric/vow").EUnwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("@agoric/vow").EUnwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>;
22
+ /**
23
+ * When replaying, this comes from interpreting the log.
24
+ * Otherwise, it is triggered by a watcher watching hostVow,
25
+ * that must also log it.
26
+ *
27
+ * @param {HostVow} hostVow
28
+ * @param {Host} hostFulfillment
29
+ */
30
+ watch: <T_1 = any, TResult1_1 = T_1, TResult2_1 = never, C = any>(specimenP: import("@agoric/vow").ERef<T_1 | Vow<T_1>>, watcher?: import("@agoric/vow").Watcher<T_1, TResult1_1, TResult2_1> | undefined, watcherContext?: C | undefined) => Vow<Exclude<TResult1_1, void> | Exclude<TResult2_1, void> extends never ? TResult1_1 : Exclude<TResult1_1, void> | Exclude<TResult2_1, void>>;
31
+ /**
32
+ * When replaying, this comes from interpreting the log.
33
+ * Otherwise, it is triggered by a watcher watching hostVow,
34
+ * that must also log it.
35
+ *
36
+ * @param {HostVow} hostVow
37
+ * @param {Host} hostFulfillment
38
+ */
23
39
  makeVowKit: <T_2>() => import("@agoric/vow").VowKit<T_2>;
24
- allVows: (vows: any) => Vow<any>;
40
+ allVows: (vows: unknown[]) => Vow<any[]>;
25
41
  }, watchWake: (vowish: Promise<any> | Vow) => void, panic: (problem: Error) => never): {
26
42
  hostToGuest: (specimen: Passable, label?: string | undefined) => any;
27
43
  guestToHost: (specimen: Passable, label?: string | undefined) => any;
@@ -53,10 +69,26 @@ export type ReplayMembrane = ReturnType<(log: import("@endo/exo").Guarded<{
53
69
  guestToHost(g: any): any;
54
70
  hostToGuest(h: any): any;
55
71
  }>, vowTools: {
56
- when: <T, TResult1 = import("@agoric/vow").Unwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("@agoric/vow").Unwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>;
57
- watch: <T_1 = unknown, TResult1_1 = T_1, TResult2_1 = T_1, C = unknown>(specimenP: import("@agoric/vow").ERef<T_1 | Vow<T_1>>, watcher?: import("@agoric/vow").Watcher<T_1, TResult1_1, TResult2_1> | undefined, watcherContext?: C | undefined) => Vow<TResult1_1 | TResult2_1>;
72
+ when: <T, TResult1 = import("@agoric/vow").EUnwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("@agoric/vow").EUnwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>;
73
+ /**
74
+ * When replaying, this comes from interpreting the log.
75
+ * Otherwise, it is triggered by a watcher watching hostVow,
76
+ * that must also log it.
77
+ *
78
+ * @param {HostVow} hostVow
79
+ * @param {Host} hostFulfillment
80
+ */
81
+ watch: <T_1 = any, TResult1_1 = T_1, TResult2_1 = never, C = any>(specimenP: import("@agoric/vow").ERef<T_1 | Vow<T_1>>, watcher?: import("@agoric/vow").Watcher<T_1, TResult1_1, TResult2_1> | undefined, watcherContext?: C | undefined) => Vow<Exclude<TResult1_1, void> | Exclude<TResult2_1, void> extends never ? TResult1_1 : Exclude<TResult1_1, void> | Exclude<TResult2_1, void>>;
82
+ /**
83
+ * When replaying, this comes from interpreting the log.
84
+ * Otherwise, it is triggered by a watcher watching hostVow,
85
+ * that must also log it.
86
+ *
87
+ * @param {HostVow} hostVow
88
+ * @param {Host} hostFulfillment
89
+ */
58
90
  makeVowKit: <T_2>() => import("@agoric/vow").VowKit<T_2>;
59
- allVows: (vows: any) => Vow<any>;
91
+ allVows: (vows: unknown[]) => Vow<any[]>;
60
92
  }, watchWake: (vowish: Promise<any> | Vow) => void, panic: (problem: Error) => never) => {
61
93
  hostToGuest: (specimen: Passable, label?: string | undefined) => any;
62
94
  guestToHost: (specimen: Passable, label?: string | undefined) => any;
@@ -1 +1 @@
1
- {"version":3,"file":"replay-membrane.d.ts","sourceRoot":"","sources":["replay-membrane.js"],"names":[],"mappings":"AAkBO;;;;;;;;;;;;;;;;;;;;uFATK,CAAC;;;;8CAMyB,IAAI,SAC/B,CAAC,OAAO,EAAE,KAAK,KAAK,KAAK;;;;;;;;;;GA+ZnC;6BAGa,UAAU;;;;;;;;;;;;;;;;;;;;uFAzaZ,CAAC;;;;2DAOF,CAAC,OAAO,EAAE,KAAK,KAAK,KAAK;;;;;;;;;;GAkaQ"}
1
+ {"version":3,"file":"replay-membrane.d.ts","sourceRoot":"","sources":["replay-membrane.js"],"names":[],"mappings":"AAqBO;;;;;;;;;;;;;;;;;;;;wFATuC,CAAC;IA4B7C;;;;;;;OAOG;;IAPH;;;;;;;OAOG;;oBAbM,SAAS;8CAhBkB,IAAI,SAC/B,CAAC,OAAO,EAAE,KAAK,KAAK,KAAK;;;;;;;;;;GAqdnC;6BAGa,UAAU;;;;;;;;;;;;;;;;;;;;wFA/dsB,CAAC;IA4B7C;;;;;;;OAOG;;IAPH;;;;;;;OAOG;;oBAbM,SAAS;2DAfT,CAAC,OAAO,EAAE,KAAK,KAAK,KAAK;;;;;;;;;;GAwdQ"}
@@ -1,13 +1,16 @@
1
1
  /* eslint-disable no-use-before-define */
2
- import { Fail, b, q } from '@endo/errors';
2
+ import { Fail, X, b, makeError, q } from '@endo/errors';
3
3
  import { Far, Remotable, getInterfaceOf } from '@endo/pass-style';
4
4
  import { E } from '@endo/eventual-send';
5
5
  import { getMethodNames } from '@endo/eventual-send/utils.js';
6
- import { makePromiseKit } from '@endo/promise-kit';
7
6
  import { makeEquate } from './equate.js';
8
7
  import { makeConvertKit } from './convert.js';
9
8
 
10
- const { fromEntries, defineProperties } = Object;
9
+ /**
10
+ * @import {PromiseKit} from '@endo/promise-kit'
11
+ */
12
+
13
+ const { fromEntries, defineProperties, assign } = Object;
11
14
 
12
15
  /**
13
16
  * @param {LogStore} log
@@ -31,6 +34,8 @@ export const makeReplayMembrane = (
31
34
 
32
35
  let stopped = false;
33
36
 
37
+ const Panic = (template, ...args) => panic(makeError(X(template, ...args)));
38
+
34
39
  // ////////////// Host or Interpreter to Guest ///////////////////////////////
35
40
 
36
41
  /**
@@ -196,9 +201,61 @@ export const makeReplayMembrane = (
196
201
  default: {
197
202
  // @ts-expect-error TS correctly knows this case would be outside
198
203
  // the type. But that's what we want to check.
199
- throw Fail`unexpected outcome kind ${q(outcome.kind)}`;
204
+ throw Panic`unexpected outcome kind ${q(outcome.kind)}`;
205
+ }
206
+ }
207
+ };
208
+
209
+ // //////////////// Eventual Send ////////////////////////////////////////////
210
+
211
+ const guestHandler = harden({
212
+ applyMethod(guestTarget, optVerb, guestArgs, guestReturnedP) {
213
+ if (optVerb === undefined) {
214
+ throw Panic`guest eventual call not yet supported: ${guestTarget}(${b(guestArgs)}) -> ${b(guestReturnedP)}`;
215
+ } else {
216
+ throw Panic`guest eventual send not yet supported: ${guestTarget}.${b(optVerb)}(${b(guestArgs)}) -> ${b(guestReturnedP)}`;
200
217
  }
218
+ },
219
+ applyFunction(guestTarget, guestArgs, guestReturnedP) {
220
+ return guestHandler.applyMethod(
221
+ guestTarget,
222
+ undefined,
223
+ guestArgs,
224
+ guestReturnedP,
225
+ );
226
+ },
227
+ get(guestTarget, prop, guestReturnedP) {
228
+ throw Panic`guest eventual get not yet supported: ${guestTarget}.${b(prop)} -> ${b(guestReturnedP)}`;
229
+ },
230
+ });
231
+
232
+ const makeGuestPresence = (iface, methodEntries) => {
233
+ let guestPresence;
234
+ void new HandledPromise((_res, _rej, resolveWithPresence) => {
235
+ guestPresence = resolveWithPresence(guestHandler);
236
+ }); // no unfulfilledHandler
237
+ if (typeof guestPresence !== 'object') {
238
+ throw Fail`presence expected to be object ${guestPresence}`;
201
239
  }
240
+ assign(guestPresence, fromEntries(methodEntries));
241
+ const result = Remotable(iface, undefined, guestPresence);
242
+ result === guestPresence ||
243
+ Fail`Remotable expected to make presence in place: ${guestPresence} vs ${result}`;
244
+ return result;
245
+ };
246
+
247
+ /**
248
+ * @returns {PromiseKit<any>}
249
+ */
250
+ const makeGuestPromiseKit = () => {
251
+ let resolve;
252
+ let reject;
253
+ const promise = new HandledPromise((res, rej, _resPres) => {
254
+ resolve = res;
255
+ reject = rej;
256
+ }, guestHandler);
257
+ // @ts-expect-error TS cannot infer that it is a PromiseKit
258
+ return harden({ promise, resolve, reject });
202
259
  };
203
260
 
204
261
  // //////////////// Converters ///////////////////////////////////////////////
@@ -246,9 +303,7 @@ export const makeReplayMembrane = (
246
303
  name,
247
304
  makeGuestMethod(name),
248
305
  ]);
249
- // TODO in order to support E *well*,
250
- // use HandledPromise to make gRem a remote presence for hRem
251
- gRem = Remotable(guestIface, undefined, fromEntries(guestMethods));
306
+ gRem = makeGuestPresence(guestIface, guestMethods);
252
307
  }
253
308
  // See note at the top of the function to see why clearing the `hRem`
254
309
  // variable is safe, and what invariant the above code needs to maintain so
@@ -258,10 +313,12 @@ export const makeReplayMembrane = (
258
313
  };
259
314
  harden(makeGuestForHostRemotable);
260
315
 
316
+ /**
317
+ * @param {Vow} hVow
318
+ * @returns {Promise}
319
+ */
261
320
  const makeGuestForHostVow = hVow => {
262
- // TODO in order to support E *well*,
263
- // use HandledPromise to make `promise` a handled promise for hVow
264
- const { promise, resolve, reject } = makePromiseKit();
321
+ const { promise, resolve, reject } = makeGuestPromiseKit();
265
322
  guestPromiseMap.set(promise, harden({ resolve, reject }));
266
323
 
267
324
  watchWake(hVow);
package/src/types.d.ts CHANGED
@@ -12,10 +12,10 @@ type GuestAsyncFunc = (...activationArgs: Guest[]) => Guest<Promise<any>>;
12
12
  type HostAsyncFuncWrapper = (...activationArgs: Host[]) => HostVow;
13
13
  type PreparationOptions = {
14
14
  vowTools?: {
15
- when: <T, TResult1 = import("@agoric/vow").Unwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("@agoric/vow").Unwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>;
16
- watch: <T_1 = unknown, TResult1_1 = T_1, TResult2_1 = T_1, C = unknown>(specimenP: import("@agoric/vow").ERef<T_1 | Vow<T_1>>, watcher?: import("@agoric/vow").Watcher<T_1, TResult1_1, TResult2_1> | undefined, watcherContext?: C | undefined) => Vow<TResult1_1 | TResult2_1>;
15
+ when: <T, TResult1 = import("@agoric/vow").EUnwrap<T>, TResult2 = never>(specimenP: T, onFulfilled?: ((value: import("@agoric/vow").EUnwrap<T>) => TResult1 | PromiseLike<TResult1>) | undefined, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined) => Promise<TResult1 | TResult2>;
16
+ watch: <T_1 = any, TResult1_1 = T_1, TResult2_1 = never, C = any>(specimenP: import("@agoric/vow").ERef<T_1 | Vow<T_1>>, watcher?: import("@agoric/vow").Watcher<T_1, TResult1_1, TResult2_1> | undefined, watcherContext?: C | undefined) => Vow<Exclude<TResult1_1, void> | Exclude<TResult2_1, void> extends never ? TResult1_1 : Exclude<TResult1_1, void> | Exclude<TResult2_1, void>>;
17
17
  makeVowKit: <T_2>() => import("@agoric/vow").VowKit<T_2>;
18
- allVows: (vows: any) => Vow<any>;
18
+ allVows: (vows: unknown[]) => Vow<any[]>;
19
19
  } | undefined;
20
20
  makeLogStore?: (() => import("@endo/exo").Guarded<{
21
21
  reset(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.js"],"names":[],"mappings":"iBAWa,SAAS,GACrB,UAAsB,GACtB,WAAuB,GACvB,QAAoB,GACpB,MAAkB;WAMN,CAAC,gCAAD,CAAC;UAKD,CAAC,gCAAD,CAAC;;;;;aAQQ,CAAC;;;sBAIV,CAAC,GAAG,cAAc,EAAE,KAAK,EAAE,KAAK,KAAK,cAAS;4BAI9C,CAAC,GAAG,cAAc,EAAE,IAAI,EAAE,KAAK,OAAO;;;2FA7BlC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAwCL,QAAQ,GAAC,OAAO;eAIhB;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAC,GAC7B;IAAC,IAAI,EAAE,OAAO,CAAC;IAAE,OAAO,EAAE,GAAG,CAAA;CAAC;cAStB,CAAC,4BADK,CAAC;SAAd,CAAC,IAAI,EACE,CAAC,AADA,KAAK,CAAC;cACd,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI;;;;;;;gBAQlB,CAAE,iEAAiE;AAC/E,EAAQ,EAAE,WAAW,EACrB,GAAS,EAAE,OAAO,EAClB,WAAiB,EAAE,IAAI,CAClB,GAAG,CACR,EAAQ,EAAE,UAAU,EACpB,GAAS,EAAE,OAAO,EAClB,MAAY,EAAE,IAAI,CACb,GAAG,CACR,EAAQ,EAAE,UAAU,EACpB,SAAe,EAAE,MAAM,EACvB,MAAY,EAAE,IAAI,CACb,GAAG,CACR,EAAQ,EAAE,SAAS,EACnB,SAAe,EAAE,MAAM,EACvB,OAAa,EAAE,IAAI,CACd,GAAG,CAAE,qEAAqE;AAC/E,EAAQ,EAAE,WAAW,EACrB,MAAY,EAAE,IAAI,EAClB,OAAa,EAAE,WAAW,GAAC,SAAS,EACpC,IAAU,EAAE,IAAI,EAAE,EAClB,SAAe,EAAE,MAAM,CAClB;gCAhGuB,mBAAmB;8BACrB,kBAAkB;0BACtB,mBAAmB;yBACV,aAAa;8BAAb,aAAa;8BAClB,gBAAgB;+BACf,gBAAgB;oCACX,sBAAsB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.js"],"names":[],"mappings":"iBAWa,SAAS,GACrB,UAAsB,GACtB,WAAuB,GACvB,QAAoB,GACpB,MAAkB;WAMN,CAAC,gCAAD,CAAC;UAKD,CAAC,gCAAD,CAAC;;;;;aAQQ,CAAC;;;sBAIV,CAAC,GAAG,cAAc,EAAE,KAAK,EAAE,KAAK,KAAK,cAAS;4BAI9C,CAAC,GAAG,cAAc,EAAE,IAAI,EAAE,KAAK,OAAO;;;4FA1BlD,CAAA;;;wBA0BW,SAAQ;;;;;;;;;;;;;;;;;;;;;;;;mBAWP,QAAQ,GAAC,OAAO;eAIhB;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAC,GAC7B;IAAC,IAAI,EAAE,OAAO,CAAC;IAAE,OAAO,EAAE,GAAG,CAAA;CAAC;cAStB,CAAC,4BADK,CAAC;SAAd,CAAC,IAAI,EACE,CAAC,AADA,KAAK,CAAC;cACd,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI;;;;;;;gBAQlB,CAAE,iEAAiE;AAC/E,EAAQ,EAAE,WAAW,EACrB,GAAS,EAAE,OAAO,EAClB,WAAiB,EAAE,IAAI,CAClB,GAAG,CACR,EAAQ,EAAE,UAAU,EACpB,GAAS,EAAE,OAAO,EAClB,MAAY,EAAE,IAAI,CACb,GAAG,CACR,EAAQ,EAAE,UAAU,EACpB,SAAe,EAAE,MAAM,EACvB,MAAY,EAAE,IAAI,CACb,GAAG,CACR,EAAQ,EAAE,SAAS,EACnB,SAAe,EAAE,MAAM,EACvB,OAAa,EAAE,IAAI,CACd,GAAG,CAAE,qEAAqE;AAC/E,EAAQ,EAAE,WAAW,EACrB,MAAY,EAAE,IAAI,EAClB,OAAa,EAAE,WAAW,GAAC,SAAS,EACpC,IAAU,EAAE,IAAI,EAAE,EAClB,SAAe,EAAE,MAAM,CAClB;gCAhGuB,mBAAmB;8BACrB,kBAAkB;0BACtB,mBAAmB;yBACV,aAAa;8BAAb,aAAa;8BAClB,gBAAgB;+BACf,gBAAgB;oCACX,sBAAsB"}
@@ -0,0 +1,201 @@
1
+ // eslint-disable-next-line import/order
2
+ import {
3
+ test,
4
+ getBaggage,
5
+ annihilate,
6
+ nextLife,
7
+ } from './prepare-test-env-ava.js';
8
+
9
+ import { Fail } from '@endo/errors';
10
+ import { passStyleOf } from '@endo/pass-style';
11
+ import { makeCopyMap } from '@endo/patterns';
12
+ import { makePromiseKit } from '@endo/promise-kit';
13
+ import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js';
14
+ import { isVow } from '@agoric/vow/src/vow-utils.js';
15
+ import { prepareVowTools } from '@agoric/vow';
16
+ import { makeDurableZone } from '@agoric/zone/durable.js';
17
+
18
+ import { prepareAsyncFlowTools } from '../src/async-flow.js';
19
+
20
+ /**
21
+ * @import {AsyncFlow} from '../src/async-flow.js'
22
+ */
23
+
24
+ /**
25
+ * @param {Zone} zone
26
+ * @param {number} [k]
27
+ */
28
+ const prepareOrchestra = (zone, k = 1) =>
29
+ zone.exoClass(
30
+ 'Orchestra',
31
+ undefined,
32
+ (factor, vow, resolver) => ({ factor, vow, resolver }),
33
+ {
34
+ scale(n) {
35
+ const { state } = this;
36
+ return k * state.factor * n;
37
+ },
38
+ vow() {
39
+ const { state } = this;
40
+ return state.vow;
41
+ },
42
+ resolve(x) {
43
+ const { state } = this;
44
+ state.resolver.resolve(x);
45
+ },
46
+ },
47
+ );
48
+
49
+ /** @typedef {ReturnType<ReturnType<prepareOrchestra>>} Orchestra */
50
+
51
+ const firstLogLen = 7;
52
+
53
+ /**
54
+ * @param {any} t
55
+ * @param {Zone} zone
56
+ */
57
+ const testFirstPlay = async (t, zone) => {
58
+ t.log('firstPlay started');
59
+ const vowTools = prepareVowTools(zone);
60
+ const { asyncFlow, adminAsyncFlow } = prepareAsyncFlowTools(zone, {
61
+ vowTools,
62
+ });
63
+ const makeOrchestra = prepareOrchestra(zone);
64
+ const { makeVowKit } = vowTools;
65
+
66
+ const { vow: v1, resolver: r1 } = zone.makeOnce('v1', () => makeVowKit());
67
+ const { vow: v2, resolver: r2 } = zone.makeOnce('v2', () => makeVowKit());
68
+ const { vow: v3, resolver: _r3 } = zone.makeOnce('v3', () => makeVowKit());
69
+ const hOrch7 = zone.makeOnce('hOrch7', () => makeOrchestra(7, v2, r2));
70
+
71
+ // purposely violate rule that guestMethod is closed.
72
+ const { promise: promiseStep, resolve: resolveStep } = makePromiseKit();
73
+
74
+ const { guestMethod } = {
75
+ async guestMethod(gOrch7, g1, _p3) {
76
+ t.log(' firstPlay about to await g1');
77
+ t.is(await g1, 'x');
78
+ const p2 = gOrch7.vow();
79
+ const prod = gOrch7.scale(3);
80
+ t.is(prod, 21);
81
+
82
+ let gErr;
83
+ try {
84
+ gOrch7.scale(9n);
85
+ } catch (e) {
86
+ gErr = e;
87
+ }
88
+ t.is(gErr.name, 'TypeError');
89
+
90
+ resolveStep(true);
91
+ t.log(' firstPlay to hang awaiting p2');
92
+ // awaiting a promise that won't be resolved until next incarnation
93
+ await p2;
94
+ t.fail('must not reach here in first incarnation');
95
+ },
96
+ };
97
+
98
+ const wrapperFunc = asyncFlow(zone, 'AsyncFlow1', guestMethod);
99
+
100
+ const outcomeV = zone.makeOnce('outcomeV', () => wrapperFunc(hOrch7, v1, v3));
101
+
102
+ t.true(isVow(outcomeV));
103
+ r1.resolve('x');
104
+
105
+ const flow = zone.makeOnce('flow', () =>
106
+ adminAsyncFlow.getFlowForOutcomeVow(outcomeV),
107
+ );
108
+ t.is(passStyleOf(flow), 'remotable');
109
+
110
+ await promiseStep;
111
+
112
+ const logDump = flow.dump();
113
+ t.is(logDump.length, firstLogLen);
114
+ t.deepEqual(logDump, [
115
+ ['doFulfill', v1, 'x'],
116
+ ['checkCall', hOrch7, 'vow', [], 1],
117
+ ['doReturn', 1, v2],
118
+ ['checkCall', hOrch7, 'scale', [3], 3],
119
+ ['doReturn', 3, 21],
120
+ ['checkCall', hOrch7, 'scale', [9n], 5],
121
+ [
122
+ 'doThrow',
123
+ 5,
124
+ TypeError('Cannot mix BigInt and other types, use explicit conversions'),
125
+ ],
126
+ ]);
127
+ t.log('firstPlay done');
128
+ };
129
+
130
+ /**
131
+ * Test from bug https://github.com/Agoric/agoric-sdk/issues/9465
132
+ *
133
+ * @param {any} t
134
+ * @param {Zone} zone
135
+ */
136
+ const testBadShortReplay = async (t, zone) => {
137
+ t.log('badShortReplay started');
138
+ const vowTools = prepareVowTools(zone);
139
+ const { asyncFlow, adminAsyncFlow } = prepareAsyncFlowTools(zone, {
140
+ vowTools,
141
+ });
142
+ prepareOrchestra(zone);
143
+ const { when } = vowTools;
144
+
145
+ // purposely violate rule that guestMethod is closed.
146
+ const { promise: promiseStep, resolve: resolveStep } = makePromiseKit();
147
+
148
+ const { guestMethod } = {
149
+ async guestMethod(_gOrch7, _g1, _p3) {
150
+ t.log(' badReplay return early');
151
+ resolveStep(true);
152
+ return 'bad';
153
+ },
154
+ };
155
+
156
+ // `asyncFlow` can be used simply to re-prepare the guest function
157
+ // by ignoring the returned wrapper function. If the wrapper function is
158
+ // invoked, that would be a *new* activation with a new outcome and
159
+ // flow, and would have nothing to do with the existing one.
160
+ asyncFlow(zone, 'AsyncFlow1', guestMethod);
161
+
162
+ const outcomeV = /** @type {Vow} */ (
163
+ zone.makeOnce('outcomeV', () => Fail`need outcomeV`)
164
+ );
165
+ const flow = /** @type {AsyncFlow} */ (
166
+ zone.makeOnce('flow', () => Fail`need flow`)
167
+ );
168
+ const flow1 = adminAsyncFlow.getFlowForOutcomeVow(outcomeV);
169
+ t.is(flow, flow1);
170
+ t.is(passStyleOf(flow), 'remotable');
171
+
172
+ await promiseStep;
173
+
174
+ const replayProblem = flow.getOptFatalProblem();
175
+ t.log(' badShortReplay failures', replayProblem);
176
+ t.true(replayProblem instanceof Error);
177
+
178
+ const outcome = when(outcomeV);
179
+ await eventLoopIteration();
180
+
181
+ t.is(await Promise.race([outcome, Promise.resolve('good')]), 'good');
182
+
183
+ t.deepEqual(
184
+ adminAsyncFlow.getFailures(),
185
+ makeCopyMap([[flow, replayProblem]]),
186
+ );
187
+
188
+ t.log('badShortReplay done');
189
+ };
190
+
191
+ test.serial.failing('test durable async-flow early completion', async t => {
192
+ annihilate();
193
+ const zone1 = makeDurableZone(getBaggage(), 'durableRoot');
194
+ await testFirstPlay(t, zone1);
195
+
196
+ await eventLoopIteration();
197
+
198
+ nextLife();
199
+ const zone2a = makeDurableZone(getBaggage(), 'durableRoot');
200
+ await testBadShortReplay(t, zone2a);
201
+ });
@@ -0,0 +1,91 @@
1
+ // eslint-disable-next-line import/order
2
+ import {
3
+ test,
4
+ getBaggage,
5
+ annihilate,
6
+ nextLife,
7
+ } from './prepare-test-env-ava.js';
8
+
9
+ import { Fail } from '@endo/errors';
10
+ import { prepareVowTools } from '@agoric/vow';
11
+ import { E } from '@endo/eventual-send';
12
+ // import E from '@agoric/vow/src/E.js';
13
+ import { makeHeapZone } from '@agoric/zone/heap.js';
14
+ import { makeVirtualZone } from '@agoric/zone/virtual.js';
15
+ import { makeDurableZone } from '@agoric/zone/durable.js';
16
+
17
+ import { prepareLogStore } from '../src/log-store.js';
18
+ import { prepareBijection } from '../src/bijection.js';
19
+ import { makeReplayMembrane } from '../src/replay-membrane.js';
20
+
21
+ const watchWake = _vowish => {};
22
+ const panic = problem => Fail`panic over ${problem}`;
23
+
24
+ /**
25
+ * @param {Zone} zone
26
+ */
27
+ const preparePingee = zone =>
28
+ zone.exoClass('Pingee', undefined, () => ({}), {
29
+ ping(_str) {},
30
+ });
31
+
32
+ /**
33
+ * @typedef {ReturnType<ReturnType<preparePingee>>} Pingee
34
+ */
35
+
36
+ /**
37
+ * @param {any} t
38
+ * @param {Zone} zone
39
+ */
40
+ const testFirstPlay = async (t, zone) => {
41
+ const vowTools = prepareVowTools(zone);
42
+ const makeLogStore = prepareLogStore(zone);
43
+ const makeBijection = prepareBijection(zone);
44
+ const makePingee = preparePingee(zone);
45
+
46
+ const log = zone.makeOnce('log', () => makeLogStore());
47
+ const bij = zone.makeOnce('bij', makeBijection);
48
+
49
+ const mem = makeReplayMembrane(log, bij, vowTools, watchWake, panic);
50
+
51
+ t.deepEqual(log.dump(), []);
52
+
53
+ /** @type {Pingee} */
54
+ const pingee = zone.makeOnce('pingee', () => makePingee());
55
+ /** @type {Pingee} */
56
+ const guestPingee = mem.hostToGuest(pingee);
57
+ t.deepEqual(log.dump(), []);
58
+
59
+ const pingTestSendResult = t.throwsAsync(() => E(guestPingee).ping('send'), {
60
+ message:
61
+ 'panic over "[Error: guest eventual send not yet supported: \\"[Alleged: Pingee guest wrapper]\\".ping([\\"send\\"]) -> \\"[Promise]\\"]"',
62
+ });
63
+
64
+ guestPingee.ping('call');
65
+
66
+ await pingTestSendResult;
67
+
68
+ t.deepEqual(log.dump(), [
69
+ ['checkCall', pingee, 'ping', ['call'], 0],
70
+ ['doReturn', 0, undefined],
71
+ ]);
72
+ };
73
+
74
+ test.serial('test heap replay-membrane settlement', async t => {
75
+ const zone = makeHeapZone('heapRoot');
76
+ return testFirstPlay(t, zone);
77
+ });
78
+
79
+ test.serial('test virtual replay-membrane settlement', async t => {
80
+ annihilate();
81
+ const zone = makeVirtualZone('virtualRoot');
82
+ return testFirstPlay(t, zone);
83
+ });
84
+
85
+ test.serial('test durable replay-membrane settlement', async t => {
86
+ annihilate();
87
+
88
+ nextLife();
89
+ const zone1 = makeDurableZone(getBaggage(), 'durableRoot');
90
+ return testFirstPlay(t, zone1);
91
+ });