@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.
Files changed (141) hide show
  1. package/README.md +2 -0
  2. package/package.json +34 -26
  3. package/src/boyd-gc.d.ts +12 -0
  4. package/src/boyd-gc.d.ts.map +1 -0
  5. package/src/boyd-gc.js +598 -0
  6. package/src/cache.d.ts +71 -0
  7. package/src/cache.d.ts.map +1 -0
  8. package/src/cache.js +3 -2
  9. package/src/capdata.d.ts +16 -0
  10. package/src/capdata.d.ts.map +1 -0
  11. package/src/capdata.js +17 -10
  12. package/src/collectionManager.d.ts +47 -0
  13. package/src/collectionManager.d.ts.map +1 -0
  14. package/src/collectionManager.js +220 -103
  15. package/src/facetiousness.d.ts +25 -0
  16. package/src/facetiousness.d.ts.map +1 -0
  17. package/src/facetiousness.js +1 -1
  18. package/src/index.d.ts +4 -0
  19. package/src/index.d.ts.map +1 -0
  20. package/src/index.js +4 -2
  21. package/src/kdebug.d.ts +7 -0
  22. package/src/kdebug.d.ts.map +1 -0
  23. package/src/liveslots.d.ts +42 -0
  24. package/src/liveslots.d.ts.map +1 -0
  25. package/src/liveslots.js +137 -305
  26. package/src/message.d.ts +49 -0
  27. package/src/message.d.ts.map +1 -0
  28. package/src/message.js +9 -5
  29. package/src/parseVatSlots.d.ts +125 -0
  30. package/src/parseVatSlots.d.ts.map +1 -0
  31. package/src/parseVatSlots.js +1 -1
  32. package/src/types-index.d.ts +4 -0
  33. package/src/types-index.js +2 -0
  34. package/src/types.d.ts +81 -0
  35. package/src/types.d.ts.map +1 -0
  36. package/src/types.js +14 -7
  37. package/src/vatDataTypes.d.ts +170 -0
  38. package/src/vatDataTypes.d.ts.map +1 -0
  39. package/src/vatDataTypes.ts +272 -0
  40. package/src/vatstore-iterators.d.ts +4 -0
  41. package/src/vatstore-iterators.d.ts.map +1 -0
  42. package/src/vatstore-iterators.js +2 -0
  43. package/src/vatstore-usage.md +198 -0
  44. package/src/virtualObjectManager.d.ts +44 -0
  45. package/src/virtualObjectManager.d.ts.map +1 -0
  46. package/src/virtualObjectManager.js +254 -84
  47. package/src/virtualReferences.d.ts +61 -0
  48. package/src/virtualReferences.d.ts.map +1 -0
  49. package/src/virtualReferences.js +135 -26
  50. package/src/vpid-tracking.md +92 -0
  51. package/src/watchedPromises.d.ts +31 -0
  52. package/src/watchedPromises.d.ts.map +1 -0
  53. package/src/watchedPromises.js +81 -24
  54. package/test/{test-baggage.js → baggage.test.js} +1 -2
  55. package/test/{test-cache.js → cache.test.js} +0 -1
  56. package/test/clear-collection.test.js +586 -0
  57. package/test/{test-collection-schema-refcount.js → collection-schema-refcount.test.js} +1 -2
  58. package/test/{test-collection-upgrade.js → collection-upgrade.test.js} +1 -3
  59. package/test/{test-collections.js → collections.test.js} +183 -18
  60. package/test/{test-dropped-collection-weakrefs.js → dropped-collection-weakrefs.test.js} +1 -2
  61. package/test/dropped-weakset-9939.test.js +80 -0
  62. package/test/dummyMeterControl.d.ts +2 -0
  63. package/test/dummyMeterControl.d.ts.map +1 -0
  64. package/test/dummyMeterControl.js +1 -1
  65. package/test/{test-durabilityChecks.js → durabilityChecks.test.js} +4 -4
  66. package/test/engine-gc.d.ts +3 -0
  67. package/test/engine-gc.d.ts.map +1 -0
  68. package/test/exo-utils.js +70 -0
  69. package/test/{test-facetiousness.js → facetiousness.test.js} +1 -2
  70. package/test/gc-and-finalize.d.ts +5 -0
  71. package/test/gc-and-finalize.d.ts.map +1 -0
  72. package/test/gc-and-finalize.js +30 -1
  73. package/test/gc-before-finalizer.test.js +230 -0
  74. package/test/gc-helpers.js +4 -5
  75. package/test/{test-gc-sensitivity.js → gc-sensitivity.test.js} +2 -2
  76. package/test/handled-promises.test.js +872 -0
  77. package/test/{test-initial-vrefs.js → initial-vrefs.test.js} +13 -20
  78. package/test/liveslots-helpers.d.ts +64 -0
  79. package/test/liveslots-helpers.d.ts.map +1 -0
  80. package/test/liveslots-helpers.js +13 -7
  81. package/test/{test-liveslots-mock-gc.js → liveslots-mock-gc.test.js} +101 -2
  82. package/test/{test-liveslots-real-gc.js → liveslots-real-gc.test.js} +73 -46
  83. package/test/{test-liveslots.js → liveslots.test.js} +17 -18
  84. package/test/mock-gc.js +1 -0
  85. package/test/storeGC/{test-lifecycle.js → lifecycle.test.js} +15 -14
  86. package/test/storeGC/{test-refcount-management.js → refcount-management.test.js} +1 -2
  87. package/test/storeGC/{test-scalar-store-kind.js → scalar-store-kind.test.js} +0 -1
  88. package/test/storeGC/{test-weak-key.js → weak-key.test.js} +1 -2
  89. package/test/strict-test-env-upgrade.test.js +94 -0
  90. package/test/util.d.ts +25 -0
  91. package/test/util.d.ts.map +1 -0
  92. package/test/util.js +4 -4
  93. package/test/vat-environment.test.js +65 -0
  94. package/test/vat-util.d.ts +9 -0
  95. package/test/vat-util.d.ts.map +1 -0
  96. package/test/vat-util.js +2 -2
  97. package/test/virtual-objects/{test-cease-recognition.js → cease-recognition.test.js} +2 -2
  98. package/test/virtual-objects/{test-cross-facet.js → cross-facet.test.js} +5 -4
  99. package/test/virtual-objects/{test-empty-data.js → empty-data.test.js} +1 -2
  100. package/test/virtual-objects/{test-facets.js → facets.test.js} +1 -2
  101. package/test/virtual-objects/{test-kind-changes.js → kind-changes.test.js} +2 -2
  102. package/test/virtual-objects/{test-reachable-vrefs.js → reachable-vrefs.test.js} +2 -2
  103. package/test/virtual-objects/{test-rep-tostring.js → rep-tostring.test.js} +3 -5
  104. package/test/virtual-objects/{test-retain-remotable.js → retain-remotable.test.js} +25 -24
  105. package/test/virtual-objects/set-debug-label-instances.js +1 -1
  106. package/test/virtual-objects/state-shape.test.js +389 -0
  107. package/test/virtual-objects/{test-virtualObjectGC.js → virtualObjectGC.test.js} +39 -38
  108. package/test/virtual-objects/{test-virtualObjectManager.js → virtualObjectManager.test.js} +104 -8
  109. package/test/virtual-objects/{test-vo-real-gc.js → vo-real-gc.test.js} +8 -8
  110. package/test/virtual-objects/{test-weakcollections-vref-handling.js → weakcollections-vref-handling.test.js} +1 -2
  111. package/test/{test-vo-test-harness.js → vo-test-harness.test.js} +13 -10
  112. package/test/{test-vpid-liveslots.js → vpid-liveslots.test.js} +105 -5
  113. package/test/waitUntilQuiescent.d.ts +3 -0
  114. package/test/waitUntilQuiescent.d.ts.map +1 -0
  115. package/test/waitUntilQuiescent.js +2 -1
  116. package/test/weakset-dropped-remotable.test.js +50 -0
  117. package/tools/fakeCollectionManager.d.ts +14 -0
  118. package/tools/fakeCollectionManager.d.ts.map +1 -0
  119. package/tools/fakeCollectionManager.js +44 -0
  120. package/tools/fakeVirtualObjectManager.d.ts +32 -0
  121. package/tools/fakeVirtualObjectManager.d.ts.map +1 -0
  122. package/tools/fakeVirtualObjectManager.js +62 -0
  123. package/tools/fakeVirtualSupport.d.ts +278 -0
  124. package/tools/fakeVirtualSupport.d.ts.map +1 -0
  125. package/tools/fakeVirtualSupport.js +389 -0
  126. package/tools/prepare-strict-test-env.d.ts +37 -0
  127. package/tools/prepare-strict-test-env.d.ts.map +1 -0
  128. package/tools/prepare-strict-test-env.js +124 -0
  129. package/tools/prepare-test-env.d.ts +2 -0
  130. package/tools/prepare-test-env.d.ts.map +1 -0
  131. package/tools/prepare-test-env.js +13 -0
  132. package/tools/setup-vat-data.d.ts +9 -0
  133. package/tools/setup-vat-data.d.ts.map +1 -0
  134. package/tools/setup-vat-data.js +95 -0
  135. package/tools/vo-test-harness.d.ts +33 -0
  136. package/tools/vo-test-harness.d.ts.map +1 -0
  137. package/tools/vo-test-harness.js +164 -0
  138. package/CHANGELOG.md +0 -61
  139. package/test/kmarshal.js +0 -79
  140. package/test/test-handled-promises.js +0 -360
  141. 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
- });