@agoric/swingset-vat 0.32.3-dev-0f42fb6.0 → 0.32.3-dev-6d9ae67.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 (2) hide show
  1. package/package.json +14 -13
  2. package/tools/run-utils.ts +156 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/swingset-vat",
3
- "version": "0.32.3-dev-0f42fb6.0+0f42fb6",
3
+ "version": "0.32.3-dev-6d9ae67.0+6d9ae67",
4
4
  "description": "Vat/Container Launcher",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -27,17 +27,17 @@
27
27
  "@types/yargs-parser": "^21.0.0"
28
28
  },
29
29
  "dependencies": {
30
- "@agoric/assert": "0.6.1-dev-0f42fb6.0+0f42fb6",
31
- "@agoric/internal": "0.3.3-dev-0f42fb6.0+0f42fb6",
32
- "@agoric/kmarshal": "0.1.1-dev-0f42fb6.0+0f42fb6",
33
- "@agoric/store": "0.9.3-dev-0f42fb6.0+0f42fb6",
34
- "@agoric/swing-store": "0.9.2-dev-0f42fb6.0+0f42fb6",
35
- "@agoric/swingset-liveslots": "0.10.3-dev-0f42fb6.0+0f42fb6",
36
- "@agoric/swingset-xsnap-supervisor": "0.10.3-dev-0f42fb6.0+0f42fb6",
37
- "@agoric/time": "0.3.3-dev-0f42fb6.0+0f42fb6",
38
- "@agoric/vat-data": "0.5.3-dev-0f42fb6.0+0f42fb6",
39
- "@agoric/xsnap": "0.14.3-dev-0f42fb6.0+0f42fb6",
40
- "@agoric/xsnap-lockdown": "0.14.1-dev-0f42fb6.0+0f42fb6",
30
+ "@agoric/assert": "0.6.1-dev-6d9ae67.0+6d9ae67",
31
+ "@agoric/internal": "0.3.3-dev-6d9ae67.0+6d9ae67",
32
+ "@agoric/kmarshal": "0.1.1-dev-6d9ae67.0+6d9ae67",
33
+ "@agoric/store": "0.9.3-dev-6d9ae67.0+6d9ae67",
34
+ "@agoric/swing-store": "0.9.2-dev-6d9ae67.0+6d9ae67",
35
+ "@agoric/swingset-liveslots": "0.10.3-dev-6d9ae67.0+6d9ae67",
36
+ "@agoric/swingset-xsnap-supervisor": "0.10.3-dev-6d9ae67.0+6d9ae67",
37
+ "@agoric/time": "0.3.3-dev-6d9ae67.0+6d9ae67",
38
+ "@agoric/vat-data": "0.5.3-dev-6d9ae67.0+6d9ae67",
39
+ "@agoric/xsnap": "0.14.3-dev-6d9ae67.0+6d9ae67",
40
+ "@agoric/xsnap-lockdown": "0.14.1-dev-6d9ae67.0+6d9ae67",
41
41
  "@endo/base64": "^0.2.34",
42
42
  "@endo/bundle-source": "^2.7.0",
43
43
  "@endo/captp": "^3.1.4",
@@ -52,6 +52,7 @@
52
52
  "@endo/patterns": "^0.2.5",
53
53
  "@endo/promise-kit": "^0.2.59",
54
54
  "@endo/ses-ava": "^0.2.43",
55
+ "@endo/stream": "^0.3.28",
55
56
  "@endo/zip": "^0.2.34",
56
57
  "ansi-styles": "^6.2.1",
57
58
  "anylogger": "^0.21.0",
@@ -101,5 +102,5 @@
101
102
  "typeCoverage": {
102
103
  "atLeast": 75.26
103
104
  },
104
- "gitHead": "0f42fb639a6b3619de097ec0f819499200c9f6b7"
105
+ "gitHead": "6d9ae67c57499d7139dfce019b8c76f9ecdb825f"
105
106
  }
