@agoric/swingset-liveslots 0.10.3-other-dev-8f8782b.0 → 0.10.3-other-dev-fbe72e7.0.fbe72e7
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/README.md +2 -0
- package/package.json +34 -26
- package/src/boyd-gc.d.ts +12 -0
- package/src/boyd-gc.d.ts.map +1 -0
- package/src/boyd-gc.js +598 -0
- package/src/cache.d.ts +71 -0
- package/src/cache.d.ts.map +1 -0
- package/src/cache.js +3 -2
- package/src/capdata.d.ts +16 -0
- package/src/capdata.d.ts.map +1 -0
- package/src/capdata.js +17 -10
- package/src/collectionManager.d.ts +47 -0
- package/src/collectionManager.d.ts.map +1 -0
- package/src/collectionManager.js +220 -103
- package/src/facetiousness.d.ts +25 -0
- package/src/facetiousness.d.ts.map +1 -0
- package/src/facetiousness.js +1 -1
- package/src/index.d.ts +4 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +4 -2
- package/src/kdebug.d.ts +7 -0
- package/src/kdebug.d.ts.map +1 -0
- package/src/liveslots.d.ts +42 -0
- package/src/liveslots.d.ts.map +1 -0
- package/src/liveslots.js +137 -305
- package/src/message.d.ts +49 -0
- package/src/message.d.ts.map +1 -0
- package/src/message.js +9 -5
- package/src/parseVatSlots.d.ts +125 -0
- package/src/parseVatSlots.d.ts.map +1 -0
- package/src/parseVatSlots.js +1 -1
- package/src/types-index.d.ts +4 -0
- package/src/types-index.js +2 -0
- package/src/types.d.ts +81 -0
- package/src/types.d.ts.map +1 -0
- package/src/types.js +14 -7
- package/src/vatDataTypes.d.ts +170 -0
- package/src/vatDataTypes.d.ts.map +1 -0
- package/src/vatDataTypes.ts +272 -0
- package/src/vatstore-iterators.d.ts +4 -0
- package/src/vatstore-iterators.d.ts.map +1 -0
- package/src/vatstore-iterators.js +2 -0
- package/src/vatstore-usage.md +198 -0
- package/src/virtualObjectManager.d.ts +44 -0
- package/src/virtualObjectManager.d.ts.map +1 -0
- package/src/virtualObjectManager.js +254 -84
- package/src/virtualReferences.d.ts +61 -0
- package/src/virtualReferences.d.ts.map +1 -0
- package/src/virtualReferences.js +135 -26
- package/src/vpid-tracking.md +92 -0
- package/src/watchedPromises.d.ts +31 -0
- package/src/watchedPromises.d.ts.map +1 -0
- package/src/watchedPromises.js +81 -24
- package/test/{test-baggage.js → baggage.test.js} +1 -2
- package/test/{test-cache.js → cache.test.js} +0 -1
- package/test/clear-collection.test.js +586 -0
- package/test/{test-collection-schema-refcount.js → collection-schema-refcount.test.js} +1 -2
- package/test/{test-collection-upgrade.js → collection-upgrade.test.js} +1 -3
- package/test/{test-collections.js → collections.test.js} +183 -18
- package/test/{test-dropped-collection-weakrefs.js → dropped-collection-weakrefs.test.js} +1 -2
- package/test/dropped-weakset-9939.test.js +80 -0
- package/test/dummyMeterControl.d.ts +2 -0
- package/test/dummyMeterControl.d.ts.map +1 -0
- package/test/dummyMeterControl.js +1 -1
- package/test/{test-durabilityChecks.js → durabilityChecks.test.js} +4 -4
- package/test/engine-gc.d.ts +3 -0
- package/test/engine-gc.d.ts.map +1 -0
- package/test/exo-utils.js +70 -0
- package/test/{test-facetiousness.js → facetiousness.test.js} +1 -2
- package/test/gc-and-finalize.d.ts +5 -0
- package/test/gc-and-finalize.d.ts.map +1 -0
- package/test/gc-and-finalize.js +30 -1
- package/test/gc-before-finalizer.test.js +230 -0
- package/test/gc-helpers.js +4 -5
- package/test/{test-gc-sensitivity.js → gc-sensitivity.test.js} +2 -2
- package/test/handled-promises.test.js +872 -0
- package/test/{test-initial-vrefs.js → initial-vrefs.test.js} +13 -20
- package/test/liveslots-helpers.d.ts +64 -0
- package/test/liveslots-helpers.d.ts.map +1 -0
- package/test/liveslots-helpers.js +13 -7
- package/test/{test-liveslots-mock-gc.js → liveslots-mock-gc.test.js} +101 -2
- package/test/{test-liveslots-real-gc.js → liveslots-real-gc.test.js} +73 -46
- package/test/{test-liveslots.js → liveslots.test.js} +17 -18
- package/test/mock-gc.js +1 -0
- package/test/storeGC/{test-lifecycle.js → lifecycle.test.js} +15 -14
- package/test/storeGC/{test-refcount-management.js → refcount-management.test.js} +1 -2
- package/test/storeGC/{test-scalar-store-kind.js → scalar-store-kind.test.js} +0 -1
- package/test/storeGC/{test-weak-key.js → weak-key.test.js} +1 -2
- package/test/strict-test-env-upgrade.test.js +94 -0
- package/test/util.d.ts +25 -0
- package/test/util.d.ts.map +1 -0
- package/test/util.js +4 -4
- package/test/vat-environment.test.js +65 -0
- package/test/vat-util.d.ts +9 -0
- package/test/vat-util.d.ts.map +1 -0
- package/test/vat-util.js +2 -2
- package/test/virtual-objects/{test-cease-recognition.js → cease-recognition.test.js} +2 -2
- package/test/virtual-objects/{test-cross-facet.js → cross-facet.test.js} +5 -4
- package/test/virtual-objects/{test-empty-data.js → empty-data.test.js} +1 -2
- package/test/virtual-objects/{test-facets.js → facets.test.js} +1 -2
- package/test/virtual-objects/{test-kind-changes.js → kind-changes.test.js} +2 -2
- package/test/virtual-objects/{test-reachable-vrefs.js → reachable-vrefs.test.js} +2 -2
- package/test/virtual-objects/{test-rep-tostring.js → rep-tostring.test.js} +3 -5
- package/test/virtual-objects/{test-retain-remotable.js → retain-remotable.test.js} +25 -24
- package/test/virtual-objects/set-debug-label-instances.js +1 -1
- package/test/virtual-objects/state-shape.test.js +389 -0
- package/test/virtual-objects/{test-virtualObjectGC.js → virtualObjectGC.test.js} +39 -38
- package/test/virtual-objects/{test-virtualObjectManager.js → virtualObjectManager.test.js} +104 -8
- package/test/virtual-objects/{test-vo-real-gc.js → vo-real-gc.test.js} +8 -8
- package/test/virtual-objects/{test-weakcollections-vref-handling.js → weakcollections-vref-handling.test.js} +1 -2
- package/test/{test-vo-test-harness.js → vo-test-harness.test.js} +13 -10
- package/test/{test-vpid-liveslots.js → vpid-liveslots.test.js} +105 -5
- package/test/waitUntilQuiescent.d.ts +3 -0
- package/test/waitUntilQuiescent.d.ts.map +1 -0
- package/test/waitUntilQuiescent.js +2 -1
- package/test/weakset-dropped-remotable.test.js +50 -0
- package/tools/fakeCollectionManager.d.ts +14 -0
- package/tools/fakeCollectionManager.d.ts.map +1 -0
- package/tools/fakeCollectionManager.js +44 -0
- package/tools/fakeVirtualObjectManager.d.ts +32 -0
- package/tools/fakeVirtualObjectManager.d.ts.map +1 -0
- package/tools/fakeVirtualObjectManager.js +62 -0
- package/tools/fakeVirtualSupport.d.ts +278 -0
- package/tools/fakeVirtualSupport.d.ts.map +1 -0
- package/tools/fakeVirtualSupport.js +389 -0
- package/tools/prepare-strict-test-env.d.ts +37 -0
- package/tools/prepare-strict-test-env.d.ts.map +1 -0
- package/tools/prepare-strict-test-env.js +124 -0
- package/tools/prepare-test-env.d.ts +2 -0
- package/tools/prepare-test-env.d.ts.map +1 -0
- package/tools/prepare-test-env.js +13 -0
- package/tools/setup-vat-data.d.ts +9 -0
- package/tools/setup-vat-data.d.ts.map +1 -0
- package/tools/setup-vat-data.js +95 -0
- package/tools/vo-test-harness.d.ts +33 -0
- package/tools/vo-test-harness.d.ts.map +1 -0
- package/tools/vo-test-harness.js +164 -0
- package/CHANGELOG.md +0 -61
- package/test/kmarshal.js +0 -79
- package/test/test-handled-promises.js +0 -360
- package/test/virtual-objects/test-state-shape.js +0 -298
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-await-in-loop, @jessie.js/no-nested-await, no-shadow */
|
|
2
|
-
import test from 'ava';
|
|
3
|
-
import '@endo/init/debug.js';
|
|
4
|
-
|
|
5
|
-
import { Far } from '@endo/marshal';
|
|
6
|
-
import { Fail } from '@agoric/assert';
|
|
7
|
-
import { M, provideLazy as provide } from '@agoric/store';
|
|
8
|
-
import { makePromiseKit } from '@endo/promise-kit';
|
|
9
|
-
// Disabled to avoid circular dependencies.
|
|
10
|
-
// import { makeStoreUtils } from '@agoric/vat-data/src/vat-data-bindings.js';
|
|
11
|
-
// import { makeExoUtils } from '@agoric/vat-data/src/exo-utils.js';
|
|
12
|
-
import { kslot, kser } from './kmarshal.js';
|
|
13
|
-
import { setupTestLiveslots } from './liveslots-helpers.js';
|
|
14
|
-
import { makeResolve, makeReject } from './util.js';
|
|
15
|
-
|
|
16
|
-
// eslint-disable-next-line no-unused-vars
|
|
17
|
-
const compareEntriesByKey = ([ka], [kb]) => (ka < kb ? -1 : 1);
|
|
18
|
-
|
|
19
|
-
// Paritally duplicates @agoric/vat-data to avoid circular dependencies.
|
|
20
|
-
const makeExoUtils = VatData => {
|
|
21
|
-
const { defineDurableKind, makeKindHandle, watchPromise } = VatData;
|
|
22
|
-
|
|
23
|
-
const provideKindHandle = (baggage, kindName) =>
|
|
24
|
-
provide(baggage, `${kindName}_kindHandle`, () => makeKindHandle(kindName));
|
|
25
|
-
|
|
26
|
-
const emptyRecord = harden({});
|
|
27
|
-
const initEmpty = () => emptyRecord;
|
|
28
|
-
|
|
29
|
-
const defineDurableExoClass = (
|
|
30
|
-
kindHandle,
|
|
31
|
-
interfaceGuard,
|
|
32
|
-
init,
|
|
33
|
-
methods,
|
|
34
|
-
options,
|
|
35
|
-
) =>
|
|
36
|
-
defineDurableKind(kindHandle, init, methods, {
|
|
37
|
-
...options,
|
|
38
|
-
thisfulMethods: true,
|
|
39
|
-
interfaceGuard,
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
const prepareExoClass = (
|
|
43
|
-
baggage,
|
|
44
|
-
kindName,
|
|
45
|
-
interfaceGuard,
|
|
46
|
-
init,
|
|
47
|
-
methods,
|
|
48
|
-
options = undefined,
|
|
49
|
-
) =>
|
|
50
|
-
defineDurableExoClass(
|
|
51
|
-
provideKindHandle(baggage, kindName),
|
|
52
|
-
interfaceGuard,
|
|
53
|
-
init,
|
|
54
|
-
methods,
|
|
55
|
-
options,
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
const prepareExo = (
|
|
59
|
-
baggage,
|
|
60
|
-
kindName,
|
|
61
|
-
interfaceGuard,
|
|
62
|
-
methods,
|
|
63
|
-
options = undefined,
|
|
64
|
-
) => {
|
|
65
|
-
const makeSingleton = prepareExoClass(
|
|
66
|
-
baggage,
|
|
67
|
-
kindName,
|
|
68
|
-
interfaceGuard,
|
|
69
|
-
initEmpty,
|
|
70
|
-
methods,
|
|
71
|
-
options,
|
|
72
|
-
);
|
|
73
|
-
return provide(baggage, `the_${kindName}`, () => makeSingleton());
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
return {
|
|
77
|
-
defineDurableKind,
|
|
78
|
-
makeKindHandle,
|
|
79
|
-
watchPromise,
|
|
80
|
-
|
|
81
|
-
provideKindHandle,
|
|
82
|
-
defineDurableExoClass,
|
|
83
|
-
prepareExoClass,
|
|
84
|
-
prepareExo,
|
|
85
|
-
};
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
// cf. packages/SwingSet/test/vat-durable-promise-watcher.js
|
|
89
|
-
const buildPromiseWatcherRootObject = (vatPowers, _vatParameters, baggage) => {
|
|
90
|
-
const { VatData } = vatPowers;
|
|
91
|
-
const { watchPromise } = VatData;
|
|
92
|
-
const { prepareExo } = makeExoUtils(VatData);
|
|
93
|
-
// const { makeScalarBigMapStore } = makeStoreUtils(VatData);
|
|
94
|
-
const PromiseWatcherI = M.interface('ExtraArgPromiseWatcher', {
|
|
95
|
-
onFulfilled: M.call(M.any(), M.string()).returns(),
|
|
96
|
-
onRejected: M.call(M.any(), M.string()).returns(),
|
|
97
|
-
});
|
|
98
|
-
const watcher = prepareExo(
|
|
99
|
-
baggage,
|
|
100
|
-
'DurablePromiseIgnorer',
|
|
101
|
-
PromiseWatcherI,
|
|
102
|
-
{
|
|
103
|
-
onFulfilled(_value, _name) {},
|
|
104
|
-
onRejected(_reason, _name) {},
|
|
105
|
-
},
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
const localPromises = new Map();
|
|
109
|
-
|
|
110
|
-
return Far('root', {
|
|
111
|
-
exportPromise: () => [Promise.resolve()],
|
|
112
|
-
createLocalPromise: (name, fulfillment, rejection) => {
|
|
113
|
-
!localPromises.has(name) || Fail`local promise already exists: ${name}`;
|
|
114
|
-
const { promise, resolve, reject } = makePromiseKit();
|
|
115
|
-
if (fulfillment !== undefined) {
|
|
116
|
-
resolve(fulfillment);
|
|
117
|
-
} else if (rejection !== undefined) {
|
|
118
|
-
reject(rejection);
|
|
119
|
-
}
|
|
120
|
-
localPromises.set(name, promise);
|
|
121
|
-
return `created local promise: ${name}`;
|
|
122
|
-
},
|
|
123
|
-
watchLocalPromise: name => {
|
|
124
|
-
localPromises.has(name) || Fail`local promise not found: ${name}`;
|
|
125
|
-
watchPromise(localPromises.get(name), watcher, name);
|
|
126
|
-
return `watched local promise: ${name}`;
|
|
127
|
-
},
|
|
128
|
-
});
|
|
129
|
-
};
|
|
130
|
-
const kvStoreDataV1 = Object.entries({
|
|
131
|
-
baggageID: 'o+d6/1',
|
|
132
|
-
idCounters: '{"exportID":11,"collectionID":5,"promiseID":9}',
|
|
133
|
-
kindIDID: '1',
|
|
134
|
-
storeKindIDTable:
|
|
135
|
-
'{"scalarMapStore":2,"scalarWeakMapStore":3,"scalarSetStore":4,"scalarWeakSetStore":5,"scalarDurableMapStore":6,"scalarDurableWeakMapStore":7,"scalarDurableSetStore":8,"scalarDurableWeakSetStore":9}',
|
|
136
|
-
'vc.1.sDurablePromiseIgnorer_kindHandle':
|
|
137
|
-
'{"body":"#\\"$0.Alleged: kind\\"","slots":["o+d1/10"]}',
|
|
138
|
-
'vc.1.sthe_DurablePromiseIgnorer':
|
|
139
|
-
'{"body":"#\\"$0.Alleged: DurablePromiseIgnorer\\"","slots":["o+d10/1"]}',
|
|
140
|
-
'vc.1.|entryCount': '2',
|
|
141
|
-
'vc.1.|nextOrdinal': '1',
|
|
142
|
-
'vc.1.|schemata':
|
|
143
|
-
'{"label":"baggage","body":"#{\\"keyShape\\":{\\"#tag\\":\\"match:string\\",\\"payload\\":[]}}","slots":[]}',
|
|
144
|
-
// non-durable
|
|
145
|
-
// 'vc.2.sp+6': '{"body":"#\\"&0\\"","slots":["p+6"]}',
|
|
146
|
-
// 'vc.2.|entryCount': '1',
|
|
147
|
-
// 'vc.2.|nextOrdinal': '1',
|
|
148
|
-
// 'vc.2.|schemata': '{"label":"promiseRegistrations","body":"#{\\"keyShape\\":{\\"#tag\\":\\"match:scalar\\",\\"payload\\":\\"#undefined\\"}}","slots":[]}',
|
|
149
|
-
'vc.3.|entryCount': '0',
|
|
150
|
-
'vc.3.|nextOrdinal': '1',
|
|
151
|
-
'vc.3.|schemata':
|
|
152
|
-
'{"label":"promiseWatcherByKind","body":"#{\\"keyShape\\":{\\"#tag\\":\\"match:scalar\\",\\"payload\\":\\"#undefined\\"}}","slots":[]}',
|
|
153
|
-
'vc.4.sp+6':
|
|
154
|
-
'{"body":"#[[\\"$0.Alleged: DurablePromiseIgnorer\\",\\"orphaned\\"]]","slots":["o+d10/1"]}',
|
|
155
|
-
'vc.4.sp-8':
|
|
156
|
-
'{"body":"#[[\\"$0.Alleged: DurablePromiseIgnorer\\",\\"unresolved\\"]]","slots":["o+d10/1"]}',
|
|
157
|
-
'vc.4.sp-9':
|
|
158
|
-
'{"body":"#[[\\"$0.Alleged: DurablePromiseIgnorer\\",\\"late-rejected\\"]]","slots":["o+d10/1"]}',
|
|
159
|
-
'vc.4.|entryCount': '3',
|
|
160
|
-
'vc.4.|nextOrdinal': '1',
|
|
161
|
-
'vc.4.|schemata':
|
|
162
|
-
'{"label":"watchedPromises","body":"#{\\"keyShape\\":{\\"#tag\\":\\"match:and\\",\\"payload\\":[{\\"#tag\\":\\"match:scalar\\",\\"payload\\":\\"#undefined\\"},{\\"#tag\\":\\"match:string\\",\\"payload\\":[]}]}}","slots":[]}',
|
|
163
|
-
'vom.dkind.10.descriptor':
|
|
164
|
-
'{"kindID":"10","tag":"DurablePromiseIgnorer","unfaceted":true}',
|
|
165
|
-
'vom.dkind.10.nextID': '2',
|
|
166
|
-
'vom.o+d10/1': '{}',
|
|
167
|
-
'vom.rc.o+d1/10': '1',
|
|
168
|
-
'vom.rc.o+d10/1': '3',
|
|
169
|
-
'vom.rc.o+d6/1': '1',
|
|
170
|
-
'vom.rc.o+d6/3': '1',
|
|
171
|
-
'vom.rc.o+d6/4': '1',
|
|
172
|
-
watchedPromiseTableID: 'o+d6/4',
|
|
173
|
-
watcherTableID: 'o+d6/3',
|
|
174
|
-
});
|
|
175
|
-
const kvStoreDataV1VpidsToReject = ['p+6', 'p-9'];
|
|
176
|
-
const kvStoreDataV1KeysToDelete = ['vc.4.sp+6', 'vc.4.sp-9'];
|
|
177
|
-
const kvStoreDataV1VpidsToKeep = ['p-8'];
|
|
178
|
-
const kvStoreDataV1KeysToKeep = ['vc.4.sp-8'];
|
|
179
|
-
|
|
180
|
-
test('past-incarnation watched promises', async t => {
|
|
181
|
-
const kvStore = new Map();
|
|
182
|
-
let { v, dispatch, dispatchMessage } = await setupTestLiveslots(
|
|
183
|
-
t,
|
|
184
|
-
buildPromiseWatcherRootObject,
|
|
185
|
-
'durable-promise-watcher',
|
|
186
|
-
{ kvStore },
|
|
187
|
-
);
|
|
188
|
-
let vatLogs = v.log;
|
|
189
|
-
|
|
190
|
-
// Anchor promise counters upon which the other assertions depend.
|
|
191
|
-
const firstPImport = 1;
|
|
192
|
-
// cf. src/liveslots.js:initialIDCounters
|
|
193
|
-
const firstPExport = 5;
|
|
194
|
-
let lastPImport = firstPImport - 1;
|
|
195
|
-
let lastPExport = firstPExport - 1;
|
|
196
|
-
const nextPImport = () => (lastPImport += 1);
|
|
197
|
-
const nextPExport = () => (lastPExport += 1);
|
|
198
|
-
// Ignore vatstore syscalls.
|
|
199
|
-
const getDispatchLogs = () =>
|
|
200
|
-
vatLogs.splice(0).filter(m => !m.type.startsWith('vatstore'));
|
|
201
|
-
const settlementMessage = (vpid, rejected, value) => ({
|
|
202
|
-
type: 'resolve',
|
|
203
|
-
resolutions: [[vpid, rejected, kser(value)]],
|
|
204
|
-
});
|
|
205
|
-
const fulfillmentMessage = (vpid, value) =>
|
|
206
|
-
settlementMessage(vpid, false, value);
|
|
207
|
-
const rejectionMessage = (vpid, value) =>
|
|
208
|
-
settlementMessage(vpid, true, value);
|
|
209
|
-
const subscribeMessage = vpid => ({
|
|
210
|
-
type: 'subscribe',
|
|
211
|
-
target: vpid,
|
|
212
|
-
});
|
|
213
|
-
vatLogs.length = 0;
|
|
214
|
-
await dispatchMessage('exportPromise');
|
|
215
|
-
t.deepEqual(getDispatchLogs(), [
|
|
216
|
-
fulfillmentMessage(`p-${nextPImport()}`, [kslot(`p+${nextPExport()}`)]),
|
|
217
|
-
fulfillmentMessage(`p+${lastPExport}`, undefined),
|
|
218
|
-
]);
|
|
219
|
-
|
|
220
|
-
const S = 'settlement';
|
|
221
|
-
await dispatchMessage('createLocalPromise', 'orphaned');
|
|
222
|
-
t.deepEqual(getDispatchLogs(), [
|
|
223
|
-
fulfillmentMessage(`p-${nextPImport()}`, 'created local promise: orphaned'),
|
|
224
|
-
]);
|
|
225
|
-
await dispatchMessage('createLocalPromise', 'fulfilled', S);
|
|
226
|
-
t.deepEqual(getDispatchLogs(), [
|
|
227
|
-
fulfillmentMessage(
|
|
228
|
-
`p-${nextPImport()}`,
|
|
229
|
-
'created local promise: fulfilled',
|
|
230
|
-
),
|
|
231
|
-
]);
|
|
232
|
-
await dispatchMessage('createLocalPromise', 'rejected', undefined, S);
|
|
233
|
-
t.deepEqual(getDispatchLogs(), [
|
|
234
|
-
fulfillmentMessage(`p-${nextPImport()}`, 'created local promise: rejected'),
|
|
235
|
-
]);
|
|
236
|
-
t.deepEqual(
|
|
237
|
-
lastPImport - firstPImport + 1,
|
|
238
|
-
4,
|
|
239
|
-
'imported 4 promises (1 per dispatch)',
|
|
240
|
-
);
|
|
241
|
-
t.deepEqual(lastPExport - firstPExport + 1, 1, 'exported 1 promise: first');
|
|
242
|
-
|
|
243
|
-
await dispatchMessage('watchLocalPromise', 'orphaned');
|
|
244
|
-
t.deepEqual(getDispatchLogs(), [
|
|
245
|
-
subscribeMessage(`p+${nextPExport()}`),
|
|
246
|
-
fulfillmentMessage(`p-${nextPImport()}`, 'watched local promise: orphaned'),
|
|
247
|
-
]);
|
|
248
|
-
await dispatchMessage('watchLocalPromise', 'fulfilled');
|
|
249
|
-
t.deepEqual(getDispatchLogs(), [
|
|
250
|
-
subscribeMessage(`p+${nextPExport()}`),
|
|
251
|
-
fulfillmentMessage(
|
|
252
|
-
`p-${nextPImport()}`,
|
|
253
|
-
'watched local promise: fulfilled',
|
|
254
|
-
),
|
|
255
|
-
fulfillmentMessage(`p+${lastPExport}`, S),
|
|
256
|
-
]);
|
|
257
|
-
await dispatchMessage('watchLocalPromise', 'rejected');
|
|
258
|
-
t.deepEqual(getDispatchLogs(), [
|
|
259
|
-
subscribeMessage(`p+${nextPExport()}`),
|
|
260
|
-
fulfillmentMessage(`p-${nextPImport()}`, 'watched local promise: rejected'),
|
|
261
|
-
rejectionMessage(`p+${lastPExport}`, S),
|
|
262
|
-
]);
|
|
263
|
-
t.deepEqual(
|
|
264
|
-
lastPImport - firstPImport + 1,
|
|
265
|
-
7,
|
|
266
|
-
'imported 7 promises (1 per dispatch)',
|
|
267
|
-
);
|
|
268
|
-
t.deepEqual(
|
|
269
|
-
lastPExport - firstPExport + 1,
|
|
270
|
-
4,
|
|
271
|
-
'exported 4 promises: first, orphaned, fulfilled, rejected',
|
|
272
|
-
);
|
|
273
|
-
|
|
274
|
-
// Simulate upgrade by starting from the non-empty kvStore.
|
|
275
|
-
// t.log(Object.fromEntries([...kvStore.entries()].sort(compareEntriesByKey)));
|
|
276
|
-
const clonedStore = new Map(kvStore);
|
|
277
|
-
({ v, dispatch, dispatchMessage } = await setupTestLiveslots(
|
|
278
|
-
t,
|
|
279
|
-
buildPromiseWatcherRootObject,
|
|
280
|
-
'durable-promise-watcher-v2',
|
|
281
|
-
{ kvStore: clonedStore, nextPromiseImportNumber: lastPImport + 1 },
|
|
282
|
-
));
|
|
283
|
-
vatLogs = v.log;
|
|
284
|
-
|
|
285
|
-
// Simulate kernel rejection of promises orphaned by termination/upgrade of their decider vat.
|
|
286
|
-
const expectedDeletions = [...clonedStore.entries()].filter(entry =>
|
|
287
|
-
entry[1].includes('orphaned'),
|
|
288
|
-
);
|
|
289
|
-
t.true(expectedDeletions.length >= 1);
|
|
290
|
-
await dispatch(
|
|
291
|
-
makeReject(`p+${firstPExport + 1}`, kser('tomorrow never came')),
|
|
292
|
-
);
|
|
293
|
-
for (const [key, value] of expectedDeletions) {
|
|
294
|
-
t.false(clonedStore.has(key), `entry should be removed: ${key}: ${value}`);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// Verify that the data is still in loadable condition.
|
|
298
|
-
const finalClonedStore = new Map(clonedStore);
|
|
299
|
-
({ v, dispatch, dispatchMessage } = await setupTestLiveslots(
|
|
300
|
-
t,
|
|
301
|
-
buildPromiseWatcherRootObject,
|
|
302
|
-
'durable-promise-watcher-final',
|
|
303
|
-
{ kvStore: finalClonedStore, nextPromiseImportNumber: lastPImport + 1 },
|
|
304
|
-
));
|
|
305
|
-
vatLogs = v.log;
|
|
306
|
-
vatLogs.length = 0;
|
|
307
|
-
await dispatchMessage('createLocalPromise', 'final', S);
|
|
308
|
-
await dispatchMessage('watchLocalPromise', 'final');
|
|
309
|
-
t.deepEqual(getDispatchLogs(), [
|
|
310
|
-
fulfillmentMessage(`p-${nextPImport()}`, 'created local promise: final'),
|
|
311
|
-
subscribeMessage(`p+${nextPExport()}`),
|
|
312
|
-
fulfillmentMessage(`p-${nextPImport()}`, 'watched local promise: final'),
|
|
313
|
-
fulfillmentMessage(`p+${lastPExport}`, S),
|
|
314
|
-
]);
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
test('past-incarnation watched promises from original-format kvStore', async t => {
|
|
318
|
-
const kvStore = new Map(kvStoreDataV1);
|
|
319
|
-
for (const key of [
|
|
320
|
-
...kvStoreDataV1KeysToDelete,
|
|
321
|
-
...kvStoreDataV1KeysToKeep,
|
|
322
|
-
]) {
|
|
323
|
-
t.true(kvStore.has(key), `key must be initially present: ${key}`);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
let { v, dispatch, dispatchMessage } = await setupTestLiveslots(
|
|
327
|
-
t,
|
|
328
|
-
buildPromiseWatcherRootObject,
|
|
329
|
-
'durable-promise-watcher',
|
|
330
|
-
{ kvStore, nextPromiseImportNumber: 100 },
|
|
331
|
-
);
|
|
332
|
-
let vatLogs = v.log;
|
|
333
|
-
for (const vpid of kvStoreDataV1VpidsToReject) {
|
|
334
|
-
await dispatch(makeReject(vpid, kser('tomorrow never came')));
|
|
335
|
-
}
|
|
336
|
-
for (const key of kvStoreDataV1KeysToDelete) {
|
|
337
|
-
t.false(kvStore.has(key), `key should be removed: ${key}`);
|
|
338
|
-
}
|
|
339
|
-
for (const key of kvStoreDataV1KeysToKeep) {
|
|
340
|
-
t.true(kvStore.has(key), `key should remain: ${key}`);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// Verify that the data is still in loadable condition.
|
|
344
|
-
const finalClonedStore = new Map(kvStore);
|
|
345
|
-
// eslint-disable-next-line no-unused-vars
|
|
346
|
-
({ v, dispatch, dispatchMessage } = await setupTestLiveslots(
|
|
347
|
-
t,
|
|
348
|
-
buildPromiseWatcherRootObject,
|
|
349
|
-
'durable-promise-watcher-final',
|
|
350
|
-
{ kvStore: finalClonedStore, nextPromiseImportNumber: 200 },
|
|
351
|
-
));
|
|
352
|
-
vatLogs = v.log;
|
|
353
|
-
vatLogs.length = 0;
|
|
354
|
-
for (const vpid of kvStoreDataV1VpidsToKeep) {
|
|
355
|
-
await dispatch(makeResolve(vpid, kser('finally')));
|
|
356
|
-
}
|
|
357
|
-
for (const key of kvStoreDataV1KeysToKeep) {
|
|
358
|
-
t.false(finalClonedStore.has(key), `key should be removed: ${key}`);
|
|
359
|
-
}
|
|
360
|
-
});
|
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
import test from 'ava';
|
|
2
|
-
import '@endo/init/debug.js';
|
|
3
|
-
|
|
4
|
-
import { Far } from '@endo/marshal';
|
|
5
|
-
import { M } from '@agoric/store';
|
|
6
|
-
import { makeLiveSlots } from '../../src/liveslots.js';
|
|
7
|
-
import { kser, kslot } from '../kmarshal.js';
|
|
8
|
-
import { buildSyscall } from '../liveslots-helpers.js';
|
|
9
|
-
import { makeStartVat, makeMessage } from '../util.js';
|
|
10
|
-
import { makeMockGC } from '../mock-gc.js';
|
|
11
|
-
import { makeFakeVirtualStuff } from '../../tools/fakeVirtualSupport.js';
|
|
12
|
-
|
|
13
|
-
function makeGenericRemotable(typeName) {
|
|
14
|
-
return Far(typeName, {
|
|
15
|
-
aMethod() {
|
|
16
|
-
return 'whatever';
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
const eph1 = makeGenericRemotable('ephemeral1');
|
|
21
|
-
const eph2 = makeGenericRemotable('ephemeral2');
|
|
22
|
-
|
|
23
|
-
const init = value => ({ value });
|
|
24
|
-
const behavior = {
|
|
25
|
-
set: ({ state }, value) => (state.value = value),
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// virtual/durable Kinds can specify a 'stateShape', which should be
|
|
29
|
-
// enforced, both during initialization and subsequent state changes
|
|
30
|
-
|
|
31
|
-
test('constrain state shape', t => {
|
|
32
|
-
const { vom } = makeFakeVirtualStuff();
|
|
33
|
-
const { defineKind } = vom;
|
|
34
|
-
const any = { value: M.any() };
|
|
35
|
-
const number = { value: M.number() };
|
|
36
|
-
const string = { value: M.string() };
|
|
37
|
-
const remotable = { value: M.remotable() };
|
|
38
|
-
const eph = { value: eph1 };
|
|
39
|
-
|
|
40
|
-
// M.any() allows anything
|
|
41
|
-
const makeA = defineKind('kindA', init, behavior, { stateShape: any });
|
|
42
|
-
makeA(eph1);
|
|
43
|
-
makeA(1);
|
|
44
|
-
makeA('string');
|
|
45
|
-
const a = makeA(1);
|
|
46
|
-
a.set(eph1);
|
|
47
|
-
a.set(2);
|
|
48
|
-
a.set('other string');
|
|
49
|
-
|
|
50
|
-
// M.number() requires a number
|
|
51
|
-
const numberFail = { message: /Must be a number/ };
|
|
52
|
-
const makeB = defineKind('kindB', init, behavior, { stateShape: number });
|
|
53
|
-
t.throws(() => makeB(eph1), numberFail);
|
|
54
|
-
const b = makeB(1);
|
|
55
|
-
t.throws(() => makeB('string'), numberFail);
|
|
56
|
-
t.throws(() => b.set(eph1), numberFail);
|
|
57
|
-
t.throws(() => b.set('string'), numberFail);
|
|
58
|
-
|
|
59
|
-
// M.string() requires a string
|
|
60
|
-
const stringFail = { message: /Must be a string/ };
|
|
61
|
-
const makeC = defineKind('kindC', init, behavior, { stateShape: string });
|
|
62
|
-
t.throws(() => makeC(eph1), stringFail);
|
|
63
|
-
const c = makeC('string');
|
|
64
|
-
t.throws(() => makeC(1), stringFail);
|
|
65
|
-
t.throws(() => c.set(eph1), stringFail);
|
|
66
|
-
t.throws(() => c.set(2), stringFail);
|
|
67
|
-
|
|
68
|
-
// M.remotable() requires any Remotable
|
|
69
|
-
const remotableFail = { message: /Must be a remotable/ };
|
|
70
|
-
const makeD = defineKind('kindD', init, behavior, { stateShape: remotable });
|
|
71
|
-
const d = makeD(eph1);
|
|
72
|
-
makeD(eph2);
|
|
73
|
-
t.throws(() => makeD(1), remotableFail);
|
|
74
|
-
t.throws(() => makeD('string'), remotableFail);
|
|
75
|
-
d.set(eph2);
|
|
76
|
-
t.throws(() => d.set(2), remotableFail);
|
|
77
|
-
t.throws(() => d.set('string'), remotableFail);
|
|
78
|
-
|
|
79
|
-
// using a specific Remotable object requires that exact object
|
|
80
|
-
const eph1Fail = { message: /Must be:.*Alleged: ephemeral1/ };
|
|
81
|
-
const makeE = defineKind('kindE', init, behavior, { stateShape: eph });
|
|
82
|
-
const e = makeE(eph1);
|
|
83
|
-
t.throws(() => makeE(eph2), eph1Fail);
|
|
84
|
-
t.throws(() => makeE(1), eph1Fail);
|
|
85
|
-
t.throws(() => makeE('string'), eph1Fail);
|
|
86
|
-
e.set(eph1);
|
|
87
|
-
t.throws(() => e.set(eph2), eph1Fail);
|
|
88
|
-
t.throws(() => e.set(2), eph1Fail);
|
|
89
|
-
t.throws(() => e.set('string'), eph1Fail);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
// durable Kinds serialize and store their stateShape, which must
|
|
93
|
-
// itself be durable
|
|
94
|
-
|
|
95
|
-
test('durable state shape', t => {
|
|
96
|
-
// note: relaxDurabilityRules defaults to true in fake tools
|
|
97
|
-
const { vom } = makeFakeVirtualStuff({ relaxDurabilityRules: false });
|
|
98
|
-
const { makeKindHandle, defineDurableKind } = vom;
|
|
99
|
-
|
|
100
|
-
const make = (which, stateShape) => {
|
|
101
|
-
const kh = makeKindHandle(`kind${which}`);
|
|
102
|
-
return defineDurableKind(kh, init, behavior, { stateShape });
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const makeKind1 = make(1);
|
|
106
|
-
makeKind1();
|
|
107
|
-
|
|
108
|
-
const makeKind2 = make(2);
|
|
109
|
-
makeKind2();
|
|
110
|
-
|
|
111
|
-
const makeKind3 = make(3, { value: M.any() });
|
|
112
|
-
const obj3 = makeKind3();
|
|
113
|
-
|
|
114
|
-
const makeKind4 = make(4, { value: M.string() });
|
|
115
|
-
const obj4 = makeKind4('string');
|
|
116
|
-
|
|
117
|
-
const makeKind5 = make(5, { value: M.remotable() });
|
|
118
|
-
const durableValueFail = { message: /value for "value" is not durable/ };
|
|
119
|
-
t.throws(() => makeKind5(eph1), durableValueFail);
|
|
120
|
-
|
|
121
|
-
const durableShapeFail = { message: /stateShape.*is not durable: slot 0 of/ };
|
|
122
|
-
t.throws(() => make(6, { value: eph1 }), durableShapeFail);
|
|
123
|
-
|
|
124
|
-
const makeKind7 = make(7, { value: obj4 }); // obj4 is durable
|
|
125
|
-
makeKind7(obj4);
|
|
126
|
-
const specificRemotableFail = { message: /kind3.*Must be:.*kind4/ };
|
|
127
|
-
t.throws(() => makeKind7(obj3), specificRemotableFail);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// durable Kinds maintain refcounts on their serialized stateShape
|
|
131
|
-
|
|
132
|
-
test('durable stateShape refcounts', async t => {
|
|
133
|
-
const kvStore = new Map();
|
|
134
|
-
const { syscall: sc1 } = buildSyscall({ kvStore });
|
|
135
|
-
const gcTools = makeMockGC();
|
|
136
|
-
|
|
137
|
-
function build1(vatPowers, _vp, baggage) {
|
|
138
|
-
const { VatData } = vatPowers;
|
|
139
|
-
const { makeKindHandle, defineDurableKind } = VatData;
|
|
140
|
-
|
|
141
|
-
return Far('root', {
|
|
142
|
-
accept: _standard1 => 0, // assign it a vref
|
|
143
|
-
create: standard1 => {
|
|
144
|
-
const kh = makeKindHandle('shaped');
|
|
145
|
-
baggage.init('kh', kh);
|
|
146
|
-
const stateShape = { value: standard1 };
|
|
147
|
-
defineDurableKind(kh, init, behavior, { stateShape });
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const makeNS1 = () => ({ buildRootObject: build1 });
|
|
153
|
-
const ls1 = makeLiveSlots(sc1, 'vatA', {}, {}, gcTools, undefined, makeNS1);
|
|
154
|
-
const startVat1 = makeStartVat(kser());
|
|
155
|
-
await ls1.dispatch(startVat1);
|
|
156
|
-
const rootA = 'o+0';
|
|
157
|
-
|
|
158
|
-
const standard1Vref = 'o-1';
|
|
159
|
-
await ls1.dispatch(makeMessage(rootA, 'accept', []));
|
|
160
|
-
t.falsy(ls1.testHooks.getReachableRefCount(standard1Vref));
|
|
161
|
-
|
|
162
|
-
await ls1.dispatch(makeMessage(rootA, 'create', [kslot(standard1Vref)]));
|
|
163
|
-
|
|
164
|
-
// using our 'standard1' object in stateShape causes its refcount to
|
|
165
|
-
// be incremented
|
|
166
|
-
t.is(ls1.testHooks.getReachableRefCount(standard1Vref), 1);
|
|
167
|
-
|
|
168
|
-
// ------
|
|
169
|
-
|
|
170
|
-
// Simulate upgrade by starting from the non-empty kvStore.
|
|
171
|
-
const clonedStore = new Map(kvStore);
|
|
172
|
-
const { syscall: sc2 } = buildSyscall({ kvStore: clonedStore });
|
|
173
|
-
|
|
174
|
-
function build2(vatPowers, vatParameters, baggage) {
|
|
175
|
-
const { VatData } = vatPowers;
|
|
176
|
-
const { defineDurableKind } = VatData;
|
|
177
|
-
const { standard2 } = vatParameters;
|
|
178
|
-
const kh = baggage.get('kh');
|
|
179
|
-
const stateShape = { value: standard2 };
|
|
180
|
-
defineDurableKind(kh, init, behavior, { stateShape });
|
|
181
|
-
|
|
182
|
-
return Far('root', {});
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// to test refcount increment/decrement, we need to override the
|
|
186
|
-
// usual rule that the new version must exactly match the original
|
|
187
|
-
// stateShape
|
|
188
|
-
const options = { allowStateShapeChanges: true };
|
|
189
|
-
const makeNS2 = () => ({ buildRootObject: build2 });
|
|
190
|
-
const ls2 = makeLiveSlots(
|
|
191
|
-
sc2,
|
|
192
|
-
'vatA',
|
|
193
|
-
{},
|
|
194
|
-
options,
|
|
195
|
-
gcTools,
|
|
196
|
-
undefined,
|
|
197
|
-
makeNS2,
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
const standard2Vref = 'o-2';
|
|
201
|
-
const vp = { standard2: kslot(standard2Vref) };
|
|
202
|
-
const startVat2 = makeStartVat(kser(vp));
|
|
203
|
-
await ls2.dispatch(startVat2);
|
|
204
|
-
|
|
205
|
-
// redefining the durable kind, with a different 'standard' object,
|
|
206
|
-
// will decrement the standard1 refcount, and increment that of
|
|
207
|
-
// standard2
|
|
208
|
-
|
|
209
|
-
t.falsy(ls2.testHooks.getReachableRefCount(standard1Vref));
|
|
210
|
-
t.is(ls2.testHooks.getReachableRefCount(standard2Vref), 1);
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
test('durable stateShape must match', async t => {
|
|
214
|
-
const kvStore = new Map();
|
|
215
|
-
const { syscall: sc1 } = buildSyscall({ kvStore });
|
|
216
|
-
const gcTools = makeMockGC();
|
|
217
|
-
|
|
218
|
-
function build1(vatPowers, _vp, baggage) {
|
|
219
|
-
const { VatData } = vatPowers;
|
|
220
|
-
const { makeKindHandle, defineDurableKind } = VatData;
|
|
221
|
-
|
|
222
|
-
return Far('root', {
|
|
223
|
-
create: (obj1, obj2) => {
|
|
224
|
-
const kh = makeKindHandle('shaped');
|
|
225
|
-
baggage.init('kh', kh);
|
|
226
|
-
const stateShape = { x: obj1, y: obj2 };
|
|
227
|
-
defineDurableKind(kh, init, behavior, { stateShape });
|
|
228
|
-
},
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const makeNS1 = () => ({ buildRootObject: build1 });
|
|
233
|
-
const ls1 = makeLiveSlots(sc1, 'vatA', {}, {}, gcTools, undefined, makeNS1);
|
|
234
|
-
const startVat1 = makeStartVat(kser());
|
|
235
|
-
await ls1.dispatch(startVat1);
|
|
236
|
-
const rootA = 'o+0';
|
|
237
|
-
|
|
238
|
-
const vref1 = 'o-1';
|
|
239
|
-
const vref2 = 'o-2';
|
|
240
|
-
await ls1.dispatch(
|
|
241
|
-
makeMessage(rootA, 'create', [kslot(vref1), kslot(vref2)]),
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
// the first version's state is { x: vref1, y: vref2 }
|
|
245
|
-
|
|
246
|
-
// ------
|
|
247
|
-
|
|
248
|
-
// Simulate upgrade by starting from the non-empty kvStore.
|
|
249
|
-
const clonedStore = new Map(kvStore);
|
|
250
|
-
const { syscall: sc2 } = buildSyscall({ kvStore: clonedStore });
|
|
251
|
-
|
|
252
|
-
function build2(vatPowers, vatParameters, baggage) {
|
|
253
|
-
const { VatData } = vatPowers;
|
|
254
|
-
const { defineDurableKind } = VatData;
|
|
255
|
-
const { obj1, obj2 } = vatParameters;
|
|
256
|
-
const kh = baggage.get('kh');
|
|
257
|
-
// several shapes that are not compatible
|
|
258
|
-
const shape1 = { x: obj1, y: M.any() };
|
|
259
|
-
const shape2 = { x: obj1 };
|
|
260
|
-
const shape3 = { x: obj1, y: obj2, z: M.string() };
|
|
261
|
-
const shape4 = { x: M.or(obj1, M.string()), y: obj2 };
|
|
262
|
-
const shape5 = { x: obj2, y: obj1 }; // wrong slots
|
|
263
|
-
const trial = shape => {
|
|
264
|
-
t.throws(
|
|
265
|
-
() => defineDurableKind(kh, init, behavior, { stateShape: shape }),
|
|
266
|
-
{ message: /durable Kind stateShape mismatch/ },
|
|
267
|
-
);
|
|
268
|
-
};
|
|
269
|
-
trial(shape1);
|
|
270
|
-
trial(shape2);
|
|
271
|
-
trial(shape3);
|
|
272
|
-
trial(shape4);
|
|
273
|
-
trial(shape5);
|
|
274
|
-
const stateShape = { x: obj1, y: obj2 }; // the correct shape
|
|
275
|
-
defineDurableKind(kh, init, behavior, { stateShape });
|
|
276
|
-
t.pass();
|
|
277
|
-
|
|
278
|
-
return Far('root', {});
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// we do *not* override allowStateShapeChanges
|
|
282
|
-
// const options = { allowStateShapeChanges: true };
|
|
283
|
-
const options = undefined;
|
|
284
|
-
const makeNS2 = () => ({ buildRootObject: build2 });
|
|
285
|
-
const ls2 = makeLiveSlots(
|
|
286
|
-
sc2,
|
|
287
|
-
'vatA',
|
|
288
|
-
{},
|
|
289
|
-
options,
|
|
290
|
-
gcTools,
|
|
291
|
-
undefined,
|
|
292
|
-
makeNS2,
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
const vp = { obj1: kslot(vref1), obj2: kslot(vref2) };
|
|
296
|
-
const startVat2 = makeStartVat(kser(vp));
|
|
297
|
-
await ls2.dispatch(startVat2);
|
|
298
|
-
});
|