@agoric/swingset-liveslots 0.10.3-u17.1 → 0.10.3-u18.1
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 +17 -17
- package/src/collectionManager.js +0 -10
- package/src/index.js +1 -2
- package/src/liveslots.js +1 -23
- package/src/types-index.d.ts +4 -0
- package/src/types-index.js +2 -0
- package/src/virtualObjectManager.js +1 -1
- package/src/virtualReferences.js +1 -1
- package/src/watchedPromises.js +13 -3
- package/test/exo-utils.js +70 -0
- package/test/handled-promises.test.js +2 -70
- package/test/strict-test-env-upgrade.test.js +94 -0
- package/test/virtual-objects/set-debug-label-instances.js +1 -1
- package/test/virtual-objects/virtualObjectManager.test.js +4 -4
- package/test/watch-promise.test.js +42 -0
- package/tools/fakeVirtualObjectManager.js +2 -0
- package/tools/fakeVirtualSupport.js +10 -6
- package/tools/prepare-strict-test-env.js +124 -0
- package/tools/setup-vat-data.js +34 -7
- package/src/vatDataTypes.d.ts +0 -276
- package/src/vatDataTypes.js +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/swingset-liveslots",
|
|
3
|
-
"version": "0.10.3-
|
|
3
|
+
"version": "0.10.3-u18.1",
|
|
4
4
|
"description": "SwingSet ocap support layer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -17,22 +17,22 @@
|
|
|
17
17
|
"lint:eslint": "eslint ."
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@agoric/internal": "^0.4.0-
|
|
21
|
-
"@agoric/store": "^0.9.3-
|
|
22
|
-
"@endo/env-options": "^1.1.
|
|
23
|
-
"@endo/errors": "^1.2.
|
|
24
|
-
"@endo/eventual-send": "^1.2.
|
|
25
|
-
"@endo/exo": "^1.5.
|
|
26
|
-
"@endo/far": "^1.1.
|
|
27
|
-
"@endo/init": "^1.1.
|
|
28
|
-
"@endo/marshal": "^1.
|
|
29
|
-
"@endo/nat": "^5.0.
|
|
30
|
-
"@endo/pass-style": "^1.4.
|
|
31
|
-
"@endo/patterns": "^1.4.
|
|
32
|
-
"@endo/promise-kit": "^1.1.
|
|
20
|
+
"@agoric/internal": "^0.4.0-u18.1",
|
|
21
|
+
"@agoric/store": "^0.9.3-u18.1",
|
|
22
|
+
"@endo/env-options": "^1.1.8",
|
|
23
|
+
"@endo/errors": "^1.2.8",
|
|
24
|
+
"@endo/eventual-send": "^1.2.8",
|
|
25
|
+
"@endo/exo": "^1.5.7",
|
|
26
|
+
"@endo/far": "^1.1.9",
|
|
27
|
+
"@endo/init": "^1.1.7",
|
|
28
|
+
"@endo/marshal": "^1.6.2",
|
|
29
|
+
"@endo/nat": "^5.0.13",
|
|
30
|
+
"@endo/pass-style": "^1.4.7",
|
|
31
|
+
"@endo/patterns": "^1.4.7",
|
|
32
|
+
"@endo/promise-kit": "^1.1.8"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@agoric/kmarshal": "^0.1.1-
|
|
35
|
+
"@agoric/kmarshal": "^0.1.1-u18.1",
|
|
36
36
|
"ava": "^5.3.0"
|
|
37
37
|
},
|
|
38
38
|
"files": [
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"access": "public"
|
|
67
67
|
},
|
|
68
68
|
"typeCoverage": {
|
|
69
|
-
"atLeast": 75.
|
|
69
|
+
"atLeast": 75.24
|
|
70
70
|
},
|
|
71
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "f8c45b8a2e29a51522a81a6692af25b2d7f6b50f"
|
|
72
72
|
}
|
package/src/collectionManager.js
CHANGED
|
@@ -146,56 +146,48 @@ export function makeCollectionManager(
|
|
|
146
146
|
scalarMapStore: {
|
|
147
147
|
hasWeakKeys: false,
|
|
148
148
|
kindID: 0,
|
|
149
|
-
// eslint-disable-next-line no-use-before-define
|
|
150
149
|
reanimator: reanimateMapStore,
|
|
151
150
|
durable: false,
|
|
152
151
|
},
|
|
153
152
|
scalarWeakMapStore: {
|
|
154
153
|
hasWeakKeys: true,
|
|
155
154
|
kindID: 0,
|
|
156
|
-
// eslint-disable-next-line no-use-before-define
|
|
157
155
|
reanimator: reanimateWeakMapStore,
|
|
158
156
|
durable: false,
|
|
159
157
|
},
|
|
160
158
|
scalarSetStore: {
|
|
161
159
|
hasWeakKeys: false,
|
|
162
160
|
kindID: 0,
|
|
163
|
-
// eslint-disable-next-line no-use-before-define
|
|
164
161
|
reanimator: reanimateSetStore,
|
|
165
162
|
durable: false,
|
|
166
163
|
},
|
|
167
164
|
scalarWeakSetStore: {
|
|
168
165
|
hasWeakKeys: true,
|
|
169
166
|
kindID: 0,
|
|
170
|
-
// eslint-disable-next-line no-use-before-define
|
|
171
167
|
reanimator: reanimateWeakSetStore,
|
|
172
168
|
durable: false,
|
|
173
169
|
},
|
|
174
170
|
scalarDurableMapStore: {
|
|
175
171
|
hasWeakKeys: false,
|
|
176
172
|
kindID: 0,
|
|
177
|
-
// eslint-disable-next-line no-use-before-define
|
|
178
173
|
reanimator: reanimateMapStore,
|
|
179
174
|
durable: true,
|
|
180
175
|
},
|
|
181
176
|
scalarDurableWeakMapStore: {
|
|
182
177
|
hasWeakKeys: true,
|
|
183
178
|
kindID: 0,
|
|
184
|
-
// eslint-disable-next-line no-use-before-define
|
|
185
179
|
reanimator: reanimateWeakMapStore,
|
|
186
180
|
durable: true,
|
|
187
181
|
},
|
|
188
182
|
scalarDurableSetStore: {
|
|
189
183
|
hasWeakKeys: false,
|
|
190
184
|
kindID: 0,
|
|
191
|
-
// eslint-disable-next-line no-use-before-define
|
|
192
185
|
reanimator: reanimateSetStore,
|
|
193
186
|
durable: true,
|
|
194
187
|
},
|
|
195
188
|
scalarDurableWeakSetStore: {
|
|
196
189
|
hasWeakKeys: true,
|
|
197
190
|
kindID: 0,
|
|
198
|
-
// eslint-disable-next-line no-use-before-define
|
|
199
191
|
reanimator: reanimateWeakSetStore,
|
|
200
192
|
durable: true,
|
|
201
193
|
},
|
|
@@ -218,7 +210,6 @@ export function makeCollectionManager(
|
|
|
218
210
|
vrm.registerKind(
|
|
219
211
|
kindID,
|
|
220
212
|
storeKindInfo[kind].reanimator,
|
|
221
|
-
// eslint-disable-next-line no-use-before-define
|
|
222
213
|
deleteCollection,
|
|
223
214
|
storeKindInfo[kind].durable,
|
|
224
215
|
);
|
|
@@ -313,7 +304,6 @@ export function makeCollectionManager(
|
|
|
313
304
|
// * vref(o-4) -> "vc.5.r0000000001:o-4"
|
|
314
305
|
|
|
315
306
|
const encodeRemotable = remotable => {
|
|
316
|
-
// eslint-disable-next-line no-use-before-define
|
|
317
307
|
const ordinal = getOrdinal(remotable);
|
|
318
308
|
ordinal !== undefined || Fail`no ordinal for ${remotable}`;
|
|
319
309
|
const ordinalTag = zeroPad(ordinal, BIGINT_TAG_LEN);
|
package/src/index.js
CHANGED
package/src/liveslots.js
CHANGED
|
@@ -155,10 +155,8 @@ function build(
|
|
|
155
155
|
const { type, allocatedByVat, virtual, durable } = parseVatSlot(vref);
|
|
156
156
|
if (type === 'object' && allocatedByVat) {
|
|
157
157
|
if (virtual || durable) {
|
|
158
|
-
// eslint-disable-next-line no-use-before-define
|
|
159
158
|
vrm.setExportStatus(vref, 'reachable');
|
|
160
159
|
} else {
|
|
161
|
-
// eslint-disable-next-line no-use-before-define
|
|
162
160
|
const remotable = requiredValForSlot(vref);
|
|
163
161
|
exportedRemotables.add(remotable);
|
|
164
162
|
kernelRecognizableRemotables.add(vref);
|
|
@@ -183,7 +181,6 @@ function build(
|
|
|
183
181
|
|
|
184
182
|
if (wr && !wr.deref()) {
|
|
185
183
|
// we're in the COLLECTED state, or FINALIZED after a re-introduction
|
|
186
|
-
// eslint-disable-next-line no-use-before-define
|
|
187
184
|
addToPossiblyDeadSet(baseRef);
|
|
188
185
|
slotToVal.delete(baseRef);
|
|
189
186
|
}
|
|
@@ -209,11 +206,9 @@ function build(
|
|
|
209
206
|
// Support: o~.[prop](...args) remote method invocation
|
|
210
207
|
lsdebug(`makeImportedPresence handler.applyMethod (${slot})`);
|
|
211
208
|
if (disavowedPresences.has(o)) {
|
|
212
|
-
// eslint-disable-next-line no-use-before-define
|
|
213
209
|
exitVatWithFailure(disavowalError);
|
|
214
210
|
throw disavowalError;
|
|
215
211
|
}
|
|
216
|
-
// eslint-disable-next-line no-use-before-define
|
|
217
212
|
return queueMessage(slot, prop, args, returnedP);
|
|
218
213
|
},
|
|
219
214
|
applyFunction(o, args, returnedP) {
|
|
@@ -222,7 +217,6 @@ function build(
|
|
|
222
217
|
get(o, prop) {
|
|
223
218
|
lsdebug(`makeImportedPresence handler.get (${slot})`);
|
|
224
219
|
if (disavowedPresences.has(o)) {
|
|
225
|
-
// eslint-disable-next-line no-use-before-define
|
|
226
220
|
exitVatWithFailure(disavowalError);
|
|
227
221
|
throw disavowalError;
|
|
228
222
|
}
|
|
@@ -294,7 +288,6 @@ function build(
|
|
|
294
288
|
console.error(`mIPromise handler called after resolution`);
|
|
295
289
|
Fail`mIPromise handler called after resolution`;
|
|
296
290
|
}
|
|
297
|
-
// eslint-disable-next-line no-use-before-define
|
|
298
291
|
return queueMessage(vpid, prop, args, returnedP);
|
|
299
292
|
},
|
|
300
293
|
get(p, prop) {
|
|
@@ -347,17 +340,14 @@ function build(
|
|
|
347
340
|
// use a slot from the corresponding allocateX
|
|
348
341
|
|
|
349
342
|
function allocateExportID() {
|
|
350
|
-
// eslint-disable-next-line no-use-before-define
|
|
351
343
|
return vrm.allocateNextID('exportID');
|
|
352
344
|
}
|
|
353
345
|
|
|
354
346
|
function allocateCollectionID() {
|
|
355
|
-
// eslint-disable-next-line no-use-before-define
|
|
356
347
|
return vrm.allocateNextID('collectionID');
|
|
357
348
|
}
|
|
358
349
|
|
|
359
350
|
function allocatePromiseID() {
|
|
360
|
-
// eslint-disable-next-line no-use-before-define
|
|
361
351
|
const promiseID = vrm.allocateNextID('promiseID');
|
|
362
352
|
return makeVatSlot('promise', true, promiseID);
|
|
363
353
|
}
|
|
@@ -385,10 +375,8 @@ function build(
|
|
|
385
375
|
// do a syscall.resolve when it fires. The caller must finish
|
|
386
376
|
// doing their syscall before this turn finishes, to ensure the
|
|
387
377
|
// kernel isn't surprised by a spurious resolution.
|
|
388
|
-
// eslint-disable-next-line no-use-before-define
|
|
389
378
|
const p = requiredValForSlot(vpid);
|
|
390
379
|
// if (!knownResolutions.has(p)) { // TODO really?
|
|
391
|
-
// eslint-disable-next-line no-use-before-define
|
|
392
380
|
followForKernel(vpid, p);
|
|
393
381
|
return true;
|
|
394
382
|
}
|
|
@@ -400,7 +388,6 @@ function build(
|
|
|
400
388
|
return makeVatSlot('object', true, exportID);
|
|
401
389
|
}
|
|
402
390
|
|
|
403
|
-
// eslint-disable-next-line no-use-before-define
|
|
404
391
|
const m = makeMarshal(convertValToSlot, convertSlotToVal, {
|
|
405
392
|
marshalName: `liveSlots:${forVatID}`,
|
|
406
393
|
serializeBodyFormat: 'smallcaps',
|
|
@@ -413,7 +400,6 @@ function build(
|
|
|
413
400
|
console.warn('Logging sent error stack', err),
|
|
414
401
|
});
|
|
415
402
|
const unmeteredUnserialize = meterControl.unmetered(m.unserialize);
|
|
416
|
-
// eslint-disable-next-line no-use-before-define
|
|
417
403
|
const unmeteredConvertSlotToVal = meterControl.unmetered(convertSlotToVal);
|
|
418
404
|
|
|
419
405
|
function getSlotForVal(val) {
|
|
@@ -458,7 +444,6 @@ function build(
|
|
|
458
444
|
allocateExportID,
|
|
459
445
|
getSlotForVal,
|
|
460
446
|
requiredValForSlot,
|
|
461
|
-
// eslint-disable-next-line no-use-before-define
|
|
462
447
|
registerValue,
|
|
463
448
|
m.serialize,
|
|
464
449
|
unmeteredUnserialize,
|
|
@@ -471,10 +456,8 @@ function build(
|
|
|
471
456
|
vrm,
|
|
472
457
|
allocateExportID,
|
|
473
458
|
allocateCollectionID,
|
|
474
|
-
// eslint-disable-next-line no-use-before-define
|
|
475
459
|
convertValToSlot,
|
|
476
460
|
unmeteredConvertSlotToVal,
|
|
477
|
-
// eslint-disable-next-line no-use-before-define
|
|
478
461
|
registerValue,
|
|
479
462
|
m.serialize,
|
|
480
463
|
unmeteredUnserialize,
|
|
@@ -486,7 +469,6 @@ function build(
|
|
|
486
469
|
vrm,
|
|
487
470
|
vom,
|
|
488
471
|
collectionManager,
|
|
489
|
-
// eslint-disable-next-line no-use-before-define
|
|
490
472
|
convertValToSlot,
|
|
491
473
|
convertSlotToVal: unmeteredConvertSlotToVal,
|
|
492
474
|
maybeExportPromise,
|
|
@@ -516,7 +498,6 @@ function build(
|
|
|
516
498
|
slot = allocatePromiseID();
|
|
517
499
|
} else {
|
|
518
500
|
if (disavowedPresences.has(val)) {
|
|
519
|
-
// eslint-disable-next-line no-use-before-define
|
|
520
501
|
exitVatWithFailure(disavowalError);
|
|
521
502
|
throw disavowalError; // cannot reference a disavowed object
|
|
522
503
|
}
|
|
@@ -686,7 +667,6 @@ function build(
|
|
|
686
667
|
const priorResolution = knownResolutions.get(p);
|
|
687
668
|
if (priorResolution && !doneResolutions.has(slot)) {
|
|
688
669
|
const [priorRejected, priorRes] = priorResolution;
|
|
689
|
-
// eslint-disable-next-line no-use-before-define
|
|
690
670
|
collect(slot, priorRejected, priorRes);
|
|
691
671
|
}
|
|
692
672
|
}
|
|
@@ -972,7 +952,6 @@ function build(
|
|
|
972
952
|
}
|
|
973
953
|
// in both cases, we are now the decider, so treat it like an
|
|
974
954
|
// exported promise
|
|
975
|
-
// eslint-disable-next-line no-use-before-define
|
|
976
955
|
followForKernel(resultVPID, p);
|
|
977
956
|
}
|
|
978
957
|
}
|
|
@@ -1249,7 +1228,6 @@ function build(
|
|
|
1249
1228
|
possiblyRetiredSet,
|
|
1250
1229
|
slotToVal,
|
|
1251
1230
|
valToSlot,
|
|
1252
|
-
// eslint-disable-next-line no-use-before-define
|
|
1253
1231
|
afterDispatchActions,
|
|
1254
1232
|
});
|
|
1255
1233
|
|
|
@@ -1341,7 +1319,7 @@ function build(
|
|
|
1341
1319
|
|
|
1342
1320
|
/**
|
|
1343
1321
|
* @param {import('./types.js').VatDeliveryObject} delivery
|
|
1344
|
-
* @returns {
|
|
1322
|
+
* @returns {undefined | ReturnType<startVat>}
|
|
1345
1323
|
*/
|
|
1346
1324
|
function dispatchToUserspace(delivery) {
|
|
1347
1325
|
let result;
|
package/src/virtualReferences.js
CHANGED
package/src/watchedPromises.js
CHANGED
|
@@ -235,13 +235,23 @@ export function makeWatchedPromiseManager({
|
|
|
235
235
|
} else {
|
|
236
236
|
watchedPromiseTable.init(vpid, harden([[watcher, ...args]]));
|
|
237
237
|
|
|
238
|
+
promiseRegistrations.init(vpid, p);
|
|
239
|
+
|
|
240
|
+
// pseudoThen registers a settlement callback that will remove
|
|
241
|
+
// this promise from promiseRegistrations and
|
|
242
|
+
// watchedPromiseTable. To avoid triggering
|
|
243
|
+
// https://github.com/Agoric/agoric-sdk/issues/10757 and
|
|
244
|
+
// preventing slotToVal cleanup, the `pseudoThen()` should
|
|
245
|
+
// precede `maybeExportPromise()`. This isn't foolproof, but
|
|
246
|
+
// does mitigate in advance of a proper fix. See #10756 for
|
|
247
|
+
// details of this particular mitigation, and #10757 for the
|
|
248
|
+
// deeper bug.
|
|
249
|
+
pseudoThen(p, vpid);
|
|
250
|
+
|
|
238
251
|
// Ensure that this vat's promises are rejected at termination.
|
|
239
252
|
if (maybeExportPromise(vpid)) {
|
|
240
253
|
syscall.subscribe(vpid);
|
|
241
254
|
}
|
|
242
|
-
|
|
243
|
-
promiseRegistrations.init(vpid, p);
|
|
244
|
-
pseudoThen(p, vpid);
|
|
245
255
|
}
|
|
246
256
|
});
|
|
247
257
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { provideLazy as provide } from '@agoric/store';
|
|
2
|
+
|
|
3
|
+
// Partially duplicates @agoric/vat-data to avoid circular dependencies.
|
|
4
|
+
export const makeExoUtils = VatData => {
|
|
5
|
+
const { defineDurableKind, makeKindHandle, watchPromise } = VatData;
|
|
6
|
+
|
|
7
|
+
const provideKindHandle = (baggage, kindName) =>
|
|
8
|
+
provide(baggage, `${kindName}_kindHandle`, () => makeKindHandle(kindName));
|
|
9
|
+
|
|
10
|
+
const emptyRecord = harden({});
|
|
11
|
+
const initEmpty = () => emptyRecord;
|
|
12
|
+
|
|
13
|
+
const defineDurableExoClass = (
|
|
14
|
+
kindHandle,
|
|
15
|
+
interfaceGuard,
|
|
16
|
+
init,
|
|
17
|
+
methods,
|
|
18
|
+
options,
|
|
19
|
+
) =>
|
|
20
|
+
defineDurableKind(kindHandle, init, methods, {
|
|
21
|
+
...options,
|
|
22
|
+
thisfulMethods: true,
|
|
23
|
+
interfaceGuard,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const prepareExoClass = (
|
|
27
|
+
baggage,
|
|
28
|
+
kindName,
|
|
29
|
+
interfaceGuard,
|
|
30
|
+
init,
|
|
31
|
+
methods,
|
|
32
|
+
options = undefined,
|
|
33
|
+
) =>
|
|
34
|
+
defineDurableExoClass(
|
|
35
|
+
provideKindHandle(baggage, kindName),
|
|
36
|
+
interfaceGuard,
|
|
37
|
+
init,
|
|
38
|
+
methods,
|
|
39
|
+
options,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const prepareExo = (
|
|
43
|
+
baggage,
|
|
44
|
+
kindName,
|
|
45
|
+
interfaceGuard,
|
|
46
|
+
methods,
|
|
47
|
+
options = undefined,
|
|
48
|
+
) => {
|
|
49
|
+
const makeSingleton = prepareExoClass(
|
|
50
|
+
baggage,
|
|
51
|
+
kindName,
|
|
52
|
+
interfaceGuard,
|
|
53
|
+
initEmpty,
|
|
54
|
+
methods,
|
|
55
|
+
options,
|
|
56
|
+
);
|
|
57
|
+
return provide(baggage, `the_${kindName}`, () => makeSingleton());
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
defineDurableKind,
|
|
62
|
+
makeKindHandle,
|
|
63
|
+
watchPromise,
|
|
64
|
+
|
|
65
|
+
provideKindHandle,
|
|
66
|
+
defineDurableExoClass,
|
|
67
|
+
prepareExoClass,
|
|
68
|
+
prepareExo,
|
|
69
|
+
};
|
|
70
|
+
};
|
|
@@ -2,7 +2,7 @@ import test from 'ava';
|
|
|
2
2
|
|
|
3
3
|
import { Fail } from '@endo/errors';
|
|
4
4
|
import { Far } from '@endo/marshal';
|
|
5
|
-
import { M
|
|
5
|
+
import { M } from '@agoric/store';
|
|
6
6
|
import { makePromiseKit } from '@endo/promise-kit';
|
|
7
7
|
// Disabled to avoid circular dependencies.
|
|
8
8
|
// import { makeStoreUtils } from '@agoric/vat-data/src/vat-data-bindings.js';
|
|
@@ -10,79 +10,11 @@ import { makePromiseKit } from '@endo/promise-kit';
|
|
|
10
10
|
import { kslot, kser } from '@agoric/kmarshal';
|
|
11
11
|
import { setupTestLiveslots } from './liveslots-helpers.js';
|
|
12
12
|
import { makeResolve, makeReject } from './util.js';
|
|
13
|
+
import { makeExoUtils } from './exo-utils.js';
|
|
13
14
|
|
|
14
15
|
// eslint-disable-next-line no-unused-vars
|
|
15
16
|
const compareEntriesByKey = ([ka], [kb]) => (ka < kb ? -1 : 1);
|
|
16
17
|
|
|
17
|
-
// Paritally duplicates @agoric/vat-data to avoid circular dependencies.
|
|
18
|
-
const makeExoUtils = VatData => {
|
|
19
|
-
const { defineDurableKind, makeKindHandle, watchPromise } = VatData;
|
|
20
|
-
|
|
21
|
-
const provideKindHandle = (baggage, kindName) =>
|
|
22
|
-
provide(baggage, `${kindName}_kindHandle`, () => makeKindHandle(kindName));
|
|
23
|
-
|
|
24
|
-
const emptyRecord = harden({});
|
|
25
|
-
const initEmpty = () => emptyRecord;
|
|
26
|
-
|
|
27
|
-
const defineDurableExoClass = (
|
|
28
|
-
kindHandle,
|
|
29
|
-
interfaceGuard,
|
|
30
|
-
init,
|
|
31
|
-
methods,
|
|
32
|
-
options,
|
|
33
|
-
) =>
|
|
34
|
-
defineDurableKind(kindHandle, init, methods, {
|
|
35
|
-
...options,
|
|
36
|
-
thisfulMethods: true,
|
|
37
|
-
interfaceGuard,
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
const prepareExoClass = (
|
|
41
|
-
baggage,
|
|
42
|
-
kindName,
|
|
43
|
-
interfaceGuard,
|
|
44
|
-
init,
|
|
45
|
-
methods,
|
|
46
|
-
options = undefined,
|
|
47
|
-
) =>
|
|
48
|
-
defineDurableExoClass(
|
|
49
|
-
provideKindHandle(baggage, kindName),
|
|
50
|
-
interfaceGuard,
|
|
51
|
-
init,
|
|
52
|
-
methods,
|
|
53
|
-
options,
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const prepareExo = (
|
|
57
|
-
baggage,
|
|
58
|
-
kindName,
|
|
59
|
-
interfaceGuard,
|
|
60
|
-
methods,
|
|
61
|
-
options = undefined,
|
|
62
|
-
) => {
|
|
63
|
-
const makeSingleton = prepareExoClass(
|
|
64
|
-
baggage,
|
|
65
|
-
kindName,
|
|
66
|
-
interfaceGuard,
|
|
67
|
-
initEmpty,
|
|
68
|
-
methods,
|
|
69
|
-
options,
|
|
70
|
-
);
|
|
71
|
-
return provide(baggage, `the_${kindName}`, () => makeSingleton());
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
defineDurableKind,
|
|
76
|
-
makeKindHandle,
|
|
77
|
-
watchPromise,
|
|
78
|
-
|
|
79
|
-
provideKindHandle,
|
|
80
|
-
defineDurableExoClass,
|
|
81
|
-
prepareExoClass,
|
|
82
|
-
prepareExo,
|
|
83
|
-
};
|
|
84
|
-
};
|
|
85
|
-
|
|
86
18
|
// cf. packages/SwingSet/test/vat-durable-promise-watcher.js
|
|
87
19
|
const buildPromiseWatcherRootObject = (vatPowers, vatParameters, baggage) => {
|
|
88
20
|
const { VatData } = vatPowers;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* global globalThis */
|
|
2
|
+
// eslint-disable-next-line import/order
|
|
3
|
+
import { annihilate, startLife } from '../tools/prepare-strict-test-env.js';
|
|
4
|
+
|
|
5
|
+
import test from 'ava';
|
|
6
|
+
|
|
7
|
+
import { makeUpgradeDisconnection } from '@agoric/internal/src/upgrade-api.js';
|
|
8
|
+
import { makeExoUtils } from './exo-utils.js';
|
|
9
|
+
|
|
10
|
+
test.serial('kind redefinition enforced', async t => {
|
|
11
|
+
annihilate();
|
|
12
|
+
|
|
13
|
+
const { prepareExoClass } = makeExoUtils(globalThis.VatData);
|
|
14
|
+
|
|
15
|
+
await startLife(async baggage => {
|
|
16
|
+
const makeTestExo = prepareExoClass(
|
|
17
|
+
baggage,
|
|
18
|
+
'TestExo',
|
|
19
|
+
undefined,
|
|
20
|
+
() => ({}),
|
|
21
|
+
{
|
|
22
|
+
foo() {
|
|
23
|
+
return 'bar';
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
baggage.init('testExo', makeTestExo());
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
await t.throwsAsync(
|
|
32
|
+
async () =>
|
|
33
|
+
startLife(async () => {
|
|
34
|
+
// Not redefining the kind here
|
|
35
|
+
}),
|
|
36
|
+
{ message: 'defineDurableKind not called for tags: [TestExo]' },
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
await startLife(async baggage => {
|
|
40
|
+
prepareExoClass(baggage, 'TestExo', undefined, () => ({}), {
|
|
41
|
+
foo() {
|
|
42
|
+
return 'baz';
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
t.is(baggage.get('testExo').foo(), 'baz');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test.serial('decided promise rejected', async t => {
|
|
51
|
+
annihilate();
|
|
52
|
+
|
|
53
|
+
const { prepareExo } = makeExoUtils(globalThis.VatData);
|
|
54
|
+
const { watchPromise } = globalThis.VatData;
|
|
55
|
+
|
|
56
|
+
t.plan(1);
|
|
57
|
+
|
|
58
|
+
await startLife(async baggage => {
|
|
59
|
+
const watcher = prepareExo(
|
|
60
|
+
baggage,
|
|
61
|
+
'DurablePromiseTestWatcher',
|
|
62
|
+
undefined,
|
|
63
|
+
{
|
|
64
|
+
onFulfilled(value) {
|
|
65
|
+
t.fail(
|
|
66
|
+
`First incarnation watcher onFulfilled triggered with value ${value}`,
|
|
67
|
+
);
|
|
68
|
+
},
|
|
69
|
+
onRejected(reason) {
|
|
70
|
+
t.fail(
|
|
71
|
+
`First incarnation watcher onRejected triggered with reason ${reason}`,
|
|
72
|
+
);
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const never = harden(new Promise(() => {}));
|
|
78
|
+
|
|
79
|
+
watchPromise(never, watcher);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
await startLife(async baggage => {
|
|
83
|
+
prepareExo(baggage, 'DurablePromiseTestWatcher', undefined, {
|
|
84
|
+
onFulfilled(value) {
|
|
85
|
+
t.fail(
|
|
86
|
+
`Second incarnation watcher onFulfilled triggered with value ${value}`,
|
|
87
|
+
);
|
|
88
|
+
},
|
|
89
|
+
onRejected(reason) {
|
|
90
|
+
t.deepEqual(reason, makeUpgradeDisconnection('vat upgraded', 1));
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -127,8 +127,8 @@ test('multifaceted virtual objects', t => {
|
|
|
127
127
|
|
|
128
128
|
flushStateCache();
|
|
129
129
|
t.deepEqual(log.splice(0), [
|
|
130
|
-
`get kindIDID => undefined`,
|
|
131
130
|
`get idCounters => undefined`,
|
|
131
|
+
`get kindIDID => undefined`,
|
|
132
132
|
`set kindIDID 1`,
|
|
133
133
|
`set vom.vkind.2.descriptor {"kindID":"2","tag":"multithing"}`,
|
|
134
134
|
`set vom.${kid}/1 ${multiThingVal('foo', 1)}`,
|
|
@@ -203,8 +203,8 @@ test('virtual object operations', t => {
|
|
|
203
203
|
// t3-0: 'thing-3' 200 0
|
|
204
204
|
const thing4 = makeThing('thing-4', 300); // [t4-0* t3-0* t2-0* t1-0*]
|
|
205
205
|
// t4-0: 'thing-4' 300 0
|
|
206
|
-
t.is(log.shift(), `get kindIDID => undefined`);
|
|
207
206
|
t.is(log.shift(), `get idCounters => undefined`);
|
|
207
|
+
t.is(log.shift(), `get kindIDID => undefined`);
|
|
208
208
|
t.is(log.shift(), `set kindIDID 1`);
|
|
209
209
|
t.is(log.shift(), `set vom.vkind.2.descriptor {"kindID":"2","tag":"thing"}`);
|
|
210
210
|
t.is(log.shift(), `set vom.vkind.3.descriptor {"kindID":"3","tag":"zot"}`);
|
|
@@ -468,8 +468,8 @@ test('symbol named methods', t => {
|
|
|
468
468
|
// t1-0: 'thing-1' 0 0
|
|
469
469
|
const thing2 = makeThing('thing-2', 100); // [t1-0* t2-0*]
|
|
470
470
|
// t2-0: 'thing-2' 100 0
|
|
471
|
-
t.is(log.shift(), `get kindIDID => undefined`);
|
|
472
471
|
t.is(log.shift(), `get idCounters => undefined`);
|
|
472
|
+
t.is(log.shift(), `get kindIDID => undefined`);
|
|
473
473
|
t.is(log.shift(), `set kindIDID 1`);
|
|
474
474
|
t.is(
|
|
475
475
|
log.shift(),
|
|
@@ -649,8 +649,8 @@ test('virtual object gc', t => {
|
|
|
649
649
|
},
|
|
650
650
|
});
|
|
651
651
|
|
|
652
|
-
t.is(log.shift(), `get kindIDID => undefined`);
|
|
653
652
|
t.is(log.shift(), `get idCounters => undefined`);
|
|
653
|
+
t.is(log.shift(), `get kindIDID => undefined`);
|
|
654
654
|
t.is(log.shift(), `set kindIDID 1`);
|
|
655
655
|
const skit = [
|
|
656
656
|
'storeKindIDTable',
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
|
|
3
|
+
import { Far } from '@endo/marshal';
|
|
4
|
+
import { makePromiseKit } from '@endo/promise-kit';
|
|
5
|
+
import { setupTestLiveslots } from './liveslots-helpers.js';
|
|
6
|
+
|
|
7
|
+
const build = vatPowers => {
|
|
8
|
+
const { VatData } = vatPowers;
|
|
9
|
+
const { makeKindHandle, defineDurableKind, watchPromise } = VatData;
|
|
10
|
+
|
|
11
|
+
const kh = makeKindHandle('handler');
|
|
12
|
+
const init = () => ({});
|
|
13
|
+
const behavior = {
|
|
14
|
+
onFulfilled: _value => 0,
|
|
15
|
+
onRejected: _reason => 0,
|
|
16
|
+
};
|
|
17
|
+
const makeHandler = defineDurableKind(kh, init, behavior);
|
|
18
|
+
|
|
19
|
+
return Far('root', {
|
|
20
|
+
async run() {
|
|
21
|
+
const pr = makePromiseKit();
|
|
22
|
+
const handler = makeHandler();
|
|
23
|
+
watchPromise(pr.promise, handler);
|
|
24
|
+
pr.resolve('ignored');
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
test('watched local promises should not leak slotToVal entries', async t => {
|
|
30
|
+
const { dispatchMessage, testHooks } = await setupTestLiveslots(
|
|
31
|
+
t,
|
|
32
|
+
build,
|
|
33
|
+
'vatA',
|
|
34
|
+
);
|
|
35
|
+
const { slotToVal } = testHooks;
|
|
36
|
+
const initial = slotToVal.size;
|
|
37
|
+
|
|
38
|
+
await dispatchMessage('run');
|
|
39
|
+
t.is(slotToVal.size, initial);
|
|
40
|
+
await dispatchMessage('run');
|
|
41
|
+
t.is(slotToVal.size, initial);
|
|
42
|
+
});
|
|
@@ -23,6 +23,7 @@ export function makeFakeVirtualObjectManager(vrm, fakeStuff) {
|
|
|
23
23
|
VirtualObjectAwareWeakSet,
|
|
24
24
|
flushStateCache,
|
|
25
25
|
canBeDurable,
|
|
26
|
+
insistAllDurableKindsReconnected,
|
|
26
27
|
} = makeVirtualObjectManager(
|
|
27
28
|
fakeStuff.syscall,
|
|
28
29
|
vrm,
|
|
@@ -43,6 +44,7 @@ export function makeFakeVirtualObjectManager(vrm, fakeStuff) {
|
|
|
43
44
|
defineDurableKindMulti,
|
|
44
45
|
makeKindHandle,
|
|
45
46
|
canBeDurable,
|
|
47
|
+
insistAllDurableKindsReconnected,
|
|
46
48
|
VirtualObjectAwareWeakMap,
|
|
47
49
|
VirtualObjectAwareWeakSet,
|
|
48
50
|
};
|
|
@@ -28,12 +28,14 @@ class FakeFinalizationRegistry {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
class FakeWeakRef {
|
|
31
|
+
#target;
|
|
32
|
+
|
|
31
33
|
constructor(target) {
|
|
32
|
-
this
|
|
34
|
+
this.#target = target;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
deref() {
|
|
36
|
-
return this
|
|
38
|
+
return this.#target; // strong ref
|
|
37
39
|
}
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -41,6 +43,7 @@ export function makeFakeLiveSlotsStuff(options = {}) {
|
|
|
41
43
|
let vrm;
|
|
42
44
|
function setVrm(vrmToUse) {
|
|
43
45
|
assert(!vrm, 'vrm already configured');
|
|
46
|
+
vrmToUse.initializeIDCounters();
|
|
44
47
|
vrm = vrmToUse;
|
|
45
48
|
}
|
|
46
49
|
|
|
@@ -174,6 +177,7 @@ export function makeFakeLiveSlotsStuff(options = {}) {
|
|
|
174
177
|
// and the WeakRef may or may not contain the target value. Use
|
|
175
178
|
// options={weak:true} to match that behavior, or the default weak:false to
|
|
176
179
|
// keep strong references.
|
|
180
|
+
const WeakRefForSlot = weak ? RealWeakRef : FakeWeakRef;
|
|
177
181
|
const valToSlot = new WeakMap();
|
|
178
182
|
const slotToVal = new Map();
|
|
179
183
|
|
|
@@ -183,7 +187,7 @@ export function makeFakeLiveSlotsStuff(options = {}) {
|
|
|
183
187
|
|
|
184
188
|
function getValForSlot(slot) {
|
|
185
189
|
const d = slotToVal.get(slot);
|
|
186
|
-
return d &&
|
|
190
|
+
return d && d.deref();
|
|
187
191
|
}
|
|
188
192
|
|
|
189
193
|
function requiredValForSlot(slot) {
|
|
@@ -193,7 +197,7 @@ export function makeFakeLiveSlotsStuff(options = {}) {
|
|
|
193
197
|
}
|
|
194
198
|
|
|
195
199
|
function setValForSlot(slot, val) {
|
|
196
|
-
slotToVal.set(slot,
|
|
200
|
+
slotToVal.set(slot, new WeakRefForSlot(val));
|
|
197
201
|
}
|
|
198
202
|
|
|
199
203
|
function convertValToSlot(val) {
|
|
@@ -230,7 +234,6 @@ export function makeFakeLiveSlotsStuff(options = {}) {
|
|
|
230
234
|
assert.fail('fake liveSlots stuff configured without vrm');
|
|
231
235
|
}
|
|
232
236
|
}
|
|
233
|
-
// eslint-disable-next-line no-use-before-define
|
|
234
237
|
registerEntry(baseRef, val, facet !== undefined);
|
|
235
238
|
if (!result) {
|
|
236
239
|
result = val;
|
|
@@ -275,6 +278,7 @@ export function makeFakeLiveSlotsStuff(options = {}) {
|
|
|
275
278
|
return {
|
|
276
279
|
syscall,
|
|
277
280
|
allocateExportID,
|
|
281
|
+
allocatePromiseID,
|
|
278
282
|
allocateCollectionID,
|
|
279
283
|
getSlotForVal,
|
|
280
284
|
requiredValForSlot,
|
|
@@ -339,7 +343,7 @@ export function makeFakeWatchedPromiseManager(
|
|
|
339
343
|
* @param {object} [options]
|
|
340
344
|
* @param {number} [options.cacheSize]
|
|
341
345
|
* @param {boolean} [options.relaxDurabilityRules]
|
|
342
|
-
* @param {Map<
|
|
346
|
+
* @param {Map<string, string>} [options.fakeStore]
|
|
343
347
|
* @param {WeakMapConstructor} [options.WeakMap]
|
|
344
348
|
* @param {WeakSetConstructor} [options.WeakSet]
|
|
345
349
|
* @param {boolean} [options.weak]
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prepare Agoric SwingSet vat global strict environment for testing.
|
|
3
|
+
*
|
|
4
|
+
* Installs Hardened JS (and does lockdown), plus adds mocks for virtual objects
|
|
5
|
+
* and stores.
|
|
6
|
+
*
|
|
7
|
+
* Exports tools for simulating upgrades.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import '@agoric/internal/src/install-ses-debug.js';
|
|
11
|
+
|
|
12
|
+
// eslint-disable-next-line import/order
|
|
13
|
+
import { reincarnate, flushIncarnation } from './setup-vat-data.js';
|
|
14
|
+
|
|
15
|
+
import { makePromiseKit } from '@endo/promise-kit';
|
|
16
|
+
import { Fail } from '@endo/errors';
|
|
17
|
+
import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js';
|
|
18
|
+
import { makeUpgradeDisconnection } from '@agoric/internal/src/upgrade-api.js';
|
|
19
|
+
|
|
20
|
+
export { flushIncarnation };
|
|
21
|
+
export { eventLoopIteration as nextCrank };
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @import { PromiseKit } from '@endo/promise-kit'
|
|
25
|
+
* @import { Baggage } from '@agoric/swingset-liveslots'
|
|
26
|
+
* @import { ReincarnateOptions } from './setup-vat-data.js'
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** @type {ReincarnateOptions} */
|
|
30
|
+
let incarnation;
|
|
31
|
+
let incarnationNumber = 0;
|
|
32
|
+
|
|
33
|
+
/** @param {Omit<ReincarnateOptions, 'fakeVomKit' | 'fakeStore'>} [options] */
|
|
34
|
+
export const annihilate = (options = {}) => {
|
|
35
|
+
// @ts-expect-error fakeStore and fakeVomKit don't exist on type, but drop them if they do at runtime
|
|
36
|
+
const { fakeStore: _fs, fakeVomKit: _fvk, ...opts } = options;
|
|
37
|
+
incarnation = reincarnate({ relaxDurabilityRules: false, ...opts });
|
|
38
|
+
incarnationNumber = 0;
|
|
39
|
+
return incarnation;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/** @returns {Baggage} */
|
|
43
|
+
export const getBaggage = () => {
|
|
44
|
+
return incarnation.fakeVomKit.cm.provideBaggage();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {ReincarnateOptions} [fromIncarnation]
|
|
49
|
+
*/
|
|
50
|
+
export const nextLife = (fromIncarnation = incarnation) => {
|
|
51
|
+
incarnation = reincarnate(fromIncarnation);
|
|
52
|
+
incarnationNumber += 1;
|
|
53
|
+
return incarnation;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @template {(baggage: Baggage) => Promise<any> | any} B
|
|
58
|
+
* @param {B} build
|
|
59
|
+
* @param {(tools: Awaited<ReturnType<B>>) => Promise<void> | void} [run]
|
|
60
|
+
* @param {object} [options]
|
|
61
|
+
* @param {ReincarnateOptions} [options.fromIncarnation]
|
|
62
|
+
* @param {boolean} [options.cleanStart]
|
|
63
|
+
*/
|
|
64
|
+
export const startLife = async (
|
|
65
|
+
build,
|
|
66
|
+
run,
|
|
67
|
+
{ fromIncarnation, cleanStart } = {},
|
|
68
|
+
) => {
|
|
69
|
+
await eventLoopIteration();
|
|
70
|
+
if (cleanStart) annihilate();
|
|
71
|
+
const oldIncarnationNumber = incarnationNumber;
|
|
72
|
+
const oldIncarnation = incarnation;
|
|
73
|
+
const disconnectionObject = makeUpgradeDisconnection(
|
|
74
|
+
'vat upgraded',
|
|
75
|
+
oldIncarnationNumber,
|
|
76
|
+
);
|
|
77
|
+
const { fakeVomKit } = nextLife(fromIncarnation);
|
|
78
|
+
/** @type {Map<string, PromiseKit<any>>} */
|
|
79
|
+
const previouslyWatchedPromises = new Map();
|
|
80
|
+
let buildTools;
|
|
81
|
+
try {
|
|
82
|
+
buildTools = await build(getBaggage());
|
|
83
|
+
fakeVomKit.wpm.loadWatchedPromiseTable(vref => {
|
|
84
|
+
// See revivePromise in liveslots.js
|
|
85
|
+
const { getValForSlot, valToSlot, setValForSlot } = fakeVomKit.fakeStuff;
|
|
86
|
+
// Assume all promises were decided by the previous incarnation
|
|
87
|
+
!getValForSlot(vref) || Fail`Attempting to revive known promise ${vref}`;
|
|
88
|
+
const pk = makePromiseKit();
|
|
89
|
+
previouslyWatchedPromises.set(vref, pk);
|
|
90
|
+
const val = pk.promise;
|
|
91
|
+
valToSlot.set(val, vref);
|
|
92
|
+
setValForSlot(vref, val);
|
|
93
|
+
return val;
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
fakeVomKit.vom.insistAllDurableKindsReconnected();
|
|
97
|
+
|
|
98
|
+
await eventLoopIteration();
|
|
99
|
+
// End of start crank
|
|
100
|
+
} catch (err) {
|
|
101
|
+
// Rollback upgrade
|
|
102
|
+
incarnation = oldIncarnation;
|
|
103
|
+
incarnationNumber = oldIncarnationNumber;
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Simulate a dispatch of previously decided promise rejections
|
|
108
|
+
// In real swingset this could happen after some deliveries
|
|
109
|
+
for (const { reject } of previouslyWatchedPromises.values()) {
|
|
110
|
+
reject(disconnectionObject);
|
|
111
|
+
}
|
|
112
|
+
await eventLoopIteration();
|
|
113
|
+
// End of resolution dispatch crank
|
|
114
|
+
|
|
115
|
+
if (run) {
|
|
116
|
+
await run(buildTools);
|
|
117
|
+
await eventLoopIteration();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return incarnation;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Setup the initial incarnation
|
|
124
|
+
annihilate();
|
package/tools/setup-vat-data.js
CHANGED
|
@@ -12,7 +12,9 @@ import { makeFakeVirtualStuff } from './fakeVirtualSupport.js';
|
|
|
12
12
|
|
|
13
13
|
const { WeakMap, WeakSet } = globalThis;
|
|
14
14
|
|
|
15
|
-
/** @
|
|
15
|
+
/** @typedef {ReturnType<typeof makeFakeVirtualStuff>} FakeVomKit */
|
|
16
|
+
|
|
17
|
+
/** @type {FakeVomKit} */
|
|
16
18
|
let fakeVomKit;
|
|
17
19
|
|
|
18
20
|
globalThis.VatData = harden({
|
|
@@ -44,18 +46,43 @@ globalThis.VatData = harden({
|
|
|
44
46
|
|
|
45
47
|
globalThis[PassStyleOfEndowmentSymbol] = passStyleOf;
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
/**
|
|
50
|
+
* @typedef {import("@agoric/internal").Simplify<
|
|
51
|
+
* Omit<NonNullable<Parameters<typeof makeFakeVirtualStuff>[0]>, 'WeakMap' | 'WeakSet'> &
|
|
52
|
+
* { fakeVomKit: FakeVomKit; fakeStore: Map<string, string> }
|
|
53
|
+
* >} ReincarnateOptions
|
|
54
|
+
*/
|
|
49
55
|
|
|
50
|
-
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
* @param {Partial<ReincarnateOptions>} options
|
|
59
|
+
* @returns {Omit<ReincarnateOptions, 'fakeVomKit'>}
|
|
60
|
+
*/
|
|
61
|
+
export const flushIncarnation = (options = {}) => {
|
|
62
|
+
const { fakeVomKit: fvk = fakeVomKit, ...fakeStuffOptions } = options;
|
|
63
|
+
|
|
64
|
+
if (fvk) {
|
|
51
65
|
fvk.vom.flushStateCache();
|
|
52
66
|
fvk.cm.flushSchemaCache();
|
|
53
67
|
fvk.vrm.flushIDCounters();
|
|
54
68
|
}
|
|
55
69
|
|
|
70
|
+
// Clone previous fakeStore (if any) to avoid mutations from previous incarnation
|
|
71
|
+
const fakeStore = new Map(options.fakeStore);
|
|
72
|
+
|
|
73
|
+
return { ...fakeStuffOptions, fakeStore };
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
*
|
|
78
|
+
* @param {Partial<ReincarnateOptions>} options
|
|
79
|
+
* @returns {ReincarnateOptions}
|
|
80
|
+
*/
|
|
81
|
+
export const reincarnate = (options = {}) => {
|
|
82
|
+
const clonedIncarnation = flushIncarnation(options);
|
|
83
|
+
|
|
56
84
|
fakeVomKit = makeFakeVirtualStuff({
|
|
57
|
-
...
|
|
58
|
-
fakeStore,
|
|
85
|
+
...clonedIncarnation,
|
|
59
86
|
WeakMap,
|
|
60
87
|
WeakSet,
|
|
61
88
|
});
|
|
@@ -65,5 +92,5 @@ export const reincarnate = (options = {}) => {
|
|
|
65
92
|
// @ts-expect-error ditto
|
|
66
93
|
globalThis.WeakSet = fakeVomKit.vom.VirtualObjectAwareWeakSet;
|
|
67
94
|
|
|
68
|
-
return { ...
|
|
95
|
+
return { ...clonedIncarnation, fakeVomKit };
|
|
69
96
|
};
|
package/src/vatDataTypes.d.ts
DELETED
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Types for vat-data
|
|
3
|
-
*
|
|
4
|
-
* Facet is a single object with methods.
|
|
5
|
-
* Behavior is a description when defining a kind of what facets it will have.
|
|
6
|
-
* For the non-multi defineKind, there is just one facet so it doesn't have a key.
|
|
7
|
-
*/
|
|
8
|
-
import type {
|
|
9
|
-
MapStore,
|
|
10
|
-
SetStore,
|
|
11
|
-
StoreOptions,
|
|
12
|
-
WeakMapStore,
|
|
13
|
-
WeakSetStore,
|
|
14
|
-
} from '@agoric/store';
|
|
15
|
-
import type { Amplify, IsInstance, ReceivePower, StateShape } from '@endo/exo';
|
|
16
|
-
import type { RemotableObject } from '@endo/pass-style';
|
|
17
|
-
import type { RemotableBrand } from '@endo/eventual-send';
|
|
18
|
-
import type { InterfaceGuard, Pattern } from '@endo/patterns';
|
|
19
|
-
import type { makeWatchedPromiseManager } from './watchedPromises.js';
|
|
20
|
-
|
|
21
|
-
// TODO should be moved into @endo/patterns and eventually imported here
|
|
22
|
-
// instead of this local definition.
|
|
23
|
-
export type InterfaceGuardKit = Record<string, InterfaceGuard>;
|
|
24
|
-
export type { MapStore, Pattern };
|
|
25
|
-
|
|
26
|
-
// This needs `any` values. If they were `unknown`, code that uses Baggage
|
|
27
|
-
// would need explicit runtime checks or casts for every fetch, which is
|
|
28
|
-
// onerous.
|
|
29
|
-
export type Baggage = MapStore<string, any>;
|
|
30
|
-
|
|
31
|
-
type WatchedPromisesManager = ReturnType<typeof makeWatchedPromiseManager>;
|
|
32
|
-
|
|
33
|
-
type Tail<T extends any[]> = T extends [head: any, ...rest: infer Rest]
|
|
34
|
-
? Rest
|
|
35
|
-
: [];
|
|
36
|
-
|
|
37
|
-
// used to omit the 'context' parameter
|
|
38
|
-
type OmitFirstArg<F> = F extends (x: any, ...args: infer P) => infer R
|
|
39
|
-
? (...args: P) => R
|
|
40
|
-
: never;
|
|
41
|
-
|
|
42
|
-
// The type of a passable local object with methods.
|
|
43
|
-
// An internal helper to avoid having to repeat `O`.
|
|
44
|
-
type PrimaryRemotable<O> = O & RemotableObject & RemotableBrand<{}, O>;
|
|
45
|
-
|
|
46
|
-
export type KindFacet<O> = PrimaryRemotable<{
|
|
47
|
-
[K in keyof O]: OmitFirstArg<O[K]>; // omit the 'context' parameter
|
|
48
|
-
}>;
|
|
49
|
-
|
|
50
|
-
export type KindFacets<B> = {
|
|
51
|
-
[FacetKey in keyof B]: KindFacet<B[FacetKey]>;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export type KindContext<S, F> = { state: S; self: KindFacet<F> };
|
|
55
|
-
export type MultiKindContext<S, B> = { state: S; facets: KindFacets<B> };
|
|
56
|
-
|
|
57
|
-
export type PlusContext<C, M extends (...args: any[]) => any> = (
|
|
58
|
-
c: C,
|
|
59
|
-
...args: Parameters<M>
|
|
60
|
-
) => ReturnType<M>;
|
|
61
|
-
|
|
62
|
-
export type FunctionsPlusContext<
|
|
63
|
-
C,
|
|
64
|
-
O extends Record<string, (...args: any[]) => any>,
|
|
65
|
-
> = {
|
|
66
|
-
[K in keyof O]: PlusContext<C, O[K]>;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
declare class DurableKindHandleClass {
|
|
70
|
-
private descriptionTag: string;
|
|
71
|
-
}
|
|
72
|
-
export type DurableKindHandle = DurableKindHandleClass;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Grab bag of options that can be provided to `defineDurableKind` and its
|
|
76
|
-
* siblings. Not all options are meaningful in all contexts. See the
|
|
77
|
-
* doc-comments on each option.
|
|
78
|
-
*/
|
|
79
|
-
export type DefineKindOptions<C> = {
|
|
80
|
-
/**
|
|
81
|
-
* If provided, the `finish` function will be called after the instance is
|
|
82
|
-
* made and internally registered, but before it is returned. The finish
|
|
83
|
-
* function is to do any post-intantiation initialization that should be
|
|
84
|
-
* done before exposing the object to its clients.
|
|
85
|
-
*/
|
|
86
|
-
finish?: (context: C) => void;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* If provided, it describes the shape of all state records of instances
|
|
90
|
-
* of this kind.
|
|
91
|
-
*/
|
|
92
|
-
stateShape?: StateShape;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* If a `receiveAmplifier` function is provided to an exo class kit definition,
|
|
96
|
-
* it will be called with an `Amplify` function. If provided to the definition
|
|
97
|
-
* of a normal exo or exo class, the definition will throw, since only
|
|
98
|
-
* exo kits can be amplified.
|
|
99
|
-
* An `Amplify` function is a function that takes a facet instance of
|
|
100
|
-
* this class kit as an argument, in which case it will return the facets
|
|
101
|
-
* record, giving access to all the facet instances of the same cohort.
|
|
102
|
-
*/
|
|
103
|
-
receiveAmplifier?: ReceivePower<Amplify>;
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* If a `receiveInstanceTester` function is provided, it will be called
|
|
107
|
-
* during the definition of the exo class or exo class kit with an
|
|
108
|
-
* `IsInstance` function. The first argument of `IsInstance`
|
|
109
|
-
* is the value to be tested. When it may be a facet instance of an
|
|
110
|
-
* exo class kit, the optional second argument, if provided, is
|
|
111
|
-
* a `facetName`. In that case, the function tests only if the first
|
|
112
|
-
* argument is an instance of that facet of the associated exo class kit.
|
|
113
|
-
*/
|
|
114
|
-
receiveInstanceTester?: ReceivePower<IsInstance>;
|
|
115
|
-
|
|
116
|
-
// TODO properties above are identical to those in FarClassOptions.
|
|
117
|
-
// These are the only options that should be exposed by
|
|
118
|
-
// vat-data's public virtual/durable exo APIs. This DefineKindOptions
|
|
119
|
-
// should explicitly be a subtype, where the methods below are only for
|
|
120
|
-
// internal use, i.e., below the exo level.
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* As a kind option, intended for internal use only.
|
|
124
|
-
* Meaningful to `makeScalarBigMapStore` and its siblings. These maker
|
|
125
|
-
* fuctions will make either virtual or durable stores, depending on
|
|
126
|
-
* this flag. Defaults to off, making virtual but not durable collections.
|
|
127
|
-
*
|
|
128
|
-
* Generally, durable collections are provided with `provideDurableMapStore`
|
|
129
|
-
* and its sibling, which use this flag internally. If you do not make
|
|
130
|
-
* durable collections by other means, you can consider this as
|
|
131
|
-
* intended for internal use only.
|
|
132
|
-
*/
|
|
133
|
-
durable?: boolean;
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Intended for internal use only.
|
|
137
|
-
* Should the raw methods receive their `context` argument as their first
|
|
138
|
-
* argument or as their `this` binding? For `defineDurableKind` and its
|
|
139
|
-
* siblings (including `prepareSingleton`), this defaults to off, meaning that
|
|
140
|
-
* their behavior methods receive `context` as their first argument.
|
|
141
|
-
* `prepareExoClass` and its siblings (including `prepareExo`) use
|
|
142
|
-
* this flag internally to indicate that their methods receive `context`
|
|
143
|
-
* as their `this` binding.
|
|
144
|
-
*/
|
|
145
|
-
thisfulMethods?: boolean;
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Intended for internal use only.
|
|
149
|
-
* Only applicable if this is a class kind. A class kit kind should use
|
|
150
|
-
* `interfaceGuardKit` instead.
|
|
151
|
-
*
|
|
152
|
-
* If an `interfaceGuard` is provided, then the raw methods passed alongside
|
|
153
|
-
* it are wrapped by a function that first checks that this method's guard
|
|
154
|
-
* pattern is satisfied before calling the raw method.
|
|
155
|
-
*
|
|
156
|
-
* In `defineDurableKind` and its siblings, this defaults to `undefined`.
|
|
157
|
-
* Exo classes use this internally to protect their raw class methods
|
|
158
|
-
* using the provided interface.
|
|
159
|
-
* In absence, an exo is protected anyway, while a bare kind is
|
|
160
|
-
* not (detected by `!thisfulMethods`),
|
|
161
|
-
*/
|
|
162
|
-
interfaceGuard?: InterfaceGuard;
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Intended for internal use only.
|
|
166
|
-
* Only applicable if this is a class kit kind. A class kind should use
|
|
167
|
-
* `interfaceGuard` instead.
|
|
168
|
-
*
|
|
169
|
-
* If an `interfaceGuardKit` is provided, then each member of the
|
|
170
|
-
* interfaceGuardKit is used to guard the corresponding facet of the
|
|
171
|
-
* class kit.
|
|
172
|
-
*
|
|
173
|
-
* In `defineDurableKindMulti` and its siblings, this defaults to `undefined`.
|
|
174
|
-
* Exo class kits use this internally to protect their facets.
|
|
175
|
-
* In absence, an exo is protected anyway, while a bare kind is
|
|
176
|
-
* not (detected by `!thisfulMethods`),
|
|
177
|
-
*/
|
|
178
|
-
interfaceGuardKit?: InterfaceGuardKit;
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
export type VatData = {
|
|
182
|
-
// virtual kinds
|
|
183
|
-
/** @deprecated Use defineVirtualExoClass instead */
|
|
184
|
-
defineKind: <P extends Array<any>, S, F>(
|
|
185
|
-
tag: string,
|
|
186
|
-
init: (...args: P) => S,
|
|
187
|
-
facet: F,
|
|
188
|
-
options?: DefineKindOptions<KindContext<S, F>>,
|
|
189
|
-
) => (...args: P) => KindFacet<F>;
|
|
190
|
-
|
|
191
|
-
/** @deprecated Use defineVirtualExoClassKit instead */
|
|
192
|
-
defineKindMulti: <P extends Array<any>, S, B>(
|
|
193
|
-
tag: string,
|
|
194
|
-
init: (...args: P) => S,
|
|
195
|
-
behavior: B,
|
|
196
|
-
options?: DefineKindOptions<MultiKindContext<S, B>>,
|
|
197
|
-
) => (...args: P) => KindFacets<B>;
|
|
198
|
-
|
|
199
|
-
// durable kinds
|
|
200
|
-
makeKindHandle: (descriptionTag: string) => DurableKindHandle;
|
|
201
|
-
|
|
202
|
-
/** @deprecated Use defineDurableExoClass instead */
|
|
203
|
-
defineDurableKind: <P extends Array<any>, S, F>(
|
|
204
|
-
kindHandle: DurableKindHandle,
|
|
205
|
-
init: (...args: P) => S,
|
|
206
|
-
facet: F,
|
|
207
|
-
options?: DefineKindOptions<KindContext<S, F>>,
|
|
208
|
-
) => (...args: P) => KindFacet<F>;
|
|
209
|
-
|
|
210
|
-
/** @deprecated Use defineDurableExoClassKit instead */
|
|
211
|
-
defineDurableKindMulti: <P extends Array<any>, S, B>(
|
|
212
|
-
kindHandle: DurableKindHandle,
|
|
213
|
-
init: (...args: P) => S,
|
|
214
|
-
behavior: B,
|
|
215
|
-
options?: DefineKindOptions<MultiKindContext<S, B>>,
|
|
216
|
-
) => (...args: P) => KindFacets<B>;
|
|
217
|
-
|
|
218
|
-
providePromiseWatcher: WatchedPromisesManager['providePromiseWatcher'];
|
|
219
|
-
watchPromise: WatchedPromisesManager['watchPromise'];
|
|
220
|
-
|
|
221
|
-
makeScalarBigMapStore: <K, V>(
|
|
222
|
-
label: string,
|
|
223
|
-
options?: StoreOptions,
|
|
224
|
-
) => MapStore<K, V>;
|
|
225
|
-
makeScalarBigWeakMapStore: <K, V>(
|
|
226
|
-
label: string,
|
|
227
|
-
options?: StoreOptions,
|
|
228
|
-
) => WeakMapStore<K, V>;
|
|
229
|
-
|
|
230
|
-
makeScalarBigSetStore: <K>(
|
|
231
|
-
label: string,
|
|
232
|
-
options?: StoreOptions,
|
|
233
|
-
) => SetStore<K>;
|
|
234
|
-
makeScalarBigWeakSetStore: <K>(
|
|
235
|
-
label: string,
|
|
236
|
-
options?: StoreOptions,
|
|
237
|
-
) => WeakSetStore<K>;
|
|
238
|
-
canBeDurable: (specimen: unknown) => boolean;
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
// The JSDoc is repeated here and at the function definition so it appears
|
|
242
|
-
// in IDEs where it's used, regardless of type resolution.
|
|
243
|
-
export interface PickFacet {
|
|
244
|
-
/**
|
|
245
|
-
* When making a multi-facet kind, it's common to pick one facet to
|
|
246
|
-
* expose. E.g.,
|
|
247
|
-
*
|
|
248
|
-
* const makeFoo = (a, b, c, d) => makeFooBase(a, b, c, d).self;
|
|
249
|
-
*
|
|
250
|
-
* This helper reduces the duplication:
|
|
251
|
-
*
|
|
252
|
-
* const makeFoo = pickFacet(makeFooBase, 'self');
|
|
253
|
-
*/
|
|
254
|
-
<M extends (...args: any[]) => any, F extends keyof ReturnType<M>>(
|
|
255
|
-
maker: M,
|
|
256
|
-
facetName: F,
|
|
257
|
-
): (...args: Parameters<M>) => ReturnType<M>[F];
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/** @deprecated Use prepareExoClass instead */
|
|
261
|
-
export type PrepareKind = <P extends Array<any>, S, F>(
|
|
262
|
-
baggage: Baggage,
|
|
263
|
-
tag: string,
|
|
264
|
-
init: (...args: P) => S,
|
|
265
|
-
facet: F,
|
|
266
|
-
options?: DefineKindOptions<KindContext<S, F>>,
|
|
267
|
-
) => (...args: P) => KindFacet<F>;
|
|
268
|
-
|
|
269
|
-
/** @deprecated Use prepareExoClassKit instead */
|
|
270
|
-
export type PrepareKindMulti = <P extends Array<any>, S, B>(
|
|
271
|
-
baggage: Baggage,
|
|
272
|
-
tag: string,
|
|
273
|
-
init: (...args: P) => S,
|
|
274
|
-
behavior: B,
|
|
275
|
-
options?: DefineKindOptions<MultiKindContext<S, B>>,
|
|
276
|
-
) => (...args: P) => KindFacets<B>;
|
package/src/vatDataTypes.js
DELETED