@agoric/swingset-vat 0.32.3-upgrade-18-dev-6ddbef0.0 → 0.32.3-upgrade-19-dev-c605745.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.
@@ -2,12 +2,18 @@ import { Fail, q } from '@endo/errors';
2
2
  import { kunser } from '@agoric/kmarshal';
3
3
  import { makeQueue } from '@endo/stream';
4
4
 
5
- /** @import { ERef } from '@endo/far' */
5
+ /**
6
+ * @import { ERef } from '@endo/far'
7
+ * @import { RunPolicy } from '../src/types-external.js'
8
+ */
9
+
10
+ /** @typedef {{ provideRunPolicy: () => RunPolicy | undefined }} RunHarness */
6
11
 
7
12
  /**
8
13
  * @param {import('../src/controller/controller.js').SwingsetController} controller
14
+ * @param {RunHarness} [harness]
9
15
  */
10
- export const makeRunUtils = controller => {
16
+ export const makeRunUtils = (controller, harness) => {
11
17
  const mutex = makeQueue();
12
18
  const logRunFailure = reason =>
13
19
  console.log('controller.run() failure', reason);
@@ -17,7 +23,7 @@ export const makeRunUtils = controller => {
17
23
  * Wait for exclusive access to the controller, then before relinquishing that access,
18
24
  * enqueue and process a delivery and return the result.
19
25
  *
20
- * @param {() => ERef<void | ReturnType<controller['queueToVatObject']>>} deliveryThunk
26
+ * @param {() => ERef<void | ReturnType<typeof controller['queueToVatObject']>>} deliveryThunk
21
27
  * function for enqueueing a delivery and returning the result kpid (if any)
22
28
  * @param {boolean} [voidResult] whether to ignore the result
23
29
  * @returns {Promise<any>}
@@ -25,7 +31,8 @@ export const makeRunUtils = controller => {
25
31
  const queueAndRun = async (deliveryThunk, voidResult = false) => {
26
32
  await mutex.get();
27
33
  const kpid = await deliveryThunk();
28
- const runResultP = controller.run();
34
+ const runPolicy = harness && harness.provideRunPolicy();
35
+ const runResultP = controller.run(runPolicy);
29
36
  mutex.put(runResultP.catch(logRunFailure));
30
37
  await runResultP;
31
38
 
@@ -46,10 +53,25 @@ export const makeRunUtils = controller => {
46
53
  };
47
54
 
48
55
  /**
49
- * @typedef {import('@endo/eventual-send').EProxy & {
50
- * sendOnly: (presence: unknown) => Record<string, (...args: any) => void>;
51
- * vat: (name: string) => Record<string, (...args: any) => Promise<any>>;
52
- * }} EVProxy
56
+ * @typedef EVProxyMethods
57
+ * @property {(presence: unknown) => Record<string, (...args: any) => Promise<void>>} sendOnly
58
+ * Returns a "methods proxy" for the presence that ignores the results of
59
+ * each method invocation.
60
+ * @property {(name: string) => Record<string, (...args: any) => Promise<any>>} vat
61
+ * Returns a "methods proxy" for the root object of the specified vat.
62
+ * So e.g. `EV.vat('foo').m(0)` becomes
63
+ * `controller.queueToVatRoot('foo', 'm', [0])`.
64
+ * @property {(presence: unknown) => Record<string, Promise<any>>} get
65
+ * Returns a "values proxy" for the presence for which each requested
66
+ * property manifests as a promise.
67
+ */
68
+ /**
69
+ * @typedef {import('@endo/eventual-send').EProxy & EVProxyMethods} EVProxy
70
+ * Given a presence, return a "methods proxy" for which each requested
71
+ * property manifests as a method that forwards its invocation through the
72
+ * controller to the presence as an invocation of an identically-named method
73
+ * with identical arguments (modulo passable translation).
74
+ * So e.g. `EV(x).m(0)` becomes `controller.queueToVatObject(x, 'm', [0])`.
53
75
  */
54
76
 
55
77
  // IMPORTANT WARNING TO USERS OF `EV`
@@ -96,52 +118,39 @@ export const makeRunUtils = controller => {
96
118
  // promise that can remain pending indefinitely, possibly to be settled by a
97
119
  // future message delivery.
98
120
 
99
- /** @type {EVProxy} */
100
- // @ts-expect-error cast, approximate
101
- const EV = Object.assign(
102
- presence =>
103
- new Proxy(harden({}), {
104
- get: (_t, method, _rx) => {
105
- const boundMethod = (...args) =>
106
- queueAndRun(() =>
107
- controller.queueToVatObject(presence, method, args),
108
- );
109
- return harden(boundMethod);
110
- },
111
- }),
112
- {
113
- vat: vatName =>
114
- new Proxy(harden({}), {
115
- get: (_t, method, _rx) => {
116
- const boundMethod = (...args) =>
117
- queueAndRun(() =>
118
- controller.queueToVatRoot(vatName, method, args),
119
- );
120
- return harden(boundMethod);
121
- },
122
- }),
123
- sendOnly: presence =>
124
- new Proxy(harden({}), {
125
- get: (_t, method, _rx) => {
126
- const boundMethod = (...args) =>
127
- queueAndRun(
128
- () => controller.queueToVatObject(presence, method, args),
129
- true,
130
- );
131
- return harden(boundMethod);
132
- },
133
- }),
134
- get: presence =>
135
- new Proxy(harden({}), {
136
- get: (_t, pathElement, _rx) =>
137
- queueAndRun(() =>
138
- controller.queueToVatRoot('bootstrap', 'awaitVatObject', [
139
- presence,
140
- [pathElement],
141
- ]),
142
- ),
143
- }),
144
- },
121
+ /**
122
+ * @template {(typeof controller.queueToVatObject) | (typeof controller.queueToVatRoot)} T
123
+ * @param {T} invoker
124
+ * @param {Parameters<T>[0]} target
125
+ * @param {boolean} [voidResult]
126
+ */
127
+ const makeMethodsProxy = (invoker, target, voidResult = false) =>
128
+ new Proxy(harden({}), {
129
+ get: (_t, method, _rx) => {
130
+ const resultPolicy = voidResult ? 'none' : undefined;
131
+ const boundMethod = (...args) =>
132
+ queueAndRun(
133
+ () => invoker(target, method, args, resultPolicy),
134
+ voidResult,
135
+ );
136
+ return harden(boundMethod);
137
+ },
138
+ });
139
+
140
+ const EV = /** @type {EVProxy} */ (
141
+ Object.assign(
142
+ presence => makeMethodsProxy(controller.queueToVatObject, presence),
143
+ {
144
+ vat: vatName => makeMethodsProxy(controller.queueToVatRoot, vatName),
145
+ sendOnly: presence =>
146
+ makeMethodsProxy(controller.queueToVatObject, presence, true),
147
+ get: presence =>
148
+ new Proxy(harden({}), {
149
+ get: (_t, key, _rx) =>
150
+ EV.vat('bootstrap').awaitVatObject(presence, [key]),
151
+ }),
152
+ },
153
+ )
145
154
  );
146
155
  return harden({ queueAndRun, EV });
147
156
  };
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @file Source code for a vat that exposes reflective methods for use in
3
+ * testing.
4
+ */
5
+
6
+ import { Fail, q } from '@endo/errors';
7
+ import { Far, E } from '@endo/far';
8
+ import { makePromiseKit } from '@endo/promise-kit';
9
+ import { objectMap } from '@agoric/internal';
10
+
11
+ /**
12
+ * @callback Die
13
+ * @param {unknown} completion
14
+ * @param {[target: unknown, method: string, ...args: unknown[]]} [finalSend]
15
+ */
16
+
17
+ /**
18
+ * @typedef {Array<[name: string, ...args: unknown[]]>} CallLog
19
+ */
20
+
21
+ /**
22
+ * @param {import('@agoric/swingset-vat').VatPowers} vatPowers
23
+ * @param {import('@agoric/vat-data').Baggage} baggage
24
+ */
25
+ export const makeReflectionMethods = (vatPowers, baggage) => {
26
+ let baggageHoldCount = 0;
27
+ /** @type {Map<object, CallLog>} */
28
+ const callLogsByRemotable = new Map();
29
+ const heldInHeap = [];
30
+ const send = (target, method, ...args) => E(target)[method](...args);
31
+ const makeSpy = (value, name, callLog) => {
32
+ const spyName = `get ${name}`;
33
+ const spy = {
34
+ [spyName](...args) {
35
+ callLog.push([name, ...args]);
36
+ return value;
37
+ },
38
+ }[spyName];
39
+ return spy;
40
+ };
41
+
42
+ return {
43
+ /** @type {Die} */
44
+ dieHappy: (completion, finalSend) => {
45
+ vatPowers.exitVat(completion);
46
+ if (finalSend) send(...finalSend);
47
+ },
48
+
49
+ /** @type {Die} */
50
+ dieSad: (reason, finalSend) => {
51
+ vatPowers.exitVatWithFailure(/** @type {Error} */ (reason));
52
+ if (finalSend) send(...finalSend);
53
+ },
54
+
55
+ holdInBaggage: (...values) => {
56
+ for (const value of values) {
57
+ baggage.init(`held-${baggageHoldCount}`, value);
58
+ baggageHoldCount += 1;
59
+ }
60
+ return baggageHoldCount;
61
+ },
62
+
63
+ holdInHeap: (...values) => heldInHeap.push(...values),
64
+
65
+ makePromiseKit: () => {
66
+ const { promise, ...resolverMethods } = makePromiseKit();
67
+ void promise.catch(() => {});
68
+ const resolver = Far('resolver', resolverMethods);
69
+ return harden({ promise, resolver });
70
+ },
71
+
72
+ makeUnsettledPromise() {
73
+ const { promise } = makePromiseKit();
74
+ void promise.catch(() => {});
75
+ return promise;
76
+ },
77
+
78
+ /**
79
+ * Returns a remotable with methods that return provided values. Invocations
80
+ * of those methods and their arguments are captured for later retrieval by
81
+ * `getCallLogForRemotable`.
82
+ *
83
+ * @param {string} [label]
84
+ * @param {Record<string, any>} [fields]
85
+ */
86
+ makeRemotable: (label = 'Remotable', fields = {}) => {
87
+ /** @type {CallLog} */
88
+ const callLog = [];
89
+ const methods = objectMap(fields, (value, name) =>
90
+ makeSpy(value, name, callLog),
91
+ );
92
+ const remotable = Far(label, { ...methods });
93
+ callLogsByRemotable.set(remotable, callLog);
94
+ return remotable;
95
+ },
96
+
97
+ /**
98
+ * @param {object} remotable
99
+ * @returns {CallLog}
100
+ */
101
+ getCallLogForRemotable: remotable =>
102
+ callLogsByRemotable.get(remotable) ||
103
+ Fail`unknown remotable ${q(remotable)}`,
104
+ };
105
+ };
106
+ harden(makeReflectionMethods);
107
+
108
+ export function buildRootObject(vatPowers, _vatParameters, baggage) {
109
+ const methods = makeReflectionMethods(vatPowers, baggage);
110
+ return Far('root', methods);
111
+ }