@@ -0,0 +1,156 @@
1
+ /* eslint-disable @jessie.js/safe-await-separator */
2
+ import { Fail, q } from '@agoric/assert';
3
+ import { kunser } from '@agoric/kmarshal';
4
+ import { makeQueue } from '@endo/stream';
5
+ import type { E } from '@endo/eventual-send';
6
+
7
+ import type { SwingsetController } from '../src/controller/controller.js';
8
+
9
+ const sink = () => {};
10
+
11
+ export const makeRunUtils = (
12
+ controller: SwingsetController,
13
+ log = (..._) => {},
14
+ ) => {
15
+ let cranksRun = 0;
16
+
17
+ const mutex = makeQueue();
18
+
19
+ mutex.put(controller.run());
20
+
21
+ const runThunk = async <T extends () => any>(
22
+ thunk: T,
23
+ ): Promise<ReturnType<T>> => {
24
+ try {
25
+ // this promise for the last lock may fail
26
+ await mutex.get();
27
+ } catch {
28
+ // noop because the result will resolve for the previous runMethod return
29
+ }
30
+
31
+ const thunkResult = await thunk();
32
+
33
+ const result = controller.run().then(cranks => {
34
+ cranksRun += cranks;
35
+ log(`kernel ran ${cranks} cranks`);
36
+ return thunkResult;
37
+ });
38
+ mutex.put(result.then(sink, sink));
39
+ return result;
40
+ };
41
+
42
+ const queueAndRun = async (deliveryThunk, voidResult = false) => {
43
+ log('queueAndRun at', cranksRun);
44
+
45
+ const kpid = await runThunk(deliveryThunk);
46
+
47
+ if (voidResult) {
48
+ return undefined;
49
+ }
50
+ const status = controller.kpStatus(kpid);
51
+ switch (status) {
52
+ case 'fulfilled':
53
+ return kunser(controller.kpResolution(kpid));
54
+ case 'rejected':
55
+ throw kunser(controller.kpResolution(kpid));
56
+ case 'unresolved':
57
+ throw Fail`unsettled value for ${q(kpid)}`;
58
+ default:
59
+ throw Fail`unknown promise status ${q(kpid)} ${q(status)}`;
60
+ }
61
+ };
62
+
63
+ type EVProxy = typeof E & {
64
+ sendOnly: (presence: unknown) => Record<string, (...args: any) => void>;
65
+ vat: (name: string) => Record<string, (...args: any) => Promise<any>>;
66
+ };
67
+
68
+ // IMPORTANT WARNING TO USERS OF `EV`
69
+ //
70
+ // `EV` presents an abstraction that can be used (within tests only!) to get
71
+ // much of the convenience with respect to messaging that `E` provides in
72
+ // normal code. However, this convenience comes with a huge caveat that all
73
+ // users of this convenience feature MUST keep in mind.
74
+ //
75
+ // A test can drop messages onto the kernel's run queue using the
76
+ // `controller.queueToVatRoot` and `controller.queueToVatObject` methods.
77
+ // These are synchronous operations which merely place messages onto the run
78
+ // queue without causing execution. Execution, on the other hand, is
79
+ // initiated by calling `controller.run`, which will cause the kernel to begin
80
+ // delivering messages to vats from the run queue, continuing until the run
81
+ // queue is exhausted. HOWEVER, exhaustion of the run queue, which resolves
82
+ // the result promise returned by the `run` call, IS NOT coupled in any causal
83
+ // way to the resolution of result promises associated with the individual
84
+ // queued messages themselves. The status and resolution values of these
85
+ // promises can be synchronously queried (by kpid) via the
86
+ // `controller.kpStatus` and `controller.kpResolution` methods once `run` has
87
+ // completed. These queries are only available once the swingset has
88
+ // reqlinquished agency, i.e., when the work initiated by `controller.run` has
89
+ // finished. At that point, nothing is going on inside the kernel, and
90
+ // nothing WILL be going on inside the kernel until a subsequent call to
91
+ // `controller.run`, which in turn will only have an effect if additional
92
+ // messages have been placed on the kernel run queue in the meantime. You MAY
93
+ // NOT call `queueToVatRoot`, `queueToVatObject`, `kpStatus`, or
94
+ // `kpResolution` while run queue execution, triggered by a call to `run`, is
95
+ // in progress
96
+ //
97
+ // The functionality made available by `EV` looks similar to that provided by
98
+ // `E`, but it is very much not. When you send a message using `EV`, it
99
+ // places the message onto the kernel run queue and then immediately invokes
100
+ // `controller.run`. When the result of `run` resolves, the kpid returned by
101
+ // the message enqueueing operation is queried. If at that time the promise
102
+ // it identifies is resolved (or rejected), the value it was resolved (or
103
+ // rejected) to is used as the result from the `EV` invocation. However, if
104
+ // it is still pending at that time, `EV` will throw an exception, which will
105
+ // manifest as a rejection and your test will fail confusingly or abort. This
106
+ // means that if you initiate some operation via an `EV` message send, it must
107
+ // complete within a single `run` cycle for it to be of any use to you. This
108
+ // is quite different from a message sent using `E`, which will return a
109
+ // promise that can remain pending indefinitely, possibly to be settled by a
110
+ // future message delivery.
111
+
112
+ // @ts-expect-error cast, approximate
113
+ const EV: EVProxy = presence =>
114
+ new Proxy(harden({}), {
115
+ get: (_t, method, _rx) => {
116
+ const boundMethod = (...args) =>
117
+ queueAndRun(() =>
118
+ controller.queueToVatObject(presence, method, args),
119
+ );
120
+ return harden(boundMethod);
121
+ },
122
+ });
123
+ EV.vat = vatName =>
124
+ new Proxy(harden({}), {
125
+ get: (_t, method, _rx) => {
126
+ const boundMethod = (...args) =>
127
+ queueAndRun(() => controller.queueToVatRoot(vatName, method, args));
128
+ return harden(boundMethod);
129
+ },
130
+ });
131
+ // @ts-expect-error xxx
132
+ EV.sendOnly = presence =>
133
+ new Proxy(harden({}), {
134
+ get: (_t, method, _rx) => {
135
+ const boundMethod = (...args) =>
136
+ queueAndRun(
137
+ () => controller.queueToVatObject(presence, method, args),
138
+ true,
139
+ );
140
+ return harden(boundMethod);
141
+ },
142
+ });
143
+ // @ts-expect-error xxx
144
+ EV.get = presence =>
145
+ new Proxy(harden({}), {
146
+ get: (_t, pathElement, _rx) =>
147
+ queueAndRun(() =>
148
+ controller.queueToVatRoot('bootstrap', 'awaitVatObject', [
149
+ presence,
150
+ [pathElement],
151
+ ]),
152
+ ),
153
+ });
154
+ return harden({ runThunk, EV });
155
+ };
156
+ export type RunUtils = ReturnType<typeof makeRunUtils>;